|
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 |