summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Varga <pvarga@inf.u-szeged.hu>2024-02-28 14:43:16 +0100
committerPeter Varga <pvarga@inf.u-szeged.hu>2024-03-21 12:30:37 +0100
commitd7e2eabed009cf7607a36e29611eb54c3be335b9 (patch)
tree3f149c5b18fcc7fc3ac11be3bf5c333ddf0c682e
parentddc5f7d22b05f8b8de4ca7240c59e9a0899755d7 (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.in7
-rw-r--r--src/core/ozone/gl_context_qt.cpp112
-rw-r--r--src/core/ozone/gl_context_qt.h47
-rw-r--r--src/core/ozone/ozone_platform_qt.cpp11
-rw-r--r--src/core/ozone/surface_factory_qt.cpp86
-rw-r--r--src/core/ozone/surface_factory_qt.h2
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;