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