Bug 1771374 - Fix lint warnings. r=gfx-reviewers,aosmond
[gecko.git] / gfx / gl / GLContextProviderWGL.cpp
blobc174d250489563a2448f4fcbf24833f25d47b204
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"
9 #include "nsDebug.h"
10 #include "nsIWidget.h"
11 #include "gfxPlatform.h"
12 #include "gfxWindowsSurface.h"
14 #include "gfxCrashReporterUtils.h"
16 #include "prenv.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"
26 namespace mozilla {
27 namespace gl {
29 using namespace mozilla::gfx;
30 using namespace mozilla::widget;
32 WGLLibrary sWGLLib;
35 ScopedWindow::~ScopedWindow()
37 if (mDC) {
38 MOZ_ALWAYS_TRUE( ReleaseDC(mDC) );
40 if (mWindow) {
41 MOZ_ALWAYS_TRUE( DestroyWindow(mWindow) );
45 static HWND CreateDummyWindow() {
46 WNDCLASSW wc{};
47 if (!GetClassInfoW(GetModuleHandle(nullptr), L"GLContextWGLClass", &wc)) {
48 wc = {};
49 wc.style = CS_OWNDC;
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?
56 return nullptr;
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);
73 return ret;
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")) {
84 libGLFilename =
85 std::wstring(_wgetenv(L"SU_SPIES_DIRECTORY")) + L"\\opengl32.dll";
88 if (!mOGLLibrary) {
89 mOGLLibrary = LoadLibraryWithFlags(libGLFilename.c_str());
90 if (!mOGLLibrary) {
91 NS_WARNING("Couldn't load OpenGL library.");
92 return false;
96 #define SYMBOL(X) {(PRFuncPtr*)&mSymbols.f##X, {{"wgl" #X}}}
97 #define END_OF_SYMBOLS \
98 { \
99 nullptr, {} \
103 const auto loader = SymbolLoader(*mOGLLibrary);
104 const SymLoadStruct earlySymbols[] = {SYMBOL(CreateContext),
105 SYMBOL(MakeCurrent),
106 SYMBOL(GetProcAddress),
107 SYMBOL(DeleteContext),
108 SYMBOL(GetCurrentContext),
109 SYMBOL(GetCurrentDC),
110 END_OF_SYMBOLS};
112 if (!loader.LoadSymbols(earlySymbols)) {
113 NS_WARNING(
114 "Couldn't find required entry points in OpenGL DLL (early init)");
115 return false;
119 mDummyWindow = CreateDummyWindow();
120 MOZ_ASSERT(mDummyWindow);
121 if (!mDummyWindow) return false;
122 auto cleanup = MakeScopeExit([&]() { Reset(); });
124 mRootDc = GetDC(mDummyWindow);
125 MOZ_ASSERT(mRootDc);
126 if (!mRootDc) return false;
128 // --
131 PIXELFORMATDESCRIPTOR pfd{};
132 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
133 pfd.nVersion = 1;
134 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
135 // pfd.iPixelType = PFD_TYPE_RGBA;
136 // pfd.cColorBits = 24;
137 // pfd.cRedBits = 8;
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;
151 // --
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");
162 return false;
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.
171 // clang-format off
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),
182 END_OF_SYMBOLS
184 // clang-format on
185 if (!loader.LoadSymbols(reqExtSymbols)) {
186 NS_WARNING("reqExtSymbols missing");
187 return false;
190 // --
192 const auto extString = mSymbols.fGetExtensionsStringARB(mRootDc);
193 MOZ_ASSERT(extString);
194 MOZ_ASSERT(HasExtension(extString, "WGL_ARB_extensions_string"));
196 // --
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;
205 } else {
206 NS_ERROR(
207 "WGL_ARB_create_context announced without supplying its functions.");
208 ClearSymbols(createContextSymbols);
212 // --
214 bool hasDXInterop2 = HasExtension(extString, "WGL_NV_DX_interop2");
215 if (gfxVars::DXInterop2Blocked() &&
216 !StaticPrefs::gl_ignore_dx_interop2_blacklist()) {
217 hasDXInterop2 = false;
220 if (hasDXInterop2) {
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),
230 END_OF_SYMBOLS};
231 if (!loader.LoadSymbols(dxInteropSymbols)) {
232 NS_ERROR(
233 "WGL_NV_DX_interop2 announceed without supplying its functions.");
234 ClearSymbols(dxInteropSymbols);
238 // --
240 cleanup.release();
242 mInitialized = true;
244 reporter.SetSuccessful();
245 return true;
248 #undef SYMBOL
249 #undef END_OF_SYMBOLS
251 void WGLLibrary::Reset() {
252 if (mDummyGlrc) {
253 (void)mSymbols.fDeleteContext(mDummyGlrc);
254 mDummyGlrc = nullptr;
256 if (mRootDc) {
257 (void)ReleaseDC(mDummyWindow, mRootDc);
258 mRootDc = nullptr;
260 if (mDummyWindow) {
261 (void)DestroyWindow(mDummyWindow);
262 mDummyWindow = nullptr;
266 GLContextWGL::GLContextWGL(const GLContextDesc& desc, HDC aDC, HGLRC aContext,
267 HWND aWindow)
268 : GLContext(desc, nullptr, false),
269 mDC(aDC),
270 mContext(aContext),
271 mWnd(aWindow),
272 mPBuffer(nullptr),
273 mPixelFormat(0) {}
275 GLContextWGL::GLContextWGL(const GLContextDesc& desc, HANDLE aPbuffer, HDC aDC,
276 HGLRC aContext, int aPixelFormat)
277 : GLContext(desc, nullptr, false),
278 mDC(aDC),
279 mContext(aContext),
280 mWnd(nullptr),
281 mPBuffer(aPbuffer),
282 mPixelFormat(aPixelFormat) {}
284 GLContextWGL::~GLContextWGL() {
285 MarkDestroyed();
287 (void)sWGLLib.mSymbols.fDeleteContext(mContext);
289 if (mPBuffer) {
290 (void)sWGLLib.mSymbols.fReleasePbufferDC(mPBuffer, mDC);
291 (void)sWGLLib.mSymbols.fDestroyPbuffer(mPBuffer);
293 if (mWnd) {
294 (void)ReleaseDC(mWnd, mDC);
295 DestroyWindow(mWnd);
299 bool GLContextWGL::MakeCurrentImpl() const {
300 const bool succeeded = sWGLLib.mSymbols.fMakeCurrent(mDC, mContext);
301 NS_ASSERTION(succeeded, "Failed to make GL context current!");
302 return succeeded;
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));
319 HGLRC
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};
328 const auto context =
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};
335 const auto context =
336 mSymbols.fCreateContextAttribsARB(dc, nullptr, attribs);
337 if (context) return context;
339 if (mSymbols.fCreateContextAttribsARB) {
340 const auto context =
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) {
350 auto& wgl = sWGLLib;
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); });
357 int chosenFormat;
358 UINT foundFormats = 0;
360 if (!foundFormats) {
361 const int kAttribs[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB,
362 true,
363 LOCAL_WGL_SUPPORT_OPENGL_ARB,
364 true,
365 LOCAL_WGL_DOUBLE_BUFFER_ARB,
366 true,
367 LOCAL_WGL_ACCELERATION_ARB,
368 LOCAL_WGL_FULL_ACCELERATION_ARB,
370 const int kAttribsForWebRender[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB,
371 true,
372 LOCAL_WGL_SUPPORT_OPENGL_ARB,
373 true,
374 LOCAL_WGL_DOUBLE_BUFFER_ARB,
375 true,
376 LOCAL_WGL_DEPTH_BITS_ARB,
378 LOCAL_WGL_ACCELERATION_ARB,
379 LOCAL_WGL_FULL_ACCELERATION_ARB,
381 const int* attribs;
382 if (isWebRender) {
383 attribs = kAttribsForWebRender;
384 } else {
385 attribs = kAttribs;
388 if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), attribs, nullptr, 1,
389 &chosenFormat, &foundFormats)) {
390 foundFormats = 0;
393 if (!foundFormats) {
394 if (requireAccelerated) return nullptr;
396 const int kAttribs[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB,
397 true,
398 LOCAL_WGL_SUPPORT_OPENGL_ARB,
399 true,
400 LOCAL_WGL_DOUBLE_BUFFER_ARB,
401 true,
403 const int kAttribsForWebRender[] = {LOCAL_WGL_DRAW_TO_WINDOW_ARB,
404 true,
405 LOCAL_WGL_SUPPORT_OPENGL_ARB,
406 true,
407 LOCAL_WGL_DOUBLE_BUFFER_ARB,
408 true,
409 LOCAL_WGL_DEPTH_BITS_ARB,
413 const int* attribs;
414 if (isWebRender) {
415 attribs = kAttribsForWebRender;
416 } else {
417 attribs = kAttribs;
420 if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), attribs, nullptr, 1,
421 &chosenFormat, &foundFormats)) {
422 foundFormats = 0;
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);
436 cleanupDc.release();
437 gl->mIsDoubleBuffered = true;
438 if (!gl->Init()) return nullptr;
440 return gl;
443 already_AddRefed<GLContext> GLContextProviderWGL::CreateForCompositorWidget(
444 CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
445 bool aForceAccelerated) {
446 if (!aCompositorWidget) {
447 MOZ_ASSERT(false);
448 return nullptr;
450 return CreateForWidget(aCompositorWidget->AsWindows()->GetHwnd(),
451 aHardwareWebRender, aForceAccelerated)
452 .forget();
455 /*static*/
456 already_AddRefed<GLContext> GLContextProviderWGL::CreateHeadless(
457 const GLContextCreateDesc& desc, nsACString* const out_failureId) {
458 auto& wgl = sWGLLib;
459 if (!wgl.EnsureInitialized()) return nullptr;
461 int chosenFormat;
462 UINT foundFormats = 0;
464 if (!foundFormats) {
465 const int kAttribs[] = {LOCAL_WGL_DRAW_TO_PBUFFER_ARB,
466 true,
467 LOCAL_WGL_SUPPORT_OPENGL_ARB,
468 true,
469 LOCAL_WGL_ACCELERATION_ARB,
470 LOCAL_WGL_FULL_ACCELERATION_ARB,
472 if (!wgl.mSymbols.fChoosePixelFormat(wgl.RootDc(), kAttribs, nullptr, 1,
473 &chosenFormat, &foundFormats)) {
474 foundFormats = 0;
477 if (!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)) {
482 foundFormats = 0;
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();
505 cleanupDc.release();
506 if (!gl->Init()) return nullptr;
508 return RefPtr<GLContext>(gl.get()).forget();
511 /*static*/
512 GLContext* GLContextProviderWGL::GetGlobalContext() { return nullptr; }
514 /*static*/
515 void GLContextProviderWGL::Shutdown() {}
517 } /* namespace gl */
518 } /* namespace mozilla */