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