gfx/gl/GLContextProviderGLX.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial