Quellcode durchsuchen

Added graceful error handling during initialization.

Branimir Karadžić vor 10 Jahren
Ursprung
Commit
5f59978e6b
7 geänderte Dateien mit 793 neuen und 427 gelöschten Zeilen
  1. 1 1
      include/bgfx.c99.h
  2. 3 1
      include/bgfx.h
  3. 88 15
      src/bgfx.cpp
  4. 1 1
      src/bgfx_p.h
  5. 336 213
      src/renderer_d3d11.cpp
  6. 268 185
      src/renderer_d3d12.cpp
  7. 96 11
      src/renderer_d3d9.cpp

+ 1 - 1
include/bgfx.c99.h

@@ -432,7 +432,7 @@ BGFX_C_API uint8_t bgfx_get_supported_renderers(bgfx_renderer_type_t _enum[BGFX_
 BGFX_C_API const char* bgfx_get_renderer_name(bgfx_renderer_type_t _type);
 
 /**/
-BGFX_C_API void bgfx_init(bgfx_renderer_type_t _type, uint16_t _vendorId, uint16_t _deviceId, bgfx_callback_interface_t* _callback, bgfx_reallocator_interface_t* _allocator);
+BGFX_C_API bool bgfx_init(bgfx_renderer_type_t _type, uint16_t _vendorId, uint16_t _deviceId, bgfx_callback_interface_t* _callback, bgfx_reallocator_interface_t* _allocator);
 
 /**/
 BGFX_C_API void bgfx_shutdown();

+ 3 - 1
include/bgfx.h

@@ -709,9 +709,11 @@ namespace bgfx
 	///   specified, library uses default CRT allocator. The library assumes
 	///   icustom allocator is thread safe.
 	///
+	/// @returns `true` if initialization is sucessful.
+	///
 	/// @attention C99 equivalent is `bgfx_init`.
 	///
-	void init(RendererType::Enum _type = RendererType::Count, uint16_t _vendorId = BGFX_PCI_ID_NONE, uint16_t _deviceId = 0, CallbackI* _callback = NULL, bx::ReallocatorI* _reallocator = NULL);
+	bool init(RendererType::Enum _type = RendererType::Count, uint16_t _vendorId = BGFX_PCI_ID_NONE, uint16_t _deviceId = 0, CallbackI* _callback = NULL, bx::ReallocatorI* _reallocator = NULL);
 
 	/// Shutdown bgfx library.
 	///

+ 88 - 15
src/bgfx.cpp

@@ -915,7 +915,7 @@ namespace bgfx
 		TextureFormat::RGBA8, // D3D9 doesn't support RGBA8
 	};
 
-	void Context::init(RendererType::Enum _type)
+	bool Context::init(RendererType::Enum _type)
 	{
 		BX_CHECK(!m_rendererInitialized, "Already initialized?");
 
@@ -990,6 +990,19 @@ namespace bgfx
 		// g_caps is initialized and available after this point.
 		frame();
 
+		if (!m_rendererInitialized)
+		{
+			getCommandBuffer(CommandBuffer::RendererShutdownEnd);
+			frame();
+			frame();
+			m_declRef.shutdown(m_vertexDeclHandle);
+			m_submit->destroy();
+#if BGFX_CONFIG_MULTITHREADED
+			m_render->destroy();
+#endif // BGFX_CONFIG_MULTITHREADED
+			return false;
+		}
+
 		for (uint32_t ii = 0; ii < BX_COUNTOF(s_emulatedFormats); ++ii)
 		{
 			if (0 == (g_caps.formats[s_emulatedFormats[ii] ] & BGFX_CAPS_FORMAT_TEXTURE_COLOR) )
@@ -1020,6 +1033,8 @@ namespace bgfx
 			m_submit->m_transientIb = createTransientIndexBuffer(BGFX_CONFIG_TRANSIENT_INDEX_BUFFER_SIZE);
 			frame();
 		}
+
+		return true;
 	}
 
 	void Context::shutdown()
@@ -1370,7 +1385,7 @@ namespace bgfx
 		bool supported;
 	};
 
-	static const RendererCreator s_rendererCreator[] =
+	static RendererCreator s_rendererCreator[] =
 	{
 		{ noop::rendererCreate,  noop::rendererDestroy,  BGFX_RENDERER_NULL_NAME,       !!BGFX_CONFIG_RENDERER_NULL       }, // Noop
 		{ d3d9::rendererCreate,  d3d9::rendererDestroy,  BGFX_RENDERER_DIRECT3D9_NAME,  !!BGFX_CONFIG_RENDERER_DIRECT3D9  }, // Direct3D9
@@ -1467,10 +1482,18 @@ again:
 				{
 					_type = RendererType::OpenGLES;
 				}
+				else if (s_rendererCreator[RendererType::Direct3D12].supported)
+				{
+					_type = RendererType::Direct3D12;
+				}
 				else if (s_rendererCreator[RendererType::Vulkan].supported)
 				{
 					_type = RendererType::Vulkan;
 				}
+				else
+				{
+					_type = RendererType::Null;
+				}
 			}
 			else if (BX_ENABLED(0
 				 ||  BX_PLATFORM_ANDROID
@@ -1508,6 +1531,7 @@ again:
 
 		if (NULL == renderCtx)
 		{
+			s_rendererCreator[_type].supported = false;
 			goto again;
 		}
 
@@ -1532,19 +1556,41 @@ again:
 			uint8_t command;
 			_cmdbuf.read(command);
 
-			BX_CHECK(CommandBuffer::RendererInit == command
-				, "RendererInit must be the first command in command buffer before initialization."
-				);
-			BX_CHECK(!m_rendererInitialized, "This shouldn't happen! Bad synchronization?");
+			switch (command)
+			{
+			case CommandBuffer::RendererShutdownEnd:
+				m_exit = true;
+				return;
 
-			RendererType::Enum type;
-			_cmdbuf.read(type);
+			case CommandBuffer::End:
+				return;
 
-			m_renderCtx = rendererCreate(type);
-			m_rendererInitialized = true;
-		}
+			default:
+				{
+					BX_CHECK(CommandBuffer::RendererInit == command
+						, "RendererInit must be the first command in command buffer before initialization. Unexpected command %d?"
+						, command
+						);
+					BX_CHECK(!m_rendererInitialized, "This shouldn't happen! Bad synchronization?");
+
+					RendererType::Enum type;
+					_cmdbuf.read(type);
 
-		BX_CHECK(NULL != m_renderCtx, "Should not be NULL at this point.");
+					m_renderCtx = rendererCreate(type);
+					m_rendererInitialized = NULL != m_renderCtx;
+
+					if (!m_rendererInitialized)
+					{
+						_cmdbuf.read(command);
+						BX_CHECK(CommandBuffer::End == command, "Unexpected command %d?"
+							, command
+							);
+						return;
+					}
+				}
+				break;
+			}
+		}
 
 		do
 		{
@@ -2015,7 +2061,7 @@ again:
 		return s_rendererCreator[_type].name;
 	}
 
-	void init(RendererType::Enum _type, uint16_t _vendorId, uint16_t _deviceId, CallbackI* _callback, bx::ReallocatorI* _allocator)
+	bool init(RendererType::Enum _type, uint16_t _vendorId, uint16_t _deviceId, CallbackI* _callback, bx::ReallocatorI* _allocator)
 	{
 		BX_CHECK(NULL == s_ctx, "bgfx is already initialized.");
 
@@ -2050,9 +2096,36 @@ again:
 		BX_TRACE("Init...");
 
 		s_ctx = BX_ALIGNED_NEW(g_allocator, Context, 16);
-		s_ctx->init(_type);
+		if (!s_ctx->init(_type) )
+		{
+			BX_TRACE("Init failed.");
+
+			BX_ALIGNED_DELETE(g_allocator, s_ctx, 16);
+			s_ctx = NULL;
+
+			if (NULL != s_callbackStub)
+			{
+				BX_DELETE(g_allocator, s_callbackStub);
+				s_callbackStub = NULL;
+			}
+
+			if (NULL != s_allocatorStub)
+			{
+//				s_allocatorStub->checkLeaks();
+
+				bx::CrtAllocator allocator;
+				BX_DELETE(&allocator, s_allocatorStub);
+				s_allocatorStub = NULL;
+			}
+
+			s_threadIndex = 0;
+			g_callback    = NULL;
+			g_allocator   = NULL;
+			return false;
+		}
 
 		BX_TRACE("Init complete.");
+		return true;
 	}
 
 	void shutdown()
@@ -3243,7 +3316,7 @@ BGFX_C_API const char* bgfx_get_renderer_name(bgfx_renderer_type_t _type)
 	return bgfx::getRendererName(bgfx::RendererType::Enum(_type) );
 }
 
-BGFX_C_API void bgfx_init(bgfx_renderer_type_t _type, uint16_t _vendorId, uint16_t _deviceId, bgfx_callback_interface_t* _callback, bgfx_reallocator_interface_t* _allocator)
+BGFX_C_API bool bgfx_init(bgfx_renderer_type_t _type, uint16_t _vendorId, uint16_t _deviceId, bgfx_callback_interface_t* _callback, bgfx_reallocator_interface_t* _allocator)
 {
 	static bgfx::CallbackC99 s_callback;
 	s_callback.m_interface = _callback;

+ 1 - 1
src/bgfx_p.h

@@ -1929,7 +1929,7 @@ namespace bgfx
 		}
 
 		// game thread
