summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp')
-rw-r--r--Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp282
1 files changed, 149 insertions, 133 deletions
diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
index a0b76cc88..7f2f07b60 100644
--- a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
+++ b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
@@ -19,13 +19,7 @@
#include "config.h"
#include "GraphicsContext3D.h"
-#if ENABLE(GRAPHICS_CONTEXT_3D)
-
-#if USE(OPENGL_ES_2)
-#include "Extensions3DOpenGLES.h"
-#else
-#include "Extensions3DOpenGL.h"
-#endif
+#include "Extensions3DOpenGLCommon.h"
#include "GraphicsContext.h"
#include "GraphicsSurface.h"
#include "HostWindow.h"
@@ -33,32 +27,51 @@
#include "ImageData.h"
#include "NativeImageQt.h"
#include "NotImplemented.h"
-#include "OpenGLShims.h"
#include "QWebPageClient.h"
#include "SharedBuffer.h"
#include "TextureMapperPlatformLayer.h"
+#include <QOffscreenSurface>
+#include <private/qopenglextensions_p.h>
#include <qpa/qplatformpixmap.h>
#include <wtf/text/CString.h>
-#include <QOffscreenSurface>
-
#if USE(TEXTURE_MAPPER_GL)
#include <texmap/TextureMapperGL.h>
#endif
+#if ENABLE(GRAPHICS_CONTEXT_3D)
+
+QT_BEGIN_NAMESPACE
+extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize&, bool alpha_format, bool include_alpha);
+QT_END_NAMESPACE
+
namespace WebCore {
#if !defined(GLchar)
typedef char GLchar;
#endif
-#if !defined(GL_DEPTH24_STENCIL8)
-#define GL_DEPTH24_STENCIL8 0x88F0
+#ifndef GL_VERTEX_PROGRAM_POINT_SIZE
+#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
#endif
-class GraphicsContext3DPrivate final
- : public TextureMapperPlatformLayer
-{
+#ifndef GL_POINT_SPRITE
+#define GL_POINT_SPRITE 0x8861
+#endif
+
+#ifndef GL_DEPTH24_STENCIL8
+#define GL_DEPTH24_STENCIL8 0x88F0
+#endif
+
+#ifndef GL_READ_FRAMEBUFFER
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#endif
+
+#ifndef GL_DRAW_FRAMEBUFFER
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#endif
+
+class GraphicsContext3DPrivate final : public TextureMapperPlatformLayer, public QOpenGLExtensions {
public:
GraphicsContext3DPrivate(GraphicsContext3D*, HostWindow*, GraphicsContext3D::RenderStyle);
~GraphicsContext3DPrivate();
@@ -71,13 +84,16 @@ public:
#endif
QRectF boundingRect() const;
- void blitMultisampleFramebuffer() const;
- void blitMultisampleFramebufferAndRestoreContext() const;
+ void blitMultisampleFramebuffer();
+ void blitMultisampleFramebufferAndRestoreContext();
bool makeCurrentIfNeeded() const;
void createOffscreenBuffers();
void initializeANGLE();
void createGraphicsSurfaces(const IntSize&);
+ bool isOpenGLES() const;
+ bool isValid() const;
+
GraphicsContext3D* m_context;
HostWindow* m_hostWindow;
PlatformGraphicsSurface3D m_surface;
@@ -87,10 +103,43 @@ public:
GraphicsSurface::Flags m_surfaceFlags;
RefPtr<GraphicsSurface> m_graphicsSurface;
#endif
+
+ // Register as a child of a Qt context to make the necessary when it may be destroyed before the GraphicsContext3D instance
+ class QtContextWatcher : public QObject {
+ public:
+ QtContextWatcher(QObject* ctx, GraphicsContext3DPrivate* watcher)
+ : QObject(ctx), m_watcher(watcher) { }
+ ~QtContextWatcher() { m_watcher->m_platformContext = 0; m_watcher->m_platformContextWatcher = 0; }
+
+ private:
+ GraphicsContext3DPrivate* m_watcher;
+ };
+ QtContextWatcher* m_platformContextWatcher;
};
+bool GraphicsContext3DPrivate::isOpenGLES() const
+{
+ if (m_platformContext)
+ return m_platformContext->isOpenGLES();
+#if USE(OPENGL_ES_2)
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool GraphicsContext3DPrivate::isValid() const
+{
+ if (!m_platformContext || !m_platformContext->isValid())
+ return false;
+ return m_platformContext->isOpenGLES() || m_platformContext->format().majorVersion() >= 2;
+}
+
bool GraphicsContext3D::isGLES2Compliant() const
{
+ if (m_private)
+ return m_private->isOpenGLES();
+ ASSERT_NOT_REACHED();
#if USE(OPENGL_ES_2)
return true;
#else
@@ -104,17 +153,23 @@ GraphicsContext3DPrivate::GraphicsContext3DPrivate(GraphicsContext3D* context, H
, m_surface(0)
, m_platformContext(0)
, m_surfaceOwner(0)
+ , m_platformContextWatcher(0)
{
if (renderStyle == GraphicsContext3D::RenderToCurrentGLContext) {
m_platformContext = QOpenGLContext::currentContext();
if (m_platformContext)
m_surface = m_platformContext->surface();
+
+ // Watcher needed to invalidate the GL context if destroyed before this instance
+ m_platformContextWatcher = new QtContextWatcher(m_platformContext, this);
+
+ initializeOpenGLFunctions();
return;
}
QOpenGLContext* shareContext = 0;
- if (hostWindow && hostWindow->platformPageClient() && hostWindow->platformPageClient()->makeOpenGLContextCurrentIfAvailable())
- shareContext = QOpenGLContext::currentContext();
+ if (hostWindow && hostWindow->platformPageClient())
+ shareContext = hostWindow->platformPageClient()->openGLContextIfAvailable();
QOffscreenSurface* surface = new QOffscreenSurface;
surface->create();
@@ -125,15 +180,18 @@ GraphicsContext3DPrivate::GraphicsContext3DPrivate(GraphicsContext3D* context, H
if (shareContext)
m_platformContext->setShareContext(shareContext);
- if (!m_platformContext->create())
+ if (!m_platformContext->create()) {
+ delete m_platformContext;
+ m_platformContext = 0;
return;
+ }
makeCurrentIfNeeded();
+ initializeOpenGLFunctions();
#if USE(GRAPHICS_SURFACE)
IntSize surfaceSize(m_context->m_currentWidth, m_context->m_currentHeight);
- m_surfaceFlags = GraphicsSurface::SupportsTextureTarget
- | GraphicsSurface::SupportsSharing;
+ m_surfaceFlags = GraphicsSurface::SupportsTextureTarget | GraphicsSurface::SupportsSharing;
if (!surfaceSize.isEmpty())
m_graphicsSurface = GraphicsSurface::create(surfaceSize, m_surfaceFlags, m_platformContext);
@@ -145,31 +203,31 @@ void GraphicsContext3DPrivate::createOffscreenBuffers()
glGenFramebuffers(/* count */ 1, &m_context->m_fbo);
glGenTextures(1, &m_context->m_texture);
- glBindTexture(GraphicsContext3D::TEXTURE_2D, m_context->m_texture);
- glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
- glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
- glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
- glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
- glBindTexture(GraphicsContext3D::TEXTURE_2D, 0);
+ glBindTexture(GL_TEXTURE_2D, m_context->m_texture);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
// Create a multisample FBO.
if (m_context->m_attrs.antialias) {
glGenFramebuffers(1, &m_context->m_multisampleFBO);
- glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_multisampleFBO);
+ glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_multisampleFBO);
m_context->m_state.boundFBO = m_context->m_multisampleFBO;
glGenRenderbuffers(1, &m_context->m_multisampleColorBuffer);
if (m_context->m_attrs.stencil || m_context->m_attrs.depth)
glGenRenderbuffers(1, &m_context->m_multisampleDepthStencilBuffer);
} else {
// Bind canvas FBO.
- glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_fbo);
m_context->m_state.boundFBO = m_context->m_fbo;
-#if USE(OPENGL_ES_2)
- if (m_context->m_attrs.depth)
- glGenRenderbuffers(1, &m_context->m_depthBuffer);
- if (m_context->m_attrs.stencil)
- glGenRenderbuffers(1, &m_context->m_stencilBuffer);
-#endif
+ if (isOpenGLES()) {
+ if (m_context->m_attrs.depth)
+ glGenRenderbuffers(1, &m_context->m_depthBuffer);
+ if (m_context->m_attrs.stencil)
+ glGenRenderbuffers(1, &m_context->m_stencilBuffer);
+ }
if (m_context->m_attrs.stencil || m_context->m_attrs.depth)
glGenRenderbuffers(1, &m_context->m_depthStencilBuffer);
}
@@ -206,11 +264,9 @@ GraphicsContext3DPrivate::~GraphicsContext3DPrivate()
{
delete m_surfaceOwner;
m_surfaceOwner = 0;
-}
-static inline quint32 swapBgrToRgb(quint32 pixel)
-{
- return (((pixel << 16) | (pixel >> 16)) & 0x00ff00ff) | (pixel & 0xff00ff00);
+ delete m_platformContextWatcher;
+ m_platformContextWatcher = 0;
}
void GraphicsContext3DPrivate::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity)
@@ -218,34 +274,15 @@ void GraphicsContext3DPrivate::paintToTextureMapper(TextureMapper& textureMapper
m_context->markLayerComposited();
blitMultisampleFramebufferAndRestoreContext();
- // FIXME: For now we have OpenGLMode only
-// if (textureMapper->accelerationMode() == TextureMapper::OpenGLMode) {
+ if (textureMapper.accelerationMode() == TextureMapper::OpenGLMode) {
TextureMapperGL& texmapGL = static_cast<TextureMapperGL&>(textureMapper);
-#if USE(GRAPHICS_SURFACE)
- ASSERT(m_graphicsSurface);
- // CGL only provides us the context, but not the view the context is currently bound to.
- // To make sure the context is bound the the right surface we have to do a makeCurrent through QOpenGL again.
- // FIXME: Remove this code as soon as GraphicsSurfaceMac makes use of NSOpenGL.
- QOpenGLContext* currentContext = QOpenGLContext::currentContext();
- QSurface* currentSurface = currentContext->surface();
- makeCurrentIfNeeded();
-
- m_graphicsSurface->copyFromTexture(m_context->m_texture, IntRect(0, 0, m_context->m_currentWidth, m_context->m_currentHeight));
-
- // CGL only provides us the context, but not the view the context is currently bound to.
- // To make sure the context is bound the the right surface we have to do a makeCurrent through QOpenGL again.
- // FIXME: Remove this code as soon as GraphicsSurfaceMac makes use of NSOpenGL.
- currentContext->makeCurrent(currentSurface);
-
- m_graphicsSurface->paintToTextureMapper(texmapGL, targetRect, matrix, opacity);
-#else
TextureMapperGL::Flags flags = TextureMapperGL::ShouldFlipTexture | (m_context->m_attrs.alpha ? TextureMapperGL::ShouldBlend : 0);
IntSize textureSize(m_context->m_currentWidth, m_context->m_currentHeight);
texmapGL.drawTexture(m_context->m_texture, flags, textureSize, targetRect, matrix, opacity);
-#endif
return;
-// }
+ }
+ // Alternatively read pixels to a memory buffer.
GraphicsContext* context = textureMapper.graphicsContext();
QPainter* painter = context->platformContext();
painter->save();
@@ -255,36 +292,13 @@ void GraphicsContext3DPrivate::paintToTextureMapper(TextureMapper& textureMapper
const int height = m_context->m_currentHeight;
const int width = m_context->m_currentWidth;
- // Alternatively read pixels to a memory buffer.
- QImage offscreenImage(width, height, QImage::Format_ARGB32);
- quint32* imagePixels = reinterpret_cast<quint32*>(offscreenImage.bits());
-
+ painter->beginNativePainting();
makeCurrentIfNeeded();
- glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_fbo);
- glReadPixels(/* x */ 0, /* y */ 0, width, height, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, imagePixels);
- glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_state.boundFBO);
-
- // OpenGL gives us ABGR on 32 bits, and with the origin at the bottom left
- // We need RGB32 or ARGB32_PM, with the origin at the top left.
- quint32* pixelsSrc = imagePixels;
- const int halfHeight = height / 2;
- for (int row = 0; row < halfHeight; ++row) {
- const int targetIdx = (height - 1 - row) * width;
- quint32* pixelsDst = imagePixels + targetIdx;
- for (int column = 0; column < width; ++column) {
- quint32 tempPixel = *pixelsSrc;
- *pixelsSrc = swapBgrToRgb(*pixelsDst);
- *pixelsDst = swapBgrToRgb(tempPixel);
- ++pixelsSrc;
- ++pixelsDst;
- }
- }
- if (static_cast<int>(height) % 2) {
- for (int column = 0; column < width; ++column) {
- *pixelsSrc = swapBgrToRgb(*pixelsSrc);
- ++pixelsSrc;
- }
- }
+ glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_fbo);
+ QImage offscreenImage = qt_gl_read_framebuffer(QSize(width, height), true, true);
+ glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_state.boundFBO);
+
+ painter->endNativePainting();
painter->drawImage(targetRect, offscreenImage);
painter->restore();
@@ -318,19 +332,21 @@ QRectF GraphicsContext3DPrivate::boundingRect() const
return QRectF(QPointF(0, 0), QSizeF(m_context->m_currentWidth, m_context->m_currentHeight));
}
-void GraphicsContext3DPrivate::blitMultisampleFramebuffer() const
+void GraphicsContext3DPrivate::blitMultisampleFramebuffer()
{
if (!m_context->m_attrs.antialias)
return;
-#if !USE(OPENGL_ES_2)
- glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_context->m_multisampleFBO);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_context->m_fbo);
- glBlitFramebuffer(0, 0, m_context->m_currentWidth, m_context->m_currentHeight, 0, 0, m_context->m_currentWidth, m_context->m_currentHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
-#endif
- glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context->m_state.boundFBO);
+
+ if (!isOpenGLES()) {
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, m_context->m_multisampleFBO);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_context->m_fbo);
+ glBlitFramebuffer(0, 0, m_context->m_currentWidth, m_context->m_currentHeight, 0, 0, m_context->m_currentWidth, m_context->m_currentHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, m_context->m_state.boundFBO);
}
-void GraphicsContext3DPrivate::blitMultisampleFramebufferAndRestoreContext() const
+void GraphicsContext3DPrivate::blitMultisampleFramebufferAndRestoreContext()
{
const QOpenGLContext* currentContext = QOpenGLContext::currentContext();
QSurface* currentSurface = 0;
@@ -352,6 +368,8 @@ void GraphicsContext3DPrivate::blitMultisampleFramebufferAndRestoreContext() con
bool GraphicsContext3DPrivate::makeCurrentIfNeeded() const
{
+ if (!m_platformContext)
+ return false;
const QOpenGLContext* currentContext = QOpenGLContext::currentContext();
if (currentContext == m_platformContext)
return true;
@@ -382,39 +400,34 @@ PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attri
GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
: m_currentWidth(0)
, m_currentHeight(0)
- , m_compiler(isGLES2Compliant() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT)
, m_attrs(attrs)
, m_renderStyle(renderStyle)
, m_texture(0)
, m_compositorTexture(0)
, m_fbo(0)
-#if USE(OPENGL_ES_2)
, m_depthBuffer(0)
, m_stencilBuffer(0)
-#endif
, m_depthStencilBuffer(0)
, m_layerComposited(false)
, m_internalColorFormat(0)
, m_multisampleFBO(0)
, m_multisampleDepthStencilBuffer(0)
, m_multisampleColorBuffer(0)
+ , m_functions(0)
, m_private(std::make_unique<GraphicsContext3DPrivate>(this, hostWindow, renderStyle))
+ , m_compiler(isGLES2Compliant() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT)
+ , m_webglContext(nullptr)
{
- validateAttributes();
-
if (!m_private->m_surface || !m_private->m_platformContext) {
LOG_ERROR("GraphicsContext3D: GL context creation failed.");
m_private = nullptr;
return;
}
- static bool initialized = false;
- static bool success = true;
- if (!initialized) {
- success = initializeOpenGLShims();
- initialized = true;
- }
- if (!success) {
+ m_functions = m_private.get();
+ validateAttributes();
+
+ if (!m_private->isValid()) {
m_private = nullptr;
return;
}
@@ -424,13 +437,13 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWi
m_private->initializeANGLE();
-#if !USE(OPENGL_ES_2)
- glEnable(GL_POINT_SPRITE);
- glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
-#endif
+ if (!isGLES2Compliant()) {
+ m_functions->glEnable(GL_POINT_SPRITE);
+ m_functions->glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
+ }
if (renderStyle != RenderToCurrentGLContext)
- glClearColor(0.0, 0.0, 0.0, 0.0);
+ m_functions->glClearColor(0.0, 0.0, 0.0, 0.0);
}
GraphicsContext3D::~GraphicsContext3D()
@@ -439,23 +452,26 @@ GraphicsContext3D::~GraphicsContext3D()
if (!m_private)
return;
- makeContextCurrent();
- glDeleteTextures(1, &m_texture);
- glDeleteFramebuffers(1, &m_fbo);
- if (m_attrs.antialias) {
- glDeleteRenderbuffers(1, &m_multisampleColorBuffer);
- glDeleteFramebuffers(1, &m_multisampleFBO);
- if (m_attrs.stencil || m_attrs.depth)
- glDeleteRenderbuffers(1, &m_multisampleDepthStencilBuffer);
- } else if (m_attrs.stencil || m_attrs.depth) {
-#if USE(OPENGL_ES_2)
- if (m_attrs.depth)
- glDeleteRenderbuffers(1, &m_depthBuffer);
- if (m_attrs.stencil)
- glDeleteRenderbuffers(1, &m_stencilBuffer);
-#endif
- glDeleteRenderbuffers(1, &m_depthStencilBuffer);
+ if (makeContextCurrent()) {
+ m_functions->glDeleteTextures(1, &m_texture);
+ m_functions->glDeleteFramebuffers(1, &m_fbo);
+ if (m_attrs.antialias) {
+ m_functions->glDeleteRenderbuffers(1, &m_multisampleColorBuffer);
+ m_functions->glDeleteFramebuffers(1, &m_multisampleFBO);
+ if (m_attrs.stencil || m_attrs.depth)
+ m_functions->glDeleteRenderbuffers(1, &m_multisampleDepthStencilBuffer);
+ } else if (m_attrs.stencil || m_attrs.depth) {
+ if (isGLES2Compliant()) {
+ if (m_attrs.depth)
+ m_functions->glDeleteRenderbuffers(1, &m_depthBuffer);
+ if (m_attrs.stencil)
+ m_functions->glDeleteRenderbuffers(1, &m_stencilBuffer);
+ }
+ m_functions->glDeleteRenderbuffers(1, &m_depthStencilBuffer);
+ }
}
+
+ m_functions = 0;
}
PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D()
@@ -475,7 +491,7 @@ PlatformLayer* GraphicsContext3D::platformLayer() const
bool GraphicsContext3D::makeContextCurrent()
{
- if (!m_private || m_renderStyle == RenderToCurrentGLContext)
+ if (!m_private)
return false;
return m_private->makeCurrentIfNeeded();
}