From ab22a64a1331dafa9c6ca542845240ada6850b48 Mon Sep 17 00:00:00 2001 From: Carsten Kroll Date: Mon, 22 Aug 2011 14:46:48 +0200 Subject: [PATCH] d3dvideosink: flush GPU before Present added alternate wait for vsync method based on GetRasterStatus --- sys/d3dvideosink/d3dvideosink.c | 69 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/sys/d3dvideosink/d3dvideosink.c b/sys/d3dvideosink/d3dvideosink.c index c42f6c2..77626b1 100644 --- a/sys/d3dvideosink/d3dvideosink.c +++ b/sys/d3dvideosink/d3dvideosink.c @@ -1587,6 +1587,65 @@ gst_d3dvideosink_stop (GstBaseSink * bsink) return TRUE; } +static void +gst_d3dvideosink_flush_gpu (GstD3DVideoSink * sink) +{ + LPDIRECT3DDEVICE9 d3ddev = NULL; + LPDIRECT3DQUERY9 pEventQuery = NULL; + + if (D3D_OK == IDirect3DSwapChain9_GetDevice (sink->d3d_swap_chain, &d3ddev)) { + IDirect3DDevice9_CreateQuery (d3ddev, D3DQUERYTYPE_EVENT, &pEventQuery); + IDirect3DDevice9_Release (d3ddev); + if (pEventQuery) { + IDirect3DQuery9_Issue (pEventQuery, D3DISSUE_END); + /* Empty the command buffer and wait until the GPU is idle. */ + while (S_FALSE == IDirect3DQuery9_GetData (pEventQuery, NULL, 0, + D3DGETDATA_FLUSH)); + IDirect3DQuery9_Release (pEventQuery); + } + } +} + +static void +gst_d3dvideosink_wait_for_vsync (GstD3DVideoSink * sink) +{ + D3DPRESENT_PARAMETERS d3dpp; + ZeroMemory (&d3dpp, sizeof (d3dpp)); + + IDirect3DSwapChain9_GetPresentParameters (sink->d3d_swap_chain, &d3dpp); + + if (d3dpp.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) { + D3DRASTER_STATUS raster_stat; + D3DDISPLAYMODE d3ddm; + UINT lastScanline = 0; + UINT vblankStart = 0; + HANDLE thdl = GetCurrentThread (); + int prio = GetThreadPriority (thdl); + ZeroMemory (&d3ddm, sizeof (d3ddm)); + + GST_ERROR_OBJECT (sink, "USING ALT VSYNC"); + + IDirect3DSwapChain9_GetDisplayMode (sink->d3d_swap_chain, &d3ddm); + vblankStart = d3ddm.Height - 10; + SetThreadPriority (thdl, THREAD_PRIORITY_TIME_CRITICAL); + do { + if (FAILED (IDirect3DSwapChain9_GetRasterStatus (sink->d3d_swap_chain, + &raster_stat))) + break; + if (!raster_stat.InVBlank) { + if (raster_stat.ScanLine < lastScanline) { + GST_INFO_OBJECT (sink, "missed last vsync curr : %d", + raster_stat.ScanLine); + break; + } + lastScanline = raster_stat.ScanLine; + SwitchToThread (); + } + } while (raster_stat.ScanLine < vblankStart); + SetThreadPriority (thdl, prio); + } +} + static GstFlowReturn gst_d3dvideosink_show_frame (GstVideoSink * vsink, GstBuffer * buffer) { @@ -1763,10 +1822,12 @@ gst_d3dvideosink_show_frame (GstVideoSink * vsink, GstBuffer * buffer) gst_d3dvideosink_stretch (sink, backBuffer); IDirect3DDevice9_EndScene (shared.d3ddev); } + gst_d3dvideosink_flush_gpu (sink); + gst_d3dvideosink_wait_for_vsync (sink); + hr = IDirect3DSwapChain9_Present (sink->d3d_swap_chain, NULL, NULL, NULL, + NULL, 0); /* Swap back and front buffers on video card and present to the user */ - if (FAILED (hr = - IDirect3DSwapChain9_Present (sink->d3d_swap_chain, NULL, NULL, NULL, - NULL, 0))) { + if (FAILED (hr)) { switch (hr) { case D3DERR_DEVICELOST: case D3DERR_DEVICENOTRESET: @@ -2237,11 +2298,13 @@ gst_d3dvideosink_initialize_swap_chain (GstD3DVideoSink * sink) ZeroMemory (&d3dpp, sizeof (d3dpp)); d3dpp.Windowed = TRUE; + d3dpp.Flags = D3DPRESENTFLAG_VIDEO; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = sink->window_handle; d3dpp.BackBufferFormat = d3dformat; d3dpp.BackBufferWidth = width; d3dpp.BackBufferHeight = height; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; /*D3DPRESENT_INTERVAL_IMMEDIATE; */ if (FAILED (IDirect3DDevice9_CreateAdditionalSwapChain (shared.d3ddev, &d3dpp, &d3dswapchain))) -- 2.7.4