-		void init(RendererType::Enum _type);
+		bool init(RendererType::Enum _type);
 		void shutdown();
 
 		CommandBuffer& getCommandBuffer(CommandBuffer::Enum _cmd)

+ 336 - 213
src/renderer_d3d11.cpp

@@ -489,8 +489,10 @@ namespace bgfx { namespace d3d11
 		{
 		}
 
-		void init()
+		bool init()
 		{
+			uint32_t errorState = 0;
+
 			// Must be before device creation, and before RenderDoc.
 			m_ovr.init();
 
@@ -505,7 +507,14 @@ namespace bgfx { namespace d3d11
 
 #if USE_D3D11_DYNAMIC_LIB
 			m_d3d11dll = bx::dlopen("d3d11.dll");
-			BGFX_FATAL(NULL != m_d3d11dll, Fatal::UnableToInitialize, "Failed to load d3d11.dll.");
+			BX_WARN(NULL != m_d3d11dll, "Failed to load d3d11.dll.");
+
+			if (NULL == m_d3d11dll)
+			{
+				goto error;
+			}
+
+			errorState = 1;
 
 			m_d3d9dll = NULL;
 
@@ -514,26 +523,41 @@ namespace bgfx { namespace d3d11
 				// D3D11_1.h has ID3DUserDefinedAnnotation
 				// http://msdn.microsoft.com/en-us/library/windows/desktop/hh446881%28v=vs.85%29.aspx
 				m_d3d9dll = bx::dlopen("d3d9.dll");
-				BGFX_FATAL(NULL != m_d3d9dll, Fatal::UnableToInitialize, "Failed to load d3d9.dll.");
-
-				D3DPERF_SetMarker  = (PFN_D3DPERF_SET_MARKER )bx::dlsym(m_d3d9dll, "D3DPERF_SetMarker" );
-				D3DPERF_BeginEvent = (PFN_D3DPERF_BEGIN_EVENT)bx::dlsym(m_d3d9dll, "D3DPERF_BeginEvent");
-				D3DPERF_EndEvent   = (PFN_D3DPERF_END_EVENT  )bx::dlsym(m_d3d9dll, "D3DPERF_EndEvent"  );
-				BX_CHECK(NULL != D3DPERF_SetMarker
-					  && NULL != D3DPERF_BeginEvent
-					  && NULL != D3DPERF_EndEvent
-					  , "Failed to initialize PIX events."
-					  );
+				if (NULL != m_d3d9dll)
+				{
+					D3DPERF_SetMarker  = (PFN_D3DPERF_SET_MARKER )bx::dlsym(m_d3d9dll, "D3DPERF_SetMarker" );
+					D3DPERF_BeginEvent = (PFN_D3DPERF_BEGIN_EVENT)bx::dlsym(m_d3d9dll, "D3DPERF_BeginEvent");
+					D3DPERF_EndEvent   = (PFN_D3DPERF_END_EVENT  )bx::dlsym(m_d3d9dll, "D3DPERF_EndEvent"  );
+					BX_CHECK(NULL != D3DPERF_SetMarker
+						  && NULL != D3DPERF_BeginEvent
+						  && NULL != D3DPERF_EndEvent
+						  , "Failed to initialize PIX events."
+						  );
+				}
 			}
 
 			D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)bx::dlsym(m_d3d11dll, "D3D11CreateDevice");
-			BGFX_FATAL(NULL != D3D11CreateDevice, Fatal::UnableToInitialize, "Function D3D11CreateDevice not found.");
+			BX_WARN(NULL != D3D11CreateDevice, "Function D3D11CreateDevice not found.");
+			if (NULL == D3D11CreateDevice)
+			{
+				goto error;
+			}
 
 			m_dxgidll = bx::dlopen("dxgi.dll");
-			BGFX_FATAL(NULL != m_dxgidll, Fatal::UnableToInitialize, "Failed to load dxgi.dll.");
+			BX_WARN(NULL != m_dxgidll, "Failed to load dxgi.dll.");
+			if (NULL == m_dxgidll)
+			{
+				goto error;
+			}
+
+			errorState = 2;
 
 			CreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)bx::dlsym(m_dxgidll, "CreateDXGIFactory");
-			BGFX_FATAL(NULL != CreateDXGIFactory, Fatal::UnableToInitialize, "Function CreateDXGIFactory not found.");
+			BX_WARN(NULL != CreateDXGIFactory, "Function CreateDXGIFactory not found.");
+			if (NULL == CreateDXGIFactory)
+			{
+				goto error;
+			}
 
 			m_dxgidebugdll = bx::dlopen("dxgidebug.dll");
 			if (NULL != m_dxgidebugdll)
@@ -558,11 +582,16 @@ namespace bgfx { namespace d3d11
 #if BX_PLATFORM_WINRT
 			// WinRT requires the IDXGIFactory2 interface, which isn't supported on older platforms
 			hr = CreateDXGIFactory1(__uuidof(IDXGIFactory2), (void**)&factory);
-			BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Unable to create DXGI factory.");
 #else
 			hr = CreateDXGIFactory(IID_IDXGIFactory, (void**)&factory);
-			BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Unable to create DXGI factory.");
 #endif // BX_PLATFORM_WINRT
+			BX_WARN(SUCCEEDED(hr), "Unable to create DXGI factory.");
+			if (FAILED(hr) )
+			{
+				goto error;
+			}
+
+			errorState = 3;
 
 			m_device = (ID3D11Device*)g_platformData.context;
 
@@ -686,7 +715,14 @@ namespace bgfx { namespace d3d11
 
 					break;
 				}
-				BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Unable to create Direct3D11 device.");
+				BX_WARN(SUCCEEDED(hr), "Unable to create Direct3D11 device.");
+
+				if (FAILED(hr) )
+				{
+					goto error;
+				}
+
+				errorState = 4;
 
 				if (NULL != m_adapter)
 				{
@@ -696,7 +732,14 @@ namespace bgfx { namespace d3d11
 			else
 			{
 				m_device->GetImmediateContext(&m_deviceCtx);
-				BGFX_FATAL(NULL != m_deviceCtx, Fatal::UnableToInitialize, "Unable to create Direct3D11 device.");
+				BX_WARN(NULL != m_deviceCtx, "Unable to create Direct3D11 device.");
+
+				if (NULL == m_deviceCtx)
+				{
+					goto error;
+				}
+
+				errorState = 4;
 			}
 
 			IDXGIDevice*  device = NULL;
@@ -729,7 +772,11 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 #endif // BX_COMPILER_MSVC
 				}
 			}
-			BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Unable to create Direct3D11 device.");
+			BX_WARN(SUCCEEDED(hr), "Unable to create Direct3D11 device.");
+			if (FAILED(hr) )
+			{
+				goto error;
+			}
 
 			// GPA increases device ref count.
 			// RenderDoc makes device ref count 0 here.
@@ -750,7 +797,13 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 			}
 
 			hr = adapter->GetDesc(&m_adapterDesc);
-			BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Unable to create Direct3D11 device.");
+			BX_WARN(SUCCEEDED(hr), "Unable to create Direct3D11 device.");
+			if (FAILED(hr) )
+			{
+				DX_RELEASE(adapter, 2);
+				goto error;
+			}
+
 			g_caps.vendorId = 0 == m_adapterDesc.VendorId
 				? BGFX_PCI_ID_SOFTWARE_RASTERIZER
 				: (uint16_t)m_adapterDesc.VendorId
@@ -761,8 +814,12 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 			{
 #if BX_PLATFORM_WINRT
 				hr = adapter->GetParent(__uuidof(IDXGIFactory2), (void**)&m_factory);
-				BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Unable to create Direct3D11 device.");
+				BX_WARN(SUCCEEDED(hr), "Unable to create Direct3D11 device.");
 				DX_RELEASE(adapter, 2);
+				if (FAILED(hr) )
+				{
+					goto error;
+				}
 
 				memset(&m_scd, 0, sizeof(m_scd) );
 				m_scd.Width  = BGFX_DEFAULT_WIDTH;
@@ -783,11 +840,14 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 					, NULL
 					, &m_swapChain
 					);
-				BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Failed to create swap chain.");
 #else
 				hr = adapter->GetParent(IID_IDXGIFactory, (void**)&m_factory);
-				BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Unable to create Direct3D11 device.");
+				BX_WARN(SUCCEEDED(hr), "Unable to create Direct3D11 device.");
 				DX_RELEASE(adapter, 2);
+				if (FAILED(hr) )
+				{
+					goto error;
+				}
 
 				memset(&m_scd, 0, sizeof(m_scd) );
 				m_scd.BufferDesc.Width  = BGFX_DEFAULT_WIDTH;
@@ -806,13 +866,19 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 					, &m_scd
 					, &m_swapChain
 					);
-				BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Failed to create swap chain.");
 
 				DX_CHECK(m_factory->MakeWindowAssociation( (HWND)g_platformData.nwh, 0
 					| DXGI_MWA_NO_WINDOW_CHANGES
 					| DXGI_MWA_NO_ALT_ENTER
 					) );
 #endif // BX_PLATFORM_WINRT
+				BX_WARN(SUCCEEDED(hr), "Failed to create swap chain.");
+				if (FAILED(hr) )
+				{
+					goto error;
+				}
+
+				errorState = 5;
 			}
 			else
 			{
@@ -853,242 +919,292 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 				}
 			}
 #endif // __MINGW__
