summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
authorPeter Varga <pvarga@inf.u-szeged.hu>2024-03-12 16:04:18 +0100
committerPeter Varga <pvarga@inf.u-szeged.hu>2024-03-21 12:30:39 +0100
commit13d4d720880ae3ef69240f618f0430ecc041533a (patch)
tree743ad03ab36de02dbb4b89a7c93f6d15a041f888 /src/core
parentd7e2eabed009cf7607a36e29611eb54c3be335b9 (diff)
Do not use GBM directly for EGL
Replace GBM API usage with using dma_buf import/export EGL extensions. Pick-to: 6.7 Change-Id: I0b332f084d1ada8b7ed58472f546b91628b9d771 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src/core')
-rw-r--r--src/core/configure/BUILD.root.gn.in3
-rw-r--r--src/core/ozone/gl_context_qt.cpp183
-rw-r--r--src/core/ozone/gl_context_qt.h28
-rw-r--r--src/core/ozone/surface_factory_qt.cpp114
4 files changed, 238 insertions, 90 deletions
diff --git a/src/core/configure/BUILD.root.gn.in b/src/core/configure/BUILD.root.gn.in
index f58897ca5..986db5026 100644
--- a/src/core/configure/BUILD.root.gn.in
+++ b/src/core/configure/BUILD.root.gn.in
@@ -373,13 +373,10 @@ source_set("qtwebengine_sources") {
]
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 8c8fc881a..608d5c21a 100644
--- a/src/core/ozone/gl_context_qt.cpp
+++ b/src/core/ozone/gl_context_qt.cpp
@@ -10,12 +10,15 @@
#include <qpa/qplatformnativeinterface.h>
#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.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"
+#include "ui/gl/egl_util.h"
+
+#include <QOpenGLFunctions>
+#include <QOffscreenSurface>
+
+#include <vector>
#endif
#if BUILDFLAG(IS_WIN)
@@ -173,15 +176,90 @@ bool GLContextHelper::isCreateContextRobustnessSupported()
}
#if defined(USE_OZONE)
+class ScopedGLContext
+{
+public:
+ ScopedGLContext()
+ : m_context(new QOpenGLContext())
+ , m_previousContext(gl::GLContext::GetCurrent())
+ , m_previousSurface(gl::GLSurface::GetCurrent())
+ {
+ if (!m_context->create()) {
+ qWarning("Failed to create OpenGL context.");
+ return;
+ }
+
+ QOffscreenSurface *surface = new QOffscreenSurface(m_context->screen(), m_context.get());
+ surface->create();
+ Q_ASSERT(surface->isValid());
+
+ if (!m_context->makeCurrent(surface)) {
+ qWarning("Failed to make OpenGL context current.");
+ return;
+ }
+ }
+
+ ~ScopedGLContext()
+ {
+ if (!m_textures.empty()) {
+ auto glFun = m_context->functions();
+ glFun->glDeleteTextures(m_textures.size(), m_textures.data());
+ }
+
+ if (m_previousContext)
+ m_previousContext->MakeCurrent(m_previousSurface);
+ }
+
+ bool isValid() const { return m_context->isValid() && (m_context->surface() != nullptr); }
+
+ EGLDisplay eglDisplay() const
+ {
+ QNativeInterface::QEGLContext *nativeInterface =
+ m_context->nativeInterface<QNativeInterface::QEGLContext>();
+ return nativeInterface->display();
+ }
+
+ EGLContext eglContext() const
+ {
+ QNativeInterface::QEGLContext *nativeInterface =
+ m_context->nativeInterface<QNativeInterface::QEGLContext>();
+ return nativeInterface->nativeContext();
+ }
+
+ uint createTexture(int width, int height)
+ {
+ auto glFun = m_context->functions();
+
+ uint glTexture;
+ glFun->glGenTextures(1, &glTexture);
+ glFun->glBindTexture(GL_TEXTURE_2D, glTexture);
+ glFun->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ NULL);
+ glFun->glBindTexture(GL_TEXTURE_2D, 0);
+
+ m_textures.push_back(glTexture);
+ return glTexture;
+ }
+
+private:
+ QScopedPointer<QOpenGLContext> m_context;
+ gl::GLContext *m_previousContext;
+ gl::GLSurface *m_previousSurface;
+ std::vector<uint> m_textures;
+};
+
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"));
+ eglCreateImage = reinterpret_cast<PFNEGLCREATEIMAGEPROC>(getProcAddress("eglCreateImage"));
+ eglDestroyImage = reinterpret_cast<PFNEGLDESTROYIMAGEPROC>(getProcAddress("eglDestroyImage"));
+ eglGetError = reinterpret_cast<PFNEGLGETERRORPROC>(getProcAddress("eglGetError"));
+ eglExportDMABUFImageMESA = reinterpret_cast<PFNEGLEXPORTDMABUFIMAGEMESAPROC>(
+ getProcAddress("eglExportDMABUFImageMESA"));
+ eglExportDMABUFImageQueryMESA = reinterpret_cast<PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC>(
+ getProcAddress("eglExportDMABUFImageQueryMESA"));
eglQueryString = reinterpret_cast<PFNEGLQUERYSTRINGPROC>(getProcAddress("eglQueryString"));
}
@@ -199,6 +277,11 @@ EGLHelper::EGLHelper() : m_functions(new EGLHelper::EGLFunctions())
return;
}
+ if (strstr(extensions, "EGL_KHR_base_image")) {
+ qWarning("EGL: EGL_KHR_base_image extension is not supported.");
+ return;
+ }
+
auto eglDisplay = GLContextHelper::getEGLDisplay();
if (!eglDisplay) {
qWarning("EGL: No EGL display.");
@@ -206,22 +289,9 @@ EGLHelper::EGLHelper() : m_functions(new EGLHelper::EGLFunctions())
}
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;
+ m_isDmaBufSupported = strstr(displayExtensions, "EGL_EXT_image_dma_buf_import")
+ && strstr(displayExtensions, "EGL_EXT_image_dma_buf_import_modifiers")
+ && strstr(displayExtensions, "EGL_MESA_image_dma_buf_export");
if (m_isDmaBufSupported) {
// FIXME: This disables GBM for nvidia. Remove this when nvidia fixes its GBM support.
@@ -238,39 +308,60 @@ EGLHelper::EGLHelper() : m_functions(new EGLHelper::EGLFunctions())
}
}
-ui::GbmDevice *EGLHelper::getGbmDevice()
+void EGLHelper::queryDmaBuf(const int width, const int height, int *fd, int *stride, int *offset,
+ uint64_t *modifiers)
{
if (!m_isDmaBufSupported)
- return nullptr;
+ return;
- if (m_gbmDevice)
- return m_gbmDevice.get();
+ ScopedGLContext context;
+ if (!context.isValid())
+ return;
- 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;
+ EGLDisplay eglDisplay = context.eglDisplay();
+ EGLContext eglContext = context.eglContext();
+ if (!eglContext) {
+ qWarning("EGL: No EGLContext.");
+ return;
}
- ui::DrmRenderNodeHandle handle;
- if (!handle.Initialize(base::FilePath(drmRenderNodeFilePath))) {
- qWarning("EGL: Failed to initialize DRM render node handle.");
- m_isDmaBufSupported = false;
- return nullptr;
+ uint64_t textureId = context.createTexture(width, height);
+ EGLImage eglImage = m_functions->eglCreateImage(eglDisplay, eglContext, EGL_GL_TEXTURE_2D,
+ (EGLClientBuffer)textureId, NULL);
+ if (eglImage == EGL_NO_IMAGE) {
+ qWarning() << "EGL: Failed to create EGLImage:"
+ << ui::GetEGLErrorString(m_functions->eglGetError());
+ return;
}
- m_drmRenderNodeFd = handle.PassFD();
- m_gbmDevice = ui::CreateGbmDevice(m_drmRenderNodeFd.get());
- if (!m_gbmDevice) {
- qWarning("EGL: Failed to initialize GBM device.");
+ int numPlanes = 0;
+ if (!m_functions->eglExportDMABUFImageQueryMESA(eglDisplay, eglImage, nullptr, &numPlanes,
+ modifiers))
+ qWarning() << "EGL: Failed to retrieve the pixel format of the buffer:"
+ << ui::GetEGLErrorString(m_functions->eglGetError());
+ Q_ASSERT(numPlanes == 1);
+
+ if (!m_functions->eglExportDMABUFImageMESA(eglDisplay, eglImage, fd, stride, offset))
+ qWarning() << "EGL: Failed to retrieve the dma_buf file descriptor:"
+ << ui::GetEGLErrorString(m_functions->eglGetError());
+
+ m_functions->eglDestroyImage(eglDisplay, eglImage);
+}
+
+bool EGLHelper::isDmaBufSupported()
+{
+ if (!m_isDmaBufSupported)
+ return false;
+
+ int fd = -1;
+ queryDmaBuf(2, 2, &fd, nullptr, nullptr, nullptr);
+ if (fd == -1) {
m_isDmaBufSupported = false;
- return nullptr;
+ return false;
}
- return m_gbmDevice.get();
+ close(fd);
+ return true;
}
#endif // defined(USE_OZONE)
diff --git a/src/core/ozone/gl_context_qt.h b/src/core/ozone/gl_context_qt.h
index 6e6a24310..c1524abf2 100644
--- a/src/core/ozone/gl_context_qt.h
+++ b/src/core/ozone/gl_context_qt.h
@@ -12,18 +12,12 @@
#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 {
@@ -52,8 +46,11 @@ private:
};
#if defined(USE_OZONE)
-#undef eglQueryDevices
-#undef eglQueryDeviceString
+#undef eglCreateImage
+#undef eglDestroyImage
+#undef eglExportDMABUFImageMESA
+#undef eglExportDMABUFImageQueryMESA
+#undef eglGetError
#undef eglQueryString
class EGLHelper
@@ -63,24 +60,25 @@ public:
{
EGLFunctions();
- PFNEGLQUERYDEVICESEXTPROC eglQueryDevices;
- PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceString;
+ PFNEGLCREATEIMAGEPROC eglCreateImage;
+ PFNEGLDESTROYIMAGEPROC eglDestroyImage;
+ PFNEGLEXPORTDMABUFIMAGEMESAPROC eglExportDMABUFImageMESA;
+ PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC eglExportDMABUFImageQueryMESA;
+ PFNEGLGETERRORPROC eglGetError;
PFNEGLQUERYSTRINGPROC eglQueryString;
};
static EGLHelper *instance();
EGLFunctions *functions() const { return m_functions.get(); }
- EGLDeviceEXT getEGLDevice() const { return m_eglDevice; }
- ui::GbmDevice *getGbmDevice();
+ void queryDmaBuf(const int width, const int height, int *fd, int *stride, int *offset,
+ uint64_t *modifiers);
+ bool isDmaBufSupported();
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)
diff --git a/src/core/ozone/surface_factory_qt.cpp b/src/core/ozone/surface_factory_qt.cpp
index c8264d05f..374f870e2 100644
--- a/src/core/ozone/surface_factory_qt.cpp
+++ b/src/core/ozone/surface_factory_qt.cpp
@@ -1,28 +1,28 @@
-// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#if defined(USE_OZONE)
#include "surface_factory_qt.h"
+#include "qtwebenginecoreglobal_p.h"
#include "ozone/gl_context_qt.h"
#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/gl/egl_util.h"
#include "ui/ozone/buildflags.h"
+#include <QDebug>
+
#if BUILDFLAG(OZONE_PLATFORM_X11)
#include "ozone/gl_ozone_glx_qt.h"
#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h"
#endif
-#include "qtwebenginecoreglobal_p.h"
-
#if QT_CONFIG(webengine_vulkan)
#include "compositor/vulkan_implementation_qt.h"
#endif
@@ -95,29 +95,35 @@ scoped_refptr<gfx::NativePixmap> SurfaceFactoryQt::CreateNativePixmap(
if (framebuffer_size && !gfx::Rect(size).Contains(gfx::Rect(*framebuffer_size)))
return nullptr;
- std::unique_ptr<ui::GbmBuffer> gbmBuffer;
+ gfx::NativePixmapHandle handle;
#if BUILDFLAG(OZONE_PLATFORM_X11)
if (GLContextHelper::getGlxPlatformInterface()) {
- gbmBuffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBuffer(format, size, usage);
+ auto gbmBuffer =
+ ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBuffer(format, size, usage);
if (!gbmBuffer)
qFatal("Failed to create GBM buffer for GLX.");
+ handle = gbmBuffer->ExportHandle();
}
#endif
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.");
+ int fd = -1;
+ int stride;
+ int offset;
+ uint64_t modifiers;
+ EGLHelper::instance()->queryDmaBuf(size.width(), size.height(), &fd, &stride, &offset,
+ &modifiers);
+ if (fd == -1)
+ qFatal("Failed to query DRM FD for EGL.");
+
+ const uint64_t planeSize = uint64_t(size.width()) * size.height() * 4;
+ gfx::NativePixmapPlane plane(stride, offset, planeSize, base::ScopedFD(::dup(fd)));
+
+ handle.planes.push_back(std::move(plane));
+ handle.modifier = modifiers;
}
- Q_ASSERT(gbmBuffer);
- gfx::NativePixmapHandle handle = gbmBuffer->ExportHandle();
return base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(handle));
}
@@ -143,28 +149,84 @@ SurfaceFactoryQt::CreateNativePixmapFromHandle(
gfx::NativePixmapHandle handle)
{
Q_ASSERT(SupportsNativePixmaps());
- std::unique_ptr<ui::GbmBuffer> gbmBuffer;
+ gfx::NativePixmapHandle bufferHandle;
#if BUILDFLAG(OZONE_PLATFORM_X11)
if (GLContextHelper::getGlxPlatformInterface()) {
- gbmBuffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBufferFromHandle(
+ auto gbmBuffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBufferFromHandle(
size, format, std::move(handle));
if (!gbmBuffer)
qFatal("Failed to create GBM buffer for GLX.");
+ bufferHandle = gbmBuffer->ExportHandle();
}
#endif
if (GLContextHelper::getEglPlatformInterface()) {
+ const size_t numPlanes = handle.planes.size();
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.");
+ std::vector<EGLAttrib> attrs;
+ attrs.push_back(EGL_WIDTH);
+ attrs.push_back(size.width());
+ attrs.push_back(EGL_HEIGHT);
+ attrs.push_back(size.height());
+ attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT);
+ attrs.push_back(fourccFormat);
+ for (size_t planeIndex = 0; planeIndex < numPlanes; ++planeIndex) {
+ attrs.push_back(EGL_DMA_BUF_PLANE0_FD_EXT + planeIndex * 3);
+ attrs.push_back(handle.planes[planeIndex].fd.get());
+ attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT + planeIndex * 3);
+ attrs.push_back(handle.planes[planeIndex].offset);
+ attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT + planeIndex * 3);
+ attrs.push_back(handle.planes[planeIndex].stride);
+ attrs.push_back(EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT + planeIndex * 2);
+ attrs.push_back(handle.modifier & 0xffffffff);
+ attrs.push_back(EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT + planeIndex * 2);
+ attrs.push_back(handle.modifier >> 32);
+ }
+ attrs.push_back(EGL_NONE);
+
+ EGLDisplay eglDisplay = GLContextHelper::getEGLDisplay();
+ EGLHelper *eglHelper = EGLHelper::instance();
+ auto *eglFun = eglHelper->functions();
+
+ EGLImage eglImage =
+ eglFun->eglCreateImage(eglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT,
+ (EGLClientBuffer)NULL, attrs.data());
+ if (eglImage == EGL_NO_IMAGE_KHR) {
+ qFatal() << "Failed to import EGLImage:"
+ << ui::GetEGLErrorString(eglFun->eglGetError());
+ }
+
+ Q_ASSERT(numPlanes <= 3);
+ int fds[3];
+ int strides[3];
+ int offsets[3];
+ if (!eglFun->eglExportDMABUFImageMESA(eglDisplay, eglImage, fds, strides, offsets)) {
+ qFatal() << "Failed to export EGLImage:"
+ << ui::GetEGLErrorString(eglFun->eglGetError());
+ }
+
+ bufferHandle.modifier = handle.modifier;
+ for (size_t i = 0; i < numPlanes; ++i) {
+ int fd = fds[i];
+ int stride = strides[i];
+ int offset = offsets[i];
+ int size = handle.planes[i].size;
+
+ if (fd == -1) {
+ fd = fds[0];
+ stride = handle.planes[i].stride;
+ offset = handle.planes[i].offset;
+ }
+
+ gfx::NativePixmapPlane plane(stride, offset, size, base::ScopedFD(::dup(fd)));
+ bufferHandle.planes.push_back(std::move(plane));
+ }
+
+ eglFun->eglDestroyImage(eglDisplay, eglImage);
}
- Q_ASSERT(gbmBuffer);
- gfx::NativePixmapHandle bufferHandle = gbmBuffer->ExportHandle();
return base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(bufferHandle));
}
@@ -176,7 +238,7 @@ bool SurfaceFactoryQt::SupportsNativePixmaps() const
#endif
if (GLContextHelper::getEglPlatformInterface())
- return (EGLHelper::instance()->getGbmDevice() != nullptr);
+ return EGLHelper::instance()->isDmaBufSupported();
return false;
}