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/. */
6 #include "GLContextProvider.h"
7 #include "GLContextWGL.h"
8 #include "GLLibraryLoader.h"
10 #include "nsIWidget.h"
11 #include "gfxPlatform.h"
12 #include "gfxWindowsSurface.h"
14 #include "gfxCrashReporterUtils.h"
18 #include "mozilla/gfx/gfxVars.h"
19 #include "mozilla/Preferences.h"
20 #include "mozilla/ScopeExit.h"
21 #include "mozilla/StaticPtr.h"
22 #include "mozilla/layers/CompositorOptions.h"
23 #include "mozilla/widget/CompositorWidget.h"
24 #include "mozilla/widget/WinCompositorWidget.h"
29 using namespace mozilla::gfx
;
30 using namespace mozilla::widget
;
35 ScopedWindow::~ScopedWindow()
38 MOZ_ALWAYS_TRUE( ReleaseDC(mDC) );
41 MOZ_ALWAYS_TRUE( DestroyWindow(mWindow) );
45 static HWND
CreateDummyWindow() {
47 if (!GetClassInfoW(GetModuleHandle(nullptr), L
"GLContextWGLClass", &wc
)) {
50 wc
.hInstance
= GetModuleHandle(nullptr);
51 wc
.lpfnWndProc
= DefWindowProc
;
52 wc
.lpszClassName
= L
"GLContextWGLClass";
53 if (!RegisterClassW(&wc
)) {
54 NS_WARNING("Failed to register GLContextWGLClass?!");
55 // er. failed to register our class?
60 return CreateWindowW(L
"GLContextWGLClass", L
"GLContextWGL", 0, 0, 0, 1, 1,
61 nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
64 static inline bool HasExtension(const char* aExtensions
,
65 const char* aRequiredExtension
) {
66 return GLContext::ListHasExtension(
67 reinterpret_cast<const GLubyte
*>(aExtensions
), aRequiredExtension
);
70 SymbolLoader
WGLLibrary::GetSymbolLoader() const {
71 auto ret
= SymbolLoader(*mOGLLibrary
);
72 ret
.mPfn
= SymbolLoader::GetProcAddressT(mSymbols
.fGetProcAddress
);
76 bool WGLLibrary::EnsureInitialized() {
77 if (mInitialized
) return true;
79 mozilla::ScopedGfxFeatureReporter
reporter("WGL");
81 std::wstring libGLFilename
= L
"Opengl32.dll";
82 // SU_SPIES_DIRECTORY is for AMD CodeXL/gDEBugger
83 if (_wgetenv(L
"SU_SPIES_DIRECTORY")) {
85 std::wstring(_wgetenv(L
"SU_SPIES_DIRECTORY")) + L
"\\opengl32.dll";
89 mOGLLibrary
= LoadLibraryWithFlags(libGLFilename
.c_str());
91 NS_WARNING("Couldn't load OpenGL library.");
96 #define SYMBOL(X) {(PRFuncPtr*)&mSymbols.f##X, {{"wgl" #X}}}
97 #define END_OF_SYMBOLS \
103 const auto loader
= SymbolLoader(*mOGLLibrary
);
104 const SymLoadStruct earlySymbols
[] = {SYMBOL(CreateContext
),
106 SYMBOL(GetProcAddress
),
107 SYMBOL(DeleteContext
),
108 SYMBOL(GetCurrentContext
),
109 SYMBOL(GetCurrentDC
),
112 if (!loader
.LoadSymbols(earlySymbols
)) {
114 "Couldn't find required entry points in OpenGL DLL (early init)");
119 mDummyWindow
= CreateDummyWindow();
120 MOZ_ASSERT(mDummyWindow
);
121 if (!mDummyWindow
) return false;
122 auto cleanup
= MakeScopeExit([&]() { Reset(); });
124 mRootDc
= GetDC(mDummyWindow
);
126 if (!mRootDc
) return false;
131 PIXELFORMATDESCRIPTOR pfd
{};
132 pfd
.nSize
= sizeof(PIXELFORMATDESCRIPTOR
);
134 pfd
.dwFlags
= PFD_DRAW_TO_WINDOW
| PFD_SUPPORT_OPENGL
;
135 // pfd.iPixelType = PFD_TYPE_RGBA;
136 // pfd.cColorBits = 24;
138 // pfd.cGreenBits = 8;
139 // pfd.cBlueBits = 8;
140 // pfd.cAlphaBits = 8;
141 pfd
.iLayerType
= PFD_MAIN_PLANE
;
143 const auto pixelFormat
= ChoosePixelFormat(mRootDc
, &pfd
);
144 MOZ_ASSERT(pixelFormat
);
145 if (!pixelFormat
) return false;
146 const bool setPixelFormatOk
= SetPixelFormat(mRootDc
, pixelFormat
, nullptr);
147 MOZ_ASSERT(setPixelFormatOk
);
148 if (!setPixelFormatOk
) return false;
153 // create rendering context
154 mDummyGlrc
= mSymbols
.fCreateContext(mRootDc
);
155 if (!mDummyGlrc
) return false;
157 const auto curCtx
= mSymbols
.fGetCurrentContext();
158 const auto curDC
= mSymbols
.fGetCurrentDC();
160 if (!mSymbols
.fMakeCurrent(mRootDc
, mDummyGlrc
)) {
161 NS_WARNING("wglMakeCurrent failed");
164 const auto resetContext
=
165 MakeScopeExit([&]() { mSymbols
.fMakeCurrent(curDC
, curCtx
); });
167 const auto loader
= GetSymbolLoader();
169 // Now we can grab all the other symbols that we couldn't without having
170 // a context current.
172 const SymLoadStruct reqExtSymbols
[] = {
173 { (PRFuncPtr
*)&mSymbols
.fCreatePbuffer
, {{ "wglCreatePbufferARB", "wglCreatePbufferEXT" }} },
174 { (PRFuncPtr
*)&mSymbols
.fDestroyPbuffer
, {{ "wglDestroyPbufferARB", "wglDestroyPbufferEXT" }} },
175 { (PRFuncPtr
*)&mSymbols
.fGetPbufferDC
, {{ "wglGetPbufferDCARB", "wglGetPbufferDCEXT" }} },
176 { (PRFuncPtr
*)&mSymbols
.fReleasePbufferDC
, {{ "wglReleasePbufferDCARB", "wglReleasePbufferDCEXT" }} },
177 // { (PRFuncPtr*)&mSymbols.fBindTexImage, {{ "wglBindTexImageARB", "wglBindTexImageEXT" }} },
178 // { (PRFuncPtr*)&mSymbols.fReleaseTexImage, {{ "wglReleaseTexImageARB", "wglReleaseTexImageEXT" }} },
179 { (PRFuncPtr
*)&mSymbols
.fChoosePixelFormat
, {{ "wglChoosePixelFormatARB", "wglChoosePixelFormatEXT" }} },
180 // { (PRFuncPtr*)&mSymbols.fGetPixelFormatAttribiv, {{ "wglGetPixelFormatAttribivARB", "wglGetPixelFormatAttribivEXT" }} },
181 SYMBOL(GetExtensionsStringARB
),
185 if (!loader
.LoadSymbols(reqExtSymbols
)) {
186 NS_WARNING("reqExtSymbols missing");
192 const auto extString
= mSymbols
.fGetExtensionsStringARB(mRootDc
);
193 MOZ_ASSERT(extString
);
194 MOZ_ASSERT(HasExtension(extString
, "WGL_ARB_extensions_string"));
198 if (HasExtension(extString
, "WGL_ARB_create_context")) {
199 const SymLoadStruct createContextSymbols
[] = {
200 SYMBOL(CreateContextAttribsARB
), END_OF_SYMBOLS
};
201 if (loader
.LoadSymbols(createContextSymbols
)) {
202 if (HasExtension(extString
, "WGL_ARB_create_context_robustness")) {
203 mHasRobustness
= true;
207 "WGL_ARB_create_context announced without supplying its functions.");
208 ClearSymbols(createContextSymbols
);
214 bool hasDXInterop2
= HasExtension(extString
, "WGL_NV_DX_interop2");
215 if (gfxVars::DXInterop2Blocked() &&
216 !StaticPrefs::gl_ignore_dx_interop2_blacklist()) {
217 hasDXInterop2
= false;
221 const SymLoadStruct dxInteropSymbols
[] = {
222 SYMBOL(DXSetResourceShareHandleNV
),
223 SYMBOL(DXOpenDeviceNV
),
224 SYMBOL(DXCloseDeviceNV
),
225 SYMBOL(DXRegisterObjectNV
),
226 SYMBOL(DXUnregisterObjectNV
),
227 SYMBOL(DXObjectAccessNV
),
228 SYMBOL(DXLockObjectsNV
),
229 SYMBOL(DXUnlockObjectsNV
),
231 if (!loader
.LoadSymbols(dxInteropSymbols
)) {
233 "WGL_NV_DX_interop2 announceed without supplying its functions.");
234 ClearSymbols(dxInteropSymbols
);
244 reporter
.SetSuccessful();
249 #undef END_OF_SYMBOLS
251 void WGLLibrary::Reset() {
253 (void)mSymbols
.fDeleteContext(mDummyGlrc
);
254 mDummyGlrc
= nullptr;
257 (void)ReleaseDC(mDummyWindow
, mRootDc
);
261 (void)DestroyWindow(mDummyWindow
);
262 mDummyWindow
= nullptr;
266 GLContextWGL::GLContextWGL(const GLContextDesc
& desc
, HDC aDC
, HGLRC aContext
,
268 : GLContext(desc
, nullptr, false),
275 GLContextWGL::GLContextWGL(const GLContextDesc
& desc
, HANDLE aPbuffer
, HDC aDC
,
276 HGLRC aContext
, int aPixelFormat
)
277 : GLContext(desc
, nullptr, false),
282 mPixelFormat(aPixelFormat
) {}
284 GLContextWGL::~GLContextWGL() {
287 (void)sWGLLib
.mSymbols
.fDeleteContext(mContext
);
290 (void)sWGLLib
.mSymbols
.fReleasePbufferDC(mPBuffer
, mDC
);
291 (void)sWGLLib
.mSymbols
.fDestroyPbuffer(mPBuffer
);
294 (void)ReleaseDC(mWnd
, mDC
);
299 bool GLContextWGL::MakeCurrentImpl() const {
300 const bool succeeded
= sWGLLib
.mSymbols
.fMakeCurrent(mDC
, mContext
);
301 NS_ASSERTION(succeeded
, "Failed to make GL context current!");
305 bool GLContextWGL::IsCurrentImpl() const {
306 return sWGLLib
.mSymbols
.fGetCurrentContext() == mContext
;
309 bool GLContextWGL::SwapBuffers() {
310 if (!mIsDoubleBuffered
) return false;
311 return ::SwapBuffers(mDC
);
314 void GLContextWGL::GetWSIInfo(nsCString
* const out
) const {
315 out
->AppendLiteral("wglGetExtensionsString: ");
316 out
->Append(sWGLLib
.mSymbols
.fGetExtensionsStringARB(mDC
));
320 WGLLibrary::CreateContextWithFallback(const HDC dc
,
321 const bool tryRobustBuffers
) const {
322 if (mHasRobustness
) {
323 if (tryRobustBuffers
) {
324 const int attribs
[] = {LOCAL_WGL_CONTEXT_FLAGS_ARB
,
325 LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB
,
326 LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB
,
327 LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB
, 0};
329 mSymbols
.fCreateContextAttribsARB(dc
, nullptr, attribs
);
330 if (context
) return context
;
333 const int attribs
[] = {LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB
,
334 LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB
, 0};
336 mSymbols
.fCreateContextAttribsARB(dc
, nullptr, attribs
);
337 if (context
) return context
;
339 if (mSymbols
.fCreateContextAttribsARB
) {
341 mSymbols
.fCreateContextAttribsARB(dc
, nullptr, nullptr);
342 if (context
) return context
;
344 return mSymbols
.fCreateContext(dc
);
347 static RefPtr
<GLContext
> CreateForWidget(const HWND window
,
348 const bool isWebRender
,
349 const bool requireAccelerated
) {
351 if (!wgl
.EnsureInitialized()) return nullptr;
353 const auto dc
= GetDC(window
);
354 if (!dc
) return nullptr;
355 auto cleanupDc
= MakeScopeExit([&]() { (void)ReleaseDC(window
, dc
); });
358 UINT foundFormats
= 0;
361 const int kAttribs
[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB
,
363 LOCAL_WGL_SUPPORT_OPENGL_ARB
,
365 LOCAL_WGL_DOUBLE_BUFFER_ARB
,
367 LOCAL_WGL_ACCELERATION_ARB
,
368 LOCAL_WGL_FULL_ACCELERATION_ARB
,
370 const int kAttribsForWebRender
[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB
,
372 LOCAL_WGL_SUPPORT_OPENGL_ARB
,
374 LOCAL_WGL_DOUBLE_BUFFER_ARB
,
376 LOCAL_WGL_DEPTH_BITS_ARB
,
378 LOCAL_WGL_ACCELERATION_ARB
,
379 LOCAL_WGL_FULL_ACCELERATION_ARB
,
383 attribs
= kAttribsForWebRender
;
388 if (!wgl
.mSymbols
.fChoosePixelFormat(wgl
.RootDc(), attribs
, nullptr, 1,
389 &chosenFormat
, &foundFormats
)) {
394 if (requireAccelerated
) return nullptr;
396 const int kAttribs
[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB
,
398 LOCAL_WGL_SUPPORT_OPENGL_ARB
,
400 LOCAL_WGL_DOUBLE_BUFFER_ARB
,
403 const int kAttribsForWebRender
[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB
,
405 LOCAL_WGL_SUPPORT_OPENGL_ARB
,
407 LOCAL_WGL_DOUBLE_BUFFER_ARB
,
409 LOCAL_WGL_DEPTH_BITS_ARB
,
415 attribs
= kAttribsForWebRender
;
420 if (!wgl
.mSymbols
.fChoosePixelFormat(wgl
.RootDc(), attribs
, nullptr, 1,
421 &chosenFormat
, &foundFormats
)) {
425 if (!foundFormats
) return nullptr;
427 // We need to make sure we call SetPixelFormat -after- calling
428 // EnsureInitialized, otherwise it can load/unload the dll and
429 // wglCreateContext will fail.
431 SetPixelFormat(dc
, chosenFormat
, nullptr);
432 const auto context
= sWGLLib
.CreateContextWithFallback(dc
, false);
433 if (!context
) return nullptr;
435 const RefPtr
<GLContextWGL
> gl
= new GLContextWGL({}, dc
, context
);
437 gl
->mIsDoubleBuffered
= true;
438 if (!gl
->Init()) return nullptr;
443 already_AddRefed
<GLContext
> GLContextProviderWGL::CreateForCompositorWidget(
444 CompositorWidget
* aCompositorWidget
, bool aHardwareWebRender
,
445 bool aForceAccelerated
) {
446 if (!aCompositorWidget
) {
450 return CreateForWidget(aCompositorWidget
->AsWindows()->GetHwnd(),
451 aHardwareWebRender
, aForceAccelerated
)
456 already_AddRefed
<GLContext
> GLContextProviderWGL::CreateHeadless(
457 const GLContextCreateDesc
& desc
, nsACString
* const out_failureId
) {
459 if (!wgl
.EnsureInitialized()) return nullptr;
462 UINT foundFormats
= 0;
465 const int kAttribs
[] = {LOCAL_WGL_DRAW_TO_PBUFFER_ARB
,
467 LOCAL_WGL_SUPPORT_OPENGL_ARB
,
469 LOCAL_WGL_ACCELERATION_ARB
,
470 LOCAL_WGL_FULL_ACCELERATION_ARB
,
472 if (!wgl
.mSymbols
.fChoosePixelFormat(wgl
.RootDc(), kAttribs
, nullptr, 1,
473 &chosenFormat
, &foundFormats
)) {
478 const int kAttribs
[] = {LOCAL_WGL_DRAW_TO_PBUFFER_ARB
, true,
479 LOCAL_WGL_SUPPORT_OPENGL_ARB
, true, 0};
480 if (!wgl
.mSymbols
.fChoosePixelFormat(wgl
.RootDc(), kAttribs
, nullptr, 1,
481 &chosenFormat
, &foundFormats
)) {
485 if (!foundFormats
) return nullptr;
486 const int kPbufferAttribs
[] = {0};
487 const auto pbuffer
= wgl
.mSymbols
.fCreatePbuffer(wgl
.RootDc(), chosenFormat
,
488 1, 1, kPbufferAttribs
);
489 if (!pbuffer
) return nullptr;
490 auto cleanupPbuffer
=
491 MakeScopeExit([&]() { (void)wgl
.mSymbols
.fDestroyPbuffer(pbuffer
); });
493 const auto dc
= wgl
.mSymbols
.fGetPbufferDC(pbuffer
);
494 if (!dc
) return nullptr;
495 auto cleanupDc
= MakeScopeExit(
496 [&]() { (void)wgl
.mSymbols
.fReleasePbufferDC(pbuffer
, dc
); });
498 const auto context
= wgl
.CreateContextWithFallback(dc
, true);
499 if (!context
) return nullptr;
501 const auto fullDesc
= GLContextDesc
{desc
, true};
502 const RefPtr
<GLContextWGL
> gl
=
503 new GLContextWGL(fullDesc
, pbuffer
, dc
, context
, chosenFormat
);
504 cleanupPbuffer
.release();
506 if (!gl
->Init()) return nullptr;
508 return RefPtr
<GLContext
>(gl
.get()).forget();
512 GLContext
* GLContextProviderWGL::GetGlobalContext() { return nullptr; }
515 void GLContextProviderWGL::Shutdown() {}
518 } /* namespace mozilla */