-
-			UniformHandle handle = BGFX_INVALID_HANDLE;
-			for (uint32_t ii = 0; ii < PredefinedUniform::Count; ++ii)
 			{
-				m_uniformReg.add(handle, getPredefinedUniformName(PredefinedUniform::Enum(ii) ), &m_predefinedUniforms[ii]);
-			}
 
-			g_caps.supported |= (0
-				| BGFX_CAPS_TEXTURE_3D
-				| BGFX_CAPS_VERTEX_ATTRIB_HALF
-				| BGFX_CAPS_FRAGMENT_DEPTH
-				| (getIntelExtensions(m_device) ? BGFX_CAPS_FRAGMENT_ORDERING : 0)
-				| BGFX_CAPS_SWAP_CHAIN
-				| (m_ovr.isInitialized() ? BGFX_CAPS_HMD : 0)
-				| BGFX_CAPS_DRAW_INDIRECT
-				);
-
-			if (m_featureLevel <= D3D_FEATURE_LEVEL_9_2)
-			{
-				g_caps.maxTextureSize   = D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION;
-				g_caps.maxFBAttachments = uint8_t(bx::uint32_min(D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) );
-			}
-			else if (m_featureLevel == D3D_FEATURE_LEVEL_9_3)
-			{
-				g_caps.maxTextureSize   = D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION;
-				g_caps.maxFBAttachments = uint8_t(bx::uint32_min(D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) );
-			}
-			else
-			{
-				g_caps.supported |= BGFX_CAPS_TEXTURE_COMPARE_ALL;
-				g_caps.maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
-				g_caps.maxFBAttachments = uint8_t(bx::uint32_min(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) );
-			}
-
-			// 32-bit indices only supported on 9_2+.
-			if (m_featureLevel >= D3D_FEATURE_LEVEL_9_2)
-			{
-				g_caps.supported |= BGFX_CAPS_INDEX32;
-			}
+				UniformHandle handle = BGFX_INVALID_HANDLE;
+				for (uint32_t ii = 0; ii < PredefinedUniform::Count; ++ii)
+				{
+					m_uniformReg.add(handle, getPredefinedUniformName(PredefinedUniform::Enum(ii) ), &m_predefinedUniforms[ii]);
+				}
 
-			// Independent blend only supported on 10_1+.
-			if (m_featureLevel >= D3D_FEATURE_LEVEL_10_1)
-			{
-				g_caps.supported |= BGFX_CAPS_BLEND_INDEPENDENT;
-			}
+				g_caps.supported |= (0
+					| BGFX_CAPS_TEXTURE_3D
+					| BGFX_CAPS_VERTEX_ATTRIB_HALF
+					| BGFX_CAPS_FRAGMENT_DEPTH
+					| (getIntelExtensions(m_device) ? BGFX_CAPS_FRAGMENT_ORDERING : 0)
+					| BGFX_CAPS_SWAP_CHAIN
+					| (m_ovr.isInitialized() ? BGFX_CAPS_HMD : 0)
+					| BGFX_CAPS_DRAW_INDIRECT
+					);
 
-			// Compute support is optional on 10_0 and 10_1 targets.
-			if (m_featureLevel == D3D_FEATURE_LEVEL_10_0
-			||  m_featureLevel == D3D_FEATURE_LEVEL_10_1)
-			{
-				struct D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS
+				if (m_featureLevel <= D3D_FEATURE_LEVEL_9_2)
 				{
-					BOOL ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x;
-				};
-
-				D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS data;
-				hr = m_device->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &data, sizeof(data) );
-				if (SUCCEEDED(hr)
-				&&  data.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x)
+					g_caps.maxTextureSize   = D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+					g_caps.maxFBAttachments = uint8_t(bx::uint32_min(D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) );
+				}
+				else if (m_featureLevel == D3D_FEATURE_LEVEL_9_3)
 				{
-					g_caps.supported |= BGFX_CAPS_COMPUTE;
+					g_caps.maxTextureSize   = D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+					g_caps.maxFBAttachments = uint8_t(bx::uint32_min(D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) );
+				}
+				else
+				{
+					g_caps.supported |= BGFX_CAPS_TEXTURE_COMPARE_ALL;
+					g_caps.maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+					g_caps.maxFBAttachments = uint8_t(bx::uint32_min(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) );
 				}
-			}
-			else if (m_featureLevel >= D3D_FEATURE_LEVEL_11_0)
-			{
-				g_caps.supported |= BGFX_CAPS_COMPUTE;
-			}
 
-			// Instancing fully supported on 9_3+, optionally partially supported at lower levels.
-			if (m_featureLevel >= D3D_FEATURE_LEVEL_9_3)
-			{
-				g_caps.supported |= BGFX_CAPS_INSTANCING;
-			}
-			else
-			{
-				struct D3D11_FEATURE_DATA_D3D9_SIMPLE_INSTANCING_SUPPORT
+				// 32-bit indices only supported on 9_2+.
+				if (m_featureLevel >= D3D_FEATURE_LEVEL_9_2)
 				{
-					BOOL SimpleInstancingSupported;
-				};
+					g_caps.supported |= BGFX_CAPS_INDEX32;
+				}
 
-				D3D11_FEATURE_DATA_D3D9_SIMPLE_INSTANCING_SUPPORT data;
-				hr = m_device->CheckFeatureSupport(D3D11_FEATURE(11) /*D3D11_FEATURE_D3D9_SIMPLE_INSTANCING_SUPPORT*/, &data, sizeof(data) );
-				if (SUCCEEDED(hr)
-				&&  data.SimpleInstancingSupported)
+				// Independent blend only supported on 10_1+.
+				if (m_featureLevel >= D3D_FEATURE_LEVEL_10_1)
 				{
-					g_caps.supported |= BGFX_CAPS_INSTANCING;
+					g_caps.supported |= BGFX_CAPS_BLEND_INDEPENDENT;
 				}
-			}
 
-			// shadow compare is optional on 9_1 through 9_3 targets
-			if (m_featureLevel <= D3D_FEATURE_LEVEL_9_3)
-			{
-				struct D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT
+				// Compute support is optional on 10_0 and 10_1 targets.
+				if (m_featureLevel == D3D_FEATURE_LEVEL_10_0
+				||  m_featureLevel == D3D_FEATURE_LEVEL_10_1)
 				{
-					BOOL SupportsDepthAsTextureWithLessEqualComparisonFilter;
-				};
+					struct D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS
+					{
+						BOOL ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x;
+					};
 
-				D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT data;
-				hr = m_device->CheckFeatureSupport(D3D11_FEATURE(9) /*D3D11_FEATURE_D3D9_SHADOW_SUPPORT*/, &data, sizeof(data) );
-				if (SUCCEEDED(hr)
-				&&  data.SupportsDepthAsTextureWithLessEqualComparisonFilter)
+					D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS data;
+					hr = m_device->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &data, sizeof(data) );
+					if (SUCCEEDED(hr)
+					&&  data.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x)
+					{
+						g_caps.supported |= BGFX_CAPS_COMPUTE;
+					}
+				}
+				else if (m_featureLevel >= D3D_FEATURE_LEVEL_11_0)
 				{
-					g_caps.supported |= BGFX_CAPS_TEXTURE_COMPARE_LEQUAL;
+					g_caps.supported |= BGFX_CAPS_COMPUTE;
 				}
-			}
 
