From 23b641070c2cda0a0d1429466c1af9c70e6bffaf Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 21 Jul 2026 11:07:51 -0700
Subject: [PATCH] Added HDR10 display support for the direct3d11, direct3d12,
and vulkan renderers
---
include/SDL3/SDL_surface.h | 4 +-
src/render/SDL_render.c | 45 +-
src/render/SDL_sysrender.h | 9 +-
.../direct3d11/D3D11_PixelShader_Colors_PQ.h | 432 +++++
.../D3D11_PixelShader_Colors_PQ.hlsl | 7 +
.../direct3d11/D3D11_PixelShader_Common.hlsli | 119 +-
.../D3D11_PixelShader_Textures_PQ.h | 1698 ++++++++++++++++
.../D3D11_PixelShader_Textures_PQ.hlsl | 7 +
.../D3D11_PixelShader_Textures_Simple.h | 180 ++
.../D3D11_PixelShader_Textures_Simple.hlsl | 7 +
src/render/direct3d11/SDL_render_d3d11.c | 68 +-
src/render/direct3d11/SDL_shaders_d3d11.c | 15 +
src/render/direct3d11/SDL_shaders_d3d11.h | 3 +
src/render/direct3d11/compile_shaders.bat | 3 +
.../direct3d12/D3D12_PixelShader_Advanced.h | 1486 +++++++-------
.../direct3d12/D3D12_PixelShader_Colors.h | 442 +++--
.../direct3d12/D3D12_PixelShader_Colors_PQ.h | 592 ++++++
.../D3D12_PixelShader_Colors_PQ.hlsl | 8 +
.../direct3d12/D3D12_PixelShader_Common.hlsli | 119 +-
.../direct3d12/D3D12_PixelShader_Textures.h | 523 ++---
.../D3D12_PixelShader_Textures_PQ.h | 1725 +++++++++++++++++
.../D3D12_PixelShader_Textures_PQ.hlsl | 8 +
.../D3D12_PixelShader_Textures_Simple.h | 494 +++++
.../D3D12_PixelShader_Textures_Simple.hlsl | 8 +
.../direct3d12/D3D12_VertexShader_Advanced.h | 577 +++---
.../direct3d12/D3D12_VertexShader_Color.h | 613 +++---
.../direct3d12/D3D12_VertexShader_Texture.h | 713 +++----
src/render/direct3d12/SDL_render_d3d12.c | 70 +-
src/render/direct3d12/SDL_shaders_d3d12.c | 27 +-
src/render/direct3d12/SDL_shaders_d3d12.h | 3 +
.../direct3d12/SDL_shaders_d3d12_xboxone.cpp | 27 +-
.../SDL_shaders_d3d12_xboxseries.cpp | 27 +-
src/render/direct3d12/compile_shaders.bat | 3 +
src/render/gpu/SDL_render_gpu.c | 6 +-
src/render/metal/SDL_render_metal.m | 8 +-
src/render/vulkan/SDL_render_vulkan.c | 79 +-
src/render/vulkan/SDL_shaders_vulkan.c | 9 +
src/render/vulkan/SDL_shaders_vulkan.h | 3 +
.../vulkan/VULKAN_PixelShader_Advanced.h | 862 ++++----
.../vulkan/VULKAN_PixelShader_Advanced_YUV.h | 818 ++++----
.../vulkan/VULKAN_PixelShader_Colors_PQ.h | 62 +
.../vulkan/VULKAN_PixelShader_Colors_PQ.hlsl | 7 +
.../vulkan/VULKAN_PixelShader_Common.hlsli | 119 +-
.../vulkan/VULKAN_PixelShader_Textures_PQ.h | 355 ++++
.../VULKAN_PixelShader_Textures_PQ.hlsl | 7 +
.../VULKAN_PixelShader_Textures_Simple.h | 22 +
.../VULKAN_PixelShader_Textures_Simple.hlsl | 7 +
src/render/vulkan/compile_shaders.bat | 3 +
src/video/SDL_pixels.c | 121 +-
src/video/SDL_pixels_c.h | 1 +
src/video/SDL_surface.c | 8 +-
test/testautomation_surface.c | 4 +
test/testcolorspace.c | 13 +-
53 files changed, 9403 insertions(+), 3173 deletions(-)
create mode 100644 src/render/direct3d11/D3D11_PixelShader_Colors_PQ.h
create mode 100644 src/render/direct3d11/D3D11_PixelShader_Colors_PQ.hlsl
create mode 100644 src/render/direct3d11/D3D11_PixelShader_Textures_PQ.h
create mode 100644 src/render/direct3d11/D3D11_PixelShader_Textures_PQ.hlsl
create mode 100644 src/render/direct3d11/D3D11_PixelShader_Textures_Simple.h
create mode 100644 src/render/direct3d11/D3D11_PixelShader_Textures_Simple.hlsl
create mode 100644 src/render/direct3d12/D3D12_PixelShader_Colors_PQ.h
create mode 100644 src/render/direct3d12/D3D12_PixelShader_Colors_PQ.hlsl
create mode 100644 src/render/direct3d12/D3D12_PixelShader_Textures_PQ.h
create mode 100644 src/render/direct3d12/D3D12_PixelShader_Textures_PQ.hlsl
create mode 100644 src/render/direct3d12/D3D12_PixelShader_Textures_Simple.h
create mode 100644 src/render/direct3d12/D3D12_PixelShader_Textures_Simple.hlsl
create mode 100644 src/render/vulkan/VULKAN_PixelShader_Colors_PQ.h
create mode 100644 src/render/vulkan/VULKAN_PixelShader_Colors_PQ.hlsl
create mode 100644 src/render/vulkan/VULKAN_PixelShader_Textures_PQ.h
create mode 100644 src/render/vulkan/VULKAN_PixelShader_Textures_PQ.hlsl
create mode 100644 src/render/vulkan/VULKAN_PixelShader_Textures_Simple.h
create mode 100644 src/render/vulkan/VULKAN_PixelShader_Textures_Simple.hlsl
diff --git a/include/SDL3/SDL_surface.h b/include/SDL3/SDL_surface.h
index 1194596cd251e..c2184e3ab250b 100644
--- a/include/SDL3/SDL_surface.h
+++ b/include/SDL3/SDL_surface.h
@@ -1703,7 +1703,7 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapSurfaceRGB(SDL_Surface *surface, Uint8
extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapSurfaceRGBA(SDL_Surface *surface, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
/**
- * Retrieves a single pixel from a surface.
+ * Retrieves a single pixel from a surface as RGBA in the sRGB colorspace.
*
* This function prioritizes correctness over speed: it is suitable for unit
* tests, but is not intended for use in a game engine.
@@ -1733,7 +1733,7 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapSurfaceRGBA(SDL_Surface *surface, Uint
extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a);
/**
- * Retrieves a single pixel from a surface.
+ * Retrieves a single pixel from a surface as RGBA in the sRGB colorspace.
*
* This function prioritizes correctness over speed: it is suitable for unit
* tests, but is not intended for use in a game engine.
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index e9645aca93d94..8d441e317cfd1 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -186,35 +186,17 @@ void SDL_SetupRendererColorspace(SDL_Renderer *renderer, SDL_PropertiesID props)
#else
renderer->output_colorspace = (SDL_Colorspace)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB);
#endif
+ renderer->current_colorspace = renderer->output_colorspace;
}
-bool SDL_RenderingLinearSpace(SDL_Renderer *renderer)
-{
- SDL_Colorspace colorspace;
-
- if (renderer->target) {
- colorspace = renderer->target->colorspace;
- } else {
- colorspace = renderer->output_colorspace;
- }
- if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
- return true;
- }
- return false;
-}
-
-void SDL_ConvertToLinear(SDL_FColor *color)
+void SDL_ConvertToLinear(SDL_Renderer *renderer, SDL_FColor *color)
{
color->r = SDL_sRGBtoLinear(color->r);
color->g = SDL_sRGBtoLinear(color->g);
color->b = SDL_sRGBtoLinear(color->b);
-}
-
-void SDL_ConvertFromLinear(SDL_FColor *color)
-{
- color->r = SDL_sRGBfromLinear(color->r);
- color->g = SDL_sRGBfromLinear(color->g);
- color->b = SDL_sRGBfromLinear(color->b);
+ if (renderer->current_colorspace == SDL_COLORSPACE_HDR10) {
+ SDL_ConvertColor709to2020(&color->r, &color->g, &color->b);
+ }
}
static SDL_INLINE void DebugLogRenderCommands(const SDL_RenderCommand *cmd)
@@ -875,7 +857,8 @@ static void UpdateHDRProperties(SDL_Renderer *renderer)
return;
}
- if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
+ if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR ||
+ renderer->output_colorspace == SDL_COLORSPACE_HDR10) {
renderer->SDR_white_point = SDL_GetFloatProperty(window_props, SDL_PROP_WINDOW_SDR_WHITE_LEVEL_FLOAT, 1.0f);
renderer->HDR_headroom = SDL_GetFloatProperty(window_props, SDL_PROP_WINDOW_HDR_HEADROOM_FLOAT, 1.0f);
} else {
@@ -2829,8 +2812,10 @@ bool SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
renderer->target = texture;
if (texture) {
renderer->view = &texture->view;
+ renderer->current_colorspace = texture->colorspace;
} else {
renderer->view = &renderer->main_view;
+ renderer->current_colorspace = renderer->output_colorspace;
}
UpdateColorScale(renderer);
@@ -5462,7 +5447,11 @@ SDL_Surface *SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
SDL_Texture *parent = SDL_GetPointerProperty(SDL_GetTextureProperties(target), SDL_PROP_TEXTURE_PARENT_POINTER, NULL);
SDL_PixelFormat expected_format = (parent ? parent->format : target->format);
- SDL_SetFloatProperty(props, SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT, target->SDR_white_point);
+ if (SDL_COLORSPACETRANSFER(target->colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) {
+ SDL_SetFloatProperty(props, SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT, target->SDR_white_point * 80.0f);
+ } else {
+ SDL_SetFloatProperty(props, SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT, target->SDR_white_point);
+ }
SDL_SetFloatProperty(props, SDL_PROP_SURFACE_HDR_HEADROOM_FLOAT, target->HDR_headroom);
// Set the expected surface format
@@ -5474,7 +5463,11 @@ SDL_Surface *SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
surface->fmt = SDL_GetPixelFormatDetails(expected_format);
}
} else {
- SDL_SetFloatProperty(props, SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT, renderer->SDR_white_point);
+ if (SDL_COLORSPACETRANSFER(renderer->output_colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) {
+ SDL_SetFloatProperty(props, SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT, renderer->SDR_white_point * 80.0f);
+ } else {
+ SDL_SetFloatProperty(props, SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT, renderer->SDR_white_point);
+ }
SDL_SetFloatProperty(props, SDL_PROP_SURFACE_HDR_HEADROOM_FLOAT, renderer->HDR_headroom);
}
}
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
index 49566067bac6f..87fbbaf35d242 100644
--- a/src/render/SDL_sysrender.h
+++ b/src/render/SDL_sysrender.h
@@ -322,6 +322,7 @@ struct SDL_Renderer
// The list of palettes
SDL_HashTable *palettes;
+ SDL_Colorspace current_colorspace;
SDL_Colorspace output_colorspace;
float SDR_white_point;
float HDR_headroom;
@@ -407,9 +408,11 @@ extern bool SDL_AddSupportedTextureFormat(SDL_Renderer *renderer, SDL_PixelForma
extern void SDL_SetupRendererColorspace(SDL_Renderer *renderer, SDL_PropertiesID props);
// Colorspace conversion functions
-extern bool SDL_RenderingLinearSpace(SDL_Renderer *renderer);
-extern void SDL_ConvertToLinear(SDL_FColor *color);
-extern void SDL_ConvertFromLinear(SDL_FColor *color);
+#define SDL_RenderingLinearSpace(renderer) \
+ (renderer->current_colorspace == SDL_COLORSPACE_SRGB_LINEAR || \
+ renderer->current_colorspace == SDL_COLORSPACE_HDR10)
+
+extern void SDL_ConvertToLinear(SDL_Renderer *renderer, SDL_FColor *color);
// Blend mode functions
extern SDL_BlendFactor SDL_GetBlendModeSrcColorFactor(SDL_BlendMode blendMode);
diff --git a/src/render/direct3d11/D3D11_PixelShader_Colors_PQ.h b/src/render/direct3d11/D3D11_PixelShader_Colors_PQ.h
new file mode 100644
index 0000000000000..cc0a152fdb29e
--- /dev/null
+++ b/src/render/direct3d11/D3D11_PixelShader_Colors_PQ.h
@@ -0,0 +1,432 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
+//
+//
+// Buffer Definitions:
+//
+// cbuffer Constants
+// {
+//
+// float scRGB_output; // Offset: 0 Size: 4 [unused]
+// float texture_type; // Offset: 4 Size: 4 [unused]
+// float input_type; // Offset: 8 Size: 4 [unused]
+// float color_scale; // Offset: 12 Size: 4
+// float4 texel_size; // Offset: 16 Size: 16 [unused]
+// float tonemap_method; // Offset: 32 Size: 4 [unused]
+// float tonemap_factor1; // Offset: 36 Size: 4 [unused]
+// float tonemap_factor2; // Offset: 40 Size: 4 [unused]
+// float sdr_white_point; // Offset: 44 Size: 4 [unused]
+// float4 Yoffset; // Offset: 48 Size: 16 [unused]
+// float4 Rcoeff; // Offset: 64 Size: 16 [unused]
+// float4 Gcoeff; // Offset: 80 Size: 16 [unused]
+// float4 Bcoeff; // Offset: 96 Size: 16 [unused]
+//
+// }
+//
+//
+// Resource Bindings:
+//
+// Name Type Format Dim HLSL Bind Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// Constants cbuffer NA NA cb0 1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION 0 xyzw 0 POS float
+// TEXCOORD 0 xy 1 NONE float
+// COLOR 0 xyzw 2 NONE float xyzw
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_TARGET 0 xyzw 0 TARGET float xyzw
+//
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer Start Reg # of Regs Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c0 cb0 0 1 ( FLT, FLT, FLT, FLT)
+//
+//
+// Level9 shader bytecode:
+//
+ ps_2_0
+ def c1, 0.00799999945, 0.159301758, 18.8515625, 0.8359375
+ def c2, 18.6875, 1, 78.84375, 0
+ dcl t1
+ mul r0.xyz, t1, c0.w
+ mul_sat r0.xyz, r0, c1.x
+ log r1.x, r0.x
+ log r1.y, r0.y
+ log r1.z, r0.z
+ mul r0.xyz, r1, c1.y
+ exp r1.x, r0.x
+ exp r1.y, r0.y
+ exp r1.z, r0.z
+ mad r0.xyz, r1, c1.z, c1.w
+ mad r1.xyz, r1, c2.x, c2.y
+ rcp r2.x, r1.x
+ rcp r2.y, r1.y
+ rcp r2.z, r1.z
+ mul r0.xyz, r0, r2
+ log r1.x, r0.x
+ log r1.y, r0.y
+ log r1.z, r0.z
+ mul r0.xyz, r1, c2.z
+ exp r1.x, r0.x
+ exp r1.y, r0.y
+ exp r1.z, r0.z
+ mov r1.w, t1.w
+ mov oC0, r1
+
+// approximately 24 instruction slots used
+ps_4_0
+dcl_constantbuffer CB0[1], immediateIndexed
+dcl_input_ps linear v2.xyzw
+dcl_output o0.xyzw
+dcl_temps 2
+mul r0.xyz, v2.xyzx, cb0[0].wwww
+mul_sat r0.xyz, r0.xyzx, l(0.008000, 0.008000, 0.008000, 0.000000)
+log r0.xyz, r0.xyzx
+mul r0.xyz, r0.xyzx, l(0.159302, 0.159302, 0.159302, 0.000000)
+exp r0.xyz, r0.xyzx
+mad r1.xyz, r0.xyzx, l(18.851562, 18.851562, 18.851562, 0.000000), l(0.835938, 0.835938, 0.835938, 0.000000)
+mad r0.xyz, r0.xyzx, l(18.687500, 18.687500, 18.687500, 0.000000), l(1.000000, 1.000000, 1.000000, 0.000000)
+div r0.xyz, r1.xyzx, r0.xyzx
+log r0.xyz, r0.xyzx
+mul r0.xyz, r0.xyzx, l(78.843750, 78.843750, 78.843750, 0.000000)
+exp o0.xyz, r0.xyzx
+mov o0.w, v2.w
+ret
+// Approximately 13 instruction slots used
+#endif
+
+const BYTE g_main[] =
+{
+ 68, 88, 66, 67, 215, 236,
+ 43, 101, 209, 206, 96, 142,
+ 117, 123, 67, 203, 11, 112,
+ 225, 132, 1, 0, 0, 0,
+ 116, 7, 0, 0, 6, 0,
+ 0, 0, 56, 0, 0, 0,
+ 248, 1, 0, 0, 204, 3,
+ 0, 0, 72, 4, 0, 0,
+ 204, 6, 0, 0, 64, 7,
+ 0, 0, 65, 111, 110, 57,
+ 184, 1, 0, 0, 184, 1,
+ 0, 0, 0, 2, 255, 255,
+ 136, 1, 0, 0, 48, 0,
+ 0, 0, 1, 0, 36, 0,
+ 0, 0, 48, 0, 0, 0,
+ 48, 0, 0, 0, 36, 0,
+ 0, 0, 48, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2,
+ 255, 255, 81, 0, 0, 5,
+ 1, 0, 15, 160, 110, 18,
+ 3, 60, 0, 32, 35, 62,
+ 0, 208, 150, 65, 0, 0,
+ 86, 63, 81, 0, 0, 5,
+ 2, 0, 15, 160, 0, 128,
+ 149, 65, 0, 0, 128, 63,
+ 0, 176, 157, 66, 0, 0,
+ 0, 0, 31, 0, 0, 2,
+ 0, 0, 0, 128, 1, 0,
+ 15, 176, 5, 0, 0, 3,
+ 0, 0, 7, 128, 1, 0,
+ 228, 176, 0, 0, 255, 160,
+ 5, 0, 0, 3, 0, 0,
+ 23, 128, 0, 0, 228, 128,
+ 1, 0, 0, 160, 15, 0,
+ 0, 2, 1, 0, 1, 128,
+ 0, 0, 0, 128, 15, 0,
+ 0, 2, 1, 0, 2, 128,
+ 0, 0, 85, 128, 15, 0,
+ 0, 2, 1, 0, 4, 128,
+ 0, 0, 170, 128, 5, 0,
+ 0, 3, 0, 0, 7, 128,
+ 1, 0, 228, 128, 1, 0,
+ 85, 160, 14, 0, 0, 2,
+ 1, 0, 1, 128, 0, 0,
+ 0, 128, 14, 0, 0, 2,
+ 1, 0, 2, 128, 0, 0,
+ 85, 128, 14, 0, 0, 2,
+ 1, 0, 4, 128, 0, 0,
+ 170, 128, 4, 0, 0, 4,
+ 0, 0, 7, 128, 1, 0,
+ 228, 128, 1, 0, 170, 160,
+ 1, 0, 255, 160, 4, 0,
+ 0, 4, 1, 0, 7, 128,
+ 1, 0, 228, 128, 2, 0,
+ 0, 160, 2, 0, 85, 160,
+ 6, 0, 0, 2, 2, 0,
+ 1, 128, 1, 0, 0, 128,
+ 6, 0, 0, 2, 2, 0,
+ 2, 128, 1, 0, 85, 128,
+ 6, 0, 0, 2, 2, 0,
+ 4, 128, 1, 0, 170, 128,
+ 5, 0, 0, 3, 0, 0,
+ 7, 128, 0, 0, 228, 128,
+ 2, 0, 228, 128, 15, 0,
+ 0, 2, 1, 0, 1, 128,
+ 0, 0, 0, 128, 15, 0,
+ 0, 2, 1, 0, 2, 128,
+ 0, 0, 85, 128, 15, 0,
+ 0, 2, 1, 0, 4, 128,
+ 0, 0, 170, 128, 5, 0,
+ 0, 3, 0, 0, 7, 128,
+ 1, 0, 228, 128, 2, 0,
+ 170, 160, 14, 0, 0, 2,
+ 1, 0, 1, 128, 0, 0,
+ 0, 128, 14, 0, 0, 2,
+ 1, 0, 2, 128, 0, 0,
+ 85, 128, 14, 0, 0, 2,
+ 1, 0, 4, 128, 0, 0,
+ 170, 128, 1, 0, 0, 2,
+ 1, 0, 8, 128, 1, 0,
+ 255, 176, 1, 0, 0, 2,
+ 0, 8, 15, 128, 1, 0,
+ 228, 128, 255, 255, 0, 0,
+ 83, 72, 68, 82, 204, 1,
+ 0, 0, 64, 0, 0, 0,
+ 115, 0, 0, 0, 89, 0,
+ 0, 4, 70, 142, 32, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 98, 16, 0, 3,
+ 242, 16, 16, 0, 2, 0,
+ 0, 0, 101, 0, 0, 3,
+ 242, 32, 16, 0, 0, 0,
+ 0, 0, 104, 0, 0, 2,
+ 2, 0, 0, 0, 56, 0,
+ 0, 8, 114, 0, 16, 0,
+ 0, 0, 0, 0, 70, 18,
+ 16, 0, 2, 0, 0, 0,
+ 246, 143, 32, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 56, 32, 0, 10, 114, 0,
+ 16, 0, 0, 0, 0, 0,
+ 70, 2, 16, 0, 0, 0,
+ 0, 0, 2, 64, 0, 0,
+ 110, 18, 3, 60, 110, 18,
+ 3, 60, 110, 18, 3, 60,
+ 0, 0, 0, 0, 47, 0,
+ 0, 5, 114, 0, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 16, 0, 0, 0, 0, 0,
+ 56, 0, 0, 10, 114, 0,
+ 16, 0, 0, 0, 0, 0,
+ 70, 2, 16, 0, 0, 0,
+ 0, 0, 2, 64, 0, 0,
+ 0, 32, 35, 62, 0, 32,
+ 35, 62, 0, 32, 35, 62,
+ 0, 0, 0, 0, 25, 0,
+ 0, 5, 114, 0, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 16, 0, 0, 0, 0, 0,
+ 50, 0, 0, 15, 114, 0,
+ 16, 0, 1, 0, 0, 0,
+ 70, 2, 16, 0, 0, 0,
+ 0, 0, 2, 64, 0, 0,
+ 0, 208, 150, 65, 0, 208,
+ 150, 65, 0, 208, 150, 65,
+ 0, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 86, 63,
+ 0, 0, 86, 63, 0, 0,
+ 86, 63, 0, 0, 0, 0,
+ 50, 0, 0, 15, 114, 0,
+ 16, 0, 0, 0, 0, 0,
+ 70, 2, 16, 0, 0, 0,
+ 0, 0, 2, 64, 0, 0,
+ 0, 128, 149, 65, 0, 128,
+ 149, 65, 0, 128, 149, 65,
+ 0, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 128, 63,
+ 0, 0, 128, 63, 0, 0,
+ 128, 63, 0, 0, 0, 0,
+ 14, 0, 0, 7, 114, 0,
+ 16, 0, 0, 0, 0, 0,
+ 70, 2, 16, 0, 1, 0,
+ 0, 0, 70, 2, 16, 0,
+ 0, 0, 0, 0, 47, 0,
+ 0, 5, 114, 0, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 16, 0, 0, 0, 0, 0,
+ 56, 0, 0, 10, 114, 0,
+ 16, 0, 0, 0, 0, 0,
+ 70, 2, 16, 0, 0, 0,
+ 0, 0, 2, 64, 0, 0,
+ 0, 176, 157, 66, 0, 176,
+ 157, 66, 0, 176, 157, 66,
+ 0, 0, 0, 0, 25, 0,
+ 0, 5, 114, 32, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 16, 0, 0, 0, 0, 0,
+ 54, 0, 0, 5, 130, 32,
+ 16, 0, 0, 0, 0, 0,
+ 58, 16, 16, 0, 2, 0,
+ 0, 0, 62, 0, 0, 1,
+ 83, 84, 65, 84, 116, 0,
+ 0, 0, 13, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0,
+ 11, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 82, 68,
+ 69, 70, 124, 2, 0, 0,
+ 1, 0, 0, 0, 72, 0,
+ 0, 0, 1, 0, 0, 0,
+ 28, 0, 0, 0, 0, 4,
+ 255, 255, 0, 1, 0, 0,
+ 84, 2, 0, 0, 60, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 67, 111, 110, 115, 116, 97,
+ 110, 116, 115, 0, 171, 171,
+ 60, 0, 0, 0, 13, 0,
+ 0, 0, 96, 0, 0, 0,
+ 112, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 152, 1, 0, 0, 0, 0,
+ 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 168, 1,
+ 0, 0, 0, 0, 0, 0,
+ 184, 1, 0, 0, 4, 0,
+ 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 168, 1,
+ 0, 0, 0, 0, 0, 0,
+ 197, 1, 0, 0, 8, 0,
+ 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 168, 1,
+ 0, 0, 0, 0, 0, 0,
+ 208, 1, 0, 0, 12, 0,
+ 0, 0, 4, 0, 0, 0,
+ 2, 0, 0, 0, 168, 1,
+ 0, 0, 0, 0, 0, 0,
+ 220, 1, 0, 0, 16, 0,
+ 0, 0, 16, 0, 0, 0,
+ 0, 0, 0, 0, 232, 1,
+ 0, 0, 0, 0, 0, 0,
+ 248, 1, 0, 0, 32, 0,
+ 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 168, 1,
+ 0, 0, 0, 0, 0, 0,
+ 7, 2, 0, 0, 36, 0,
+ 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 168, 1,
+ 0, 0, 0, 0, 0, 0,
+ 23, 2, 0, 0, 40, 0,
+ 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 168, 1,
+ 0, 0, 0, 0, 0, 0,
+ 39, 2, 0, 0, 44, 0,
+ 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 168, 1,
+ 0, 0, 0, 0, 0, 0,
+ 55, 2, 0, 0, 48, 0,
+ 0, 0, 16, 0, 0, 0,
+ 0, 0, 0, 0, 232, 1,
+ 0, 0, 0, 0, 0, 0,
+ 63, 2, 0, 0, 64, 0,
+ 0, 0, 16, 0, 0, 0,
+ 0, 0, 0, 0, 232, 1,
+ 0, 0, 0, 0, 0, 0,
+ 70, 2, 0, 0, 80, 0,
+ 0, 0, 16, 0, 0, 0,
+ 0, 0, 0, 0, 232, 1,
+ 0, 0, 0, 0, 0, 0,
+ 77, 2, 0, 0, 96, 0,
+ 0, 0, 16, 0, 0, 0,
+ 0, 0, 0, 0, 232, 1,
+ 0, 0, 0, 0, 0, 0,
+ 115, 99, 82, 71, 66, 95,
+ 111, 117, 116, 112, 117, 116,
+ 0, 171, 171, 171, 0, 0,
+ 3, 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 116, 101, 120, 116,
+ 117, 114, 101, 95, 116, 121,
+ 112, 101, 0, 105, 110, 112,
+ 117, 116, 95, 116, 121, 112,
+ 101, 0, 99, 111, 108, 111,
+ 114, 95, 115, 99, 97, 108,
+ 101, 0, 116, 101, 120, 101,
+ 108, 95, 115, 105, 122, 101,
+ 0, 171, 1, 0, 3, 0,
+ 1, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 116, 111, 110, 101, 109, 97,
+ 112, 95, 109, 101, 116, 104,
+ 111, 100, 0, 116, 111, 110,
+ 101, 109, 97, 112, 95, 102,
+ 97, 99, 116, 111, 114, 49,
+ 0, 116, 111, 110, 101, 109,
+ 97, 112, 95, 102, 97, 99,
+ 116, 111, 114, 50, 0, 115,
+ 100, 114, 95, 119, 104, 105,
+ 116, 101, 95, 112, 111, 105,
+ 110, 116, 0, 89, 111, 102,
+ 102, 115, 101, 116, 0, 82,
+ 99, 111, 101, 102, 102, 0,
+ 71, 99, 111, 101, 102, 102,
+ 0, 66, 99, 111, 101, 102,
+ 102, 0, 77, 105, 99, 114,
+ 111, 115, 111, 102, 116, 32,
+ 40, 82, 41, 32, 72, 76,
+ 83, 76, 32, 83, 104, 97,
+ 100, 101, 114, 32, 67, 111,
+ 109, 112, 105, 108, 101, 114,
+ 32, 49, 48, 46, 49, 0,
+ 73, 83, 71, 78, 108, 0,
+ 0, 0, 3, 0, 0, 0,
+ 8, 0, 0, 0, 80, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 3, 0,
+ 0, 0, 0, 0, 0, 0,
+ 15, 0, 0, 0, 92, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 1, 0, 0, 0,
+ 3, 0, 0, 0, 101, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 2, 0, 0, 0,
+ 15, 15, 0, 0, 83, 86,
+ 95, 80, 79, 83, 73, 84,
+ 73, 79, 78, 0, 84, 69,
+ 88, 67, 79, 79, 82, 68,
+ 0, 67, 79, 76, 79, 82,
+ 0, 171, 79, 83, 71, 78,
+ 44, 0, 0, 0, 1, 0,
+ 0, 0, 8, 0, 0, 0,
+ 32, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 15, 0, 0, 0,
+ 83, 86, 95, 84, 65, 82,
+ 71, 69, 84, 0, 171, 171
+};
diff --git a/src/render/direct3d11/D3D11_PixelShader_Colors_PQ.hlsl b/src/render/direct3d11/D3D11_PixelShader_Colors_PQ.hlsl
new file mode 100644
index 0000000000000..583c140eafb78
--- /dev/null
+++ b/src/render/direct3d11/D3D11_PixelShader_Colors_PQ.hlsl
@@ -0,0 +1,7 @@
+
+#include "D3D11_PixelShader_Common.hlsli"
+
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+ return PQColorPixelShader(input);
+}
diff --git a/src/render/direct3d11/D3D11_PixelShader_Common.hlsli b/src/render/direct3d11/D3D11_PixelShader_Common.hlsli
index 4a4cedd06ba25..14f9aafec9adf 100644
--- a/src/render/direct3d11/D3D11_PixelShader_Common.hlsli
+++ b/src/render/direct3d11/D3D11_PixelShader_Common.hlsli
@@ -63,6 +63,16 @@ static const float3x3 mat2020to709 = {
{ -0.018154, -0.100597, 1.118751 }
};
+float3 scRGBtoNits( float3 v )
+{
+ return v * 80.0;
+}
+
+float3 scRGBfromNits(float3 v)
+{
+ return v / 80.0;
+}
+
float sRGBtoLinear(float v)
{
if (v <= 0.04045) {
@@ -73,6 +83,14 @@ float sRGBtoLinear(float v)
return v;
}
+float3 sRGBtoLinear(float3 v)
+{
+ v.r = sRGBtoLinear(v.r);
+ v.g = sRGBtoLinear(v.g);
+ v.b = sRGBtoLinear(v.b);
+ return v;
+}
+
float sRGBfromLinear(float v)
{
if (v <= 0.0031308) {
@@ -83,7 +101,15 @@ float sRGBfromLinear(float v)
return v;
}
-float3 PQtoLinear(float3 v)
+float3 sRGBfromLinear(float3 v)
+{
+ v.r = sRGBfromLinear(v.r);
+ v.g = sRGBfromLinear(v.g);
+ v.b = sRGBfromLinear(v.b);
+ return v;
+}
+
+float3 PQtoNits(float3 v)
{
const float c1 = 0.8359375;
const float c2 = 18.8515625;
@@ -93,7 +119,26 @@ float3 PQtoLinear(float3 v)
float3 num = max(pow(abs(v), oo_m2) - c1, 0.0);
float3 den = c2 - c3 * pow(abs(v), oo_m2);
- return (10000.0 * pow(abs(num / den), oo_m1) / sdr_white_point);
+ return 10000.0 * pow(abs(num / den), oo_m1);
+}
+
+float3 PQtoLinear(float3 v)
+{
+ return PQtoNits(v) / sdr_white_point;
+}
+
+float3 PQFromNits(float3 v)
+{
+ const float c1 = 0.8359375;
+ const float c2 = 18.8515625;
+ const float c3 = 18.6875;
+ const float m1 = 0.1593017578125;
+ const float m2 = 78.84375;
+
+ float3 y = saturate( v / 10000.0 );
+ float3 num = c1 + c2 * pow( abs( y ), m1 );
+ float3 den = 1.0 + c3 * pow( abs( y ), m1 );
+ return pow( abs( num / den ), m2 );
}
float3 ApplyTonemap(float3 v)
@@ -120,6 +165,20 @@ float3 ApplyTonemap(float3 v)
return v;
}
+float3 ApplyTonemap2020(float3 v)
+{
+ if (tonemap_method == TONEMAP_LINEAR) {
+ v *= tonemap_factor1;
+ } else if (tonemap_method == TONEMAP_CHROME) {
+ float vmax = max(v.r, max(v.g, v.b));
+ if (vmax > 0.0) {
+ float scale = (1.0 + tonemap_factor1 * vmax) / (1.0 + tonemap_factor2 * vmax);
+ v *= scale;
+ }
+ }
+ return v;
+}
+
float4 SamplePaletteNearest(float2 uv)
{
float index = texture0.Sample(sampler0, uv).r * 255;
@@ -238,9 +297,7 @@ float3 GetOutputColorFromSRGB(float3 rgb)
float3 output;
if (scRGB_output) {
- rgb.r = sRGBtoLinear(rgb.r);
- rgb.g = sRGBtoLinear(rgb.g);
- rgb.b = sRGBtoLinear(rgb.b);
+ rgb = sRGBtoLinear(rgb);
}
output.rgb = rgb * color_scale;
@@ -255,15 +312,59 @@ float3 GetOutputColorFromLinear(float3 rgb)
output.rgb = rgb * color_scale;
if (!scRGB_output) {
- output.r = sRGBfromLinear(output.r);
- output.g = sRGBfromLinear(output.g);
- output.b = sRGBfromLinear(output.b);
- output.rgb = saturate(output.rgb);
+ output.rgb = saturate(sRGBfromLinear(output.rgb));
}
return output;
}
+float4 PQColorPixelShader(PixelShaderInput input)
+{
+ float3 rgb = float3(1.0, 1.0, 1.0);
+ float4 output;
+
+ // Apply color scaling, which will include display SDR white level
+ rgb = rgb * input.color.rgb * color_scale;
+
+ // Convert to nits
+ rgb = scRGBtoNits(rgb);
+
+ output.rgb = PQFromNits(rgb);
+ output.a = input.color.a;
+
+ return output;
+}
+
+float4 PQTexturePixelShader(PixelShaderInput input)
+{
+ float4 rgba = GetInputColor(input);
+ float4 output;
+
+ if (input_type == INPUTTYPE_HDR10) {
+ rgba.rgb = PQtoLinear(rgba.rgb);
+ } else {
+ if (input_type == INPUTTYPE_SRGB) {
+ rgba.rgb = sRGBtoLinear(rgba.rgb);
+ }
+ rgba.rgb = mul(mat709to2020, rgba.rgb);
+ }
+
+ if (tonemap_method != TONEMAP_NONE) {
+ rgba.rgb = ApplyTonemap2020(rgba.rgb);
+ }
+
+ // Apply color scaling, which will include display SDR white level
+ rgba.rgb = rgba.rgb * input.color.rgb * color_scale;
+
+ // Convert to nits
+ rgba.rgb = scRGBtoNits(rgba.rgb);
+
+ output.rgb = PQFromNits(rgba.rgb);
+ output.a = rgba.a * input.color.a;
+
+ return output;
+}
+
float4 AdvancedPixelShader(PixelShaderInput input)
{
float4 rgba = GetInputColor(input);
diff --git a/src/render/direct3d11/D3D11_PixelShader_Textures_PQ.h b/src/render/direct3d11/D3D11_PixelShader_Textures_PQ.h
new file mode 100644
index 0000000000000..3acd1be41dcec
--- /dev/null
+++ b/src/render/dir
(Patch may be truncated, please check the link at the top of this post.)