Bug 574778 - Fix win widget's ConstrainPosition so that it supports full screen windo...
[mozilla-central.git] / gfx / thebes / GLContextProviderGLX.cpp
blobeef367971bf46d3e6d5cf822fa415c5fe040fca2
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Initial Developer of the Original Code is Mozilla Foundation.
16 * Portions created by the Initial Developer are Copyright (C) 2010
17 * the Initial Developer. All Rights Reserved.
19 * Contributor(s):
20 * Matt Woodrow <mwoodrow@mozilla.com>
21 * Bas Schouten <bschouten@mozilla.com>
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #ifdef MOZ_WIDGET_GTK2
38 #include <gdk/gdk.h>
39 #include <gdk/gdkx.h>
40 #define GET_NATIVE_WINDOW(aWidget) GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW))
41 #elif defined(MOZ_WIDGET_QT)
42 #include <QWidget>
43 #include <QX11Info>
44 #define GET_NATIVE_WINDOW(aWidget) static_cast<QWidget*>(aWidget->GetNativeData(NS_NATIVE_SHELLWIDGET))->handle()
45 #endif
47 #include <X11/Xlib.h>
48 #include <X11/Xutil.h>
50 #include "mozilla/X11Util.h"
52 #include "GLContextProvider.h"
53 #include "nsDebug.h"
54 #include "nsIWidget.h"
55 #include "GLXLibrary.h"
56 #include "gfxXlibSurface.h"
57 #include "gfxContext.h"
58 #include "gfxImageSurface.h"
59 #include "gfxPlatform.h"
61 namespace mozilla {
62 namespace gl {
64 static PRBool gIsATI = PR_FALSE;
65 static PRBool gIsChromium = PR_FALSE;
66 static int gGLXVersion = 0;
68 PRBool
69 GLXLibrary::EnsureInitialized()
71 if (mInitialized) {
72 return PR_TRUE;
75 if (!mOGLLibrary) {
76 mOGLLibrary = PR_LoadLibrary("libGL.so.1");
77 if (!mOGLLibrary) {
78 NS_WARNING("Couldn't load OpenGL shared library.");
79 return PR_FALSE;
83 LibrarySymbolLoader::SymLoadStruct symbols[] = {
84 { (PRFuncPtr*) &xDeleteContext, { "glXDestroyContext", NULL } },
85 { (PRFuncPtr*) &xMakeCurrent, { "glXMakeCurrent", NULL } },
86 { (PRFuncPtr*) &xGetProcAddress, { "glXGetProcAddress", NULL } },
87 { (PRFuncPtr*) &xChooseVisual, { "glXChooseVisual", NULL } },
88 { (PRFuncPtr*) &xChooseFBConfig, { "glXChooseFBConfig", NULL } },
89 { (PRFuncPtr*) &xGetFBConfigs, { "glXGetFBConfigs", NULL } },
90 { (PRFuncPtr*) &xCreatePbuffer, { "glXCreatePbuffer", NULL } },
91 { (PRFuncPtr*) &xCreateNewContext, { "glXCreateNewContext", NULL } },
92 { (PRFuncPtr*) &xDestroyPbuffer, { "glXDestroyPbuffer", NULL } },
93 { (PRFuncPtr*) &xGetVisualFromFBConfig, { "glXGetVisualFromFBConfig", NULL } },
94 { (PRFuncPtr*) &xGetFBConfigAttrib, { "glXGetFBConfigAttrib", NULL } },
95 { (PRFuncPtr*) &xSwapBuffers, { "glXSwapBuffers", NULL } },
96 { (PRFuncPtr*) &xQueryServerString, { "glXQueryServerString", NULL } },
97 { (PRFuncPtr*) &xCreatePixmap, { "glXCreatePixmap", NULL } },
98 { (PRFuncPtr*) &xDestroyPixmap, { "glXDestroyPixmap", NULL } },
99 { (PRFuncPtr*) &xGetClientString, { "glXGetClientString", NULL } },
100 { (PRFuncPtr*) &xCreateContext, { "glXCreateContext", NULL } },
101 { NULL, { NULL } }
104 if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &symbols[0])) {
105 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
106 return PR_FALSE;
109 const char *vendor = xQueryServerString(DefaultXDisplay(),
110 DefaultScreen(DefaultXDisplay()),
111 GLX_VENDOR);
112 const char *serverVersionStr = xQueryServerString(DefaultXDisplay(),
113 DefaultScreen(DefaultXDisplay()),
114 GLX_VERSION);
115 const char *clientVersionStr = xGetClientString(DefaultXDisplay(),
116 GLX_VERSION);
119 int serverVersion = 0, clientVersion = 0;
120 if (serverVersionStr &&
121 strlen(serverVersionStr) >= 3 &&
122 serverVersionStr[1] == '.')
124 serverVersion = (serverVersionStr[0] - '0') << 8 | (serverVersionStr[2] - '0');
127 if (clientVersionStr &&
128 strlen(clientVersionStr) >= 3 &&
129 clientVersionStr[1] == '.')
131 clientVersion = (clientVersionStr[0] - '0') << 8 | (clientVersionStr[2] - '0');
134 gGLXVersion = PR_MIN(clientVersion, serverVersion);
136 if (gGLXVersion < 0x0103)
137 return PR_FALSE;
139 gIsATI = vendor && strstr(vendor, "ATI");
140 gIsChromium = (vendor && strstr(vendor, "Chromium")) ||
141 (serverVersion && strstr(serverVersionStr, "Chromium"));
143 mInitialized = PR_TRUE;
144 return PR_TRUE;
147 GLXLibrary sGLXLibrary;
149 static bool ctxErrorOccurred = false;
150 static int
151 ctxErrorHandler(Display *dpy, XErrorEvent *ev)
153 ctxErrorOccurred = true;
154 return 0;
157 class GLContextGLX : public GLContext
159 public:
160 static already_AddRefed<GLContextGLX>
161 CreateGLContext(const ContextFormat& format,
162 Display *display,
163 GLXDrawable drawable,
164 GLXFBConfig cfg,
165 XVisualInfo *vinfo,
166 GLContextGLX *shareContext,
167 PRBool deleteDrawable,
168 gfxXlibSurface *pixmap = nsnull)
170 int db = 0, err;
171 err = sGLXLibrary.xGetFBConfigAttrib(display, cfg,
172 GLX_DOUBLEBUFFER, &db);
173 if (GLX_BAD_ATTRIBUTE != err) {
174 #ifdef DEBUG
175 printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
176 #endif
179 ctxErrorOccurred = false;
180 int (*oldHandler)(Display *, XErrorEvent *);
181 GLXContext context;
183 TRY_AGAIN_NO_SHARING:
184 oldHandler = XSetErrorHandler(&ctxErrorHandler);
186 if (gGLXVersion >= 0x0103) {
187 context = sGLXLibrary.xCreateNewContext(display,
188 cfg,
189 GLX_RGBA_TYPE,
190 shareContext ? shareContext->mContext : NULL,
191 True);
192 } else {
193 context = sGLXLibrary.xCreateContext(display,
194 vinfo,
195 shareContext ? shareContext->mContext : NULL,
196 True);
199 XSync(display, False);
200 XSetErrorHandler(oldHandler);
202 if (!context || ctxErrorOccurred) {
203 if (shareContext) {
204 shareContext = nsnull;
205 goto TRY_AGAIN_NO_SHARING;
207 NS_WARNING("Failed to create GLXContext!");
208 return nsnull;
211 nsRefPtr<GLContextGLX> glContext(new GLContextGLX(format,
212 shareContext,
213 display,
214 drawable,
215 context,
216 deleteDrawable,
218 pixmap));
219 if (!glContext->Init()) {
220 return nsnull;
223 return glContext.forget();
226 ~GLContextGLX()
228 sGLXLibrary.xDeleteContext(mDisplay, mContext);
230 if (mDeleteDrawable) {
231 sGLXLibrary.xDestroyPixmap(mDisplay, mDrawable);
235 GLContextType GetContextType() {
236 return ContextTypeGLX;
239 PRBool Init()
241 MakeCurrent();
242 SetupLookupFunction();
243 if (!InitWithPrefix("gl", PR_TRUE)) {
244 return PR_FALSE;
247 return IsExtensionSupported("GL_EXT_framebuffer_object");
250 PRBool MakeCurrent()
252 Bool succeeded = sGLXLibrary.xMakeCurrent(mDisplay, mDrawable, mContext);
253 NS_ASSERTION(succeeded, "Failed to make GL context current!");
254 return succeeded;
257 PRBool SetupLookupFunction()
259 mLookupFunc = (PlatformLookupFunction)sGLXLibrary.xGetProcAddress;
260 return PR_TRUE;
263 void *GetNativeData(NativeDataType aType)
265 switch(aType) {
266 case NativeGLContext:
267 return mContext;
269 case NativeThebesSurface:
270 return mPixmap;
272 default:
273 return nsnull;
277 PRBool IsDoubleBuffered()
279 return mDoubleBuffered;
282 PRBool SwapBuffers()
284 if (!mDoubleBuffered)
285 return PR_FALSE;
286 sGLXLibrary.xSwapBuffers(mDisplay, mDrawable);
287 return PR_TRUE;
290 void WindowDestroyed()
292 for (unsigned int i=0; i<textures.Length(); i++) {
293 GLContext::DestroyTexture(textures.ElementAt(i));
295 textures.Clear();
298 // NB: we could set a flag upon WindowDestroyed() to dictate an
299 // early-return from CreateTexture(), but then we would need the
300 // same check before all GL calls, and that heads down a rabbit
301 // hole.
302 virtual GLuint CreateTexture()
304 GLuint tex = GLContext::CreateTexture();
305 NS_ASSERTION(!textures.Contains(tex), "");
306 textures.AppendElement(tex);
307 return tex;
310 virtual void DestroyTexture(GLuint texture)
312 if (textures.Contains(texture)) {
313 textures.RemoveElement(texture);
314 GLContext::DestroyTexture(texture);
318 virtual already_AddRefed<TextureImage>
319 CreateBasicTextureImage(GLuint aTexture,
320 const nsIntSize& aSize,
321 TextureImage::ContentType aContentType,
322 GLContext* aContext);
324 private:
325 friend class GLContextProviderGLX;
327 GLContextGLX(const ContextFormat& aFormat,
328 GLContext *aShareContext,
329 Display *aDisplay,
330 GLXDrawable aDrawable,
331 GLXContext aContext,
332 PRBool aDeleteDrawable,
333 PRBool aDoubleBuffered,
334 gfxXlibSurface *aPixmap)
335 : GLContext(aFormat, aDeleteDrawable ? PR_TRUE : PR_FALSE, aShareContext),
336 mContext(aContext),
337 mDisplay(aDisplay),
338 mDrawable(aDrawable),
339 mDeleteDrawable(aDeleteDrawable),
340 mDoubleBuffered(aDoubleBuffered),
341 mPixmap(aPixmap)
344 GLXContext mContext;
345 Display *mDisplay;
346 GLXDrawable mDrawable;
347 PRPackedBool mDeleteDrawable;
348 PRPackedBool mDoubleBuffered;
350 nsTArray<GLuint> textures;
351 nsRefPtr<gfxXlibSurface> mPixmap;
354 // FIXME/bug 575505: this is a (very slow!) placeholder
355 // implementation. Much better would be to create a Pixmap, wrap that
356 // in a GLXPixmap, and then glXBindTexImage() to our texture.
357 class TextureImageGLX : public BasicTextureImage
359 friend already_AddRefed<TextureImage>
360 GLContextGLX::CreateBasicTextureImage(GLuint,
361 const nsIntSize&,
362 TextureImage::ContentType,
363 GLContext*);
365 protected:
366 virtual already_AddRefed<gfxASurface>
367 CreateUpdateSurface(const gfxIntSize& aSize, ImageFormat aFmt)
369 mUpdateFormat = aFmt;
370 return gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, aFmt);
373 virtual already_AddRefed<gfxImageSurface>
374 GetImageForUpload(gfxASurface* aUpdateSurface)
376 nsRefPtr<gfxImageSurface> image =
377 new gfxImageSurface(gfxIntSize(mUpdateRect.width,
378 mUpdateRect.height),
379 mUpdateFormat);
380 nsRefPtr<gfxContext> tmpContext = new gfxContext(image);
382 tmpContext->SetSource(aUpdateSurface);
383 tmpContext->SetOperator(gfxContext::OPERATOR_SOURCE);
384 tmpContext->Paint();
386 return image.forget();
389 private:
390 TextureImageGLX(GLuint aTexture,
391 const nsIntSize& aSize,
392 ContentType aContentType,
393 GLContext* aContext)
394 : BasicTextureImage(aTexture, aSize, aContentType, aContext)
397 ImageFormat mUpdateFormat;
400 already_AddRefed<TextureImage>
401 GLContextGLX::CreateBasicTextureImage(GLuint aTexture,
402 const nsIntSize& aSize,
403 TextureImage::ContentType aContentType,
404 GLContext* aContext)
406 nsRefPtr<TextureImageGLX> teximage(
407 new TextureImageGLX(aTexture, aSize, aContentType, aContext));
408 return teximage.forget();
411 static GLContextGLX *
412 GetGlobalContextGLX()
414 return static_cast<GLContextGLX*>(GLContextProviderGLX::GetGlobalContext());
417 static PRBool
418 AreCompatibleVisuals(XVisualInfo *one, XVisualInfo *two)
420 if (one->c_class != two->c_class) {
421 return PR_FALSE;
424 if (one->depth != two->depth) {
425 return PR_FALSE;
428 if (one->red_mask != two->red_mask ||
429 one->green_mask != two->green_mask ||
430 one->blue_mask != two->blue_mask) {
431 return PR_FALSE;
434 if (one->bits_per_rgb != two->bits_per_rgb) {
435 return PR_FALSE;
438 return PR_TRUE;
441 already_AddRefed<GLContext>
442 GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
444 if (!sGLXLibrary.EnsureInitialized()) {
445 return nsnull;
448 // Currently, we take whatever Visual the window already has, and
449 // try to create an fbconfig for that visual. This isn't
450 // necessarily what we want in the long run; an fbconfig may not
451 // be available for the existing visual, or if it is, the GL
452 // performance might be suboptimal. But using the existing visual
453 // is a relatively safe intermediate step.
455 Display *display = (Display*)aWidget->GetNativeData(NS_NATIVE_DISPLAY);
456 int xscreen = DefaultScreen(display);
457 Window window = GET_NATIVE_WINDOW(aWidget);
459 int numConfigs;
460 ScopedXFree<GLXFBConfig> cfgs;
461 if (gIsATI) {
462 const int attribs[] = {
463 GLX_DOUBLEBUFFER, False,
466 cfgs = sGLXLibrary.xChooseFBConfig(display,
467 xscreen,
468 attribs,
469 &numConfigs);
470 } else {
471 cfgs = sGLXLibrary.xGetFBConfigs(display,
472 xscreen,
473 &numConfigs);
476 if (!cfgs) {
477 NS_WARNING("[GLX] glXGetFBConfigs() failed");
478 return nsnull;
480 NS_ASSERTION(numConfigs > 0, "No FBConfigs found!");
482 // XXX the visual ID is almost certainly the GLX_FBCONFIG_ID, so
483 // we could probably do this first and replace the glXGetFBConfigs
484 // with glXChooseConfigs. Docs are sparklingly clear as always.
485 XWindowAttributes widgetAttrs;
486 if (!XGetWindowAttributes(display, window, &widgetAttrs)) {
487 NS_WARNING("[GLX] XGetWindowAttributes() failed");
488 XFree(cfgs);
489 return nsnull;
491 const VisualID widgetVisualID = XVisualIDFromVisual(widgetAttrs.visual);
492 #ifdef DEBUG
493 printf("[GLX] widget has VisualID 0x%lx\n", widgetVisualID);
494 #endif
496 ScopedXFree<XVisualInfo> vi;
497 if (gIsATI) {
498 XVisualInfo vinfo_template;
499 int nvisuals;
500 vinfo_template.visual = widgetAttrs.visual;
501 vinfo_template.visualid = XVisualIDFromVisual(vinfo_template.visual);
502 vinfo_template.depth = widgetAttrs.depth;
503 vinfo_template.screen = xscreen;
504 vi = XGetVisualInfo(display, VisualIDMask|VisualDepthMask|VisualScreenMask,
505 &vinfo_template, &nvisuals);
506 NS_ASSERTION(vi && nvisuals == 1, "Could not locate unique matching XVisualInfo for Visual");
509 int matchIndex = -1;
510 ScopedXFree<XVisualInfo> vinfo;
512 for (int i = 0; i < numConfigs; i++) {
513 vinfo = sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]);
514 if (!vinfo) {
515 continue;
517 if (gIsATI) {
518 if (AreCompatibleVisuals(vi, vinfo)) {
519 matchIndex = i;
520 break;
522 } else {
523 if (widgetVisualID == vinfo->visualid) {
524 matchIndex = i;
525 break;
530 if (matchIndex == -1) {
531 NS_WARNING("[GLX] Couldn't find a FBConfig matching widget visual");
532 return nsnull;
535 GLContextGLX *shareContext = GetGlobalContextGLX();
537 nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
538 display,
539 window,
540 cfgs[matchIndex],
541 vinfo,
542 shareContext,
543 PR_FALSE);
544 return glContext.forget();
547 static already_AddRefed<GLContextGLX>
548 CreateOffscreenPixmapContext(const gfxIntSize& aSize,
549 const ContextFormat& aFormat,
550 PRBool aShare)
552 if (!sGLXLibrary.EnsureInitialized()) {
553 return nsnull;
556 Display *display = DefaultXDisplay();
557 int xscreen = DefaultScreen(display);
559 int attribs[] = {
560 GLX_DOUBLEBUFFER, False,
561 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
562 GLX_X_RENDERABLE, True,
563 GLX_RED_SIZE, 1,
564 GLX_GREEN_SIZE, 1,
565 GLX_BLUE_SIZE, 1,
566 GLX_ALPHA_SIZE, 0,
567 GLX_DEPTH_SIZE, 0,
570 int numConfigs = 0;
572 ScopedXFree<GLXFBConfig> cfgs;
573 cfgs = sGLXLibrary.xChooseFBConfig(display,
574 xscreen,
575 attribs,
576 &numConfigs);
577 if (!cfgs) {
578 return nsnull;
581 NS_ASSERTION(numConfigs > 0,
582 "glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
584 ScopedXFree<XVisualInfo> vinfo;
585 int chosenIndex;
587 for (int i = 0; i < numConfigs; ++i) {
588 int dtype, visid;
590 if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], GLX_DRAWABLE_TYPE, &dtype) != Success
591 || !(dtype & GLX_PIXMAP_BIT))
593 continue;
595 if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &visid) != Success
596 || visid == 0)
598 continue;
601 vinfo = sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]);
603 if (vinfo) {
604 chosenIndex = i;
605 break;
609 if (!vinfo) {
610 NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!");
611 return nsnull;
614 nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
615 vinfo->visual,
616 gfxIntSize(16, 16));
617 if (xsurface->CairoStatus() != 0) {
618 return nsnull;
622 GLXPixmap glxpixmap = sGLXLibrary.xCreatePixmap(display,
623 cfgs[chosenIndex],
624 xsurface->XDrawable(),
625 NULL);
626 if (glxpixmap == 0) {
627 return nsnull;
630 GLContextGLX *shareContext = aShare ? GetGlobalContextGLX() : nsnull;
632 nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(aFormat,
633 display,
634 glxpixmap,
635 cfgs[chosenIndex],
636 vinfo,
637 shareContext,
638 PR_TRUE,
639 xsurface);
641 return glContext.forget();
644 already_AddRefed<GLContext>
645 GLContextProviderGLX::CreateOffscreen(const gfxIntSize& aSize,
646 const ContextFormat& aFormat)
649 nsRefPtr<GLContextGLX> glContext =
650 CreateOffscreenPixmapContext(aSize, aFormat, PR_TRUE);
652 if (!glContext) {
653 return nsnull;
656 if (!glContext->GetSharedContext()) {
657 // no point in returning anything if sharing failed, we can't
658 // render from this
659 return nsnull;
662 if (!glContext->ResizeOffscreenFBO(aSize)) {
663 // we weren't able to create the initial
664 // offscreen FBO, so this is dead
665 return nsnull;
668 return glContext.forget();
671 already_AddRefed<GLContext>
672 GLContextProviderGLX::CreateForNativePixmapSurface(gfxASurface *aSurface)
674 if (!sGLXLibrary.EnsureInitialized()) {
675 return nsnull;
678 if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib) {
679 NS_WARNING("GLContextProviderGLX::CreateForNativePixmapSurface called with non-Xlib surface");
680 return nsnull;
683 nsAutoTArray<int, 20> attribs;
685 #define A1_(_x) do { attribs.AppendElement(_x); } while(0)
686 #define A2_(_x,_y) do { \
687 attribs.AppendElement(_x); \
688 attribs.AppendElement(_y); \
689 } while(0)
691 A2_(GLX_DOUBLEBUFFER, False);
692 A2_(GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT);
693 A1_(0);
695 int numFormats;
696 Display *display = DefaultXDisplay();
697 int xscreen = DefaultScreen(display);
699 ScopedXFree<GLXFBConfig> cfg(sGLXLibrary.xChooseFBConfig(display,
700 xscreen,
701 attribs.Elements(),
702 &numFormats));
703 if (!cfg) {
704 return nsnull;
706 NS_ASSERTION(numFormats > 0,
707 "glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
709 gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
711 GLXPixmap glxpixmap = sGLXLibrary.xCreatePixmap(display,
712 cfg[0],
713 xs->XDrawable(),
714 NULL);
716 nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
717 display,
718 glxpixmap,
719 cfg[0],
720 NULL,
721 NULL,
722 PR_FALSE,
723 xs);
725 if (!glContext->Init()) {
726 return nsnull;
729 return glContext.forget();
732 static nsRefPtr<GLContext> gGlobalContext;
734 GLContext *
735 GLContextProviderGLX::GetGlobalContext()
737 static bool triedToCreateContext = false;
738 if (!triedToCreateContext && !gGlobalContext) {
739 triedToCreateContext = true;
740 gGlobalContext = CreateOffscreenPixmapContext(gfxIntSize(1, 1),
741 ContextFormat(ContextFormat::BasicRGB24),
742 PR_FALSE);
745 return gGlobalContext;
748 void
749 GLContextProviderGLX::Shutdown()
751 gGlobalContext = nsnull;
754 } /* namespace gl */
755 } /* namespace mozilla */