2 Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
3 Copyright (C) 2013 Intel Corporation.
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 #include "GraphicsSurface.h"
24 #if USE(GRAPHICS_SURFACE)
26 #include "NotImplemented.h"
27 #include "TextureMapperGL.h"
30 // Qt headers must be included before glx headers.
31 #include <QGuiApplication>
32 #include <QOpenGLContext>
33 #include <qpa/qplatformnativeinterface.h>
37 #include <opengl/GLDefs.h>
40 #include "GLXConfigSelector.h"
44 static PFNGLXBINDTEXIMAGEEXTPROC pGlXBindTexImageEXT = 0;
45 static PFNGLXRELEASETEXIMAGEEXTPROC pGlXReleaseTexImageEXT = 0;
46 static PFNGLBINDFRAMEBUFFERPROC pGlBindFramebuffer = 0;
47 static PFNGLBLITFRAMEBUFFERPROC pGlBlitFramebuffer = 0;
48 static PFNGLGENFRAMEBUFFERSPROC pGlGenFramebuffers = 0;
49 static PFNGLDELETEFRAMEBUFFERSPROC pGlDeleteFramebuffers = 0;
50 static PFNGLFRAMEBUFFERTEXTURE2DPROC pGlFramebufferTexture2D = 0;
52 static int glxAttributes[] = {
53 GLX_TEXTURE_FORMAT_EXT,
54 GLX_TEXTURE_FORMAT_RGBA_EXT,
55 GLX_TEXTURE_TARGET_EXT,
60 static bool isMesaGLX()
62 static bool isMesa = !!strstr(glXGetClientString(X11Helper::nativeDisplay(), GLX_VENDOR), "Mesa");
66 struct GraphicsSurfacePrivate {
67 GraphicsSurfacePrivate(const PlatformGraphicsContext3D shareContext = 0)
73 , m_detachedContext(0)
74 , m_detachedSurface(0)
78 GLXContext shareContextObject = 0;
82 QPlatformNativeInterface* nativeInterface = QGuiApplication::platformNativeInterface();
83 shareContextObject = static_cast<GLXContext>(nativeInterface->nativeResourceForContext(QByteArrayLiteral("glxcontext"), shareContext));
84 if (!shareContextObject)
88 UNUSED_PARAM(shareContext);
91 m_configSelector = adoptPtr(new GLXConfigSelector());
93 if (!m_configSelector->surfaceContextConfig()) {
98 // Create a GLX context for OpenGL rendering
99 m_glContext = glXCreateNewContext(display(), m_configSelector->surfaceContextConfig(), GLX_RGBA_TYPE, shareContextObject, true);
102 GraphicsSurfacePrivate(uint32_t winId)
108 , m_detachedContext(0)
109 , m_detachedSurface(0)
113 m_configSelector = adoptPtr(new GLXConfigSelector());
116 ~GraphicsSurfacePrivate()
121 uint32_t createSurface(const IntSize& size)
123 if (!display() || !m_configSelector)
126 OwnPtrX11<XVisualInfo> visInfo(m_configSelector->visualInfo());
128 if (!visInfo.get()) {
133 X11Helper::createOffScreenWindow(&m_surface, *visInfo.get(), size);
140 m_glxSurface = glXCreateWindow(display(), m_configSelector->surfaceContextConfig(), m_surface, 0);
144 void createPixmap(uint32_t winId)
146 if (!m_configSelector)
149 XWindowAttributes attr;
150 if (!XGetWindowAttributes(display(), winId, &attr))
153 // Ensure that the window is mapped.
154 if (attr.map_state == IsUnmapped || attr.map_state == IsUnviewable)
157 ScopedXPixmapCreationErrorHandler handler;
158 m_size = IntSize(attr.width, attr.height);
160 XRenderPictFormat* format = XRenderFindVisualFormat(display(), attr.visual);
161 bool hasAlpha = (format->type == PictTypeDirect && format->direct.alphaMask);
162 m_xPixmap = XCompositeNameWindowPixmap(display(), winId);
163 glxAttributes[1] = (format->depth == 32 || hasAlpha) ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT;
164 m_glxPixmap = glXCreatePixmap(display(), m_configSelector->surfaceClientConfig(format->depth, XVisualIDFromVisual(attr.visual)), m_xPixmap, glxAttributes);
166 if (!handler.isValidOperation())
170 glXQueryDrawable(display(), m_glxPixmap, GLX_Y_INVERTED_EXT, &inverted);
171 m_flags = !!inverted ? TextureMapperGL::ShouldFlipTexture : 0;
174 m_flags |= TextureMapperGL::ShouldBlend;
180 m_detachedContext = glXGetCurrentContext();
181 m_detachedSurface = glXGetCurrentDrawable();
182 if (m_surface && m_glContext)
183 glXMakeCurrent(display(), m_surface, m_glContext);
188 if (m_detachedContext)
189 glXMakeCurrent(display(), m_detachedSurface, m_detachedContext);
190 m_detachedContext = 0;
196 if (isMesaGLX() && textureID()) {
197 glBindTexture(GL_TEXTURE_2D, textureID());
198 // Mesa doesn't re-bind texture to the front buffer on glXSwapBufer
199 // Manually release previous lock and rebind texture to surface to ensure frame updates.
200 pGlXReleaseTexImageEXT(display(), glxPixmap(), GLX_FRONT_EXT);
201 pGlXBindTexImageEXT(display(), glxPixmap(), GLX_FRONT_EXT, 0);
207 GLXContext glContext = glXGetCurrentContext();
209 if (m_surface && glContext) {
211 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFBO);
212 pGlBindFramebuffer(GL_FRAMEBUFFER, 0);
213 glXSwapBuffers(display(), m_surface);
214 pGlBindFramebuffer(GL_FRAMEBUFFER, oldFBO);
218 void copyFromTexture(uint32_t texture, const IntRect& sourceRect)
221 int x = sourceRect.x();
222 int y = sourceRect.y();
223 int width = sourceRect.width();
224 int height = sourceRect.height();
226 glPushAttrib(GL_ALL_ATTRIB_BITS);
228 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previousFBO);
231 pGlGenFramebuffers(1, &originFBO);
232 pGlBindFramebuffer(GL_READ_FRAMEBUFFER, originFBO);
233 glBindTexture(GL_TEXTURE_2D, texture);
234 pGlFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
236 pGlBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
237 pGlBlitFramebuffer(x, y, width, height, x, y, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
239 pGlFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
240 glBindTexture(GL_TEXTURE_2D, 0);
241 pGlBindFramebuffer(GL_FRAMEBUFFER, previousFBO);
242 pGlDeleteFramebuffers(1, &originFBO);
250 Display* display() const { return X11Helper::nativeDisplay(); }
252 GLXPixmap glxPixmap() const
254 if (!m_glxPixmap && m_surface)
255 const_cast<GraphicsSurfacePrivate*>(this)->createPixmap(m_surface);
261 if (m_size.isEmpty()) {
262 XWindowAttributes attr;
263 if (XGetWindowAttributes(display(), m_surface, &attr))
264 const_cast<GraphicsSurfacePrivate*>(this)->m_size = IntSize(attr.width, attr.height);
269 bool isReceiver() const { return m_isReceiver; }
271 TextureMapperGL::Flags flags() const { return m_flags; }
273 Window surface() const { return m_surface; }
275 GLuint textureID() const
280 GLXPixmap pixmap = glxPixmap();
285 glGenTextures(1, &texture);
286 glBindTexture(GL_TEXTURE_2D, texture);
287 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
288 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
289 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
290 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
291 pGlXBindTexImageEXT(display(), pixmap, GLX_FRONT_EXT, 0);
292 const_cast<GraphicsSurfacePrivate*>(this)->m_texture = texture;
300 pGlXReleaseTexImageEXT(display(), glxPixmap(), GLX_FRONT_EXT);
301 glDeleteTextures(1, &m_texture);
305 glXDestroyPixmap(display(), m_glxPixmap);
310 XFreePixmap(display(), m_xPixmap);
314 // Client doesn't own the window. Delete surface only on writing side.
315 if (!m_isReceiver && m_surface) {
316 XDestroyWindow(display(), m_surface);
321 glXDestroyContext(display(), m_glContext);
325 if (m_configSelector)
326 m_configSelector = nullptr;
331 GLXPixmap m_glxPixmap;
334 GLXContext m_glContext;
335 GLXContext m_detachedContext;
336 GLXDrawable m_detachedSurface;
337 OwnPtr<GLXConfigSelector> m_configSelector;
339 TextureMapperGL::Flags m_flags;
343 static bool resolveGLMethods()
345 static bool resolved = false;
348 pGlXBindTexImageEXT = reinterpret_cast<PFNGLXBINDTEXIMAGEEXTPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXBindTexImageEXT")));
349 pGlXReleaseTexImageEXT = reinterpret_cast<PFNGLXRELEASETEXIMAGEEXTPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXReleaseTexImageEXT")));
350 pGlBindFramebuffer = reinterpret_cast<PFNGLBINDFRAMEBUFFERPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glBindFramebuffer")));
351 pGlBlitFramebuffer = reinterpret_cast<PFNGLBLITFRAMEBUFFERPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glBlitFramebuffer")));
353 pGlGenFramebuffers = reinterpret_cast<PFNGLGENFRAMEBUFFERSPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glGenFramebuffers")));
354 pGlDeleteFramebuffers = reinterpret_cast<PFNGLDELETEFRAMEBUFFERSPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glDeleteFramebuffers")));
355 pGlFramebufferTexture2D = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glFramebufferTexture2D")));
356 resolved = pGlBlitFramebuffer && pGlBindFramebuffer && pGlXBindTexImageEXT && pGlXReleaseTexImageEXT;
361 GraphicsSurfaceToken GraphicsSurface::platformExport()
363 return GraphicsSurfaceToken(m_private->surface());
366 uint32_t GraphicsSurface::platformGetTextureID()
368 return m_private->textureID();
371 void GraphicsSurface::platformCopyToGLTexture(uint32_t /*target*/, uint32_t /*id*/, const IntRect& /*targetRect*/, const IntPoint& /*offset*/)
373 // This is not supported by GLX/Xcomposite.
376 void GraphicsSurface::platformCopyFromTexture(uint32_t texture, const IntRect& sourceRect)
378 m_private->copyFromTexture(texture, sourceRect);
381 void GraphicsSurface::platformPaintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity, BitmapTexture* mask)
383 IntSize size = m_private->size();
386 uint32_t texture = platformGetTextureID();
390 FloatRect rectOnContents(FloatPoint::zero(), size);
391 TransformationMatrix adjustedTransform = transform;
392 adjustedTransform.multiply(TransformationMatrix::rectToRect(rectOnContents, targetRect));
393 static_cast<TextureMapperGL*>(textureMapper)->drawTexture(texture, m_private->flags(), size, rectOnContents, adjustedTransform, opacity, mask);
396 uint32_t GraphicsSurface::platformFrontBuffer() const
401 uint32_t GraphicsSurface::platformSwapBuffers()
403 m_private->swapBuffers();
407 IntSize GraphicsSurface::platformSize() const
409 return m_private->size();
412 PassRefPtr<GraphicsSurface> GraphicsSurface::platformCreate(const IntSize& size, Flags flags, const PlatformGraphicsContext3D shareContext)
414 // X11 does not support CopyToTexture, so we do not create a GraphicsSurface if this is requested.
415 // GraphicsSurfaceGLX uses an XWindow as native surface. This one always has a front and a back buffer.
416 // Therefore single buffered GraphicsSurfaces are not supported.
417 if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered)
418 return PassRefPtr<GraphicsSurface>();
420 RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags));
422 surface->m_private = new GraphicsSurfacePrivate(shareContext);
423 if (!resolveGLMethods())
424 return PassRefPtr<GraphicsSurface>();
426 surface->m_private->createSurface(size);
431 PassRefPtr<GraphicsSurface> GraphicsSurface::platformImport(const IntSize& size, Flags flags, const GraphicsSurfaceToken& token)
433 // X11 does not support CopyToTexture, so we do not create a GraphicsSurface if this is requested.
434 // GraphicsSurfaceGLX uses an XWindow as native surface. This one always has a front and a back buffer.
435 // Therefore single buffered GraphicsSurfaces are not supported.
436 if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered)
437 return PassRefPtr<GraphicsSurface>();
439 RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags));
441 surface->m_private = new GraphicsSurfacePrivate(token.frontBufferHandle);
442 if (!resolveGLMethods())
443 return PassRefPtr<GraphicsSurface>();
448 char* GraphicsSurface::platformLock(const IntRect&, int* /*outputStride*/, LockOptions)
450 // GraphicsSurface is currently only being used for WebGL, which does not require this locking mechanism.
454 void GraphicsSurface::platformUnlock()
456 // GraphicsSurface is currently only being used for WebGL, which does not require this locking mechanism.
459 void GraphicsSurface::platformDestroy()
466 PassOwnPtr<GraphicsContext> GraphicsSurface::platformBeginPaint(const IntSize&, char*, int)
472 PassRefPtr<Image> GraphicsSurface::createReadOnlyImage(const IntRect&)