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;