Przeglądaj źródła

libobs-d3d11: Use waitable object to avoid stalls

Skip Present if the waitable object says the swap chain isn't ready.
jpark37 4 lat temu
rodzic
commit
608cd3867e

+ 30 - 7
libobs-d3d11/d3d11-subsystem.cpp

@@ -203,6 +203,7 @@ gs_swap_chain::gs_swap_chain(gs_device *device, const gs_init_data *data)
 		initData.num_backbuffers = max(data->num_backbuffers, 2);
 
 		effect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
+		flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
 
 		ComPtr<IDXGIFactory5> factory5;
 		factory5 = ComQIPtr<IDXGIFactory5>(device->factory);
@@ -221,17 +222,34 @@ gs_swap_chain::gs_swap_chain(gs_device *device, const gs_init_data *data)
 	}
 
 	make_swap_desc(swapDesc, &initData, effect, flags);
-	const HRESULT hr = device->factory->CreateSwapChain(
-		device->device, &swapDesc, swap.Assign());
+	HRESULT hr = device->factory->CreateSwapChain(device->device, &swapDesc,
+						      swap.Assign());
 	if (FAILED(hr))
 		throw HRError("Failed to create swap chain", hr);
 
 	/* Ignore Alt+Enter */
 	device->factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
 
+	if (flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) {
+		ComPtr<IDXGISwapChain2> swap2 = ComQIPtr<IDXGISwapChain2>(swap);
+		hWaitable = swap2->GetFrameLatencyWaitableObject();
+		if (hWaitable) {
+			hr = swap2->SetMaximumFrameLatency(40);
+			if (FAILED(hr))
+				throw HRError("Could not relax frame latency",
+					      hr);
+		}
+	}
+
 	Init();
 }
 
+gs_swap_chain::~gs_swap_chain()
+{
+	if (hWaitable)
+		CloseHandle(hWaitable);
+}
+
 void gs_device::InitCompiler()
 {
 	char d3dcompiler[40] = {};
@@ -2019,11 +2037,16 @@ void device_present(gs_device_t *device)
 {
 	gs_swap_chain *const curSwapChain = device->curSwapChain;
 	if (curSwapChain) {
-		const HRESULT hr = curSwapChain->swap->Present(
-			0, curSwapChain->presentFlags);
-		if (hr == DXGI_ERROR_DEVICE_REMOVED ||
-		    hr == DXGI_ERROR_DEVICE_RESET) {
-			device->RebuildDevice();
+		/* Skip Present because full queue may cause a stall */
+		const HANDLE hWaitiable = curSwapChain->hWaitable;
+		if ((hWaitiable == NULL) ||
+		    WaitForSingleObject(hWaitiable, 0) == WAIT_OBJECT_0) {
+			const HRESULT hr = curSwapChain->swap->Present(
+				0, curSwapChain->presentFlags);
+			if (hr == DXGI_ERROR_DEVICE_REMOVED ||
+			    hr == DXGI_ERROR_DEVICE_RESET) {
+				device->RebuildDevice();
+			}
 		}
 	} else {
 		blog(LOG_WARNING, "device_present (D3D11): No active swap");

+ 7 - 1
libobs-d3d11/d3d11-subsystem.hpp

@@ -801,6 +801,7 @@ struct gs_swap_chain : gs_obj {
 	gs_texture_2d target;
 	gs_zstencil_buffer zs;
 	ComPtr<IDXGISwapChain> swap;
+	HANDLE hWaitable = NULL;
 
 	void InitTarget(uint32_t cx, uint32_t cy);
 	void InitZStencilBuffer(uint32_t cx, uint32_t cy);
@@ -813,10 +814,15 @@ struct gs_swap_chain : gs_obj {
 	{
 		target.Release();
 		zs.Release();
-		swap.Release();
+		if (hWaitable) {
+			CloseHandle(hWaitable);
+			hWaitable = NULL;
+		}
+		swap.Clear();
 	}
 
 	gs_swap_chain(gs_device *device, const gs_init_data *data);
+	virtual ~gs_swap_chain();
 };
 
 struct BlendState {