summaryrefslogtreecommitdiffstats
path: root/src/core/ozone/gl_context_qt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/ozone/gl_context_qt.cpp')
-rw-r--r--src/core/ozone/gl_context_qt.cpp283
1 files changed, 227 insertions, 56 deletions
diff --git a/src/core/ozone/gl_context_qt.cpp b/src/core/ozone/gl_context_qt.cpp
index 8f9093a4e..0042f2bce 100644
--- a/src/core/ozone/gl_context_qt.cpp
+++ b/src/core/ozone/gl_context_qt.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 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
#include "gl_context_qt.h"
@@ -44,10 +8,21 @@
#include <QThread>
#include <QtGui/private/qtgui-config_p.h>
#include <qpa/qplatformnativeinterface.h>
-#include "ui/gl/gl_context_egl.h"
+
#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
+
+#if defined(USE_OZONE)
+#include "ui/gl/egl_util.h"
-#if defined(OS_WIN)
+#include <QOpenGLFunctions>
+#include <QOffscreenSurface>
+
+#include <vector>
+#endif
+
+#if BUILDFLAG(IS_WIN)
+#include "ui/gl/gl_context_egl.h"
#include "ui/gl/gl_context_wgl.h"
#endif
@@ -63,7 +38,8 @@ inline void *resourceForContext(const QByteArray &resource)
#if QT_CONFIG(opengl)
QOpenGLContext *shareContext = qt_gl_global_share_context();
if (!shareContext) {
- qFatal("QWebEngine: OpenGL resource sharing is not set up in QtQuick. Please make sure to call QtWebEngineCore::initialize() in your main() function.");
+ qFatal("QWebEngine: OpenGL resource sharing is not set up in QtQuick. Please make sure to "
+ "call QtWebEngineQuick::initialize() in your main() function.");
}
return qApp->platformNativeInterface()->nativeResourceForContext(resource, shareContext);
#else
@@ -130,7 +106,7 @@ void* GLContextHelper::getGlXConfig()
void* GLContextHelper::getEGLDisplay()
{
-#ifdef Q_OS_WIN
+#if BUILDFLAG(IS_WIN)
// Windows QPA plugin does not implement resourceForIntegration for "egldisplay".
// Use resourceForContext instead.
return resourceForContext(QByteArrayLiteral("egldisplay"));
@@ -199,33 +175,228 @@ bool GLContextHelper::isCreateContextRobustnessSupported()
return contextHelper->m_robustness;
}
+#if QT_CONFIG(opengl) && 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());
+
+ 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"));
+}
+
+EGLHelper *EGLHelper::instance()
+{
+ static EGLHelper eglHelper;
+ return &eglHelper;
+}
+
+EGLHelper::EGLHelper() : m_functions(new EGLHelper::EGLFunctions())
+{
+ const char *extensions = m_functions->eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+ if (!extensions) {
+ qWarning("EGL: Failed to query EGL extensions.");
+ 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.");
+ return;
+ }
+
+ const char *displayExtensions = m_functions->eglQueryString(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_image_dma_buf_export");
+
+ if (m_isDmaBufSupported) {
+ // FIXME: This disables GBM for nvidia. Remove this when nvidia fixes its GBM support.
+ //
+ // "Buffer allocation and submission to DRM KMS using gbm is not currently supported."
+ // See: https://download.nvidia.com/XFree86/Linux-x86_64/550.40.07/README/kms.html
+ //
+ // Chromium uses GBM to allocate scanout buffers. Scanout requires DRM KMS. If KMS is
+ // enabled, gbm_device and gbm_buffer are created without any issues but rendering to the
+ // buffer will malfunction. It is not known how to detect this problem before rendering
+ // so we just disable GBM for nvidia.
+ const char *displayVendor = m_functions->eglQueryString(eglDisplay, EGL_VENDOR);
+ m_isDmaBufSupported = !strstr(displayVendor, "NVIDIA");
+ }
+}
+
+void EGLHelper::queryDmaBuf(const int width, const int height, int *fd, int *stride, int *offset,
+ uint64_t *modifiers)
+{
+ if (!m_isDmaBufSupported)
+ return;
+
+ ScopedGLContext context;
+ if (!context.isValid())
+ return;
+
+ EGLDisplay eglDisplay = context.eglDisplay();
+ EGLContext eglContext = context.eglContext();
+ if (!eglContext) {
+ qWarning("EGL: No EGLContext.");
+ return;
+ }
+
+ 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;
+ }
+
+ 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 false;
+ }
+
+ close(fd);
+ return true;
+}
+#endif // QT_CONFIG(opengl) && defined(USE_OZONE)
+
QT_END_NAMESPACE
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
namespace gl {
namespace init {
-scoped_refptr<GLContext> CreateGLContext(GLShareGroup* share_group,
- GLSurface* compatible_surface,
- const GLContextAttribs& attribs)
+scoped_refptr<GLContext> CreateGLContext(GLShareGroup *share_group,
+ GLSurface *compatible_surface,
+ const GLContextAttribs &attribs)
{
- scoped_refptr<GLContext> context;
- if (GetGLImplementation() == kGLImplementationDesktopGL) {
- context = new GLContextWGL(share_group);
+ switch (GetGLImplementation()) {
+ case kGLImplementationDesktopGLCoreProfile:
+ case kGLImplementationDesktopGL: {
+ scoped_refptr<GLContext> context = new GLContextWGL(share_group);
if (!context->Initialize(compatible_surface, attribs))
return nullptr;
return context;
- } else {
- context = new GLContextEGL(share_group);
}
-
- if (!GLContextHelper::initializeContext(context.get(), compatible_surface, attribs))
+ case kGLImplementationEGLANGLE:
+ case kGLImplementationEGLGLES2:
+ return InitializeGLContext(new GLContextEGL(share_group),
+ compatible_surface, attribs);
+ case kGLImplementationDisabled:
return nullptr;
-
- return context;
+ default:
+ break;
+ }
+ Q_UNREACHABLE();
+ return nullptr;
}
} // namespace init
} // namespace gl
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)