|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
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/Preferences.h" |
|
19 |
|
20 using namespace mozilla::gfx; |
|
21 |
|
22 namespace mozilla { |
|
23 namespace gl { |
|
24 |
|
25 WGLLibrary sWGLLib; |
|
26 |
|
27 HWND |
|
28 WGLLibrary::CreateDummyWindow(HDC *aWindowDC) |
|
29 { |
|
30 WNDCLASSW wc; |
|
31 if (!GetClassInfoW(GetModuleHandle(nullptr), L"GLContextWGLClass", &wc)) { |
|
32 ZeroMemory(&wc, sizeof(WNDCLASSW)); |
|
33 wc.style = CS_OWNDC; |
|
34 wc.hInstance = GetModuleHandle(nullptr); |
|
35 wc.lpfnWndProc = DefWindowProc; |
|
36 wc.lpszClassName = L"GLContextWGLClass"; |
|
37 if (!RegisterClassW(&wc)) { |
|
38 NS_WARNING("Failed to register GLContextWGLClass?!"); |
|
39 // er. failed to register our class? |
|
40 return nullptr; |
|
41 } |
|
42 } |
|
43 |
|
44 HWND win = CreateWindowW(L"GLContextWGLClass", L"GLContextWGL", 0, |
|
45 0, 0, 16, 16, |
|
46 nullptr, nullptr, GetModuleHandle(nullptr), |
|
47 nullptr); |
|
48 NS_ENSURE_TRUE(win, nullptr); |
|
49 |
|
50 HDC dc = GetDC(win); |
|
51 NS_ENSURE_TRUE(dc, nullptr); |
|
52 |
|
53 if (mWindowPixelFormat == 0) { |
|
54 PIXELFORMATDESCRIPTOR pfd; |
|
55 ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR)); |
|
56 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); |
|
57 pfd.nVersion = 1; |
|
58 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; |
|
59 pfd.iPixelType = PFD_TYPE_RGBA; |
|
60 pfd.cColorBits = 24; |
|
61 pfd.cRedBits = 8; |
|
62 pfd.cGreenBits = 8; |
|
63 pfd.cBlueBits = 8; |
|
64 pfd.cAlphaBits = 8; |
|
65 pfd.cDepthBits = 0; |
|
66 pfd.iLayerType = PFD_MAIN_PLANE; |
|
67 |
|
68 mWindowPixelFormat = ChoosePixelFormat(dc, &pfd); |
|
69 } |
|
70 |
|
71 if (!mWindowPixelFormat || |
|
72 !SetPixelFormat(dc, mWindowPixelFormat, nullptr)) |
|
73 { |
|
74 NS_WARNING("SetPixelFormat failed!"); |
|
75 DestroyWindow(win); |
|
76 return nullptr; |
|
77 } |
|
78 |
|
79 if (aWindowDC) { |
|
80 *aWindowDC = dc; |
|
81 } |
|
82 |
|
83 return win; |
|
84 } |
|
85 |
|
86 static inline bool |
|
87 HasExtension(const char* aExtensions, const char* aRequiredExtension) |
|
88 { |
|
89 return GLContext::ListHasExtension( |
|
90 reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension); |
|
91 } |
|
92 |
|
93 bool |
|
94 WGLLibrary::EnsureInitialized() |
|
95 { |
|
96 if (mInitialized) |
|
97 return true; |
|
98 |
|
99 mozilla::ScopedGfxFeatureReporter reporter("WGL"); |
|
100 |
|
101 std::string libGLFilename = "Opengl32.dll"; |
|
102 // SU_SPIES_DIRECTORY is for AMD CodeXL/gDEBugger |
|
103 if (PR_GetEnv("SU_SPIES_DIRECTORY")) { |
|
104 libGLFilename = std::string(PR_GetEnv("SU_SPIES_DIRECTORY")) + "\\opengl32.dll"; |
|
105 } |
|
106 |
|
107 if (!mOGLLibrary) { |
|
108 mOGLLibrary = PR_LoadLibrary(&libGLFilename[0]); |
|
109 if (!mOGLLibrary) { |
|
110 NS_WARNING("Couldn't load OpenGL library."); |
|
111 return false; |
|
112 } |
|
113 } |
|
114 |
|
115 GLLibraryLoader::SymLoadStruct earlySymbols[] = { |
|
116 { (PRFuncPtr*) &fCreateContext, { "wglCreateContext", nullptr } }, |
|
117 { (PRFuncPtr*) &fMakeCurrent, { "wglMakeCurrent", nullptr } }, |
|
118 { (PRFuncPtr*) &fGetProcAddress, { "wglGetProcAddress", nullptr } }, |
|
119 { (PRFuncPtr*) &fDeleteContext, { "wglDeleteContext", nullptr } }, |
|
120 { (PRFuncPtr*) &fGetCurrentContext, { "wglGetCurrentContext", nullptr } }, |
|
121 { (PRFuncPtr*) &fGetCurrentDC, { "wglGetCurrentDC", nullptr } }, |
|
122 { (PRFuncPtr*) &fShareLists, { "wglShareLists", nullptr } }, |
|
123 { nullptr, { nullptr } } |
|
124 }; |
|
125 |
|
126 if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &earlySymbols[0])) { |
|
127 NS_WARNING("Couldn't find required entry points in OpenGL DLL (early init)"); |
|
128 return false; |
|
129 } |
|
130 |
|
131 // This is ridiculous -- we have to actually create a context to |
|
132 // get the OpenGL ICD to load. |
|
133 mWindow = CreateDummyWindow(&mWindowDC); |
|
134 NS_ENSURE_TRUE(mWindow, false); |
|
135 |
|
136 // create rendering context |
|
137 mWindowGLContext = fCreateContext(mWindowDC); |
|
138 NS_ENSURE_TRUE(mWindowGLContext, false); |
|
139 |
|
140 HGLRC curCtx = fGetCurrentContext(); |
|
141 HDC curDC = fGetCurrentDC(); |
|
142 |
|
143 if (!fMakeCurrent((HDC)mWindowDC, (HGLRC)mWindowGLContext)) { |
|
144 NS_WARNING("wglMakeCurrent failed"); |
|
145 return false; |
|
146 } |
|
147 |
|
148 // Now we can grab all the other symbols that we couldn't without having |
|
149 // a context current. |
|
150 |
|
151 GLLibraryLoader::SymLoadStruct pbufferSymbols[] = { |
|
152 { (PRFuncPtr*) &fCreatePbuffer, { "wglCreatePbufferARB", "wglCreatePbufferEXT", nullptr } }, |
|
153 { (PRFuncPtr*) &fDestroyPbuffer, { "wglDestroyPbufferARB", "wglDestroyPbufferEXT", nullptr } }, |
|
154 { (PRFuncPtr*) &fGetPbufferDC, { "wglGetPbufferDCARB", "wglGetPbufferDCEXT", nullptr } }, |
|
155 { (PRFuncPtr*) &fBindTexImage, { "wglBindTexImageARB", "wglBindTexImageEXT", nullptr } }, |
|
156 { (PRFuncPtr*) &fReleaseTexImage, { "wglReleaseTexImageARB", "wglReleaseTexImageEXT", nullptr } }, |
|
157 { nullptr, { nullptr } } |
|
158 }; |
|
159 |
|
160 GLLibraryLoader::SymLoadStruct pixFmtSymbols[] = { |
|
161 { (PRFuncPtr*) &fChoosePixelFormat, { "wglChoosePixelFormatARB", "wglChoosePixelFormatEXT", nullptr } }, |
|
162 { (PRFuncPtr*) &fGetPixelFormatAttribiv, { "wglGetPixelFormatAttribivARB", "wglGetPixelFormatAttribivEXT", nullptr } }, |
|
163 { nullptr, { nullptr } } |
|
164 }; |
|
165 |
|
166 if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &pbufferSymbols[0], |
|
167 (GLLibraryLoader::PlatformLookupFunction)fGetProcAddress)) |
|
168 { |
|
169 // this isn't an error, just means that pbuffers aren't supported |
|
170 fCreatePbuffer = nullptr; |
|
171 } |
|
172 |
|
173 if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &pixFmtSymbols[0], |
|
174 (GLLibraryLoader::PlatformLookupFunction)fGetProcAddress)) |
|
175 { |
|
176 // this isn't an error, just means that we don't have the pixel format extension |
|
177 fChoosePixelFormat = nullptr; |
|
178 } |
|
179 |
|
180 GLLibraryLoader::SymLoadStruct extensionsSymbols[] = { |
|
181 { (PRFuncPtr *) &fGetExtensionsString, { "wglGetExtensionsStringARB", nullptr} }, |
|
182 { nullptr, { nullptr } } |
|
183 }; |
|
184 |
|
185 GLLibraryLoader::SymLoadStruct robustnessSymbols[] = { |
|
186 { (PRFuncPtr *) &fCreateContextAttribs, { "wglCreateContextAttribsARB", nullptr} }, |
|
187 { nullptr, { nullptr } } |
|
188 }; |
|
189 |
|
190 if (GLLibraryLoader::LoadSymbols(mOGLLibrary, &extensionsSymbols[0], |
|
191 (GLLibraryLoader::PlatformLookupFunction)fGetProcAddress)) { |
|
192 const char *wglExts = fGetExtensionsString(mWindowDC); |
|
193 if (wglExts && HasExtension(wglExts, "WGL_ARB_create_context")) { |
|
194 GLLibraryLoader::LoadSymbols(mOGLLibrary, &robustnessSymbols[0], |
|
195 (GLLibraryLoader::PlatformLookupFunction)fGetProcAddress); |
|
196 if (HasExtension(wglExts, "WGL_ARB_create_context_robustness")) { |
|
197 mHasRobustness = true; |
|
198 } |
|
199 } |
|
200 } |
|
201 |
|
202 // reset back to the previous context, just in case |
|
203 fMakeCurrent(curDC, curCtx); |
|
204 |
|
205 if (mHasRobustness) { |
|
206 fDeleteContext(mWindowGLContext); |
|
207 |
|
208 int attribs[] = { |
|
209 LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, |
|
210 LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, |
|
211 0 |
|
212 }; |
|
213 |
|
214 mWindowGLContext = fCreateContextAttribs(mWindowDC, nullptr, attribs); |
|
215 if (!mWindowGLContext) { |
|
216 mHasRobustness = false; |
|
217 mWindowGLContext = fCreateContext(mWindowDC); |
|
218 } |
|
219 } |
|
220 |
|
221 mInitialized = true; |
|
222 |
|
223 // Call this to create the global GLContext instance, |
|
224 // and to check for errors. Note that this must happen /after/ |
|
225 // setting mInitialized to TRUE, or an infinite loop results. |
|
226 if (GLContextProviderWGL::GetGlobalContext() == nullptr) { |
|
227 mInitialized = false; |
|
228 return false; |
|
229 } |
|
230 |
|
231 reporter.SetSuccessful(); |
|
232 return true; |
|
233 } |
|
234 |
|
235 GLContextWGL::GLContextWGL( |
|
236 const SurfaceCaps& caps, |
|
237 GLContext* sharedContext, |
|
238 bool isOffscreen, |
|
239 HDC aDC, |
|
240 HGLRC aContext, |
|
241 HWND aWindow) |
|
242 : GLContext(caps, sharedContext, isOffscreen), |
|
243 mDC(aDC), |
|
244 mContext(aContext), |
|
245 mWnd(aWindow), |
|
246 mPBuffer(nullptr), |
|
247 mPixelFormat(0), |
|
248 mIsDoubleBuffered(false) |
|
249 { |
|
250 // See 899855 |
|
251 SetProfileVersion(ContextProfile::OpenGLCompatibility, 200); |
|
252 } |
|
253 |
|
254 GLContextWGL::GLContextWGL( |
|
255 const SurfaceCaps& caps, |
|
256 GLContext* sharedContext, |
|
257 bool isOffscreen, |
|
258 HANDLE aPbuffer, |
|
259 HDC aDC, |
|
260 HGLRC aContext, |
|
261 int aPixelFormat) |
|
262 : GLContext(caps, sharedContext, isOffscreen), |
|
263 mDC(aDC), |
|
264 mContext(aContext), |
|
265 mWnd(nullptr), |
|
266 mPBuffer(aPbuffer), |
|
267 mPixelFormat(aPixelFormat), |
|
268 mIsDoubleBuffered(false) |
|
269 { |
|
270 // See 899855 |
|
271 SetProfileVersion(ContextProfile::OpenGLCompatibility, 200); |
|
272 } |
|
273 |
|
274 GLContextWGL::~GLContextWGL() |
|
275 { |
|
276 MarkDestroyed(); |
|
277 |
|
278 sWGLLib.fDeleteContext(mContext); |
|
279 |
|
280 if (mPBuffer) |
|
281 sWGLLib.fDestroyPbuffer(mPBuffer); |
|
282 if (mWnd) |
|
283 DestroyWindow(mWnd); |
|
284 } |
|
285 |
|
286 bool |
|
287 GLContextWGL::Init() |
|
288 { |
|
289 if (!mDC || !mContext) |
|
290 return false; |
|
291 |
|
292 // see bug 929506 comment 29. wglGetProcAddress requires a current context. |
|
293 if (!sWGLLib.fMakeCurrent(mDC, mContext)) |
|
294 return false; |
|
295 |
|
296 SetupLookupFunction(); |
|
297 if (!InitWithPrefix("gl", true)) |
|
298 return false; |
|
299 |
|
300 return true; |
|
301 } |
|
302 |
|
303 bool |
|
304 GLContextWGL::MakeCurrentImpl(bool aForce) |
|
305 { |
|
306 BOOL succeeded = true; |
|
307 |
|
308 // wglGetCurrentContext seems to just pull the HGLRC out |
|
309 // of its TLS slot, so no need to do our own tls slot. |
|
310 // You would think that wglMakeCurrent would avoid doing |
|
311 // work if mContext was already current, but not so much.. |
|
312 if (aForce || sWGLLib.fGetCurrentContext() != mContext) { |
|
313 succeeded = sWGLLib.fMakeCurrent(mDC, mContext); |
|
314 NS_ASSERTION(succeeded, "Failed to make GL context current!"); |
|
315 } |
|
316 |
|
317 return succeeded; |
|
318 } |
|
319 |
|
320 bool |
|
321 GLContextWGL::IsCurrent() |
|
322 { |
|
323 return sWGLLib.fGetCurrentContext() == mContext; |
|
324 } |
|
325 |
|
326 void |
|
327 GLContextWGL::SetIsDoubleBuffered(bool aIsDB) |
|
328 { |
|
329 mIsDoubleBuffered = aIsDB; |
|
330 } |
|
331 |
|
332 bool |
|
333 GLContextWGL::IsDoubleBuffered() const |
|
334 { |
|
335 return mIsDoubleBuffered; |
|
336 } |
|
337 |
|
338 bool |
|
339 GLContextWGL::SupportsRobustness() const |
|
340 { |
|
341 return sWGLLib.HasRobustness(); |
|
342 } |
|
343 |
|
344 bool |
|
345 GLContextWGL::SwapBuffers() { |
|
346 if (!mIsDoubleBuffered) |
|
347 return false; |
|
348 return ::SwapBuffers(mDC); |
|
349 } |
|
350 |
|
351 bool |
|
352 GLContextWGL::SetupLookupFunction() |
|
353 { |
|
354 // Make sure that we have a ref to the OGL library; |
|
355 // when run under CodeXL, wglGetProcAddress won't return |
|
356 // the right thing for some core functions. |
|
357 MOZ_ASSERT(mLibrary == nullptr); |
|
358 |
|
359 mLibrary = sWGLLib.GetOGLLibrary(); |
|
360 mLookupFunc = (PlatformLookupFunction)sWGLLib.fGetProcAddress; |
|
361 return true; |
|
362 } |
|
363 |
|
364 static bool |
|
365 GetMaxSize(HDC hDC, int format, gfxIntSize& size) |
|
366 { |
|
367 int query[] = {LOCAL_WGL_MAX_PBUFFER_WIDTH_ARB, LOCAL_WGL_MAX_PBUFFER_HEIGHT_ARB}; |
|
368 int result[2]; |
|
369 |
|
370 // (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int* piAttributes, int *piValues) |
|
371 if (!sWGLLib.fGetPixelFormatAttribiv(hDC, format, 0, 2, query, result)) |
|
372 return false; |
|
373 |
|
374 size.width = result[0]; |
|
375 size.height = result[1]; |
|
376 return true; |
|
377 } |
|
378 |
|
379 static bool |
|
380 IsValidSizeForFormat(HDC hDC, int format, |
|
381 const gfxIntSize& requested) |
|
382 { |
|
383 gfxIntSize max; |
|
384 if (!GetMaxSize(hDC, format, max)) |
|
385 return true; |
|
386 |
|
387 if (requested.width > max.width) |
|
388 return false; |
|
389 if (requested.height > max.height) |
|
390 return false; |
|
391 |
|
392 return true; |
|
393 } |
|
394 |
|
395 static GLContextWGL * |
|
396 GetGlobalContextWGL() |
|
397 { |
|
398 return static_cast<GLContextWGL*>(GLContextProviderWGL::GetGlobalContext()); |
|
399 } |
|
400 |
|
401 already_AddRefed<GLContext> |
|
402 GLContextProviderWGL::CreateWrappingExisting(void*, void*) |
|
403 { |
|
404 return nullptr; |
|
405 } |
|
406 |
|
407 already_AddRefed<GLContext> |
|
408 GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget) |
|
409 { |
|
410 if (!sWGLLib.EnsureInitialized()) { |
|
411 return nullptr; |
|
412 } |
|
413 |
|
414 /** |
|
415 * We need to make sure we call SetPixelFormat -after- calling |
|
416 * EnsureInitialized, otherwise it can load/unload the dll and |
|
417 * wglCreateContext will fail. |
|
418 */ |
|
419 |
|
420 HDC dc = (HDC)aWidget->GetNativeData(NS_NATIVE_GRAPHIC); |
|
421 |
|
422 SetPixelFormat(dc, sWGLLib.GetWindowPixelFormat(), nullptr); |
|
423 HGLRC context; |
|
424 |
|
425 GLContextWGL *shareContext = GetGlobalContextWGL(); |
|
426 |
|
427 if (sWGLLib.HasRobustness()) { |
|
428 int attribs[] = { |
|
429 LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, |
|
430 LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, |
|
431 0 |
|
432 }; |
|
433 |
|
434 context = sWGLLib.fCreateContextAttribs(dc, |
|
435 shareContext ? shareContext->Context() : nullptr, |
|
436 attribs); |
|
437 } else { |
|
438 context = sWGLLib.fCreateContext(dc); |
|
439 if (context && |
|
440 shareContext && |
|
441 !sWGLLib.fShareLists(shareContext->Context(), context)) |
|
442 { |
|
443 printf_stderr("WGL context creation failed for window: wglShareLists returned false!"); |
|
444 sWGLLib.fDeleteContext(context); |
|
445 context = nullptr; |
|
446 } |
|
447 } |
|
448 |
|
449 if (!context) { |
|
450 return nullptr; |
|
451 } |
|
452 |
|
453 SurfaceCaps caps = SurfaceCaps::ForRGBA(); |
|
454 nsRefPtr<GLContextWGL> glContext = new GLContextWGL(caps, |
|
455 shareContext, |
|
456 false, |
|
457 dc, |
|
458 context); |
|
459 if (!glContext->Init()) { |
|
460 return nullptr; |
|
461 } |
|
462 |
|
463 glContext->SetIsDoubleBuffered(true); |
|
464 |
|
465 return glContext.forget(); |
|
466 } |
|
467 |
|
468 static already_AddRefed<GLContextWGL> |
|
469 CreatePBufferOffscreenContext(const gfxIntSize& aSize, |
|
470 GLContextWGL *aShareContext) |
|
471 { |
|
472 WGLLibrary& wgl = sWGLLib; |
|
473 |
|
474 #define A1(_a,_x) do { _a.AppendElement(_x); } while(0) |
|
475 #define A2(_a,_x,_y) do { _a.AppendElement(_x); _a.AppendElement(_y); } while(0) |
|
476 |
|
477 nsTArray<int> attrs; |
|
478 |
|
479 A2(attrs, LOCAL_WGL_SUPPORT_OPENGL_ARB, LOCAL_GL_TRUE); |
|
480 A2(attrs, LOCAL_WGL_DRAW_TO_PBUFFER_ARB, LOCAL_GL_TRUE); |
|
481 A2(attrs, LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE); |
|
482 |
|
483 A2(attrs, LOCAL_WGL_ACCELERATION_ARB, LOCAL_WGL_FULL_ACCELERATION_ARB); |
|
484 |
|
485 A2(attrs, LOCAL_WGL_DOUBLE_BUFFER_ARB, LOCAL_GL_FALSE); |
|
486 A2(attrs, LOCAL_WGL_STEREO_ARB, LOCAL_GL_FALSE); |
|
487 |
|
488 A1(attrs, 0); |
|
489 |
|
490 nsTArray<int> pbattrs; |
|
491 A1(pbattrs, 0); |
|
492 |
|
493 #undef A1 |
|
494 #undef A2 |
|
495 |
|
496 // We only need one! |
|
497 UINT numFormats = 1; |
|
498 int formats[1]; |
|
499 HDC windowDC = wgl.GetWindowDC(); |
|
500 if (!wgl.fChoosePixelFormat(windowDC, |
|
501 attrs.Elements(), nullptr, |
|
502 numFormats, formats, &numFormats) |
|
503 || numFormats == 0) |
|
504 { |
|
505 return nullptr; |
|
506 } |
|
507 |
|
508 // We don't care; just pick the first one. |
|
509 int chosenFormat = formats[0]; |
|
510 if (!IsValidSizeForFormat(windowDC, chosenFormat, aSize)) |
|
511 return nullptr; |
|
512 |
|
513 HANDLE pbuffer = wgl.fCreatePbuffer(windowDC, chosenFormat, |
|
514 aSize.width, aSize.height, |
|
515 pbattrs.Elements()); |
|
516 if (!pbuffer) { |
|
517 return nullptr; |
|
518 } |
|
519 |
|
520 HDC pbdc = wgl.fGetPbufferDC(pbuffer); |
|
521 NS_ASSERTION(pbdc, "expected a dc"); |
|
522 |
|
523 HGLRC context; |
|
524 if (wgl.HasRobustness()) { |
|
525 int attribs[] = { |
|
526 LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, |
|
527 LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, |
|
528 0 |
|
529 }; |
|
530 |
|
531 context = wgl.fCreateContextAttribs(pbdc, aShareContext->Context(), attribs); |
|
532 } else { |
|
533 context = wgl.fCreateContext(pbdc); |
|
534 if (context && aShareContext) { |
|
535 if (!wgl.fShareLists(aShareContext->Context(), context)) { |
|
536 wgl.fDeleteContext(context); |
|
537 context = nullptr; |
|
538 printf_stderr("ERROR - creating pbuffer context failed because wglShareLists returned FALSE"); |
|
539 } |
|
540 } |
|
541 } |
|
542 |
|
543 if (!context) { |
|
544 wgl.fDestroyPbuffer(pbuffer); |
|
545 return nullptr; |
|
546 } |
|
547 |
|
548 SurfaceCaps dummyCaps = SurfaceCaps::Any(); |
|
549 nsRefPtr<GLContextWGL> glContext = new GLContextWGL(dummyCaps, |
|
550 aShareContext, |
|
551 true, |
|
552 pbuffer, |
|
553 pbdc, |
|
554 context, |
|
555 chosenFormat); |
|
556 |
|
557 return glContext.forget(); |
|
558 } |
|
559 |
|
560 static already_AddRefed<GLContextWGL> |
|
561 CreateWindowOffscreenContext() |
|
562 { |
|
563 // CreateWindowOffscreenContext must return a global-shared context |
|
564 GLContextWGL *shareContext = GetGlobalContextWGL(); |
|
565 if (!shareContext) { |
|
566 return nullptr; |
|
567 } |
|
568 |
|
569 HDC dc; |
|
570 HWND win = sWGLLib.CreateDummyWindow(&dc); |
|
571 if (!win) { |
|
572 return nullptr; |
|
573 } |
|
574 |
|
575 HGLRC context = sWGLLib.fCreateContext(dc); |
|
576 if (sWGLLib.HasRobustness()) { |
|
577 int attribs[] = { |
|
578 LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB, |
|
579 LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB, |
|
580 0 |
|
581 }; |
|
582 |
|
583 context = sWGLLib.fCreateContextAttribs(dc, shareContext->Context(), attribs); |
|
584 } else { |
|
585 context = sWGLLib.fCreateContext(dc); |
|
586 if (context && shareContext && |
|
587 !sWGLLib.fShareLists(shareContext->Context(), context)) |
|
588 { |
|
589 NS_WARNING("wglShareLists failed!"); |
|
590 |
|
591 sWGLLib.fDeleteContext(context); |
|
592 DestroyWindow(win); |
|
593 return nullptr; |
|
594 } |
|
595 } |
|
596 |
|
597 if (!context) { |
|
598 return nullptr; |
|
599 } |
|
600 |
|
601 SurfaceCaps caps = SurfaceCaps::ForRGBA(); |
|
602 nsRefPtr<GLContextWGL> glContext = new GLContextWGL(caps, |
|
603 shareContext, true, |
|
604 dc, context, win); |
|
605 |
|
606 return glContext.forget(); |
|
607 } |
|
608 |
|
609 already_AddRefed<GLContext> |
|
610 GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size, |
|
611 const SurfaceCaps& caps) |
|
612 { |
|
613 if (!sWGLLib.EnsureInitialized()) { |
|
614 return nullptr; |
|
615 } |
|
616 |
|
617 nsRefPtr<GLContextWGL> glContext; |
|
618 |
|
619 // Always try to create a pbuffer context first, because we |
|
620 // want the context isolation. |
|
621 if (sWGLLib.fCreatePbuffer && |
|
622 sWGLLib.fChoosePixelFormat) |
|
623 { |
|
624 gfxIntSize dummySize = gfxIntSize(16, 16); |
|
625 glContext = CreatePBufferOffscreenContext(dummySize, GetGlobalContextWGL()); |
|
626 } |
|
627 |
|
628 // If it failed, then create a window context and use a FBO. |
|
629 if (!glContext) { |
|
630 glContext = CreateWindowOffscreenContext(); |
|
631 } |
|
632 |
|
633 if (!glContext || |
|
634 !glContext->Init()) |
|
635 { |
|
636 return nullptr; |
|
637 } |
|
638 |
|
639 if (!glContext->InitOffscreen(ToIntSize(size), caps)) |
|
640 return nullptr; |
|
641 |
|
642 return glContext.forget(); |
|
643 } |
|
644 |
|
645 static nsRefPtr<GLContextWGL> gGlobalContext; |
|
646 |
|
647 GLContext * |
|
648 GLContextProviderWGL::GetGlobalContext() |
|
649 { |
|
650 if (!sWGLLib.EnsureInitialized()) { |
|
651 return nullptr; |
|
652 } |
|
653 |
|
654 static bool triedToCreateContext = false; |
|
655 |
|
656 if (!triedToCreateContext && !gGlobalContext) { |
|
657 triedToCreateContext = true; |
|
658 |
|
659 // conveniently, we already have what we need... |
|
660 SurfaceCaps dummyCaps = SurfaceCaps::Any(); |
|
661 gGlobalContext = new GLContextWGL(dummyCaps, |
|
662 nullptr, true, |
|
663 sWGLLib.GetWindowDC(), |
|
664 sWGLLib.GetWindowGLContext()); |
|
665 if (!gGlobalContext->Init()) { |
|
666 NS_WARNING("Global context GLContext initialization failed?"); |
|
667 gGlobalContext = nullptr; |
|
668 return nullptr; |
|
669 } |
|
670 } |
|
671 |
|
672 return static_cast<GLContext*>(gGlobalContext); |
|
673 } |
|
674 |
|
675 void |
|
676 GLContextProviderWGL::Shutdown() |
|
677 { |
|
678 gGlobalContext = nullptr; |
|
679 } |
|
680 |
|
681 } /* namespace gl */ |
|
682 } /* namespace mozilla */ |