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