gfx/gl/GLContextProviderGLX.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:44214ece2842
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifdef MOZ_WIDGET_GTK
7 #include <gdk/gdk.h>
8 #include <gdk/gdkx.h>
9 #define GET_NATIVE_WINDOW(aWidget) GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW))
10 #elif defined(MOZ_WIDGET_QT)
11 #define GET_NATIVE_WINDOW(aWidget) (Window)(aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW))
12 #endif
13
14 #include <X11/Xlib.h>
15 #include <X11/Xutil.h>
16
17 #include "mozilla/MathAlgorithms.h"
18 #include "mozilla/StaticPtr.h"
19 #include "mozilla/X11Util.h"
20
21 #include "prenv.h"
22 #include "GLContextProvider.h"
23 #include "GLLibraryLoader.h"
24 #include "nsDebug.h"
25 #include "nsIWidget.h"
26 #include "GLXLibrary.h"
27 #include "gfxXlibSurface.h"
28 #include "gfxContext.h"
29 #include "gfxPlatform.h"
30 #include "GLContextGLX.h"
31 #include "gfxUtils.h"
32 #include "gfx2DGlue.h"
33
34 #include "gfxCrashReporterUtils.h"
35
36 #ifdef MOZ_WIDGET_GTK
37 #include "gfxPlatformGtk.h"
38 #endif
39
40 using namespace mozilla::gfx;
41
42 namespace mozilla {
43 namespace gl {
44
45 GLXLibrary sGLXLibrary;
46
47 // Check that we have at least version aMajor.aMinor .
48 bool
49 GLXLibrary::GLXVersionCheck(int aMajor, int aMinor)
50 {
51 return aMajor < mGLXMajorVersion ||
52 (aMajor == mGLXMajorVersion && aMinor <= mGLXMinorVersion);
53 }
54
55 static inline bool
56 HasExtension(const char* aExtensions, const char* aRequiredExtension)
57 {
58 return GLContext::ListHasExtension(
59 reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension);
60 }
61
62 bool
63 GLXLibrary::EnsureInitialized()
64 {
65 if (mInitialized) {
66 return true;
67 }
68
69 // Don't repeatedly try to initialize.
70 if (mTriedInitializing) {
71 return false;
72 }
73 mTriedInitializing = true;
74
75 // Force enabling s3 texture compression. (Bug 774134)
76 PR_SetEnv("force_s3tc_enable=true");
77
78 if (!mOGLLibrary) {
79 const char* libGLfilename = nullptr;
80 bool forceFeatureReport = false;
81
82 // see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1
83 // because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls,
84 // which trigger glibc bug http://sourceware.org/bugzilla/show_bug.cgi?id=12225
85 #ifdef __OpenBSD__
86 libGLfilename = "libGL.so";
87 #else
88 libGLfilename = "libGL.so.1";
89 #endif
90
91 ScopedGfxFeatureReporter reporter(libGLfilename, forceFeatureReport);
92 mOGLLibrary = PR_LoadLibrary(libGLfilename);
93 if (!mOGLLibrary) {
94 NS_WARNING("Couldn't load OpenGL shared library.");
95 return false;
96 }
97 reporter.SetSuccessful();
98 }
99
100 if (PR_GetEnv("MOZ_GLX_DEBUG")) {
101 mDebug = true;
102 }
103
104 GLLibraryLoader::SymLoadStruct symbols[] = {
105 /* functions that were in GLX 1.0 */
106 { (PRFuncPtr*) &xDestroyContextInternal, { "glXDestroyContext", nullptr } },
107 { (PRFuncPtr*) &xMakeCurrentInternal, { "glXMakeCurrent", nullptr } },
108 { (PRFuncPtr*) &xSwapBuffersInternal, { "glXSwapBuffers", nullptr } },
109 { (PRFuncPtr*) &xQueryVersionInternal, { "glXQueryVersion", nullptr } },
110 { (PRFuncPtr*) &xGetCurrentContextInternal, { "glXGetCurrentContext", nullptr } },
111 { (PRFuncPtr*) &xWaitGLInternal, { "glXWaitGL", nullptr } },
112 { (PRFuncPtr*) &xWaitXInternal, { "glXWaitX", nullptr } },
113 /* functions introduced in GLX 1.1 */
114 { (PRFuncPtr*) &xQueryExtensionsStringInternal, { "glXQueryExtensionsString", nullptr } },
115 { (PRFuncPtr*) &xGetClientStringInternal, { "glXGetClientString", nullptr } },
116 { (PRFuncPtr*) &xQueryServerStringInternal, { "glXQueryServerString", nullptr } },
117 { nullptr, { nullptr } }
118 };
119
120 GLLibraryLoader::SymLoadStruct symbols13[] = {
121 /* functions introduced in GLX 1.3 */
122 { (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfig", nullptr } },
123 { (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttrib", nullptr } },
124 // WARNING: xGetFBConfigs not set in symbols13_ext
125 { (PRFuncPtr*) &xGetFBConfigsInternal, { "glXGetFBConfigs", nullptr } },
126 // WARNING: symbols13_ext sets xCreateGLXPixmapWithConfig instead
127 { (PRFuncPtr*) &xCreatePixmapInternal, { "glXCreatePixmap", nullptr } },
128 { (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyPixmap", nullptr } },
129 { (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateNewContext", nullptr } },
130 { nullptr, { nullptr } }
131 };
132
133 GLLibraryLoader::SymLoadStruct symbols13_ext[] = {
134 /* extension equivalents for functions introduced in GLX 1.3 */
135 // GLX_SGIX_fbconfig extension
136 { (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfigSGIX", nullptr } },
137 { (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttribSGIX", nullptr } },
138 // WARNING: no xGetFBConfigs equivalent in extensions
139 // WARNING: different from symbols13:
140 { (PRFuncPtr*) &xCreateGLXPixmapWithConfigInternal, { "glXCreateGLXPixmapWithConfigSGIX", nullptr } },
141 { (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyGLXPixmap", nullptr } }, // not from ext
142 { (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateContextWithConfigSGIX", nullptr } },
143 { nullptr, { nullptr } }
144 };
145
146 GLLibraryLoader::SymLoadStruct symbols14[] = {
147 /* functions introduced in GLX 1.4 */
148 { (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddress", nullptr } },
149 { nullptr, { nullptr } }
150 };
151
152 GLLibraryLoader::SymLoadStruct symbols14_ext[] = {
153 /* extension equivalents for functions introduced in GLX 1.4 */
154 // GLX_ARB_get_proc_address extension
155 { (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddressARB", nullptr } },
156 { nullptr, { nullptr } }
157 };
158
159 GLLibraryLoader::SymLoadStruct symbols_texturefrompixmap[] = {
160 { (PRFuncPtr*) &xBindTexImageInternal, { "glXBindTexImageEXT", nullptr } },
161 { (PRFuncPtr*) &xReleaseTexImageInternal, { "glXReleaseTexImageEXT", nullptr } },
162 { nullptr, { nullptr } }
163 };
164
165 GLLibraryLoader::SymLoadStruct symbols_robustness[] = {
166 { (PRFuncPtr*) &xCreateContextAttribsInternal, { "glXCreateContextAttribsARB", nullptr } },
167 { nullptr, { nullptr } }
168 };
169
170 if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &symbols[0])) {
171 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
172 return false;
173 }
174
175 Display *display = DefaultXDisplay();
176 int screen = DefaultScreen(display);
177
178 if (!xQueryVersion(display, &mGLXMajorVersion, &mGLXMinorVersion)) {
179 mGLXMajorVersion = 0;
180 mGLXMinorVersion = 0;
181 return false;
182 }
183
184 if (!GLXVersionCheck(1, 1))
185 // Not possible to query for extensions.
186 return false;
187
188 const char *clientVendor = xGetClientString(display, LOCAL_GLX_VENDOR);
189 const char *serverVendor = xQueryServerString(display, screen, LOCAL_GLX_VENDOR);
190 const char *extensionsStr = xQueryExtensionsString(display, screen);
191
192 GLLibraryLoader::SymLoadStruct *sym13;
193 if (!GLXVersionCheck(1, 3)) {
194 // Even if we don't have 1.3, we might have equivalent extensions
195 // (as on the Intel X server).
196 if (!HasExtension(extensionsStr, "GLX_SGIX_fbconfig")) {
197 return false;
198 }
199 sym13 = symbols13_ext;
200 } else {
201 sym13 = symbols13;
202 }
203 if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, sym13)) {
204 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
205 return false;
206 }
207
208 GLLibraryLoader::SymLoadStruct *sym14;
209 if (!GLXVersionCheck(1, 4)) {
210 // Even if we don't have 1.4, we might have equivalent extensions
211 // (as on the Intel X server).
212 if (!HasExtension(extensionsStr, "GLX_ARB_get_proc_address")) {
213 return false;
214 }
215 sym14 = symbols14_ext;
216 } else {
217 sym14 = symbols14;
218 }
219 if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, sym14)) {
220 NS_WARNING("Couldn't find required entry point in OpenGL shared library");
221 return false;
222 }
223
224 if (HasExtension(extensionsStr, "GLX_EXT_texture_from_pixmap") &&
225 GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_texturefrompixmap,
226 (GLLibraryLoader::PlatformLookupFunction)&xGetProcAddress))
227 {
228 #ifdef MOZ_WIDGET_GTK
229 mUseTextureFromPixmap = gfxPlatformGtk::GetPlatform()->UseXRender();
230 #else
231 mUseTextureFromPixmap = true;
232 #endif
233 } else {
234 mUseTextureFromPixmap = false;
235 NS_WARNING("Texture from pixmap disabled");
236 }
237
238 if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness") &&
239 GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) {
240 mHasRobustness = true;
241 }
242
243 mIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI");
244 mIsNVIDIA = serverVendor && DoesStringMatch(serverVendor, "NVIDIA Corporation");
245 mClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa");
246
247 mInitialized = true;
248
249 return true;
250 }
251
252 bool
253 GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface)
254 {
255 if (!EnsureInitialized()) {
256 return false;
257 }
258
259 if (aSurface->GetType() != gfxSurfaceType::Xlib || !mUseTextureFromPixmap) {
260 return false;
261 }
262
263 return true;
264 }
265
266 GLXPixmap
267 GLXLibrary::CreatePixmap(gfxASurface* aSurface)
268 {
269 if (!SupportsTextureFromPixmap(aSurface)) {
270 return None;
271 }
272
273 gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
274 const XRenderPictFormat *format = xs->XRenderFormat();
275 if (!format || format->type != PictTypeDirect) {
276 return None;
277 }
278 const XRenderDirectFormat& direct = format->direct;
279 int alphaSize = FloorLog2(direct.alphaMask + 1);
280 NS_ASSERTION((1 << alphaSize) - 1 == direct.alphaMask,
281 "Unexpected render format with non-adjacent alpha bits");
282
283 int attribs[] = { LOCAL_GLX_DOUBLEBUFFER, False,
284 LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT,
285 LOCAL_GLX_ALPHA_SIZE, alphaSize,
286 (alphaSize ? LOCAL_GLX_BIND_TO_TEXTURE_RGBA_EXT
287 : LOCAL_GLX_BIND_TO_TEXTURE_RGB_EXT), True,
288 LOCAL_GLX_RENDER_TYPE, LOCAL_GLX_RGBA_BIT,
289 None };
290
291 int numConfigs = 0;
292 Display *display = xs->XDisplay();
293 int xscreen = DefaultScreen(display);
294
295 ScopedXFree<GLXFBConfig> cfgs(xChooseFBConfig(display,
296 xscreen,
297 attribs,
298 &numConfigs));
299
300 // Find an fbconfig that matches the pixel format used on the Pixmap.
301 int matchIndex = -1;
302 unsigned long redMask =
303 static_cast<unsigned long>(direct.redMask) << direct.red;
304 unsigned long greenMask =
305 static_cast<unsigned long>(direct.greenMask) << direct.green;
306 unsigned long blueMask =
307 static_cast<unsigned long>(direct.blueMask) << direct.blue;
308 // This is true if the Pixmap has bits for alpha or unused bits.
309 bool haveNonColorBits =
310 ~(redMask | greenMask | blueMask) != -1UL << format->depth;
311
312 for (int i = 0; i < numConfigs; i++) {
313 int id = None;
314 sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &id);
315 Visual *visual;
316 int depth;
317 FindVisualAndDepth(display, id, &visual, &depth);
318 if (!visual ||
319 visual->c_class != TrueColor ||
320 visual->red_mask != redMask ||
321 visual->green_mask != greenMask ||
322 visual->blue_mask != blueMask ) {
323 continue;
324 }
325
326 // Historically Xlib Visuals did not try to represent an alpha channel
327 // and there was no means to use an alpha channel on a Pixmap. The
328 // Xlib Visual from the fbconfig was not intended to have any
329 // information about alpha bits.
330 //
331 // Since then, RENDER has added formats for 32 bit depth Pixmaps.
332 // Some of these formats have bits for alpha and some have unused
333 // bits.
334 //
335 // Then the Composite extension added a 32 bit depth Visual intended
336 // for Windows with an alpha channel, so bits not in the visual color
337 // masks were expected to be treated as alpha bits.
338 //
339 // Usually GLX counts only color bits in the Visual depth, but the
340 // depth of Composite's ARGB Visual includes alpha bits. However,
341 // bits not in the color masks are not necessarily alpha bits because
342 // sometimes (NVIDIA) 32 bit Visuals are added for fbconfigs with 32
343 // bit BUFFER_SIZE but zero alpha bits and 24 color bits (NVIDIA
344 // again).
345 //
346 // This checks that the depth matches in one of the two ways.
347 // NVIDIA now forces format->depth == depth so only the first way
348 // is checked for NVIDIA
349 if (depth != format->depth &&
350 (mIsNVIDIA || depth != format->depth - alphaSize) ) {
351 continue;
352 }
353
354 // If all bits of the Pixmap are color bits and the Pixmap depth
355 // matches the depth of the fbconfig visual, then we can assume that
356 // the driver will do whatever is necessary to ensure that any
357 // GLXPixmap alpha bits are treated as set. We can skip the
358 // ALPHA_SIZE check in this situation. We need to skip this check for
359 // situations (ATI) where there are no fbconfigs without alpha bits.
360 //
361 // glXChooseFBConfig should prefer configs with smaller
362 // LOCAL_GLX_BUFFER_SIZE, so we should still get zero alpha bits if
363 // available, except perhaps with NVIDIA drivers where buffer size is
364 // not the specified sum of the component sizes.
365 if (haveNonColorBits) {
366 // There are bits in the Pixmap format that haven't been matched
367 // against the fbconfig visual. These bits could either represent
368 // alpha or be unused, so just check that the number of alpha bits
369 // matches.
370 int size = 0;
371 sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i],
372 LOCAL_GLX_ALPHA_SIZE, &size);
373 if (size != alphaSize) {
374 continue;
375 }
376 }
377
378 matchIndex = i;
379 break;
380 }
381 if (matchIndex == -1) {
382 // GLX can't handle A8 surfaces, so this is not really unexpected. The
383 // caller should deal with this situation.
384 NS_WARN_IF_FALSE(format->depth == 8,
385 "[GLX] Couldn't find a FBConfig matching Pixmap format");
386 return None;
387 }
388
389 int pixmapAttribs[] = { LOCAL_GLX_TEXTURE_TARGET_EXT, LOCAL_GLX_TEXTURE_2D_EXT,
390 LOCAL_GLX_TEXTURE_FORMAT_EXT,
391 (alphaSize ? LOCAL_GLX_TEXTURE_FORMAT_RGBA_EXT
392 : LOCAL_GLX_TEXTURE_FORMAT_RGB_EXT),
393 None};
394
395 GLXPixmap glxpixmap = xCreatePixmap(display,
396 cfgs[matchIndex],
397 xs->XDrawable(),
398 pixmapAttribs);
399
400 return glxpixmap;
401 }
402
403 void
404 GLXLibrary::DestroyPixmap(Display* aDisplay, GLXPixmap aPixmap)
405 {
406 if (!mUseTextureFromPixmap) {
407 return;
408 }
409
410 xDestroyPixmap(aDisplay, aPixmap);
411 }
412
413 void
414 GLXLibrary::BindTexImage(Display* aDisplay, GLXPixmap aPixmap)
415 {
416 if (!mUseTextureFromPixmap) {
417 return;
418 }
419
420 // Make sure all X drawing to the surface has finished before binding to a texture.
421 if (mClientIsMesa) {
422 // Using XSync instead of Mesa's glXWaitX, because its glxWaitX is a
423 // noop when direct rendering unless the current drawable is a
424 // single-buffer window.
425 FinishX(aDisplay);
426 } else {
427 xWaitX();
428 }
429 xBindTexImage(aDisplay, aPixmap, LOCAL_GLX_FRONT_LEFT_EXT, nullptr);
430 }
431
432 void
433 GLXLibrary::ReleaseTexImage(Display* aDisplay, GLXPixmap aPixmap)
434 {
435 if (!mUseTextureFromPixmap) {
436 return;
437 }
438
439 xReleaseTexImage(aDisplay, aPixmap, LOCAL_GLX_FRONT_LEFT_EXT);
440 }
441
442 void
443 GLXLibrary::UpdateTexImage(Display* aDisplay, GLXPixmap aPixmap)
444 {
445 // NVIDIA drivers don't require a rebind of the pixmap in order
446 // to display an updated image, and it's faster not to do it.
447 if (mIsNVIDIA) {
448 xWaitX();
449 return;
450 }
451
452 ReleaseTexImage(aDisplay, aPixmap);
453 BindTexImage(aDisplay, aPixmap);
454 }
455
456 #ifdef DEBUG
457
458 static int (*sOldErrorHandler)(Display *, XErrorEvent *);
459 ScopedXErrorHandler::ErrorEvent sErrorEvent;
460 static int GLXErrorHandler(Display *display, XErrorEvent *ev)
461 {
462 if (!sErrorEvent.mError.error_code) {
463 sErrorEvent.mError = *ev;
464 }
465 return 0;
466 }
467
468 void
469 GLXLibrary::BeforeGLXCall()
470 {
471 if (mDebug) {
472 sOldErrorHandler = XSetErrorHandler(GLXErrorHandler);
473 }
474 }
475
476 void
477 GLXLibrary::AfterGLXCall()
478 {
479 if (mDebug) {
480 FinishX(DefaultXDisplay());
481 if (sErrorEvent.mError.error_code) {
482 char buffer[2048];
483 XGetErrorText(DefaultXDisplay(), sErrorEvent.mError.error_code, buffer, sizeof(buffer));
484 printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %i",
485 buffer,
486 sErrorEvent.mError.error_code,
487 sErrorEvent.mError.request_code,
488 sErrorEvent.mError.minor_code,
489 sErrorEvent.mError.serial);
490 NS_ABORT();
491 }
492 XSetErrorHandler(sOldErrorHandler);
493 }
494 }
495
496 #define BEFORE_GLX_CALL do { \
497 sGLXLibrary.BeforeGLXCall(); \
498 } while (0)
499
500 #define AFTER_GLX_CALL do { \
501 sGLXLibrary.AfterGLXCall(); \
502 } while (0)
503
504 #else
505
506 #define BEFORE_GLX_CALL do { } while(0)
507 #define AFTER_GLX_CALL do { } while(0)
508
509 #endif
510
511 void
512 GLXLibrary::xDestroyContext(Display* display, GLXContext context)
513 {
514 BEFORE_GLX_CALL;
515 xDestroyContextInternal(display, context);
516 AFTER_GLX_CALL;
517 }
518
519 Bool
520 GLXLibrary::xMakeCurrent(Display* display,
521 GLXDrawable drawable,
522 GLXContext context)
523 {
524 BEFORE_GLX_CALL;
525 Bool result = xMakeCurrentInternal(display, drawable, context);
526 AFTER_GLX_CALL;
527 return result;
528 }
529
530 GLXContext
531 GLXLibrary::xGetCurrentContext()
532 {
533 BEFORE_GLX_CALL;
534 GLXContext result = xGetCurrentContextInternal();
535 AFTER_GLX_CALL;
536 return result;
537 }
538
539 /* static */ void*
540 GLXLibrary::xGetProcAddress(const char *procName)
541 {
542 BEFORE_GLX_CALL;
543 void* result = sGLXLibrary.xGetProcAddressInternal(procName);
544 AFTER_GLX_CALL;
545 return result;
546 }
547
548 GLXFBConfig*
549 GLXLibrary::xChooseFBConfig(Display* display,
550 int screen,
551 const int *attrib_list,
552 int *nelements)
553 {
554 BEFORE_GLX_CALL;
555 GLXFBConfig* result = xChooseFBConfigInternal(display, screen, attrib_list, nelements);
556 AFTER_GLX_CALL;
557 return result;
558 }
559
560 GLXFBConfig*
561 GLXLibrary::xGetFBConfigs(Display* display,
562 int screen,
563 int *nelements)
564 {
565 BEFORE_GLX_CALL;
566 GLXFBConfig* result = xGetFBConfigsInternal(display, screen, nelements);
567 AFTER_GLX_CALL;
568 return result;
569 }
570
571 GLXContext
572 GLXLibrary::xCreateNewContext(Display* display,
573 GLXFBConfig config,
574 int render_type,
575 GLXContext share_list,
576 Bool direct)
577 {
578 BEFORE_GLX_CALL;
579 GLXContext result = xCreateNewContextInternal(display, config,
580 render_type,
581 share_list, direct);
582 AFTER_GLX_CALL;
583 return result;
584 }
585
586 int
587 GLXLibrary::xGetFBConfigAttrib(Display *display,
588 GLXFBConfig config,
589 int attribute,
590 int *value)
591 {
592 BEFORE_GLX_CALL;
593 int result = xGetFBConfigAttribInternal(display, config,
594 attribute, value);
595 AFTER_GLX_CALL;
596 return result;
597 }
598
599 void
600 GLXLibrary::xSwapBuffers(Display *display, GLXDrawable drawable)
601 {
602 BEFORE_GLX_CALL;
603 xSwapBuffersInternal(display, drawable);
604 AFTER_GLX_CALL;
605 }
606
607 const char *
608 GLXLibrary::xQueryExtensionsString(Display *display,
609 int screen)
610 {
611 BEFORE_GLX_CALL;
612 const char *result = xQueryExtensionsStringInternal(display, screen);
613 AFTER_GLX_CALL;
614 return result;
615 }
616
617 const char *
618 GLXLibrary::xGetClientString(Display *display,
619 int screen)
620 {
621 BEFORE_GLX_CALL;
622 const char *result = xGetClientStringInternal(display, screen);
623 AFTER_GLX_CALL;
624 return result;
625 }
626
627 const char *
628 GLXLibrary::xQueryServerString(Display *display,
629 int screen, int name)
630 {
631 BEFORE_GLX_CALL;
632 const char *result = xQueryServerStringInternal(display, screen, name);
633 AFTER_GLX_CALL;
634 return result;
635 }
636
637 GLXPixmap
638 GLXLibrary::xCreatePixmap(Display *display,
639 GLXFBConfig config,
640 Pixmap pixmap,
641 const int *attrib_list)
642 {
643 BEFORE_GLX_CALL;
644 GLXPixmap result = xCreatePixmapInternal(display, config,
645 pixmap, attrib_list);
646 AFTER_GLX_CALL;
647 return result;
648 }
649
650 GLXPixmap
651 GLXLibrary::xCreateGLXPixmapWithConfig(Display *display,
652 GLXFBConfig config,
653 Pixmap pixmap)
654 {
655 BEFORE_GLX_CALL;
656 GLXPixmap result = xCreateGLXPixmapWithConfigInternal(display, config, pixmap);
657 AFTER_GLX_CALL;
658 return result;
659 }
660
661 void
662 GLXLibrary::xDestroyPixmap(Display *display, GLXPixmap pixmap)
663 {
664 BEFORE_GLX_CALL;
665 xDestroyPixmapInternal(display, pixmap);
666 AFTER_GLX_CALL;
667 }
668
669 Bool
670 GLXLibrary::xQueryVersion(Display *display,
671 int *major,
672 int *minor)
673 {
674 BEFORE_GLX_CALL;
675 Bool result = xQueryVersionInternal(display, major, minor);
676 AFTER_GLX_CALL;
677 return result;
678 }
679
680 void
681 GLXLibrary::xBindTexImage(Display *display,
682 GLXDrawable drawable,
683 int buffer,
684 const int *attrib_list)
685 {
686 BEFORE_GLX_CALL;
687 xBindTexImageInternal(display, drawable, buffer, attrib_list);
688 AFTER_GLX_CALL;
689 }
690
691 void
692 GLXLibrary::xReleaseTexImage(Display *display,
693 GLXDrawable drawable,
694 int buffer)
695 {
696 BEFORE_GLX_CALL;
697 xReleaseTexImageInternal(display, drawable, buffer);
698 AFTER_GLX_CALL;
699 }
700
701 void
702 GLXLibrary::xWaitGL()
703 {
704 BEFORE_GLX_CALL;
705 xWaitGLInternal();
706 AFTER_GLX_CALL;
707 }
708
709 void
710 GLXLibrary::xWaitX()
711 {
712 BEFORE_GLX_CALL;
713 xWaitXInternal();
714 AFTER_GLX_CALL;
715 }
716
717 GLXContext
718 GLXLibrary::xCreateContextAttribs(Display* display,
719 GLXFBConfig config,
720 GLXContext share_list,
721 Bool direct,
722 const int* attrib_list)
723 {
724 BEFORE_GLX_CALL;
725 GLXContext result = xCreateContextAttribsInternal(display,
726 config,
727 share_list,
728 direct,
729 attrib_list);
730 AFTER_GLX_CALL;
731 return result;
732 }
733
734 already_AddRefed<GLContextGLX>
735 GLContextGLX::CreateGLContext(
736 const SurfaceCaps& caps,
737 GLContextGLX* shareContext,
738 bool isOffscreen,
739 Display* display,
740 GLXDrawable drawable,
741 GLXFBConfig cfg,
742 bool deleteDrawable,
743 gfxXlibSurface* pixmap)
744 {
745 GLXLibrary& glx = sGLXLibrary;
746
747 int db = 0;
748 int err = glx.xGetFBConfigAttrib(display, cfg,
749 LOCAL_GLX_DOUBLEBUFFER, &db);
750 if (LOCAL_GLX_BAD_ATTRIBUTE != err) {
751 #ifdef DEBUG
752 if (DebugMode()) {
753 printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
754 }
755 #endif
756 }
757
758 GLXContext context;
759 nsRefPtr<GLContextGLX> glContext;
760 bool error;
761
762 ScopedXErrorHandler xErrorHandler;
763
764 TRY_AGAIN_NO_SHARING:
765
766 error = false;
767
768 GLXContext glxContext = shareContext ? shareContext->mContext : nullptr;
769 if (glx.HasRobustness()) {
770 int attrib_list[] = {
771 LOCAL_GL_CONTEXT_FLAGS_ARB, LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
772 LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB,
773 0,
774 };
775
776 context = glx.xCreateContextAttribs(
777 display,
778 cfg,
779 glxContext,
780 True,
781 attrib_list);
782 } else {
783 context = glx.xCreateNewContext(
784 display,
785 cfg,
786 LOCAL_GLX_RGBA_TYPE,
787 glxContext,
788 True);
789 }
790
791 if (context) {
792 glContext = new GLContextGLX(caps,
793 shareContext,
794 isOffscreen,
795 display,
796 drawable,
797 context,
798 deleteDrawable,
799 db,
800 pixmap);
801 if (!glContext->Init())
802 error = true;
803 } else {
804 error = true;
805 }
806
807 error |= xErrorHandler.SyncAndGetError(display);
808
809 if (error) {
810 if (shareContext) {
811 shareContext = nullptr;
812 goto TRY_AGAIN_NO_SHARING;
813 }
814
815 NS_WARNING("Failed to create GLXContext!");
816 glContext = nullptr; // note: this must be done while the graceful X error handler is set,
817 // because glxMakeCurrent can give a GLXBadDrawable error
818 }
819
820 return glContext.forget();
821 }
822
823 GLContextGLX::~GLContextGLX()
824 {
825 MarkDestroyed();
826
827 // Wrapped context should not destroy glxContext/Surface
828 if (!mOwnsContext) {
829 return;
830 }
831
832 // see bug 659842 comment 76
833 #ifdef DEBUG
834 bool success =
835 #endif
836 mGLX->xMakeCurrent(mDisplay, None, nullptr);
837 NS_ABORT_IF_FALSE(success,
838 "glXMakeCurrent failed to release GL context before we call glXDestroyContext!");
839
840 mGLX->xDestroyContext(mDisplay, mContext);
841
842 if (mDeleteDrawable) {
843 mGLX->xDestroyPixmap(mDisplay, mDrawable);
844 }
845 }
846
847 bool
848 GLContextGLX::Init()
849 {
850 SetupLookupFunction();
851 if (!InitWithPrefix("gl", true)) {
852 return false;
853 }
854
855 if (!IsExtensionSupported(EXT_framebuffer_object))
856 return false;
857
858 return true;
859 }
860
861 bool
862 GLContextGLX::MakeCurrentImpl(bool aForce)
863 {
864 bool succeeded = true;
865
866 // With the ATI FGLRX driver, glxMakeCurrent is very slow even when the context doesn't change.
867 // (This is not the case with other drivers such as NVIDIA).
868 // So avoid calling it more than necessary. Since GLX documentation says that:
869 // "glXGetCurrentContext returns client-side information.
870 // It does not make a round trip to the server."
871 // I assume that it's not worth using our own TLS slot here.
872 if (aForce || mGLX->xGetCurrentContext() != mContext) {
873 succeeded = mGLX->xMakeCurrent(mDisplay, mDrawable, mContext);
874 NS_ASSERTION(succeeded, "Failed to make GL context current!");
875 }
876
877 return succeeded;
878 }
879
880 bool
881 GLContextGLX::IsCurrent() {
882 return mGLX->xGetCurrentContext() == mContext;
883 }
884
885 bool
886 GLContextGLX::SetupLookupFunction()
887 {
888 mLookupFunc = (PlatformLookupFunction)&GLXLibrary::xGetProcAddress;
889 return true;
890 }
891
892 bool
893 GLContextGLX::IsDoubleBuffered() const
894 {
895 return mDoubleBuffered;
896 }
897
898 bool
899 GLContextGLX::SupportsRobustness() const
900 {
901 return mGLX->HasRobustness();
902 }
903
904 bool
905 GLContextGLX::SwapBuffers()
906 {
907 if (!mDoubleBuffered)
908 return false;
909 mGLX->xSwapBuffers(mDisplay, mDrawable);
910 mGLX->xWaitGL();
911 return true;
912 }
913
914 GLContextGLX::GLContextGLX(
915 const SurfaceCaps& caps,
916 GLContext* shareContext,
917 bool isOffscreen,
918 Display *aDisplay,
919 GLXDrawable aDrawable,
920 GLXContext aContext,
921 bool aDeleteDrawable,
922 bool aDoubleBuffered,
923 gfxXlibSurface *aPixmap)
924 : GLContext(caps, shareContext, isOffscreen),//aDeleteDrawable ? true : false, aShareContext, ),
925 mContext(aContext),
926 mDisplay(aDisplay),
927 mDrawable(aDrawable),
928 mDeleteDrawable(aDeleteDrawable),
929 mDoubleBuffered(aDoubleBuffered),
930 mGLX(&sGLXLibrary),
931 mPixmap(aPixmap),
932 mOwnsContext(true)
933 {
934 MOZ_ASSERT(mGLX);
935 // See 899855
936 SetProfileVersion(ContextProfile::OpenGLCompatibility, 200);
937 }
938
939
940 static GLContextGLX *
941 GetGlobalContextGLX()
942 {
943 return static_cast<GLContextGLX*>(GLContextProviderGLX::GetGlobalContext());
944 }
945
946 static bool
947 AreCompatibleVisuals(Visual *one, Visual *two)
948 {
949 if (one->c_class != two->c_class) {
950 return false;
951 }
952
953 if (one->red_mask != two->red_mask ||
954 one->green_mask != two->green_mask ||
955 one->blue_mask != two->blue_mask) {
956 return false;
957 }
958
959 if (one->bits_per_rgb != two->bits_per_rgb) {
960 return false;
961 }
962
963 return true;
964 }
965
966 static StaticRefPtr<GLContext> gGlobalContext;
967
968 already_AddRefed<GLContext>
969 GLContextProviderGLX::CreateWrappingExisting(void* aContext, void* aSurface)
970 {
971 if (!sGLXLibrary.EnsureInitialized()) {
972 return nullptr;
973 }
974
975 if (aContext && aSurface) {
976 SurfaceCaps caps = SurfaceCaps::Any();
977 nsRefPtr<GLContextGLX> glContext =
978 new GLContextGLX(caps,
979 nullptr, // SharedContext
980 false, // Offscreen
981 (Display*)DefaultXDisplay(), // Display
982 (GLXDrawable)aSurface, (GLXContext)aContext,
983 false, // aDeleteDrawable,
984 true,
985 (gfxXlibSurface*)nullptr);
986
987 glContext->mOwnsContext = false;
988 gGlobalContext = glContext;
989
990 return glContext.forget();
991 }
992
993 return nullptr;
994 }
995
996 already_AddRefed<GLContext>
997 GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
998 {
999 if (!sGLXLibrary.EnsureInitialized()) {
1000 return nullptr;
1001 }
1002
1003 // Currently, we take whatever Visual the window already has, and
1004 // try to create an fbconfig for that visual. This isn't
1005 // necessarily what we want in the long run; an fbconfig may not
1006 // be available for the existing visual, or if it is, the GL
1007 // performance might be suboptimal. But using the existing visual
1008 // is a relatively safe intermediate step.
1009
1010 Display *display = (Display*)aWidget->GetNativeData(NS_NATIVE_DISPLAY);
1011 if (!display) {
1012 NS_ERROR("X Display required for GLX Context provider");
1013 return nullptr;
1014 }
1015
1016 int xscreen = DefaultScreen(display);
1017 Window window = GET_NATIVE_WINDOW(aWidget);
1018
1019 int numConfigs;
1020 ScopedXFree<GLXFBConfig> cfgs;
1021 if (sGLXLibrary.IsATI() ||
1022 !sGLXLibrary.GLXVersionCheck(1, 3)) {
1023 const int attribs[] = {
1024 LOCAL_GLX_DOUBLEBUFFER, False,
1025 0
1026 };
1027 cfgs = sGLXLibrary.xChooseFBConfig(display,
1028 xscreen,
1029 attribs,
1030 &numConfigs);
1031 } else {
1032 cfgs = sGLXLibrary.xGetFBConfigs(display,
1033 xscreen,
1034 &numConfigs);
1035 }
1036
1037 if (!cfgs) {
1038 NS_WARNING("[GLX] glXGetFBConfigs() failed");
1039 return nullptr;
1040 }
1041 NS_ASSERTION(numConfigs > 0, "No FBConfigs found!");
1042
1043 // XXX the visual ID is almost certainly the LOCAL_GLX_FBCONFIG_ID, so
1044 // we could probably do this first and replace the glXGetFBConfigs
1045 // with glXChooseConfigs. Docs are sparklingly clear as always.
1046 XWindowAttributes widgetAttrs;
1047 if (!XGetWindowAttributes(display, window, &widgetAttrs)) {
1048 NS_WARNING("[GLX] XGetWindowAttributes() failed");
1049 return nullptr;
1050 }
1051 const VisualID widgetVisualID = XVisualIDFromVisual(widgetAttrs.visual);
1052 #ifdef DEBUG
1053 printf("[GLX] widget has VisualID 0x%lx\n", widgetVisualID);
1054 #endif
1055
1056 int matchIndex = -1;
1057
1058 for (int i = 0; i < numConfigs; i++) {
1059 int visid = None;
1060 sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid);
1061 if (!visid) {
1062 continue;
1063 }
1064 if (sGLXLibrary.IsATI()) {
1065 int depth;
1066 Visual *visual;
1067 FindVisualAndDepth(display, visid, &visual, &depth);
1068 if (depth == widgetAttrs.depth &&
1069 AreCompatibleVisuals(widgetAttrs.visual, visual)) {
1070 matchIndex = i;
1071 break;
1072 }
1073 } else {
1074 if (widgetVisualID == static_cast<VisualID>(visid)) {
1075 matchIndex = i;
1076 break;
1077 }
1078 }
1079 }
1080
1081 if (matchIndex == -1) {
1082 NS_WARNING("[GLX] Couldn't find a FBConfig matching widget visual");
1083 return nullptr;
1084 }
1085
1086 GLContextGLX *shareContext = GetGlobalContextGLX();
1087
1088 SurfaceCaps caps = SurfaceCaps::Any();
1089 nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(caps,
1090 shareContext,
1091 false,
1092 display,
1093 window,
1094 cfgs[matchIndex],
1095 false);
1096
1097 return glContext.forget();
1098 }
1099
1100 static already_AddRefed<GLContextGLX>
1101 CreateOffscreenPixmapContext(const gfxIntSize& size)
1102 {
1103 GLXLibrary& glx = sGLXLibrary;
1104 if (!glx.EnsureInitialized()) {
1105 return nullptr;
1106 }
1107
1108 Display *display = DefaultXDisplay();
1109 int xscreen = DefaultScreen(display);
1110
1111 int attribs[] = {
1112 LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT,
1113 LOCAL_GLX_X_RENDERABLE, True,
1114 0
1115 };
1116 int numConfigs = 0;
1117
1118 ScopedXFree<GLXFBConfig> cfgs;
1119 cfgs = glx.xChooseFBConfig(display,
1120 xscreen,
1121 attribs,
1122 &numConfigs);
1123 if (!cfgs) {
1124 return nullptr;
1125 }
1126
1127 MOZ_ASSERT(numConfigs > 0,
1128 "glXChooseFBConfig() failed to match our requested format and violated its spec!");
1129
1130 int visid = None;
1131 int chosenIndex = 0;
1132
1133 for (int i = 0; i < numConfigs; ++i) {
1134 int dtype;
1135
1136 if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_DRAWABLE_TYPE, &dtype) != Success
1137 || !(dtype & LOCAL_GLX_PIXMAP_BIT))
1138 {
1139 continue;
1140 }
1141 if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid) != Success
1142 || visid == 0)
1143 {
1144 continue;
1145 }
1146
1147 chosenIndex = i;
1148 break;
1149 }
1150
1151 if (!visid) {
1152 NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!");
1153 return nullptr;
1154 }
1155
1156 Visual *visual;
1157 int depth;
1158 FindVisualAndDepth(display, visid, &visual, &depth);
1159 ScopedXErrorHandler xErrorHandler;
1160 GLXPixmap glxpixmap = 0;
1161 bool error = false;
1162
1163 gfxIntSize dummySize(16, 16);
1164 nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
1165 visual,
1166 dummySize);
1167 if (xsurface->CairoStatus() != 0) {
1168 error = true;
1169 goto DONE_CREATING_PIXMAP;
1170 }
1171
1172 // Handle slightly different signature between glXCreatePixmap and
1173 // its pre-GLX-1.3 extension equivalent (though given the ABI, we
1174 // might not need to).
1175 if (glx.GLXVersionCheck(1, 3)) {
1176 glxpixmap = glx.xCreatePixmap(display,
1177 cfgs[chosenIndex],
1178 xsurface->XDrawable(),
1179 nullptr);
1180 } else {
1181 glxpixmap = glx.xCreateGLXPixmapWithConfig(display,
1182 cfgs[chosenIndex],
1183 xsurface->
1184 XDrawable());
1185 }
1186 if (glxpixmap == 0) {
1187 error = true;
1188 }
1189
1190 DONE_CREATING_PIXMAP:
1191
1192 nsRefPtr<GLContextGLX> glContext;
1193 bool serverError = xErrorHandler.SyncAndGetError(display);
1194
1195 if (!error && // earlier recorded error
1196 !serverError)
1197 {
1198 // We might have an alpha channel, but it doesn't matter.
1199 SurfaceCaps dummyCaps = SurfaceCaps::Any();
1200 GLContextGLX* shareContext = GetGlobalContextGLX();
1201
1202 glContext = GLContextGLX::CreateGLContext(dummyCaps,
1203 shareContext,
1204 true,
1205 display,
1206 glxpixmap,
1207 cfgs[chosenIndex],
1208 true,
1209 xsurface);
1210 }
1211
1212 return glContext.forget();
1213 }
1214
1215 already_AddRefed<GLContext>
1216 GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
1217 const SurfaceCaps& caps)
1218 {
1219 gfxIntSize dummySize = gfxIntSize(16, 16);
1220 nsRefPtr<GLContextGLX> glContext =
1221 CreateOffscreenPixmapContext(dummySize);
1222
1223 if (!glContext)
1224 return nullptr;
1225
1226 if (!glContext->InitOffscreen(ToIntSize(size), caps))
1227 return nullptr;
1228
1229 return glContext.forget();
1230 }
1231
1232 GLContext*
1233 GLContextProviderGLX::GetGlobalContext()
1234 {
1235 static bool checkedContextSharing = false;
1236 static bool useContextSharing = false;
1237
1238 if (!checkedContextSharing) {
1239 useContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0;
1240 checkedContextSharing = true;
1241 }
1242
1243 // TODO: get GLX context sharing to work well with multiple threads
1244 if (!useContextSharing) {
1245 return nullptr;
1246 }
1247
1248 static bool triedToCreateContext = false;
1249 if (!triedToCreateContext && !gGlobalContext) {
1250 triedToCreateContext = true;
1251
1252 gfxIntSize dummySize = gfxIntSize(16, 16);
1253 // StaticPtr doesn't support assignments from already_AddRefed,
1254 // so use a temporary nsRefPtr to make the reference counting
1255 // fall out correctly.
1256 nsRefPtr<GLContext> holder = CreateOffscreenPixmapContext(dummySize);
1257 gGlobalContext = holder;
1258 }
1259
1260 return gGlobalContext;
1261 }
1262
1263 void
1264 GLContextProviderGLX::Shutdown()
1265 {
1266 gGlobalContext = nullptr;
1267 }
1268
1269 } /* namespace gl */
1270 } /* namespace mozilla */
1271

mercurial