@@ 0,0 1,228 @@
+https://codereview.qt-project.org/c/qt/qtwebengine/+/675112
+From 3cc88e0f85113e38ccb1bfdadb7d150c2389b1bc Mon Sep 17 00:00:00 2001
+From: Moss Heim <moss.heim@qt.io>
+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 <pvarga@inf.u-szeged.hu>
+---
+ 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 <QtCore/qthread.h>
+ #include <QtGui/qguiapplication.h>
++#include <QtGui/qoffscreensurface.h>
+ #include <QtGui/qopenglcontext.h>
+ #include <QtGui/qopenglfunctions.h>
+ #include <qpa/qplatformnativeinterface.h>
+@@ -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<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;
++ EGLHelper::EGLFunctions *m_eglFun;
++ EGLContext m_previousEGLContext = nullptr;
++ EGLSurface m_previousEGLDrawSurface = nullptr;
++ EGLSurface m_previousEGLReadSurface = nullptr;
++ EGLDisplay m_previousEGLDisplay = nullptr;
++ std::vector<uint> 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<ScopedGLContext> 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<ScopedGLContext>(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<EGLFunctions> m_functions;
++ QScopedPointer<QOffscreenSurface> m_offscreenSurface;
+ bool m_isDmaBufSupported = false;
++ bool m_isCreateDRMImageMesaSupported = false;
+ };
+
+ QT_END_NAMESPACE