diff options
-rw-r--r-- | src/core/core_gyp_generator.pro | 2 | ||||
-rw-r--r-- | src/core/gl_context_qt.cpp | 62 | ||||
-rw-r--r-- | src/core/gl_context_qt.h | 6 | ||||
-rw-r--r-- | src/core/gl_surface_qt.cpp | 498 | ||||
-rw-r--r-- | src/core/gl_surface_qt.h | 75 | ||||
-rw-r--r-- | src/core/qtwebengine_extras.gypi | 8 |
6 files changed, 647 insertions, 4 deletions
diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index 0e67eb59b..1c2857030 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -51,6 +51,7 @@ SOURCES = \ dev_tools_http_handler_delegate_qt.cpp \ download_manager_delegate_qt.cpp \ gl_context_qt.cpp \ + gl_surface_qt.cpp \ javascript_dialog_controller.cpp \ javascript_dialog_manager_qt.cpp \ media_capture_devices_dispatcher.cpp \ @@ -94,6 +95,7 @@ HEADERS = \ download_manager_delegate_qt.h \ chromium_gpu_helper.h \ gl_context_qt.h \ + gl_surface_qt.h \ javascript_dialog_controller_p.h \ javascript_dialog_controller.h \ javascript_dialog_manager_qt.h \ diff --git a/src/core/gl_context_qt.cpp b/src/core/gl_context_qt.cpp index f440679cf..e0cca2bd8 100644 --- a/src/core/gl_context_qt.cpp +++ b/src/core/gl_context_qt.cpp @@ -45,10 +45,32 @@ #include <QThread> #include "ui/gl/gl_context_egl.h" +#include <private/qopenglcontext_p.h> +#include <private/qsgcontext_p.h> +#include <qpa/qplatformnativeinterface.h> + +#if defined(USE_X11) +#include <X11/Xlib.h> +#endif + QT_BEGIN_NAMESPACE GLContextHelper* GLContextHelper::contextHelper = 0; +namespace { + +inline void *resourceForContext(const QByteArray &resource) +{ + return qApp->platformNativeInterface()->nativeResourceForContext(resource, QOpenGLContextPrivate::globalShareContext()); +} + +inline void *resourceForIntegration(const QByteArray &resource) +{ + return qApp->platformNativeInterface()->nativeResourceForIntegration(resource); +} + +} + void GLContextHelper::initialize() { if (!contextHelper) @@ -77,9 +99,43 @@ bool GLContextHelper::initializeContext(gfx::GLContext* context, gfx::GLSurface* return ret; } +void* GLContextHelper::getEGLConfig() +{ + QByteArray resource = QByteArrayLiteral("eglconfig"); + return resourceForContext(resource); +} + +void* GLContextHelper::getXConfig() +{ + return resourceForContext(QByteArrayLiteral("glxconfig")); +} + +void* GLContextHelper::getEGLDisplay() +{ + return resourceForContext(QByteArrayLiteral("egldisplay")); +} + +void* GLContextHelper::getXDisplay() +{ + void *display = qApp->platformNativeInterface()->nativeResourceForScreen(QByteArrayLiteral("display"), qApp->primaryScreen()); +#if defined(USE_X11) + if (!display) { + // XLib isn't available or has not been initialized, which is a decision we wish to + // support, for example for the GPU process. + display = XOpenDisplay(NULL); + } +#endif + return display; +} + +void* GLContextHelper::getNativeDisplay() +{ + return resourceForIntegration(QByteArrayLiteral("nativedisplay")); +} + QT_END_NAMESPACE -#if defined(USE_OZONE) || defined(OS_ANDROID) +#if defined(USE_OZONE) || defined(OS_ANDROID) || defined(OS_WIN) namespace gfx { @@ -94,6 +150,4 @@ scoped_refptr<GLContext> GLContext::CreateGLContext(GLShareGroup* share_group, G } // namespace gfx -#endif // defined(USE_OZONE) - - +#endif // defined(USE_OZONE) || defined(OS_ANDROID) || defined(OS_WIN) diff --git a/src/core/gl_context_qt.h b/src/core/gl_context_qt.h index 1ad6d2944..0ee6d12dd 100644 --- a/src/core/gl_context_qt.h +++ b/src/core/gl_context_qt.h @@ -58,6 +58,12 @@ public: static void destroy(); static bool initializeContext(gfx::GLContext* context, gfx::GLSurface* surface); + static void* getEGLConfig(); + static void* getXConfig(); + static void* getEGLDisplay(); + static void* getXDisplay(); + static void* getNativeDisplay(); + private: Q_INVOKABLE bool initializeContextOnBrowserThread(gfx::GLContext* context, gfx::GLSurface* surface); diff --git a/src/core/gl_surface_qt.cpp b/src/core/gl_surface_qt.cpp new file mode 100644 index 000000000..d8d306c5c --- /dev/null +++ b/src/core/gl_surface_qt.cpp @@ -0,0 +1,498 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gl_surface_qt.h" + +#if !defined(OS_MACOSX) + +#include <QGuiApplication> +#include <qpa/qplatformnativeinterface.h> +#include "gl_context_qt.h" +#include "qtwebenginecoreglobal.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "content/common/gpu/image_transport_surface.h" +#include "content/common/gpu/gpu_channel_manager.h" +#include "content/common/gpu/gpu_command_buffer_stub.h" +#include "ui/gl/egl_util.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_implementation.h" +#include "ui/gl/gl_surface_egl.h" + +#if defined(USE_X11) +#include "ui/gl/gl_surface_glx.h" + +extern "C" { +#include <X11/Xlib.h> +} +#endif + +using ui::GetLastEGLErrorString; + +namespace gfx { + +namespace { + +void* g_config; +void* g_display; + +const char* g_extensions = NULL; + +} // namespace + + +class GLSurfaceQtEGL: public GLSurfaceQt { +public: + explicit GLSurfaceQtEGL(const gfx::Size& size); + + static bool InitializeOneOff(); + + virtual bool Initialize() Q_DECL_OVERRIDE; + virtual void Destroy() Q_DECL_OVERRIDE; + virtual void* GetHandle() Q_DECL_OVERRIDE; + virtual void* GetShareHandle() Q_DECL_OVERRIDE; + virtual bool Resize(const gfx::Size &size) Q_DECL_OVERRIDE; + +protected: + ~GLSurfaceQtEGL(); + +private: + EGLSurface m_surfaceBuffer; + DISALLOW_COPY_AND_ASSIGN(GLSurfaceQtEGL); +}; + + +GLSurfaceQt::~GLSurfaceQt() +{ +} + +GLSurfaceQtEGL::~GLSurfaceQtEGL() +{ + Destroy(); +} + +#if defined(USE_X11) +class GLSurfaceQtGLX: public GLSurfaceQt { +public: + explicit GLSurfaceQtGLX(const gfx::Size& size); + + static bool InitializeOneOff(); + + virtual bool Initialize() Q_DECL_OVERRIDE; + virtual void Destroy() Q_DECL_OVERRIDE; + virtual void* GetHandle() Q_DECL_OVERRIDE; + +protected: + ~GLSurfaceQtGLX(); + +private: + XID m_surfaceBuffer; + DISALLOW_COPY_AND_ASSIGN(GLSurfaceQtGLX); +}; + +GLSurfaceQtGLX::~GLSurfaceQtGLX() +{ + Destroy(); +} + +bool GLSurfaceGLX::IsCreateContextSupported() +{ + return ExtensionsContain(g_extensions, "GLX_ARB_create_context"); +} + +bool GLSurfaceGLX::HasGLXExtension(const char *name) +{ + return ExtensionsContain(g_extensions, name); +} + +bool GLSurfaceGLX::IsTextureFromPixmapSupported() +{ + return ExtensionsContain(g_extensions, "GLX_EXT_texture_from_pixmap"); +} + +const char* GLSurfaceGLX::GetGLXExtensions() +{ + return g_extensions; +} + +bool GLSurfaceGLX::IsCreateContextRobustnessSupported() +{ + return false; +} + +bool GLSurfaceQtGLX::InitializeOneOff() +{ + static bool initialized = false; + if (initialized) + return true; + + // http://crbug.com/245466 + qputenv("force_s3tc_enable", "true"); + + XInitThreads(); + + g_display = GLContextHelper::getXDisplay(); + if (!g_display) { + LOG(ERROR) << "GLContextHelper::getXDisplay() failed."; + return false; + } + + g_config = GLContextHelper::getXConfig(); + if (!g_config) { + LOG(ERROR) << "GLContextHelper::getXConfig() failed."; + return false; + } + + Display* display = static_cast<Display*>(g_display); + int major, minor; + if (!glXQueryVersion(display, &major, &minor)) { + LOG(ERROR) << "glxQueryVersion failed."; + return false; + } + + if (major == 1 && minor < 3) { + LOG(ERROR) << "GLX 1.3 or later is required."; + return false; + } + + g_extensions = glXQueryExtensionsString(display, 0); + initialized = true; + return true; +} + +bool GLSurfaceQtGLX::Initialize() +{ + Q_ASSERT(!m_surfaceBuffer); + + Display* display = static_cast<Display*>(g_display); + const int pbuffer_attributes[] = { + GLX_PBUFFER_WIDTH, m_size.width(), + GLX_PBUFFER_HEIGHT, m_size.height(), + GLX_LARGEST_PBUFFER, False, + GLX_PRESERVED_CONTENTS, False, + GLX_NONE + }; + + m_surfaceBuffer = glXCreatePbuffer(display, static_cast<GLXFBConfig>(g_config), pbuffer_attributes); + + if (!m_surfaceBuffer) { + Destroy(); + LOG(ERROR) << "glXCreatePbuffer failed."; + return false; + } + return true; +} + +void GLSurfaceQtGLX::Destroy() +{ + if (m_surfaceBuffer) { + glXDestroyPbuffer(static_cast<Display*>(g_display), m_surfaceBuffer); + m_surfaceBuffer = 0; + } +} + +GLSurfaceQtGLX::GLSurfaceQtGLX(const gfx::Size& size) + : GLSurfaceQt(size), + m_surfaceBuffer(0) +{ +} + +void* GLSurfaceQtGLX::GetHandle() +{ + return reinterpret_cast<void*>(m_surfaceBuffer); +} + +#endif // defined(USE_X11) + +GLSurfaceQt::GLSurfaceQt() +{ +} + +bool GLSurfaceQtEGL::InitializeOneOff() +{ + static bool initialized = false; + if (initialized) + return true; + +#if defined(USE_X11) + EGLNativeDisplayType nativeDisplay = reinterpret_cast<EGLNativeDisplayType>(GLContextHelper::getXDisplay()); + g_display = eglGetDisplay(nativeDisplay); +#else + g_display = GLContextHelper::getEGLDisplay(); +#endif + + if (!g_display) { + LOG(ERROR) << "GLContextHelper::getEGLDisplay() failed."; + return false; + } + + g_config = GLContextHelper::getEGLConfig(); + if (!g_config) { + LOG(ERROR) << "GLContextHelper::getEGLConfig() failed."; + return false; + } + + g_extensions = eglQueryString(g_display, EGL_EXTENSIONS); + if (!eglInitialize(g_display, NULL, NULL)) { + LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString(); + return false; + } + + initialized = true; + return true; +} + +bool GLSurface::InitializeOneOffInternal() +{ + if (GetGLImplementation() == kGLImplementationOSMesaGL) + return false; + + if (GetGLImplementation() == kGLImplementationEGLGLES2) + return GLSurfaceQtEGL::InitializeOneOff(); + +#if defined(USE_X11) + if (GetGLImplementation() == kGLImplementationDesktopGL) + return GLSurfaceQtGLX::InitializeOneOff(); +#endif + + return false; +} + +EGLDisplay GLSurfaceEGL::GetHardwareDisplay() +{ + return static_cast<EGLDisplay>(g_display); +} + +bool GLSurfaceEGL::IsCreateContextRobustnessSupported() +{ + return false; +} + +GLSurfaceQt::GLSurfaceQt(const gfx::Size& size) + : m_size(size) +{ +} + +GLSurfaceQtEGL::GLSurfaceQtEGL(const gfx::Size& size) + : GLSurfaceQt(size), + m_surfaceBuffer(0) +{ +} + +bool GLSurfaceQtEGL::Initialize() +{ + Q_ASSERT(!m_surfaceBuffer); + + EGLDisplay display = g_display; + if (!display) { + LOG(ERROR) << "Trying to create surface with invalid display."; + return false; + } + + if (m_size.GetArea() == 0) { + LOG(ERROR) << "Error: surface has zero area" + << m_size.width() << " x " << m_size.height(); + return false; + } + + const EGLint pbuffer_attributes[] = { + EGL_WIDTH, m_size.width(), + EGL_HEIGHT, m_size.height(), + EGL_LARGEST_PBUFFER, EGL_FALSE, + EGL_NONE + }; + + m_surfaceBuffer = eglCreatePbufferSurface(display, + g_config, + pbuffer_attributes); + if (!m_surfaceBuffer) { + LOG(ERROR) << "eglCreatePbufferSurface failed with error ", GetLastEGLErrorString(); + Destroy(); + return false; + } + + return true; +} + +void GLSurfaceQtEGL::Destroy() +{ + if (m_surfaceBuffer) { + if (!eglDestroySurface(g_display, m_surfaceBuffer)) + LOG(ERROR) << "eglDestroySurface failed with error " << GetLastEGLErrorString(); + + m_surfaceBuffer = 0; + } +} + +bool GLSurfaceQt::IsOffscreen() +{ + return true; +} + +bool GLSurfaceQt::SwapBuffers() +{ + LOG(ERROR) << "Attempted to call SwapBuffers on a pbuffer."; + Q_UNREACHABLE(); + return false; +} + +gfx::Size GLSurfaceQt::GetSize() +{ + return m_size; +} + +bool GLSurfaceQtEGL::Resize(const gfx::Size& size) +{ + if (size == m_size) + return true; + + GLContext *currentContext = GLContext::GetCurrent(); + bool wasCurrent = currentContext && currentContext->IsCurrent(this); + if (wasCurrent) + currentContext->ReleaseCurrent(this); + + Destroy(); + + m_size = size; + + if (!Initialize()) { + LOG(ERROR) << "Failed to resize pbuffer."; + return false; + } + + if (wasCurrent) + return currentContext->MakeCurrent(this); + + return true; +} + +void* GLSurfaceQtEGL::GetHandle() +{ + return reinterpret_cast<void*>(m_surfaceBuffer); +} + +void* GLSurfaceQtEGL::GetShareHandle() +{ +#if defined(OS_ANDROID) + Q_UNREACHABLE(); + return NULL; +#else + if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_query_surface_pointer) + return NULL; + + if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle) + return NULL; + + void* handle; + if (!eglQuerySurfacePointerANGLE(g_display, + GetHandle(), + EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, + &handle)) { + return NULL; + } + + return handle; +#endif +} + +void* GLSurfaceQt::GetDisplay() +{ + return g_display; +} + +void* GLSurfaceQt::GetConfig() +{ + return g_config; +} + +// static +scoped_refptr<GLSurface> +GLSurface::CreateOffscreenGLSurface(const gfx::Size& size) +{ + switch (GetGLImplementation()) { + case kGLImplementationDesktopGL: { +#if defined(USE_X11) + scoped_refptr<GLSurface> surface = new GLSurfaceQtGLX(size); + if (!surface->Initialize()) + return NULL; + return surface; +#else + LOG(ERROR) << "Desktop GL is not supported on this platform."; + Q_UNREACHABLE(); + return NULL; +#endif + } + case kGLImplementationEGLGLES2: { + scoped_refptr<GLSurface> surface = new GLSurfaceQtEGL(size); + if (!surface->Initialize()) + return NULL; + return surface; + } + default: + Q_UNREACHABLE(); + return NULL; + } +} + +// static +scoped_refptr<GLSurface> +GLSurface::CreateViewGLSurface(gfx::AcceleratedWidget window) +{ + QT_NOT_USED + return NULL; +} + +} // namespace gfx + +namespace content { +scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(GpuChannelManager* manager, GpuCommandBufferStub* stub, const gfx::GLSurfaceHandle& handle) +{ + QT_NOT_USED + return scoped_refptr<gfx::GLSurface>(); +} +} + +#endif // !defined(OS_MACOSX) diff --git a/src/core/gl_surface_qt.h b/src/core/gl_surface_qt.h new file mode 100644 index 000000000..010f7064a --- /dev/null +++ b/src/core/gl_surface_qt.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GL_SURFACE_QT_H_ +#define GL_SURFACE_QT_H_ + +#include "ui/gfx/size.h" +#include "ui/gl/gl_surface.h" + +#include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE + +namespace gfx { + +class GLSurfaceQt: public GLSurface { +public: + explicit GLSurfaceQt(const gfx::Size& size); + + // Implement GLSurface. + virtual void* GetDisplay() Q_DECL_OVERRIDE; + virtual void* GetConfig() Q_DECL_OVERRIDE; + virtual bool IsOffscreen() Q_DECL_OVERRIDE; + virtual bool SwapBuffers() Q_DECL_OVERRIDE; + virtual gfx::Size GetSize() Q_DECL_OVERRIDE; + +protected: + GLSurfaceQt(); + virtual ~GLSurfaceQt(); + + gfx::Size m_size; + +private: + DISALLOW_COPY_AND_ASSIGN(GLSurfaceQt); +}; + +} + +#endif diff --git a/src/core/qtwebengine_extras.gypi b/src/core/qtwebengine_extras.gypi index d6c116bf3..eafe5bc28 100644 --- a/src/core/qtwebengine_extras.gypi +++ b/src/core/qtwebengine_extras.gypi @@ -40,6 +40,14 @@ ['exclude', 'browser/accessibility/browser_accessibility_manager_android\\.(cc|h)$'], ['exclude', 'browser/accessibility/browser_accessibility_manager_gtk\\.(cc|h)$'], ['exclude', 'browser/accessibility/browser_accessibility_manager_mac\\.(cc|h)$'], + ['exclude', 'command_buffer/service/async_pixel_transfer_manager_egl\\.(cc|h)$'], + ['exclude', 'common/gpu/image_transport_surface_android\\.cc$'], + ['exclude', 'common/gpu/image_transport_surface_linux\\.cc$'], + ['exclude', 'common/gpu/image_transport_surface_win\\.cc$'], + ['exclude', 'gl_surface_egl\\.cc$'], + ['exclude', 'gl_surface_glx\\.cc$'], + ['exclude', 'gl_surface_x11\\.cc$'], + ['exclude', 'gl_surface_win\\.cc$'], ], 'defines': [ 'TOOLKIT_QT', |