-			for (uint32_t ii = 0; ii < TextureFormat::Count; ++ii)
-			{
-				uint8_t support = BGFX_CAPS_FORMAT_TEXTURE_NONE;
+				// Instancing fully supported on 9_3+, optionally partially supported at lower levels.
+				if (m_featureLevel >= D3D_FEATURE_LEVEL_9_3)
+				{
+					g_caps.supported |= BGFX_CAPS_INSTANCING;
+				}
+				else
+				{
+					struct D3D11_FEATURE_DATA_D3D9_SIMPLE_INSTANCING_SUPPORT
+					{
+						BOOL SimpleInstancingSupported;
+					};
 
-				const DXGI_FORMAT fmt = isDepth(TextureFormat::Enum(ii) )
-					? s_textureFormat[ii].m_fmtDsv
-					: s_textureFormat[ii].m_fmt
-					;
-				const DXGI_FORMAT fmtSrgb = s_textureFormat[ii].m_fmtSrgb;
+					D3D11_FEATURE_DATA_D3D9_SIMPLE_INSTANCING_SUPPORT data;
+					hr = m_device->CheckFeatureSupport(D3D11_FEATURE(11) /*D3D11_FEATURE_D3D9_SIMPLE_INSTANCING_SUPPORT*/, &data, sizeof(data) );
+					if (SUCCEEDED(hr)
+					&&  data.SimpleInstancingSupported)
+					{
+						g_caps.supported |= BGFX_CAPS_INSTANCING;
+					}
+				}
 
-				if (DXGI_FORMAT_UNKNOWN != fmt)
+				// shadow compare is optional on 9_1 through 9_3 targets
+				if (m_featureLevel <= D3D_FEATURE_LEVEL_9_3)
 				{
-					struct D3D11_FEATURE_DATA_FORMAT_SUPPORT
+					struct D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT
 					{
-						DXGI_FORMAT InFormat;
-						UINT OutFormatSupport;
+						BOOL SupportsDepthAsTextureWithLessEqualComparisonFilter;
 					};
 
-					D3D11_FEATURE_DATA_FORMAT_SUPPORT data; // D3D11_FEATURE_DATA_FORMAT_SUPPORT2
-					data.InFormat = fmt;
-					hr = m_device->CheckFeatureSupport(D3D11_FEATURE_FORMAT_SUPPORT, &data, sizeof(data) );
-					if (SUCCEEDED(hr) )
+					D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT data;
+					hr = m_device->CheckFeatureSupport(D3D11_FEATURE(9) /*D3D11_FEATURE_D3D9_SHADOW_SUPPORT*/, &data, sizeof(data) );
+					if (SUCCEEDED(hr)
+					&&  data.SupportsDepthAsTextureWithLessEqualComparisonFilter)
 					{
-						support |= 0 != (data.OutFormatSupport & (0
-								| D3D11_FORMAT_SUPPORT_TEXTURE2D
-								| D3D11_FORMAT_SUPPORT_TEXTURE3D
-								| D3D11_FORMAT_SUPPORT_TEXTURECUBE
-								) )
-								? BGFX_CAPS_FORMAT_TEXTURE_COLOR
-								: BGFX_CAPS_FORMAT_TEXTURE_NONE
-								;
+						g_caps.supported |= BGFX_CAPS_TEXTURE_COMPARE_LEQUAL;
+					}
+				}
 
-						support |= 0 != (data.OutFormatSupport & (0
-								| D3D11_FORMAT_SUPPORT_BUFFER
-								| D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER
-								| D3D11_FORMAT_SUPPORT_IA_INDEX_BUFFER
-								) )
-								? BGFX_CAPS_FORMAT_TEXTURE_VERTEX
-								: BGFX_CAPS_FORMAT_TEXTURE_NONE
-								;
+				for (uint32_t ii = 0; ii < TextureFormat::Count; ++ii)
+				{
+					uint8_t support = BGFX_CAPS_FORMAT_TEXTURE_NONE;
 
-						support |= 0 != (data.OutFormatSupport & (0
-								| D3D11_FORMAT_SUPPORT_SHADER_LOAD
-								) )
-								? BGFX_CAPS_FORMAT_TEXTURE_IMAGE
-								: BGFX_CAPS_FORMAT_TEXTURE_NONE
-								;
+					const DXGI_FORMAT fmt = isDepth(TextureFormat::Enum(ii) )
+						? s_textureFormat[ii].m_fmtDsv
+						: s_textureFormat[ii].m_fmt
+						;
+					const DXGI_FORMAT fmtSrgb = s_textureFormat[ii].m_fmtSrgb;
 
-						support |= 0 != (data.OutFormatSupport & (0
-								| D3D11_FORMAT_SUPPORT_RENDER_TARGET
-								| D3D11_FORMAT_SUPPORT_DEPTH_STENCIL
-								) )
-								? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER
-								: BGFX_CAPS_FORMAT_TEXTURE_NONE
-								;
-					}
-					else
+					if (DXGI_FORMAT_UNKNOWN != fmt)
 					{
-						BX_TRACE("CheckFeatureSupport failed with %x for format %s.", hr, getName(TextureFormat::Enum(ii) ) );
+						struct D3D11_FEATURE_DATA_FORMAT_SUPPORT
+						{
+							DXGI_FORMAT InFormat;
+							UINT OutFormatSupport;
+						};
+
+						D3D11_FEATURE_DATA_FORMAT_SUPPORT data; // D3D11_FEATURE_DATA_FORMAT_SUPPORT2
+						data.InFormat = fmt;
+						hr = m_device->CheckFeatureSupport(D3D11_FEATURE_FORMAT_SUPPORT, &data, sizeof(data) );
+						if (SUCCEEDED(hr) )
+						{
+							support |= 0 != (data.OutFormatSupport & (0
+									| D3D11_FORMAT_SUPPORT_TEXTURE2D
+									| D3D11_FORMAT_SUPPORT_TEXTURE3D
+									| D3D11_FORMAT_SUPPORT_TEXTURECUBE
+									) )
+									? BGFX_CAPS_FORMAT_TEXTURE_COLOR
+									: BGFX_CAPS_FORMAT_TEXTURE_NONE
+									;
+
+							support |= 0 != (data.OutFormatSupport & (0
+									| D3D11_FORMAT_SUPPORT_BUFFER
+									| D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER
+									| D3D11_FORMAT_SUPPORT_IA_INDEX_BUFFER
+									) )
+									? BGFX_CAPS_FORMAT_TEXTURE_VERTEX
+									: BGFX_CAPS_FORMAT_TEXTURE_NONE
+									;
+
+							support |= 0 != (data.OutFormatSupport & (0
+									| D3D11_FORMAT_SUPPORT_SHADER_LOAD
+									) )
+									? BGFX_CAPS_FORMAT_TEXTURE_IMAGE
+									: BGFX_CAPS_FORMAT_TEXTURE_NONE
+									;
+
+							support |= 0 != (data.OutFormatSupport & (0
+									| D3D11_FORMAT_SUPPORT_RENDER_TARGET
+									| D3D11_FORMAT_SUPPORT_DEPTH_STENCIL
+									) )
+									? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER
+									: BGFX_CAPS_FORMAT_TEXTURE_NONE
+									;
+						}
+						else
+						{
+							BX_TRACE("CheckFeatureSupport failed with %x for format %s.", hr, getName(TextureFormat::Enum(ii) ) );
+						}
+
+						if (0 != (support & BGFX_CAPS_FORMAT_TEXTURE_IMAGE) )
+						{
+							// clear image flag for additional testing
+							support &= ~BGFX_CAPS_FORMAT_TEXTURE_IMAGE;
+
+							data.InFormat = s_textureFormat[ii].m_fmt;
+							hr = m_device->CheckFeatureSupport(D3D11_FEATURE_FORMAT_SUPPORT2, &data, sizeof(data) );
+							if (SUCCEEDED(hr) )
+							{
+								support |= 0 != (data.OutFormatSupport & (0
+										| D3D11_FORMAT_SUPPORT2_UAV_TYPED_LOAD
+										| D3D11_FORMAT_SUPPORT2_UAV_TYPED_STORE
+										) )
+										? BGFX_CAPS_FORMAT_TEXTURE_IMAGE
+										: BGFX_CAPS_FORMAT_TEXTURE_NONE
+										;
+							}
+						}
 					}
 
-					if (0 != (support & BGFX_CAPS_FORMAT_TEXTURE_IMAGE) )
+					if (DXGI_FORMAT_UNKNOWN != fmtSrgb)
 					{
-						// clear image flag for additional testing
-						support &= ~BGFX_CAPS_FORMAT_TEXTURE_IMAGE;
+						struct D3D11_FEATURE_DATA_FORMAT_SUPPORT
+						{
+							DXGI_FORMAT InFormat;
+							UINT OutFormatSupport;
+						};
 
-						data.InFormat = s_textureFormat[ii].m_fmt;
-						hr = m_device->CheckFeatureSupport(D3D11_FEATURE_FORMAT_SUPPORT2, &data, sizeof(data) );
+						D3D11_FEATURE_DATA_FORMAT_SUPPORT data; // D3D11_FEATURE_DATA_FORMAT_SUPPORT2
+						data.InFormat = fmtSrgb;
+						hr = m_device->CheckFeatureSupport(D3D11_FEATURE_FORMAT_SUPPORT, &data, sizeof(data) );
 						if (SUCCEEDED(hr) )
 						{
 							support |= 0 != (data.OutFormatSupport & (0
-									| D3D11_FORMAT_SUPPORT2_UAV_TYPED_LOAD
-									| D3D11_FORMAT_SUPPORT2_UAV_TYPED_STORE
+									| D3D11_FORMAT_SUPPORT_TEXTURE2D
+									| D3D11_FORMAT_SUPPORT_TEXTURE3D
+									| D3D11_FORMAT_SUPPORT_TEXTURECUBE
 									) )
-									? BGFX_CAPS_FORMAT_TEXTURE_IMAGE
+									? BGFX_CAPS_FORMAT_TEXTURE_COLOR_SRGB
 									: BGFX_CAPS_FORMAT_TEXTURE_NONE
 									;
 						}
+						else
+						{
+							BX_TRACE("CheckFeatureSupport failed with %x for sRGB format %s.", hr, getName(TextureFormat::Enum(ii) ) );
+						}
 					}
+
+					g_caps.formats[ii] = support;
 				}
 
-				if (DXGI_FORMAT_UNKNOWN != fmtSrgb)
+				// Init reserved part of view name.
+				for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii)
 				{
-					struct D3D11_FEATURE_DATA_FORMAT_SUPPORT
-					{
-						DXGI_FORMAT InFormat;
-						UINT OutFormatSupport;
-					};
+					char name[BGFX_CONFIG_MAX_VIEW_NAME_RESERVED+1];
+					bx::snprintf(name, sizeof(name), "%3d   ", ii);
+					mbstowcs(s_viewNameW[ii], name, BGFX_CONFIG_MAX_VIEW_NAME_RESERVED);
+				}
 
