Line data Source code
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 : #endif
11 :
12 : #include <X11/Xlib.h>
13 : #include <X11/Xutil.h>
14 : #include "X11UndefineNone.h"
15 :
16 : #include "mozilla/MathAlgorithms.h"
17 : #include "mozilla/StaticPtr.h"
18 : #include "mozilla/layers/CompositorOptions.h"
19 : #include "mozilla/widget/CompositorWidget.h"
20 : #include "mozilla/widget/X11CompositorWidget.h"
21 : #include "mozilla/Unused.h"
22 :
23 : #include "prenv.h"
24 : #include "GLContextProvider.h"
25 : #include "GLLibraryLoader.h"
26 : #include "nsDebug.h"
27 : #include "nsIWidget.h"
28 : #include "GLXLibrary.h"
29 : #include "gfxXlibSurface.h"
30 : #include "gfxContext.h"
31 : #include "gfxEnv.h"
32 : #include "gfxPlatform.h"
33 : #include "GLContextGLX.h"
34 : #include "gfxUtils.h"
35 : #include "gfx2DGlue.h"
36 : #include "GLScreenBuffer.h"
37 : #include "gfxPrefs.h"
38 :
39 : #include "gfxCrashReporterUtils.h"
40 :
41 : #ifdef MOZ_WIDGET_GTK
42 : #include "gfxPlatformGtk.h"
43 : #endif
44 :
45 : namespace mozilla {
46 : namespace gl {
47 :
48 : using namespace mozilla::gfx;
49 : using namespace mozilla::widget;
50 :
51 3 : GLXLibrary sGLXLibrary;
52 :
53 : static inline bool
54 0 : HasExtension(const char* aExtensions, const char* aRequiredExtension)
55 : {
56 : return GLContext::ListHasExtension(
57 0 : reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension);
58 : }
59 :
60 : bool
61 0 : GLXLibrary::EnsureInitialized()
62 : {
63 0 : if (mInitialized) {
64 0 : return true;
65 : }
66 :
67 : // Don't repeatedly try to initialize.
68 0 : if (mTriedInitializing) {
69 0 : return false;
70 : }
71 0 : mTriedInitializing = true;
72 :
73 : // Force enabling s3 texture compression. (Bug 774134)
74 0 : PR_SetEnv("force_s3tc_enable=true");
75 :
76 0 : if (!mOGLLibrary) {
77 0 : const char* libGLfilename = nullptr;
78 0 : bool forceFeatureReport = false;
79 :
80 : // see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1
81 : // because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls,
82 : // which trigger glibc bug http://sourceware.org/bugzilla/show_bug.cgi?id=12225
83 : #ifdef __OpenBSD__
84 : libGLfilename = "libGL.so";
85 : #else
86 0 : libGLfilename = "libGL.so.1";
87 : #endif
88 :
89 0 : ScopedGfxFeatureReporter reporter(libGLfilename, forceFeatureReport);
90 0 : mOGLLibrary = PR_LoadLibrary(libGLfilename);
91 0 : if (!mOGLLibrary) {
92 0 : NS_WARNING("Couldn't load OpenGL shared library.");
93 0 : return false;
94 : }
95 0 : reporter.SetSuccessful();
96 : }
97 :
98 0 : if (gfxEnv::GlxDebug()) {
99 0 : mDebug = true;
100 : }
101 :
102 : #define SYMBOL(X) { (PRFuncPtr*)&mSymbols.f##X, { "glX" #X, nullptr } }
103 : #define END_OF_SYMBOLS { nullptr, { nullptr } }
104 :
105 : const GLLibraryLoader::SymLoadStruct symbols[] = {
106 : /* functions that were in GLX 1.0 */
107 0 : SYMBOL(DestroyContext),
108 0 : SYMBOL(MakeCurrent),
109 0 : SYMBOL(SwapBuffers),
110 0 : SYMBOL(QueryVersion),
111 0 : SYMBOL(GetCurrentContext),
112 0 : SYMBOL(WaitGL),
113 0 : SYMBOL(WaitX),
114 :
115 : /* functions introduced in GLX 1.1 */
116 0 : SYMBOL(QueryExtensionsString),
117 0 : SYMBOL(GetClientString),
118 0 : SYMBOL(QueryServerString),
119 :
120 : /* functions introduced in GLX 1.3 */
121 0 : SYMBOL(ChooseFBConfig),
122 0 : SYMBOL(GetFBConfigAttrib),
123 0 : SYMBOL(GetFBConfigs),
124 0 : SYMBOL(CreatePixmap),
125 0 : SYMBOL(DestroyPixmap),
126 0 : SYMBOL(CreateNewContext),
127 :
128 : // Core in GLX 1.4, ARB extension before.
129 0 : { (PRFuncPtr*)&mSymbols.fGetProcAddress, { "glXGetProcAddress",
130 : "glXGetProcAddressARB",
131 : nullptr } },
132 : END_OF_SYMBOLS
133 0 : };
134 0 : if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols)) {
135 0 : NS_WARNING("Couldn't load required GLX symbols.");
136 0 : return false;
137 : }
138 :
139 0 : Display* display = DefaultXDisplay();
140 0 : int screen = DefaultScreen(display);
141 :
142 : {
143 : int major, minor;
144 0 : if (!fQueryVersion(display, &major, &minor) ||
145 0 : major != 1 || minor < 3)
146 : {
147 0 : NS_ERROR("GLX version older than 1.3. (released in 1998)");
148 0 : return false;
149 : }
150 : }
151 :
152 : const GLLibraryLoader::SymLoadStruct symbols_texturefrompixmap[] = {
153 0 : SYMBOL(BindTexImageEXT),
154 0 : SYMBOL(ReleaseTexImageEXT),
155 : END_OF_SYMBOLS
156 0 : };
157 :
158 : const GLLibraryLoader::SymLoadStruct symbols_createcontext[] = {
159 0 : SYMBOL(CreateContextAttribsARB),
160 : END_OF_SYMBOLS
161 0 : };
162 :
163 : const GLLibraryLoader::SymLoadStruct symbols_videosync[] = {
164 0 : SYMBOL(GetVideoSyncSGI),
165 0 : SYMBOL(WaitVideoSyncSGI),
166 : END_OF_SYMBOLS
167 0 : };
168 :
169 : const GLLibraryLoader::SymLoadStruct symbols_swapcontrol[] = {
170 0 : SYMBOL(SwapIntervalEXT),
171 : END_OF_SYMBOLS
172 0 : };
173 :
174 : const auto lookupFunction =
175 0 : (GLLibraryLoader::PlatformLookupFunction)mSymbols.fGetProcAddress;
176 :
177 0 : const auto fnLoadSymbols = [&](const GLLibraryLoader::SymLoadStruct* symbols) {
178 0 : if (GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols, lookupFunction))
179 0 : return true;
180 :
181 0 : GLLibraryLoader::ClearSymbols(symbols);
182 0 : return false;
183 0 : };
184 :
185 0 : const char* clientVendor = fGetClientString(display, LOCAL_GLX_VENDOR);
186 0 : const char* serverVendor = fQueryServerString(display, screen, LOCAL_GLX_VENDOR);
187 0 : const char* extensionsStr = fQueryExtensionsString(display, screen);
188 :
189 0 : if (HasExtension(extensionsStr, "GLX_EXT_texture_from_pixmap") &&
190 0 : fnLoadSymbols(symbols_texturefrompixmap))
191 : {
192 0 : mUseTextureFromPixmap = gfxPrefs::UseGLXTextureFromPixmap();
193 : } else {
194 0 : mUseTextureFromPixmap = false;
195 0 : NS_WARNING("Texture from pixmap disabled");
196 : }
197 :
198 0 : if (HasExtension(extensionsStr, "GLX_ARB_create_context") &&
199 0 : HasExtension(extensionsStr, "GLX_ARB_create_context_profile") &&
200 0 : fnLoadSymbols(symbols_createcontext))
201 : {
202 0 : mHasCreateContextAttribs = true;
203 : }
204 :
205 0 : if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness")) {
206 0 : mHasRobustness = true;
207 : }
208 :
209 0 : if (HasExtension(extensionsStr, "GLX_SGI_video_sync") &&
210 0 : fnLoadSymbols(symbols_videosync))
211 : {
212 0 : mHasVideoSync = true;
213 : }
214 :
215 0 : if (!HasExtension(extensionsStr, "GLX_EXT_swap_control") ||
216 0 : !fnLoadSymbols(symbols_swapcontrol))
217 : {
218 0 : NS_WARNING("GLX_swap_control unsupported, ASAP mode may still block on buffer swaps.");
219 : }
220 :
221 0 : mIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI");
222 0 : mIsNVIDIA = serverVendor && DoesStringMatch(serverVendor, "NVIDIA Corporation");
223 0 : mClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa");
224 :
225 0 : mInitialized = true;
226 :
227 0 : return true;
228 : }
229 :
230 : bool
231 0 : GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface)
232 : {
233 0 : if (!EnsureInitialized()) {
234 0 : return false;
235 : }
236 :
237 0 : if (aSurface->GetType() != gfxSurfaceType::Xlib || !mUseTextureFromPixmap) {
238 0 : return false;
239 : }
240 :
241 0 : return true;
242 : }
243 :
244 : bool
245 0 : GLXLibrary::SupportsVideoSync()
246 : {
247 0 : if (!EnsureInitialized()) {
248 0 : return false;
249 : }
250 :
251 0 : return mHasVideoSync;
252 : }
253 :
254 : GLXPixmap
255 0 : GLXLibrary::CreatePixmap(gfxASurface* aSurface)
256 : {
257 0 : if (!SupportsTextureFromPixmap(aSurface)) {
258 0 : return X11None;
259 : }
260 :
261 0 : gfxXlibSurface* xs = static_cast<gfxXlibSurface*>(aSurface);
262 0 : const XRenderPictFormat* format = xs->XRenderFormat();
263 0 : if (!format || format->type != PictTypeDirect) {
264 0 : return X11None;
265 : }
266 0 : const XRenderDirectFormat& direct = format->direct;
267 0 : int alphaSize = FloorLog2(direct.alphaMask + 1);
268 0 : NS_ASSERTION((1 << alphaSize) - 1 == direct.alphaMask,
269 : "Unexpected render format with non-adjacent alpha bits");
270 :
271 : int attribs[] = { LOCAL_GLX_DOUBLEBUFFER, False,
272 : LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT,
273 : LOCAL_GLX_ALPHA_SIZE, alphaSize,
274 0 : (alphaSize ? LOCAL_GLX_BIND_TO_TEXTURE_RGBA_EXT
275 : : LOCAL_GLX_BIND_TO_TEXTURE_RGB_EXT), True,
276 : LOCAL_GLX_RENDER_TYPE, LOCAL_GLX_RGBA_BIT,
277 0 : X11None };
278 :
279 0 : int numConfigs = 0;
280 0 : Display* display = xs->XDisplay();
281 0 : int xscreen = DefaultScreen(display);
282 :
283 : ScopedXFree<GLXFBConfig> cfgs(fChooseFBConfig(display,
284 : xscreen,
285 : attribs,
286 0 : &numConfigs));
287 :
288 : // Find an fbconfig that matches the pixel format used on the Pixmap.
289 0 : int matchIndex = -1;
290 : unsigned long redMask =
291 0 : static_cast<unsigned long>(direct.redMask) << direct.red;
292 : unsigned long greenMask =
293 0 : static_cast<unsigned long>(direct.greenMask) << direct.green;
294 : unsigned long blueMask =
295 0 : static_cast<unsigned long>(direct.blueMask) << direct.blue;
296 : // This is true if the Pixmap has bits for alpha or unused bits.
297 : bool haveNonColorBits =
298 0 : ~(redMask | greenMask | blueMask) != -1UL << format->depth;
299 :
300 0 : for (int i = 0; i < numConfigs; i++) {
301 0 : int id = X11None;
302 0 : sGLXLibrary.fGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &id);
303 : Visual* visual;
304 : int depth;
305 0 : FindVisualAndDepth(display, id, &visual, &depth);
306 0 : if (!visual ||
307 0 : visual->c_class != TrueColor ||
308 0 : visual->red_mask != redMask ||
309 0 : visual->green_mask != greenMask ||
310 0 : visual->blue_mask != blueMask ) {
311 0 : continue;
312 : }
313 :
314 : // Historically Xlib Visuals did not try to represent an alpha channel
315 : // and there was no means to use an alpha channel on a Pixmap. The
316 : // Xlib Visual from the fbconfig was not intended to have any
317 : // information about alpha bits.
318 : //
319 : // Since then, RENDER has added formats for 32 bit depth Pixmaps.
320 : // Some of these formats have bits for alpha and some have unused
321 : // bits.
322 : //
323 : // Then the Composite extension added a 32 bit depth Visual intended
324 : // for Windows with an alpha channel, so bits not in the visual color
325 : // masks were expected to be treated as alpha bits.
326 : //
327 : // Usually GLX counts only color bits in the Visual depth, but the
328 : // depth of Composite's ARGB Visual includes alpha bits. However,
329 : // bits not in the color masks are not necessarily alpha bits because
330 : // sometimes (NVIDIA) 32 bit Visuals are added for fbconfigs with 32
331 : // bit BUFFER_SIZE but zero alpha bits and 24 color bits (NVIDIA
332 : // again).
333 : //
334 : // This checks that the depth matches in one of the two ways.
335 : // NVIDIA now forces format->depth == depth so only the first way
336 : // is checked for NVIDIA
337 0 : if (depth != format->depth &&
338 0 : (mIsNVIDIA || depth != format->depth - alphaSize) ) {
339 0 : continue;
340 : }
341 :
342 : // If all bits of the Pixmap are color bits and the Pixmap depth
343 : // matches the depth of the fbconfig visual, then we can assume that
344 : // the driver will do whatever is necessary to ensure that any
345 : // GLXPixmap alpha bits are treated as set. We can skip the
346 : // ALPHA_SIZE check in this situation. We need to skip this check for
347 : // situations (ATI) where there are no fbconfigs without alpha bits.
348 : //
349 : // glXChooseFBConfig should prefer configs with smaller
350 : // LOCAL_GLX_BUFFER_SIZE, so we should still get zero alpha bits if
351 : // available, except perhaps with NVIDIA drivers where buffer size is
352 : // not the specified sum of the component sizes.
353 0 : if (haveNonColorBits) {
354 : // There are bits in the Pixmap format that haven't been matched
355 : // against the fbconfig visual. These bits could either represent
356 : // alpha or be unused, so just check that the number of alpha bits
357 : // matches.
358 0 : int size = 0;
359 0 : sGLXLibrary.fGetFBConfigAttrib(display, cfgs[i],
360 0 : LOCAL_GLX_ALPHA_SIZE, &size);
361 0 : if (size != alphaSize) {
362 0 : continue;
363 : }
364 : }
365 :
366 0 : matchIndex = i;
367 0 : break;
368 : }
369 0 : if (matchIndex == -1) {
370 : // GLX can't handle A8 surfaces, so this is not really unexpected. The
371 : // caller should deal with this situation.
372 0 : NS_WARNING_ASSERTION(
373 : format->depth == 8,
374 : "[GLX] Couldn't find a FBConfig matching Pixmap format");
375 0 : return X11None;
376 : }
377 :
378 : int pixmapAttribs[] = { LOCAL_GLX_TEXTURE_TARGET_EXT, LOCAL_GLX_TEXTURE_2D_EXT,
379 : LOCAL_GLX_TEXTURE_FORMAT_EXT,
380 0 : (alphaSize ? LOCAL_GLX_TEXTURE_FORMAT_RGBA_EXT
381 : : LOCAL_GLX_TEXTURE_FORMAT_RGB_EXT),
382 0 : X11None};
383 :
384 0 : GLXPixmap glxpixmap = fCreatePixmap(display,
385 0 : cfgs[matchIndex],
386 : xs->XDrawable(),
387 0 : pixmapAttribs);
388 :
389 0 : return glxpixmap;
390 : }
391 :
392 : void
393 0 : GLXLibrary::DestroyPixmap(Display* aDisplay, GLXPixmap aPixmap)
394 : {
395 0 : if (!mUseTextureFromPixmap) {
396 0 : return;
397 : }
398 :
399 0 : fDestroyPixmap(aDisplay, aPixmap);
400 : }
401 :
402 : void
403 0 : GLXLibrary::BindTexImage(Display* aDisplay, GLXPixmap aPixmap)
404 : {
405 0 : if (!mUseTextureFromPixmap) {
406 0 : return;
407 : }
408 :
409 : // Make sure all X drawing to the surface has finished before binding to a texture.
410 0 : if (mClientIsMesa) {
411 : // Using XSync instead of Mesa's glXWaitX, because its glxWaitX is a
412 : // noop when direct rendering unless the current drawable is a
413 : // single-buffer window.
414 0 : FinishX(aDisplay);
415 : } else {
416 0 : fWaitX();
417 : }
418 0 : fBindTexImage(aDisplay, aPixmap, LOCAL_GLX_FRONT_LEFT_EXT, nullptr);
419 : }
420 :
421 : void
422 0 : GLXLibrary::ReleaseTexImage(Display* aDisplay, GLXPixmap aPixmap)
423 : {
424 0 : if (!mUseTextureFromPixmap) {
425 0 : return;
426 : }
427 :
428 0 : fReleaseTexImage(aDisplay, aPixmap, LOCAL_GLX_FRONT_LEFT_EXT);
429 : }
430 :
431 : void
432 0 : GLXLibrary::UpdateTexImage(Display* aDisplay, GLXPixmap aPixmap)
433 : {
434 : // NVIDIA drivers don't require a rebind of the pixmap in order
435 : // to display an updated image, and it's faster not to do it.
436 0 : if (mIsNVIDIA) {
437 0 : fWaitX();
438 0 : return;
439 : }
440 :
441 0 : ReleaseTexImage(aDisplay, aPixmap);
442 0 : BindTexImage(aDisplay, aPixmap);
443 : }
444 :
445 : static int (*sOldErrorHandler)(Display*, XErrorEvent*);
446 3 : ScopedXErrorHandler::ErrorEvent sErrorEvent;
447 0 : static int GLXErrorHandler(Display* display, XErrorEvent* ev)
448 : {
449 0 : if (!sErrorEvent.mError.error_code) {
450 0 : sErrorEvent.mError = *ev;
451 : }
452 0 : return 0;
453 : }
454 :
455 : void
456 0 : GLXLibrary::BeforeGLXCall() const
457 : {
458 0 : if (mDebug) {
459 0 : sOldErrorHandler = XSetErrorHandler(GLXErrorHandler);
460 : }
461 0 : }
462 :
463 : void
464 0 : GLXLibrary::AfterGLXCall() const
465 : {
466 0 : if (mDebug) {
467 0 : FinishX(DefaultXDisplay());
468 0 : if (sErrorEvent.mError.error_code) {
469 : char buffer[2048];
470 0 : XGetErrorText(DefaultXDisplay(), sErrorEvent.mError.error_code, buffer, sizeof(buffer));
471 0 : printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %lu",
472 : buffer,
473 0 : sErrorEvent.mError.error_code,
474 0 : sErrorEvent.mError.request_code,
475 0 : sErrorEvent.mError.minor_code,
476 0 : sErrorEvent.mError.serial);
477 0 : NS_ABORT();
478 : }
479 0 : XSetErrorHandler(sOldErrorHandler);
480 : }
481 0 : }
482 :
483 : already_AddRefed<GLContextGLX>
484 0 : GLContextGLX::CreateGLContext(CreateContextFlags flags, const SurfaceCaps& caps,
485 : bool isOffscreen, Display* display, GLXDrawable drawable,
486 : GLXFBConfig cfg, bool deleteDrawable,
487 : gfxXlibSurface* pixmap)
488 : {
489 0 : GLXLibrary& glx = sGLXLibrary;
490 :
491 0 : int db = 0;
492 : int err = glx.fGetFBConfigAttrib(display, cfg,
493 0 : LOCAL_GLX_DOUBLEBUFFER, &db);
494 0 : if (LOCAL_GLX_BAD_ATTRIBUTE != err) {
495 0 : if (ShouldSpew()) {
496 0 : printf("[GLX] FBConfig is %sdouble-buffered\n", db ? "" : "not ");
497 : }
498 : }
499 :
500 : GLXContext context;
501 0 : RefPtr<GLContextGLX> glContext;
502 : bool error;
503 :
504 0 : OffMainThreadScopedXErrorHandler xErrorHandler;
505 :
506 : do {
507 0 : error = false;
508 :
509 0 : if (glx.HasCreateContextAttribs()) {
510 0 : AutoTArray<int, 11> attrib_list;
511 0 : if (glx.HasRobustness()) {
512 : const int robust_attribs[] = {
513 : LOCAL_GLX_CONTEXT_FLAGS_ARB,
514 : LOCAL_GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
515 : LOCAL_GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
516 : LOCAL_GLX_LOSE_CONTEXT_ON_RESET_ARB,
517 0 : };
518 0 : attrib_list.AppendElements(robust_attribs, MOZ_ARRAY_LENGTH(robust_attribs));
519 : }
520 0 : if (!(flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE)) {
521 : int core_attribs[] = {
522 : LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
523 : LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB, 2,
524 : LOCAL_GLX_CONTEXT_PROFILE_MASK_ARB, LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
525 0 : };
526 0 : attrib_list.AppendElements(core_attribs, MOZ_ARRAY_LENGTH(core_attribs));
527 : };
528 0 : attrib_list.AppendElement(0);
529 :
530 : context = glx.fCreateContextAttribs(
531 : display,
532 : cfg,
533 : nullptr,
534 : True,
535 0 : attrib_list.Elements());
536 : } else {
537 : context = glx.fCreateNewContext(
538 : display,
539 : cfg,
540 : LOCAL_GLX_RGBA_TYPE,
541 : nullptr,
542 0 : True);
543 : }
544 :
545 0 : if (context) {
546 : glContext = new GLContextGLX(flags, caps, isOffscreen, display, drawable,
547 0 : context, deleteDrawable, db, pixmap);
548 0 : if (!glContext->Init())
549 0 : error = true;
550 : } else {
551 0 : error = true;
552 : }
553 :
554 0 : error |= xErrorHandler.SyncAndGetError(display);
555 :
556 0 : if (error) {
557 0 : NS_WARNING("Failed to create GLXContext!");
558 0 : glContext = nullptr; // note: this must be done while the graceful X error handler is set,
559 : // because glxMakeCurrent can give a GLXBadDrawable error
560 : }
561 :
562 0 : return glContext.forget();
563 : } while (true);
564 : }
565 :
566 0 : GLContextGLX::~GLContextGLX()
567 : {
568 0 : MarkDestroyed();
569 :
570 : // Wrapped context should not destroy glxContext/Surface
571 0 : if (!mOwnsContext) {
572 0 : return;
573 : }
574 :
575 : // see bug 659842 comment 76
576 : #ifdef DEBUG
577 : bool success =
578 : #endif
579 0 : mGLX->fMakeCurrent(mDisplay, X11None, nullptr);
580 0 : MOZ_ASSERT(success,
581 : "glXMakeCurrent failed to release GL context before we call "
582 : "glXDestroyContext!");
583 :
584 0 : mGLX->fDestroyContext(mDisplay, mContext);
585 :
586 0 : if (mDeleteDrawable) {
587 0 : mGLX->fDestroyPixmap(mDisplay, mDrawable);
588 : }
589 0 : }
590 :
591 :
592 : bool
593 0 : GLContextGLX::Init()
594 : {
595 0 : SetupLookupFunction();
596 0 : if (!InitWithPrefix("gl", true)) {
597 0 : return false;
598 : }
599 :
600 : // EXT_framebuffer_object is not supported on Core contexts
601 : // so we'll also check for ARB_framebuffer_object
602 0 : if (!IsExtensionSupported(EXT_framebuffer_object) && !IsSupported(GLFeature::framebuffer_object))
603 0 : return false;
604 :
605 0 : return true;
606 : }
607 :
608 : bool
609 0 : GLContextGLX::MakeCurrentImpl(bool aForce)
610 : {
611 0 : bool succeeded = true;
612 :
613 : // With the ATI FGLRX driver, glxMakeCurrent is very slow even when the context doesn't change.
614 : // (This is not the case with other drivers such as NVIDIA).
615 : // So avoid calling it more than necessary. Since GLX documentation says that:
616 : // "glXGetCurrentContext returns client-side information.
617 : // It does not make a round trip to the server."
618 : // I assume that it's not worth using our own TLS slot here.
619 0 : if (aForce || mGLX->fGetCurrentContext() != mContext) {
620 0 : if (mGLX->IsMesa()) {
621 : // Read into the event queue to ensure that Mesa receives a
622 : // DRI2InvalidateBuffers event before drawing. See bug 1280653.
623 0 : Unused << XPending(mDisplay);
624 : }
625 :
626 0 : succeeded = mGLX->fMakeCurrent(mDisplay, mDrawable, mContext);
627 0 : NS_ASSERTION(succeeded, "Failed to make GL context current!");
628 :
629 0 : if (!IsOffscreen() && mGLX->SupportsSwapControl()) {
630 : // Many GLX implementations default to blocking until the next
631 : // VBlank when calling glXSwapBuffers. We want to run unthrottled
632 : // in ASAP mode. See bug 1280744.
633 0 : const bool isASAP = (gfxPrefs::LayoutFrameRate() == 0);
634 0 : mGLX->fSwapInterval(mDisplay, mDrawable, isASAP ? 0 : 1);
635 : }
636 : }
637 :
638 0 : return succeeded;
639 : }
640 :
641 : bool
642 0 : GLContextGLX::IsCurrent() {
643 0 : return mGLX->fGetCurrentContext() == mContext;
644 : }
645 :
646 : bool
647 0 : GLContextGLX::SetupLookupFunction()
648 : {
649 0 : mLookupFunc = (PlatformLookupFunction)sGLXLibrary.GetGetProcAddress();
650 0 : return true;
651 : }
652 :
653 : bool
654 0 : GLContextGLX::IsDoubleBuffered() const
655 : {
656 0 : return mDoubleBuffered;
657 : }
658 :
659 : bool
660 0 : GLContextGLX::SwapBuffers()
661 : {
662 0 : if (!mDoubleBuffered)
663 0 : return false;
664 0 : mGLX->fSwapBuffers(mDisplay, mDrawable);
665 0 : return true;
666 : }
667 :
668 : void
669 0 : GLContextGLX::GetWSIInfo(nsCString* const out) const
670 : {
671 0 : Display* display = DefaultXDisplay();
672 0 : int screen = DefaultScreen(display);
673 :
674 : int majorVersion, minorVersion;
675 0 : sGLXLibrary.fQueryVersion(display, &majorVersion, &minorVersion);
676 :
677 0 : out->Append(nsPrintfCString("GLX %u.%u", majorVersion, minorVersion));
678 :
679 0 : out->AppendLiteral("\nGLX_VENDOR(client): ");
680 0 : out->Append(sGLXLibrary.fGetClientString(display, LOCAL_GLX_VENDOR));
681 :
682 0 : out->AppendLiteral("\nGLX_VENDOR(server): ");
683 0 : out->Append(sGLXLibrary.fQueryServerString(display, screen, LOCAL_GLX_VENDOR));
684 :
685 0 : out->AppendLiteral("\nExtensions: ");
686 0 : out->Append(sGLXLibrary.fQueryExtensionsString(display, screen));
687 0 : }
688 :
689 : bool
690 0 : GLContextGLX::OverrideDrawable(GLXDrawable drawable)
691 : {
692 0 : if (Screen())
693 0 : Screen()->AssureBlitted();
694 0 : Bool result = mGLX->fMakeCurrent(mDisplay, drawable, mContext);
695 0 : return result;
696 : }
697 :
698 : bool
699 0 : GLContextGLX::RestoreDrawable()
700 : {
701 0 : return mGLX->fMakeCurrent(mDisplay, mDrawable, mContext);
702 : }
703 :
704 0 : GLContextGLX::GLContextGLX(
705 : CreateContextFlags flags,
706 : const SurfaceCaps& caps,
707 : bool isOffscreen,
708 : Display* aDisplay,
709 : GLXDrawable aDrawable,
710 : GLXContext aContext,
711 : bool aDeleteDrawable,
712 : bool aDoubleBuffered,
713 0 : gfxXlibSurface* aPixmap)
714 : : GLContext(flags, caps, nullptr, isOffscreen),
715 : mContext(aContext),
716 : mDisplay(aDisplay),
717 : mDrawable(aDrawable),
718 : mDeleteDrawable(aDeleteDrawable),
719 : mDoubleBuffered(aDoubleBuffered),
720 : mGLX(&sGLXLibrary),
721 : mPixmap(aPixmap),
722 0 : mOwnsContext(true)
723 : {
724 0 : }
725 :
726 : static bool
727 0 : AreCompatibleVisuals(Visual* one, Visual* two)
728 : {
729 0 : if (one->c_class != two->c_class) {
730 0 : return false;
731 : }
732 :
733 0 : if (one->red_mask != two->red_mask ||
734 0 : one->green_mask != two->green_mask ||
735 0 : one->blue_mask != two->blue_mask) {
736 0 : return false;
737 : }
738 :
739 0 : if (one->bits_per_rgb != two->bits_per_rgb) {
740 0 : return false;
741 : }
742 :
743 0 : return true;
744 : }
745 :
746 : already_AddRefed<GLContext>
747 0 : GLContextProviderGLX::CreateWrappingExisting(void* aContext, void* aSurface)
748 : {
749 0 : if (!sGLXLibrary.EnsureInitialized()) {
750 0 : return nullptr;
751 : }
752 :
753 0 : if (aContext && aSurface) {
754 0 : SurfaceCaps caps = SurfaceCaps::Any();
755 : RefPtr<GLContextGLX> glContext =
756 : new GLContextGLX(CreateContextFlags::NONE, caps,
757 : false, // Offscreen
758 0 : (Display*)DefaultXDisplay(), // Display
759 : (GLXDrawable)aSurface, (GLXContext)aContext,
760 : false, // aDeleteDrawable,
761 : true,
762 0 : (gfxXlibSurface*)nullptr);
763 :
764 0 : glContext->mOwnsContext = false;
765 0 : return glContext.forget();
766 : }
767 :
768 0 : return nullptr;
769 : }
770 :
771 : already_AddRefed<GLContext>
772 0 : CreateForWidget(Display* aXDisplay, Window aXWindow,
773 : bool aWebRender,
774 : bool aForceAccelerated)
775 : {
776 0 : if (!sGLXLibrary.EnsureInitialized()) {
777 0 : return nullptr;
778 : }
779 :
780 : // Currently, we take whatever Visual the window already has, and
781 : // try to create an fbconfig for that visual. This isn't
782 : // necessarily what we want in the long run; an fbconfig may not
783 : // be available for the existing visual, or if it is, the GL
784 : // performance might be suboptimal. But using the existing visual
785 : // is a relatively safe intermediate step.
786 :
787 0 : if (!aXDisplay) {
788 0 : NS_ERROR("X Display required for GLX Context provider");
789 0 : return nullptr;
790 : }
791 :
792 0 : int xscreen = DefaultScreen(aXDisplay);
793 :
794 0 : ScopedXFree<GLXFBConfig> cfgs;
795 : GLXFBConfig config;
796 : int visid;
797 0 : if (!GLContextGLX::FindFBConfigForWindow(aXDisplay, xscreen, aXWindow, &cfgs,
798 : &config, &visid, aWebRender))
799 : {
800 0 : return nullptr;
801 : }
802 :
803 : CreateContextFlags flags;
804 0 : if (aWebRender) {
805 0 : flags = CreateContextFlags::NONE; // WR needs GL3.2+
806 : } else {
807 0 : flags = CreateContextFlags::REQUIRE_COMPAT_PROFILE;
808 : }
809 0 : return GLContextGLX::CreateGLContext(flags, SurfaceCaps::Any(), false, aXDisplay,
810 0 : aXWindow, config, false, nullptr);
811 : }
812 :
813 : already_AddRefed<GLContext>
814 0 : GLContextProviderGLX::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
815 : {
816 0 : X11CompositorWidget* compWidget = aCompositorWidget->AsX11();
817 0 : MOZ_ASSERT(compWidget);
818 :
819 : return CreateForWidget(compWidget->XDisplay(),
820 : compWidget->XWindow(),
821 0 : compWidget->GetCompositorOptions().UseWebRender(),
822 0 : aForceAccelerated);
823 : }
824 :
825 : already_AddRefed<GLContext>
826 0 : GLContextProviderGLX::CreateForWindow(nsIWidget* aWidget,
827 : bool aWebRender,
828 : bool aForceAccelerated)
829 : {
830 0 : Display* display = (Display*)aWidget->GetNativeData(NS_NATIVE_COMPOSITOR_DISPLAY);
831 0 : Window window = GET_NATIVE_WINDOW(aWidget);
832 :
833 : return CreateForWidget(display,
834 : window,
835 : aWebRender,
836 0 : aForceAccelerated);
837 : }
838 :
839 : static bool
840 0 : ChooseConfig(GLXLibrary* glx, Display* display, int screen, const SurfaceCaps& minCaps,
841 : ScopedXFree<GLXFBConfig>* const out_scopedConfigArr,
842 : GLXFBConfig* const out_config, int* const out_visid)
843 : {
844 0 : ScopedXFree<GLXFBConfig>& scopedConfigArr = *out_scopedConfigArr;
845 :
846 0 : if (minCaps.antialias)
847 0 : return false;
848 :
849 : int attribs[] = {
850 : LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT,
851 : LOCAL_GLX_X_RENDERABLE, True,
852 : LOCAL_GLX_RED_SIZE, 8,
853 : LOCAL_GLX_GREEN_SIZE, 8,
854 : LOCAL_GLX_BLUE_SIZE, 8,
855 0 : LOCAL_GLX_ALPHA_SIZE, minCaps.alpha ? 8 : 0,
856 0 : LOCAL_GLX_DEPTH_SIZE, minCaps.depth ? 16 : 0,
857 0 : LOCAL_GLX_STENCIL_SIZE, minCaps.stencil ? 8 : 0,
858 : 0
859 0 : };
860 :
861 0 : int numConfigs = 0;
862 0 : scopedConfigArr = glx->fChooseFBConfig(display, screen, attribs, &numConfigs);
863 0 : if (!scopedConfigArr || !numConfigs)
864 0 : return false;
865 :
866 : // Issues with glxChooseFBConfig selection and sorting:
867 : // * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't request
868 : // alpha bits, we'll probably get RGBA anyways, since 32 is more than 24.
869 : // * DEPTH_SIZE is sorted largest first, including for `0` inputs.
870 : // * STENCIL_SIZE is smallest first, but it might return `8` even though we ask for
871 : // `0`.
872 :
873 : // For now, we don't care about these. We *will* care when we do XPixmap sharing.
874 :
875 0 : for (int i = 0; i < numConfigs; ++i) {
876 0 : GLXFBConfig curConfig = scopedConfigArr[i];
877 :
878 : int visid;
879 0 : if (glx->fGetFBConfigAttrib(display, curConfig, LOCAL_GLX_VISUAL_ID, &visid)
880 : != Success)
881 : {
882 0 : continue;
883 : }
884 :
885 0 : if (!visid)
886 0 : continue;
887 :
888 0 : *out_config = curConfig;
889 0 : *out_visid = visid;
890 0 : return true;
891 : }
892 :
893 0 : return false;
894 : }
895 :
896 : bool
897 0 : GLContextGLX::FindFBConfigForWindow(Display* display, int screen, Window window,
898 : ScopedXFree<GLXFBConfig>* const out_scopedConfigArr,
899 : GLXFBConfig* const out_config, int* const out_visid,
900 : bool aWebRender)
901 : {
902 0 : ScopedXFree<GLXFBConfig>& cfgs = *out_scopedConfigArr;
903 : int numConfigs;
904 : const int webrenderAttribs[] = {
905 : LOCAL_GLX_DEPTH_SIZE, 24,
906 : LOCAL_GLX_DOUBLEBUFFER, True,
907 : 0
908 0 : };
909 :
910 0 : if (aWebRender) {
911 : cfgs = sGLXLibrary.fChooseFBConfig(display,
912 : screen,
913 : webrenderAttribs,
914 0 : &numConfigs);
915 : } else {
916 : cfgs = sGLXLibrary.fGetFBConfigs(display,
917 : screen,
918 0 : &numConfigs);
919 : }
920 :
921 0 : if (!cfgs) {
922 0 : NS_WARNING("[GLX] glXGetFBConfigs() failed");
923 0 : return false;
924 : }
925 0 : NS_ASSERTION(numConfigs > 0, "No FBConfigs found!");
926 :
927 : // XXX the visual ID is almost certainly the LOCAL_GLX_FBCONFIG_ID, so
928 : // we could probably do this first and replace the glXGetFBConfigs
929 : // with glXChooseConfigs. Docs are sparklingly clear as always.
930 : XWindowAttributes windowAttrs;
931 0 : if (!XGetWindowAttributes(display, window, &windowAttrs)) {
932 0 : NS_WARNING("[GLX] XGetWindowAttributes() failed");
933 0 : return false;
934 : }
935 0 : const VisualID windowVisualID = XVisualIDFromVisual(windowAttrs.visual);
936 : #ifdef DEBUG
937 0 : printf("[GLX] window %lx has VisualID 0x%lx\n", window, windowVisualID);
938 : #endif
939 :
940 0 : if (aWebRender) {
941 0 : for (int i = 0; i < numConfigs; i++) {
942 0 : int visid = X11None;
943 0 : sGLXLibrary.fGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid);
944 0 : if (!visid) {
945 0 : continue;
946 : }
947 :
948 : int depth;
949 : Visual* visual;
950 0 : FindVisualAndDepth(display, visid, &visual, &depth);
951 0 : if (depth == windowAttrs.depth &&
952 0 : AreCompatibleVisuals(windowAttrs.visual, visual)) {
953 0 : *out_config = cfgs[i];
954 0 : *out_visid = visid;
955 0 : return true;
956 : }
957 : }
958 : } else {
959 0 : for (int i = 0; i < numConfigs; i++) {
960 0 : int visid = X11None;
961 0 : sGLXLibrary.fGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid);
962 0 : if (!visid) {
963 0 : continue;
964 : }
965 0 : if (sGLXLibrary.IsATI()) {
966 : int depth;
967 : Visual* visual;
968 0 : FindVisualAndDepth(display, visid, &visual, &depth);
969 0 : if (depth == windowAttrs.depth &&
970 0 : AreCompatibleVisuals(windowAttrs.visual, visual)) {
971 0 : *out_config = cfgs[i];
972 0 : *out_visid = visid;
973 0 : return true;
974 : }
975 : } else {
976 0 : if (windowVisualID == static_cast<VisualID>(visid)) {
977 0 : *out_config = cfgs[i];
978 0 : *out_visid = visid;
979 0 : return true;
980 : }
981 : }
982 : }
983 : }
984 :
985 0 : NS_WARNING("[GLX] Couldn't find a FBConfig matching window visual");
986 0 : return false;
987 : }
988 :
989 : static already_AddRefed<GLContextGLX>
990 0 : CreateOffscreenPixmapContext(CreateContextFlags flags, const IntSize& size,
991 : const SurfaceCaps& minCaps, nsACString* const out_failureId)
992 : {
993 0 : GLXLibrary* glx = &sGLXLibrary;
994 0 : if (!glx->EnsureInitialized())
995 0 : return nullptr;
996 :
997 0 : Display* display = DefaultXDisplay();
998 0 : int screen = DefaultScreen(display);
999 :
1000 0 : ScopedXFree<GLXFBConfig> scopedConfigArr;
1001 : GLXFBConfig config;
1002 : int visid;
1003 0 : if (!ChooseConfig(glx, display, screen, minCaps, &scopedConfigArr, &config, &visid)) {
1004 0 : NS_WARNING("Failed to find a compatible config.");
1005 0 : return nullptr;
1006 : }
1007 :
1008 : Visual* visual;
1009 : int depth;
1010 0 : FindVisualAndDepth(display, visid, &visual, &depth);
1011 :
1012 0 : OffMainThreadScopedXErrorHandler xErrorHandler;
1013 0 : bool error = false;
1014 :
1015 0 : gfx::IntSize dummySize(16, 16);
1016 0 : RefPtr<gfxXlibSurface> surface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display),
1017 : visual,
1018 0 : dummySize);
1019 0 : if (surface->CairoStatus() != 0) {
1020 0 : mozilla::Unused << xErrorHandler.SyncAndGetError(display);
1021 0 : return nullptr;
1022 : }
1023 :
1024 : // Handle slightly different signature between glXCreatePixmap and
1025 : // its pre-GLX-1.3 extension equivalent (though given the ABI, we
1026 : // might not need to).
1027 0 : const auto drawable = surface->XDrawable();
1028 0 : const auto pixmap = glx->fCreatePixmap(display, config, drawable, nullptr);
1029 0 : if (pixmap == 0) {
1030 0 : error = true;
1031 : }
1032 :
1033 0 : bool serverError = xErrorHandler.SyncAndGetError(display);
1034 0 : if (error || serverError)
1035 0 : return nullptr;
1036 :
1037 : return GLContextGLX::CreateGLContext(flags, minCaps, true, display, pixmap, config,
1038 0 : true, surface);
1039 : }
1040 :
1041 : /*static*/ already_AddRefed<GLContext>
1042 0 : GLContextProviderGLX::CreateHeadless(CreateContextFlags flags,
1043 : nsACString* const out_failureId)
1044 : {
1045 0 : IntSize dummySize = IntSize(16, 16);
1046 0 : SurfaceCaps dummyCaps = SurfaceCaps::Any();
1047 0 : return CreateOffscreenPixmapContext(flags, dummySize, dummyCaps, out_failureId);
1048 : }
1049 :
1050 : /*static*/ already_AddRefed<GLContext>
1051 0 : GLContextProviderGLX::CreateOffscreen(const IntSize& size,
1052 : const SurfaceCaps& minCaps,
1053 : CreateContextFlags flags,
1054 : nsACString* const out_failureId)
1055 : {
1056 0 : SurfaceCaps minBackbufferCaps = minCaps;
1057 0 : if (minCaps.antialias) {
1058 0 : minBackbufferCaps.antialias = false;
1059 0 : minBackbufferCaps.depth = false;
1060 0 : minBackbufferCaps.stencil = false;
1061 : }
1062 :
1063 0 : RefPtr<GLContext> gl;
1064 0 : gl = CreateOffscreenPixmapContext(flags, size, minBackbufferCaps, out_failureId);
1065 0 : if (!gl)
1066 0 : return nullptr;
1067 :
1068 0 : if (!gl->InitOffscreen(size, minCaps)) {
1069 0 : *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_GLX_INIT");
1070 0 : return nullptr;
1071 : }
1072 :
1073 0 : return gl.forget();
1074 : }
1075 :
1076 : /*static*/ GLContext*
1077 0 : GLContextProviderGLX::GetGlobalContext()
1078 : {
1079 : // Context sharing not supported.
1080 0 : return nullptr;
1081 : }
1082 :
1083 : /*static*/ void
1084 0 : GLContextProviderGLX::Shutdown()
1085 : {
1086 0 : }
1087 :
1088 : } /* namespace gl */
1089 9 : } /* namespace mozilla */
1090 :
|