From b6bb96223d744c2baddb7790f2a5f1b587640450 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 22 Jun 2024 12:34:10 -0500 Subject: [PATCH] Revert "Remove manual hwframe ctx setup for D3D11VA" We need this back to avoid the copy that's tanking performance on Intel iGPUs. This reverts commit 2cef09471b80d46ea3b59a936494a44a68ad5d67. --- .../video/ffmpeg-renderers/d3d11va.cpp | 59 +++++++++++++++++-- .../video/ffmpeg-renderers/d3d11va.h | 3 + 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/app/streaming/video/ffmpeg-renderers/d3d11va.cpp b/app/streaming/video/ffmpeg-renderers/d3d11va.cpp index 66364532..50cf15e9 100644 --- a/app/streaming/video/ffmpeg-renderers/d3d11va.cpp +++ b/app/streaming/video/ffmpeg-renderers/d3d11va.cpp @@ -93,7 +93,8 @@ D3D11VARenderer::D3D11VARenderer(int decoderSelectionPass) m_VideoTexture(nullptr), m_OverlayLock(0), m_OverlayPixelShader(nullptr), - m_HwDeviceContext(nullptr) + m_HwDeviceContext(nullptr), + m_HwFramesContext(nullptr) { RtlZeroMemory(m_OverlayVertexBuffers, sizeof(m_OverlayVertexBuffers)); RtlZeroMemory(m_OverlayTextures, sizeof(m_OverlayTextures)); @@ -139,6 +140,10 @@ D3D11VARenderer::~D3D11VARenderer() SAFE_COM_RELEASE(m_RenderTargetView); SAFE_COM_RELEASE(m_SwapChain); + if (m_HwFramesContext != nullptr) { + av_buffer_unref(&m_HwFramesContext); + } + // Force destruction of the swapchain immediately if (m_DeviceContext != nullptr) { m_DeviceContext->ClearState(); @@ -429,6 +434,10 @@ bool D3D11VARenderer::initialize(PDECODER_PARAMETERS params) return false; } + // Surfaces must be 16 pixel aligned for H.264 and 128 pixel aligned for everything else + // https://github.com/FFmpeg/FFmpeg/blob/a234e5cd80224c95a205c1f3e297d8c04a1374c3/libavcodec/dxva2.c#L609-L616 + m_TextureAlignment = (params->videoFormat & VIDEO_FORMAT_MASK_H264) ? 16 : 128; + if (!setupRenderingResources()) { return false; } @@ -462,9 +471,43 @@ bool D3D11VARenderer::initialize(PDECODER_PARAMETERS params) } } - // Create our video texture and SRVs - if (!setupVideoTexture()) { - return false; + { + m_HwFramesContext = av_hwframe_ctx_alloc(m_HwDeviceContext); + if (!m_HwFramesContext) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Failed to allocate D3D11VA frame context"); + return false; + } + + AVHWFramesContext* framesContext = (AVHWFramesContext*)m_HwFramesContext->data; + + // We require NV12 or P010 textures for our shader + framesContext->format = AV_PIX_FMT_D3D11; + framesContext->sw_format = (params->videoFormat & VIDEO_FORMAT_MASK_10BIT) ? + AV_PIX_FMT_P010 : AV_PIX_FMT_NV12; + + framesContext->width = FFALIGN(params->width, m_TextureAlignment); + framesContext->height = FFALIGN(params->height, m_TextureAlignment); + + // We can have up to 16 reference frames plus a working surface + framesContext->initial_pool_size = 17; + + AVD3D11VAFramesContext* d3d11vaFramesContext = (AVD3D11VAFramesContext*)framesContext->hwctx; + + d3d11vaFramesContext->BindFlags = D3D11_BIND_DECODER; + + int err = av_hwframe_ctx_init(m_HwFramesContext); + if (err < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Failed to initialize D3D11VA frame context: %d", + err); + return false; + } + + // Create our video texture and SRVs + if (!setupVideoTexture()) { + return false; + } } return true; @@ -480,6 +523,14 @@ bool D3D11VARenderer::prepareDecoderContext(AVCodecContext* context, AVDictionar return true; } +bool D3D11VARenderer::prepareDecoderContextInGetFormat(AVCodecContext *context, AVPixelFormat) +{ + // hw_frames_ctx must be initialized in ffGetFormat(). + context->hw_frames_ctx = av_buffer_ref(m_HwFramesContext); + + return true; +} + void D3D11VARenderer::renderFrame(AVFrame* frame) { // Acquire the context lock for rendering to prevent concurrent diff --git a/app/streaming/video/ffmpeg-renderers/d3d11va.h b/app/streaming/video/ffmpeg-renderers/d3d11va.h index 88aa86fc..6434a5c2 100644 --- a/app/streaming/video/ffmpeg-renderers/d3d11va.h +++ b/app/streaming/video/ffmpeg-renderers/d3d11va.h @@ -16,6 +16,7 @@ public: virtual ~D3D11VARenderer() override; virtual bool initialize(PDECODER_PARAMETERS params) override; virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary**) override; + virtual bool prepareDecoderContextInGetFormat(AVCodecContext* context, AVPixelFormat pixelFormat) override; virtual void renderFrame(AVFrame* frame) override; virtual void notifyOverlayUpdated(Overlay::OverlayType) override; virtual int getRendererAttributes() override; @@ -47,6 +48,7 @@ private: SDL_mutex* m_ContextLock; DECODER_PARAMETERS m_DecoderParams; + int m_TextureAlignment; int m_DisplayWidth; int m_DisplayHeight; int m_LastColorSpace; @@ -70,5 +72,6 @@ private: ID3D11PixelShader* m_OverlayPixelShader; AVBufferRef* m_HwDeviceContext; + AVBufferRef* m_HwFramesContext; };