File: | var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp |
Warning: | line 345, column 29 Called C++ object pointer is uninitialized |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |||
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_GTK1 | |||
7 | # include <gdk/gdk.h> | |||
8 | # include <gdk/gdkx.h> | |||
9 | # define GET_NATIVE_WINDOW(aWidget)(gdk_x11_window_get_xid ((GdkWindow*)aWidget->GetNativeData (0))) \ | |||
10 | GDK_WINDOW_XID((GdkWindow*)aWidget->GetNativeData(NS_NATIVE_WINDOW))(gdk_x11_window_get_xid ((GdkWindow*)aWidget->GetNativeData (0))) | |||
11 | #endif | |||
12 | ||||
13 | #include <X11/Xlib.h> | |||
14 | #include <X11/Xutil.h> | |||
15 | #include "X11UndefineNone.h" | |||
16 | ||||
17 | #include "mozilla/MathAlgorithms.h" | |||
18 | #include "mozilla/StaticPtr.h" | |||
19 | #include "mozilla/layers/CompositorOptions.h" | |||
20 | #include "mozilla/Range.h" | |||
21 | #include "mozilla/ScopeExit.h" | |||
22 | #include "mozilla/Sprintf.h" | |||
23 | #include "mozilla/StaticPrefs_gfx.h" | |||
24 | #include "mozilla/StaticPrefs_layout.h" | |||
25 | #include "mozilla/widget/CompositorWidget.h" | |||
26 | #include "mozilla/widget/GtkCompositorWidget.h" | |||
27 | #include "mozilla/Unused.h" | |||
28 | ||||
29 | #include "prenv.h" | |||
30 | #include "GLContextProvider.h" | |||
31 | #include "GLLibraryLoader.h" | |||
32 | #include "nsDebug.h" | |||
33 | #include "nsIWidget.h" | |||
34 | #include "GLXLibrary.h" | |||
35 | #include "gfxContext.h" | |||
36 | #include "gfxEnv.h" | |||
37 | #include "gfxPlatform.h" | |||
38 | #include "GLContextGLX.h" | |||
39 | #include "gfxUtils.h" | |||
40 | #include "gfx2DGlue.h" | |||
41 | #include "GLScreenBuffer.h" | |||
42 | ||||
43 | #include "gfxCrashReporterUtils.h" | |||
44 | ||||
45 | #ifdef MOZ_WIDGET_GTK1 | |||
46 | # include "gfxPlatformGtk.h" | |||
47 | #endif | |||
48 | ||||
49 | namespace mozilla::gl { | |||
50 | ||||
51 | using namespace mozilla::gfx; | |||
52 | using namespace mozilla::widget; | |||
53 | ||||
54 | GLXLibrary sGLXLibrary; | |||
55 | ||||
56 | static inline bool HasExtension(const char* aExtensions, | |||
57 | const char* aRequiredExtension) { | |||
58 | return GLContext::ListHasExtension( | |||
59 | reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension); | |||
60 | } | |||
61 | ||||
62 | bool GLXLibrary::EnsureInitialized(Display* aDisplay) { | |||
63 | if (mInitialized) { | |||
64 | return true; | |||
65 | } | |||
66 | ||||
67 | // Don't repeatedly try to initialize. | |||
68 | if (mTriedInitializing) { | |||
69 | return false; | |||
70 | } | |||
71 | mTriedInitializing = true; | |||
72 | ||||
73 | MOZ_ASSERT(aDisplay)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDisplay)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDisplay))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDisplay", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 73); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDisplay" ")" ); do { *((volatile int*)__null) = 73; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
74 | if (!aDisplay) { | |||
75 | return false; | |||
76 | } | |||
77 | ||||
78 | // Force enabling s3 texture compression. (Bug 774134) | |||
79 | PR_SetEnv("force_s3tc_enable=true"); | |||
80 | ||||
81 | if (!mOGLLibrary) { | |||
82 | // see e.g. bug 608526: it is intrinsically interesting to know whether we | |||
83 | // have dynamically linked to libGL.so.1 because at least the NVIDIA | |||
84 | // implementation requires an executable stack, which causes mprotect calls, | |||
85 | // which trigger glibc bug | |||
86 | // http://sourceware.org/bugzilla/show_bug.cgi?id=12225 | |||
87 | const char* libGLfilename = "libGL.so.1"; | |||
88 | #if defined(__OpenBSD__) || defined(__NetBSD__) | |||
89 | libGLfilename = "libGL.so"; | |||
90 | #endif | |||
91 | ||||
92 | const bool forceFeatureReport = false; | |||
93 | ScopedGfxFeatureReporter reporter(libGLfilename, forceFeatureReport); | |||
94 | mOGLLibrary = PR_LoadLibrary(libGLfilename); | |||
95 | if (!mOGLLibrary) { | |||
96 | NS_WARNING("Couldn't load OpenGL shared library.")NS_DebugBreak(NS_DEBUG_WARNING, "Couldn't load OpenGL shared library." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 96); | |||
97 | return false; | |||
98 | } | |||
99 | reporter.SetSuccessful(); | |||
100 | } | |||
101 | ||||
102 | if (gfxEnv::MOZ_GLX_DEBUG()) { | |||
103 | mDebug = true; | |||
104 | } | |||
105 | ||||
106 | #define SYMBOL(X){ (PRFuncPtr*)&mSymbols.fX, { { "glX" "X" } } } \ | |||
107 | { \ | |||
108 | (PRFuncPtr*)&mSymbols.f##X, { \ | |||
109 | { "glX" #X } \ | |||
110 | } \ | |||
111 | } | |||
112 | #define END_OF_SYMBOLS{ nullptr, {} } \ | |||
113 | { \ | |||
114 | nullptr, {} \ | |||
115 | } | |||
116 | ||||
117 | const SymLoadStruct symbols[] = { | |||
118 | /* functions that were in GLX 1.0 */ | |||
119 | SYMBOL(DestroyContext){ (PRFuncPtr*)&mSymbols.fDestroyContext, { { "glX" "DestroyContext" } } }, | |||
120 | SYMBOL(MakeCurrent){ (PRFuncPtr*)&mSymbols.fMakeCurrent, { { "glX" "MakeCurrent" } } }, | |||
121 | SYMBOL(SwapBuffers){ (PRFuncPtr*)&mSymbols.fSwapBuffers, { { "glX" "SwapBuffers" } } }, | |||
122 | SYMBOL(QueryVersion){ (PRFuncPtr*)&mSymbols.fQueryVersion, { { "glX" "QueryVersion" } } }, | |||
123 | SYMBOL(GetConfig){ (PRFuncPtr*)&mSymbols.fGetConfig, { { "glX" "GetConfig" } } }, | |||
124 | SYMBOL(GetCurrentContext){ (PRFuncPtr*)&mSymbols.fGetCurrentContext, { { "glX" "GetCurrentContext" } } }, | |||
125 | SYMBOL(WaitGL){ (PRFuncPtr*)&mSymbols.fWaitGL, { { "glX" "WaitGL" } } }, | |||
126 | SYMBOL(WaitX){ (PRFuncPtr*)&mSymbols.fWaitX, { { "glX" "WaitX" } } }, | |||
127 | ||||
128 | /* functions introduced in GLX 1.1 */ | |||
129 | SYMBOL(QueryExtensionsString){ (PRFuncPtr*)&mSymbols.fQueryExtensionsString, { { "glX" "QueryExtensionsString" } } }, | |||
130 | SYMBOL(GetClientString){ (PRFuncPtr*)&mSymbols.fGetClientString, { { "glX" "GetClientString" } } }, | |||
131 | SYMBOL(QueryServerString){ (PRFuncPtr*)&mSymbols.fQueryServerString, { { "glX" "QueryServerString" } } }, | |||
132 | ||||
133 | /* functions introduced in GLX 1.3 */ | |||
134 | SYMBOL(ChooseFBConfig){ (PRFuncPtr*)&mSymbols.fChooseFBConfig, { { "glX" "ChooseFBConfig" } } }, | |||
135 | SYMBOL(ChooseVisual){ (PRFuncPtr*)&mSymbols.fChooseVisual, { { "glX" "ChooseVisual" } } }, | |||
136 | SYMBOL(GetFBConfigAttrib){ (PRFuncPtr*)&mSymbols.fGetFBConfigAttrib, { { "glX" "GetFBConfigAttrib" } } }, | |||
137 | SYMBOL(GetFBConfigs){ (PRFuncPtr*)&mSymbols.fGetFBConfigs, { { "glX" "GetFBConfigs" } } }, | |||
138 | SYMBOL(CreatePixmap){ (PRFuncPtr*)&mSymbols.fCreatePixmap, { { "glX" "CreatePixmap" } } }, | |||
139 | SYMBOL(DestroyPixmap){ (PRFuncPtr*)&mSymbols.fDestroyPixmap, { { "glX" "DestroyPixmap" } } }, | |||
140 | SYMBOL(CreateNewContext){ (PRFuncPtr*)&mSymbols.fCreateNewContext, { { "glX" "CreateNewContext" } } }, | |||
141 | ||||
142 | // Core in GLX 1.4, ARB extension before. | |||
143 | {(PRFuncPtr*)&mSymbols.fGetProcAddress, | |||
144 | {{"glXGetProcAddress", "glXGetProcAddressARB"}}}, | |||
145 | END_OF_SYMBOLS{ nullptr, {} }}; | |||
146 | ||||
147 | { | |||
148 | const SymbolLoader libLoader(*mOGLLibrary); | |||
149 | if (!libLoader.LoadSymbols(symbols)) { | |||
150 | NS_WARNING("Couldn't load required GLX symbols.")NS_DebugBreak(NS_DEBUG_WARNING, "Couldn't load required GLX symbols." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 150); | |||
151 | return false; | |||
152 | } | |||
153 | } | |||
154 | const SymbolLoader pfnLoader(mSymbols.fGetProcAddress); | |||
155 | ||||
156 | int screen = DefaultScreen(aDisplay)(((_XPrivDisplay)(aDisplay))->default_screen); | |||
157 | ||||
158 | { | |||
159 | int major, minor; | |||
160 | if (!fQueryVersion(aDisplay, &major, &minor) || major != 1 || minor < 3) { | |||
161 | NS_ERROR("GLX version older than 1.3. (released in 1998)")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "GLX version older than 1.3. (released in 1998)" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 161); MOZ_PretendNoReturn(); } while (0); | |||
162 | return false; | |||
163 | } | |||
164 | } | |||
165 | ||||
166 | const SymLoadStruct symbols_createcontext[] = { | |||
167 | SYMBOL(CreateContextAttribsARB){ (PRFuncPtr*)&mSymbols.fCreateContextAttribsARB, { { "glX" "CreateContextAttribsARB" } } }, END_OF_SYMBOLS{ nullptr, {} }}; | |||
168 | ||||
169 | const SymLoadStruct symbols_videosync[] = { | |||
170 | SYMBOL(GetVideoSyncSGI){ (PRFuncPtr*)&mSymbols.fGetVideoSyncSGI, { { "glX" "GetVideoSyncSGI" } } }, SYMBOL(WaitVideoSyncSGI){ (PRFuncPtr*)&mSymbols.fWaitVideoSyncSGI, { { "glX" "WaitVideoSyncSGI" } } }, END_OF_SYMBOLS{ nullptr, {} }}; | |||
171 | ||||
172 | const SymLoadStruct symbols_swapcontrol[] = {SYMBOL(SwapIntervalEXT){ (PRFuncPtr*)&mSymbols.fSwapIntervalEXT, { { "glX" "SwapIntervalEXT" } } }, | |||
173 | END_OF_SYMBOLS{ nullptr, {} }}; | |||
174 | ||||
175 | const SymLoadStruct symbols_querydrawable[] = {SYMBOL(QueryDrawable){ (PRFuncPtr*)&mSymbols.fQueryDrawable, { { "glX" "QueryDrawable" } } }, | |||
176 | END_OF_SYMBOLS{ nullptr, {} }}; | |||
177 | ||||
178 | const auto fnLoadSymbols = [&](const SymLoadStruct* symbols) { | |||
179 | if (pfnLoader.LoadSymbols(symbols)) return true; | |||
180 | ||||
181 | ClearSymbols(symbols); | |||
182 | return false; | |||
183 | }; | |||
184 | ||||
185 | const char* clientVendor = fGetClientString(aDisplay, LOCAL_GLX_VENDOR0x1); | |||
186 | const char* serverVendor = | |||
187 | fQueryServerString(aDisplay, screen, LOCAL_GLX_VENDOR0x1); | |||
188 | const char* extensionsStr = fQueryExtensionsString(aDisplay, screen); | |||
189 | ||||
190 | if (HasExtension(extensionsStr, "GLX_ARB_create_context") && | |||
191 | HasExtension(extensionsStr, "GLX_ARB_create_context_profile") && | |||
192 | fnLoadSymbols(symbols_createcontext)) { | |||
193 | mHasCreateContextAttribs = true; | |||
194 | } | |||
195 | ||||
196 | if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness")) { | |||
197 | mHasRobustness = true; | |||
198 | } | |||
199 | ||||
200 | if (HasExtension(extensionsStr, "GLX_NV_robustness_video_memory_purge")) { | |||
201 | mHasVideoMemoryPurge = true; | |||
202 | } | |||
203 | ||||
204 | if (HasExtension(extensionsStr, "GLX_SGI_video_sync") && | |||
205 | fnLoadSymbols(symbols_videosync)) { | |||
206 | mHasVideoSync = true; | |||
207 | } | |||
208 | ||||
209 | if (!HasExtension(extensionsStr, "GLX_EXT_swap_control") || | |||
210 | !fnLoadSymbols(symbols_swapcontrol)) { | |||
211 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "GLX_swap_control unsupported, ASAP mode may still block on buffer " "swaps.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 213) | |||
212 | "GLX_swap_control unsupported, ASAP mode may still block on buffer "NS_DebugBreak(NS_DEBUG_WARNING, "GLX_swap_control unsupported, ASAP mode may still block on buffer " "swaps.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 213) | |||
213 | "swaps.")NS_DebugBreak(NS_DEBUG_WARNING, "GLX_swap_control unsupported, ASAP mode may still block on buffer " "swaps.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 213); | |||
214 | } | |||
215 | ||||
216 | if (HasExtension(extensionsStr, "GLX_EXT_buffer_age") && | |||
217 | fnLoadSymbols(symbols_querydrawable)) { | |||
218 | mHasBufferAge = true; | |||
219 | } | |||
220 | ||||
221 | mIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI"); | |||
222 | mIsNVIDIA = | |||
223 | serverVendor && DoesStringMatch(serverVendor, "NVIDIA Corporation"); | |||
224 | mClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa"); | |||
225 | ||||
226 | mInitialized = true; | |||
227 | ||||
228 | // This needs to be after `fQueryServerString` is called so that the | |||
229 | // driver is loaded. | |||
230 | MesaMemoryLeakWorkaround(); | |||
231 | ||||
232 | return true; | |||
233 | } | |||
234 | ||||
235 | bool GLXLibrary::SupportsVideoSync(Display* aDisplay) { | |||
236 | if (!EnsureInitialized(aDisplay)) { | |||
237 | return false; | |||
238 | } | |||
239 | ||||
240 | return mHasVideoSync; | |||
241 | } | |||
242 | ||||
243 | static int (*sOldErrorHandler)(Display*, XErrorEvent*); | |||
244 | static XErrorEvent sErrorEvent = {}; | |||
245 | ||||
246 | static int GLXErrorHandler(Display* display, XErrorEvent* ev) { | |||
247 | if (!sErrorEvent.error_code) { | |||
248 | sErrorEvent = *ev; | |||
249 | } | |||
250 | return 0; | |||
251 | } | |||
252 | ||||
253 | GLXLibrary::WrapperScope::WrapperScope(const GLXLibrary& glx, | |||
254 | const char* const funcName, | |||
255 | Display* aDisplay) | |||
256 | : mGlx(glx), mFuncName(funcName), mDisplay(aDisplay) { | |||
257 | if (mGlx.mDebug) { | |||
258 | sOldErrorHandler = XSetErrorHandler(GLXErrorHandler); | |||
259 | } | |||
260 | } | |||
261 | ||||
262 | GLXLibrary::WrapperScope::~WrapperScope() { | |||
263 | if (mGlx.mDebug) { | |||
264 | if (mDisplay) { | |||
265 | FinishX(mDisplay); | |||
266 | } | |||
267 | if (sErrorEvent.error_code) { | |||
268 | char buffer[100] = {}; | |||
269 | if (mDisplay) { | |||
270 | XGetErrorText(mDisplay, sErrorEvent.error_code, buffer, sizeof(buffer)); | |||
271 | } else { | |||
272 | SprintfLiteral(buffer, "%d", sErrorEvent.error_code); | |||
273 | } | |||
274 | printf_stderr("X ERROR after %s: %s (%i) - Request: %i.%i, Serial: %lu", | |||
275 | mFuncName, buffer, sErrorEvent.error_code, | |||
276 | sErrorEvent.request_code, sErrorEvent.minor_code, | |||
277 | sErrorEvent.serial); | |||
278 | MOZ_ASSERT_UNREACHABLE("AfterGLXCall sErrorEvent")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "AfterGLXCall sErrorEvent" ")", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 278); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "AfterGLXCall sErrorEvent" ")"); do { *((volatile int*)__null) = 278; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); | |||
279 | } | |||
280 | const auto was = XSetErrorHandler(sOldErrorHandler); | |||
281 | if (was != GLXErrorHandler) { | |||
282 | NS_WARNING("Concurrent XSetErrorHandlers")NS_DebugBreak(NS_DEBUG_WARNING, "Concurrent XSetErrorHandlers" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 282); | |||
283 | } | |||
284 | } | |||
285 | } | |||
286 | ||||
287 | // Returns the GTK display if available; otherwise, if a display was | |||
288 | // previously opened by this method and is still open, returns a | |||
289 | // reference to it; otherwise, opens a new connection. (The non-GTK | |||
290 | // cases are similar to what we do for EGL.) | |||
291 | std::shared_ptr<XlibDisplay> GLXLibrary::GetDisplay() { | |||
292 | std::shared_ptr<XlibDisplay> display; | |||
293 | ||||
294 | #ifdef MOZ_WIDGET_GTK1 | |||
295 | static const bool kHaveGtk = !!gdk_display_get_default(); | |||
296 | if (kHaveGtk) { | |||
297 | display = XlibDisplay::Borrow(DefaultXDisplay()); | |||
298 | } | |||
299 | #endif | |||
300 | if (display) { | |||
301 | return display; | |||
302 | } | |||
303 | ||||
304 | auto ownDisplay = mOwnDisplay.Lock(); | |||
305 | display = ownDisplay->lock(); | |||
306 | if (display) { | |||
307 | return display; | |||
308 | } | |||
309 | ||||
310 | display = XlibDisplay::Open(nullptr); | |||
311 | if (NS_WARN_IF(!display)NS_warn_if_impl(!display, "!display", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 311)) { | |||
312 | return nullptr; | |||
313 | } | |||
314 | *ownDisplay = display; | |||
315 | return display; | |||
316 | } | |||
317 | ||||
318 | already_AddRefed<GLContextGLX> GLContextGLX::CreateGLContext( | |||
319 | const GLContextDesc& desc, std::shared_ptr<XlibDisplay> display, | |||
320 | GLXDrawable drawable, GLXFBConfig cfg, Drawable ownedPixmap) { | |||
321 | GLXLibrary& glx = sGLXLibrary; | |||
322 | ||||
323 | int isDoubleBuffered = 0; | |||
324 | int err = glx.fGetFBConfigAttrib(*display, cfg, LOCAL_GLX_DOUBLEBUFFER5, | |||
325 | &isDoubleBuffered); | |||
326 | if (LOCAL_GLX_BAD_ATTRIBUTE2 != err) { | |||
327 | if (ShouldSpew()) { | |||
328 | printf("[GLX] FBConfig is %sdouble-buffered\n", | |||
329 | isDoubleBuffered ? "" : "not "); | |||
330 | } | |||
331 | } | |||
332 | ||||
333 | if (!glx.HasCreateContextAttribs()) { | |||
334 | NS_WARNING("Cannot create GLContextGLX without glxCreateContextAttribs")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot create GLContextGLX without glxCreateContextAttribs" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 334); | |||
335 | return nullptr; | |||
336 | } | |||
337 | ||||
338 | // - | |||
339 | ||||
340 | const auto CreateWithAttribs = | |||
341 | [&](const std::vector<int>& attribs) -> RefPtr<GLContextGLX> { | |||
342 | auto terminated = attribs; | |||
343 | terminated.push_back(0); | |||
344 | ||||
345 | const auto glxContext = glx.fCreateContextAttribs( | |||
| ||||
346 | *display, cfg, nullptr, X11True1, terminated.data()); | |||
347 | if (!glxContext) return nullptr; | |||
348 | const RefPtr<GLContextGLX> ret = new GLContextGLX( | |||
349 | desc, display, drawable, glxContext, isDoubleBuffered, ownedPixmap); | |||
350 | ||||
351 | if (!ret->Init()) return nullptr; | |||
352 | ||||
353 | return ret; | |||
354 | }; | |||
355 | ||||
356 | // - | |||
357 | ||||
358 | RefPtr<GLContextGLX> glContext; | |||
359 | ||||
360 | std::vector<int> attribs; | |||
361 | attribs.insert(attribs.end(), { | |||
362 | LOCAL_GLX_RENDER_TYPE0x8011, | |||
363 | LOCAL_GLX_RGBA_TYPE0x8014, | |||
364 | }); | |||
365 | if (glx.HasVideoMemoryPurge()) { | |||
366 | attribs.insert(attribs.end(), | |||
367 | { | |||
368 | LOCAL_GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV0x20F7, | |||
369 | LOCAL_GL_TRUE1, | |||
370 | }); | |||
371 | } | |||
372 | const bool useCore = | |||
373 | !(desc.flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE); | |||
374 | if (useCore
| |||
375 | attribs.insert(attribs.end(), { | |||
376 | LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB0x2091, | |||
377 | 3, | |||
378 | LOCAL_GLX_CONTEXT_MINOR_VERSION_ARB0x2092, | |||
379 | 2, | |||
380 | LOCAL_GLX_CONTEXT_PROFILE_MASK_ARB0x9126, | |||
381 | LOCAL_GLX_CONTEXT_CORE_PROFILE_BIT_ARB0x00000001, | |||
382 | }); | |||
383 | } | |||
384 | ||||
385 | if (glx.HasRobustness()) { | |||
386 | auto withRobustness = attribs; | |||
387 | withRobustness.insert(withRobustness.end(), | |||
388 | { | |||
389 | LOCAL_GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB0x8256, | |||
390 | LOCAL_GLX_LOSE_CONTEXT_ON_RESET_ARB0x8252, | |||
391 | }); | |||
392 | ||||
393 | { | |||
394 | auto withRBAB = withRobustness; | |||
395 | withRBAB.insert(withRBAB.end(), | |||
396 | { | |||
397 | LOCAL_GLX_CONTEXT_FLAGS_ARB0x2094, | |||
398 | LOCAL_GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB0x00000004, | |||
399 | }); | |||
400 | if (!glContext) { | |||
401 | glContext = CreateWithAttribs(withRBAB); | |||
402 | if (!glContext) { | |||
403 | NS_WARNING("Failed to create+init GLContextGLX with RBAB")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to create+init GLContextGLX with RBAB" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 403); | |||
404 | } | |||
405 | } | |||
406 | } | |||
407 | ||||
408 | if (!glContext) { | |||
409 | glContext = CreateWithAttribs(withRobustness); | |||
410 | if (!glContext) { | |||
411 | NS_WARNING("Failed to create+init GLContextGLX with Robustness")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to create+init GLContextGLX with Robustness" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 411); | |||
412 | } | |||
413 | } | |||
414 | } | |||
415 | ||||
416 | if (!glContext) { | |||
417 | glContext = CreateWithAttribs(attribs); | |||
418 | if (!glContext) { | |||
419 | NS_WARNING("Failed to create+init GLContextGLX with required attribs")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to create+init GLContextGLX with required attribs" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 419); | |||
420 | } | |||
421 | } | |||
422 | ||||
423 | return glContext.forget(); | |||
424 | } | |||
425 | ||||
426 | GLContextGLX::~GLContextGLX() { | |||
427 | MarkDestroyed(); | |||
428 | ||||
429 | // Wrapped context should not destroy glxContext/Surface | |||
430 | if (!mOwnsContext) { | |||
431 | return; | |||
432 | } | |||
433 | ||||
434 | // see bug 659842 comment 76 | |||
435 | bool success = mGLX->fMakeCurrent(*mDisplay, X11None0L, nullptr); | |||
436 | if (!success) { | |||
437 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "glXMakeCurrent failed to release GL context before we call " "glXDestroyContext!", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 439) | |||
438 | "glXMakeCurrent failed to release GL context before we call "NS_DebugBreak(NS_DEBUG_WARNING, "glXMakeCurrent failed to release GL context before we call " "glXDestroyContext!", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 439) | |||
439 | "glXDestroyContext!")NS_DebugBreak(NS_DEBUG_WARNING, "glXMakeCurrent failed to release GL context before we call " "glXDestroyContext!", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 439); | |||
440 | } | |||
441 | ||||
442 | mGLX->fDestroyContext(*mDisplay, mContext); | |||
443 | ||||
444 | // If we own the enclosed X pixmap, then free it after we free the enclosing | |||
445 | // GLX pixmap. | |||
446 | if (mOwnedPixmap) { | |||
447 | mGLX->fDestroyPixmap(*mDisplay, mDrawable); | |||
448 | XFreePixmap(*mDisplay, mOwnedPixmap); | |||
449 | } | |||
450 | } | |||
451 | ||||
452 | bool GLContextGLX::Init() { | |||
453 | if (!GLContext::Init()) { | |||
454 | return false; | |||
455 | } | |||
456 | ||||
457 | // EXT_framebuffer_object is not supported on Core contexts | |||
458 | // so we'll also check for ARB_framebuffer_object | |||
459 | if (!IsExtensionSupported(EXT_framebuffer_object) && | |||
460 | !IsSupported(GLFeature::framebuffer_object)) | |||
461 | return false; | |||
462 | ||||
463 | return true; | |||
464 | } | |||
465 | ||||
466 | bool GLContextGLX::MakeCurrentImpl() const { | |||
467 | if (mGLX->IsMesa()) { | |||
468 | // Read into the event queue to ensure that Mesa receives a | |||
469 | // DRI2InvalidateBuffers event before drawing. See bug 1280653. | |||
470 | Unused << XPending(*mDisplay); | |||
471 | } | |||
472 | ||||
473 | const bool succeeded = mGLX->fMakeCurrent(*mDisplay, mDrawable, mContext); | |||
474 | if (!succeeded) { | |||
475 | NS_WARNING("Failed to make GL context current!")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to make GL context current!" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 475); | |||
476 | } | |||
477 | ||||
478 | if (!IsOffscreen() && mGLX->SupportsSwapControl()) { | |||
479 | // Many GLX implementations default to blocking until the next | |||
480 | // VBlank when calling glXSwapBuffers. We want to run unthrottled | |||
481 | // in ASAP mode. See bug 1280744. | |||
482 | const bool swapInterval = gfxVars::SwapIntervalGLX(); | |||
483 | const bool isASAP = (StaticPrefs::layout_frame_rate() == 0); | |||
484 | const int interval = (swapInterval && !isASAP) ? 1 : 0; | |||
485 | mGLX->fSwapInterval(*mDisplay, mDrawable, interval); | |||
486 | } | |||
487 | return succeeded; | |||
488 | } | |||
489 | ||||
490 | bool GLContextGLX::IsCurrentImpl() const { | |||
491 | return mGLX->fGetCurrentContext() == mContext; | |||
492 | } | |||
493 | ||||
494 | Maybe<SymbolLoader> GLContextGLX::GetSymbolLoader() const { | |||
495 | const auto pfn = sGLXLibrary.GetGetProcAddress(); | |||
496 | return Some(SymbolLoader(pfn)); | |||
497 | } | |||
498 | ||||
499 | bool GLContextGLX::IsDoubleBuffered() const { return mDoubleBuffered; } | |||
500 | ||||
501 | bool GLContextGLX::SwapBuffers() { | |||
502 | if (!mDoubleBuffered) return false; | |||
503 | mGLX->fSwapBuffers(*mDisplay, mDrawable); | |||
504 | return true; | |||
505 | } | |||
506 | ||||
507 | GLint GLContextGLX::GetBufferAge() const { | |||
508 | if (!sGLXLibrary.SupportsBufferAge()) { | |||
509 | return 0; | |||
510 | } | |||
511 | ||||
512 | GLuint result = 0; | |||
513 | mGLX->fQueryDrawable(*mDisplay, mDrawable, LOCAL_GLX_BACK_BUFFER_AGE_EXT0x20F4, | |||
514 | &result); | |||
515 | if (result > INT32_MAX(2147483647)) { | |||
516 | // If the result can't fit, just assume the buffer cannot be reused. | |||
517 | return 0; | |||
518 | } | |||
519 | return result; | |||
520 | } | |||
521 | ||||
522 | void GLContextGLX::GetWSIInfo(nsCString* const out) const { | |||
523 | int screen = DefaultScreen(mDisplay->get())(((_XPrivDisplay)(mDisplay->get()))->default_screen); | |||
524 | ||||
525 | int majorVersion, minorVersion; | |||
526 | sGLXLibrary.fQueryVersion(*mDisplay, &majorVersion, &minorVersion); | |||
527 | ||||
528 | out->Append(nsPrintfCString("GLX %u.%u", majorVersion, minorVersion)); | |||
529 | ||||
530 | out->AppendLiteral("\nGLX_VENDOR(client): "); | |||
531 | out->Append(sGLXLibrary.fGetClientString(*mDisplay, LOCAL_GLX_VENDOR0x1)); | |||
532 | ||||
533 | out->AppendLiteral("\nGLX_VENDOR(server): "); | |||
534 | out->Append( | |||
535 | sGLXLibrary.fQueryServerString(*mDisplay, screen, LOCAL_GLX_VENDOR0x1)); | |||
536 | ||||
537 | out->AppendLiteral("\nExtensions: "); | |||
538 | out->Append(sGLXLibrary.fQueryExtensionsString(*mDisplay, screen)); | |||
539 | } | |||
540 | ||||
541 | bool GLContextGLX::OverrideDrawable(GLXDrawable drawable) { | |||
542 | return mGLX->fMakeCurrent(*mDisplay, drawable, mContext); | |||
543 | } | |||
544 | ||||
545 | bool GLContextGLX::RestoreDrawable() { | |||
546 | return mGLX->fMakeCurrent(*mDisplay, mDrawable, mContext); | |||
547 | } | |||
548 | ||||
549 | GLContextGLX::GLContextGLX(const GLContextDesc& desc, | |||
550 | std::shared_ptr<XlibDisplay> aDisplay, | |||
551 | GLXDrawable aDrawable, GLXContext aContext, | |||
552 | bool aDoubleBuffered, Drawable aOwnedPixmap) | |||
553 | : GLContext(desc, nullptr), | |||
554 | mContext(aContext), | |||
555 | mDisplay(aDisplay), | |||
556 | mDrawable(aDrawable), | |||
557 | mOwnedPixmap(aOwnedPixmap), | |||
558 | mDoubleBuffered(aDoubleBuffered), | |||
559 | mGLX(&sGLXLibrary) {} | |||
560 | ||||
561 | static bool AreCompatibleVisuals(Visual* one, Visual* two) { | |||
562 | if (one->c_class != two->c_class) { | |||
563 | return false; | |||
564 | } | |||
565 | ||||
566 | if (one->red_mask != two->red_mask || one->green_mask != two->green_mask || | |||
567 | one->blue_mask != two->blue_mask) { | |||
568 | return false; | |||
569 | } | |||
570 | ||||
571 | if (one->bits_per_rgb != two->bits_per_rgb) { | |||
572 | return false; | |||
573 | } | |||
574 | ||||
575 | return true; | |||
576 | } | |||
577 | ||||
578 | already_AddRefed<GLContext> CreateForWidget(Display* aXDisplay, Window aXWindow, | |||
579 | bool aHardwareWebRender, | |||
580 | bool aForceAccelerated) { | |||
581 | if (!sGLXLibrary.EnsureInitialized(aXDisplay)) { | |||
582 | return nullptr; | |||
583 | } | |||
584 | ||||
585 | // Currently, we take whatever Visual the window already has, and | |||
586 | // try to create an fbconfig for that visual. This isn't | |||
587 | // necessarily what we want in the long run; an fbconfig may not | |||
588 | // be available for the existing visual, or if it is, the GL | |||
589 | // performance might be suboptimal. But using the existing visual | |||
590 | // is a relatively safe intermediate step. | |||
591 | ||||
592 | if (!aXDisplay) { | |||
593 | NS_ERROR("X Display required for GLX Context provider")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "X Display required for GLX Context provider" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 593); MOZ_PretendNoReturn(); } while (0); | |||
594 | return nullptr; | |||
595 | } | |||
596 | ||||
597 | if (!aXWindow) { | |||
598 | NS_ERROR("X window required for GLX Context provider")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "X window required for GLX Context provider" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 598); MOZ_PretendNoReturn(); } while (0); | |||
599 | return nullptr; | |||
600 | } | |||
601 | ||||
602 | int xscreen = DefaultScreen(aXDisplay)(((_XPrivDisplay)(aXDisplay))->default_screen); | |||
603 | ||||
604 | GLXFBConfig config; | |||
605 | int visid; | |||
606 | if (!GLContextGLX::FindFBConfigForWindow( | |||
607 | aXDisplay, xscreen, aXWindow, &config, &visid, aHardwareWebRender)) { | |||
608 | return nullptr; | |||
609 | } | |||
610 | ||||
611 | CreateContextFlags flags; | |||
612 | if (aHardwareWebRender) { | |||
613 | flags = CreateContextFlags::NONE; // WR needs GL3.2+ | |||
614 | } else { | |||
615 | flags = CreateContextFlags::REQUIRE_COMPAT_PROFILE; | |||
616 | } | |||
617 | return GLContextGLX::CreateGLContext( | |||
618 | {{flags}, false}, XlibDisplay::Borrow(aXDisplay), aXWindow, config); | |||
619 | } | |||
620 | ||||
621 | already_AddRefed<GLContext> GLContextProviderGLX::CreateForCompositorWidget( | |||
622 | CompositorWidget* aCompositorWidget, bool aHardwareWebRender, | |||
623 | bool aForceAccelerated) { | |||
624 | if (!aCompositorWidget) { | |||
625 | MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 625); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")"); do { *((volatile int*)__null) = 625; __attribute__((nomerge) ) ::abort(); } while (false); } } while (false); | |||
626 | return nullptr; | |||
627 | } | |||
628 | GtkCompositorWidget* compWidget = aCompositorWidget->AsGTK(); | |||
629 | MOZ_ASSERT(compWidget)do { static_assert( mozilla::detail::AssertionConditionType< decltype(compWidget)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compWidget))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("compWidget", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 629); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compWidget" ")" ); do { *((volatile int*)__null) = 629; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
630 | ||||
631 | return CreateForWidget(DefaultXDisplay(), compWidget->XWindow(), | |||
632 | aHardwareWebRender, aForceAccelerated); | |||
633 | } | |||
634 | ||||
635 | static bool ChooseConfig(GLXLibrary* glx, Display* display, int screen, | |||
636 | GLXFBConfig* const out_config, int* const out_visid) { | |||
637 | const int attribs[] = { | |||
638 | LOCAL_GLX_RENDER_TYPE0x8011, | |||
639 | LOCAL_GLX_RGBA_BIT0x00000001, | |||
640 | LOCAL_GLX_DRAWABLE_TYPE0x8010, | |||
641 | LOCAL_GLX_PIXMAP_BIT0x00000002, | |||
642 | LOCAL_GLX_X_RENDERABLE0x8012, | |||
643 | X11True1, | |||
644 | LOCAL_GLX_RED_SIZE8, | |||
645 | 8, | |||
646 | LOCAL_GLX_GREEN_SIZE9, | |||
647 | 8, | |||
648 | LOCAL_GLX_BLUE_SIZE10, | |||
649 | 8, | |||
650 | LOCAL_GLX_ALPHA_SIZE11, | |||
651 | 8, | |||
652 | LOCAL_GLX_DEPTH_SIZE12, | |||
653 | 0, | |||
654 | LOCAL_GLX_STENCIL_SIZE13, | |||
655 | 0, | |||
656 | 0, | |||
657 | }; | |||
658 | ||||
659 | int numConfigs = 0; | |||
660 | const auto scopedConfigArr = | |||
661 | glx->fChooseFBConfig(display, screen, attribs, &numConfigs); | |||
662 | const auto freeConfigList = MakeScopeExit([&]() { | |||
663 | if (scopedConfigArr) { | |||
664 | XFree(scopedConfigArr); | |||
665 | } | |||
666 | }); | |||
667 | if (!scopedConfigArr || !numConfigs) return false; | |||
668 | ||||
669 | // Issues with glxChooseFBConfig selection and sorting: | |||
670 | // * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't | |||
671 | // request | |||
672 | // alpha bits, we'll probably get RGBA anyways, since 32 is more than 24. | |||
673 | // * DEPTH_SIZE is sorted largest first, including for `0` inputs. | |||
674 | // * STENCIL_SIZE is smallest first, but it might return `8` even though we | |||
675 | // ask for | |||
676 | // `0`. | |||
677 | ||||
678 | // For now, we don't care about these. We *will* care when we do XPixmap | |||
679 | // sharing. | |||
680 | ||||
681 | for (int i = 0; i < numConfigs; ++i) { | |||
682 | GLXFBConfig curConfig = scopedConfigArr[i]; | |||
683 | ||||
684 | int visid; | |||
685 | if (glx->fGetFBConfigAttrib(display, curConfig, LOCAL_GLX_VISUAL_ID0x800B, | |||
686 | &visid) != Success0) { | |||
687 | continue; | |||
688 | } | |||
689 | ||||
690 | if (!visid) continue; | |||
691 | ||||
692 | *out_config = curConfig; | |||
693 | *out_visid = visid; | |||
694 | return true; | |||
695 | } | |||
696 | ||||
697 | return false; | |||
698 | } | |||
699 | ||||
700 | bool GLContextGLX::FindVisual(Display* display, int screen, | |||
701 | int* const out_visualId) { | |||
702 | if (!sGLXLibrary.EnsureInitialized(display)) { | |||
703 | return false; | |||
704 | } | |||
705 | ||||
706 | XVisualInfo visualTemplate; | |||
707 | visualTemplate.screen = screen; | |||
708 | ||||
709 | // Get all visuals of screen | |||
710 | ||||
711 | int visualsLen = 0; | |||
712 | XVisualInfo* xVisuals = | |||
713 | XGetVisualInfo(display, VisualScreenMask0x2, &visualTemplate, &visualsLen); | |||
714 | if (!xVisuals) { | |||
715 | return false; | |||
716 | } | |||
717 | const Range<XVisualInfo> visualInfos(xVisuals, visualsLen); | |||
718 | auto cleanupVisuals = MakeScopeExit([&] { XFree(xVisuals); }); | |||
719 | ||||
720 | // Get default visual info | |||
721 | ||||
722 | Visual* defaultVisual = DefaultVisual(display, screen)((&((_XPrivDisplay)(display))->screens[screen])->root_visual ); | |||
723 | const auto defaultVisualInfo = [&]() -> const XVisualInfo* { | |||
724 | for (const auto& cur : visualInfos) { | |||
725 | if (cur.visual == defaultVisual) { | |||
726 | return &cur; | |||
727 | } | |||
728 | } | |||
729 | return nullptr; | |||
730 | }(); | |||
731 | if (!defaultVisualInfo) { | |||
732 | MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 732); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")"); do { *((volatile int*)__null) = 732; __attribute__((nomerge) ) ::abort(); } while (false); } } while (false); | |||
733 | return false; | |||
734 | } | |||
735 | ||||
736 | const int bpp = 32; | |||
737 | ||||
738 | for (auto& cur : visualInfos) { | |||
739 | const auto fnConfigMatches = [&](const int pname, const int expected) { | |||
740 | int actual; | |||
741 | if (sGLXLibrary.fGetConfig(display, &cur, pname, &actual)) { | |||
742 | return false; | |||
743 | } | |||
744 | return actual == expected; | |||
745 | }; | |||
746 | ||||
747 | // Check if visual is compatible. | |||
748 | if (cur.depth != bpp || cur.c_class != defaultVisualInfo->c_class) { | |||
749 | continue; | |||
750 | } | |||
751 | ||||
752 | // Check if visual is compatible to GL requests. | |||
753 | if (fnConfigMatches(LOCAL_GLX_USE_GL1, 1) && | |||
754 | fnConfigMatches(LOCAL_GLX_DOUBLEBUFFER5, 1) && | |||
755 | fnConfigMatches(LOCAL_GLX_RED_SIZE8, 8) && | |||
756 | fnConfigMatches(LOCAL_GLX_GREEN_SIZE9, 8) && | |||
757 | fnConfigMatches(LOCAL_GLX_BLUE_SIZE10, 8) && | |||
758 | fnConfigMatches(LOCAL_GLX_ALPHA_SIZE11, 8)) { | |||
759 | *out_visualId = cur.visualid; | |||
760 | return true; | |||
761 | } | |||
762 | } | |||
763 | ||||
764 | return false; | |||
765 | } | |||
766 | ||||
767 | bool GLContextGLX::FindFBConfigForWindow(Display* display, int screen, | |||
768 | Window window, | |||
769 | GLXFBConfig* const out_config, | |||
770 | int* const out_visid, | |||
771 | bool aWebRender) { | |||
772 | // XXX the visual ID is almost certainly the LOCAL_GLX_FBCONFIG_ID, so | |||
773 | // we could probably do this first and replace the glXGetFBConfigs | |||
774 | // with glXChooseConfigs. Docs are sparklingly clear as always. | |||
775 | XWindowAttributes windowAttrs; | |||
776 | if (!XGetWindowAttributes(display, window, &windowAttrs)) { | |||
777 | NS_WARNING("[GLX] XGetWindowAttributes() failed")NS_DebugBreak(NS_DEBUG_WARNING, "[GLX] XGetWindowAttributes() failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 777); | |||
778 | return false; | |||
779 | } | |||
780 | ||||
781 | GLXFBConfig* cfgs = nullptr; | |||
782 | const auto freeConfigList = MakeScopeExit([&]() { | |||
783 | if (cfgs) { | |||
784 | XFree(cfgs); | |||
785 | } | |||
786 | }); | |||
787 | int numConfigs; | |||
788 | const int webrenderAttribs[] = {LOCAL_GLX_ALPHA_SIZE11, | |||
789 | windowAttrs.depth == 32 ? 8 : 0, | |||
790 | LOCAL_GLX_DOUBLEBUFFER5, X11True1, 0}; | |||
791 | ||||
792 | if (aWebRender) { | |||
793 | cfgs = sGLXLibrary.fChooseFBConfig(display, screen, webrenderAttribs, | |||
794 | &numConfigs); | |||
795 | } else { | |||
796 | cfgs = sGLXLibrary.fGetFBConfigs(display, screen, &numConfigs); | |||
797 | } | |||
798 | ||||
799 | if (!cfgs) { | |||
800 | NS_WARNING("[GLX] glXGetFBConfigs() failed")NS_DebugBreak(NS_DEBUG_WARNING, "[GLX] glXGetFBConfigs() failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 800); | |||
801 | return false; | |||
802 | } | |||
803 | NS_ASSERTION(numConfigs > 0, "No FBConfigs found!")do { if (!(numConfigs > 0)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "No FBConfigs found!", "numConfigs > 0", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 803); MOZ_PretendNoReturn(); } } while (0); | |||
804 | ||||
805 | const VisualID windowVisualID = XVisualIDFromVisual(windowAttrs.visual); | |||
806 | #ifdef DEBUG1 | |||
807 | printf("[GLX] window %lx has VisualID 0x%lx\n", window, windowVisualID); | |||
808 | #endif | |||
809 | ||||
810 | for (int i = 0; i < numConfigs; i++) { | |||
811 | int visid = X11None0L; | |||
812 | sGLXLibrary.fGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID0x800B, | |||
813 | &visid); | |||
814 | if (visid) { | |||
815 | // WebRender compatible GLX visual is configured | |||
816 | // at nsWindow::Create() by GLContextGLX::FindVisual(), | |||
817 | // just reuse it here. | |||
818 | if (windowVisualID == static_cast<VisualID>(visid)) { | |||
819 | *out_config = cfgs[i]; | |||
820 | *out_visid = visid; | |||
821 | return true; | |||
822 | } | |||
823 | } | |||
824 | } | |||
825 | ||||
826 | // We don't have a frame buffer visual which matches the GLX visual | |||
827 | // from GLContextGLX::FindVisual(). Let's try to find a near one and hope | |||
828 | // we're not on NVIDIA (Bug 1478454) as it causes X11 BadMatch error there. | |||
829 | for (int i = 0; i < numConfigs; i++) { | |||
830 | int visid = X11None0L; | |||
831 | sGLXLibrary.fGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID0x800B, | |||
832 | &visid); | |||
833 | if (visid) { | |||
834 | int depth; | |||
835 | Visual* visual; | |||
836 | FindVisualAndDepth(display, visid, &visual, &depth); | |||
837 | if (depth == windowAttrs.depth && | |||
838 | AreCompatibleVisuals(windowAttrs.visual, visual)) { | |||
839 | *out_config = cfgs[i]; | |||
840 | *out_visid = visid; | |||
841 | return true; | |||
842 | } | |||
843 | } | |||
844 | } | |||
845 | ||||
846 | NS_WARNING("[GLX] Couldn't find a FBConfig matching window visual")NS_DebugBreak(NS_DEBUG_WARNING, "[GLX] Couldn't find a FBConfig matching window visual" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 846); | |||
847 | return false; | |||
848 | } | |||
849 | ||||
850 | static already_AddRefed<GLContextGLX> CreateOffscreenPixmapContext( | |||
851 | const GLContextCreateDesc& desc, const IntSize& size, | |||
852 | nsACString* const out_failureId) { | |||
853 | GLXLibrary* glx = &sGLXLibrary; | |||
854 | auto display = glx->GetDisplay(); | |||
855 | ||||
856 | if (!display || !glx->EnsureInitialized(*display)) return nullptr; | |||
857 | ||||
858 | int screen = DefaultScreen(display->get())(((_XPrivDisplay)(display->get()))->default_screen); | |||
859 | ||||
860 | GLXFBConfig config; | |||
861 | int visid; | |||
862 | if (!ChooseConfig(glx, *display, screen, &config, &visid)) { | |||
863 | NS_WARNING("Failed to find a compatible config.")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to find a compatible config." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/gfx/gl/GLContextProviderGLX.cpp" , 863); | |||
864 | return nullptr; | |||
865 | } | |||
866 | ||||
867 | Visual* visual; | |||
868 | int depth; | |||
869 | FindVisualAndDepth(*display, visid, &visual, &depth); | |||
870 | ||||
871 | gfx::IntSize dummySize(16, 16); | |||
872 | const auto drawable = | |||
873 | XCreatePixmap(*display, DefaultRootWindow(display->get())((&((_XPrivDisplay)(display->get()))->screens[(((_XPrivDisplay )(display->get()))->default_screen)])->root), | |||
874 | dummySize.width, dummySize.height, depth); | |||
875 | if (!drawable) { | |||
876 | return nullptr; | |||
877 | } | |||
878 | ||||
879 | // Handle slightly different signature between glXCreatePixmap and | |||
880 | // its pre-GLX-1.3 extension equivalent (though given the ABI, we | |||
881 | // might not need to). | |||
882 | const auto pixmap = glx->fCreatePixmap(*display, config, drawable, nullptr); | |||
883 | if (pixmap == 0) { | |||
884 | XFreePixmap(*display, drawable); | |||
885 | return nullptr; | |||
886 | } | |||
887 | ||||
888 | auto fullDesc = GLContextDesc{desc}; | |||
889 | fullDesc.isOffscreen = true; | |||
890 | ||||
891 | if (fullDesc.flags & CreateContextFlags::FORBID_HARDWARE) { | |||
892 | fullDesc.flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE; | |||
893 | } | |||
894 | ||||
895 | return GLContextGLX::CreateGLContext(fullDesc, display, pixmap, config, | |||
896 | drawable); | |||
897 | } | |||
898 | ||||
899 | /*static*/ | |||
900 | already_AddRefed<GLContext> GLContextProviderGLX::CreateHeadless( | |||
901 | const GLContextCreateDesc& desc, nsACString* const out_failureId) { | |||
902 | IntSize dummySize = IntSize(16, 16); | |||
903 | return CreateOffscreenPixmapContext(desc, dummySize, out_failureId); | |||
| ||||
904 | } | |||
905 | ||||
906 | /*static*/ | |||
907 | GLContext* GLContextProviderGLX::GetGlobalContext() { | |||
908 | // Context sharing not supported. | |||
909 | return nullptr; | |||
910 | } | |||
911 | ||||
912 | /*static*/ | |||
913 | void GLContextProviderGLX::Shutdown() {} | |||
914 | ||||
915 | } // namespace mozilla::gl |