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