[vlc-commits] direct3d11: use a ID3D11Fence to tell when the rendering is done

Steve Lhomme git at videolan.org
Mon Jan 18 08:47:04 UTC 2021


vlc | branch: master | Steve Lhomme <robux4 at ycbcr.xyz> | Fri Jan 15 14:29:54 2021 +0100| [61dbb36ebd3d58f230bfeb1c171eabe770affedd] | committer: Steve Lhomme

direct3d11: use a ID3D11Fence to tell when the rendering is done

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. Then 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 rendering.

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

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=61dbb36ebd3d58f230bfeb1c171eabe770affedd
---

 configure.ac                            |  2 +-
 modules/video_output/win32/direct3d11.c | 87 +++++++++++++++++++++++++++++++--
 2 files changed, 85 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index 96e47b1969..d8fdc9f57a 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 75221bf62d..daa5a2f6c8 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,58 @@ 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 (SUCCEEDED(hr))
+    {
+        msg_Dbg(vd, "using GPU render fence");
+    }
+    else
+#endif
+    {
+        D3D11_QUERY_DESC query = { 0 };
+        query.Query = D3D11_QUERY_EVENT;
+        ID3D11Device_CreateQuery(sys->d3d_dev->d3ddevice, &query, (ID3D11Query**)&sys->prepareWait);
+    }
 
     ID3D11BlendState *pSpuBlendState;
     D3D11_BLEND_DESC spuBlendDesc = { 0 };
@@ -1166,6 +1235,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);



More information about the vlc-commits mailing list