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
4 : *
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/
9 : *
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.
14 : *
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.
18 : *
19 : * Contributor(s):
20 : * Matt Woodrow <mwoodrow@mozilla.com>
21 : * Bas Schouten <bschouten@mozilla.com>
22 : *
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.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
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
46 :
47 : #include <X11/Xlib.h>
48 : #include <X11/Xutil.h>
49 :
50 : #include "mozilla/X11Util.h"
51 :
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"
62 : #include "gfxUtils.h"
63 :
64 : #include "gfxCrashReporterUtils.h"
65 :
66 : namespace mozilla {
67 : namespace gl {
68 :
69 : static bool gIsATI = false;
70 : static bool gIsChromium = false;
71 : static int gGLXMajorVersion = 0, gGLXMinorVersion = 0;
72 :
73 : // Check that we have at least version aMajor.aMinor .
74 : static inline bool
75 0 : GLXVersionCheck(int aMajor, int aMinor)
76 : {
77 : return aMajor < gGLXMajorVersion ||
78 0 : (aMajor == gGLXMajorVersion && aMinor <= gGLXMinorVersion);
79 : }
80 :
81 : static inline bool
82 0 : HasExtension(const char* aExtensions, const char* aRequiredExtension)
83 : {
84 : return GLContext::ListHasExtension(
85 0 : reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension);
86 : }
87 :
88 : bool
89 0 : GLXLibrary::EnsureInitialized()
90 : {
91 0 : if (mInitialized) {
92 0 : return true;
93 : }
94 :
95 : // Don't repeatedly try to initialize.
96 0 : if (mTriedInitializing) {
97 0 : return false;
98 : }
99 0 : mTriedInitializing = true;
100 :
101 0 : if (!mOGLLibrary) {
102 : // see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1
103 : // because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls,
104 : // which trigger glibc bug http://sourceware.org/bugzilla/show_bug.cgi?id=12225
105 : #ifdef __OpenBSD__
106 : const char *libGLfilename = "libGL.so";
107 : #else
108 0 : const char *libGLfilename = "libGL.so.1";
109 : #endif
110 0 : ScopedGfxFeatureReporter reporter(libGLfilename);
111 0 : mOGLLibrary = PR_LoadLibrary(libGLfilename);
112 0 : if (!mOGLLibrary) {
113 0 : NS_WARNING("Couldn't load OpenGL shared library.");
114 0 : return false;
115 : }
116 0 : reporter.SetSuccessful();
117 : }
118 :
119 0 : if (PR_GetEnv("MOZ_GLX_DEBUG")) {
120 0 : mDebug = true;
121 : }
122 :
123 : LibrarySymbolLoader::SymLoadStruct symbols[] = {
124 : /* functions that were in GLX 1.0 */
125 : { (PRFuncPtr*) &xDestroyContextInternal, { "glXDestroyContext", NULL } },
126 : { (PRFuncPtr*) &xMakeCurrentInternal, { "glXMakeCurrent", NULL } },
127 : { (PRFuncPtr*) &xSwapBuffersInternal, { "glXSwapBuffers", NULL } },
128 : { (PRFuncPtr*) &xQueryVersionInternal, { "glXQueryVersion", NULL } },
129 : { (PRFuncPtr*) &xGetCurrentContextInternal, { "glXGetCurrentContext", NULL } },
130 : { (PRFuncPtr*) &xWaitGLInternal, { "glXWaitGL", NULL } },
131 : { (PRFuncPtr*) &xWaitXInternal, { "glXWaitX", NULL } },
132 : /* functions introduced in GLX 1.1 */
133 : { (PRFuncPtr*) &xQueryExtensionsStringInternal, { "glXQueryExtensionsString", NULL } },
134 : { (PRFuncPtr*) &xGetClientStringInternal, { "glXGetClientString", NULL } },
135 : { (PRFuncPtr*) &xQueryServerStringInternal, { "glXQueryServerString", NULL } },
136 : { NULL, { NULL } }
137 0 : };
138 :
139 : LibrarySymbolLoader::SymLoadStruct symbols13[] = {
140 : /* functions introduced in GLX 1.3 */
141 : { (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfig", NULL } },
142 : { (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttrib", NULL } },
143 : // WARNING: xGetFBConfigs not set in symbols13_ext
144 : { (PRFuncPtr*) &xGetFBConfigsInternal, { "glXGetFBConfigs", NULL } },
145 : { (PRFuncPtr*) &xGetVisualFromFBConfigInternal, { "glXGetVisualFromFBConfig", NULL } },
146 : // WARNING: symbols13_ext sets xCreateGLXPixmapWithConfig instead
147 : { (PRFuncPtr*) &xCreatePixmapInternal, { "glXCreatePixmap", NULL } },
148 : { (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyPixmap", NULL } },
149 : { (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateNewContext", NULL } },
150 : { NULL, { NULL } }
151 0 : };
152 :
153 : LibrarySymbolLoader::SymLoadStruct symbols13_ext[] = {
154 : /* extension equivalents for functions introduced in GLX 1.3 */
155 : // GLX_SGIX_fbconfig extension
156 : { (PRFuncPtr*) &xChooseFBConfigInternal, { "glXChooseFBConfigSGIX", NULL } },
157 : { (PRFuncPtr*) &xGetFBConfigAttribInternal, { "glXGetFBConfigAttribSGIX", NULL } },
158 : // WARNING: no xGetFBConfigs equivalent in extensions
159 : { (PRFuncPtr*) &xGetVisualFromFBConfigInternal, { "glXGetVisualFromFBConfig", NULL } },
160 : // WARNING: different from symbols13:
161 : { (PRFuncPtr*) &xCreateGLXPixmapWithConfigInternal, { "glXCreateGLXPixmapWithConfigSGIX", NULL } },
162 : { (PRFuncPtr*) &xDestroyPixmapInternal, { "glXDestroyGLXPixmap", NULL } }, // not from ext
163 : { (PRFuncPtr*) &xCreateNewContextInternal, { "glXCreateContextWithConfigSGIX", NULL } },
164 : { NULL, { NULL } }
165 0 : };
166 :
167 : LibrarySymbolLoader::SymLoadStruct symbols14[] = {
168 : /* functions introduced in GLX 1.4 */
169 : { (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddress", NULL } },
170 : { NULL, { NULL } }
171 0 : };
172 :
173 : LibrarySymbolLoader::SymLoadStruct symbols14_ext[] = {
174 : /* extension equivalents for functions introduced in GLX 1.4 */
175 : // GLX_ARB_get_proc_address extension
176 : { (PRFuncPtr*) &xGetProcAddressInternal, { "glXGetProcAddressARB", NULL } },
177 : { NULL, { NULL } }
178 0 : };
179 :
180 : LibrarySymbolLoader::SymLoadStruct symbols_texturefrompixmap[] = {
181 : { (PRFuncPtr*) &xBindTexImageInternal, { "glXBindTexImageEXT", NULL } },
182 : { (PRFuncPtr*) &xReleaseTexImageInternal, { "glXReleaseTexImageEXT", NULL } },
183 : { NULL, { NULL } }
184 0 : };
185 :
186 : LibrarySymbolLoader::SymLoadStruct symbols_robustness[] = {
187 : { (PRFuncPtr*) &xCreateContextAttribsInternal, { "glXCreateContextAttribsARB", NULL } },
188 : { NULL, { NULL } }
189 0 : };
190 :
191 0 : if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &symbols[0])) {
192 0 : NS_WARNING("Couldn't find required entry point in OpenGL shared library");
193 0 : return false;
194 : }
195 :
196 0 : Display *display = DefaultXDisplay();
197 :
198 0 : int screen = DefaultScreen(display);
199 0 : const char *serverVendor = NULL;
200 0 : const char *serverVersionStr = NULL;
201 0 : const char *extensionsStr = NULL;
202 :
203 0 : if (!xQueryVersion(display, &gGLXMajorVersion, &gGLXMinorVersion)) {
204 0 : gGLXMajorVersion = 0;
205 0 : gGLXMinorVersion = 0;
206 0 : return false;
207 : }
208 :
209 0 : serverVendor = xQueryServerString(display, screen, GLX_VENDOR);
210 0 : serverVersionStr = xQueryServerString(display, screen, GLX_VERSION);
211 :
212 0 : if (!GLXVersionCheck(1, 1))
213 : // Not possible to query for extensions.
214 0 : return false;
215 :
216 0 : extensionsStr = xQueryExtensionsString(display, screen);
217 :
218 : LibrarySymbolLoader::SymLoadStruct *sym13;
219 0 : if (!GLXVersionCheck(1, 3)) {
220 : // Even if we don't have 1.3, we might have equivalent extensions
221 : // (as on the Intel X server).
222 0 : if (!HasExtension(extensionsStr, "GLX_SGIX_fbconfig")) {
223 0 : return false;
224 : }
225 0 : sym13 = symbols13_ext;
226 : } else {
227 0 : sym13 = symbols13;
228 : }
229 0 : if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, sym13)) {
230 0 : NS_WARNING("Couldn't find required entry point in OpenGL shared library");
231 0 : return false;
232 : }
233 :
234 : LibrarySymbolLoader::SymLoadStruct *sym14;
235 0 : if (!GLXVersionCheck(1, 4)) {
236 : // Even if we don't have 1.4, we might have equivalent extensions
237 : // (as on the Intel X server).
238 0 : if (!HasExtension(extensionsStr, "GLX_ARB_get_proc_address")) {
239 0 : return false;
240 : }
241 0 : sym14 = symbols14_ext;
242 : } else {
243 0 : sym14 = symbols14;
244 : }
245 0 : if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, sym14)) {
246 0 : NS_WARNING("Couldn't find required entry point in OpenGL shared library");
247 0 : return false;
248 : }
249 :
250 0 : if (HasExtension(extensionsStr, "GLX_EXT_texture_from_pixmap") &&
251 : LibrarySymbolLoader::LoadSymbols(mOGLLibrary, symbols_texturefrompixmap,
252 0 : (LibrarySymbolLoader::PlatformLookupFunction)&xGetProcAddress))
253 : {
254 0 : mHasTextureFromPixmap = true;
255 : } else {
256 0 : NS_WARNING("Texture from pixmap disabled");
257 : }
258 :
259 0 : if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness") &&
260 0 : LibrarySymbolLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) {
261 0 : mHasRobustness = true;
262 : }
263 :
264 0 : gIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI");
265 : gIsChromium = (serverVendor &&
266 0 : DoesStringMatch(serverVendor, "Chromium")) ||
267 : (serverVersionStr &&
268 0 : DoesStringMatch(serverVersionStr, "Chromium"));
269 :
270 0 : mInitialized = true;
271 0 : return true;
272 : }
273 :
274 : bool
275 0 : GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface)
276 : {
277 0 : if (!EnsureInitialized()) {
278 0 : return false;
279 : }
280 :
281 0 : if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib || !mHasTextureFromPixmap) {
282 0 : return false;
283 : }
284 :
285 0 : return true;
286 : }
287 :
288 : GLXPixmap
289 0 : GLXLibrary::CreatePixmap(gfxASurface* aSurface)
290 : {
291 0 : if (!SupportsTextureFromPixmap(aSurface)) {
292 0 : return 0;
293 : }
294 :
295 : int attribs[] = { GLX_DOUBLEBUFFER, False,
296 : GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
297 : GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
298 0 : None };
299 :
300 : int numFormats;
301 0 : Display *display = DefaultXDisplay();
302 0 : int xscreen = DefaultScreen(display);
303 :
304 : ScopedXFree<GLXFBConfig> cfg(xChooseFBConfig(display,
305 : xscreen,
306 : attribs,
307 0 : &numFormats));
308 0 : if (!cfg) {
309 0 : return 0;
310 : }
311 0 : NS_ABORT_IF_FALSE(numFormats > 0,
312 : "glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
313 :
314 0 : gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
315 :
316 : int pixmapAttribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
317 : GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
318 0 : None};
319 :
320 : GLXPixmap glxpixmap = xCreatePixmap(display,
321 0 : cfg[0],
322 : xs->XDrawable(),
323 0 : pixmapAttribs);
324 :
325 0 : return glxpixmap;
326 : }
327 :
328 : void
329 0 : GLXLibrary::DestroyPixmap(GLXPixmap aPixmap)
330 : {
331 0 : if (!mHasTextureFromPixmap) {
332 0 : return;
333 : }
334 :
335 0 : Display *display = DefaultXDisplay();
336 0 : xDestroyPixmap(display, aPixmap);
337 : }
338 :
339 : void
340 0 : GLXLibrary::BindTexImage(GLXPixmap aPixmap)
341 : {
342 0 : if (!mHasTextureFromPixmap) {
343 0 : return;
344 : }
345 :
346 0 : Display *display = DefaultXDisplay();
347 : // Make sure all X drawing to the surface has finished before binding to a texture.
348 0 : xWaitX();
349 0 : xBindTexImage(display, aPixmap, GLX_FRONT_LEFT_EXT, NULL);
350 : }
351 :
352 : void
353 0 : GLXLibrary::ReleaseTexImage(GLXPixmap aPixmap)
354 : {
355 0 : if (!mHasTextureFromPixmap) {
356 0 : return;
357 : }
358 :
359 0 : Display *display = DefaultXDisplay();
360 0 : xReleaseTexImage(display, aPixmap, GLX_FRONT_LEFT_EXT);
361 : }
362 :
363 : #ifdef DEBUG
364 :
365 : static int (*sOldErrorHandler)(Display *, XErrorEvent *);
366 1464 : ScopedXErrorHandler::ErrorEvent sErrorEvent;
367 0 : static int GLXErrorHandler(Display *display, XErrorEvent *ev)
368 : {
369 0 : if (!sErrorEvent.mError.error_code) {
370 0 : sErrorEvent.mError = *ev;
371 : }
372 0 : return 0;
373 : }
374 :
375 : void
376 0 : GLXLibrary::BeforeGLXCall()
377 : {
378 0 : if (mDebug) {
379 0 : sOldErrorHandler = XSetErrorHandler(GLXErrorHandler);
380 : }
381 0 : }
382 :
383 : void
384 0 : GLXLibrary::AfterGLXCall()
385 : {
386 0 : if (mDebug) {
387 0 : XSync(DefaultXDisplay(), False);
388 0 : if (sErrorEvent.mError.error_code) {
389 : char buffer[2048];
390 0 : XGetErrorText(DefaultXDisplay(), sErrorEvent.mError.error_code, buffer, sizeof(buffer));
391 : printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %i",
392 : buffer,
393 : sErrorEvent.mError.error_code,
394 : sErrorEvent.mError.request_code,
395 : sErrorEvent.mError.minor_code,
396 0 : sErrorEvent.mError.serial);
397 0 : NS_ABORT();
398 : }
399 0 : XSetErrorHandler(sOldErrorHandler);
400 : }
401 0 : }
402 :
403 : #define BEFORE_GLX_CALL do { \
404 : sGLXLibrary.BeforeGLXCall(); \
405 : } while (0)
406 :
407 : #define AFTER_GLX_CALL do { \
408 : sGLXLibrary.AfterGLXCall(); \
409 : } while (0)
410 :
411 : #else
412 :
413 : #define BEFORE_GLX_CALL do { } while(0)
414 : #define AFTER_GLX_CALL do { } while(0)
415 :
416 : #endif
417 :
418 : void
419 0 : GLXLibrary::xDestroyContext(Display* display, GLXContext context)
420 : {
421 0 : BEFORE_GLX_CALL;
422 0 : xDestroyContextInternal(display, context);
423 0 : AFTER_GLX_CALL;
424 0 : }
425 :
426 : Bool
427 0 : GLXLibrary::xMakeCurrent(Display* display,
428 : GLXDrawable drawable,
429 : GLXContext context)
430 : {
431 0 : BEFORE_GLX_CALL;
432 0 : Bool result = xMakeCurrentInternal(display, drawable, context);
433 0 : AFTER_GLX_CALL;
434 0 : return result;
435 : }
436 :
437 : GLXContext
438 0 : GLXLibrary::xGetCurrentContext()
439 : {
440 0 : BEFORE_GLX_CALL;
441 0 : GLXContext result = xGetCurrentContextInternal();
442 0 : AFTER_GLX_CALL;
443 0 : return result;
444 : }
445 :
446 : /* static */ void*
447 0 : GLXLibrary::xGetProcAddress(const char *procName)
448 : {
449 0 : BEFORE_GLX_CALL;
450 0 : void* result = sGLXLibrary.xGetProcAddressInternal(procName);
451 0 : AFTER_GLX_CALL;
452 0 : return result;
453 : }
454 :
455 : GLXFBConfig*
456 0 : GLXLibrary::xChooseFBConfig(Display* display,
457 : int screen,
458 : const int *attrib_list,
459 : int *nelements)
460 : {
461 0 : BEFORE_GLX_CALL;
462 0 : GLXFBConfig* result = xChooseFBConfigInternal(display, screen, attrib_list, nelements);
463 0 : AFTER_GLX_CALL;
464 0 : return result;
465 : }
466 :
467 : GLXFBConfig*
468 0 : GLXLibrary::xGetFBConfigs(Display* display,
469 : int screen,
470 : int *nelements)
471 : {
472 0 : BEFORE_GLX_CALL;
473 0 : GLXFBConfig* result = xGetFBConfigsInternal(display, screen, nelements);
474 0 : AFTER_GLX_CALL;
475 0 : return result;
476 : }
477 :
478 : GLXContext
479 0 : GLXLibrary::xCreateNewContext(Display* display,
480 : GLXFBConfig config,
481 : int render_type,
482 : GLXContext share_list,
483 : Bool direct)
484 : {
485 0 : BEFORE_GLX_CALL;
486 : GLXContext result = xCreateNewContextInternal(display, config,
487 : render_type,
488 0 : share_list, direct);
489 0 : AFTER_GLX_CALL;
490 0 : return result;
491 : }
492 :
493 : XVisualInfo*
494 0 : GLXLibrary::xGetVisualFromFBConfig(Display* display,
495 : GLXFBConfig config)
496 : {
497 0 : BEFORE_GLX_CALL;
498 0 : XVisualInfo* result = xGetVisualFromFBConfigInternal(display, config);
499 0 : AFTER_GLX_CALL;
500 0 : return result;
501 : }
502 :
503 : int
504 0 : GLXLibrary::xGetFBConfigAttrib(Display *display,
505 : GLXFBConfig config,
506 : int attribute,
507 : int *value)
508 : {
509 0 : BEFORE_GLX_CALL;
510 : int result = xGetFBConfigAttribInternal(display, config,
511 0 : attribute, value);
512 0 : AFTER_GLX_CALL;
513 0 : return result;
514 : }
515 :
516 : void
517 0 : GLXLibrary::xSwapBuffers(Display *display, GLXDrawable drawable)
518 : {
519 0 : BEFORE_GLX_CALL;
520 0 : xSwapBuffersInternal(display, drawable);
521 0 : AFTER_GLX_CALL;
522 0 : }
523 :
524 : const char *
525 0 : GLXLibrary::xQueryExtensionsString(Display *display,
526 : int screen)
527 : {
528 0 : BEFORE_GLX_CALL;
529 0 : const char *result = xQueryExtensionsStringInternal(display, screen);
530 0 : AFTER_GLX_CALL;
531 0 : return result;
532 : }
533 :
534 : const char *
535 0 : GLXLibrary::xGetClientString(Display *display,
536 : int screen)
537 : {
538 0 : BEFORE_GLX_CALL;
539 0 : const char *result = xGetClientStringInternal(display, screen);
540 0 : AFTER_GLX_CALL;
541 0 : return result;
542 : }
543 :
544 : const char *
545 0 : GLXLibrary::xQueryServerString(Display *display,
546 : int screen, int name)
547 : {
548 0 : BEFORE_GLX_CALL;
549 0 : const char *result = xQueryServerStringInternal(display, screen, name);
550 0 : AFTER_GLX_CALL;
551 0 : return result;
552 : }
553 :
554 : GLXPixmap
555 0 : GLXLibrary::xCreatePixmap(Display *display,
556 : GLXFBConfig config,
557 : Pixmap pixmap,
558 : const int *attrib_list)
559 : {
560 0 : BEFORE_GLX_CALL;
561 : GLXPixmap result = xCreatePixmapInternal(display, config,
562 0 : pixmap, attrib_list);
563 0 : AFTER_GLX_CALL;
564 0 : return result;
565 : }
566 :
567 : GLXPixmap
568 0 : GLXLibrary::xCreateGLXPixmapWithConfig(Display *display,
569 : GLXFBConfig config,
570 : Pixmap pixmap)
571 : {
572 0 : BEFORE_GLX_CALL;
573 0 : GLXPixmap result = xCreateGLXPixmapWithConfigInternal(display, config, pixmap);
574 0 : AFTER_GLX_CALL;
575 0 : return result;
576 : }
577 :
578 : void
579 0 : GLXLibrary::xDestroyPixmap(Display *display, GLXPixmap pixmap)
580 : {
581 0 : BEFORE_GLX_CALL;
582 0 : xDestroyPixmapInternal(display, pixmap);
583 0 : AFTER_GLX_CALL;
584 0 : }
585 :
586 : GLXContext
587 0 : GLXLibrary::xCreateContext(Display *display,
588 : XVisualInfo *vis,
589 : GLXContext shareList,
590 : Bool direct)
591 : {
592 0 : BEFORE_GLX_CALL;
593 0 : GLXContext result = xCreateContextInternal(display, vis, shareList, direct);
594 0 : AFTER_GLX_CALL;
595 0 : return result;
596 : }
597 :
598 : Bool
599 0 : GLXLibrary::xQueryVersion(Display *display,
600 : int *major,
601 : int *minor)
602 : {
603 0 : BEFORE_GLX_CALL;
604 0 : Bool result = xQueryVersionInternal(display, major, minor);
605 0 : AFTER_GLX_CALL;
606 0 : return result;
607 : }
608 :
609 : void
610 0 : GLXLibrary::xBindTexImage(Display *display,
611 : GLXDrawable drawable,
612 : int buffer,
613 : const int *attrib_list)
614 : {
615 0 : BEFORE_GLX_CALL;
616 0 : xBindTexImageInternal(display, drawable, buffer, attrib_list);
617 0 : AFTER_GLX_CALL;
618 0 : }
619 :
620 : void
621 0 : GLXLibrary::xReleaseTexImage(Display *display,
622 : GLXDrawable drawable,
623 : int buffer)
624 : {
625 0 : BEFORE_GLX_CALL;
626 0 : xReleaseTexImageInternal(display, drawable, buffer);
627 0 : AFTER_GLX_CALL;
628 0 : }
629 :
630 : void
631 0 : GLXLibrary::xWaitGL()
632 : {
633 0 : BEFORE_GLX_CALL;
634 0 : xWaitGLInternal();
635 0 : AFTER_GLX_CALL;
636 0 : }
637 :
638 : void
639 0 : GLXLibrary::xWaitX()
640 : {
641 0 : BEFORE_GLX_CALL;
642 0 : xWaitXInternal();
643 0 : AFTER_GLX_CALL;
644 0 : }
645 :
646 : GLXContext
647 0 : GLXLibrary::xCreateContextAttribs(Display* display,
648 : GLXFBConfig config,
649 : GLXContext share_list,
650 : Bool direct,
651 : const int* attrib_list)
652 : {
653 0 : BEFORE_GLX_CALL;
654 : GLXContext result = xCreateContextAttribsInternal(display,
655 : config,
656 : share_list,
657 : direct,
658 0 : attrib_list);
659 0 : AFTER_GLX_CALL;
660 0 : return result;
661 : }
662 :
663 1464 : GLXLibrary sGLXLibrary;
664 :
665 : class GLContextGLX : public GLContext
666 : {
667 : public:
668 : static already_AddRefed<GLContextGLX>
669 0 : CreateGLContext(const ContextFormat& format,
670 : Display *display,
671 : GLXDrawable drawable,
672 : GLXFBConfig cfg,
673 : XVisualInfo *vinfo,
674 : GLContextGLX *shareContext,
675 : bool deleteDrawable,
676 : gfxXlibSurface *pixmap = nsnull)
677 : {
678 0 : int db = 0, err;
679 : err = sGLXLibrary.xGetFBConfigAttrib(display, cfg,
680 0 : GLX_DOUBLEBUFFER, &db);
681 0 : if (GLX_BAD_ATTRIBUTE != err) {
682 : #ifdef DEBUG
683 0 : printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
684 : #endif
685 : }
686 :
687 : GLXContext context;
688 0 : nsRefPtr<GLContextGLX> glContext;
689 : bool error;
690 :
691 0 : ScopedXErrorHandler xErrorHandler;
692 :
693 : TRY_AGAIN_NO_SHARING:
694 :
695 0 : error = false;
696 :
697 0 : if (sGLXLibrary.HasRobustness()) {
698 : int attrib_list[] = {
699 : LOCAL_GL_CONTEXT_FLAGS_ARB, LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
700 : LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_GL_LOSE_CONTEXT_ON_RESET_ARB,
701 : 0,
702 0 : };
703 :
704 : context = sGLXLibrary.xCreateContextAttribs(display,
705 : cfg,
706 : shareContext ? shareContext->mContext : NULL,
707 : True,
708 0 : attrib_list);
709 : } else {
710 : context = sGLXLibrary.xCreateNewContext(display,
711 : cfg,
712 : GLX_RGBA_TYPE,
713 : shareContext ? shareContext->mContext : NULL,
714 0 : True);
715 : }
716 :
717 0 : if (context) {
718 : glContext = new GLContextGLX(format,
719 : shareContext,
720 : display,
721 : drawable,
722 : context,
723 : deleteDrawable,
724 : db,
725 0 : pixmap);
726 0 : if (!glContext->Init())
727 0 : error = true;
728 : } else {
729 0 : error = true;
730 : }
731 :
732 0 : error |= xErrorHandler.SyncAndGetError(display);
733 :
734 0 : if (error) {
735 0 : if (shareContext) {
736 0 : shareContext = nsnull;
737 0 : goto TRY_AGAIN_NO_SHARING;
738 : }
739 :
740 0 : NS_WARNING("Failed to create GLXContext!");
741 0 : glContext = nsnull; // note: this must be done while the graceful X error handler is set,
742 : // because glxMakeCurrent can give a GLXBadDrawable error
743 : }
744 :
745 0 : return glContext.forget();
746 : }
747 :
748 0 : ~GLContextGLX()
749 0 : {
750 0 : MarkDestroyed();
751 :
752 : // see bug 659842 comment 76
753 : #ifdef DEBUG
754 : bool success =
755 : #endif
756 0 : sGLXLibrary.xMakeCurrent(mDisplay, None, nsnull);
757 0 : NS_ABORT_IF_FALSE(success,
758 : "glXMakeCurrent failed to release GL context before we call glXDestroyContext!");
759 :
760 0 : sGLXLibrary.xDestroyContext(mDisplay, mContext);
761 :
762 0 : if (mDeleteDrawable) {
763 0 : sGLXLibrary.xDestroyPixmap(mDisplay, mDrawable);
764 : }
765 0 : }
766 :
767 0 : GLContextType GetContextType() {
768 0 : return ContextTypeGLX;
769 : }
770 :
771 0 : bool Init()
772 : {
773 0 : MakeCurrent();
774 0 : SetupLookupFunction();
775 0 : if (!InitWithPrefix("gl", true)) {
776 0 : return false;
777 : }
778 :
779 0 : if (!IsExtensionSupported("GL_EXT_framebuffer_object"))
780 0 : return false;
781 :
782 0 : InitFramebuffers();
783 :
784 0 : return true;
785 : }
786 :
787 0 : bool MakeCurrentImpl(bool aForce = false)
788 : {
789 0 : bool succeeded = true;
790 :
791 : // With the ATI FGLRX driver, glxMakeCurrent is very slow even when the context doesn't change.
792 : // (This is not the case with other drivers such as NVIDIA).
793 : // So avoid calling it more than necessary. Since GLX documentation says that:
794 : // "glXGetCurrentContext returns client-side information.
795 : // It does not make a round trip to the server."
796 : // I assume that it's not worth using our own TLS slot here.
797 0 : if (aForce || sGLXLibrary.xGetCurrentContext() != mContext) {
798 0 : succeeded = sGLXLibrary.xMakeCurrent(mDisplay, mDrawable, mContext);
799 0 : NS_ASSERTION(succeeded, "Failed to make GL context current!");
800 : }
801 :
802 0 : return succeeded;
803 : }
804 :
805 0 : bool SetupLookupFunction()
806 : {
807 0 : mLookupFunc = (PlatformLookupFunction)&GLXLibrary::xGetProcAddress;
808 0 : return true;
809 : }
810 :
811 0 : void *GetNativeData(NativeDataType aType)
812 : {
813 0 : switch(aType) {
814 : case NativeGLContext:
815 0 : return mContext;
816 :
817 : case NativeThebesSurface:
818 0 : return mPixmap;
819 :
820 : default:
821 0 : return nsnull;
822 : }
823 : }
824 :
825 0 : bool IsDoubleBuffered()
826 : {
827 0 : return mDoubleBuffered;
828 : }
829 :
830 0 : bool SupportsRobustness()
831 : {
832 0 : return sGLXLibrary.HasRobustness();
833 : }
834 :
835 0 : bool SwapBuffers()
836 : {
837 0 : if (!mDoubleBuffered)
838 0 : return false;
839 0 : sGLXLibrary.xSwapBuffers(mDisplay, mDrawable);
840 0 : sGLXLibrary.xWaitGL();
841 0 : return true;
842 : }
843 :
844 0 : bool TextureImageSupportsGetBackingSurface()
845 : {
846 0 : return sGLXLibrary.HasTextureFromPixmap();
847 : }
848 :
849 : virtual already_AddRefed<TextureImage>
850 : CreateTextureImage(const nsIntSize& aSize,
851 : TextureImage::ContentType aContentType,
852 : GLenum aWrapMode,
853 : bool aUseNearestFilter = false);
854 :
855 : private:
856 : friend class GLContextProviderGLX;
857 :
858 0 : GLContextGLX(const ContextFormat& aFormat,
859 : GLContext *aShareContext,
860 : Display *aDisplay,
861 : GLXDrawable aDrawable,
862 : GLXContext aContext,
863 : bool aDeleteDrawable,
864 : bool aDoubleBuffered,
865 : gfxXlibSurface *aPixmap)
866 : : GLContext(aFormat, aDeleteDrawable ? true : false, aShareContext),
867 : mContext(aContext),
868 : mDisplay(aDisplay),
869 : mDrawable(aDrawable),
870 : mDeleteDrawable(aDeleteDrawable),
871 : mDoubleBuffered(aDoubleBuffered),
872 0 : mPixmap(aPixmap)
873 0 : { }
874 :
875 : GLXContext mContext;
876 : Display *mDisplay;
877 : GLXDrawable mDrawable;
878 : bool mDeleteDrawable;
879 : bool mDoubleBuffered;
880 :
881 : nsRefPtr<gfxXlibSurface> mPixmap;
882 : };
883 :
884 : class TextureImageGLX : public TextureImage
885 : {
886 : friend already_AddRefed<TextureImage>
887 : GLContextGLX::CreateTextureImage(const nsIntSize&,
888 : ContentType,
889 : GLenum,
890 : bool);
891 :
892 : public:
893 0 : virtual ~TextureImageGLX()
894 0 : {
895 0 : mGLContext->MakeCurrent();
896 0 : mGLContext->fDeleteTextures(1, &mTexture);
897 0 : sGLXLibrary.DestroyPixmap(mPixmap);
898 0 : }
899 :
900 0 : virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion)
901 : {
902 0 : mInUpdate = true;
903 0 : return mUpdateSurface;
904 : }
905 :
906 0 : virtual void EndUpdate()
907 : {
908 0 : mInUpdate = false;
909 0 : }
910 :
911 :
912 0 : virtual bool DirectUpdate(gfxASurface* aSurface, const nsIntRegion& aRegion, const nsIntPoint& aFrom)
913 : {
914 0 : nsRefPtr<gfxContext> ctx = new gfxContext(mUpdateSurface);
915 0 : gfxUtils::ClipToRegion(ctx, aRegion);
916 0 : ctx->SetSource(aSurface, aFrom);
917 0 : ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
918 0 : ctx->Paint();
919 0 : return true;
920 : }
921 :
922 0 : virtual void BindTexture(GLenum aTextureUnit)
923 : {
924 0 : mGLContext->fActiveTexture(aTextureUnit);
925 0 : mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
926 0 : sGLXLibrary.BindTexImage(mPixmap);
927 0 : mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
928 0 : }
929 :
930 0 : virtual void ReleaseTexture()
931 : {
932 0 : sGLXLibrary.ReleaseTexImage(mPixmap);
933 0 : }
934 :
935 0 : virtual already_AddRefed<gfxASurface> GetBackingSurface()
936 : {
937 0 : nsRefPtr<gfxASurface> copy = mUpdateSurface;
938 0 : return copy.forget();
939 : }
940 :
941 0 : virtual bool InUpdate() const { return mInUpdate; }
942 :
943 0 : virtual GLuint GetTextureID() {
944 0 : return mTexture;
945 : };
946 :
947 : private:
948 0 : TextureImageGLX(GLuint aTexture,
949 : const nsIntSize& aSize,
950 : GLenum aWrapMode,
951 : ContentType aContentType,
952 : GLContext* aContext,
953 : gfxASurface* aSurface,
954 : GLXPixmap aPixmap)
955 : : TextureImage(aSize, aWrapMode, aContentType)
956 : , mGLContext(aContext)
957 : , mUpdateSurface(aSurface)
958 : , mPixmap(aPixmap)
959 : , mInUpdate(false)
960 0 : , mTexture(aTexture)
961 : {
962 0 : if (aSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
963 0 : mShaderType = gl::RGBALayerProgramType;
964 : } else {
965 0 : mShaderType = gl::RGBXLayerProgramType;
966 : }
967 0 : }
968 :
969 : GLContext* mGLContext;
970 : nsRefPtr<gfxASurface> mUpdateSurface;
971 : GLXPixmap mPixmap;
972 : bool mInUpdate;
973 : GLuint mTexture;
974 :
975 0 : virtual void ApplyFilter()
976 : {
977 0 : mGLContext->ApplyFilterToBoundTexture(mFilter);
978 0 : }
979 : };
980 :
981 : already_AddRefed<TextureImage>
982 0 : GLContextGLX::CreateTextureImage(const nsIntSize& aSize,
983 : TextureImage::ContentType aContentType,
984 : GLenum aWrapMode,
985 : bool aUseNearestFilter)
986 : {
987 0 : if (!TextureImageSupportsGetBackingSurface()) {
988 : return GLContext::CreateTextureImage(aSize,
989 : aContentType,
990 : aWrapMode,
991 0 : aUseNearestFilter);
992 : }
993 :
994 0 : Display *display = DefaultXDisplay();
995 0 : int xscreen = DefaultScreen(display);
996 0 : gfxASurface::gfxImageFormat imageFormat = gfxASurface::FormatFromContent(aContentType);
997 :
998 : XRenderPictFormat* xrenderFormat =
999 0 : gfxXlibSurface::FindRenderFormat(display, imageFormat);
1000 0 : NS_ASSERTION(xrenderFormat, "Could not find a render format for our display!");
1001 :
1002 :
1003 : nsRefPtr<gfxXlibSurface> surface =
1004 : gfxXlibSurface::Create(ScreenOfDisplay(display, xscreen),
1005 : xrenderFormat,
1006 0 : gfxIntSize(aSize.width, aSize.height));
1007 0 : NS_ASSERTION(surface, "Failed to create xlib surface!");
1008 :
1009 0 : if (aContentType == gfxASurface::CONTENT_COLOR_ALPHA) {
1010 0 : nsRefPtr<gfxContext> ctx = new gfxContext(surface);
1011 0 : ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
1012 0 : ctx->Paint();
1013 : }
1014 :
1015 0 : MakeCurrent();
1016 0 : GLXPixmap pixmap = sGLXLibrary.CreatePixmap(surface);
1017 0 : NS_ASSERTION(pixmap, "Failed to create pixmap!");
1018 :
1019 : GLuint texture;
1020 0 : fGenTextures(1, &texture);
1021 :
1022 0 : fActiveTexture(LOCAL_GL_TEXTURE0);
1023 0 : fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
1024 :
1025 : nsRefPtr<TextureImageGLX> teximage =
1026 0 : new TextureImageGLX(texture, aSize, aWrapMode, aContentType, this, surface, pixmap);
1027 :
1028 0 : GLint texfilter = aUseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
1029 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
1030 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
1031 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
1032 0 : fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
1033 :
1034 0 : return teximage.forget();
1035 : }
1036 :
1037 : static GLContextGLX *
1038 0 : GetGlobalContextGLX()
1039 : {
1040 0 : return static_cast<GLContextGLX*>(GLContextProviderGLX::GetGlobalContext());
1041 : }
1042 :
1043 : static bool
1044 0 : AreCompatibleVisuals(XVisualInfo *one, XVisualInfo *two)
1045 : {
1046 0 : if (one->c_class != two->c_class) {
1047 0 : return false;
1048 : }
1049 :
1050 0 : if (one->depth != two->depth) {
1051 0 : return false;
1052 : }
1053 :
1054 0 : if (one->red_mask != two->red_mask ||
1055 : one->green_mask != two->green_mask ||
1056 : one->blue_mask != two->blue_mask) {
1057 0 : return false;
1058 : }
1059 :
1060 0 : if (one->bits_per_rgb != two->bits_per_rgb) {
1061 0 : return false;
1062 : }
1063 :
1064 0 : return true;
1065 : }
1066 :
1067 : already_AddRefed<GLContext>
1068 0 : GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget)
1069 : {
1070 0 : if (!sGLXLibrary.EnsureInitialized()) {
1071 0 : return nsnull;
1072 : }
1073 :
1074 : // Currently, we take whatever Visual the window already has, and
1075 : // try to create an fbconfig for that visual. This isn't
1076 : // necessarily what we want in the long run; an fbconfig may not
1077 : // be available for the existing visual, or if it is, the GL
1078 : // performance might be suboptimal. But using the existing visual
1079 : // is a relatively safe intermediate step.
1080 :
1081 0 : Display *display = (Display*)aWidget->GetNativeData(NS_NATIVE_DISPLAY);
1082 0 : int xscreen = DefaultScreen(display);
1083 0 : Window window = GET_NATIVE_WINDOW(aWidget);
1084 :
1085 : int numConfigs;
1086 0 : ScopedXFree<GLXFBConfig> cfgs;
1087 0 : if (gIsATI || !GLXVersionCheck(1, 3)) {
1088 : const int attribs[] = {
1089 : GLX_DOUBLEBUFFER, False,
1090 : 0
1091 0 : };
1092 : cfgs = sGLXLibrary.xChooseFBConfig(display,
1093 : xscreen,
1094 : attribs,
1095 0 : &numConfigs);
1096 : } else {
1097 : cfgs = sGLXLibrary.xGetFBConfigs(display,
1098 : xscreen,
1099 0 : &numConfigs);
1100 : }
1101 :
1102 0 : if (!cfgs) {
1103 0 : NS_WARNING("[GLX] glXGetFBConfigs() failed");
1104 0 : return nsnull;
1105 : }
1106 0 : NS_ASSERTION(numConfigs > 0, "No FBConfigs found!");
1107 :
1108 : // XXX the visual ID is almost certainly the GLX_FBCONFIG_ID, so
1109 : // we could probably do this first and replace the glXGetFBConfigs
1110 : // with glXChooseConfigs. Docs are sparklingly clear as always.
1111 : XWindowAttributes widgetAttrs;
1112 0 : if (!XGetWindowAttributes(display, window, &widgetAttrs)) {
1113 0 : NS_WARNING("[GLX] XGetWindowAttributes() failed");
1114 0 : return nsnull;
1115 : }
1116 0 : const VisualID widgetVisualID = XVisualIDFromVisual(widgetAttrs.visual);
1117 : #ifdef DEBUG
1118 0 : printf("[GLX] widget has VisualID 0x%lx\n", widgetVisualID);
1119 : #endif
1120 :
1121 0 : ScopedXFree<XVisualInfo> vi;
1122 0 : if (gIsATI) {
1123 : XVisualInfo vinfo_template;
1124 : int nvisuals;
1125 0 : vinfo_template.visual = widgetAttrs.visual;
1126 0 : vinfo_template.visualid = XVisualIDFromVisual(vinfo_template.visual);
1127 0 : vinfo_template.depth = widgetAttrs.depth;
1128 0 : vinfo_template.screen = xscreen;
1129 : vi = XGetVisualInfo(display, VisualIDMask|VisualDepthMask|VisualScreenMask,
1130 0 : &vinfo_template, &nvisuals);
1131 0 : NS_ASSERTION(vi && nvisuals == 1, "Could not locate unique matching XVisualInfo for Visual");
1132 : }
1133 :
1134 0 : int matchIndex = -1;
1135 0 : ScopedXFree<XVisualInfo> vinfo;
1136 :
1137 0 : for (int i = 0; i < numConfigs; i++) {
1138 0 : vinfo = sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]);
1139 0 : if (!vinfo) {
1140 0 : continue;
1141 : }
1142 0 : if (gIsATI) {
1143 0 : if (AreCompatibleVisuals(vi, vinfo)) {
1144 0 : matchIndex = i;
1145 0 : break;
1146 : }
1147 : } else {
1148 0 : if (widgetVisualID == vinfo->visualid) {
1149 0 : matchIndex = i;
1150 0 : break;
1151 : }
1152 : }
1153 : }
1154 :
1155 0 : if (matchIndex == -1) {
1156 0 : NS_WARNING("[GLX] Couldn't find a FBConfig matching widget visual");
1157 0 : return nsnull;
1158 : }
1159 :
1160 0 : GLContextGLX *shareContext = GetGlobalContextGLX();
1161 :
1162 : nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
1163 : display,
1164 : window,
1165 0 : cfgs[matchIndex],
1166 : vinfo,
1167 : shareContext,
1168 0 : false);
1169 :
1170 0 : return glContext.forget();
1171 : }
1172 :
1173 : static already_AddRefed<GLContextGLX>
1174 0 : CreateOffscreenPixmapContext(const gfxIntSize& aSize,
1175 : const ContextFormat& aFormat,
1176 : bool aShare)
1177 : {
1178 0 : if (!sGLXLibrary.EnsureInitialized()) {
1179 0 : return nsnull;
1180 : }
1181 :
1182 0 : Display *display = DefaultXDisplay();
1183 0 : int xscreen = DefaultScreen(display);
1184 :
1185 : int attribs[] = {
1186 : GLX_DOUBLEBUFFER, False,
1187 : GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
1188 : GLX_X_RENDERABLE, True,
1189 : GLX_RED_SIZE, 1,
1190 : GLX_GREEN_SIZE, 1,
1191 : GLX_BLUE_SIZE, 1,
1192 : GLX_ALPHA_SIZE, 0,
1193 : GLX_DEPTH_SIZE, 0,
1194 : 0
1195 0 : };
1196 0 : int numConfigs = 0;
1197 :
1198 0 : ScopedXFree<GLXFBConfig> cfgs;
1199 : cfgs = sGLXLibrary.xChooseFBConfig(display,
1200 : xscreen,
1201 : attribs,
1202 0 : &numConfigs);
1203 0 : if (!cfgs) {
1204 0 : return nsnull;
1205 : }
1206 :
1207 0 : NS_ASSERTION(numConfigs > 0,
1208 : "glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
1209 :
1210 0 : ScopedXFree<XVisualInfo> vinfo;
1211 0 : int chosenIndex = 0;
1212 :
1213 0 : for (int i = 0; i < numConfigs; ++i) {
1214 : int dtype, visid;
1215 :
1216 0 : if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], GLX_DRAWABLE_TYPE, &dtype) != Success
1217 0 : || !(dtype & GLX_PIXMAP_BIT))
1218 : {
1219 0 : continue;
1220 : }
1221 0 : if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i], GLX_VISUAL_ID, &visid) != Success
1222 : || visid == 0)
1223 : {
1224 0 : continue;
1225 : }
1226 :
1227 0 : vinfo = sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]);
1228 :
1229 0 : if (vinfo) {
1230 0 : chosenIndex = i;
1231 0 : break;
1232 : }
1233 : }
1234 :
1235 0 : if (!vinfo) {
1236 0 : NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!");
1237 0 : return nsnull;
1238 : }
1239 :
1240 0 : ScopedXErrorHandler xErrorHandler;
1241 0 : GLXPixmap glxpixmap = 0;
1242 0 : bool error = false;
1243 :
1244 : nsRefPtr<gfxXlibSurface> xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
1245 0 : vinfo->visual,
1246 0 : gfxIntSize(16, 16));
1247 0 : if (xsurface->CairoStatus() != 0) {
1248 0 : error = true;
1249 0 : goto DONE_CREATING_PIXMAP;
1250 : }
1251 :
1252 : // Handle slightly different signature between glXCreatePixmap and
1253 : // its pre-GLX-1.3 extension equivalent (though given the ABI, we
1254 : // might not need to).
1255 0 : if (GLXVersionCheck(1, 3)) {
1256 : glxpixmap = sGLXLibrary.xCreatePixmap(display,
1257 0 : cfgs[chosenIndex],
1258 : xsurface->XDrawable(),
1259 0 : NULL);
1260 : } else {
1261 : glxpixmap = sGLXLibrary.xCreateGLXPixmapWithConfig(display,
1262 0 : cfgs[chosenIndex],
1263 : xsurface->
1264 0 : XDrawable());
1265 : }
1266 0 : if (glxpixmap == 0) {
1267 0 : error = true;
1268 : }
1269 :
1270 : DONE_CREATING_PIXMAP:
1271 :
1272 0 : nsRefPtr<GLContextGLX> glContext;
1273 0 : bool serverError = xErrorHandler.SyncAndGetError(display);
1274 :
1275 0 : if (!error && // earlier recorded error
1276 0 : !serverError)
1277 : {
1278 : glContext = GLContextGLX::CreateGLContext(
1279 : aFormat,
1280 : display,
1281 : glxpixmap,
1282 0 : cfgs[chosenIndex],
1283 : vinfo,
1284 : aShare ? GetGlobalContextGLX() : nsnull,
1285 : true,
1286 0 : xsurface);
1287 : }
1288 :
1289 0 : return glContext.forget();
1290 : }
1291 :
1292 : already_AddRefed<GLContext>
1293 0 : GLContextProviderGLX::CreateOffscreen(const gfxIntSize& aSize,
1294 : const ContextFormat& aFormat)
1295 : {
1296 : nsRefPtr<GLContextGLX> glContext =
1297 0 : CreateOffscreenPixmapContext(aSize, aFormat, true);
1298 :
1299 0 : if (!glContext) {
1300 0 : return nsnull;
1301 : }
1302 :
1303 0 : if (!glContext->GetSharedContext()) {
1304 : // no point in returning anything if sharing failed, we can't
1305 : // render from this
1306 0 : return nsnull;
1307 : }
1308 :
1309 0 : if (!glContext->ResizeOffscreenFBO(aSize, true)) {
1310 : // we weren't able to create the initial
1311 : // offscreen FBO, so this is dead
1312 0 : return nsnull;
1313 : }
1314 :
1315 0 : return glContext.forget();
1316 : }
1317 :
1318 : already_AddRefed<GLContext>
1319 0 : GLContextProviderGLX::CreateForNativePixmapSurface(gfxASurface *aSurface)
1320 : {
1321 0 : if (!sGLXLibrary.EnsureInitialized()) {
1322 0 : return nsnull;
1323 : }
1324 :
1325 0 : if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib) {
1326 0 : NS_WARNING("GLContextProviderGLX::CreateForNativePixmapSurface called with non-Xlib surface");
1327 0 : return nsnull;
1328 : }
1329 :
1330 0 : nsAutoTArray<int, 20> attribs;
1331 :
1332 : #define A1_(_x) do { attribs.AppendElement(_x); } while(0)
1333 : #define A2_(_x,_y) do { \
1334 : attribs.AppendElement(_x); \
1335 : attribs.AppendElement(_y); \
1336 : } while(0)
1337 :
1338 0 : A2_(GLX_DOUBLEBUFFER, False);
1339 0 : A2_(GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT);
1340 0 : A1_(0);
1341 :
1342 : int numFormats;
1343 0 : Display *display = DefaultXDisplay();
1344 0 : int xscreen = DefaultScreen(display);
1345 :
1346 : ScopedXFree<GLXFBConfig> cfg(sGLXLibrary.xChooseFBConfig(display,
1347 : xscreen,
1348 0 : attribs.Elements(),
1349 0 : &numFormats));
1350 0 : if (!cfg) {
1351 0 : return nsnull;
1352 : }
1353 0 : NS_ASSERTION(numFormats > 0,
1354 : "glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
1355 :
1356 0 : gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
1357 :
1358 : GLXPixmap glxpixmap = sGLXLibrary.xCreatePixmap(display,
1359 0 : cfg[0],
1360 : xs->XDrawable(),
1361 0 : NULL);
1362 :
1363 : nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
1364 : display,
1365 : glxpixmap,
1366 0 : cfg[0],
1367 : NULL,
1368 : NULL,
1369 : false,
1370 0 : xs);
1371 :
1372 0 : return glContext.forget();
1373 : }
1374 :
1375 1464 : static nsRefPtr<GLContext> gGlobalContext;
1376 :
1377 : GLContext *
1378 0 : GLContextProviderGLX::GetGlobalContext()
1379 : {
1380 : static bool triedToCreateContext = false;
1381 0 : if (!triedToCreateContext && !gGlobalContext) {
1382 0 : triedToCreateContext = true;
1383 : gGlobalContext = CreateOffscreenPixmapContext(gfxIntSize(1, 1),
1384 : ContextFormat(ContextFormat::BasicRGB24),
1385 0 : false);
1386 0 : if (gGlobalContext)
1387 0 : gGlobalContext->SetIsGlobalSharedContext(true);
1388 : }
1389 :
1390 0 : return gGlobalContext;
1391 : }
1392 :
1393 : void
1394 4 : GLContextProviderGLX::Shutdown()
1395 : {
1396 4 : gGlobalContext = nsnull;
1397 4 : }
1398 :
1399 : } /* namespace gl */
1400 4392 : } /* namespace mozilla */
1401 :
|