| 1 | https://codereview.qt-project.org/c/qt/qtwebengine/+/675112
|
| 2 | From 3cc88e0f85113e38ccb1bfdadb7d150c2389b1bc Mon Sep 17 00:00:00 2001
|
| 3 | From: Moss Heim <[email protected]>
|
| 4 | Date: Thu, 11 Sep 2025 13:47:04 +0200
|
| 5 | Subject: [PATCH] Return to supporting eglCreateImage in EGLHelper::queryDmaBuf
|
| 6 |
|
| 7 | eglCreateDRMImageMESA was removed in mesa 25.2.
|
| 8 | Keep using it where we can since this fixes support for
|
| 9 | panthor/panfrost, otherwise fall back to the old use of EGL API.
|
| 10 |
|
| 11 | Includes a revert of the following commits:
|
| 12 | Revert "Create EGLImage with eglCreateDRMImageMESA() for exporting dma_buf"
|
| 13 | This reverts commit 2ed5f9632292c6e531f353dae800cb12274af91a.
|
| 14 | Revert "Remove leftover QOffscreenSurface from EGLHelper"
|
| 15 | This reverts commit bcee2dbf412cc655c1b467091b581c696d234e3f.
|
| 16 |
|
| 17 | Pick-to: 6.9 6.10 6.10.0
|
| 18 | Task-number: QTBUG-136257
|
| 19 | Task-number: QTBUG-139424
|
| 20 | Change-Id: Ie115bd6373ce0a80651781aa568405477010ee25
|
| 21 | Reviewed-by: Peter Varga <[email protected]>
|
| 22 | ---
|
| 23 | src/core/ozone/egl_helper.cpp | 142 +++++++++++++++++++++++++++++++---
|
| 24 | src/core/ozone/egl_helper.h | 4 +
|
| 25 | 2 files changed, 134 insertions(+), 12 deletions(-)
|
| 26 |
|
| 27 | diff --git a/src/core/ozone/egl_helper.cpp b/src/core/ozone/egl_helper.cpp
|
| 28 | index 76e1c2a4663..68e45ffd446 100644
|
| 29 | |
| 30 | |
| 31 | @@ -3,10 +3,14 @@
|
| 32 | // Qt-Security score:significant reason:default
|
| 33 |
|
| 34 | #include "egl_helper.h"
|
| 35 | +
|
| 36 | +#include "compositor/compositor.h"
|
| 37 | #include "ozone_util_qt.h"
|
| 38 | #include "web_engine_context.h"
|
| 39 |
|
| 40 | +#include <QtCore/qthread.h>
|
| 41 | #include <QtGui/qguiapplication.h>
|
| 42 | +#include <QtGui/qoffscreensurface.h>
|
| 43 | #include <QtGui/qopenglcontext.h>
|
| 44 | #include <QtGui/qopenglfunctions.h>
|
| 45 | #include <qpa/qplatformnativeinterface.h>
|
| 46 | @@ -57,6 +61,84 @@ static const char *getEGLErrorString(uint32_t error)
|
| 47 |
|
| 48 | QT_BEGIN_NAMESPACE
|
| 49 |
|
| 50 | +class ScopedGLContext
|
| 51 | +{
|
| 52 | +public:
|
| 53 | + ScopedGLContext(QOffscreenSurface *surface, EGLHelper::EGLFunctions *eglFun)
|
| 54 | + : m_context(new QOpenGLContext()), m_eglFun(eglFun)
|
| 55 | + {
|
| 56 | + if ((m_previousEGLContext = m_eglFun->eglGetCurrentContext())) {
|
| 57 | + m_previousEGLDrawSurface = m_eglFun->eglGetCurrentSurface(EGL_DRAW);
|
| 58 | + m_previousEGLReadSurface = m_eglFun->eglGetCurrentSurface(EGL_READ);
|
| 59 | + m_previousEGLDisplay = m_eglFun->eglGetCurrentDisplay();
|
| 60 | + }
|
| 61 | +
|
| 62 | + if (!m_context->create()) {
|
| 63 | + qWarning("Failed to create OpenGL context.");
|
| 64 | + return;
|
| 65 | + }
|
| 66 | +
|
| 67 | + Q_ASSERT(surface->isValid());
|
| 68 | + if (!m_context->makeCurrent(surface)) {
|
| 69 | + qWarning("Failed to make OpenGL context current.");
|
| 70 | + return;
|
| 71 | + }
|
| 72 | + }
|
| 73 | +
|
| 74 | + ~ScopedGLContext()
|
| 75 | + {
|
| 76 | + if (!m_textures.empty()) {
|
| 77 | + auto *glFun = m_context->functions();
|
| 78 | + glFun->glDeleteTextures(m_textures.size(), m_textures.data());
|
| 79 | + }
|
| 80 | +
|
| 81 | + if (m_previousEGLContext) {
|
| 82 | + // Make sure the scoped context is not current when restoring the previous
|
| 83 | + // EGL context otherwise the QOpenGLContext destructor resets the restored
|
| 84 | + // current context.
|
| 85 | + m_context->doneCurrent();
|
| 86 | +
|
| 87 | + m_eglFun->eglMakeCurrent(m_previousEGLDisplay, m_previousEGLDrawSurface,
|
| 88 | + m_previousEGLReadSurface, m_previousEGLContext);
|
| 89 | + if (m_eglFun->eglGetError() != EGL_SUCCESS)
|
| 90 | + qWarning("Failed to restore EGL context.");
|
| 91 | + }
|
| 92 | + }
|
| 93 | +
|
| 94 | + bool isValid() const { return m_context->isValid() && (m_context->surface() != nullptr); }
|
| 95 | +
|
| 96 | + EGLContext eglContext() const
|
| 97 | + {
|
| 98 | + QNativeInterface::QEGLContext *nativeInterface =
|
| 99 | + m_context->nativeInterface<QNativeInterface::QEGLContext>();
|
| 100 | + return nativeInterface->nativeContext();
|
| 101 | + }
|
| 102 | +
|
| 103 | + uint createTexture(int width, int height)
|
| 104 | + {
|
| 105 | + auto *glFun = m_context->functions();
|
| 106 | +
|
| 107 | + uint glTexture;
|
| 108 | + glFun->glGenTextures(1, &glTexture);
|
| 109 | + glFun->glBindTexture(GL_TEXTURE_2D, glTexture);
|
| 110 | + glFun->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
| 111 | + NULL);
|
| 112 | + glFun->glBindTexture(GL_TEXTURE_2D, 0);
|
| 113 | +
|
| 114 | + m_textures.push_back(glTexture);
|
| 115 | + return glTexture;
|
| 116 | + }
|
| 117 | +
|
| 118 | +private:
|
| 119 | + QScopedPointer<QOpenGLContext> m_context;
|
| 120 | + EGLHelper::EGLFunctions *m_eglFun;
|
| 121 | + EGLContext m_previousEGLContext = nullptr;
|
| 122 | + EGLSurface m_previousEGLDrawSurface = nullptr;
|
| 123 | + EGLSurface m_previousEGLReadSurface = nullptr;
|
| 124 | + EGLDisplay m_previousEGLDisplay = nullptr;
|
| 125 | + std::vector<uint> m_textures;
|
| 126 | +};
|
| 127 | +
|
| 128 | EGLHelper::EGLFunctions::EGLFunctions()
|
| 129 | {
|
| 130 | QOpenGLContext *context = OzoneUtilQt::getQOpenGLContext();
|
| 131 | @@ -117,8 +199,23 @@ EGLHelper::EGLHelper()
|
| 132 | const char *displayExtensions = m_functions->eglQueryString(m_eglDisplay, EGL_EXTENSIONS);
|
| 133 | m_isDmaBufSupported = strstr(displayExtensions, "EGL_EXT_image_dma_buf_import")
|
| 134 | && strstr(displayExtensions, "EGL_EXT_image_dma_buf_import_modifiers")
|
| 135 | - && strstr(displayExtensions, "EGL_MESA_drm_image")
|
| 136 | && strstr(displayExtensions, "EGL_MESA_image_dma_buf_export");
|
| 137 | + m_isCreateDRMImageMesaSupported = strstr(displayExtensions, "EGL_MESA_drm_image");
|
| 138 | + if (!m_isDmaBufSupported) {
|
| 139 | + qCDebug(QtWebEngineCore::lcWebEngineCompositor,
|
| 140 | + "EGL: MESA extensions not found, will not use dma-buf");
|
| 141 | + } else if (!m_isCreateDRMImageMesaSupported) {
|
| 142 | + qCDebug(QtWebEngineCore::lcWebEngineCompositor,
|
| 143 | + "EGL: MESA extensions found but missing EGL_MESA_drm_image, will use dma-buf, "
|
| 144 | + "some older graphics cards may not be supported");
|
| 145 | + m_offscreenSurface.reset(new QOffscreenSurface());
|
| 146 | + Q_ASSERT(QThread::currentThread() == qApp->thread());
|
| 147 | + m_offscreenSurface->create();
|
| 148 | + } else {
|
| 149 | + qCDebug(QtWebEngineCore::lcWebEngineCompositor,
|
| 150 | + "EGL: MESA extensions and EGL_MESA_drm_image found, will use dma-buf with GEM "
|
| 151 | + "buffer allocation");
|
| 152 | + }
|
| 153 | }
|
| 154 |
|
| 155 | // Try to create dma-buf.
|
| 156 | @@ -138,17 +235,38 @@ void EGLHelper::queryDmaBuf(const int width, const int height, int *fd, int *str
|
| 157 | if (!m_isDmaBufSupported)
|
| 158 | return;
|
| 159 |
|
| 160 | - // clang-format off
|
| 161 | - EGLint attribs[] = {
|
| 162 | - EGL_WIDTH, width,
|
| 163 | - EGL_HEIGHT, height,
|
| 164 | - EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
|
| 165 | - EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SHARE_MESA,
|
| 166 | - EGL_NONE
|
| 167 | - };
|
| 168 | - // clang-format on
|
| 169 | -
|
| 170 | - EGLImage eglImage = m_functions->eglCreateDRMImageMESA(m_eglDisplay, attribs);
|
| 171 | + EGLImage eglImage = EGL_NO_IMAGE;
|
| 172 | + // Probably doesn't need to live to the end of the function, but just in case.
|
| 173 | + std::unique_ptr<ScopedGLContext> glContext;
|
| 174 | + if (m_isCreateDRMImageMesaSupported) {
|
| 175 | + // This approach is slightly worse for security and no longer supported in mesa 25.2,
|
| 176 | + // but it allows us to keep support for the Panthor driver prior to that mesa version.
|
| 177 | + // clang-format off
|
| 178 | + EGLint attribs[] = {
|
| 179 | + EGL_WIDTH, width,
|
| 180 | + EGL_HEIGHT, height,
|
| 181 | + EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
|
| 182 | + EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SHARE_MESA,
|
| 183 | + EGL_NONE
|
| 184 | + };
|
| 185 | + // clang-format on
|
| 186 | + eglImage = m_functions->eglCreateDRMImageMESA(m_eglDisplay, attribs);
|
| 187 | + } else {
|
| 188 | + glContext = std::make_unique<ScopedGLContext>(m_offscreenSurface.get(), m_functions.get());
|
| 189 | + if (!glContext->isValid())
|
| 190 | + return;
|
| 191 | +
|
| 192 | + EGLContext eglContext = glContext->eglContext();
|
| 193 | + if (!eglContext) {
|
| 194 | + qWarning("EGL: No EGLContext.");
|
| 195 | + return;
|
| 196 | + }
|
| 197 | +
|
| 198 | + uint64_t textureId = glContext->createTexture(width, height);
|
| 199 | + eglImage = m_functions->eglCreateImage(m_eglDisplay, eglContext, EGL_GL_TEXTURE_2D,
|
| 200 | + (EGLClientBuffer)textureId, NULL);
|
| 201 | + }
|
| 202 | +
|
| 203 | if (eglImage == EGL_NO_IMAGE) {
|
| 204 | qWarning("EGL: Failed to create EGLImage: %s", getLastEGLErrorString());
|
| 205 | return;
|
| 206 | diff --git a/src/core/ozone/egl_helper.h b/src/core/ozone/egl_helper.h
|
| 207 | index 6233ef87e4d..6e059baecb4 100644
|
| 208 | |
| 209 | |
| 210 | @@ -25,6 +25,8 @@
|
| 211 |
|
| 212 | QT_BEGIN_NAMESPACE
|
| 213 |
|
| 214 | +class QOffscreenSurface;
|
| 215 | +
|
| 216 | class EGLHelper
|
| 217 | {
|
| 218 | public:
|
| 219 | @@ -59,7 +61,9 @@ class EGLHelper
|
| 220 |
|
| 221 | EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
|
| 222 | QScopedPointer<EGLFunctions> m_functions;
|
| 223 | + QScopedPointer<QOffscreenSurface> m_offscreenSurface;
|
| 224 | bool m_isDmaBufSupported = false;
|
| 225 | + bool m_isCreateDRMImageMesaSupported = false;
|
| 226 | };
|
| 227 |
|
| 228 | QT_END_NAMESPACE
|