1/* 2 Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) 3 Copyright (C) 2013 Intel Corporation. 4 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. 9 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. 14 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. 19 */ 20 21#include "config.h" 22#include "GraphicsSurface.h" 23 24#if USE(GRAPHICS_SURFACE) 25 26#include "NotImplemented.h" 27#include "TextureMapperGL.h" 28 29#include <opengl/GLDefs.h> 30 31#include "GLXConfigSelector.h" 32 33namespace WebCore { 34 35static PFNGLXBINDTEXIMAGEEXTPROC pGlXBindTexImageEXT = 0; 36static PFNGLXRELEASETEXIMAGEEXTPROC pGlXReleaseTexImageEXT = 0; 37static PFNGLBINDFRAMEBUFFERPROC pGlBindFramebuffer = 0; 38static PFNGLBLITFRAMEBUFFERPROC pGlBlitFramebuffer = 0; 39static PFNGLGENFRAMEBUFFERSPROC pGlGenFramebuffers = 0; 40static PFNGLDELETEFRAMEBUFFERSPROC pGlDeleteFramebuffers = 0; 41static PFNGLFRAMEBUFFERTEXTURE2DPROC pGlFramebufferTexture2D = 0; 42 43static int glxAttributes[] = { 44 GLX_TEXTURE_FORMAT_EXT, 45 GLX_TEXTURE_FORMAT_RGBA_EXT, 46 GLX_TEXTURE_TARGET_EXT, 47 GLX_TEXTURE_2D_EXT, 48 0 49}; 50 51static bool isMesaGLX() 52{ 53 static bool isMesa = !!strstr(glXGetClientString(X11Helper::nativeDisplay(), GLX_VENDOR), "Mesa"); 54 return isMesa; 55} 56 57struct GraphicsSurfacePrivate { 58 GraphicsSurfacePrivate(const PlatformGraphicsContext3D shareContext = 0) 59 : m_xPixmap(0) 60 , m_glxPixmap(0) 61 , m_surface(0) 62 , m_glxSurface(0) 63 , m_glContext(0) 64 , m_detachedContext(0) 65 , m_detachedSurface(0) 66 , m_isReceiver(false) 67 , m_texture(0) 68 { 69 GLXContext shareContextObject = 0; 70 71 UNUSED_PARAM(shareContext); 72 73 GLPlatformSurface::SurfaceAttributes sharedSurfaceAttributes = GLPlatformSurface::DoubleBuffered | 74 GLPlatformSurface::SupportAlpha; 75 m_configSelector = adoptPtr(new GLXConfigSelector(sharedSurfaceAttributes)); 76 77 if (!m_configSelector->surfaceContextConfig()) { 78 clear(); 79 return; 80 } 81 82 // Create a GLX context for OpenGL rendering 83 m_glContext = glXCreateNewContext(display(), m_configSelector->surfaceContextConfig(), GLX_RGBA_TYPE, shareContextObject, true); 84 } 85 86 GraphicsSurfacePrivate(uint32_t winId) 87 : m_xPixmap(0) 88 , m_glxPixmap(0) 89 , m_surface(winId) 90 , m_glxSurface(0) 91 , m_glContext(0) 92 , m_detachedContext(0) 93 , m_detachedSurface(0) 94 , m_isReceiver(true) 95 , m_texture(0) 96 { 97 } 98 99 ~GraphicsSurfacePrivate() 100 { 101 clear(); 102 } 103 104 uint32_t createSurface(const IntSize& size) 105 { 106 if (!display() || !m_configSelector) 107 return 0; 108 109 GLXFBConfig config = m_configSelector->surfaceContextConfig(); 110 OwnPtrX11<XVisualInfo> visInfo(m_configSelector->visualInfo(config)); 111 112 if (!visInfo.get()) { 113 clear(); 114 return 0; 115 } 116 117 X11Helper::createOffScreenWindow(&m_surface, *visInfo.get(), size); 118 119 if (!m_surface) { 120 clear(); 121 return 0; 122 } 123 124 m_glxSurface = glXCreateWindow(display(), config, m_surface, 0); 125 return m_surface; 126 } 127 128 void createPixmap(uint32_t winId) 129 { 130 XWindowAttributes attr; 131 if (!XGetWindowAttributes(display(), winId, &attr)) 132 return; 133 134 // Ensure that the window is mapped. 135 if (attr.map_state == IsUnmapped || attr.map_state == IsUnviewable) 136 return; 137 138 ScopedXPixmapCreationErrorHandler handler; 139 m_size = IntSize(attr.width, attr.height); 140 141 XRenderPictFormat* format = XRenderFindVisualFormat(display(), attr.visual); 142 bool hasAlpha = (format->type == PictTypeDirect && format->direct.alphaMask); 143 m_xPixmap = XCompositeNameWindowPixmap(display(), winId); 144 glxAttributes[1] = (format->depth == 32 && hasAlpha) ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT; 145 146 GLPlatformSurface::SurfaceAttributes sharedSurfaceAttributes = GLPlatformSurface::Default; 147 if (hasAlpha) 148 sharedSurfaceAttributes = GLPlatformSurface::SupportAlpha; 149 150 if (!m_configSelector) 151 m_configSelector = adoptPtr(new GLXConfigSelector(sharedSurfaceAttributes)); 152 153 m_glxPixmap = glXCreatePixmap(display(), m_configSelector->surfaceClientConfig(format->depth, XVisualIDFromVisual(attr.visual)), m_xPixmap, glxAttributes); 154 155 if (!handler.isValidOperation()) 156 clear(); 157 else { 158 uint inverted = 0; 159 glXQueryDrawable(display(), m_glxPixmap, GLX_Y_INVERTED_EXT, &inverted); 160 m_flags = !!inverted ? TextureMapperGL::ShouldFlipTexture : 0; 161 162 if (hasAlpha) 163 m_flags |= TextureMapperGL::ShouldBlend; 164 } 165 } 166 167 void makeCurrent() 168 { 169 m_detachedContext = glXGetCurrentContext(); 170 m_detachedSurface = glXGetCurrentDrawable(); 171 if (m_surface && m_glContext) 172 glXMakeCurrent(display(), m_surface, m_glContext); 173 } 174 175 void doneCurrent() 176 { 177 if (m_detachedContext) 178 glXMakeCurrent(display(), m_detachedSurface, m_detachedContext); 179 m_detachedContext = 0; 180 } 181 182 void swapBuffers() 183 { 184 if (isReceiver()) { 185 if (isMesaGLX() && textureID()) { 186 glBindTexture(GL_TEXTURE_2D, textureID()); 187 // Mesa doesn't re-bind texture to the front buffer on glXSwapBufer 188 // Manually release previous lock and rebind texture to surface to ensure frame updates. 189 pGlXReleaseTexImageEXT(display(), glxPixmap(), GLX_FRONT_EXT); 190 pGlXBindTexImageEXT(display(), glxPixmap(), GLX_FRONT_EXT, 0); 191 } 192 193 return; 194 } 195 196 GLXContext glContext = glXGetCurrentContext(); 197 198 if (m_surface && glContext) { 199 GLint oldFBO; 200 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFBO); 201 pGlBindFramebuffer(GL_FRAMEBUFFER, 0); 202 glXSwapBuffers(display(), m_surface); 203 pGlBindFramebuffer(GL_FRAMEBUFFER, oldFBO); 204 } 205 } 206 207 void copyFromTexture(uint32_t texture, const IntRect& sourceRect) 208 { 209 makeCurrent(); 210 int x = sourceRect.x(); 211 int y = sourceRect.y(); 212 int width = sourceRect.width(); 213 int height = sourceRect.height(); 214 215 glPushAttrib(GL_ALL_ATTRIB_BITS); 216 GLint previousFBO; 217 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previousFBO); 218 219 GLuint originFBO; 220 pGlGenFramebuffers(1, &originFBO); 221 pGlBindFramebuffer(GL_READ_FRAMEBUFFER, originFBO); 222 glBindTexture(GL_TEXTURE_2D, texture); 223 pGlFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); 224 225 pGlBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 226 pGlBlitFramebuffer(x, y, width, height, x, y, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR); 227 228 pGlFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 229 glBindTexture(GL_TEXTURE_2D, 0); 230 pGlBindFramebuffer(GL_FRAMEBUFFER, previousFBO); 231 pGlDeleteFramebuffers(1, &originFBO); 232 233 glPopAttrib(); 234 235 swapBuffers(); 236 doneCurrent(); 237 } 238 239 Display* display() const { return X11Helper::nativeDisplay(); } 240 241 GLXPixmap glxPixmap() const 242 { 243 if (!m_glxPixmap && m_surface) 244 const_cast<GraphicsSurfacePrivate*>(this)->createPixmap(m_surface); 245 return m_glxPixmap; 246 } 247 248 IntSize size() const 249 { 250 if (m_size.isEmpty()) { 251 XWindowAttributes attr; 252 if (XGetWindowAttributes(display(), m_surface, &attr)) 253 const_cast<GraphicsSurfacePrivate*>(this)->m_size = IntSize(attr.width, attr.height); 254 } 255 return m_size; 256 } 257 258 bool isReceiver() const { return m_isReceiver; } 259 260 TextureMapperGL::Flags flags() const { return m_flags; } 261 262 Window surface() const { return m_surface; } 263 264 GLuint textureID() const 265 { 266 if (m_texture) 267 return m_texture; 268 269 GLXPixmap pixmap = glxPixmap(); 270 if (!pixmap) 271 return 0; 272 273 GLuint texture; 274 glGenTextures(1, &texture); 275 glBindTexture(GL_TEXTURE_2D, texture); 276 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 277 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 278 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 279 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 280 pGlXBindTexImageEXT(display(), pixmap, GLX_FRONT_EXT, 0); 281 const_cast<GraphicsSurfacePrivate*>(this)->m_texture = texture; 282 283 return texture; 284 } 285private: 286 void clear() 287 { 288 if (m_texture) { 289 pGlXReleaseTexImageEXT(display(), glxPixmap(), GLX_FRONT_EXT); 290 glDeleteTextures(1, &m_texture); 291 } 292 293 if (m_glxPixmap) { 294 glXDestroyPixmap(display(), m_glxPixmap); 295 m_glxPixmap = 0; 296 } 297 298 if (m_xPixmap) { 299 XFreePixmap(display(), m_xPixmap); 300 m_xPixmap = 0; 301 } 302 303 // Client doesn't own the window. Delete surface only on writing side. 304 if (!m_isReceiver && m_surface) { 305 XDestroyWindow(display(), m_surface); 306 m_surface = 0; 307 } 308 309 if (m_glContext) { 310 glXDestroyContext(display(), m_glContext); 311 m_glContext = 0; 312 } 313 314 if (m_configSelector) 315 m_configSelector = nullptr; 316 } 317 318 IntSize m_size; 319 Pixmap m_xPixmap; 320 GLXPixmap m_glxPixmap; 321 uint32_t m_surface; 322 Window m_glxSurface; 323 GLXContext m_glContext; 324 GLXContext m_detachedContext; 325 GLXDrawable m_detachedSurface; 326 OwnPtr<GLXConfigSelector> m_configSelector; 327 bool m_isReceiver; 328 TextureMapperGL::Flags m_flags; 329 GLuint m_texture; 330}; 331 332static bool resolveGLMethods() 333{ 334 static bool resolved = false; 335 if (resolved) 336 return true; 337 pGlXBindTexImageEXT = reinterpret_cast<PFNGLXBINDTEXIMAGEEXTPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXBindTexImageEXT"))); 338 pGlXReleaseTexImageEXT = reinterpret_cast<PFNGLXRELEASETEXIMAGEEXTPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXReleaseTexImageEXT"))); 339 pGlBindFramebuffer = reinterpret_cast<PFNGLBINDFRAMEBUFFERPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glBindFramebuffer"))); 340 pGlBlitFramebuffer = reinterpret_cast<PFNGLBLITFRAMEBUFFERPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glBlitFramebuffer"))); 341 342 pGlGenFramebuffers = reinterpret_cast<PFNGLGENFRAMEBUFFERSPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glGenFramebuffers"))); 343 pGlDeleteFramebuffers = reinterpret_cast<PFNGLDELETEFRAMEBUFFERSPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glDeleteFramebuffers"))); 344 pGlFramebufferTexture2D = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glFramebufferTexture2D"))); 345 resolved = pGlBlitFramebuffer && pGlBindFramebuffer && pGlXBindTexImageEXT && pGlXReleaseTexImageEXT; 346 347 return resolved; 348} 349 350GraphicsSurfaceToken GraphicsSurface::platformExport() 351{ 352 return GraphicsSurfaceToken(m_private->surface()); 353} 354 355uint32_t GraphicsSurface::platformGetTextureID() 356{ 357 return m_private->textureID(); 358} 359 360void GraphicsSurface::platformCopyToGLTexture(uint32_t /*target*/, uint32_t /*id*/, const IntRect& /*targetRect*/, const IntPoint& /*offset*/) 361{ 362 // This is not supported by GLX/Xcomposite. 363} 364 365void GraphicsSurface::platformCopyFromTexture(uint32_t texture, const IntRect& sourceRect) 366{ 367 m_private->copyFromTexture(texture, sourceRect); 368} 369 370void GraphicsSurface::platformPaintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity) 371{ 372 IntSize size = m_private->size(); 373 if (size.isEmpty()) 374 return; 375 uint32_t texture = platformGetTextureID(); 376 if (!texture) 377 return; 378 379 FloatRect rectOnContents(FloatPoint::zero(), size); 380 TransformationMatrix adjustedTransform = transform; 381 adjustedTransform.multiply(TransformationMatrix::rectToRect(rectOnContents, targetRect)); 382 static_cast<TextureMapperGL*>(textureMapper)->drawTexture(texture, m_private->flags(), size, rectOnContents, adjustedTransform, opacity); 383} 384 385uint32_t GraphicsSurface::platformFrontBuffer() const 386{ 387 return 0; 388} 389 390uint32_t GraphicsSurface::platformSwapBuffers() 391{ 392 m_private->swapBuffers(); 393 return 0; 394} 395 396IntSize GraphicsSurface::platformSize() const 397{ 398 return m_private->size(); 399} 400 401PassRefPtr<GraphicsSurface> GraphicsSurface::platformCreate(const IntSize& size, Flags flags, const PlatformGraphicsContext3D shareContext) 402{ 403 // X11 does not support CopyToTexture, so we do not create a GraphicsSurface if this is requested. 404 // GraphicsSurfaceGLX uses an XWindow as native surface. This one always has a front and a back buffer. 405 // Therefore single buffered GraphicsSurfaces are not supported. 406 if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered) 407 return PassRefPtr<GraphicsSurface>(); 408 409 RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags)); 410 411 surface->m_private = new GraphicsSurfacePrivate(shareContext); 412 if (!resolveGLMethods()) 413 return PassRefPtr<GraphicsSurface>(); 414 415 surface->m_private->createSurface(size); 416 417 return surface; 418} 419 420PassRefPtr<GraphicsSurface> GraphicsSurface::platformImport(const IntSize& size, Flags flags, const GraphicsSurfaceToken& token) 421{ 422 // X11 does not support CopyToTexture, so we do not create a GraphicsSurface if this is requested. 423 // GraphicsSurfaceGLX uses an XWindow as native surface. This one always has a front and a back buffer. 424 // Therefore single buffered GraphicsSurfaces are not supported. 425 if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered) 426 return PassRefPtr<GraphicsSurface>(); 427 428 RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags)); 429 430 surface->m_private = new GraphicsSurfacePrivate(token.frontBufferHandle); 431 if (!resolveGLMethods()) 432 return PassRefPtr<GraphicsSurface>(); 433 434 return surface; 435} 436 437char* GraphicsSurface::platformLock(const IntRect&, int* /*outputStride*/, LockOptions) 438{ 439 // GraphicsSurface is currently only being used for WebGL, which does not require this locking mechanism. 440 return 0; 441} 442 443void GraphicsSurface::platformUnlock() 444{ 445 // GraphicsSurface is currently only being used for WebGL, which does not require this locking mechanism. 446} 447 448void GraphicsSurface::platformDestroy() 449{ 450 delete m_private; 451 m_private = 0; 452} 453 454std::unique_ptr<GraphicsContext> GraphicsSurface::platformBeginPaint(const IntSize&, char*, int) 455{ 456 notImplemented(); 457 return nullptr; 458} 459 460PassRefPtr<Image> GraphicsSurface::createReadOnlyImage(const IntRect&) 461{ 462 notImplemented(); 463 return 0; 464} 465} 466#endif 467