[vlc-devel] [PATCH v2 2/2] direct3d11: use a ID3D11Fence to tell when the rendering is done

Steve Lhomme robux4 at ycbcr.xyz
Fri Jan 15 13:49:09 UTC 2021


This is a lot more accurate and wastes a lot less time than the Query approach.
The D3D11 Fence value is set when the GPU is done doing the previous
(rendering) commands. The we can wait in the CPU for this event and return when
it's done. All decoder/filter commands seem to not have any impact so that's
really the signal we're looking for to tell the core we're done.

This is only supported on newer mingw toolchains and only on Windows 10
Creators Update, which should cover pretty much all Win10 installed machines.

Better fixes #21600
---
 configure.ac                            |  2 +-
 modules/video_output/win32/direct3d11.c | 83 ++++++++++++++++++++++++-
 2 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index 96e47b19697..d8fdc9f57a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2763,7 +2763,7 @@ AM_CONDITIONAL([HAVE_AVCODEC_D3D11VA], [test "${have_avcodec_d3d11va}" = "yes"])
 dnl
 dnl DXGI debug
 dnl
-AC_CHECK_HEADERS([dxgidebug.h dxgi1_6.h])
+AC_CHECK_HEADERS([dxgidebug.h dxgi1_6.h d3d11_4.h])
 
 dnl
 dnl IApplicationData2
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index 75221bf62db..eb785bfaed2 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -46,6 +46,9 @@
 #define COBJMACROS
 #include <initguid.h>
 #include <d3d11.h>
+#ifdef HAVE_D3D11_4_H
+#include <d3d11_4.h>
+#endif
 
 /* avoided until we can pass ISwapchainPanel without c++/cx mode
 # include <windows.ui.xaml.media.dxinterop.h> */
@@ -101,6 +104,12 @@ struct vout_display_sys_t
     d3d_quad_t               picQuad;
 
     ID3D11Asynchronous       *prepareWait;
+#ifdef HAVE_D3D11_4_H
+    ID3D11Fence              *d3dRenderFence;
+    ID3D11DeviceContext4     *d3dcontext4;
+    UINT64                   renderFence;
+    HANDLE                   renderFinished;
+#endif
 
     picture_sys_d3d11_t      stagingSys;
     plane_t                  stagingPlanes[PICTURE_PLANE_MAX];
@@ -611,6 +620,22 @@ static void PreparePicture(vout_display_t *vd, picture_t *picture, subpicture_t
         }
     }
 
+#ifdef HAVE_D3D11_4_H
+    if (sys->d3dcontext4)
+    {
+        if (sys->renderFence == UINT64_MAX)
+            sys->renderFence;
+        else
+            sys->renderFence++;
+
+        ResetEvent(sys->renderFinished);
+        ID3D11Fence_SetEventOnCompletion(sys->d3dRenderFence, sys->renderFence, sys->renderFinished);
+        ID3D11DeviceContext4_Signal(sys->d3dcontext4, sys->d3dRenderFence, sys->renderFence);
+
+        WaitForSingleObject(sys->renderFinished, INFINITE);
+    }
+    else
+#endif
     if (sys->prepareWait)
     {
         ID3D11DeviceContext_End(sys->d3d_dev->d3dcontext, sys->prepareWait);
@@ -1061,14 +1086,54 @@ static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_forma
     return UpdateStaging(vd, fmt);
 }
 
+#ifdef HAVE_D3D11_4_H
+static HRESULT InitRenderFence(vout_display_sys_t *sys)
+{
+    HRESULT hr;
+    sys->renderFinished = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (unlikely(sys->renderFinished == NULL))
+        return S_FALSE;
+    ID3D11Device5 *d3ddev5 = NULL;
+    hr = ID3D11DeviceContext_QueryInterface(sys->d3d_dev->d3dcontext, &IID_ID3D11DeviceContext4, (void**)&sys->d3dcontext4);
+    if (FAILED(hr))
+        goto error;
+    hr = ID3D11Device_QueryInterface(sys->d3d_dev->d3ddevice, &IID_ID3D11Device5, (void**)&d3ddev5);
+    if (FAILED(hr))
+        goto error;
+    hr = ID3D11Device5_CreateFence(d3ddev5, sys->renderFence, D3D11_FENCE_FLAG_NONE, &IID_ID3D11Fence, (void**)&sys->d3dRenderFence);
+    if (FAILED(hr))
+        goto error;
+    ID3D11Device5_Release(d3ddev5);
+    return hr;
+error:
+    if (d3ddev5)
+        ID3D11Device5_Release(d3ddev5);
+    if (sys->d3dRenderFence)
+    {
+        ID3D11Fence_Release(sys->d3dRenderFence);
+        sys->d3dRenderFence = NULL;
+    }
+    ID3D11DeviceContext4_Release(sys->d3dcontext4);
+    sys->d3dcontext4 = NULL;
+    CloseHandle(sys->renderFinished);
+    return hr;
+}
+#endif // HAVE_D3D11_4_H
+
 static int Direct3D11CreateGenericResources(vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;
     HRESULT hr;
 
-    D3D11_QUERY_DESC query = { 0 };
-    query.Query = D3D11_QUERY_EVENT;
-    hr = ID3D11Device_CreateQuery(sys->d3d_dev->d3ddevice, &query, (ID3D11Query**)&sys->prepareWait);
+#ifdef HAVE_D3D11_4_H
+    hr = InitRenderFence(sys);
+    if (FAILED(hr))
+#endif
+    {
+        D3D11_QUERY_DESC query = { 0 };
+        query.Query = D3D11_QUERY_EVENT;
+        hr = ID3D11Device_CreateQuery(sys->d3d_dev->d3ddevice, &query, (ID3D11Query**)&sys->prepareWait);
+    }
 
     ID3D11BlendState *pSpuBlendState;
     D3D11_BLEND_DESC spuBlendDesc = { 0 };
@@ -1166,6 +1231,18 @@ static void Direct3D11DestroyResources(vout_display_t *vd)
     D3D11_ReleaseVertexShader(&sys->flatVShader);
     D3D11_ReleaseVertexShader(&sys->projectionVShader);
 
+#ifdef HAVE_D3D11_4_H
+    if (sys->d3dcontext4)
+    {
+        ID3D11Fence_Release(sys->d3dRenderFence);
+        sys->d3dRenderFence = NULL;
+        ID3D11DeviceContext4_Release(sys->d3dcontext4);
+        sys->d3dcontext4 = NULL;
+        CloseHandle(sys->renderFinished);
+        sys->renderFinished = NULL;
+    }
+    else
+#endif
     if (sys->prepareWait)
     {
         ID3D11Query_Release(sys->prepareWait);
-- 
2.29.2



More information about the vlc-devel mailing list