-					D3D11_FEATURE_DATA_FORMAT_SUPPORT data; // D3D11_FEATURE_DATA_FORMAT_SUPPORT2
-					data.InFormat = fmtSrgb;
-					hr = m_device->CheckFeatureSupport(D3D11_FEATURE_FORMAT_SUPPORT, &data, sizeof(data) );
-					if (SUCCEEDED(hr) )
-					{
-						support |= 0 != (data.OutFormatSupport & (0
-								| D3D11_FORMAT_SUPPORT_TEXTURE2D
-								| D3D11_FORMAT_SUPPORT_TEXTURE3D
-								| D3D11_FORMAT_SUPPORT_TEXTURECUBE
-								) )
-								? BGFX_CAPS_FORMAT_TEXTURE_COLOR_SRGB
-								: BGFX_CAPS_FORMAT_TEXTURE_NONE
-								;
-					}
-					else
-					{
-						BX_TRACE("CheckFeatureSupport failed with %x for sRGB format %s.", hr, getName(TextureFormat::Enum(ii) ) );
-					}
+	#if !defined(__MINGW32__)
+				if (BX_ENABLED(BGFX_CONFIG_DEBUG)
+				&&  NULL != m_infoQueue)
+				{
+					m_infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
 				}
+	#endif // !defined(__MINGW32__)
 
-				g_caps.formats[ii] = support;
+				updateMsaa();
+				postReset();
 			}
 
-			// Init reserved part of view name.
-			for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_VIEWS; ++ii)
-			{
-				char name[BGFX_CONFIG_MAX_VIEW_NAME_RESERVED+1];
-				bx::snprintf(name, sizeof(name), "%3d   ", ii);
-				mbstowcs(s_viewNameW[ii], name, BGFX_CONFIG_MAX_VIEW_NAME_RESERVED);
-			}
+			return true;
 
-#if !defined(__MINGW32__)
-			if (BX_ENABLED(BGFX_CONFIG_DEBUG)
-			&&  NULL != m_infoQueue)
+		error:
+			switch (errorState)
 			{
-				m_infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
+			default:
+			case 5:
+				DX_RELEASE(m_swapChain, 0);
+
+			case 4:
+				DX_RELEASE(m_deviceCtx, 0);
+				DX_RELEASE(m_device, 0);
+
+			case 3:
+				DX_RELEASE(m_factory, 0);
+
+			case 2:
+#if USE_D3D11_DYNAMIC_LIB
+				if (NULL != m_dxgidebugdll)
+				{
+					bx::dlclose(m_dxgidebugdll);
+					m_dxgidebugdll = NULL;
+				}
+
+				if (NULL != m_d3d9dll)
+				{
+					bx::dlclose(m_d3d9dll);
+					m_d3d9dll = NULL;
+				}
+
+				bx::dlclose(m_dxgidll);
+				m_dxgidll = NULL;
+#endif // USE_D3D11_DYNAMIC_LIB
+
+			case 1:
+#if USE_D3D11_DYNAMIC_LIB
+				bx::dlclose(m_d3d11dll);
+				m_d3d11dll = NULL;
+#endif // USE_D3D11_DYNAMIC_LIB
+
+			case 0:
+				unloadRenderDoc(m_renderdocdll);
+				m_ovr.shutdown();
+				break;
 			}
-#endif // !defined(__MINGW32__)
 
-			updateMsaa();
-			postReset();
+			return false;
 		}
 
 		void shutdown()
@@ -1123,7 +1239,7 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 			DX_RELEASE(m_swapChain, 0);
 			DX_RELEASE(m_deviceCtx, 0);
 			DX_RELEASE(m_device, 0);
-			DX_RELEASE(m_factory,0);
+			DX_RELEASE(m_factory, 0);
 
 			unloadRenderDoc(m_renderdocdll);
 
@@ -1134,12 +1250,15 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 				m_dxgidebugdll = NULL;
 			}
 
+			if (NULL != m_d3d9dll)
+			{
+				bx::dlclose(m_d3d9dll);
+				m_d3d9dll = NULL;
+			}
+
 			bx::dlclose(m_dxgidll);
 			m_dxgidll = NULL;
 
-			bx::dlclose(m_d3d9dll);
-			m_d3d9dll = NULL;
-
 			bx::dlclose(m_d3d11dll);
 			m_d3d11dll = NULL;
 #endif // USE_D3D11_DYNAMIC_LIB
@@ -2735,7 +2854,11 @@ BX_PRAGMA_DIAGNOSTIC_POP();
 	RendererContextI* rendererCreate()
 	{
 		s_renderD3D11 = BX_NEW(g_allocator, RendererContextD3D11);
-		s_renderD3D11->init();
+		if (!s_renderD3D11->init() )
+		{
+			BX_DELETE(g_allocator, s_renderD3D11);
+			s_renderD3D11 = NULL;
+		}
 		return s_renderD3D11;
 	}
 

+ 268 - 185
src/renderer_d3d12.cpp

@@ -413,36 +413,77 @@ namespace bgfx { namespace d3d12
 		{
 		}
 
-		void init()
+		~RendererContextD3D12()
+		{
+		}
+
+		bool init()
 		{
+			uint32_t errorState = 0;
+			LUID luid;
+
 			m_fbh.idx = invalidHandle;
 			memset(m_uniforms, 0, sizeof(m_uniforms) );
 			memset(&m_resolution, 0, sizeof(m_resolution) );
 
 #if USE_D3D12_DYNAMIC_LIB
 			m_d3d12dll = bx::dlopen("d3d12.dll");
-			BGFX_FATAL(NULL != m_d3d12dll, Fatal::UnableToInitialize, "Failed to load d3d12.dll.");
+			BX_WARN(NULL != m_d3d12dll, "Failed to load d3d12.dll.");
+			if (NULL == m_d3d12dll)
+			{
+				goto error;
+			}
+
+			errorState = 1;
 
 			D3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)bx::dlsym(m_d3d12dll, "D3D12CreateDevice");
-			BGFX_FATAL(NULL != D3D12CreateDevice, Fatal::UnableToInitialize, "Function D3D12CreateDevice not found.");
+			BX_WARN(NULL != D3D12CreateDevice, "Function D3D12CreateDevice not found.");
 
 			D3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)bx::dlsym(m_d3d12dll, "D3D12GetDebugInterface");
-			BGFX_FATAL(NULL != D3D12GetDebugInterface, Fatal::UnableToInitialize, "Function D3D12GetDebugInterface not found.");
+			BX_WARN(NULL != D3D12GetDebugInterface, "Function D3D12GetDebugInterface not found.");
 
 			D3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)bx::dlsym(m_d3d12dll, "D3D12SerializeRootSignature");
-			BGFX_FATAL(NULL != D3D12SerializeRootSignature, Fatal::UnableToInitialize, "Function D3D12SerializeRootSignature not found.");
+			BX_WARN(NULL != D3D12SerializeRootSignature, "Function D3D12SerializeRootSignature not found.");
+
+			if (NULL == D3D12CreateDevice
+			||  NULL == D3D12GetDebugInterface
+			||  NULL == D3D12SerializeRootSignature)
+			{
+				goto error;
+			}
 
 			m_dxgidll = bx::dlopen("dxgi.dll");
-			BGFX_FATAL(NULL != m_dxgidll, Fatal::UnableToInitialize, "Failed to load dxgi.dll.");
+			BX_WARN(NULL != m_dxgidll, "Failed to load dxgi.dll.");
+
+			if (NULL == m_dxgidll)
+			{
+				goto error;
+			}
+
+			errorState = 2;
 
 			CreateDXGIFactory1 = (PFN_CREATE_DXGI_FACTORY)bx::dlsym(m_dxgidll, "CreateDXGIFactory1");
-			BGFX_FATAL(NULL != CreateDXGIFactory1, Fatal::UnableToInitialize, "Function CreateDXGIFactory1 not found.");
+			BX_WARN(NULL != CreateDXGIFactory1, "Function CreateDXGIFactory1 not found.");
+
+			if (NULL == CreateDXGIFactory1)
+			{
+				goto error;
+			}
+#else
+			errorState = 2;
 #endif // USE_D3D12_DYNAMIC_LIB
 
 			HRESULT hr;
 
 			hr = CreateDXGIFactory1(__uuidof(IDXGIFactory), (void**)&m_factory);
-			BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Unable to create DXGI factory.");
+			BX_WARN(SUCCEEDED(hr), "Unable to create DXGI factory.");
+
+			if (FAILED(hr) )
+			{
+				goto error;
+			}
+
+			errorState = 3;
 
 			m_adapter = NULL;
 			m_driverType = D3D_DRIVER_TYPE_HARDWARE;
@@ -511,15 +552,22 @@ namespace bgfx { namespace d3d12
 					, __uuidof(ID3D12Device)
 					, (void**)&m_device
 					);
-			BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Unable to create Direct3D12 device.");
+			BX_WARN(SUCCEEDED(hr), "Unable to create Direct3D12 device.");
 
 			if (NULL != m_adapter)
 			{
 				DX_RELEASE(m_adapter, 2);
 			}
 
+			if (FAILED(hr) )
+			{
+				goto error;
+			}
+
+			errorState = 4;
+
 			memset(&m_adapterDesc, 0, sizeof(m_adapterDesc) );
