7757e6809f2d02b35fc3c3d7ac48f215a5df85c8
[WebKit-https.git] / Source / WebCore / platform / graphics / surfaces / glx / GraphicsSurfaceGLX.cpp
1 /*
2  Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
3
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  Library General Public License for more details.
13
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB.  If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "GraphicsSurface.h"
22
23 #if USE(GRAPHICS_SURFACE)
24
25 #include "NotImplemented.h"
26 #include "TextureMapperGL.h"
27
28 #if PLATFORM(QT)
29 // Qt headers must be included before glx headers.
30 #include <QGuiApplication>
31 #include <QOpenGLContext>
32 #include <qpa/qplatformnativeinterface.h>
33 #elif PLATFORM(EFL)
34 #include <GL/gl.h>
35 #endif
36
37 #include <GL/glext.h>
38 #include <GL/glx.h>
39 #include <X11/Xlib.h>
40 #include <X11/extensions/Xcomposite.h>
41 #include <X11/extensions/Xrender.h>
42
43 namespace WebCore {
44
45 static long X11OverrideRedirect = 1L << 9;
46
47 static PFNGLXBINDTEXIMAGEEXTPROC pGlXBindTexImageEXT = 0;
48 static PFNGLXRELEASETEXIMAGEEXTPROC pGlXReleaseTexImageEXT = 0;
49 static PFNGLBINDFRAMEBUFFERPROC pGlBindFramebuffer = 0;
50 static PFNGLBLITFRAMEBUFFERPROC pGlBlitFramebuffer = 0;
51 static PFNGLGENFRAMEBUFFERSPROC pGlGenFramebuffers = 0;
52 static PFNGLDELETEFRAMEBUFFERSPROC pGlDeleteFramebuffers = 0;
53 static PFNGLFRAMEBUFFERTEXTURE2DPROC pGlFramebufferTexture2D = 0;
54
55 // Used for handling XError.
56 static bool validOperation = true;
57 static int handleXPixmapCreationError(Display*, XErrorEvent* event)
58 {
59     if (event->error_code == BadMatch || event->error_code == BadWindow || event->error_code == BadAlloc) {
60         validOperation = false;
61
62         switch (event->error_code) {
63         case BadMatch:
64             LOG_ERROR("BadMatch.");
65             break;
66         case BadWindow:
67             LOG_ERROR("BadWindow.");
68             break;
69         case BadAlloc:
70             LOG_ERROR("BadAlloc.");
71             break;
72         default:
73             break;
74         }
75     }
76
77     return 0;
78 }
79
80 static int attributes[] = {
81     GLX_LEVEL, 0,
82     GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
83     GLX_RENDER_TYPE,   GLX_RGBA_BIT,
84     GLX_RED_SIZE,      1,
85     GLX_GREEN_SIZE,    1,
86     GLX_BLUE_SIZE,     1,
87     GLX_ALPHA_SIZE,    1,
88     GLX_DEPTH_SIZE,    1,
89     GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
90     GLX_DOUBLEBUFFER,  True,
91     None
92 };
93
94 class ScopedXPixmapCreationErrorHandler {
95
96 public:
97     ScopedXPixmapCreationErrorHandler(Display* display)
98         : m_display(display)
99     {
100         // XSync must be called to ensure that current errors are handled by the original handler.
101         XSync(m_display, false);
102         m_previousErrorHandler = XSetErrorHandler(handleXPixmapCreationError);
103     }
104
105     ~ScopedXPixmapCreationErrorHandler()
106     {
107         // Restore the original handler.
108         XSetErrorHandler(m_previousErrorHandler);
109     }
110
111     bool isValidOperation() const
112     {
113         validOperation = true;
114         // XSync is needed to catch possible errors as they are generated asynchronously.
115         XSync(m_display, false);
116         return validOperation;
117     }
118
119 private:
120     XErrorHandler m_previousErrorHandler;
121     Display* m_display;
122 };
123
124 // FIXME: Take X11WindowResources and GLXConfigSelector into use.
125 class OffScreenRootWindow {
126 public:
127     OffScreenRootWindow()
128     {
129         ++m_refCount;
130     }
131
132     Window getXWindow()
133     {
134         if (!m_window) {
135             Display* dpy = display();
136             m_window = XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy), -1, -1, 1, 1, 0, BlackPixel(dpy, 0), WhitePixel(dpy, 0));
137             XSetWindowAttributes attributes;
138             attributes.override_redirect = true;
139             XChangeWindowAttributes(dpy, m_window, X11OverrideRedirect, &attributes);
140             // Map window to the screen
141             XMapWindow(dpy, m_window);
142         }
143
144         return m_window;
145     }
146
147 private:
148     struct DisplayConnection {
149         DisplayConnection()
150         {
151             m_display = XOpenDisplay(0);
152         }
153
154         ~DisplayConnection()
155         {
156             XCloseDisplay(m_display);
157         }
158
159         Display* display() { return m_display; }
160     private:
161         Display* m_display;
162     };
163
164 public:
165     static Display* display()
166     {
167         // Display connection will only be broken at program shutdown.
168         static DisplayConnection displayConnection;
169         return displayConnection.display();
170     }
171
172     ~OffScreenRootWindow()
173     {
174         if (--m_refCount)
175             return;
176
177         if (m_window) {
178             XUnmapWindow(display(), m_window);
179             XDestroyWindow(display(), m_window);
180             m_window = 0;
181         }
182     }
183
184     static bool isMesaGLX()
185     {
186         static bool isMesa = !!strstr(glXGetClientString(display(), GLX_VENDOR), "Mesa");
187         return isMesa;
188     }
189
190 private:
191     static int m_refCount;
192     static Window m_window;
193 };
194
195 int OffScreenRootWindow::m_refCount = 0;
196 Window OffScreenRootWindow::m_window = 0;
197
198 static const int glxSpec[] = {
199     // The specification is a set key value pairs stored in a simple array.
200     GLX_LEVEL,                          0,
201     GLX_DRAWABLE_TYPE,                  GLX_PIXMAP_BIT | GLX_WINDOW_BIT,
202     GLX_BIND_TO_TEXTURE_TARGETS_EXT,    GLX_TEXTURE_2D_BIT_EXT,
203     GLX_BIND_TO_TEXTURE_RGBA_EXT,       TRUE,
204     0
205 };
206
207 static const int glxAttributes[] = {
208     GLX_TEXTURE_FORMAT_EXT,
209     GLX_TEXTURE_FORMAT_RGBA_EXT,
210     GLX_TEXTURE_TARGET_EXT,
211     GLX_TEXTURE_2D_EXT,
212     0
213 };
214
215 struct GraphicsSurfacePrivate {
216     GraphicsSurfacePrivate(const PlatformGraphicsContext3D shareContext = 0)
217         : m_offScreenWindow(adoptPtr(new OffScreenRootWindow()))
218         , m_xPixmap(0)
219         , m_glxPixmap(0)
220         , m_surface(0)
221         , m_glxSurface(0)
222         , m_glContext(0)
223         , m_detachedContext(0)
224         , m_detachedSurface(0)
225         , m_fbConfig(0)
226         , m_textureIsYInverted(false)
227         , m_hasAlpha(false)
228         , m_isReceiver(false)
229     {
230         GLXContext shareContextObject = 0;
231
232 #if PLATFORM(QT)
233         if (shareContext) {
234             QPlatformNativeInterface* nativeInterface = QGuiApplication::platformNativeInterface();
235             shareContextObject = static_cast<GLXContext>(nativeInterface->nativeResourceForContext(QByteArrayLiteral("glxcontext"), shareContext));
236             if (!shareContextObject)
237                 return;
238         }
239 #else
240         UNUSED_PARAM(shareContext);
241 #endif
242
243         int numReturned;
244         GLXFBConfig* fbConfigs = glXChooseFBConfig(display(), DefaultScreen(display()), attributes, &numReturned);
245
246         // Make sure that we choose a configuration that supports an alpha mask.
247         m_fbConfig = findFBConfigWithAlpha(fbConfigs, numReturned);
248
249         XFree(fbConfigs);
250
251         // Create a GLX context for OpenGL rendering
252         m_glContext = glXCreateNewContext(display(), m_fbConfig, GLX_RGBA_TYPE, shareContextObject, true);
253     }
254
255     GraphicsSurfacePrivate(uint32_t winId)
256         : m_xPixmap(0)
257         , m_glxPixmap(0)
258         , m_surface(winId)
259         , m_glxSurface(0)
260         , m_glContext(0)
261         , m_detachedContext(0)
262         , m_detachedSurface(0)
263         , m_fbConfig(0)
264         , m_textureIsYInverted(false)
265         , m_hasAlpha(false)
266         , m_isReceiver(true)
267     { }
268
269     ~GraphicsSurfacePrivate()
270     {
271         clear();
272     }
273
274     uint32_t createSurface(const IntSize& size)
275     {
276         XVisualInfo* visualInfo = glXGetVisualFromFBConfig(display(), m_fbConfig);
277         if (!visualInfo)
278             return 0;
279
280         Colormap cmap = XCreateColormap(display(), m_offScreenWindow->getXWindow(), visualInfo->visual, AllocNone);
281
282         XSetWindowAttributes a;
283         a.background_pixel = WhitePixel(display(), 0);
284         a.border_pixel = BlackPixel(display(), 0);
285         a.colormap = cmap;
286         m_surface = XCreateWindow(display(), m_offScreenWindow->getXWindow(), 0, 0, size.width(), size.height(),
287             0, visualInfo->depth, InputOutput, visualInfo->visual,
288             CWBackPixel | CWBorderPixel | CWColormap, &a);
289         XSetWindowBackgroundPixmap(display(), m_surface, 0);
290         XCompositeRedirectWindow(display(), m_surface, CompositeRedirectManual);
291         m_glxSurface = glXCreateWindow(display(), m_fbConfig, m_surface, 0);
292         XFree(visualInfo);
293
294         // Make sure the XRender Extension is available.
295         int eventBasep, errorBasep;
296         if (!XRenderQueryExtension(display(), &eventBasep, &errorBasep))
297             return 0;
298
299         XMapWindow(display(), m_surface);
300         return m_surface;
301     }
302
303     void createPixmap(uint32_t winId)
304     {
305         XWindowAttributes attr;
306         if (!XGetWindowAttributes(display(), winId, &attr))
307             return;
308
309         // Ensure that the window is mapped.
310         if (attr.map_state == IsUnmapped || attr.map_state == IsUnviewable)
311             return;
312
313         ScopedXPixmapCreationErrorHandler handler(display());
314         m_size = IntSize(attr.width, attr.height);
315
316         XRenderPictFormat* format = XRenderFindVisualFormat(display(), attr.visual);
317         m_hasAlpha = (format->type == PictTypeDirect && format->direct.alphaMask);
318
319         int numberOfConfigs;
320         GLXFBConfig* configs = glXChooseFBConfig(display(), XDefaultScreen(display()), glxSpec, &numberOfConfigs);
321
322         // If origin window has alpha then find config with alpha.
323         GLXFBConfig& config = m_hasAlpha ? findFBConfigWithAlpha(configs, numberOfConfigs) : configs[0];
324
325         m_xPixmap = XCompositeNameWindowPixmap(display(), winId);
326         m_glxPixmap = glXCreatePixmap(display(), config, m_xPixmap, glxAttributes);
327
328         if (!handler.isValidOperation())
329             clear();
330         else {
331             uint inverted = 0;
332             glXQueryDrawable(display(), m_glxPixmap, GLX_Y_INVERTED_EXT, &inverted);
333             m_textureIsYInverted = !!inverted;
334         }
335
336         XFree(configs);
337     }
338
339     bool textureIsYInverted()
340     {
341         return m_textureIsYInverted;
342     }
343
344     void makeCurrent()
345     {
346         m_detachedContext = glXGetCurrentContext();
347         m_detachedSurface = glXGetCurrentDrawable();
348         if (m_surface && m_glContext)
349             glXMakeCurrent(display(), m_surface, m_glContext);
350     }
351
352     void doneCurrent()
353     {
354         if (m_detachedContext)
355             glXMakeCurrent(display(), m_detachedSurface, m_detachedContext);
356         m_detachedContext = 0;
357     }
358
359     void swapBuffers()
360     {
361         // The buffers are being switched on the writing side, the reading side just reads
362         // whatever texture the XWindow contains.
363         if (m_isReceiver)
364             return;
365
366         GLXContext glContext = glXGetCurrentContext();
367
368         if (m_surface && glContext) {
369             GLint oldFBO;
370             glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFBO);
371             pGlBindFramebuffer(GL_FRAMEBUFFER, 0);
372             glXSwapBuffers(display(), m_surface);
373             pGlBindFramebuffer(GL_FRAMEBUFFER, oldFBO);
374         }
375     }
376
377     void copyFromTexture(uint32_t texture, const IntRect& sourceRect)
378     {
379         makeCurrent();
380         int x = sourceRect.x();
381         int y = sourceRect.y();
382         int width = sourceRect.width();
383         int height = sourceRect.height();
384
385         glPushAttrib(GL_ALL_ATTRIB_BITS);
386         GLint previousFBO;
387         glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previousFBO);
388
389         GLuint originFBO;
390         pGlGenFramebuffers(1, &originFBO);
391         pGlBindFramebuffer(GL_READ_FRAMEBUFFER, originFBO);
392         glBindTexture(GL_TEXTURE_2D, texture);
393         pGlFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
394
395         pGlBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
396         pGlBlitFramebuffer(x, y, width, height, x, y, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
397
398         pGlFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
399         glBindTexture(GL_TEXTURE_2D, 0);
400         pGlBindFramebuffer(GL_FRAMEBUFFER, previousFBO);
401         pGlDeleteFramebuffers(1, &originFBO);
402
403         glPopAttrib();
404
405         swapBuffers();
406         doneCurrent();
407     }
408
409     Display* display() const { return OffScreenRootWindow::display(); }
410
411     GLXPixmap glxPixmap() const
412     {
413         if (!m_glxPixmap && m_surface)
414             const_cast<GraphicsSurfacePrivate*>(this)->createPixmap(m_surface);
415         return m_glxPixmap;
416     }
417
418     IntSize size() const
419     {
420         if (m_size.isEmpty()) {
421             XWindowAttributes attr;
422             if (XGetWindowAttributes(display(), m_surface, &attr))
423                 const_cast<GraphicsSurfacePrivate*>(this)->m_size = IntSize(attr.width, attr.height);
424         }
425         return m_size;
426     }
427
428     bool isReceiver() const { return m_isReceiver; }
429 private:
430     GLXFBConfig& findFBConfigWithAlpha(GLXFBConfig* fbConfigs, int numberOfConfigs)
431     {
432         for (int i = 0; i < numberOfConfigs; ++i) {
433             XVisualInfo* visualInfo = glXGetVisualFromFBConfig(display(), fbConfigs[i]);
434             if (!visualInfo)
435                 continue;
436
437             XRenderPictFormat* format = XRenderFindVisualFormat(display(), visualInfo->visual);
438             XFree(visualInfo);
439
440             if (format && format->direct.alphaMask > 0)
441                 return fbConfigs[i];
442         }
443
444         // Return 1st config as a fallback with no alpha support.
445         return fbConfigs[0];
446     }
447
448     void clear()
449     {
450         if (m_glxPixmap) {
451             glXDestroyPixmap(display(), m_glxPixmap);
452             m_glxPixmap = 0;
453         }
454
455         if (m_xPixmap) {
456             XFreePixmap(display(), m_xPixmap);
457             m_xPixmap = 0;
458         }
459
460         // Client doesn't own the window. Delete surface only on writing side.
461         if (!m_isReceiver && m_surface) {
462             XDestroyWindow(display(), m_surface);
463             m_surface = 0;
464         }
465
466         if (m_glContext) {
467             glXDestroyContext(display(), m_glContext);
468             m_glContext = 0;
469         }
470     }
471
472     OwnPtr<OffScreenRootWindow> m_offScreenWindow;
473     IntSize m_size;
474     Pixmap m_xPixmap;
475     GLXPixmap m_glxPixmap;
476     Window m_surface;
477     Window m_glxSurface;
478     GLXContext m_glContext;
479     GLXContext m_detachedContext;
480     GLXDrawable m_detachedSurface;
481     GLXFBConfig m_fbConfig;
482     bool m_textureIsYInverted;
483     bool m_hasAlpha;
484     bool m_isReceiver;
485 };
486
487 static bool resolveGLMethods()
488 {
489     static bool resolved = false;
490     if (resolved)
491         return true;
492     pGlXBindTexImageEXT = reinterpret_cast<PFNGLXBINDTEXIMAGEEXTPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXBindTexImageEXT")));
493     pGlXReleaseTexImageEXT = reinterpret_cast<PFNGLXRELEASETEXIMAGEEXTPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXReleaseTexImageEXT")));
494     pGlBindFramebuffer = reinterpret_cast<PFNGLBINDFRAMEBUFFERPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glBindFramebuffer")));
495     pGlBlitFramebuffer = reinterpret_cast<PFNGLBLITFRAMEBUFFERPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glBlitFramebuffer")));
496
497     pGlGenFramebuffers = reinterpret_cast<PFNGLGENFRAMEBUFFERSPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glGenFramebuffers")));
498     pGlDeleteFramebuffers = reinterpret_cast<PFNGLDELETEFRAMEBUFFERSPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glDeleteFramebuffers")));
499     pGlFramebufferTexture2D = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glFramebufferTexture2D")));
500     resolved = pGlBlitFramebuffer && pGlBindFramebuffer && pGlXBindTexImageEXT && pGlXReleaseTexImageEXT;
501
502     return resolved;
503 }
504
505 GraphicsSurfaceToken GraphicsSurface::platformExport()
506 {
507     return GraphicsSurfaceToken(m_platformSurface);
508 }
509
510 uint32_t GraphicsSurface::platformGetTextureID()
511 {
512     if (!m_texture) {
513         GLXPixmap pixmap = m_private->glxPixmap();
514         if (!pixmap)
515             return 0;
516
517         glGenTextures(1, &m_texture);
518         glBindTexture(GL_TEXTURE_2D, m_texture);
519         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
520         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
521         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
522         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
523         pGlXBindTexImageEXT(m_private->display(), pixmap, GLX_FRONT_EXT, 0);
524     }
525
526     return m_texture;
527 }
528
529 void GraphicsSurface::platformCopyToGLTexture(uint32_t /*target*/, uint32_t /*id*/, const IntRect& /*targetRect*/, const IntPoint& /*offset*/)
530 {
531     // This is not supported by GLX/Xcomposite.
532 }
533
534 void GraphicsSurface::platformCopyFromTexture(uint32_t texture, const IntRect& sourceRect)
535 {
536     m_private->copyFromTexture(texture, sourceRect);
537 }
538
539 void GraphicsSurface::platformPaintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity, BitmapTexture* mask)
540 {
541     IntSize size = m_private->size();
542     if (size.isEmpty())
543         return;
544     uint32_t texture = platformGetTextureID();
545     if (!texture)
546         return;
547
548     TextureMapperGL::Flags flags = m_private->textureIsYInverted() ? TextureMapperGL::ShouldFlipTexture : 0;
549     flags |= TextureMapperGL::ShouldBlend;
550
551     FloatRect rectOnContents(FloatPoint::zero(), size);
552     TransformationMatrix adjustedTransform = transform;
553     adjustedTransform.multiply(TransformationMatrix::rectToRect(rectOnContents, targetRect));
554     static_cast<TextureMapperGL*>(textureMapper)->drawTexture(texture, flags, size, rectOnContents, adjustedTransform, opacity, mask);
555 }
556
557 uint32_t GraphicsSurface::platformFrontBuffer() const
558 {
559     return 0;
560 }
561
562 uint32_t GraphicsSurface::platformSwapBuffers()
563 {
564     if (m_private->isReceiver()) {
565         if (OffScreenRootWindow::isMesaGLX() && platformGetTextureID()) {
566             glBindTexture(GL_TEXTURE_2D, platformGetTextureID());
567             // Mesa doesn't re-bind texture to the front buffer on glXSwapBufer
568             // Manually release previous lock and rebind texture to surface to get frame update.
569             pGlXReleaseTexImageEXT(m_private->display(), m_private->glxPixmap(), GLX_FRONT_EXT);
570             pGlXBindTexImageEXT(m_private->display(), m_private->glxPixmap(), GLX_FRONT_EXT, 0);
571         }
572         return 0;
573     }
574
575     m_private->swapBuffers();
576     return 0;
577 }
578
579 IntSize GraphicsSurface::platformSize() const
580 {
581     return m_private->size();
582 }
583
584 PassRefPtr<GraphicsSurface> GraphicsSurface::platformCreate(const IntSize& size, Flags flags, const PlatformGraphicsContext3D shareContext)
585 {
586     // X11 does not support CopyToTexture, so we do not create a GraphicsSurface if this is requested.
587     // GraphicsSurfaceGLX uses an XWindow as native surface. This one always has a front and a back buffer.
588     // Therefore single buffered GraphicsSurfaces are not supported.
589     if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered)
590         return PassRefPtr<GraphicsSurface>();
591
592     RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags));
593
594     surface->m_private = new GraphicsSurfacePrivate(shareContext);
595     if (!resolveGLMethods())
596         return PassRefPtr<GraphicsSurface>();
597
598     surface->m_platformSurface = surface->m_private->createSurface(size);
599
600     return surface;
601 }
602
603 PassRefPtr<GraphicsSurface> GraphicsSurface::platformImport(const IntSize& size, Flags flags, const GraphicsSurfaceToken& token)
604 {
605     // X11 does not support CopyToTexture, so we do not create a GraphicsSurface if this is requested.
606     // GraphicsSurfaceGLX uses an XWindow as native surface. This one always has a front and a back buffer.
607     // Therefore single buffered GraphicsSurfaces are not supported.
608     if (flags & SupportsCopyToTexture || flags & SupportsSingleBuffered)
609         return PassRefPtr<GraphicsSurface>();
610
611     RefPtr<GraphicsSurface> surface = adoptRef(new GraphicsSurface(size, flags));
612     surface->m_platformSurface = token.frontBufferHandle;
613
614     surface->m_private = new GraphicsSurfacePrivate(surface->m_platformSurface);
615     if (!resolveGLMethods())
616         return PassRefPtr<GraphicsSurface>();
617
618     return surface;
619 }
620
621 char* GraphicsSurface::platformLock(const IntRect&, int* /*outputStride*/, LockOptions)
622 {
623     // GraphicsSurface is currently only being used for WebGL, which does not require this locking mechanism.
624     return 0;
625 }
626
627 void GraphicsSurface::platformUnlock()
628 {
629     // GraphicsSurface is currently only being used for WebGL, which does not require this locking mechanism.
630 }
631
632 void GraphicsSurface::platformDestroy()
633 {
634     if (m_texture) {
635         pGlXReleaseTexImageEXT(m_private->display(), m_private->glxPixmap(), GLX_FRONT_EXT);
636         glDeleteTextures(1, &m_texture);
637     }
638
639     delete m_private;
640     m_private = 0;
641 }
642
643 #if !PLATFORM(QT)
644 PassOwnPtr<GraphicsContext> GraphicsSurface::platformBeginPaint(const IntSize&, char*, int)
645 {
646     notImplemented();
647     return nullptr;
648 }
649
650 PassRefPtr<Image> GraphicsSurface::createReadOnlyImage(const IntRect&)
651 {
652     notImplemented();
653     return 0;
654 }
655 #endif
656 }
657 #endif