From 8b50eea485aa09a342c2c73a5b12549539f946a1 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Fri, 30 Aug 2024 22:22:30 -0500 Subject: [PATCH] Wait on a dummy fence before using textures shared with the decoder --- .../video/ffmpeg-renderers/d3d11va.cpp | 57 +++++++++++++++++++ .../video/ffmpeg-renderers/d3d11va.h | 12 +++- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/app/streaming/video/ffmpeg-renderers/d3d11va.cpp b/app/streaming/video/ffmpeg-renderers/d3d11va.cpp index d5f90f6d..fc5cd112 100644 --- a/app/streaming/video/ffmpeg-renderers/d3d11va.cpp +++ b/app/streaming/video/ffmpeg-renderers/d3d11va.cpp @@ -109,6 +109,8 @@ D3D11VARenderer::~D3D11VARenderer() SDL_DestroyMutex(m_ContextLock); + m_DecodeFence.Reset(); + m_VideoVertexBuffer.Reset(); for (auto& shader : m_VideoPixelShaders) { shader.Reset(); @@ -244,6 +246,26 @@ bool D3D11VARenderer::createDeviceByAdapterIndex(int adapterIndex, bool* adapter m_DevicesWithFL11Support++; } + // Check which fence types are supported by this GPU + { + m_FenceType = SupportedFenceType::None; + + ComPtr adapter4; + if (SUCCEEDED(adapter.As(&adapter4))) { + DXGI_ADAPTER_DESC3 desc3; + if (SUCCEEDED(adapter4->GetDesc3(&desc3))) { + if (desc3.Flags & DXGI_ADAPTER_FLAG3_SUPPORT_MONITORED_FENCES) { + // Monitored fences must be used when they are supported + m_FenceType = SupportedFenceType::Monitored; + } + else if (desc3.Flags & DXGI_ADAPTER_FLAG3_SUPPORT_NON_MONITORED_FENCES) { + // Non-monitored fences must only be used when monitored fences are unsupported + m_FenceType = SupportedFenceType::NonMonitored; + } + } + } + } + if (!checkDecoderSupport(adapter.Get())) { m_DeviceContext.Reset(); m_Device.Reset(); @@ -565,6 +587,20 @@ void D3D11VARenderer::renderFrame(AVFrame* frame) // access from inside FFmpeg's decoding code lockContext(this); + // Ensure decoding operations have completed using a dummy fence. + // This is not necessary on modern GPU drivers, but it is required + // on some older GPU drivers that don't properly synchronize the + // video engine with 3D operations. + if (m_BindDecoderOutputTextures && m_DecodeFence) { + ComPtr deviceContext4; + if (SUCCEEDED(m_DeviceContext.As(&deviceContext4))) { + auto desiredFenceValue = m_DecodeFence->GetCompletedValue() + 1; + if (SUCCEEDED(deviceContext4->Signal(m_DecodeFence.Get(), desiredFenceValue))) { + deviceContext4->Wait(m_DecodeFence.Get(), desiredFenceValue); + } + } + } + // Clear the back buffer const float clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f}; m_DeviceContext->ClearRenderTargetView(m_RenderTargetView.Get(), clearColor); @@ -1457,6 +1493,27 @@ bool D3D11VARenderer::setupRenderingResources() m_DeviceContext->RSSetViewports(1, &viewport); } + // Create our decoding fence if the GPU supports fences + if (m_FenceType != SupportedFenceType::None) { + ComPtr device5; + if (SUCCEEDED(m_Device.As(&device5))) { + hr = device5->CreateFence(0, + m_FenceType == SupportedFenceType::Monitored ? + D3D11_FENCE_FLAG_NONE : D3D11_FENCE_FLAG_NON_MONITORED, + IID_PPV_ARGS(&m_DecodeFence)); + if (FAILED(hr)) { + // Non-fatal + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "ID3D11Device5::CreateFence() failed: %x", + hr); + } + } + else { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "ID3D11Device5::CreateFence() not available until Windows 10 1703"); + } + } + return true; } diff --git a/app/streaming/video/ffmpeg-renderers/d3d11va.h b/app/streaming/video/ffmpeg-renderers/d3d11va.h index ea6c8334..5712f1a6 100644 --- a/app/streaming/video/ffmpeg-renderers/d3d11va.h +++ b/app/streaming/video/ffmpeg-renderers/d3d11va.h @@ -2,8 +2,8 @@ #include "renderer.h" -#include -#include +#include +#include extern "C" { #include @@ -53,11 +53,19 @@ private: int m_DevicesWithFL11Support; int m_DevicesWithCodecSupport; + enum class SupportedFenceType { + None, + NonMonitored, + Monitored, + }; + Microsoft::WRL::ComPtr m_Factory; Microsoft::WRL::ComPtr m_Device; Microsoft::WRL::ComPtr m_SwapChain; Microsoft::WRL::ComPtr m_DeviceContext; Microsoft::WRL::ComPtr m_RenderTargetView; + Microsoft::WRL::ComPtr m_DecodeFence; + SupportedFenceType m_FenceType; SDL_mutex* m_ContextLock; bool m_BindDecoderOutputTextures;