-			LUID luid = m_device->GetAdapterLuid();
+			luid = m_device->GetAdapterLuid();
 			for (uint32_t ii = 0; DXGI_ERROR_NOT_FOUND != m_factory->EnumAdapters(ii, &adapter); ++ii)
 			{
 				adapter->GetDesc(&m_adapterDesc);
@@ -569,206 +617,235 @@ namespace bgfx { namespace d3d12
 					, &m_scd
 					, &m_swapChain
 					);
-			BGFX_FATAL(SUCCEEDED(hr), Fatal::UnableToInitialize, "Failed to create swap chain.");
-			m_resolution.m_width  = BGFX_DEFAULT_WIDTH;
-			m_resolution.m_height = BGFX_DEFAULT_HEIGHT;
+			BX_WARN(SUCCEEDED(hr), "Failed to create swap chain.");
+			if (FAILED(hr) )
+			{
+				goto error;
+			}
 
-			DX_CHECK(m_factory->MakeWindowAssociation( (HWND)g_platformData.nwh
-					, 0
-					| DXGI_MWA_NO_WINDOW_CHANGES
-					| DXGI_MWA_NO_ALT_ENTER
-					) );
+			{
+				m_resolution.m_width  = BGFX_DEFAULT_WIDTH;
+				m_resolution.m_height = BGFX_DEFAULT_HEIGHT;
 
-			m_numWindows = 1;
+				DX_CHECK(m_factory->MakeWindowAssociation( (HWND)g_platformData.nwh
+						, 0
+						| DXGI_MWA_NO_WINDOW_CHANGES
+						| DXGI_MWA_NO_ALT_ENTER
+						) );
 
-			if (BX_ENABLED(BGFX_CONFIG_DEBUG) )
-			{
-				hr = m_device->QueryInterface(__uuidof(ID3D12InfoQueue), (void**)&m_infoQueue);
+				m_numWindows = 1;
 
-				if (SUCCEEDED(hr) )
+				if (BX_ENABLED(BGFX_CONFIG_DEBUG) )
 				{
-					m_infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
-					m_infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR,      true);
-					m_infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,    false);
-
-					D3D12_INFO_QUEUE_FILTER filter;
-					memset(&filter, 0, sizeof(filter) );
+					hr = m_device->QueryInterface(__uuidof(ID3D12InfoQueue), (void**)&m_infoQueue);
 
-					D3D12_MESSAGE_CATEGORY catlist[] =
+					if (SUCCEEDED(hr) )
 					{
-						D3D12_MESSAGE_CATEGORY_STATE_SETTING,
-						D3D12_MESSAGE_CATEGORY_EXECUTION,
-					};
-					filter.DenyList.NumCategories = BX_COUNTOF(catlist);
-					filter.DenyList.pCategoryList = catlist;
-					m_infoQueue->PushStorageFilter(&filter);
+						m_infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
+						m_infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR,      true);
+						m_infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING,    false);
+
+						D3D12_INFO_QUEUE_FILTER filter;
+						memset(&filter, 0, sizeof(filter) );
+
+						D3D12_MESSAGE_CATEGORY catlist[] =
+						{
+							D3D12_MESSAGE_CATEGORY_STATE_SETTING,
+							D3D12_MESSAGE_CATEGORY_EXECUTION,
+						};
+						filter.DenyList.NumCategories = BX_COUNTOF(catlist);
+						filter.DenyList.pCategoryList = catlist;
+						m_infoQueue->PushStorageFilter(&filter);
 
-					DX_RELEASE(m_infoQueue, 19);
+						DX_RELEASE(m_infoQueue, 19);
+					}
 				}
-			}
 
-			D3D12_DESCRIPTOR_HEAP_DESC rtvDescHeap;
-			rtvDescHeap.NumDescriptors = 0
-					+ BX_COUNTOF(m_backBufferColor)
-					+ BGFX_CONFIG_MAX_FRAME_BUFFERS*BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS
-					;
-			rtvDescHeap.Type     = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
-			rtvDescHeap.Flags    = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
-			rtvDescHeap.NodeMask = 0;
-			DX_CHECK(m_device->CreateDescriptorHeap(&rtvDescHeap
-					, __uuidof(ID3D12DescriptorHeap)
-					, (void**)&m_rtvDescriptorHeap
-					) );
-
-			D3D12_DESCRIPTOR_HEAP_DESC dsvDescHeap;
-			dsvDescHeap.NumDescriptors = 0
-					+ 1 // reserved for depth backbuffer.
-					+ BGFX_CONFIG_MAX_FRAME_BUFFERS
-					;
-			dsvDescHeap.Type     = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
-			dsvDescHeap.Flags    = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
-			dsvDescHeap.NodeMask = 0;
-			DX_CHECK(m_device->CreateDescriptorHeap(&dsvDescHeap
-					, __uuidof(ID3D12DescriptorHeap)
-					, (void**)&m_dsvDescriptorHeap
-					) );
+				D3D12_DESCRIPTOR_HEAP_DESC rtvDescHeap;
+				rtvDescHeap.NumDescriptors = 0
+						+ BX_COUNTOF(m_backBufferColor)
+						+ BGFX_CONFIG_MAX_FRAME_BUFFERS*BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS
+						;
+				rtvDescHeap.Type     = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
+				rtvDescHeap.Flags    = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
+				rtvDescHeap.NodeMask = 0;
+				DX_CHECK(m_device->CreateDescriptorHeap(&rtvDescHeap
+						, __uuidof(ID3D12DescriptorHeap)
+						, (void**)&m_rtvDescriptorHeap
+						) );
 
