diff options
author | Peter Varga <pvarga@inf.u-szeged.hu> | 2024-02-28 14:43:16 +0100 |
---|---|---|
committer | Peter Varga <pvarga@inf.u-szeged.hu> | 2024-03-21 12:30:37 +0100 |
commit | d7e2eabed009cf7607a36e29611eb54c3be335b9 (patch) | |
tree | 3f149c5b18fcc7fc3ac11be3bf5c333ddf0c682e | |
parent | ddc5f7d22b05f8b8de4ca7240c59e9a0899755d7 (diff) |
Implement NativePixmap support for EGL
Pick-to: 6.7
Change-Id: I321d0de7e12902e1ec915983cf1594508ebac883
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r-- | src/core/configure/BUILD.root.gn.in | 7 | ||||
-rw-r--r-- | src/core/ozone/gl_context_qt.cpp | 112 | ||||
-rw-r--r-- | src/core/ozone/gl_context_qt.h | 47 | ||||
-rw-r--r-- | src/core/ozone/ozone_platform_qt.cpp | 11 | ||||
-rw-r--r-- | src/core/ozone/surface_factory_qt.cpp | 86 | ||||
-rw-r--r-- | src/core/ozone/surface_factory_qt.h | 2 |
6 files changed, 234 insertions, 31 deletions
diff --git a/src/core/configure/BUILD.root.gn.in b/src/core/configure/BUILD.root.gn.in index 43b9faa3a..f58897ca5 100644 --- a/src/core/configure/BUILD.root.gn.in +++ b/src/core/configure/BUILD.root.gn.in @@ -372,7 +372,14 @@ source_set("qtwebengine_sources") { "//components/embedder_support/user_agent_utils.h", ] if (use_ozone) { + deps += [ + "//build/config/linux/libdrm", + "//ui/gfx/linux:drm", + ] + sources += [ + "//ui/ozone/platform/wayland/gpu/drm_render_node_handle.cc", + "//ui/ozone/platform/wayland/gpu/drm_render_node_handle.h", "//ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc", "//ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h", ] diff --git a/src/core/ozone/gl_context_qt.cpp b/src/core/ozone/gl_context_qt.cpp index e53c4763e..8c8fc881a 100644 --- a/src/core/ozone/gl_context_qt.cpp +++ b/src/core/ozone/gl_context_qt.cpp @@ -9,10 +9,18 @@ #include <QtGui/private/qtgui-config_p.h> #include <qpa/qplatformnativeinterface.h> +#include "ui/gl/gl_implementation.h" + +#if defined(USE_OZONE) +#include "ui/gfx/linux/drm_util_linux.h" +#include "ui/gfx/linux/gbm_device.h" +#include "ui/gfx/linux/gbm_wrapper.h" +#include "ui/ozone/platform/wayland/gpu/drm_render_node_handle.h" +#endif + #if BUILDFLAG(IS_WIN) #include "ui/gl/gl_context_egl.h" #include "ui/gl/gl_context_wgl.h" -#include "ui/gl/gl_implementation.h" #endif QT_BEGIN_NAMESPACE @@ -164,6 +172,108 @@ bool GLContextHelper::isCreateContextRobustnessSupported() return contextHelper->m_robustness; } +#if defined(USE_OZONE) +EGLHelper::EGLFunctions::EGLFunctions() +{ + const static auto getProcAddress = + reinterpret_cast<gl::GLGetProcAddressProc>(GLContextHelper::getEglGetProcAddress()); + + eglQueryDevices = + reinterpret_cast<PFNEGLQUERYDEVICESEXTPROC>(getProcAddress("eglQueryDevicesEXT")); + eglQueryDeviceString = reinterpret_cast<PFNEGLQUERYDEVICESTRINGEXTPROC>( + getProcAddress("eglQueryDeviceStringEXT")); + eglQueryString = reinterpret_cast<PFNEGLQUERYSTRINGPROC>(getProcAddress("eglQueryString")); +} + +EGLHelper *EGLHelper::instance() +{ + static EGLHelper eglHelper; + return &eglHelper; +} + +EGLHelper::EGLHelper() : m_functions(new EGLHelper::EGLFunctions()) +{ + const char *extensions = m_functions->eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (!extensions) { + qWarning("EGL: Failed to query EGL extensions."); + return; + } + + auto eglDisplay = GLContextHelper::getEGLDisplay(); + if (!eglDisplay) { + qWarning("EGL: No EGL display."); + return; + } + + const char *displayExtensions = m_functions->eglQueryString(eglDisplay, EGL_EXTENSIONS); + bool hasImageDmaBufImportExtension = strstr(displayExtensions, "EGL_EXT_image_dma_buf_import"); + + if (strstr(extensions, "EGL_EXT_device_base")) { + EGLint numDevices; + m_functions->eglQueryDevices(1, &m_eglDevice, &numDevices); + } + + bool hasDeviceDrmRenderNodeExtensions = false; + if (m_eglDevice != EGL_NO_DEVICE_EXT) { + const char *deviceExtensions = + m_functions->eglQueryDeviceString(m_eglDevice, EGL_EXTENSIONS); + hasDeviceDrmRenderNodeExtensions = + strstr(deviceExtensions, "EGL_EXT_device_drm_render_node"); + } + + m_isDmaBufSupported = hasImageDmaBufImportExtension && hasDeviceDrmRenderNodeExtensions; + + if (m_isDmaBufSupported) { + // FIXME: This disables GBM for nvidia. Remove this when nvidia fixes its GBM support. + // + // "Buffer allocation and submission to DRM KMS using gbm is not currently supported." + // See: https://download.nvidia.com/XFree86/Linux-x86_64/550.40.07/README/kms.html + // + // Chromium uses GBM to allocate scanout buffers. Scanout requires DRM KMS. If KMS is + // enabled, gbm_device and gbm_buffer are created without any issues but rendering to the + // buffer will malfunction. It is not known how to detect this problem before rendering + // so we just disable GBM for nvidia. + const char *displayVendor = m_functions->eglQueryString(eglDisplay, EGL_VENDOR); + m_isDmaBufSupported = !strstr(displayVendor, "NVIDIA"); + } +} + +ui::GbmDevice *EGLHelper::getGbmDevice() +{ + if (!m_isDmaBufSupported) + return nullptr; + + if (m_gbmDevice) + return m_gbmDevice.get(); + + Q_ASSERT(m_eglDevice != EGL_NO_DEVICE_EXT); + const char *drmRenderNodeFilePath = + m_functions->eglQueryDeviceString(m_eglDevice, EGL_DRM_RENDER_NODE_FILE_EXT); + if (!drmRenderNodeFilePath) { + qWarning("EGL: Failed to query DRM render node file path."); + m_isDmaBufSupported = false; + return nullptr; + } + + ui::DrmRenderNodeHandle handle; + if (!handle.Initialize(base::FilePath(drmRenderNodeFilePath))) { + qWarning("EGL: Failed to initialize DRM render node handle."); + m_isDmaBufSupported = false; + return nullptr; + } + + m_drmRenderNodeFd = handle.PassFD(); + m_gbmDevice = ui::CreateGbmDevice(m_drmRenderNodeFd.get()); + if (!m_gbmDevice) { + qWarning("EGL: Failed to initialize GBM device."); + m_isDmaBufSupported = false; + return nullptr; + } + + return m_gbmDevice.get(); +} +#endif // defined(USE_OZONE) + QT_END_NAMESPACE #if BUILDFLAG(IS_WIN) diff --git a/src/core/ozone/gl_context_qt.h b/src/core/ozone/gl_context_qt.h index 655fd7e19..6e6a24310 100644 --- a/src/core/ozone/gl_context_qt.h +++ b/src/core/ozone/gl_context_qt.h @@ -5,12 +5,25 @@ #define GL_GL_CONTEXT_QT_H_ #include <QObject> +#include <QtCore/qscopedpointer.h> + #include "ui/gl/gl_context.h" +#if defined(USE_OZONE) +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include "base/files/scoped_file.h" +#endif + namespace gl { class GLSurface; } +namespace ui { +class GbmDevice; +} + QT_BEGIN_NAMESPACE class GLContextHelper : public QObject { @@ -38,6 +51,40 @@ private: bool m_robustness = false; }; +#if defined(USE_OZONE) +#undef eglQueryDevices +#undef eglQueryDeviceString +#undef eglQueryString + +class EGLHelper +{ +public: + struct EGLFunctions + { + EGLFunctions(); + + PFNEGLQUERYDEVICESEXTPROC eglQueryDevices; + PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceString; + PFNEGLQUERYSTRINGPROC eglQueryString; + }; + + static EGLHelper *instance(); + + EGLFunctions *functions() const { return m_functions.get(); } + EGLDeviceEXT getEGLDevice() const { return m_eglDevice; } + ui::GbmDevice *getGbmDevice(); + +private: + EGLHelper(); + + QScopedPointer<EGLFunctions> m_functions; + EGLDeviceEXT m_eglDevice = EGL_NO_DEVICE_EXT; + base::ScopedFD m_drmRenderNodeFd; + std::unique_ptr<ui::GbmDevice> m_gbmDevice; + bool m_isDmaBufSupported = false; +}; +#endif // defined(USE_OZONE) + QT_END_NAMESPACE #endif diff --git a/src/core/ozone/ozone_platform_qt.cpp b/src/core/ozone/ozone_platform_qt.cpp index 31862c3de..e8547fa87 100644 --- a/src/core/ozone/ozone_platform_qt.cpp +++ b/src/core/ozone/ozone_platform_qt.cpp @@ -71,14 +71,9 @@ public: { static OzonePlatform::PlatformRuntimeProperties properties; if (has_initialized_gpu()) { -#if BUILDFLAG(OZONE_PLATFORM_X11) - if (GetQtXDisplay()) { - // This property is set when the GetPlatformRuntimeProperties is - // called on the gpu process side. - properties.supports_native_pixmaps = ui::GpuMemoryBufferSupportX11::GetInstance()->has_gbm_device(); - } else -#endif - properties.supports_native_pixmaps = true; // buffer_manager_->GetGbmDevice() != nullptr + // This property is set when the GetPlatformRuntimeProperties is + // called on the gpu process side. + properties.supports_native_pixmaps = surface_factory_ozone_->SupportsNativePixmaps(); } return properties; } diff --git a/src/core/ozone/surface_factory_qt.cpp b/src/core/ozone/surface_factory_qt.cpp index 0fd96ed4c..c8264d05f 100644 --- a/src/core/ozone/surface_factory_qt.cpp +++ b/src/core/ozone/surface_factory_qt.cpp @@ -8,13 +8,16 @@ #include "ozone/gl_ozone_egl_qt.h" #include "media/gpu/buildflags.h" +#include "ui/gfx/linux/drm_util_linux.h" +#include "ui/gfx/linux/gbm_buffer.h" +#include "ui/gfx/linux/gbm_device.h" +#include "ui/gfx/linux/gbm_util.h" #include "ui/gfx/linux/native_pixmap_dmabuf.h" #include "ui/ozone/buildflags.h" #if BUILDFLAG(OZONE_PLATFORM_X11) #include "ozone/gl_ozone_glx_qt.h" -#include "ui/gfx/linux/gbm_buffer.h" #include "ui/gfx/linux/gpu_memory_buffer_support_x11.h" #endif @@ -73,7 +76,11 @@ bool SurfaceFactoryQt::CanCreateNativePixmapForFormat(gfx::BufferFormat format) if (GLContextHelper::getGlxPlatformInterface()) return ui::GpuMemoryBufferSupportX11::GetInstance()->CanCreateNativePixmapForFormat(format); #endif - return ui::SurfaceFactoryOzone::CanCreateNativePixmapForFormat(format); + + if (GLContextHelper::getEglPlatformInterface()) + return ui::SurfaceFactoryOzone::CanCreateNativePixmapForFormat(format); + + return false; } scoped_refptr<gfx::NativePixmap> SurfaceFactoryQt::CreateNativePixmap( @@ -84,23 +91,34 @@ scoped_refptr<gfx::NativePixmap> SurfaceFactoryQt::CreateNativePixmap( gfx::BufferUsage usage, absl::optional<gfx::Size> framebuffer_size) { + Q_ASSERT(SupportsNativePixmaps()); if (framebuffer_size && !gfx::Rect(size).Contains(gfx::Rect(*framebuffer_size))) return nullptr; + + std::unique_ptr<ui::GbmBuffer> gbmBuffer; + #if BUILDFLAG(OZONE_PLATFORM_X11) if (GLContextHelper::getGlxPlatformInterface()) { - scoped_refptr<gfx::NativePixmapDmaBuf> pixmap; - auto buffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBuffer(format, size, usage); - if (buffer) { - gfx::NativePixmapHandle handle = buffer->ExportHandle(); - pixmap = base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(handle)); - } - // CreateNativePixmap is non-blocking operation. Thus, it is safe to call it - // and return the result with the provided callback. - return pixmap; + gbmBuffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBuffer(format, size, usage); + if (!gbmBuffer) + qFatal("Failed to create GBM buffer for GLX."); } #endif - // FIXME: No EGL implementation. - return nullptr; + + if (GLContextHelper::getEglPlatformInterface()) { + const uint32_t fourccFormat = ui::GetFourCCFormatFromBufferFormat(format); + const uint32_t gbmFlags = ui::BufferUsageToGbmFlags(usage); + + ui::GbmDevice *gbmDevice = EGLHelper::instance()->getGbmDevice(); + // FIXME: CreateBufferWithModifiers for wayland? + gbmBuffer = gbmDevice->CreateBuffer(fourccFormat, size, gbmFlags); + if (!gbmBuffer) + qFatal("Failed to create GBM buffer for EGL."); + } + + Q_ASSERT(gbmBuffer); + gfx::NativePixmapHandle handle = gbmBuffer->ExportHandle(); + return base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(handle)); } void SurfaceFactoryQt::CreateNativePixmapAsync( @@ -111,6 +129,7 @@ void SurfaceFactoryQt::CreateNativePixmapAsync( gfx::BufferUsage usage, NativePixmapCallback callback) { + Q_ASSERT(SupportsNativePixmaps()); // CreateNativePixmap is non-blocking operation. Thus, it is safe to call it // and return the result with the provided callback. std::move(callback).Run(CreateNativePixmap(widget, device_queue, size, format, usage)); @@ -123,20 +142,43 @@ SurfaceFactoryQt::CreateNativePixmapFromHandle( gfx::BufferFormat format, gfx::NativePixmapHandle handle) { + Q_ASSERT(SupportsNativePixmaps()); + std::unique_ptr<ui::GbmBuffer> gbmBuffer; + #if BUILDFLAG(OZONE_PLATFORM_X11) if (GLContextHelper::getGlxPlatformInterface()) { - scoped_refptr<gfx::NativePixmapDmaBuf> pixmap; - auto buffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBufferFromHandle(size, format, std::move(handle)); - if (buffer) { - gfx::NativePixmapHandle buffer_handle = buffer->ExportHandle(); - pixmap = base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(buffer_handle)); - } - return pixmap; + gbmBuffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBufferFromHandle( + size, format, std::move(handle)); + if (!gbmBuffer) + qFatal("Failed to create GBM buffer for GLX."); } #endif + + if (GLContextHelper::getEglPlatformInterface()) { + const uint32_t fourccFormat = ui::GetFourCCFormatFromBufferFormat(format); + ui::GbmDevice *gbmDevice = EGLHelper::instance()->getGbmDevice(); + gbmBuffer = gbmDevice->CreateBufferFromHandle(fourccFormat, size, std::move(handle)); + + if (!gbmBuffer) + qFatal("Failed to create GBM buffer for EGL."); + } + + Q_ASSERT(gbmBuffer); + gfx::NativePixmapHandle bufferHandle = gbmBuffer->ExportHandle(); + return base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(bufferHandle)); +} + +bool SurfaceFactoryQt::SupportsNativePixmaps() const +{ +#if BUILDFLAG(OZONE_PLATFORM_X11) + if (GLContextHelper::getGlxPlatformInterface()) + return ui::GpuMemoryBufferSupportX11::GetInstance()->has_gbm_device(); +#endif + if (GLContextHelper::getEglPlatformInterface()) - return base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(handle)); - return nullptr; + return (EGLHelper::instance()->getGbmDevice() != nullptr); + + return false; } } // namespace QtWebEngineCore diff --git a/src/core/ozone/surface_factory_qt.h b/src/core/ozone/surface_factory_qt.h index f85e3e0b4..07d7337ac 100644 --- a/src/core/ozone/surface_factory_qt.h +++ b/src/core/ozone/surface_factory_qt.h @@ -40,6 +40,8 @@ public: gfx::BufferFormat format, gfx::NativePixmapHandle handle) override; + bool SupportsNativePixmaps() const; + private: std::vector<gl::GLImplementationParts> m_impl; std::unique_ptr<ui::GLOzone> m_ozone; |