diff options
author | Peter Varga <pvarga@inf.u-szeged.hu> | 2024-03-12 16:04:18 +0100 |
---|---|---|
committer | Peter Varga <pvarga@inf.u-szeged.hu> | 2024-03-21 12:30:39 +0100 |
commit | 13d4d720880ae3ef69240f618f0430ecc041533a (patch) | |
tree | 743ad03ab36de02dbb4b89a7c93f6d15a041f888 /src/core | |
parent | d7e2eabed009cf7607a36e29611eb54c3be335b9 (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.in | 3 | ||||
-rw-r--r-- | src/core/ozone/gl_context_qt.cpp | 183 | ||||
-rw-r--r-- | src/core/ozone/gl_context_qt.h | 28 | ||||
-rw-r--r-- | src/core/ozone/surface_factory_qt.cpp | 114 |
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; } |