https://codereview.qt-project.org/c/qt/qtwebengine/+/675112 From 3cc88e0f85113e38ccb1bfdadb7d150c2389b1bc Mon Sep 17 00:00:00 2001 From: Moss Heim Date: Thu, 11 Sep 2025 13:47:04 +0200 Subject: [PATCH] Return to supporting eglCreateImage in EGLHelper::queryDmaBuf eglCreateDRMImageMESA was removed in mesa 25.2. Keep using it where we can since this fixes support for panthor/panfrost, otherwise fall back to the old use of EGL API. Includes a revert of the following commits: Revert "Create EGLImage with eglCreateDRMImageMESA() for exporting dma_buf" This reverts commit 2ed5f9632292c6e531f353dae800cb12274af91a. Revert "Remove leftover QOffscreenSurface from EGLHelper" This reverts commit bcee2dbf412cc655c1b467091b581c696d234e3f. Pick-to: 6.9 6.10 6.10.0 Task-number: QTBUG-136257 Task-number: QTBUG-139424 Change-Id: Ie115bd6373ce0a80651781aa568405477010ee25 Reviewed-by: Peter Varga --- src/core/ozone/egl_helper.cpp | 142 +++++++++++++++++++++++++++++++--- src/core/ozone/egl_helper.h | 4 + 2 files changed, 134 insertions(+), 12 deletions(-) diff --git a/src/core/ozone/egl_helper.cpp b/src/core/ozone/egl_helper.cpp index 76e1c2a4663..68e45ffd446 100644 --- a/src/core/ozone/egl_helper.cpp +++ b/src/core/ozone/egl_helper.cpp @@ -3,10 +3,14 @@ // Qt-Security score:significant reason:default #include "egl_helper.h" + +#include "compositor/compositor.h" #include "ozone_util_qt.h" #include "web_engine_context.h" +#include #include +#include #include #include #include @@ -57,6 +61,84 @@ static const char *getEGLErrorString(uint32_t error) QT_BEGIN_NAMESPACE +class ScopedGLContext +{ +public: + ScopedGLContext(QOffscreenSurface *surface, EGLHelper::EGLFunctions *eglFun) + : m_context(new QOpenGLContext()), m_eglFun(eglFun) + { + if ((m_previousEGLContext = m_eglFun->eglGetCurrentContext())) { + m_previousEGLDrawSurface = m_eglFun->eglGetCurrentSurface(EGL_DRAW); + m_previousEGLReadSurface = m_eglFun->eglGetCurrentSurface(EGL_READ); + m_previousEGLDisplay = m_eglFun->eglGetCurrentDisplay(); + } + + if (!m_context->create()) { + qWarning("Failed to create OpenGL context."); + return; + } + + 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_previousEGLContext) { + // Make sure the scoped context is not current when restoring the previous + // EGL context otherwise the QOpenGLContext destructor resets the restored + // current context. + m_context->doneCurrent(); + + m_eglFun->eglMakeCurrent(m_previousEGLDisplay, m_previousEGLDrawSurface, + m_previousEGLReadSurface, m_previousEGLContext); + if (m_eglFun->eglGetError() != EGL_SUCCESS) + qWarning("Failed to restore EGL context."); + } + } + + bool isValid() const { return m_context->isValid() && (m_context->surface() != nullptr); } + + EGLContext eglContext() const + { + QNativeInterface::QEGLContext *nativeInterface = + m_context->nativeInterface(); + 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 m_context; + EGLHelper::EGLFunctions *m_eglFun; + EGLContext m_previousEGLContext = nullptr; + EGLSurface m_previousEGLDrawSurface = nullptr; + EGLSurface m_previousEGLReadSurface = nullptr; + EGLDisplay m_previousEGLDisplay = nullptr; + std::vector m_textures; +}; + EGLHelper::EGLFunctions::EGLFunctions() { QOpenGLContext *context = OzoneUtilQt::getQOpenGLContext(); @@ -117,8 +199,23 @@ EGLHelper::EGLHelper() const char *displayExtensions = m_functions->eglQueryString(m_eglDisplay, EGL_EXTENSIONS); m_isDmaBufSupported = strstr(displayExtensions, "EGL_EXT_image_dma_buf_import") && strstr(displayExtensions, "EGL_EXT_image_dma_buf_import_modifiers") - && strstr(displayExtensions, "EGL_MESA_drm_image") && strstr(displayExtensions, "EGL_MESA_image_dma_buf_export"); + m_isCreateDRMImageMesaSupported = strstr(displayExtensions, "EGL_MESA_drm_image"); + if (!m_isDmaBufSupported) { + qCDebug(QtWebEngineCore::lcWebEngineCompositor, + "EGL: MESA extensions not found, will not use dma-buf"); + } else if (!m_isCreateDRMImageMesaSupported) { + qCDebug(QtWebEngineCore::lcWebEngineCompositor, + "EGL: MESA extensions found but missing EGL_MESA_drm_image, will use dma-buf, " + "some older graphics cards may not be supported"); + m_offscreenSurface.reset(new QOffscreenSurface()); + Q_ASSERT(QThread::currentThread() == qApp->thread()); + m_offscreenSurface->create(); + } else { + qCDebug(QtWebEngineCore::lcWebEngineCompositor, + "EGL: MESA extensions and EGL_MESA_drm_image found, will use dma-buf with GEM " + "buffer allocation"); + } } // Try to create dma-buf. @@ -138,17 +235,38 @@ void EGLHelper::queryDmaBuf(const int width, const int height, int *fd, int *str if (!m_isDmaBufSupported) return; - // clang-format off - EGLint attribs[] = { - EGL_WIDTH, width, - EGL_HEIGHT, height, - EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, - EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SHARE_MESA, - EGL_NONE - }; - // clang-format on - - EGLImage eglImage = m_functions->eglCreateDRMImageMESA(m_eglDisplay, attribs); + EGLImage eglImage = EGL_NO_IMAGE; + // Probably doesn't need to live to the end of the function, but just in case. + std::unique_ptr glContext; + if (m_isCreateDRMImageMesaSupported) { + // This approach is slightly worse for security and no longer supported in mesa 25.2, + // but it allows us to keep support for the Panthor driver prior to that mesa version. + // clang-format off + EGLint attribs[] = { + EGL_WIDTH, width, + EGL_HEIGHT, height, + EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, + EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SHARE_MESA, + EGL_NONE + }; + // clang-format on + eglImage = m_functions->eglCreateDRMImageMESA(m_eglDisplay, attribs); + } else { + glContext = std::make_unique(m_offscreenSurface.get(), m_functions.get()); + if (!glContext->isValid()) + return; + + EGLContext eglContext = glContext->eglContext(); + if (!eglContext) { + qWarning("EGL: No EGLContext."); + return; + } + + uint64_t textureId = glContext->createTexture(width, height); + eglImage = m_functions->eglCreateImage(m_eglDisplay, eglContext, EGL_GL_TEXTURE_2D, + (EGLClientBuffer)textureId, NULL); + } + if (eglImage == EGL_NO_IMAGE) { qWarning("EGL: Failed to create EGLImage: %s", getLastEGLErrorString()); return; diff --git a/src/core/ozone/egl_helper.h b/src/core/ozone/egl_helper.h index 6233ef87e4d..6e059baecb4 100644 --- a/src/core/ozone/egl_helper.h +++ b/src/core/ozone/egl_helper.h @@ -25,6 +25,8 @@ QT_BEGIN_NAMESPACE +class QOffscreenSurface; + class EGLHelper { public: @@ -59,7 +61,9 @@ class EGLHelper EGLDisplay m_eglDisplay = EGL_NO_DISPLAY; QScopedPointer m_functions; + QScopedPointer m_offscreenSurface; bool m_isDmaBufSupported = false; + bool m_isCreateDRMImageMesaSupported = false; }; QT_END_NAMESPACE