GLContextProviderWGL.cpp (17886B)
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 #include "GLContextProvider.h" 7 #include "GLContextWGL.h" 8 #include "GLLibraryLoader.h" 9 #include "nsDebug.h" 10 #include "nsIWidget.h" 11 #include "gfxPlatform.h" 12 #include "gfxWindowsSurface.h" 13 14 #include "gfxCrashReporterUtils.h" 15 16 #include "prenv.h" 17 18 #include "mozilla/gfx/gfxVars.h" 19 #include "mozilla/Preferences.h" 20 #include "mozilla/ScopeExit.h" 21 #include "mozilla/SharedLibrary.h" 22 #include "mozilla/StaticPrefs_gl.h" 23 #include "mozilla/StaticPtr.h" 24 #include "mozilla/layers/CompositorOptions.h" 25 #include "mozilla/widget/CompositorWidget.h" 26 #include "mozilla/widget/WinCompositorWidget.h" 27 28 namespace mozilla { 29 namespace gl { 30 31 using namespace mozilla::gfx; 32 using namespace mozilla::widget; 33 34 MOZ_RUNINIT WGLLibrary sWGLLib; 35 36 /* 37 ScopedWindow::~ScopedWindow() 38 { 39 if (mDC) { 40 MOZ_ALWAYS_TRUE( ReleaseDC(mDC) ); 41 } 42 if (mWindow) { 43 MOZ_ALWAYS_TRUE( DestroyWindow(mWindow) ); 44 } 45 } 46 */ 47 static HWND CreateDummyWindow() { 48 WNDCLASSW wc{}; 49 if (!GetClassInfoW(GetModuleHandle(nullptr), L"GLContextWGLClass", &wc)) { 50 wc = {}; 51 wc.style = CS_OWNDC; 52 wc.hInstance = GetModuleHandle(nullptr); 53 wc.lpfnWndProc = DefWindowProc; 54 wc.lpszClassName = L"GLContextWGLClass"; 55 if (!RegisterClassW(&wc)) { 56 NS_WARNING("Failed to register GLContextWGLClass?!"); 57 // er. failed to register our class? 58 return nullptr; 59 } 60 } 61 62 return CreateWindowW(L"GLContextWGLClass", L"GLContextWGL", 0, 0, 0, 1, 1, 63 nullptr, nullptr, GetModuleHandle(nullptr), nullptr); 64 } 65 66 static inline bool HasExtension(const char* aExtensions, 67 const char* aRequiredExtension) { 68 return GLContext::ListHasExtension( 69 reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension); 70 } 71 72 SymbolLoader WGLLibrary::GetSymbolLoader() const { 73 auto ret = SymbolLoader(*mOGLLibrary); 74 ret.mPfn = SymbolLoader::GetProcAddressT(mSymbols.fGetProcAddress); 75 return ret; 76 } 77 78 bool WGLLibrary::EnsureInitialized() { 79 if (mInitialized) return true; 80 81 mozilla::ScopedGfxFeatureReporter reporter("WGL"); 82 83 std::wstring libGLFilename = L"Opengl32.dll"; 84 // SU_SPIES_DIRECTORY is for AMD CodeXL/gDEBugger 85 if (_wgetenv(L"SU_SPIES_DIRECTORY")) { 86 libGLFilename = 87 std::wstring(_wgetenv(L"SU_SPIES_DIRECTORY")) + L"\\opengl32.dll"; 88 } 89 90 if (!mOGLLibrary) { 91 mOGLLibrary = LoadLibraryWithFlags(libGLFilename.c_str()); 92 if (!mOGLLibrary) { 93 NS_WARNING("Couldn't load OpenGL library."); 94 return false; 95 } 96 } 97 98 #define SYMBOL(X) \ 99 { \ 100 (PRFuncPtr*)&mSymbols.f##X, { \ 101 { \ 102 "wgl" #X \ 103 } \ 104 } \ 105 } 106 #define END_OF_SYMBOLS \ 107 { \ 108 nullptr, {} \ 109 } 110 111 { 112 const auto loader = SymbolLoader(*mOGLLibrary); 113 const SymLoadStruct earlySymbols[] = {SYMBOL(CreateContext), 114 SYMBOL(MakeCurrent), 115 SYMBOL(GetProcAddress), 116 SYMBOL(DeleteContext), 117 SYMBOL(GetCurrentContext), 118 SYMBOL(GetCurrentDC), 119 END_OF_SYMBOLS}; 120 121 if (!loader.LoadSymbols(earlySymbols)) { 122 NS_WARNING( 123 "Couldn't find required entry points in OpenGL DLL (early init)"); 124 return false; 125 } 126 } 127 128 mDummyWindow = CreateDummyWindow(); 129 MOZ_ASSERT(mDummyWindow); 130 if (!mDummyWindow) return false; 131 auto cleanup = MakeScopeExit([&]() { Reset(); }); 132 133 mRootDc = GetDC(mDummyWindow); 134 MOZ_ASSERT(mRootDc); 135 if (!mRootDc) return false; 136 137 // -- 138 139 { 140 PIXELFORMATDESCRIPTOR pfd{}; 141 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); 142 pfd.nVersion = 1; 143 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; 144 // pfd.iPixelType = PFD_TYPE_RGBA; 145 // pfd.cColorBits = 24; 146 // pfd.cRedBits = 8; 147 // pfd.cGreenBits = 8; 148 // pfd.cBlueBits = 8; 149 // pfd.cAlphaBits = 8; 150 pfd.iLayerType = PFD_MAIN_PLANE; 151 152 const auto pixelFormat = ChoosePixelFormat(mRootDc, &pfd); 153 MOZ_ASSERT(pixelFormat); 154 if (!pixelFormat) return false; 155 const bool setPixelFormatOk = SetPixelFormat(mRootDc, pixelFormat, nullptr); 156 MOZ_ASSERT(setPixelFormatOk); 157 if (!setPixelFormatOk) return false; 158 } 159 160 // -- 161 162 // create rendering context 163 mDummyGlrc = mSymbols.fCreateContext(mRootDc); 164 if (!mDummyGlrc) return false; 165 166 const auto curCtx = mSymbols.fGetCurrentContext(); 167 const auto curDC = mSymbols.fGetCurrentDC(); 168 169 GLContext::ResetTLSCurrentContext(); 170 171 if (!mSymbols.fMakeCurrent(mRootDc, mDummyGlrc)) { 172 NS_WARNING("wglMakeCurrent failed"); 173 return false; 174 } 175 const auto resetContext = MakeScopeExit([&]() { 176 GLContext::ResetTLSCurrentContext(); 177 mSymbols.fMakeCurrent(curDC, curCtx); 178 }); 179 180 const auto loader = GetSymbolLoader(); 181 182 // Now we can grab all the other symbols that we couldn't without having 183 // a context current. 184 // clang-format off 185 const SymLoadStruct reqExtSymbols[] = { 186 { (PRFuncPtr*)&mSymbols.fCreatePbuffer, {{ "wglCreatePbufferARB", "wglCreatePbufferEXT" }} }, 187 { (PRFuncPtr*)&mSymbols.fDestroyPbuffer, {{ "wglDestroyPbufferARB", "wglDestroyPbufferEXT" }} }, 188 { (PRFuncPtr*)&mSymbols.fGetPbufferDC, {{ "wglGetPbufferDCARB", "wglGetPbufferDCEXT" }} }, 189 { (PRFuncPtr*)&mSymbols.fReleasePbufferDC, {{ "wglReleasePbufferDCARB", "wglReleasePbufferDCEXT" }} }, 190 // { (PRFuncPtr*)&mSymbols.fBindTexImage, {{ "wglBindTexImageARB", "wglBindTexImageEXT" }} }, 191 // { (PRFuncPtr*)&mSymbols.fReleaseTexImage, {{ "wglReleaseTexImageARB", "wglReleaseTexImageEXT" }} }, 192 { (PRFuncPtr*)&mSymbols.fChoosePixelFormat, {{ "wglChoosePixelFormatARB", "wglChoosePixelFormatEXT" }} }, 193 // { (PRFuncPtr*)&mSymbols.fGetPixelFormatAttribiv, {{ "wglGetPixelFormatAttribivARB", "wglGetPixelFormatAttribivEXT" }} }, 194 SYMBOL(GetExtensionsStringARB), 195 END_OF_SYMBOLS 196 }; 197 // clang-format on 198 if (!loader.LoadSymbols(reqExtSymbols)) { 199 NS_WARNING("reqExtSymbols missing"); 200 return false; 201 } 202 203 // -- 204 205 const auto extString = mSymbols.fGetExtensionsStringARB(mRootDc); 206 MOZ_ASSERT(extString); 207 208 // -- 209 210 if (HasExtension(extString, "WGL_ARB_create_context")) { 211 const SymLoadStruct createContextSymbols[] = { 212 SYMBOL(CreateContextAttribsARB), END_OF_SYMBOLS}; 213 if (loader.LoadSymbols(createContextSymbols)) { 214 if (HasExtension(extString, "WGL_ARB_create_context_robustness")) { 215 mHasRobustness = true; 216 } 217 } else { 218 NS_ERROR( 219 "WGL_ARB_create_context announced without supplying its functions."); 220 ClearSymbols(createContextSymbols); 221 } 222 } 223 224 // -- 225 226 bool hasDXInterop2 = HasExtension(extString, "WGL_NV_DX_interop2"); 227 if (gfxVars::DXInterop2Blocked() && 228 !StaticPrefs::gl_ignore_dx_interop2_blacklist()) { 229 hasDXInterop2 = false; 230 } 231 232 if (hasDXInterop2) { 233 const SymLoadStruct dxInteropSymbols[] = { 234 SYMBOL(DXSetResourceShareHandleNV), 235 SYMBOL(DXOpenDeviceNV), 236 SYMBOL(DXCloseDeviceNV), 237 SYMBOL(DXRegisterObjectNV), 238 SYMBOL(DXUnregisterObjectNV), 239 SYMBOL(DXObjectAccessNV), 240 SYMBOL(DXLockObjectsNV), 241 SYMBOL(DXUnlockObjectsNV), 242 END_OF_SYMBOLS}; 243 if (!loader.LoadSymbols(dxInteropSymbols)) { 244 NS_ERROR( 245 "WGL_NV_DX_interop2 announceed without supplying its functions."); 246 ClearSymbols(dxInteropSymbols); 247 } 248 } 249 250 // -- 251 252 cleanup.release(); 253 254 mInitialized = true; 255 256 reporter.SetSuccessful(); 257 return true; 258 } 259 260 #undef SYMBOL 261 #undef END_OF_SYMBOLS 262 263 void WGLLibrary::Reset() { 264 if (mDummyGlrc) { 265 (void)mSymbols.fDeleteContext(mDummyGlrc); 266 mDummyGlrc = nullptr; 267 } 268 if (mRootDc) { 269 (void)ReleaseDC(mDummyWindow, mRootDc); 270 mRootDc = nullptr; 271 } 272 if (mDummyWindow) { 273 (void)DestroyWindow(mDummyWindow); 274 mDummyWindow = nullptr; 275 } 276 } 277 278 GLContextWGL::GLContextWGL(const GLContextDesc& desc, HDC aDC, HGLRC aContext, 279 HWND aWindow) 280 : GLContext(desc, nullptr, false), 281 mDC(aDC), 282 mContext(aContext), 283 mWnd(aWindow), 284 mPBuffer(nullptr), 285 mPixelFormat(0) {} 286 287 GLContextWGL::GLContextWGL(const GLContextDesc& desc, HANDLE aPbuffer, HDC aDC, 288 HGLRC aContext, int aPixelFormat) 289 : GLContext(desc, nullptr, false), 290 mDC(aDC), 291 mContext(aContext), 292 mWnd(nullptr), 293 mPBuffer(aPbuffer), 294 mPixelFormat(aPixelFormat) {} 295 296 GLContextWGL::~GLContextWGL() { 297 MarkDestroyed(); 298 299 (void)sWGLLib.mSymbols.fDeleteContext(mContext); 300 301 if (mPBuffer) { 302 (void)sWGLLib.mSymbols.fReleasePbufferDC(mPBuffer, mDC); 303 (void)sWGLLib.mSymbols.fDestroyPbuffer(mPBuffer); 304 } 305 if (mWnd) { 306 (void)ReleaseDC(mWnd, mDC); 307 DestroyWindow(mWnd); 308 } 309 } 310 311 bool GLContextWGL::MakeCurrentImpl() const { 312 GLContext::ResetTLSCurrentContext(); 313 314 const bool succeeded = sWGLLib.mSymbols.fMakeCurrent(mDC, mContext); 315 NS_ASSERTION(succeeded, "Failed to make GL context current!"); 316 return succeeded; 317 } 318 319 bool GLContextWGL::IsCurrentImpl() const { 320 return sWGLLib.mSymbols.fGetCurrentContext() == mContext; 321 } 322 323 bool GLContextWGL::SwapBuffers() { 324 if (!mIsDoubleBuffered) return false; 325 return ::SwapBuffers(mDC); 326 } 327 328 void GLContextWGL::GetWSIInfo(nsCString* const out) const { 329 out->AppendLiteral("wglGetExtensionsString: "); 330 out->Append(sWGLLib.mSymbols.fGetExtensionsStringARB(mDC)); 331 } 332 333 HGLRC 334 WGLLibrary::CreateContextWithFallback(const HDC dc, 335 const bool tryRobustBuffers) const { 336 if (mHasRobustness) { 337 if (tryRobustBuffers) { 338 const int attribs[] = {LOCAL_WGL_CONTEXT_FLAGS_ARB, 339 LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, 340 LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, 341 LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, 0}; 342 const auto context = 343 mSymbols.fCreateContextAttribsARB(dc, nullptr, attribs); 344 if (context) return context; 345 } 346 347 const int attribs[] = {LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, 348 LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, 0}; 349 const auto context = 350 mSymbols.fCreateContextAttribsARB(dc, nullptr, attribs); 351 if (context) return context; 352 } 353 if (mSymbols.fCreateContextAttribsARB) { 354 const auto context = 355 mSymbols.fCreateContextAttribsARB(dc, nullptr, nullptr); 356 if (context) return context; 357 } 358 return mSymbols.fCreateContext(dc); 359 } 360 361 static RefPtr<GLContext> CreateForWidget(const HWND window, 362 const bool isWebRender, 363 const bool requireAccelerated) { 364 auto& wgl = sWGLLib; 365 if (!wgl.EnsureInitialized()) return nullptr; 366 367 const auto dc = GetDC(window); 368 if (!dc) return nullptr; 369 auto cleanupDc = MakeScopeExit([&]() { (void)ReleaseDC(window, dc); }); 370 371 int chosenFormat; 372 UINT foundFormats = 0; 373 374 if (!foundFormats) { 375 const int kAttribs[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB, 376 true, 377 LOCAL_WGL_SUPPORT_OPENGL_ARB, 378 true, 379 LOCAL_WGL_DOUBLE_BUFFER_ARB, 380 true, 381 LOCAL_WGL_ACCELERATION_ARB, 382 LOCAL_WGL_FULL_ACCELERATION_ARB, 383 0}; 384 const int kAttribsForWebRender[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB, 385 true, 386 LOCAL_WGL_SUPPORT_OPENGL_ARB, 387 true, 388 LOCAL_WGL_DOUBLE_BUFFER_ARB, 389 true, 390 LOCAL_WGL_DEPTH_BITS_ARB, 391 24, 392 LOCAL_WGL_ACCELERATION_ARB, 393 LOCAL_WGL_FULL_ACCELERATION_ARB, 394 0}; 395 const int* attribs; 396 if (isWebRender) { 397 attribs = kAttribsForWebRender; 398 } else { 399 attribs = kAttribs; 400 } 401 402 if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), attribs, nullptr, 1, 403 &chosenFormat, &foundFormats)) { 404 foundFormats = 0; 405 } 406 } 407 if (!foundFormats) { 408 if (requireAccelerated) return nullptr; 409 410 const int kAttribs[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB, 411 true, 412 LOCAL_WGL_SUPPORT_OPENGL_ARB, 413 true, 414 LOCAL_WGL_DOUBLE_BUFFER_ARB, 415 true, 416 0}; 417 const int kAttribsForWebRender[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB, 418 true, 419 LOCAL_WGL_SUPPORT_OPENGL_ARB, 420 true, 421 LOCAL_WGL_DOUBLE_BUFFER_ARB, 422 true, 423 LOCAL_WGL_DEPTH_BITS_ARB, 424 24, 425 0}; 426 427 const int* attribs; 428 if (isWebRender) { 429 attribs = kAttribsForWebRender; 430 } else { 431 attribs = kAttribs; 432 } 433 434 if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), attribs, nullptr, 1, 435 &chosenFormat, &foundFormats)) { 436 foundFormats = 0; 437 } 438 } 439 if (!foundFormats) return nullptr; 440 441 // We need to make sure we call SetPixelFormat -after- calling 442 // EnsureInitialized, otherwise it can load/unload the dll and 443 // wglCreateContext will fail. 444 445 SetPixelFormat(dc, chosenFormat, nullptr); 446 const auto context = sWGLLib.CreateContextWithFallback(dc, false); 447 if (!context) return nullptr; 448 449 const RefPtr<GLContextWGL> gl = new GLContextWGL({}, dc, context); 450 cleanupDc.release(); 451 gl->mIsDoubleBuffered = true; 452 if (!gl->Init()) return nullptr; 453 454 return gl; 455 } 456 457 already_AddRefed<GLContext> GLContextProviderWGL::CreateForCompositorWidget( 458 CompositorWidget* aCompositorWidget, bool aHardwareWebRender, 459 bool aForceAccelerated) { 460 if (!aCompositorWidget) { 461 MOZ_ASSERT(false); 462 return nullptr; 463 } 464 return CreateForWidget(aCompositorWidget->AsWindows()->GetHwnd(), 465 aHardwareWebRender, aForceAccelerated) 466 .forget(); 467 } 468 469 /*static*/ 470 already_AddRefed<GLContext> GLContextProviderWGL::CreateHeadless( 471 const GLContextCreateDesc& desc, nsACString* const out_failureId) { 472 auto& wgl = sWGLLib; 473 if (!wgl.EnsureInitialized()) return nullptr; 474 475 int chosenFormat; 476 UINT foundFormats = 0; 477 478 bool forbidHardware = 479 static_cast<bool>(desc.flags & CreateContextFlags::FORBID_HARDWARE); 480 if (!foundFormats && forbidHardware) { 481 const int kAttribs[] = {LOCAL_WGL_DRAW_TO_PBUFFER_ARB, 482 true, 483 LOCAL_WGL_SUPPORT_OPENGL_ARB, 484 true, 485 LOCAL_WGL_ACCELERATION_ARB, 486 LOCAL_WGL_NO_ACCELERATION_ARB, 487 0}; 488 if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), kAttribs, nullptr, 1, 489 &chosenFormat, &foundFormats)) { 490 foundFormats = 0; 491 return nullptr; 492 } 493 } 494 495 if (!foundFormats && !forbidHardware) { 496 const int kAttribs[] = {LOCAL_WGL_DRAW_TO_PBUFFER_ARB, 497 true, 498 LOCAL_WGL_SUPPORT_OPENGL_ARB, 499 true, 500 LOCAL_WGL_ACCELERATION_ARB, 501 LOCAL_WGL_FULL_ACCELERATION_ARB, 502 0}; 503 if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), kAttribs, nullptr, 1, 504 &chosenFormat, &foundFormats)) { 505 foundFormats = 0; 506 } 507 } 508 if (!foundFormats) { 509 const int kAttribs[] = {LOCAL_WGL_DRAW_TO_PBUFFER_ARB, true, 510 LOCAL_WGL_SUPPORT_OPENGL_ARB, true, 0}; 511 if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), kAttribs, nullptr, 1, 512 &chosenFormat, &foundFormats)) { 513 foundFormats = 0; 514 } 515 } 516 if (!foundFormats) return nullptr; 517 const int kPbufferAttribs[] = {0}; 518 const auto pbuffer = wgl.mSymbols.fCreatePbuffer(wgl.RootDc(), chosenFormat, 519 1, 1, kPbufferAttribs); 520 if (!pbuffer) return nullptr; 521 auto cleanupPbuffer = 522 MakeScopeExit([&]() { (void)wgl.mSymbols.fDestroyPbuffer(pbuffer); }); 523 524 const auto dc = wgl.mSymbols.fGetPbufferDC(pbuffer); 525 if (!dc) return nullptr; 526 auto cleanupDc = MakeScopeExit( 527 [&]() { (void)wgl.mSymbols.fReleasePbufferDC(pbuffer, dc); }); 528 529 const auto context = wgl.CreateContextWithFallback(dc, true); 530 if (!context) return nullptr; 531 532 const auto fullDesc = GLContextDesc{desc, true}; 533 const RefPtr<GLContextWGL> gl = 534 new GLContextWGL(fullDesc, pbuffer, dc, context, chosenFormat); 535 cleanupPbuffer.release(); 536 cleanupDc.release(); 537 if (!gl->Init()) return nullptr; 538 539 return RefPtr<GLContext>(gl.get()).forget(); 540 } 541 542 /*static*/ 543 GLContext* GLContextProviderWGL::GetGlobalContext() { return nullptr; } 544 545 /*static*/ 546 void GLContextProviderWGL::Shutdown() {} 547 548 } /* namespace gl */ 549 } /* namespace mozilla */