diff --git a/src/bgfx.cpp b/src/bgfx.cpp index 0263f96d5..911ec9d05 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -2476,6 +2476,11 @@ namespace bgfx m_submit->destroy(); #if BGFX_CONFIG_MULTITHREADED m_render->destroy(); + + if (m_singleThreaded) + { + s_renderFrameCalled = false; + } #endif // BGFX_CONFIG_MULTITHREADED return false; } diff --git a/src/glcontext_egl.cpp b/src/glcontext_egl.cpp index 6b0fc5404..f0bc505cd 100644 --- a/src/glcontext_egl.cpp +++ b/src/glcontext_egl.cpp @@ -65,28 +65,6 @@ namespace bgfx { namespace gl EGL_IMPORT #undef EGL_IMPORT_FUNC - void* eglOpen() - { - void* handle = bx::dlopen( -#if BX_PLATFORM_LINUX - "libEGL.so.1" -#else - "libEGL." BX_DL_EXT -#endif // BX_PLATFORM_* - ); - - BGFX_FATAL(NULL != handle, Fatal::UnableToInitialize, "Failed to load libEGL dynamic library."); - -#define EGL_IMPORT_FUNC(_proto, _func) \ - _func = (_proto)bx::dlsym(handle, #_func); \ - BX_TRACE("%p " #_func, _func); \ - BGFX_FATAL(NULL != _func, Fatal::UnableToInitialize, "Failed get " #_func ".") -EGL_IMPORT -#undef EGL_IMPORT_FUNC - - return handle; - } - void eglClose(void* _handle) { bx::dlclose(_handle); @@ -96,6 +74,43 @@ EGL_IMPORT #undef EGL_IMPORT_FUNC } + void* eglOpen() + { + const char* eglDllName = +#if BX_PLATFORM_LINUX + "libEGL.so.1" +#else + "libEGL." BX_DL_EXT +#endif // BX_PLATFORM_* + ; + + void* handle = bx::dlopen(eglDllName); + + if (NULL == handle) + { + BX_TRACE("Init error: Failed to load %s.", eglDllName); + return NULL; + } + + bool imported = true; + +#define EGL_IMPORT_FUNC(_proto, _func) \ + _func = (_proto)bx::dlsym(handle, #_func); \ + BX_TRACE("%p " #_func, _func); \ + imported &= NULL != _func +EGL_IMPORT +#undef EGL_IMPORT_FUNC + + if (!imported) + { + BX_TRACE("Init error: Failed to import functions from %s.", eglDllName); + eglClose(handle); + return NULL; + } + + return handle; + } + #else void* eglOpen() @@ -126,7 +141,12 @@ WL_EGL_IMPORT void* waylandEglOpen() { void* handle = bx::dlopen("libwayland-egl.so.1"); - BGFX_FATAL(handle != NULL, Fatal::UnableToInitialize, "Could not dlopen() libwayland-egl.so.1"); + + if (NULL == handle) + { + BX_TRACE("Init error: Failed to load libwayland-egl.so.1."); + return NULL; + } # define WL_EGL_FUNC(rt, fname, params) fname = (PFNWLEGL_##fname) bx::dlsym(handle, #fname); WL_EGL_IMPORT @@ -245,8 +265,22 @@ WL_EGL_IMPORT static EGL_DISPMANX_WINDOW_T s_dispmanWindow; # endif // BX_PLATFORM_RPI - void GlContext::create(const SwapChain& _swapChain, uint32_t _reset) + bool GlContext::create(const SwapChain& _swapChain, uint32_t _reset) { + struct ErrorState + { + enum Enum + { + Default, + LoadedEGL, + InitializedDisplay, + CreatedSurface, + CreatedContext, + }; + }; + + ErrorState::Enum errorState = ErrorState::Default; + m_nwh = _swapChain.nwh; # if BX_PLATFORM_RPI @@ -254,6 +288,15 @@ WL_EGL_IMPORT # endif // BX_PLATFORM_RPI m_eglDll = eglOpen(); + + if (BX_ENABLED(BGFX_USE_GL_DYNAMIC_LIB) + && NULL == m_eglDll) + { + goto error; + } + + errorState = ErrorState::LoadedEGL; + m_ownsContext = NULL == g_platformData.context; if (m_ownsContext) @@ -276,12 +319,31 @@ WL_EGL_IMPORT # endif // BX_PLATFORM_WINDOWS m_display = eglGetDisplay(NULL == ndt ? EGL_DEFAULT_DISPLAY : ndt); - BGFX_FATAL(m_display != EGL_NO_DISPLAY, Fatal::UnableToInitialize, "Failed to create display %p", m_display); + + if (EGL_NO_DISPLAY == m_display) + { + BX_TRACE("Init error: Failed to get display (error: 0x%x).", eglGetError() ); + goto error; + } EGLint major = 0; EGLint minor = 0; EGLBoolean success = eglInitialize(m_display, &major, &minor); - BGFX_FATAL(success && major >= 1 && minor >= 3, Fatal::UnableToInitialize, "Failed to initialize %d.%d", major, minor); + + if (!success) + { + BX_TRACE("Init error: Failed to initialize display (error: 0x%x).", eglGetError() ); + goto error; + } + + errorState = ErrorState::InitializedDisplay; + + if (major < 1 + || minor < 3) + { + BX_TRACE("Init error: EGL %d.%d is not supported.", major, minor); + goto error; + } BX_TRACE("EGL info:"); const char* clientApis = eglQueryString(m_display, EGL_CLIENT_APIS); @@ -300,7 +362,12 @@ WL_EGL_IMPORT if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) ) { EGLBoolean ok = eglBindAPI(EGL_OPENGL_API); - BGFX_FATAL(ok, Fatal::UnableToInitialize, "Could not set API! error: %d", eglGetError()); + + if (!ok) + { + BX_TRACE("Init error: Failed to bind OpenGL API (error: 0x%x).", eglGetError() ); + goto error; + } } const bool isAngle = !bx::findIdentifierMatch(version, "ANGLE").isEmpty(); @@ -483,7 +550,12 @@ WL_EGL_IMPORT break; } - BGFX_FATAL(0 != numConfigs, Fatal::UnableToInitialize, "eglChooseConfig"); + if (!success + || 0 == numConfigs) + { + BX_TRACE("Init error: Failed to choose config (error: 0x%x).", eglGetError() ); + goto error; + } m_msaaContext = 1 < msaaSamples; @@ -531,6 +603,11 @@ WL_EGL_IMPORT if (g_platformData.type == NativeWindowHandleType::Wayland) { m_waylandEglDll = waylandEglOpen(); + + if (NULL == m_waylandEglDll) + { + goto error; + } } # endif // BX_PLATFORM_LINUX @@ -565,7 +642,13 @@ WL_EGL_IMPORT m_surface = eglCreateWindowSurface(m_display, m_config, nwh, NULL); } - BGFX_FATAL(m_surface != EGL_NO_SURFACE, Fatal::UnableToInitialize, "Failed to create surface."); + if (EGL_NO_SURFACE == m_surface) + { + BX_TRACE("Init error: Failed to create surface (error: 0x%x).", eglGetError() ); + goto error; + } + + errorState = ErrorState::CreatedSurface; m_readSurface = m_surface; const bool hasEglKhrCreateContext = !bx::findIdentifierMatch(extensions, "EGL_KHR_create_context").isEmpty(); @@ -629,10 +712,22 @@ WL_EGL_IMPORT BX_TRACE("Failed to create EGL context with EGL_CONTEXT_FLAGS_KHR (%08x). Retrying without it!", flags); } - BGFX_FATAL(m_context != EGL_NO_CONTEXT, Fatal::UnableToInitialize, "Failed to create context."); + if (EGL_NO_CONTEXT == m_context) + { + BX_TRACE("Init error: Failed to create context (error: 0x%x).", eglGetError() ); + goto error; + } + + errorState = ErrorState::CreatedContext; success = eglMakeCurrent(m_display, m_surface, m_surface, m_context); - BGFX_FATAL(success, Fatal::UnableToInitialize, "Failed to set context."); + + if (!success) + { + BX_TRACE("Init error: Failed to set context (error: 0x%x).", eglGetError() ); + goto error; + } + m_current = NULL; m_swapInterval = !!(_reset & BGFX_RESET_VSYNC) ? 1 : 0; @@ -641,16 +736,20 @@ WL_EGL_IMPORT else { m_context = (EGLContext)g_platformData.context; - BGFX_FATAL(m_context == eglGetCurrentContext() - , Fatal::UnableToInitialize - , "Caller-provided EGL context must be current." - ); + + if (m_context != eglGetCurrentContext() ) + { + BX_TRACE("Init error: Caller-provided EGL context must be current."); + goto error; + } m_display = eglGetCurrentDisplay(); - BGFX_FATAL(EGL_NO_DISPLAY != m_display - , Fatal::UnableToInitialize - , "Caller-provided EGL context has no current display." - ); + + if (EGL_NO_DISPLAY == m_display) + { + BX_TRACE("Init error: Caller-provided EGL context has no current display."); + goto error; + } m_surface = eglGetCurrentSurface(EGL_DRAW); m_readSurface = eglGetCurrentSurface(EGL_READ); @@ -658,7 +757,12 @@ WL_EGL_IMPORT if (BX_ENABLED(BGFX_CONFIG_RENDERER_OPENGL) ) { EGLBoolean ok = eglBindAPI(EGL_OPENGL_API); - BGFX_FATAL(ok, Fatal::UnableToInitialize, "Could not set API! error: %d", eglGetError() ); + + if (!ok) + { + BX_TRACE("Init error: Failed to bind OpenGL API (error: 0x%x).", eglGetError() ); + goto error; + } } EGLint configId = 0; @@ -750,9 +854,74 @@ WL_EGL_IMPORT m_swapInterval = !!(_reset & BGFX_RESET_VSYNC) ? 1 : 0; } - import(); + if (!import() ) + { + goto error; + } g_internalData.context = m_context; + + return true; + + error: + switch (errorState) + { + case ErrorState::CreatedContext: + eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(m_display, m_context); + [[fallthrough]]; + + case ErrorState::CreatedSurface: + eglDestroySurface(m_display, m_surface); + [[fallthrough]]; + + case ErrorState::InitializedDisplay: +# if BX_PLATFORM_LINUX + if (NULL != m_eglWindow) + { + wl_egl_window_destroy(m_eglWindow); + m_eglWindow = NULL; + } + + if (NULL != m_waylandEglDll) + { + waylandEglClose(m_waylandEglDll); + m_waylandEglDll = NULL; + } +# endif // BX_PLATFORM_LINUX + + eglTerminate(m_display); + eglReleaseThread(); + [[fallthrough]]; + + case ErrorState::LoadedEGL: + eglClose(m_eglDll); + m_eglDll = NULL; + [[fallthrough]]; + + case ErrorState::Default: + default: +# if BX_PLATFORM_WINDOWS + if (NULL != m_hdc) + { + ReleaseDC( (HWND)m_nwh, m_hdc); + m_hdc = NULL; + } +# endif // BX_PLATFORM_WINDOWS + +# if BX_PLATFORM_RPI + bcm_host_deinit(); +# endif // BX_PLATFORM_RPI + + m_config = NULL; + m_context = NULL; + m_display = NULL; + m_surface = NULL; + m_readSurface = NULL; + break; + } + + return false; } void GlContext::destroy() @@ -809,6 +978,8 @@ WL_EGL_IMPORT void GlContext::resize(const SwapChain& _swapChain, uint32_t _reset) { + BX_UNUSED(_swapChain); + if (!m_ownsContext && m_context == eglGetCurrentContext() ) { @@ -957,10 +1128,12 @@ WL_EGL_IMPORT } } - void GlContext::import() + bool GlContext::import() { BX_TRACE("Import:"); + bool imported = true; + # if BX_PLATFORM_WINDOWS || BX_PLATFORM_LINUX # if BX_PLATFORM_WINDOWS # if BGFX_CONFIG_RENDERER_OPENGL @@ -984,10 +1157,12 @@ WL_EGL_IMPORT { \ _func = bx::dlsym<_proto>(lib, #_import); \ BX_TRACE("\t%p " #_func " (" #_import ")", _func); \ - BGFX_FATAL(_optional || NULL != _func \ - , Fatal::UnableToInitialize \ - , "Failed to create OpenGLES context. eglGetProcAddress(\"%s\")" \ - , #_import); \ + if (!BX_IGNORE_C4127(_optional) \ + && NULL == _func) \ + { \ + BX_TRACE("Init error: Failed to import %s.", #_import); \ + imported = false; \ + } \ } \ } # else @@ -997,10 +1172,12 @@ WL_EGL_IMPORT { \ _func = reinterpret_cast<_proto>(eglGetProcAddress(#_import) ); \ BX_TRACE("\t%p " #_func " (" #_import ")", _func); \ - BGFX_FATAL(_optional || NULL != _func \ - , Fatal::UnableToInitialize \ - , "Failed to create OpenGLES context. eglGetProcAddress(\"%s\")" \ - , #_import); \ + if (!BX_IGNORE_C4127(_optional) \ + && NULL == _func) \ + { \ + BX_TRACE("Init error: Failed to import %s.", #_import); \ + imported = false; \ + } \ } \ } @@ -1009,6 +1186,8 @@ WL_EGL_IMPORT # include "glimports.h" # undef GL_EXTENSION + + return imported; } } /* namespace gl */ } // namespace bgfx diff --git a/src/glcontext_egl.h b/src/glcontext_egl.h index 7ff538f39..6e4d855c2 100644 --- a/src/glcontext_egl.h +++ b/src/glcontext_egl.h @@ -57,7 +57,7 @@ namespace bgfx { namespace gl { } - void create(const SwapChain& _swapChain, uint32_t _reset); + bool create(const SwapChain& _swapChain, uint32_t _reset); void destroy(); void resize(const SwapChain& _swapChain, uint32_t _reset); @@ -67,7 +67,7 @@ namespace bgfx { namespace gl void swap(SwapChainGL* _swapChain = NULL); void makeCurrent(SwapChainGL* _swapChain = NULL); - void import(); + bool import(); bool isValid() const { diff --git a/src/glcontext_html5.cpp b/src/glcontext_html5.cpp index 5e5a457a1..67f46638d 100644 --- a/src/glcontext_html5.cpp +++ b/src/glcontext_html5.cpp @@ -64,12 +64,13 @@ namespace bgfx { namespace gl char* m_canvas; }; - void GlContext::create(const SwapChain& _swapChain, uint32_t _reset) + bool GlContext::create(const SwapChain& _swapChain, uint32_t _reset) { if (NULL != m_primary) { - return; + return true; } + const bimg::ImageBlockInfo& colorBlockInfo = bimg::getBlockInfo(bimg::TextureFormat::Enum(_swapChain.formatColor) ); const bimg::ImageBlockInfo& depthStecilBlockInfo = bimg::getBlockInfo(bimg::TextureFormat::Enum(_swapChain.formatDepthStencil) ); @@ -86,19 +87,28 @@ namespace bgfx { namespace gl EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = bx::narrowCast( (uintptr_t) g_platformData.context); if (context > 0) { - if (emscripten_webgl_get_context_attributes(context, &s_attrs) >= 0) + if (emscripten_webgl_get_context_attributes(context, &s_attrs) < 0) { - import(); - m_primary = BX_NEW(g_allocator, SwapChainGL)(context, canvas); + BX_TRACE("Init error: Invalid WebGL context. (Canvas handle: '%s', context handle: %d)", canvas, context); + return false; } - else + + if (!import() ) { - BX_TRACE("Invalid WebGL context. (Canvas handle: '%s', context handle: %d)", canvas, context); + return false; } + + m_primary = BX_NEW(g_allocator, SwapChainGL)(context, canvas); } else { m_primary = createSwapChain( (void*)canvas, _swapChain.width, _swapChain.height); + + if (NULL == m_primary) + { + BX_TRACE("Init error: Failed to create WebGL context."); + return false; + } } if (0 != _swapChain.width @@ -112,6 +122,8 @@ namespace bgfx { namespace gl } makeCurrent(m_primary); + + return true; } void GlContext::destroy() @@ -157,7 +169,11 @@ namespace bgfx { namespace gl SwapChainGL* swapChain = BX_NEW(g_allocator, SwapChainGL)(context, canvas); - import(); + if (!import() ) + { + bx::deleteObject(g_allocator, swapChain); + return NULL; + } return swapChain; } @@ -213,20 +229,24 @@ namespace bgfx { namespace gl return func; } - void GlContext::import() + bool GlContext::import() { BX_TRACE("Import:"); + bool imported = true; + # define GL_EXTENSION(_optional, _proto, _func, _import) \ { \ if (NULL == _func) \ { \ _func = getProcAddress<_proto>(#_import); \ BX_TRACE("\t%p " #_func " (" #_import ")", _func); \ - BGFX_FATAL(_optional || NULL != _func, Fatal::UnableToInitialize \ - , "Failed to create WebGL/OpenGLES context. GetProcAddress(\"%s\")" \ - , #_import \ - ); \ + if (!BX_IGNORE_C4127(_optional) \ + && NULL == _func) \ + { \ + BX_TRACE("Init error: Failed to import %s.", #_import); \ + imported = false; \ + } \ } \ } @@ -234,6 +254,7 @@ namespace bgfx { namespace gl # undef GL_EXTENSION + return imported; } } /* namespace gl */ } // namespace bgfx diff --git a/src/glcontext_html5.h b/src/glcontext_html5.h index c3a7cb21b..ff1329c17 100644 --- a/src/glcontext_html5.h +++ b/src/glcontext_html5.h @@ -21,7 +21,7 @@ namespace bgfx { namespace gl { } - void create(const SwapChain& _swapChain, uint32_t _reset); + bool create(const SwapChain& _swapChain, uint32_t _reset); void destroy(); void resize(const SwapChain& _swapChain, uint32_t _reset); @@ -31,7 +31,7 @@ namespace bgfx { namespace gl void swap(SwapChainGL* _swapChain = NULL); void makeCurrent(SwapChainGL* _swapChain = NULL); - void import(); + bool import(); bool isValid() const { diff --git a/src/glcontext_wgl.cpp b/src/glcontext_wgl.cpp index 4aadf5439..e23bed0f1 100644 --- a/src/glcontext_wgl.cpp +++ b/src/glcontext_wgl.cpp @@ -89,7 +89,12 @@ namespace bgfx { namespace gl pfd.iLayerType = PFD_MAIN_PLANE; int pixelFormat = ChoosePixelFormat(_hdc, &pfd); - BGFX_FATAL(0 != pixelFormat, Fatal::UnableToInitialize, "ChoosePixelFormat failed!"); + + if (0 == pixelFormat) + { + BX_TRACE("Init error: ChoosePixelFormat failed (last err: 0x%08x).", GetLastError() ); + return NULL; + } DescribePixelFormat(_hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd); @@ -108,13 +113,29 @@ namespace bgfx { namespace gl int result; result = SetPixelFormat(_hdc, pixelFormat, &pfd); - BGFX_FATAL(0 != result, Fatal::UnableToInitialize, "SetPixelFormat failed!"); + + if (0 == result) + { + BX_TRACE("Init error: SetPixelFormat failed (last err: 0x%08x).", GetLastError() ); + return NULL; + } HGLRC context = wglCreateContext(_hdc); - BGFX_FATAL(NULL != context, Fatal::UnableToInitialize, "wglCreateContext failed!"); + + if (NULL == context) + { + BX_TRACE("Init error: wglCreateContext failed (last err: 0x%08x).", GetLastError() ); + return NULL; + } result = wglMakeCurrent(_hdc, context); - BGFX_FATAL(0 != result, Fatal::UnableToInitialize, "wglMakeCurrent failed!"); + + if (0 == result) + { + BX_TRACE("Init error: wglMakeCurrent failed (last err: 0x%08x).", GetLastError() ); + wglDeleteContext(context); + return NULL; + } return context; } @@ -138,13 +159,46 @@ namespace bgfx { namespace gl ); } - void GlContext::create(const SwapChain& _swapChain, uint32_t _reset) + bool GlContext::create(const SwapChain& _swapChain, uint32_t _reset) { + struct ErrorState + { + enum Enum + { + Default, + LoadedOpenGL32, + AcquiredDC, + CreatedContext, + }; + }; + + ErrorState::Enum errorState = ErrorState::Default; + + HWND nwh = NULL; + m_opengl32dll = bx::dlopen("opengl32.dll"); - BGFX_FATAL(NULL != m_opengl32dll, Fatal::UnableToInitialize, "Failed to load opengl32.dll."); + + if (NULL == m_opengl32dll) + { + BX_TRACE("Init error: Failed to load opengl32.dll."); + goto error; + } + + errorState = ErrorState::LoadedOpenGL32; wglGetProcAddress = bx::dlsym(m_opengl32dll, "wglGetProcAddress"); - BGFX_FATAL(NULL != wglGetProcAddress, Fatal::UnableToInitialize, "Failed get wglGetProcAddress."); + wglMakeCurrent = bx::dlsym(m_opengl32dll, "wglMakeCurrent"); + wglCreateContext = bx::dlsym(m_opengl32dll, "wglCreateContext"); + wglDeleteContext = bx::dlsym(m_opengl32dll, "wglDeleteContext"); + + if (NULL == wglGetProcAddress + || NULL == wglMakeCurrent + || NULL == wglCreateContext + || NULL == wglDeleteContext) + { + BX_TRACE("Init error: Failed to import functions from opengl32.dll."); + goto error; + } // If g_platformHooks.nwh is NULL, the assumption is that GL context was created // by user (for example, using SDL, GLFW, etc.) @@ -156,7 +210,7 @@ namespace bgfx { namespace gl m_nwh = _swapChain.nwh; - HWND nwh = (HWND)m_nwh; + nwh = (HWND)m_nwh; m_ownsContext = NULL == g_platformData.context; @@ -164,33 +218,43 @@ namespace bgfx { namespace gl && m_ownsContext) { m_dummyHwnd = createDummyWindow(); - BGFX_FATAL(NULL != m_dummyHwnd, Fatal::UnableToInitialize, "Failed to create headless window."); + + if (NULL == m_dummyHwnd) + { + BX_TRACE("Init error: Failed to create headless window (last err: 0x%08x).", GetLastError() ); + goto error; + } nwh = m_dummyHwnd; } - BGFX_FATAL(NULL != nwh - , Fatal::UnableToInitialize - , "Caller-provided GL context also needs the window it was created for." - ); + if (NULL == nwh) + { + BX_TRACE("Init error: Caller-provided GL context also needs the window it was created for."); + goto error; + } + + m_hdc = GetDC(nwh); + + if (NULL == m_hdc) + { + BX_TRACE("Init error: GetDC failed."); + goto error; + } + + errorState = ErrorState::AcquiredDC; if (!m_ownsContext) { - wglMakeCurrent = bx::dlsym(m_opengl32dll, "wglMakeCurrent"); - wglCreateContext = bx::dlsym(m_opengl32dll, "wglCreateContext"); - wglDeleteContext = bx::dlsym(m_opengl32dll, "wglDeleteContext"); - - BGFX_FATAL(NULL != wglMakeCurrent, Fatal::UnableToInitialize, "Failed get wglMakeCurrent."); - BGFX_FATAL(NULL != wglCreateContext, Fatal::UnableToInitialize, "Failed get wglCreateContext."); - BGFX_FATAL(NULL != wglDeleteContext, Fatal::UnableToInitialize, "Failed get wglDeleteContext."); - - m_hdc = GetDC(nwh); - BGFX_FATAL(NULL != m_hdc, Fatal::UnableToInitialize, "GetDC failed!"); - m_context = (HGLRC)g_platformData.context; int result = wglMakeCurrent(m_hdc, m_context); - BGFX_FATAL(0 != result, Fatal::UnableToInitialize, "wglMakeCurrent failed!"); + + if (0 == result) + { + BX_TRACE("Init error: wglMakeCurrent failed (last err: 0x%08x).", GetLastError() ); + goto error; + } m_pixelFormat = GetPixelFormat(m_hdc); @@ -256,26 +320,32 @@ namespace bgfx { namespace gl if (m_ownsContext) { - wglMakeCurrent = bx::dlsym(m_opengl32dll, "wglMakeCurrent"); - BGFX_FATAL(NULL != wglMakeCurrent, Fatal::UnableToInitialize, "Failed get wglMakeCurrent."); - - wglCreateContext = bx::dlsym(m_opengl32dll, "wglCreateContext"); - BGFX_FATAL(NULL != wglCreateContext, Fatal::UnableToInitialize, "Failed get wglCreateContext."); - - wglDeleteContext = bx::dlsym(m_opengl32dll, "wglDeleteContext"); - BGFX_FATAL(NULL != wglDeleteContext, Fatal::UnableToInitialize, "Failed get wglDeleteContext."); - - m_hdc = GetDC(nwh); - BGFX_FATAL(NULL != m_hdc, Fatal::UnableToInitialize, "GetDC failed!"); - // Dummy window to peek into WGL functionality. HWND hwnd = createDummyWindow(); + if (NULL == hwnd) + { + BX_TRACE("Init error: Failed to create dummy window (last err: 0x%08x).", GetLastError() ); + goto error; + } + HDC hdc = GetDC(hwnd); - BGFX_FATAL(NULL != hdc, Fatal::UnableToInitialize, "GetDC failed!"); + + if (NULL == hdc) + { + BX_TRACE("Init error: GetDC failed."); + DestroyWindow(hwnd); + goto error; + } HGLRC context = createContext(hdc, _swapChain); + if (NULL == context) + { + DestroyWindow(hwnd); + goto error; + } + wglGetExtensionsStringARB = wglGetProc("wglGetExtensionsStringARB"); wglChoosePixelFormatARB = wglGetProc("wglChoosePixelFormatARB"); wglCreateContextAttribsARB = wglGetProc("wglCreateContextAttribsARB"); @@ -321,12 +391,28 @@ namespace bgfx { namespace gl if (0 == result || 0 == numFormats) { + if (0 == attrs[3]) + { + break; + } + attrs[3] >>= 1; attrs[1] = attrs[3] == 0 ? 0 : 1; } } while (0 == numFormats); + if (0 == numFormats) + { + BX_TRACE("Init error: wglChoosePixelFormatARB failed (last err: 0x%08x).", GetLastError() ); + + wglMakeCurrent(NULL, NULL); + wglDeleteContext(context); + DestroyWindow(hwnd); + + goto error; + } + DescribePixelFormat(m_hdc, m_pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &m_pfd); BX_TRACE("Pixel format:\n" @@ -366,7 +452,17 @@ namespace bgfx { namespace gl contextAttrs[6] = WGL_CONTEXT_PROFILE_MASK_ARB == contextAttrs[6] ? 0 : contextAttrs[6]; m_context = wglCreateContextAttribsARB(m_hdc, 0, contextAttrs); } - BGFX_FATAL(NULL != m_context, Fatal::UnableToInitialize, "Failed to create context 0x%08x.", GetLastError() ); + + if (NULL == m_context) + { + BX_TRACE("Init error: Failed to create context (last err: 0x%08x).", GetLastError() ); + + wglMakeCurrent(NULL, NULL); + wglDeleteContext(context); + DestroyWindow(hwnd); + + goto error; + } static_assert(sizeof(contextAttrs) == sizeof(m_contextAttrs) ); bx::memCopy(m_contextAttrs, contextAttrs, sizeof(contextAttrs) ); @@ -379,10 +475,23 @@ namespace bgfx { namespace gl if (NULL == m_context) { m_context = createContext(m_hdc, _swapChain); + + if (NULL == m_context) + { + goto error; + } } + errorState = ErrorState::CreatedContext; + int result = wglMakeCurrent(m_hdc, m_context); - BGFX_FATAL(0 != result, Fatal::UnableToInitialize, "wglMakeCurrent failed!"); + + if (0 == result) + { + BX_TRACE("Init error: wglMakeCurrent failed (last err: 0x%08x).", GetLastError() ); + goto error; + } + m_current = NULL; m_swapInterval = !!(_reset & BGFX_RESET_VSYNC) ? 1 : 0; @@ -392,9 +501,47 @@ namespace bgfx { namespace gl } } - import(); + if (!import() ) + { + goto error; + } g_internalData.context = m_context; + + return true; + + error: + switch (errorState) + { + case ErrorState::CreatedContext: + wglMakeCurrent(NULL, NULL); + wglDeleteContext(m_context); + [[fallthrough]]; + + case ErrorState::AcquiredDC: + ReleaseDC(nwh, m_hdc); + m_hdc = NULL; + [[fallthrough]]; + + case ErrorState::LoadedOpenGL32: + if (NULL != m_dummyHwnd) + { + DestroyWindow(m_dummyHwnd); + m_dummyHwnd = NULL; + } + + bx::dlclose(m_opengl32dll); + m_opengl32dll = NULL; + [[fallthrough]]; + + case ErrorState::Default: + default: + m_context = NULL; + m_pixelFormat = 0; + break; + } + + return false; } void GlContext::destroy() @@ -521,10 +668,12 @@ namespace bgfx { namespace gl } } - void GlContext::import() + bool GlContext::import() { BX_TRACE("Import:"); + bool imported = true; + # define GL_EXTENSION(_optional, _proto, _func, _import) \ { \ if (NULL == _func) \ @@ -539,15 +688,20 @@ namespace bgfx { namespace gl { \ BX_TRACE("wgl %p " #_func " (" #_import ")", _func); \ } \ - BGFX_FATAL(BX_IGNORE_C4127(_optional) || NULL != _func \ - , Fatal::UnableToInitialize \ - , "Failed to create OpenGL context. wglGetProcAddress(\"%s\")", #_import); \ + if (!BX_IGNORE_C4127(_optional) \ + && NULL == _func) \ + { \ + BX_TRACE("Init error: Failed to import %s.", #_import); \ + imported = false; \ + } \ } \ } # include "glimports.h" # undef GL_EXTENSION + + return imported; } } } // namespace bgfx diff --git a/src/glcontext_wgl.h b/src/glcontext_wgl.h index d94e5e9fc..86d7707b7 100644 --- a/src/glcontext_wgl.h +++ b/src/glcontext_wgl.h @@ -84,7 +84,7 @@ typedef void (APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum z { } - void create(const SwapChain& _swapChain, uint32_t _reset); + bool create(const SwapChain& _swapChain, uint32_t _reset); void destroy(); void resize(const SwapChain& _swapChain, uint32_t _reset); @@ -94,7 +94,7 @@ typedef void (APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum z void swap(SwapChainGL* _swapChain = NULL); void makeCurrent(SwapChainGL* _swapChain = NULL); - void import(); + bool import(); bool isValid() const { diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index ffdeac717..74e5a6195 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -2303,11 +2303,15 @@ namespace bgfx { namespace gl enum Enum { Default, + CreatedContext, }; }; ErrorState::Enum errorState = ErrorState::Default; + GLint numCmpFormats = 0; + GLint* cmpFormat = NULL; + initLazyEnabledVertexAttributes(); if (_init.debug @@ -2321,7 +2325,13 @@ namespace bgfx { namespace gl m_reset = _init.reset & ~BGFX_RESET_INTERNAL_FORCE; - setRenderContextSize(_init.swapChain); + if (!m_glctx.create(_init.swapChain, m_reset) ) + { + goto error; + } + + errorState = ErrorState::CreatedContext; + m_flip = true; m_vendor = getGLString(GL_VENDOR); m_renderer = getGLString(GL_RENDERER); @@ -2340,12 +2350,9 @@ namespace bgfx { namespace gl m_workaround.reset(); - GLint numCmpFormats = 0; GL_CHECK(glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCmpFormats) ); BX_TRACE("GL_NUM_COMPRESSED_TEXTURE_FORMATS %d", numCmpFormats); - GLint* cmpFormat = NULL; - if (0 < numCmpFormats) { numCmpFormats = numCmpFormats > 256 ? 256 : numCmpFormats; @@ -3139,13 +3146,16 @@ namespace bgfx { namespace gl error: switch (errorState) { + case ErrorState::CreatedContext: + m_glctx.destroy(); + [[fallthrough]]; + case ErrorState::Default: + default: + unloadRenderDoc(m_renderdocdll); break; } - m_glctx.destroy(); - - unloadRenderDoc(m_renderdocdll); return false; } @@ -4438,21 +4448,14 @@ namespace bgfx { namespace gl void setRenderContextSize(const SwapChain& _swapChain) { - if (!m_glctx.isValid() ) - { - m_glctx.create(_swapChain, m_reset); - } - else - { - destroyMsaaFbo(); + destroyMsaaFbo(); - m_glctx.resize(_swapChain, m_reset); + m_glctx.resize(_swapChain, m_reset); - uint32_t msaa = (_swapChain.flags & BGFX_SWAP_CHAIN_MSAA_MASK)>>BGFX_SWAP_CHAIN_MSAA_SHIFT; - msaa = bx::min(m_maxMsaa, msaa == 0 ? 0 : 1<>BGFX_SWAP_CHAIN_MSAA_SHIFT; + msaa = bx::min(m_maxMsaa, msaa == 0 ? 0 : 1<