From a6fccf93d149a8b67eeac0b0fe109a142f0937d8 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 26 Oct 2022 21:48:55 -0500 Subject: [PATCH] Use a separate texture for rendering to avoid blending in the alignment padding Fixes #885 --- .../video/ffmpeg-renderers/d3d11va.cpp | 126 ++++++++++-------- .../video/ffmpeg-renderers/d3d11va.h | 6 +- 2 files changed, 70 insertions(+), 62 deletions(-) diff --git a/app/streaming/video/ffmpeg-renderers/d3d11va.cpp b/app/streaming/video/ffmpeg-renderers/d3d11va.cpp index c1e3a827..6713c4b1 100644 --- a/app/streaming/video/ffmpeg-renderers/d3d11va.cpp +++ b/app/streaming/video/ffmpeg-renderers/d3d11va.cpp @@ -87,6 +87,7 @@ D3D11VARenderer::D3D11VARenderer(int decoderSelectionPass) m_VideoBt601LimPixelShader(nullptr), m_VideoBt2020LimPixelShader(nullptr), m_VideoVertexBuffer(nullptr), + m_VideoTexture(nullptr), m_OverlayLock(0), m_OverlayPixelShader(nullptr), m_HwDeviceContext(nullptr), @@ -114,10 +115,11 @@ D3D11VARenderer::~D3D11VARenderer() SAFE_COM_RELEASE(m_VideoGenericPixelShader); for (int i = 0; i < ARRAYSIZE(m_VideoTextureResourceViews); i++) { - SAFE_COM_RELEASE(m_VideoTextureResourceViews[i][0]); - SAFE_COM_RELEASE(m_VideoTextureResourceViews[i][1]); + SAFE_COM_RELEASE(m_VideoTextureResourceViews[i]); } + SAFE_COM_RELEASE(m_VideoTexture); + for (int i = 0; i < ARRAYSIZE(m_OverlayVertexBuffers); i++) { SAFE_COM_RELEASE(m_OverlayVertexBuffers[i]); } @@ -459,12 +461,11 @@ bool D3D11VARenderer::initialize(PDECODER_PARAMETERS params) framesContext->height = FFALIGN(params->height, m_TextureAlignment); // We can have up to 16 reference frames plus a working surface - framesContext->initial_pool_size = DECODER_BUFFER_POOL_SIZE; + framesContext->initial_pool_size = 17; AVD3D11VAFramesContext* d3d11vaFramesContext = (AVD3D11VAFramesContext*)framesContext->hwctx; - // We need to override the default D3D11VA bind flags to bind the textures as a shader resources - d3d11vaFramesContext->BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE; + d3d11vaFramesContext->BindFlags = D3D11_BIND_DECODER; int err = av_hwframe_ctx_init(m_HwFramesContext); if (err < 0) { @@ -474,8 +475,8 @@ bool D3D11VARenderer::initialize(PDECODER_PARAMETERS params) return false; } - // Create SRVs for all textures in the decoder pool - if (!setupTexturePoolViews(d3d11vaFramesContext)) { + // Create our video texture and SRVs + if (!setupVideoTexture()) { return false; } } @@ -763,22 +764,21 @@ void D3D11VARenderer::renderVideo(AVFrame* frame) UINT offset = 0; m_DeviceContext->IASetVertexBuffers(0, 1, &m_VideoVertexBuffer, &stride, &offset); - // Our indexing logic depends on a direct mapping into m_VideoTextureResourceViews - // based on the texture index provided by FFmpeg. - UINT textureIndex = (uintptr_t)frame->data[1]; - SDL_assert(textureIndex < DECODER_BUFFER_POOL_SIZE); - if (textureIndex >= DECODER_BUFFER_POOL_SIZE) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "Unexpected texture index: %u", - textureIndex); - return; - } + // Copy this frame (minus alignment padding) into our video texture + D3D11_BOX srcBox; + srcBox.left = 0; + srcBox.top = 0; + srcBox.right = m_DecoderParams.width; + srcBox.bottom = m_DecoderParams.height; + srcBox.front = 0; + srcBox.back = 1; + m_DeviceContext->CopySubresourceRegion(m_VideoTexture, 0, 0, 0, 0, (ID3D11Resource*)frame->data[0], (int)(intptr_t)frame->data[1], &srcBox); // Bind our CSC shader (and constant buffer, if required) bindColorConversion(frame); // Bind SRVs for this frame - m_DeviceContext->PSSetShaderResources(0, 2, m_VideoTextureResourceViews[textureIndex]); + m_DeviceContext->PSSetShaderResources(0, 2, m_VideoTextureResourceViews); // Draw the video m_DeviceContext->DrawIndexed(6, 0, 0); @@ -1238,17 +1238,12 @@ bool D3D11VARenderer::setupRenderingResources() SDL_FRect renderRect; StreamUtils::screenSpaceToNormalizedDeviceCoords(&dst, &renderRect, m_DisplayWidth, m_DisplayHeight); - // Don't sample from the alignment padding area since that's not part of the video - SDL_assert(m_TextureAlignment != 0); - float uMax = (float)m_DecoderParams.width / FFALIGN(m_DecoderParams.width, m_TextureAlignment); - float vMax = (float)m_DecoderParams.height / FFALIGN(m_DecoderParams.height, m_TextureAlignment); - VERTEX verts[] = { - {renderRect.x, renderRect.y, 0, vMax}, + {renderRect.x, renderRect.y, 0, 1.0f}, {renderRect.x, renderRect.y+renderRect.h, 0, 0}, - {renderRect.x+renderRect.w, renderRect.y, uMax, vMax}, - {renderRect.x+renderRect.w, renderRect.y+renderRect.h, uMax, 0}, + {renderRect.x+renderRect.w, renderRect.y, 1.0f, 1.0f}, + {renderRect.x+renderRect.w, renderRect.y+renderRect.h, 1.0f, 0}, }; D3D11_BUFFER_DESC vbDesc = {}; @@ -1316,42 +1311,55 @@ bool D3D11VARenderer::setupRenderingResources() return true; } -bool D3D11VARenderer::setupTexturePoolViews(AVD3D11VAFramesContext* frameContext) +bool D3D11VARenderer::setupVideoTexture() { + HRESULT hr; + D3D11_TEXTURE2D_DESC texDesc = {}; + + texDesc.Width = m_DecoderParams.width; + texDesc.Height = m_DecoderParams.height; + texDesc.MipLevels = 1; + texDesc.ArraySize = 1; + texDesc.Format = (m_DecoderParams.videoFormat & VIDEO_FORMAT_MASK_10BIT) ? DXGI_FORMAT_P010 : DXGI_FORMAT_NV12; + texDesc.SampleDesc.Quality = 0; + texDesc.SampleDesc.Count = 1; + texDesc.Usage = D3D11_USAGE_DEFAULT; + texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + texDesc.CPUAccessFlags = 0; + texDesc.MiscFlags = 0; + + hr = m_Device->CreateTexture2D(&texDesc, nullptr, &m_VideoTexture); + if (FAILED(hr)) { + m_VideoTexture = nullptr; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "ID3D11Device::CreateTexture2D() failed: %x", + hr); + return false; + } + + // Create luminance and chrominance SRVs for each plane of the texture D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.MostDetailedMip = 0; - srvDesc.Texture2DArray.MipLevels = 1; - srvDesc.Texture2DArray.ArraySize = 1; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.MipLevels = 1; + srvDesc.Format = (m_DecoderParams.videoFormat & VIDEO_FORMAT_MASK_10BIT) ? DXGI_FORMAT_R16_UNORM : DXGI_FORMAT_R8_UNORM; + hr = m_Device->CreateShaderResourceView(m_VideoTexture, &srvDesc, &m_VideoTextureResourceViews[0]); + if (FAILED(hr)) { + m_VideoTextureResourceViews[0] = nullptr; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "ID3D11Device::CreateShaderResourceView() failed: %x", + hr); + return false; + } - // Create luminance and chrominance SRVs for each texture in the pool - for (int i = 0; i < DECODER_BUFFER_POOL_SIZE; i++) { - HRESULT hr; - - // Our rendering logic depends on the texture index working to map into our SRV array - SDL_assert(i == frameContext->texture_infos[i].index); - - srvDesc.Texture2DArray.FirstArraySlice = frameContext->texture_infos[i].index; - - srvDesc.Format = (m_DecoderParams.videoFormat & VIDEO_FORMAT_MASK_10BIT) ? DXGI_FORMAT_R16_UNORM : DXGI_FORMAT_R8_UNORM; - hr = m_Device->CreateShaderResourceView(frameContext->texture_infos[i].texture, &srvDesc, &m_VideoTextureResourceViews[i][0]); - if (FAILED(hr)) { - m_VideoTextureResourceViews[i][0] = nullptr; - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "ID3D11Device::CreateShaderResourceView() failed: %x", - hr); - return false; - } - - srvDesc.Format = (m_DecoderParams.videoFormat & VIDEO_FORMAT_MASK_10BIT) ? DXGI_FORMAT_R16G16_UNORM : DXGI_FORMAT_R8G8_UNORM; - hr = m_Device->CreateShaderResourceView(frameContext->texture_infos[i].texture, &srvDesc, &m_VideoTextureResourceViews[i][1]); - if (FAILED(hr)) { - m_VideoTextureResourceViews[i][1] = nullptr; - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "ID3D11Device::CreateShaderResourceView() failed: %x", - hr); - return false; - } + srvDesc.Format = (m_DecoderParams.videoFormat & VIDEO_FORMAT_MASK_10BIT) ? DXGI_FORMAT_R16G16_UNORM : DXGI_FORMAT_R8G8_UNORM; + hr = m_Device->CreateShaderResourceView(m_VideoTexture, &srvDesc, &m_VideoTextureResourceViews[1]); + if (FAILED(hr)) { + m_VideoTextureResourceViews[1] = nullptr; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "ID3D11Device::CreateShaderResourceView() failed: %x", + hr); + return false; } return true; diff --git a/app/streaming/video/ffmpeg-renderers/d3d11va.h b/app/streaming/video/ffmpeg-renderers/d3d11va.h index f489fa8c..e619bae6 100644 --- a/app/streaming/video/ffmpeg-renderers/d3d11va.h +++ b/app/streaming/video/ffmpeg-renderers/d3d11va.h @@ -30,7 +30,7 @@ private: static void unlockContext(void* lock_ctx); bool setupRenderingResources(); - bool setupTexturePoolViews(AVD3D11VAFramesContext* frameContext); + bool setupVideoTexture(); void renderOverlay(Overlay::OverlayType type); void bindColorConversion(AVFrame* frame); void renderVideo(AVFrame* frame); @@ -60,8 +60,8 @@ private: ID3D11PixelShader* m_VideoBt2020LimPixelShader; ID3D11Buffer* m_VideoVertexBuffer; -#define DECODER_BUFFER_POOL_SIZE 17 - ID3D11ShaderResourceView* m_VideoTextureResourceViews[DECODER_BUFFER_POOL_SIZE][2]; + ID3D11Texture2D* m_VideoTexture; + ID3D11ShaderResourceView* m_VideoTextureResourceViews[2]; SDL_SpinLock m_OverlayLock; ID3D11Buffer* m_OverlayVertexBuffers[Overlay::OverlayMax];