Backed out changeset b88172246b66 due to Win32 debug failures.
[mozilla-central.git] / gfx / thebes / GLContextProviderGLX.cpp
blob7df1df545e7885da4380fa405818a574724254e5
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 "prenv.h"
53 #include "GLContextProvider.h"
54 #include "nsDebug.h"
55 #include "nsIWidget.h"
56 #include "GLXLibrary.h"
57 #include "gfxXlibSurface.h"
58 #include "gfxContext.h"
59 #include "gfxImageSurface.h"
60 #include "gfxPlatform.h"
61 #include "GLContext.h"
63 namespace mozilla {
64 namespace gl {
66 static PRBool gIsATI = PR_FALSE;
67 static PRBool gIsChromium = PR_FALSE;
68 static int gGLXMajorVersion = 0, gGLXMinorVersion = 0;
70 // Check that we have at least version aMajor.aMinor .
71 static inline bool
72 GLXVersionCheck(int aMajor, int aMinor)
74 return aMajor < gGLXMajorVersion ||
75 (aMajor == gGLXMajorVersion && aMinor <= gGLXMinorVersion);
78 static inline bool
79 HasExtension(const char* aExtensions, const char* aRequiredExtension)
81 return GLContext::ListHasExtension(
82 reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension);
85 PRBool
86 GLXLibrary::EnsureInitialized()
88 if (mInitialized) {
89 return PR_TRUE;
92 // Don't repeatedly try to initialize.
93 if (mTriedInitializing) {
94 return PR_FALSE;
96 mTriedInitializing = PR_TRUE;
98 if (!mOGLLibrary) {
99 mOGLLibrary = PR_LoadLibrary("libGL.so.1");
100 if (!mOGLLibrary) {
101 NS_WARNING("Couldn't load OpenGL shared library.");
102 return PR_FALSE;
106 LibrarySymbolLoader::SymLoadStruct symbols[] = {
107 /* functions that were in GLX 1.0 */
108 { (PRFuncPtr*) &xDestroyContext, { "glXDestroyContext", NULL } },
109 { (PRFuncPtr*) &xMakeCurrent, { "glXMakeCurrent", NULL } },
110 { (PRFuncPtr*) &xSwapBuffers, { "glXSwapBuffers", NULL } },
111 { (PRFuncPtr*) &xQueryVersion, { "glXQueryVersion", NULL } },
112 { (PRFuncPtr*) &xGetCurrentContext, { "glXGetCurrentContext", NULL } },
113 /* functions introduced in GLX 1.1 */
114 { (PRFuncPtr*) &xQueryExtensionsString, { "glXQueryExtensionsString", NULL } },
115 { (PRFuncPtr*) &xQueryServerString, { "glXQueryServerString", NULL } },
116 { NULL, { NULL } }
119 LibrarySymbolLoader::SymLoadStruct symbols13[] = {
120 /* functions introduced in GLX 1.3 */
121 { (PRFuncPtr*) &xChooseFBConfig, { "glXChooseFBConfig", NULL } },
122 { (PRFuncPtr*) &xGetFBConfigAttrib, { "glXGetFBConfigAttrib", NULL } },
123 // WARNING: xGetFBConfigs not set in symbols13_ext
124 { (PRFuncPtr*) &xGetFBConfigs, { "glXGetFBConfigs", NULL } },
125 { (PRFuncPtr*) &xGetVisualFromFBConfig, { "glXGetVisualFromFBConfig", NULL } },
126 // WARNING: symbols13_ext sets xCreateGLXPixmapWithConfig instead
127 { (PRFuncPtr*) &xCreatePixmap, { "glXCreatePixmap", NULL } },
128 { (PRFuncPtr*) &xDestroyPixmap, { "glXDestroyPixmap", NULL } },
129 { (PRFuncPtr*) &xCreateNewContext, { "glXCreateNewContext", NULL } },
130 { NULL, { NULL } }
133 LibrarySymbolLoader::SymLoadStruct symbols13_ext[] = {
134 /* extension equivalents for functions introduced in GLX 1.3 */
135 // GLX_SGIX_fbconfig extension
136 { (PRFuncPtr*) &xChooseFBConfig, { "glXChooseFBConfigSGIX", NULL } },
137 { (PRFuncPtr*) &xGetFBConfigAttrib, { "glXGetFBConfigAttribSGIX", NULL } },
138 // WARNING: no xGetFBConfigs equivalent in extensions
139 { (PRFuncPtr*) &xGetVisualFromFBConfig, { "glXGetVisualFromFBConfig", NULL } },
140 // WARNING: different from symbols13:
141 { (PRFuncPtr*) &xCreateGLXPixmapWithConfig, { "glXCreateGLXPixmapWithConfigSGIX", NULL } },
142 { (PRFuncPtr*) &xDestroyPixmap, { "glXDestroyGLXPixmap", NULL } }, // not from ext
143 { (PRFuncPtr*) &xCreateNewContext, { "glXCreateContextWithConfigSGIX", NULL } },
144 { NULL, { NULL } }
147 LibrarySymbolLoader::SymLoadStruct symbols14[] = {
148 /* functions introduced in GLX 1.4 */
149 { (PRFuncPtr*) &xGetProcAddress, { "glXGetProcAddress", NULL } },
150 { NULL, { NULL } }
153 LibrarySymbolLoader::SymLoadStruct symbols14_ext[] = {
154 /* extension equivalents for functions introduced in GLX 1.4 */
155 // GLX_ARB_get_proc_address extension
156 { (PRFuncPtr*) &xGetProcAddress, { "glXGetProcAddressARB", NULL } },
157 { NULL, { NULL } }
160 if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &symbols[0])) {
161 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
162 return PR_FALSE;
165 Display *display = DefaultXDisplay();
166 int screen = DefaultScreen(display);
167 if (!xQueryVersion(display, &gGLXMajorVersion, &gGLXMinorVersion)) {
168 gGLXMajorVersion = 0;
169 gGLXMinorVersion = 0;
170 return PR_FALSE;
173 const char *vendor = xQueryServerString(display, screen, GLX_VENDOR);
174 const char *serverVersionStr = xQueryServerString(display, screen, GLX_VERSION);
176 if (!GLXVersionCheck(1, 1))
177 // Not possible to query for extensions.
178 return PR_FALSE;
180 const char *extensionsStr = xQueryExtensionsString(display, screen);
182 LibrarySymbolLoader::SymLoadStruct *sym13;
183 if (!GLXVersionCheck(1, 3)) {
184 // Even if we don't have 1.3, we might have equivalent extensions
185 // (as on the Intel X server).
186 if (!HasExtension(extensionsStr, "GLX_SGIX_fbconfig")) {
187 return PR_FALSE;
189 sym13 = symbols13_ext;
190 } else {
191 sym13 = symbols13;
193 if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, sym13)) {
194 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
195 return PR_FALSE;
198 LibrarySymbolLoader::SymLoadStruct *sym14;
199 if (!GLXVersionCheck(1, 4)) {
200 // Even if we don't have 1.4, we might have equivalent extensions
201 // (as on the Intel X server).
202 if (!HasExtension(extensionsStr, "GLX_ARB_get_proc_address")) {
203 return PR_FALSE;
205 sym14 = symbols14_ext;
206 } else {
207 sym14 = symbols14;
209 if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, sym14)) {
210 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
211 return PR_FALSE;
214 gIsATI = vendor && DoesVendorStringMatch(vendor, "ATI");
215 gIsChromium = (vendor && DoesVendorStringMatch(vendor, "Chromium")) ||
216 (serverVersionStr && DoesVendorStringMatch(serverVersionStr, "Chromium"));
218 mInitialized = PR_TRUE;
219 return PR_TRUE;
222 GLXLibrary sGLXLibrary;
224 class GLContextGLX : public GLContext
226 public:
227 static already_AddRefed<GLContextGLX>
228 CreateGLContext(const ContextFormat& format,
229 Display *display,
230 GLXDrawable drawable,
231 GLXFBConfig cfg,
232 XVisualInfo *vinfo,
233 GLContextGLX *shareContext,
234 PRBool deleteDrawable,
235 gfxXlibSurface *pixmap = nsnull)
237 const char *glxVendorString = sGLXLibrary.xQueryServerString(display, DefaultScreen(display), GLX_VENDOR);
238 if (strcmp(glxVendorString, "NVIDIA Corporation") &&
239 !PR_GetEnv("MOZ_GLX_IGNORE_BLACKLIST"))
241 printf("[GLX] currently only allowing the NVIDIA proprietary driver, as other drivers are giving too many crashes. "
242 "To bypass this, define the MOZ_GLX_IGNORE_BLACKLIST environment variable.\n");
243 return nsnull;
246 int db = 0, err;
247 err = sGLXLibrary.xGetFBConfigAttrib(display, cfg,
248 GLX_DOUBLEBUFFER, &db);
249 if (GLX_BAD_ATTRIBUTE != err) {
250 #ifdef DEBUG
251 printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
252 #endif
255 GLXContext context;
256 nsRefPtr<GLContextGLX> glContext;
257 bool error = false;
259 ScopedXErrorHandler xErrorHandler;
261 TRY_AGAIN_NO_SHARING:
263 context = sGLXLibrary.xCreateNewContext(display,
264 cfg,
265 GLX_RGBA_TYPE,
266 shareContext ? shareContext->mContext : NULL,
267 True);
269 if (context) {
270 glContext = new GLContextGLX(format,
271 shareContext,
272 display,
273 drawable,
274 context,
275 deleteDrawable,
277 pixmap);
278 if (!glContext->Init())
279 error = true;
280 } else {
281 error = true;
284 if (shareContext) {
285 if (error || xErrorHandler.SyncAndGetError(display)) {
286 shareContext = nsnull;
287 goto TRY_AGAIN_NO_SHARING;
291 // at this point, if shareContext != null, we know there's no error.
292 // it's important to minimize the number of XSyncs for startup performance.
293 if (!shareContext) {
294 if (error || // earlier recorded error
295 xErrorHandler.SyncAndGetError(display))
297 NS_WARNING("Failed to create GLXContext!");
298 glContext = nsnull; // note: this must be done while the graceful X error handler is set,
299 // because glxMakeCurrent can give a GLXBadDrawable error
303 return glContext.forget();
306 ~GLContextGLX()
308 MarkDestroyed();
310 sGLXLibrary.xDestroyContext(mDisplay, mContext);
312 if (mDeleteDrawable) {
313 sGLXLibrary.xDestroyPixmap(mDisplay, mDrawable);
317 GLContextType GetContextType() {
318 return ContextTypeGLX;
321 PRBool Init()
323 MakeCurrent();
324 SetupLookupFunction();
325 if (!InitWithPrefix("gl", PR_TRUE)) {
326 return PR_FALSE;
329 return IsExtensionSupported("GL_EXT_framebuffer_object");
332 PRBool MakeCurrentImpl(PRBool aForce = PR_FALSE)
334 PRBool succeeded = PR_TRUE;
336 // With the ATI FGLRX driver, glxMakeCurrent is very slow even when the context doesn't change.
337 // (This is not the case with other drivers such as NVIDIA).
338 // So avoid calling it more than necessary. Since GLX documentation says that:
339 // "glXGetCurrentContext returns client-side information.
340 // It does not make a round trip to the server."
341 // I assume that it's not worth using our own TLS slot here.
342 if (aForce || sGLXLibrary.xGetCurrentContext() != mContext) {
343 succeeded = sGLXLibrary.xMakeCurrent(mDisplay, mDrawable, mContext);
344 NS_ASSERTION(succeeded, "Failed to make GL context current!");
347 return succeeded;
350 PRBool SetupLookupFunction()
352 mLookupFunc = (PlatformLookupFunction)sGLXLibrary.xGetProcAddress;
353 return PR_TRUE;
356 void *GetNativeData(NativeDataType aType)
358 switch(aType) {
359 case NativeGLContext:
360 return mContext;
362 case NativeThebesSurface:
363 return mPixmap;
365 default:
366 return nsnull;
370 PRBool IsDoubleBuffered()
372 return mDoubleBuffered;
375 PRBool SwapBuffers()
377 if (!mDoubleBuffered)
378 return PR_FALSE;
379 sGLXLibrary.xSwapBuffers(mDisplay, mDrawable);
380 return PR_TRUE;
383 private:
384 friend class GLContextProviderGLX;
386 GLContextGLX(const ContextFormat& aFormat,
387 GLContext *aShareContext,
388 Display *aDisplay,
389 GLXDrawable aDrawable,
390 GLXContext aContext,
391 PRBool aDeleteDrawable,
392 PRBool aDoubleBuffered,
393 gfxXlibSurface *aPixmap)
394 : GLContext(aFormat, aDeleteDrawable ? PR_TRUE : PR_FALSE, aShareContext),
395 mContext(aContext),
396 mDisplay(aDisplay),
397 mDrawable(aDrawable),
398 mDeleteDrawable(aDeleteDrawable),
399 mDoubleBuffered(aDoubleBuffered),
400 mPixmap(aPixmap)
403 GLXContext mContext;
404 Display *mDisplay;
405 GLXDrawable mDrawable;
406 PRPackedBool mDeleteDrawable;
407 PRPackedBool mDoubleBuffered;
409 nsRefPtr<gfxXlibSurface> mPixmap;
412 static GLContextGLX *
413 GetGlobalContextGLX()
415 return static_cast<GLContextGLX*>(GLContextProviderGLX::GetGlobalContext());
418 static PRBool
419 AreCompatibleVisuals(XVisualInfo *one, XVisualInfo *two)
421 if (one->c_class != two->c_class) {
422 return PR_FALSE;
425 if (one->depth != two->depth) {
426 return PR_FALSE;
429 if (one->red_mask != two->red_mask ||
430 one->green_mask != two->green_mask ||
431 one->blue_mask != two->blue_mask) {
432 return PR_FALSE;
435 if (one->bits_per_rgb != two->bits_per_rgb) {
436 return PR_FALSE;
439 return PR_TRUE;
442 already_AddRefed<GLContext>
443 GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
445 if (!sGLXLibrary.EnsureInitialized()) {
446 return nsnull;
449 // Currently, we take whatever Visual the window already has, and
450 // try to create an fbconfig for that visual. This isn't
451 // necessarily what we want in the long run; an fbconfig may not
452 // be available for the existing visual, or if it is, the GL
453 // performance might be suboptimal. But using the existing visual
454 // is a relatively safe intermediate step.
456 Display *display = (Display*)aWidget->GetNativeData(NS_NATIVE_DISPLAY);
457 int xscreen = DefaultScreen(display);
458 Window window = GET_NATIVE_WINDOW(aWidget);
460 int numConfigs;
461 ScopedXFree<GLXFBConfig> cfgs;
462 if (gIsATI || !GLXVersionCheck(1, 3)) {
463 const int attribs[] = {
464 GLX_DOUBLEBUFFER, False,
467 cfgs = sGLXLibrary.xChooseFBConfig(display,
468 xscreen,
469 attribs,
470 &numConfigs);
471 } else {
472 cfgs = sGLXLibrary.xGetFBConfigs(display,
473 xscreen,
474 &numConfigs);
477 if (!cfgs) {
478 NS_WARNING("[GLX] glXGetFBConfigs() failed");
479 return nsnull;
481 NS_ASSERTION(numConfigs > 0, "No FBConfigs found!");
483 // XXX the visual ID is almost certainly the GLX_FBCONFIG_ID, so
484 // we could probably do this first and replace the glXGetFBConfigs
485 // with glXChooseConfigs. Docs are sparklingly clear as always.
486 XWindowAttributes widgetAttrs;
487 if (!XGetWindowAttributes(display, window, &widgetAttrs)) {
488 NS_WARNING("[GLX] XGetWindowAttributes() failed");
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 = 0;
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 ScopedXErrorHandler xErrorHandler;
615 GLXPixmap glxpixmap = 0;
616 bool error = false;
618 nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
619 vinfo->visual,
620 gfxIntSize(16, 16));
621 if (xsurface->CairoStatus() != 0) {
622 error = true;
623 goto DONE_CREATING_PIXMAP;
626 // Handle slightly different signature between glXCreatePixmap and
627 // its pre-GLX-1.3 extension equivalent (though given the ABI, we
628 // might not need to).
629 if (GLXVersionCheck(1, 3)) {
630 glxpixmap = sGLXLibrary.xCreatePixmap(display,
631 cfgs[chosenIndex],
632 xsurface->XDrawable(),
633 NULL);
634 } else {
635 glxpixmap = sGLXLibrary.xCreateGLXPixmapWithConfig(display,
636 cfgs[chosenIndex],
637 xsurface->
638 XDrawable());
640 if (glxpixmap == 0) {
641 error = true;
644 DONE_CREATING_PIXMAP:
646 nsRefPtr<GLContextGLX> glContext;
647 bool serverError = xErrorHandler.SyncAndGetError(display);
649 if (!error && // earlier recorded error
650 !serverError)
652 glContext = GLContextGLX::CreateGLContext(
653 aFormat,
654 display,
655 glxpixmap,
656 cfgs[chosenIndex],
657 vinfo,
658 aShare ? GetGlobalContextGLX() : nsnull,
659 PR_TRUE,
660 xsurface);
663 return glContext.forget();
666 already_AddRefed<GLContext>
667 GLContextProviderGLX::CreateOffscreen(const gfxIntSize& aSize,
668 const ContextFormat& aFormat)
671 nsRefPtr<GLContextGLX> glContext =
672 CreateOffscreenPixmapContext(aSize, aFormat, PR_TRUE);
674 if (!glContext) {
675 return nsnull;
678 if (!glContext->GetSharedContext()) {
679 // no point in returning anything if sharing failed, we can't
680 // render from this
681 return nsnull;
684 if (!glContext->ResizeOffscreenFBO(aSize)) {
685 // we weren't able to create the initial
686 // offscreen FBO, so this is dead
687 return nsnull;
690 return glContext.forget();
693 already_AddRefed<GLContext>
694 GLContextProviderGLX::CreateForNativePixmapSurface(gfxASurface *aSurface)
696 if (!sGLXLibrary.EnsureInitialized()) {
697 return nsnull;
700 if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib) {
701 NS_WARNING("GLContextProviderGLX::CreateForNativePixmapSurface called with non-Xlib surface");
702 return nsnull;
705 nsAutoTArray<int, 20> attribs;
707 #define A1_(_x) do { attribs.AppendElement(_x); } while(0)
708 #define A2_(_x,_y) do { \
709 attribs.AppendElement(_x); \
710 attribs.AppendElement(_y); \
711 } while(0)
713 A2_(GLX_DOUBLEBUFFER, False);
714 A2_(GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT);
715 A1_(0);
717 int numFormats;
718 Display *display = DefaultXDisplay();
719 int xscreen = DefaultScreen(display);
721 ScopedXFree<GLXFBConfig> cfg(sGLXLibrary.xChooseFBConfig(display,
722 xscreen,
723 attribs.Elements(),
724 &numFormats));
725 if (!cfg) {
726 return nsnull;
728 NS_ASSERTION(numFormats > 0,
729 "glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
731 gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
733 GLXPixmap glxpixmap = sGLXLibrary.xCreatePixmap(display,
734 cfg[0],
735 xs->XDrawable(),
736 NULL);
738 nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
739 display,
740 glxpixmap,
741 cfg[0],
742 NULL,
743 NULL,
744 PR_FALSE,
745 xs);
747 return glContext.forget();
750 static nsRefPtr<GLContext> gGlobalContext;
752 GLContext *
753 GLContextProviderGLX::GetGlobalContext()
755 static bool triedToCreateContext = false;
756 if (!triedToCreateContext && !gGlobalContext) {
757 triedToCreateContext = true;
758 gGlobalContext = CreateOffscreenPixmapContext(gfxIntSize(1, 1),
759 ContextFormat(ContextFormat::BasicRGB24),
760 PR_FALSE);
761 if (gGlobalContext)
762 gGlobalContext->SetIsGlobalSharedContext(PR_TRUE);
765 return gGlobalContext;
768 void
769 GLContextProviderGLX::Shutdown()
771 gGlobalContext = nsnull;
774 } /* namespace gl */
775 } /* namespace mozilla */