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

Steve Lhomme git at videolan.org
Mon Jan 18 08:53:57 UTC 2021


vlc/vlc-3.0 | branch: master | Steve Lhomme <robux4 at ycbcr.xyz> | Fri Jan 15 15:01:22 2021 +0100| [429ff5cebdb43b42783db4116cfd3638e96a243f] | 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

(cherry picked from commit 61dbb36ebd3d58f230bfeb1c171eabe770affedd) (edited)

edited:
- the release of resources is done in a more flat function
- this branch didn't use pointers for d3dev

Signed-off-by: Steve Lhomme <robux4 at ycbcr.xyz>

> http://git.videolan.org/gitweb.cgi/vlc/vlc-3.0.git/?a=commit;h=429ff5cebdb43b42783db4116cfd3638e96a243f
---

 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 63c11509d0..90454edb91 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2573,7 +2573,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  avformat demuxer/muxer plugin
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index fe659a6d5a..d59b9dc9ea 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -45,6 +45,9 @@
 #else
 # include <dxgi1_5.h>
 #endif
+#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> */
@@ -99,6 +102,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_t            stagingSys;
 
@@ -993,6 +1002,22 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
         }
     }
 
+#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);
@@ -1617,14 +1642,54 @@ static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_forma
     return VLC_SUCCESS;
 }
 
+#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 };
@@ -1828,6 +1893,18 @@ static void Direct3D11DestroyResources(vout_display_t *vd)
         ID3D11PixelShader_Release(sys->picQuad.d3dpixelShader);
         sys->picQuad.d3dpixelShader = NULL;
     }
+#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