-			for (uint32_t ii = 0; ii < BX_COUNTOF(m_scratchBuffer); ++ii)
-			{
-				m_scratchBuffer[ii].create(BGFX_CONFIG_MAX_DRAW_CALLS*1024
-						, BGFX_CONFIG_MAX_TEXTURES + BGFX_CONFIG_MAX_SHADERS + BGFX_CONFIG_MAX_DRAW_CALLS
+				D3D12_DESCRIPTOR_HEAP_DESC dsvDescHeap;
+				dsvDescHeap.NumDescriptors = 0
+						+ 1 // reserved for depth backbuffer.
+						+ BGFX_CONFIG_MAX_FRAME_BUFFERS
+						;
+				dsvDescHeap.Type     = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
+				dsvDescHeap.Flags    = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
+				dsvDescHeap.NodeMask = 0;
+				DX_CHECK(m_device->CreateDescriptorHeap(&dsvDescHeap
+						, __uuidof(ID3D12DescriptorHeap)
+						, (void**)&m_dsvDescriptorHeap
+						) );
+
+				for (uint32_t ii = 0; ii < BX_COUNTOF(m_scratchBuffer); ++ii)
+				{
+					m_scratchBuffer[ii].create(BGFX_CONFIG_MAX_DRAW_CALLS*1024
+							, BGFX_CONFIG_MAX_TEXTURES + BGFX_CONFIG_MAX_SHADERS + BGFX_CONFIG_MAX_DRAW_CALLS
+							);
+				}
+				m_samplerAllocator.create(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER
+						, 1024
+						, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS
 						);
-			}
-			m_samplerAllocator.create(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER
-					, 1024
-					, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS
-					);
 
-			D3D12_DESCRIPTOR_RANGE descRange[] =
-			{
-				{ D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, 0, 0, D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND },
-				{ D3D12_DESCRIPTOR_RANGE_TYPE_SRV,     BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, 0, 0, D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND },
-				{ D3D12_DESCRIPTOR_RANGE_TYPE_CBV,     1,                                0, 0, D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND },
-				{ D3D12_DESCRIPTOR_RANGE_TYPE_UAV,     BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, 0, 0, D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND },
-			};
-			BX_STATIC_ASSERT(BX_COUNTOF(descRange) == Rdt::Count);
+				D3D12_DESCRIPTOR_RANGE descRange[] =
+				{
+					{ D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, 0, 0, D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND },
+					{ D3D12_DESCRIPTOR_RANGE_TYPE_SRV,     BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, 0, 0, D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND },
+					{ D3D12_DESCRIPTOR_RANGE_TYPE_CBV,     1,                                0, 0, D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND },
+					{ D3D12_DESCRIPTOR_RANGE_TYPE_UAV,     BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, 0, 0, D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND },
+				};
+				BX_STATIC_ASSERT(BX_COUNTOF(descRange) == Rdt::Count);
 
-			D3D12_ROOT_PARAMETER rootParameter[] =
-			{
-				{ D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, { 1, &descRange[Rdt::Sampler] }, D3D12_SHADER_VISIBILITY_ALL    },
-				{ D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, { 1, &descRange[Rdt::SRV]     }, D3D12_SHADER_VISIBILITY_ALL    },
-				{ D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, { 1, &descRange[Rdt::CBV]     }, D3D12_SHADER_VISIBILITY_ALL    },
-//				{ D3D12_ROOT_PARAMETER_TYPE_CBV,              { 0, 0                        }, D3D12_SHADER_VISIBILITY_ALL    },
-				{ D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, { 1, &descRange[Rdt::UAV]     }, D3D12_SHADER_VISIBILITY_ALL    },
-			};
-// 			rootParameter[Rdt::CBV].Constants.ShaderRegister = 0;
-// 			rootParameter[Rdt::CBV].Constants.RegisterSpace  = 100;
-// 			rootParameter[Rdt::CBV].Constants.Num32BitValues = 0;
-
-			D3D12_ROOT_SIGNATURE_DESC descRootSignature;
-			descRootSignature.NumParameters = BX_COUNTOF(rootParameter);
-			descRootSignature.pParameters   = rootParameter;
-			descRootSignature.NumStaticSamplers = 0;
-			descRootSignature.pStaticSamplers   = NULL;
-			descRootSignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
-
-			ID3DBlob* outBlob;
-			ID3DBlob* errorBlob;
-			DX_CHECK(D3D12SerializeRootSignature(&descRootSignature
-					, D3D_ROOT_SIGNATURE_VERSION_1
-					, &outBlob
-					, &errorBlob
-					) );
-
-			DX_CHECK(m_device->CreateRootSignature(0
-					, outBlob->GetBufferPointer()
-					, outBlob->GetBufferSize()
-					, __uuidof(ID3D12RootSignature)
-					, (void**)&m_rootSignature
-					) );
-
-			UniformHandle handle = BGFX_INVALID_HANDLE;
-			for (uint32_t ii = 0; ii < PredefinedUniform::Count; ++ii)
-			{
-				m_uniformReg.add(handle, getPredefinedUniformName(PredefinedUniform::Enum(ii) ), &m_predefinedUniforms[ii]);
-			}
-
-			g_caps.supported |= ( 0
-								| BGFX_CAPS_TEXTURE_3D
-								| BGFX_CAPS_TEXTURE_COMPARE_ALL
-								| BGFX_CAPS_INSTANCING
-								| BGFX_CAPS_VERTEX_ATTRIB_HALF
-								| BGFX_CAPS_FRAGMENT_DEPTH
-								| BGFX_CAPS_BLEND_INDEPENDENT
-								| BGFX_CAPS_COMPUTE
-								| BGFX_CAPS_FRAGMENT_ORDERING
-//								| BGFX_CAPS_SWAP_CHAIN
-								);
-			g_caps.maxTextureSize   = 16384;
-			g_caps.maxFBAttachments = bx::uint32_min(16, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS);
+				D3D12_ROOT_PARAMETER rootParameter[] =
+				{
+					{ D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, { 1, &descRange[Rdt::Sampler] }, D3D12_SHADER_VISIBILITY_ALL    },
+					{ D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, { 1, &descRange[Rdt::SRV]     }, D3D12_SHADER_VISIBILITY_ALL    },
+					{ D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, { 1, &descRange[Rdt::CBV]     }, D3D12_SHADER_VISIBILITY_ALL    },
+	//				{ D3D12_ROOT_PARAMETER_TYPE_CBV,              { 0, 0                        }, D3D12_SHADER_VISIBILITY_ALL    },
+					{ D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, { 1, &descRange[Rdt::UAV]     }, D3D12_SHADER_VISIBILITY_ALL    },
+				};
+	// 			rootParameter[Rdt::CBV].Constants.ShaderRegister = 0;
+	// 			rootParameter[Rdt::CBV].Constants.RegisterSpace  = 100;
+	// 			rootParameter[Rdt::CBV].Constants.Num32BitValues = 0;
+
+				D3D12_ROOT_SIGNATURE_DESC descRootSignature;
+				descRootSignature.NumParameters = BX_COUNTOF(rootParameter);
+				descRootSignature.pParameters   = rootParameter;
+				descRootSignature.NumStaticSamplers = 0;
+				descRootSignature.pStaticSamplers   = NULL;
+				descRootSignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+				ID3DBlob* outBlob;
+				ID3DBlob* errorBlob;
+				DX_CHECK(D3D12SerializeRootSignature(&descRootSignature
+						, D3D_ROOT_SIGNATURE_VERSION_1
+						, &outBlob
+						, &errorBlob
+						) );
 
-			for (uint32_t ii = 0; ii < TextureFormat::Count; ++ii)
-			{
-				uint8_t support = BGFX_CAPS_FORMAT_TEXTURE_NONE;
+				DX_CHECK(m_device->CreateRootSignature(0
+						, outBlob->GetBufferPointer()
+						, outBlob->GetBufferSize()
+						, __uuidof(ID3D12RootSignature)
+						, (void**)&m_rootSignature
+						) );
 
-				const DXGI_FORMAT fmt = isDepth(TextureFormat::Enum(ii) )
-					? s_textureFormat[ii].m_fmtDsv
-					: s_textureFormat[ii].m_fmt
-					;
+				UniformHandle handle = BGFX_INVALID_HANDLE;
+				for (uint32_t ii = 0; ii < PredefinedUniform::Count; ++ii)
+				{
+					m_uniformReg.add(handle, getPredefinedUniformName(PredefinedUniform::Enum(ii) ), &m_predefinedUniforms[ii]);
+				}
 
-				if (DXGI_FORMAT_UNKNOWN != fmt)
+				g_caps.supported |= ( 0
+									| BGFX_CAPS_TEXTURE_3D
+									| BGFX_CAPS_TEXTURE_COMPARE_ALL
+									| BGFX_CAPS_INSTANCING
+									| BGFX_CAPS_VERTEX_ATTRIB_HALF
+									| BGFX_CAPS_FRAGMENT_DEPTH
+									| BGFX_CAPS_BLEND_INDEPENDENT
+									| BGFX_CAPS_COMPUTE
+									| BGFX_CAPS_FRAGMENT_ORDERING
+	//								| BGFX_CAPS_SWAP_CHAIN
+									);
+				g_caps.maxTextureSize   = 16384;
+				g_caps.maxFBAttachments = bx::uint32_min(16, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS);
+
+				for (uint32_t ii = 0; ii < TextureFormat::Count; ++ii)
 				{
-					D3D12_FEATURE_DATA_FORMAT_SUPPORT data;
-					data.Format = fmt;
-					hr = m_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &data, sizeof(data) );
-					if (SUCCEEDED(hr) )
-					{
-						support |= 0 != (data.Support1 & (0
-								| D3D12_FORMAT_SUPPORT1_TEXTURE2D
-								| D3D12_FORMAT_SUPPORT1_TEXTURE3D
-								| D3D12_FORMAT_SUPPORT1_TEXTURECUBE
-								) )
-								? BGFX_CAPS_FORMAT_TEXTURE_COLOR
-								: BGFX_CAPS_FORMAT_TEXTURE_NONE
-								;
-
-						support |= 0 != (data.Support1 & (0
-								| D3D12_FORMAT_SUPPORT1_BUFFER
-								| D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER
-								| D3D12_FORMAT_SUPPORT1_IA_INDEX_BUFFER
-								) )
-								? BGFX_CAPS_FORMAT_TEXTURE_VERTEX
-								: BGFX_CAPS_FORMAT_TEXTURE_NONE
-								;
-
-						support |= 0 != (data.Support1 & (0
-								| D3D12_FORMAT_SUPPORT1_SHADER_LOAD
-								) )
-								? BGFX_CAPS_FORMAT_TEXTURE_IMAGE
-								: BGFX_CAPS_FORMAT_TEXTURE_NONE
-								;
-
-						support |= 0 != (data.Support1 & (0
-								| D3D12_FORMAT_SUPPORT1_RENDER_TARGET
-								| D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL
-								) )
-								? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER
-								: BGFX_CAPS_FORMAT_TEXTURE_NONE
-								;
-					}
-					else
+					uint8_t support = BGFX_CAPS_FORMAT_TEXTURE_NONE;
+
+					const DXGI_FORMAT fmt = isDepth(TextureFormat::Enum(ii) )
+						? s_textureFormat[ii].m_fmtDsv
+						: s_textureFormat[ii].m_fmt
+						;
+
+					if (DXGI_FORMAT_UNKNOWN != fmt)
 					{
-						BX_TRACE("CheckFeatureSupport failed with %x for format %s.", hr, getName(TextureFormat::Enum(ii) ) );
+						D3D12_FEATURE_DATA_FORMAT_SUPPORT data;
+						data.Format = fmt;
+						hr = m_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &data, sizeof(data) );
+						if (SUCCEEDED(hr) )
+						{
+							support |= 0 != (data.Support1 & (0
+									| D3D12_FORMAT_SUPPORT1_TEXTURE2D
+									| D3D12_FORMAT_SUPPORT1_TEXTURE3D
+									| D3D12_FORMAT_SUPPORT1_TEXTURECUBE
+									) )
+									? BGFX_CAPS_FORMAT_TEXTURE_COLOR
+									: BGFX_CAPS_FORMAT_TEXTURE_NONE
+									;
+
+							support |= 0 != (data.Support1 & (0
+									| D3D12_FORMAT_SUPPORT1_BUFFER
+									| D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER
+									| D3D12_FORMAT_SUPPORT1_IA_INDEX_BUFFER
+									) )
+									? BGFX_CAPS_FORMAT_TEXTURE_VERTEX
+									: BGFX_CAPS_FORMAT_TEXTURE_NONE
+									;
+
+							support |= 0 != (data.Support1 & (0
+									| D3D12_FORMAT_SUPPORT1_SHADER_LOAD
+									) )
+									? BGFX_CAPS_FORMAT_TEXTURE_IMAGE
+									: BGFX_CAPS_FORMAT_TEXTURE_NONE
+									;
+
+							support |= 0 != (data.Support1 & (0
+									| D3D12_FORMAT_SUPPORT1_RENDER_TARGET
+									| D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL
+									) )
+									? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER
+									: BGFX_CAPS_FORMAT_TEXTURE_NONE
+									;
+						}
+						else
+						{
+							BX_TRACE("CheckFeatureSupport failed with %x for format %s.", hr, getName(TextureFormat::Enum(ii) ) );
+						}
 					}
+
+					g_caps.formats[ii] = support;
 				}
 
-				g_caps.formats[ii] = support;
+				postReset();
 			}
+			return true;
 
