Handle chroma co-siting in the D3D11 shaders

This commit is contained in:
Cameron Gutman
2025-11-01 22:42:51 -05:00
parent 9b3050514b
commit f67272b153
15 changed files with 129 additions and 132 deletions

View File

@@ -91,9 +91,7 @@
<file alias="egl_overlay.vert">shaders/egl_overlay.vert</file>
<file alias="d3d11_vertex.fxc">shaders/d3d11_vertex.fxc</file>
<file alias="d3d11_overlay_pixel.fxc">shaders/d3d11_overlay_pixel.fxc</file>
<file alias="d3d11_genyuv_pixel.fxc">shaders/d3d11_genyuv_pixel.fxc</file>
<file alias="d3d11_bt601lim_pixel.fxc">shaders/d3d11_bt601lim_pixel.fxc</file>
<file alias="d3d11_bt2020lim_pixel.fxc">shaders/d3d11_bt2020lim_pixel.fxc</file>
<file alias="d3d11_yuv420_pixel.fxc">shaders/d3d11_yuv420_pixel.fxc</file>
<file alias="d3d11_ayuv_pixel.fxc">shaders/d3d11_ayuv_pixel.fxc</file>
<file alias="d3d11_y410_pixel.fxc">shaders/d3d11_y410_pixel.fxc</file>
<file alias="vt_renderer.metal">shaders/vt_renderer.metal</file>

View File

@@ -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

Binary file not shown.

View File

@@ -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"

Binary file not shown.

View File

@@ -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"

Binary file not shown.

View File

@@ -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;

Binary file not shown.

Binary file not shown.

View File

@@ -4,6 +4,7 @@ cbuffer CSC_CONST_BUF : register(b1)
{
min16float3x3 cscMatrix;
min16float3 offsets;
min16float2 chromaOffset;
};
#include "d3d11_video_pixel_end.hlsli"

View File

@@ -16,4 +16,5 @@ cbuffer CSC_CONST_BUF : register(b1)
{
min16float3x3 cscMatrix;
min16float3 offsets;
min16float2 chromaOffset; // Unused for 4:4:4
};

View File

@@ -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<const char*, D3D11VARenderer::PixelShaders::_COUNT> 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,14 +711,6 @@ 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)
@@ -737,13 +735,6 @@ void D3D11VARenderer::bindColorConversion(AVFrame* frame)
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;
@@ -792,6 +783,45 @@ void D3D11VARenderer::bindColorConversion(AVFrame* frame)
}
}
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;
}
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;
@@ -806,7 +836,6 @@ void D3D11VARenderer::bindColorConversion(AVFrame* frame)
hr);
return;
}
}
m_LastColorSpace = colorspace;
m_LastFullRange = fullRange;

View File

@@ -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;