diff --git a/app/resources.qrc b/app/resources.qrc index 9e520bf8..7d8cc9dc 100644 --- a/app/resources.qrc +++ b/app/resources.qrc @@ -91,9 +91,7 @@ shaders/egl_overlay.vert shaders/d3d11_vertex.fxc shaders/d3d11_overlay_pixel.fxc - shaders/d3d11_genyuv_pixel.fxc - shaders/d3d11_bt601lim_pixel.fxc - shaders/d3d11_bt2020lim_pixel.fxc + shaders/d3d11_yuv420_pixel.fxc shaders/d3d11_ayuv_pixel.fxc shaders/d3d11_y410_pixel.fxc shaders/vt_renderer.metal diff --git a/app/shaders/build_hlsl.bat b/app/shaders/build_hlsl.bat index 8ad73264..b2971d57 100644 --- a/app/shaders/build_hlsl.bat +++ b/app/shaders/build_hlsl.bat @@ -1,8 +1,6 @@ fxc /T vs_4_0_level_9_3 /Fo d3d11_vertex.fxc d3d11_vertex.hlsl fxc /T ps_4_0_level_9_3 /Fo d3d11_overlay_pixel.fxc d3d11_overlay_pixel.hlsl -fxc /T ps_4_0_level_9_3 /Fo d3d11_genyuv_pixel.fxc d3d11_genyuv_pixel.hlsl -fxc /T ps_4_0_level_9_3 /Fo d3d11_bt601lim_pixel.fxc d3d11_bt601lim_pixel.hlsl -fxc /T ps_4_0_level_9_3 /Fo d3d11_bt2020lim_pixel.fxc d3d11_bt2020lim_pixel.hlsl +fxc /T ps_4_0_level_9_3 /Fo d3d11_yuv420_pixel.fxc d3d11_yuv420_pixel.hlsl fxc /T ps_4_0_level_9_3 /Fo d3d11_ayuv_pixel.fxc d3d11_ayuv_pixel.hlsl fxc /T ps_4_0_level_9_3 /Fo d3d11_y410_pixel.fxc d3d11_y410_pixel.hlsl \ No newline at end of file diff --git a/app/shaders/d3d11_ayuv_pixel.fxc b/app/shaders/d3d11_ayuv_pixel.fxc index e820f23f..5fdf17a9 100644 Binary files a/app/shaders/d3d11_ayuv_pixel.fxc and b/app/shaders/d3d11_ayuv_pixel.fxc differ diff --git a/app/shaders/d3d11_bt2020lim_pixel.fxc b/app/shaders/d3d11_bt2020lim_pixel.fxc deleted file mode 100644 index 9a57d143..00000000 Binary files a/app/shaders/d3d11_bt2020lim_pixel.fxc and /dev/null differ diff --git a/app/shaders/d3d11_bt2020lim_pixel.hlsl b/app/shaders/d3d11_bt2020lim_pixel.hlsl deleted file mode 100644 index bb9f3100..00000000 --- a/app/shaders/d3d11_bt2020lim_pixel.hlsl +++ /dev/null @@ -1,15 +0,0 @@ -#include "d3d11_video_pixel_start.hlsli" - -static const min16float3x3 cscMatrix = -{ - 1.1678, 1.1678, 1.1678, - 0.0, -0.1879, 2.1481, - 1.6836, -0.6524, 0.0, -}; - -static const min16float3 offsets = -{ - 64.0 / 1023.0, 512.0 / 1023.0, 512.0 / 1023.0 -}; - -#include "d3d11_video_pixel_end.hlsli" \ No newline at end of file diff --git a/app/shaders/d3d11_bt601lim_pixel.fxc b/app/shaders/d3d11_bt601lim_pixel.fxc deleted file mode 100644 index 09f25653..00000000 Binary files a/app/shaders/d3d11_bt601lim_pixel.fxc and /dev/null differ diff --git a/app/shaders/d3d11_bt601lim_pixel.hlsl b/app/shaders/d3d11_bt601lim_pixel.hlsl deleted file mode 100644 index ef184cd7..00000000 --- a/app/shaders/d3d11_bt601lim_pixel.hlsl +++ /dev/null @@ -1,15 +0,0 @@ -#include "d3d11_video_pixel_start.hlsli" - -static const min16float3x3 cscMatrix = -{ - 1.1644, 1.1644, 1.1644, - 0.0, -0.3917, 2.0172, - 1.5960, -0.8129, 0.0, -}; - -static const min16float3 offsets = -{ - 16.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0 -}; - -#include "d3d11_video_pixel_end.hlsli" \ No newline at end of file diff --git a/app/shaders/d3d11_genyuv_pixel.fxc b/app/shaders/d3d11_genyuv_pixel.fxc deleted file mode 100644 index 7aa73c5e..00000000 Binary files a/app/shaders/d3d11_genyuv_pixel.fxc and /dev/null differ diff --git a/app/shaders/d3d11_video_pixel_end.hlsli b/app/shaders/d3d11_video_pixel_end.hlsli index 6b7cc26a..0e30bbeb 100644 --- a/app/shaders/d3d11_video_pixel_end.hlsli +++ b/app/shaders/d3d11_video_pixel_end.hlsli @@ -2,7 +2,7 @@ min16float4 main(ShaderInput input) : SV_TARGET { // Clamp the chrominance texcoords to avoid sampling the row of texels adjacent to the alignment padding min16float3 yuv = min16float3(luminancePlane.Sample(theSampler, input.tex), - chrominancePlane.Sample(theSampler, min(input.tex, chromaTexMax.rg))); + chrominancePlane.Sample(theSampler, min(input.tex + chromaOffset, chromaTexMax.rg))); // Subtract the YUV offset for limited vs full range yuv -= offsets; diff --git a/app/shaders/d3d11_y410_pixel.fxc b/app/shaders/d3d11_y410_pixel.fxc index 2365f7c1..d12d690d 100644 Binary files a/app/shaders/d3d11_y410_pixel.fxc and b/app/shaders/d3d11_y410_pixel.fxc differ diff --git a/app/shaders/d3d11_yuv420_pixel.fxc b/app/shaders/d3d11_yuv420_pixel.fxc new file mode 100644 index 00000000..4285c1a9 Binary files /dev/null and b/app/shaders/d3d11_yuv420_pixel.fxc differ diff --git a/app/shaders/d3d11_genyuv_pixel.hlsl b/app/shaders/d3d11_yuv420_pixel.hlsl similarity index 85% rename from app/shaders/d3d11_genyuv_pixel.hlsl rename to app/shaders/d3d11_yuv420_pixel.hlsl index ea66df5d..1cb8bf92 100644 --- a/app/shaders/d3d11_genyuv_pixel.hlsl +++ b/app/shaders/d3d11_yuv420_pixel.hlsl @@ -4,6 +4,7 @@ cbuffer CSC_CONST_BUF : register(b1) { min16float3x3 cscMatrix; min16float3 offsets; + min16float2 chromaOffset; }; #include "d3d11_video_pixel_end.hlsli" \ No newline at end of file diff --git a/app/shaders/d3d11_yuv444_pixel_start.hlsli b/app/shaders/d3d11_yuv444_pixel_start.hlsli index ed9c42af..5697526c 100644 --- a/app/shaders/d3d11_yuv444_pixel_start.hlsli +++ b/app/shaders/d3d11_yuv444_pixel_start.hlsli @@ -16,4 +16,5 @@ cbuffer CSC_CONST_BUF : register(b1) { min16float3x3 cscMatrix; min16float3 offsets; + min16float2 chromaOffset; // Unused for 4:4:4 }; \ No newline at end of file diff --git a/app/streaming/video/ffmpeg-renderers/d3d11va.cpp b/app/streaming/video/ffmpeg-renderers/d3d11va.cpp index 212a1bf7..962dde76 100644 --- a/app/streaming/video/ffmpeg-renderers/d3d11va.cpp +++ b/app/streaming/video/ffmpeg-renderers/d3d11va.cpp @@ -54,16 +54,20 @@ typedef struct _CSC_CONST_BUF // YUV offset values float offsets[OFFSETS_ELEMENT_COUNT]; - // Padding float to be a multiple of 16 bytes + // Padding float to end 16-byte boundary float padding; + + // Chroma offset values + float chromaOffset[2]; + + // Padding to final 16-byte boundary + float padding2[2]; } CSC_CONST_BUF, *PCSC_CONST_BUF; static_assert(sizeof(CSC_CONST_BUF) % 16 == 0, "Constant buffer sizes must be a multiple of 16"); static const std::array k_VideoShaderNames = { - "d3d11_genyuv_pixel.fxc", - "d3d11_bt601lim_pixel.fxc", - "d3d11_bt2020lim_pixel.fxc", + "d3d11_yuv420_pixel.fxc", "d3d11_ayuv_pixel.fxc", "d3d11_y410_pixel.fxc", }; @@ -541,6 +545,8 @@ bool D3D11VARenderer::initialize(PDECODER_PARAMETERS params) D3D11_TEXTURE2D_DESC textureDesc; d3d11vaFramesContext->texture_infos->texture->GetDesc(&textureDesc); m_TextureFormat = textureDesc.Format; + m_TextureWidth = textureDesc.Width; + m_TextureHeight = textureDesc.Height; if (m_BindDecoderOutputTextures) { // Create SRVs for all textures in the decoder pool @@ -705,107 +711,130 @@ void D3D11VARenderer::bindColorConversion(AVFrame* frame) bool yuv444 = (m_DecoderParams.videoFormat & VIDEO_FORMAT_MASK_YUV444); int bits = (colorspace == COLORSPACE_REC_2020) ? 10 : 8; - // We have purpose-built shaders for the common Rec 601 (SDR) and Rec 2020 (HDR) YUV 4:2:0 cases - if (!yuv444 && !fullRange && colorspace == COLORSPACE_REC_601) { - m_DeviceContext->PSSetShader(m_VideoPixelShaders[PixelShaders::BT_601_LIMITED_YUV_420].Get(), nullptr, 0); - } - else if (!yuv444 && !fullRange && colorspace == COLORSPACE_REC_2020) { - m_DeviceContext->PSSetShader(m_VideoPixelShaders[PixelShaders::BT_2020_LIMITED_YUV_420].Get(), nullptr, 0); - } - else { - if (yuv444) { - // We'll need to use one of the 4:4:4 shaders for this pixel format - switch (m_TextureFormat) - { - case DXGI_FORMAT_AYUV: - m_DeviceContext->PSSetShader(m_VideoPixelShaders[PixelShaders::GENERIC_AYUV].Get(), nullptr, 0); - break; - case DXGI_FORMAT_Y410: - m_DeviceContext->PSSetShader(m_VideoPixelShaders[PixelShaders::GENERIC_Y410].Get(), nullptr, 0); - break; - default: - SDL_assert(false); - } - } - else { - // We'll need to use the generic 4:2:0 shader for this colorspace and color range combo - m_DeviceContext->PSSetShader(m_VideoPixelShaders[PixelShaders::GENERIC_YUV_420].Get(), nullptr, 0); - } - - // If nothing has changed since last frame, we're done - if (colorspace == m_LastColorSpace && fullRange == m_LastFullRange) { - return; - } - - if (!yuv444) { - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, - "Falling back to generic video pixel shader for %d (%s range)", - colorspace, - fullRange ? "full" : "limited"); - } - - D3D11_BUFFER_DESC constDesc = {}; - constDesc.ByteWidth = sizeof(CSC_CONST_BUF); - constDesc.Usage = D3D11_USAGE_IMMUTABLE; - constDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - constDesc.CPUAccessFlags = 0; - constDesc.MiscFlags = 0; - - CSC_CONST_BUF constBuf = {}; - const float* rawCscMatrix; - switch (colorspace) { - case COLORSPACE_REC_601: - rawCscMatrix = k_CscMatrix_Bt601; + if (yuv444) { + // We'll need to use one of the 4:4:4 shaders for this pixel format + switch (m_TextureFormat) + { + case DXGI_FORMAT_AYUV: + m_DeviceContext->PSSetShader(m_VideoPixelShaders[PixelShaders::GENERIC_AYUV].Get(), nullptr, 0); break; - case COLORSPACE_REC_709: - rawCscMatrix = k_CscMatrix_Bt709; - break; - case COLORSPACE_REC_2020: - rawCscMatrix = k_CscMatrix_Bt2020; + case DXGI_FORMAT_Y410: + m_DeviceContext->PSSetShader(m_VideoPixelShaders[PixelShaders::GENERIC_Y410].Get(), nullptr, 0); break; default: SDL_assert(false); - return; } + } + else { + // We'll need to use the generic 4:2:0 shader for this colorspace and color range combo + m_DeviceContext->PSSetShader(m_VideoPixelShaders[PixelShaders::GENERIC_YUV_420].Get(), nullptr, 0); + } - int range = (1 << bits); - double yMin = (fullRange ? 0 : (16 << (bits - 8))); - double yMax = (fullRange ? (range - 1) : (235 << (bits - 8))); - double yScale = (range - 1) / (yMax - yMin); - double uvMin = (fullRange ? 0 : (16 << (bits - 8))); - double uvMax = (fullRange ? (range - 1) : (240 << (bits - 8))); - double uvScale = (range - 1) / (uvMax - uvMin); + // If nothing has changed since last frame, we're done + if (colorspace == m_LastColorSpace && fullRange == m_LastFullRange) { + return; + } - // Calculate YUV offsets - constBuf.offsets[0] = yMin / (double)(range - 1); - constBuf.offsets[1] = (range / 2) / (double)(range - 1); - constBuf.offsets[2] = (range / 2) / (double)(range - 1); + D3D11_BUFFER_DESC constDesc = {}; + constDesc.ByteWidth = sizeof(CSC_CONST_BUF); + constDesc.Usage = D3D11_USAGE_IMMUTABLE; + constDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constDesc.CPUAccessFlags = 0; + constDesc.MiscFlags = 0; - // We need to adjust our raw CSC matrix to be column-major and with float3 vectors - // padded with a float in between each of them to adhere to HLSL requirements. - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - constBuf.cscMatrix[i * 4 + j] = rawCscMatrix[j * 3 + i]; + CSC_CONST_BUF constBuf = {}; + const float* rawCscMatrix; + switch (colorspace) { + case COLORSPACE_REC_601: + rawCscMatrix = k_CscMatrix_Bt601; + break; + case COLORSPACE_REC_709: + rawCscMatrix = k_CscMatrix_Bt709; + break; + case COLORSPACE_REC_2020: + rawCscMatrix = k_CscMatrix_Bt2020; + break; + default: + SDL_assert(false); + return; + } - // Scale the color matrix according to the color range - constBuf.cscMatrix[i * 4 + j] *= (j == 0) ? yScale : uvScale; - } + int range = (1 << bits); + double yMin = (fullRange ? 0 : (16 << (bits - 8))); + double yMax = (fullRange ? (range - 1) : (235 << (bits - 8))); + double yScale = (range - 1) / (yMax - yMin); + double uvMin = (fullRange ? 0 : (16 << (bits - 8))); + double uvMax = (fullRange ? (range - 1) : (240 << (bits - 8))); + double uvScale = (range - 1) / (uvMax - uvMin); + + // Calculate YUV offsets + constBuf.offsets[0] = yMin / (double)(range - 1); + constBuf.offsets[1] = (range / 2) / (double)(range - 1); + constBuf.offsets[2] = (range / 2) / (double)(range - 1); + + // We need to adjust our raw CSC matrix to be column-major and with float3 vectors + // padded with a float in between each of them to adhere to HLSL requirements. + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + constBuf.cscMatrix[i * 4 + j] = rawCscMatrix[j * 3 + i]; + + // Scale the color matrix according to the color range + constBuf.cscMatrix[i * 4 + j] *= (j == 0) ? yScale : uvScale; } + } - D3D11_SUBRESOURCE_DATA constData = {}; - constData.pSysMem = &constBuf; + switch (frame->chroma_location) { + default: + case AVCHROMA_LOC_LEFT: + constBuf.chromaOffset[0] = 0; + constBuf.chromaOffset[1] = 0.5; + break; + case AVCHROMA_LOC_CENTER: + constBuf.chromaOffset[0] = 0.5; + constBuf.chromaOffset[1] = 0.5; + break; + case AVCHROMA_LOC_TOPLEFT: + constBuf.chromaOffset[0] = 0; + constBuf.chromaOffset[1] = 0; + break; + case AVCHROMA_LOC_TOP: + constBuf.chromaOffset[0] = 0.5; + constBuf.chromaOffset[1] = 0; + break; + case AVCHROMA_LOC_BOTTOMLEFT: + constBuf.chromaOffset[0] = 0; + constBuf.chromaOffset[1] = 1.0; + break; + case AVCHROMA_LOC_BOTTOM: + constBuf.chromaOffset[0] = 0.5; + constBuf.chromaOffset[1] = 1.0; + break; + } - ComPtr constantBuffer; - HRESULT hr = m_Device->CreateBuffer(&constDesc, &constData, &constantBuffer); - if (SUCCEEDED(hr)) { - m_DeviceContext->PSSetConstantBuffers(1, 1, constantBuffer.GetAddressOf()); - } - else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "ID3D11Device::CreateBuffer() failed: %x", - hr); - return; - } + if (yuv444) { + // 4:4:4 has no subsampling + constBuf.chromaOffset[0] = 0; + constBuf.chromaOffset[1] = 0; + } + else { + // 4:2:0 has 2x2 subsampling + constBuf.chromaOffset[0] /= m_TextureWidth / 2; + constBuf.chromaOffset[1] /= m_TextureHeight / 2; + } + + D3D11_SUBRESOURCE_DATA constData = {}; + constData.pSysMem = &constBuf; + + ComPtr constantBuffer; + HRESULT hr = m_Device->CreateBuffer(&constDesc, &constData, &constantBuffer); + if (SUCCEEDED(hr)) { + m_DeviceContext->PSSetConstantBuffers(1, 1, constantBuffer.GetAddressOf()); + } + else { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "ID3D11Device::CreateBuffer() failed: %x", + hr); + return; } m_LastColorSpace = colorspace; diff --git a/app/streaming/video/ffmpeg-renderers/d3d11va.h b/app/streaming/video/ffmpeg-renderers/d3d11va.h index f37b815a..75da76bc 100644 --- a/app/streaming/video/ffmpeg-renderers/d3d11va.h +++ b/app/streaming/video/ffmpeg-renderers/d3d11va.h @@ -28,8 +28,6 @@ public: enum PixelShaders { GENERIC_YUV_420, - BT_601_LIMITED_YUV_420, - BT_2020_LIMITED_YUV_420, GENERIC_AYUV, GENERIC_Y410, _COUNT @@ -72,6 +70,8 @@ private: DECODER_PARAMETERS m_DecoderParams; int m_TextureAlignment; DXGI_FORMAT m_TextureFormat; + UINT m_TextureWidth; + UINT m_TextureHeight; int m_DisplayWidth; int m_DisplayHeight; int m_LastColorSpace;