-			postReset();
+		error:
+			switch (errorState)
+			{
+			default:
+			case 4:
+				m_cmd.shutdown();
+				DX_RELEASE(m_device, 0);
+			case 3:
+				DX_RELEASE(m_factory, 0);
+#if USE_D3D12_DYNAMIC_LIB
+			case 2:
+				bx::dlclose(m_dxgidll);
+			case 1:
+				bx::dlclose(m_d3d12dll);
+#endif // USE_D3D12_DYNAMIC_LIB
+			case 0:
+				break;
+			}
+
+			return false;
 		}
 
-		~RendererContextD3D12()
+		void shutdown()
 		{
 			preReset();
 
@@ -811,6 +888,7 @@ namespace bgfx { namespace d3d12
 			m_cmd.shutdown();
 
 			DX_RELEASE(m_device, 0);
+			DX_RELEASE(m_factory, 0);
 
 #if USE_D3D12_DYNAMIC_LIB
 			bx::dlclose(m_d3d12dll);
@@ -2188,12 +2266,17 @@ data.NumQualityLevels = 0;
 	RendererContextI* rendererCreate()
 	{
 		s_renderD3D12 = BX_NEW(g_allocator, RendererContextD3D12);
-		s_renderD3D12->init();
+		if (!s_renderD3D12->init() )
+		{
+			BX_DELETE(g_allocator, s_renderD3D12);
+			s_renderD3D12 = NULL;
+		}
 		return s_renderD3D12;
 	}
 
 	void rendererDestroy()
 	{
+		s_renderD3D12->shutdown();
 		BX_DELETE(g_allocator, s_renderD3D12);
 		s_renderD3D12 = NULL;
 	}

+ 96 - 11
src/renderer_d3d9.cpp

@@ -291,8 +291,10 @@ namespace bgfx { namespace d3d9
 		{
 		}
 
-		void init()
+		bool init()
 		{
+			uint32_t errorState = 0;
+
 			m_fbh.idx = invalidHandle;
 			memset(m_uniforms, 0, sizeof(m_uniforms) );
 			memset(&m_resolution, 0, sizeof(m_resolution) );
@@ -323,7 +325,14 @@ namespace bgfx { namespace d3d9
 			m_params.BackBufferHeight = rect.bottom-rect.top;
 
 			m_d3d9dll = bx::dlopen("d3d9.dll");
-			BGFX_FATAL(NULL != m_d3d9dll, Fatal::UnableToInitialize, "Failed to load d3d9.dll.");
+			BX_WARN(NULL != m_d3d9dll, "Failed to load d3d9.dll.");
+
+			if (NULL == m_d3d9dll)
+			{
+				goto error;
+			}
+
+			errorState = 1;
 
 			if (BX_ENABLED(BGFX_CONFIG_DEBUG_PIX) )
 			{
@@ -351,12 +360,25 @@ namespace bgfx { namespace d3d9
 #endif // BGFX_CONFIG_RENDERER_DIRECT3D9EX
 			{
 				Direct3DCreate9 = (Direct3DCreate9Fn)bx::dlsym(m_d3d9dll, "Direct3DCreate9");
-				BGFX_FATAL(NULL != Direct3DCreate9, Fatal::UnableToInitialize, "Function Direct3DCreate9 not found.");
+				BX_WARN(NULL != Direct3DCreate9, "Function Direct3DCreate9 not found.");
+
+				if (NULL == Direct3DCreate9)
+				{
+					goto error;
+				}
+
 				m_d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
 				m_pool = D3DPOOL_MANAGED;
 			}
 
-			BGFX_FATAL(m_d3d9, Fatal::UnableToInitialize, "Unable to create Direct3D.");
+			BX_WARN(NULL != m_d3d9, "Unable to create Direct3D.");
+
+			if (NULL == m_d3d9)
+			{
+				goto error;
+			}
+
+			errorState = 2;
 
 			m_adapter    = D3DADAPTER_DEFAULT;
 			m_deviceType = BGFX_PCI_ID_SOFTWARE_RASTERIZER == g_caps.vendorId
@@ -442,7 +464,14 @@ namespace bgfx { namespace d3d9
 #endif // BGFX_CONFIG_RENDERER_DIRECT3D9EX
 			}
 
-			BGFX_FATAL(m_device, Fatal::UnableToInitialize, "Unable to create Direct3D9 device.");
+			BX_WARN(NULL != m_device, "Unable to create Direct3D9 device.");
+
+			if (NULL == m_device)
+			{
+				goto error;
+			}
+
+			errorState = 3;
 
 			m_numWindows = 1;
 
@@ -456,15 +485,23 @@ namespace bgfx { namespace d3d9
 			DX_CHECK(m_device->GetDeviceCaps(&m_caps) );
 
 			// For shit GPUs that can create DX9 device but can't do simple stuff. GTFO!
-			BGFX_FATAL( (D3DPTEXTURECAPS_SQUAREONLY & m_caps.TextureCaps) == 0, Fatal::MinimumRequiredSpecs, "D3DPTEXTURECAPS_SQUAREONLY");
-			BGFX_FATAL( (D3DPTEXTURECAPS_MIPMAP & m_caps.TextureCaps) == D3DPTEXTURECAPS_MIPMAP, Fatal::MinimumRequiredSpecs, "D3DPTEXTURECAPS_MIPMAP");
-			BGFX_FATAL( (D3DPTEXTURECAPS_ALPHA & m_caps.TextureCaps) == D3DPTEXTURECAPS_ALPHA, Fatal::MinimumRequiredSpecs, "D3DPTEXTURECAPS_ALPHA");
-			BGFX_FATAL(m_caps.VertexShaderVersion >= D3DVS_VERSION(2, 0) && m_caps.PixelShaderVersion >= D3DPS_VERSION(2, 1)
-					  , Fatal::MinimumRequiredSpecs
+			BX_WARN( (D3DPTEXTURECAPS_SQUAREONLY & m_caps.TextureCaps) == 0, "D3DPTEXTURECAPS_SQUAREONLY");
+			BX_WARN( (D3DPTEXTURECAPS_MIPMAP     & m_caps.TextureCaps) == D3DPTEXTURECAPS_MIPMAP, "D3DPTEXTURECAPS_MIPMAP");
+			BX_WARN( (D3DPTEXTURECAPS_ALPHA      & m_caps.TextureCaps) == D3DPTEXTURECAPS_ALPHA, "D3DPTEXTURECAPS_ALPHA");
+			BX_WARN(m_caps.VertexShaderVersion >= D3DVS_VERSION(2, 0) && m_caps.PixelShaderVersion >= D3DPS_VERSION(2, 1)
 					  , "Shader Model Version (vs: %x, ps: %x)."
 					  , m_caps.VertexShaderVersion
 					  , m_caps.PixelShaderVersion
 					  );
+
+			if ( (D3DPTEXTURECAPS_SQUAREONLY & m_caps.TextureCaps) != 0
+			||   (D3DPTEXTURECAPS_MIPMAP     & m_caps.TextureCaps) != D3DPTEXTURECAPS_MIPMAP
+			||   (D3DPTEXTURECAPS_ALPHA      & m_caps.TextureCaps) != D3DPTEXTURECAPS_ALPHA
+			||   !(m_caps.VertexShaderVersion >= D3DVS_VERSION(2, 0) && m_caps.PixelShaderVersion >= D3DPS_VERSION(2, 1) ) )
+			{
+				goto error;
+			}
+
 			BX_TRACE("Max vertex shader 3.0 instr. slots: %d", m_caps.MaxVertexShader30InstructionSlots);
 			BX_TRACE("Max vertex shader constants: %d", m_caps.MaxVertexShaderConst);
 			BX_TRACE("Max fragment shader 2.0 instr. slots: %d", m_caps.PS20Caps.NumInstructionSlots);
@@ -632,6 +669,50 @@ namespace bgfx { namespace d3d9
 			postReset();
 
 			m_initialized = true;
+
+			return true;
+
+		error:
+			switch (errorState)
+			{
+			default:
+
+			case 3:
+#if BGFX_CONFIG_RENDERER_DIRECT3D9EX
+				if (NULL != m_d3d9ex)
+				{
+					DX_RELEASE(m_deviceEx, 1);
+					DX_RELEASE(m_device, 0);
+				}
+				else
+#endif // BGFX_CONFIG_RENDERER_DIRECT3D9EX
+				{
+					DX_RELEASE(m_device, 0);
+				}
+
+			case 2:
+#if BGFX_CONFIG_RENDERER_DIRECT3D9EX
+				if (NULL != m_d3d9ex)
+				{
+					DX_RELEASE(m_d3d9, 1);
+					DX_RELEASE(m_d3d9ex, 0);
+				}
+				else
+#endif // BGFX_CONFIG_RENDERER_DIRECT3D9EX
+				{
+					DX_RELEASE(m_d3d9, 0);
+				}
+
+#if BX_PLATFORM_WINDOWS
+			case 1:
+				bx::dlclose(m_d3d9dll);
+#endif // BX_PLATFORM_WINDOWS
+
+			case 0:
+				break;
+			}
+
+			return false;
 		}
 
 		void shutdown()
@@ -1800,7 +1881,11 @@ namespace bgfx { namespace d3d9
 	RendererContextI* rendererCreate()
 	{
 		s_renderD3D9 = BX_NEW(g_allocator, RendererContextD3D9);
-		s_renderD3D9->init();
+		if (!s_renderD3D9->init() )
+		{
+			BX_DELETE(g_allocator, s_renderD3D9);
+			s_renderD3D9 = NULL;
+		}
 		return s_renderD3D9;
 	}