1 /*****************************************************************************
2 * d3d_dynamic_shader.c: Direct3D Shader APIs
3 *****************************************************************************
4 * Copyright (C) 2017-2021 VLC authors and VideoLAN
6 * Authors: Steve Lhomme <robux4@gmail.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
30 #include <vlc_common.h>
33 #include <d3dcompiler.h>
35 #include "d3d_shaders.h"
36 #include "d3d_dynamic_shader.h"
38 static const char globPixelShaderDefault
[] = "\
39 cbuffer PS_CONSTANT_BUFFER : register(b0)\n\
41 float4x3 Colorspace;\n\
43 float LuminanceScale;\n\
46 Texture2D shaderTexture[TEXTURE_RESOURCES];\n\
47 SamplerState normalSampler : register(s0);\n\
48 SamplerState borderSampler : register(s1);\n\
52 float4 Position : SV_POSITION;\n\
53 float2 uv : TEXCOORD;\n\
56 #define TONE_MAP_HABLE 1\n\
58 #define SRC_TRANSFER_709 1\n\
59 #define SRC_TRANSFER_PQ 2\n\
60 #define SRC_TRANSFER_HLG 3\n\
61 #define SRC_TRANSFER_SRGB 4\n\
62 #define SRC_TRANSFER_470BG 5\n\
64 #define DST_TRANSFER_SRGB 1\n\
65 #define DST_TRANSFER_PQ 2\n\
67 #define FULL_RANGE 1\n\
68 #define STUDIO_RANGE 2\n\
70 #define SAMPLE_NV12_TO_YUVA 1\n\
71 #define SAMPLE_YUY2_TO_YUVA 2\n\
72 #define SAMPLE_Y210_TO_YUVA 3\n\
73 #define SAMPLE_Y410_TO_YUVA 4\n\
74 #define SAMPLE_AYUV_TO_YUVA 5\n\
75 #define SAMPLE_RGBA_TO_RGBA 6\n\
76 #define SAMPLE_TRIPLANAR_TO_YUVA 7\n\
77 #define SAMPLE_TRIPLANAR10_TO_YUVA 8\n\
78 #define SAMPLE_PLANAR_YUVA_TO_YUVA 9\n\
80 #define SAMPLE_NV12_TO_NV_Y 10\n\
81 #define SAMPLE_NV12_TO_NV_UV 11\n\
82 #define SAMPLE_RGBA_TO_NV_R 12\n\
83 #define SAMPLE_RGBA_TO_NV_GB 13\n\
84 #define SAMPLE_PLANAR_YUVA_TO_NV_Y 14\n\
85 #define SAMPLE_PLANAR_YUVA_TO_NV_UV 15\n\
87 #if (TONE_MAPPING==TONE_MAP_HABLE)\n\
88 /* see http://filmicworlds.com/blog/filmic-tonemapping-operators/ */\n\
89 inline float3 hable(float3 x) {\n\
90 const float A = 0.15, B = 0.50, C = 0.10, D = 0.20, E = 0.02, F = 0.30;\n\
91 return ((x * (A*x + (C*B))+(D*E))/(x * (A*x + B) + (D*F))) - E/F;\n\
95 #if (SRC_TO_LINEAR==SRC_TRANSFER_HLG)\n\
96 /* https://en.wikipedia.org/wiki/Hybrid_Log-Gamma#Technical_details */\n\
97 inline float inverse_HLG(float x){\n\
98 const float B67_a = 0.17883277;\n\
99 const float B67_b = 0.28466892;\n\
100 const float B67_c = 0.55991073;\n\
101 const float B67_inv_r2 = 4.0; /* 1/0.5² */\n\
103 x = x * x * B67_inv_r2;\n\
105 x = exp((x - B67_c) / B67_a) + B67_b;\n\
110 inline float3 sourceToLinear(float3 rgb) {\n\
111 #if (SRC_TO_LINEAR==SRC_TRANSFER_PQ)\n\
112 const float ST2084_m1 = 2610.0 / (4096.0 * 4);\n\
113 const float ST2084_m2 = (2523.0 / 4096.0) * 128.0;\n\
114 const float ST2084_c1 = 3424.0 / 4096.0;\n\
115 const float ST2084_c2 = (2413.0 / 4096.0) * 32.0;\n\
116 const float ST2084_c3 = (2392.0 / 4096.0) * 32.0;\n\
117 rgb = pow(max(rgb, 0), 1.0/ST2084_m2);\n\
118 rgb = max(rgb - ST2084_c1, 0.0) / (ST2084_c2 - ST2084_c3 * rgb);\n\
119 rgb = pow(rgb, 1.0/ST2084_m1);\n\
120 return rgb * 10000;\n\
121 #elif (SRC_TO_LINEAR==SRC_TRANSFER_HLG)\n\
122 /* TODO: in one call */\n\
123 rgb.r = inverse_HLG(rgb.r);\n\
124 rgb.g = inverse_HLG(rgb.g);\n\
125 rgb.b = inverse_HLG(rgb.b);\n\
126 float3 ootf_2020 = float3(0.2627, 0.6780, 0.0593);\n\
127 float ootf_ys = 1000 * dot(ootf_2020, rgb);\n\
128 return rgb * pow(ootf_ys, 0.200);\n\
129 #elif (SRC_TO_LINEAR==SRC_TRANSFER_709)\n\
130 return pow(rgb, 1.0 / 0.45);\n\
131 #elif (SRC_TO_LINEAR==SRC_TRANSFER_SRGB)\n\
132 return pow(rgb, 2.2);\n\
133 #elif (SRC_TO_LINEAR==SRC_TRANSFER_470BG)\n\
134 return pow(rgb, 2.8);\n\
140 inline float3 linearToDisplay(float3 rgb) {\n\
141 #if (LINEAR_TO_DST==DST_TRANSFER_SRGB)\n\
142 return pow(rgb, 1.0 / 2.2);\n\
143 #elif (LINEAR_TO_DST==DST_TRANSFER_PQ)\n\
144 const float ST2084_m1 = 2610.0 / (4096.0 * 4);\n\
145 const float ST2084_m2 = (2523.0 / 4096.0) * 128.0;\n\
146 const float ST2084_c1 = 3424.0 / 4096.0;\n\
147 const float ST2084_c2 = (2413.0 / 4096.0) * 32.0;\n\
148 const float ST2084_c3 = (2392.0 / 4096.0) * 32.0;\n\
149 rgb = pow(rgb / 10000, ST2084_m1);\n\
150 rgb = (ST2084_c1 + ST2084_c2 * rgb) / (1 + ST2084_c3 * rgb);\n\
151 return pow(rgb, ST2084_m2);\n\
157 inline float3 toneMapping(float3 rgb) {\n\
158 rgb = rgb * LuminanceScale;\n\
159 #if (TONE_MAPPING==TONE_MAP_HABLE)\n\
160 const float3 HABLE_DIV = hable(11.2);\n\
161 rgb = hable(rgb) / HABLE_DIV;\n\
166 inline float3 adjustRange(float3 rgb) {\n\
167 #if (SRC_RANGE!=DST_RANGE)\n\
168 return clamp((rgb + BLACK_LEVEL_SHIFT) * RANGE_FACTOR, MIN_BLACK_VALUE, MAX_WHITE_VALUE);\n\
174 inline float4 sampleTexture(SamplerState samplerState, float2 coords) {\n\
176 /* sampling routine in sample */\n\
177 #if (SAMPLE_TEXTURES==SAMPLE_NV12_TO_YUVA)\n\
178 sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n\
179 sample.yz = shaderTexture[1].Sample(samplerState, coords).xy;\n\
181 #elif (SAMPLE_TEXTURES==SAMPLE_YUY2_TO_YUVA)\n\
182 sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n\
183 sample.y = shaderTexture[0].Sample(samplerState, coords).y;\n\
184 sample.z = shaderTexture[0].Sample(samplerState, coords).a;\n\
186 #elif (SAMPLE_TEXTURES==SAMPLE_Y210_TO_YUVA)\n\
187 sample.x = shaderTexture[0].Sample(samplerState, coords).r;\n\
188 sample.y = shaderTexture[0].Sample(samplerState, coords).g;\n\
189 sample.z = shaderTexture[0].Sample(samplerState, coords).a;\n\
191 #elif (SAMPLE_TEXTURES==SAMPLE_Y410_TO_YUVA)\n\
192 sample.x = shaderTexture[0].Sample(samplerState, coords).g;\n\
193 sample.y = shaderTexture[0].Sample(samplerState, coords).r;\n\
194 sample.z = shaderTexture[0].Sample(samplerState, coords).b;\n\
196 #elif (SAMPLE_TEXTURES==SAMPLE_AYUV_TO_YUVA)\n\
197 sample.x = shaderTexture[0].Sample(samplerState, coords).z;\n\
198 sample.y = shaderTexture[0].Sample(samplerState, coords).y;\n\
199 sample.z = shaderTexture[0].Sample(samplerState, coords).x;\n\
201 #elif (SAMPLE_TEXTURES==SAMPLE_RGBA_TO_RGBA)\n\
202 sample = shaderTexture[0].Sample(samplerState, coords);\n\
203 #elif (SAMPLE_TEXTURES==SAMPLE_TRIPLANAR_TO_YUVA)\n\
204 sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n\
205 sample.y = shaderTexture[1].Sample(samplerState, coords).x;\n\
206 sample.z = shaderTexture[2].Sample(samplerState, coords).x;\n\
208 #elif (SAMPLE_TEXTURES==SAMPLE_TRIPLANAR10_TO_YUVA)\n\
209 sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n\
210 sample.y = shaderTexture[1].Sample(samplerState, coords).x;\n\
211 sample.z = shaderTexture[2].Sample(samplerState, coords).x;\n\
212 sample = sample * 64;\n\
214 #elif (SAMPLE_TEXTURES==SAMPLE_PLANAR_YUVA_TO_YUVA)\n\
215 sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n\
216 sample.y = shaderTexture[1].Sample(samplerState, coords).x;\n\
217 sample.z = shaderTexture[2].Sample(samplerState, coords).x;\n\
218 sample.a = shaderTexture[3].Sample(samplerState, coords).x;\n\
219 #elif (SAMPLE_TEXTURES==SAMPLE_NV12_TO_NV_Y)\n\
220 sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n\
224 #elif (SAMPLE_TEXTURES==SAMPLE_NV12_TO_NV_UV)\n\
225 // TODO should be shaderTexture[0] ?\n\
226 sample.xy = shaderTexture[1].Sample(samplerState, coords).xy;\n\
229 #elif (SAMPLE_TEXTURES==SAMPLE_RGBA_TO_NV_R)\n\
230 sample = shaderTexture[0].Sample(samplerState, coords);\n\
231 #elif (SAMPLE_TEXTURES==SAMPLE_RGBA_TO_NV_GB)\n\
232 sample.x = shaderTexture[0].Sample(samplerState, coords).y;\n\
233 sample.y = shaderTexture[0].Sample(samplerState, coords).z;\n\
236 #elif (SAMPLE_TEXTURES==SAMPLE_PLANAR_YUVA_TO_NV_Y)\n\
237 sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n\
240 sample.a = shaderTexture[3].Sample(samplerState, coords).x;\n\
241 #elif (SAMPLE_TEXTURES==SAMPLE_PLANAR_YUVA_TO_NV_UV)\n\
242 sample.x = shaderTexture[1].Sample(samplerState, coords).x;\n\
243 sample.y = shaderTexture[2].Sample(samplerState, coords).x;\n\
245 sample.a = shaderTexture[3].Sample(samplerState, coords).x;\n\
250 float4 main( PS_INPUT In ) : SV_TARGET\n\
254 if (In.uv.x > Boundary.x || In.uv.y > Boundary.y) \n\
255 sample = sampleTexture( borderSampler, In.uv );\n\
257 sample = sampleTexture( normalSampler, In.uv );\n\
258 float3 rgb = max(mul(sample, Colorspace),0);\n\
259 rgb = sourceToLinear(rgb);\n\
260 rgb = toneMapping(rgb);\n\
261 rgb = linearToDisplay(rgb);\n\
262 rgb = adjustRange(rgb);\n\
263 return float4(rgb, saturate(sample.a * Opacity));\n\
267 static const char globVertexShader
[] = "\n\
268 #if HAS_PROJECTION\n\
269 cbuffer VS_PROJECTION_CONST : register(b0)\n\
273 float4x4 Projection;\n\
276 struct d3d_vertex_t\n\
278 float3 Position : POSITION;\n\
279 float2 uv : TEXCOORD;\n\
284 float4 Position : SV_POSITION;\n\
285 float2 uv : TEXCOORD;\n\
288 PS_INPUT main( d3d_vertex_t In )\n\
291 float4 pos = float4(In.Position, 1);\n\
292 #if HAS_PROJECTION\n\
293 pos = mul(View, pos);\n\
294 pos = mul(Zoom, pos);\n\
295 pos = mul(Projection, pos);\n\
297 Output.Position = pos;\n\
298 Output.uv = In.uv;\n\
303 static void ReleaseID3D10Blob(d3d_shader_blob
*blob
)
305 ID3D10Blob_Release( (ID3D10Blob
*)blob
->opaque
);
308 static void ID3D10BlobtoBlob(ID3D10Blob
*d3dblob
, d3d_shader_blob
*blob
)
310 blob
->opaque
= d3dblob
;
311 blob
->pf_release
= ReleaseID3D10Blob
;
312 blob
->buf_size
= ID3D10Blob_GetBufferSize(d3dblob
);
313 blob
->buffer
= ID3D10Blob_GetBufferPointer(d3dblob
);
317 static HRESULT
CompileShader(vlc_object_t
*obj
, const d3d_shader_compiler_t
*compiler
,
318 D3D_FEATURE_LEVEL feature_level
,
319 const char *psz_shader
, bool pixelShader
,
320 const D3D_SHADER_MACRO
*defines
,
321 d3d_shader_blob
*blob
)
323 ID3D10Blob
* pShaderBlob
= NULL
, *pErrBlob
= NULL
;
325 UINT compileFlags
= 0;
327 VLC_UNUSED(compiler
);
329 # define D3DCompile(args...) compiler->OurD3DCompile(args)
330 # if !defined(NDEBUG)
331 if (IsDebuggerPresent())
332 compileFlags
+= D3DCOMPILE_DEBUG
;
340 if (likely(feature_level
>= D3D_FEATURE_LEVEL_10_0
))
342 else if (feature_level
>= D3D_FEATURE_LEVEL_9_3
)
343 target
= "ps_4_0_level_9_3";
345 target
= "ps_4_0_level_9_1";
349 if (likely(feature_level
>= D3D_FEATURE_LEVEL_10_0
))
351 else if (feature_level
>= D3D_FEATURE_LEVEL_9_3
)
352 target
= "vs_4_0_level_9_3";
354 target
= "vs_4_0_level_9_1";
357 hr
= D3DCompile(psz_shader
, strlen(psz_shader
),
358 NULL
, defines
, NULL
, "main", target
,
359 compileFlags
, 0, &pShaderBlob
, &pErrBlob
);
362 if (FAILED(hr
) || pErrBlob
) {
363 const char *err
= pErrBlob
? ID3D10Blob_GetBufferPointer(pErrBlob
) : NULL
;
365 msg_Dbg(obj
, "%s Shader: %s", pixelShader
?"Pixel":"Vertex", err
);
367 msg_Err(obj
, "invalid %s Shader (hr=0x%lX): %s", pixelShader
?"Pixel":"Vertex", hr
, err
);
369 ID3D10Blob_Release(pErrBlob
);
375 ID3D10BlobtoBlob(pShaderBlob
, blob
);
379 static HRESULT
CompilePixelShaderBlob(vlc_object_t
*o
, const d3d_shader_compiler_t
*compiler
,
380 D3D_FEATURE_LEVEL feature_level
,
381 const char *psz_sampler
,
382 const char *psz_shader_resource_views
,
383 const char *psz_src_to_linear
,
384 const char *psz_linear_to_display
,
385 const char *psz_tone_mapping
,
386 const char *psz_src_range
, const char *psz_dst_range
,
387 const char *psz_black_level
,
388 const char *psz_range_factor
,
389 const char *psz_min_black
,
390 const char *psz_max_white
,
391 d3d_shader_blob
*pPSBlob
)
393 if (var_InheritInteger(o
, "verbose") >= 4)
394 msg_Dbg(o
, "shader %s", globPixelShaderDefault
);
396 D3D_SHADER_MACRO defines
[] = {
397 { "TEXTURE_RESOURCES", psz_shader_resource_views
},
398 { "TONE_MAPPING", psz_tone_mapping
},
399 { "SRC_TO_LINEAR", psz_src_to_linear
},
400 { "LINEAR_TO_DST", psz_linear_to_display
},
401 { "SAMPLE_TEXTURES", psz_sampler
},
402 { "SRC_RANGE", psz_src_range
},
403 { "DST_RANGE", psz_dst_range
},
404 { "BLACK_LEVEL_SHIFT", psz_black_level
},
405 { "RANGE_FACTOR", psz_range_factor
},
406 { "MIN_BLACK_VALUE", psz_min_black
},
407 { "MAX_WHITE_VALUE", psz_max_white
},
412 while (defines
[param
].Name
)
414 msg_Dbg(o
,"%s = %s", defines
[param
].Name
, defines
[param
].Definition
);
419 return CompileShader(o
, compiler
, feature_level
, globPixelShaderDefault
, true,
423 HRESULT (D3D_CompilePixelShader
)(vlc_object_t
*o
, const d3d_shader_compiler_t
*compiler
,
424 D3D_FEATURE_LEVEL feature_level
,
425 const display_info_t
*display
,
426 video_transfer_func_t transfer
,
428 const d3d_format_t
*dxgi_fmt
,
429 d3d_shader_blob pPSBlob
[DXGI_MAX_RENDER_TARGET
],
430 size_t shader_views
[DXGI_MAX_RENDER_TARGET
])
432 static const char *DEFAULT_NOOP
= "0";
433 const char *psz_sampler
[DXGI_MAX_RENDER_TARGET
] = {NULL
, NULL
};
434 const char *psz_shader_resource_views
[DXGI_MAX_RENDER_TARGET
] = { NULL
, NULL
};
435 const char *psz_src_to_linear
= DEFAULT_NOOP
;
436 const char *psz_linear_to_display
= DEFAULT_NOOP
;
437 const char *psz_tone_mapping
= DEFAULT_NOOP
;
438 const char *psz_src_range
, *psz_dst_range
;
441 if ( display
->pixelFormat
->formatTexture
== DXGI_FORMAT_NV12
||
442 display
->pixelFormat
->formatTexture
== DXGI_FORMAT_P010
)
444 /* we need 2 shaders, one for the Y target, one for the UV target */
445 switch (dxgi_fmt
->formatTexture
)
447 case DXGI_FORMAT_NV12
:
448 case DXGI_FORMAT_P010
:
449 psz_sampler
[0] = "SAMPLE_NV12_TO_NV_Y";
450 psz_shader_resource_views
[0] = "1"; shader_views
[0] = 1;
451 psz_sampler
[1] = "SAMPLE_NV12_TO_NV_UV";
452 psz_shader_resource_views
[1] = "2"; shader_views
[1] = 2; // TODO should be 1 ?
454 case DXGI_FORMAT_R8G8B8A8_UNORM
:
455 case DXGI_FORMAT_B8G8R8A8_UNORM
:
456 case DXGI_FORMAT_B8G8R8X8_UNORM
:
457 case DXGI_FORMAT_R10G10B10A2_UNORM
:
458 case DXGI_FORMAT_R16G16B16A16_UNORM
:
459 case DXGI_FORMAT_B5G6R5_UNORM
:
461 psz_sampler
[0] = "SAMPLE_RGBA_TO_NV_R";
462 psz_shader_resource_views
[0] = "1"; shader_views
[0] = 1;
464 psz_sampler
[1] = "SAMPLE_RGBA_TO_NV_GB";
465 psz_shader_resource_views
[1] = "1"; shader_views
[1] = 1;
467 case DXGI_FORMAT_UNKNOWN
:
468 switch (dxgi_fmt
->fourcc
)
472 psz_sampler
[0] = "SAMPLE_PLANAR_YUVA_TO_NV_Y";
473 psz_shader_resource_views
[0] = "4"; shader_views
[0] = 4;
475 psz_sampler
[1] = "SAMPLE_PLANAR_YUVA_TO_NV_UV";
476 psz_shader_resource_views
[1] = "4"; shader_views
[1] = 4;
479 vlc_assert_unreachable();
483 vlc_assert_unreachable();
488 switch (dxgi_fmt
->formatTexture
)
490 case DXGI_FORMAT_NV12
:
491 case DXGI_FORMAT_P010
:
492 psz_sampler
[0] = "SAMPLE_NV12_TO_YUVA";
493 psz_shader_resource_views
[0] = "2"; shader_views
[0] = 2;
495 case DXGI_FORMAT_YUY2
:
496 psz_sampler
[0] = "SAMPLE_YUY2_TO_YUVA";
497 psz_shader_resource_views
[0] = "1"; shader_views
[0] = 1;
499 case DXGI_FORMAT_Y210
:
500 psz_sampler
[0] = "SAMPLE_Y210_TO_YUVA";
501 psz_shader_resource_views
[0] = "1"; shader_views
[0] = 1;
503 case DXGI_FORMAT_Y410
:
504 psz_sampler
[0] = "SAMPLE_Y410_TO_YUVA";
505 psz_shader_resource_views
[0] = "1"; shader_views
[0] = 1;
507 case DXGI_FORMAT_AYUV
:
508 psz_sampler
[0] = "SAMPLE_AYUV_TO_YUVA";
509 psz_shader_resource_views
[0] = "1"; shader_views
[0] = 1;
511 case DXGI_FORMAT_R8G8B8A8_UNORM
:
512 case DXGI_FORMAT_B8G8R8A8_UNORM
:
513 case DXGI_FORMAT_B8G8R8X8_UNORM
:
514 case DXGI_FORMAT_R10G10B10A2_UNORM
:
515 case DXGI_FORMAT_R16G16B16A16_UNORM
:
516 case DXGI_FORMAT_B5G6R5_UNORM
:
517 psz_sampler
[0] = "SAMPLE_RGBA_TO_RGBA";
518 psz_shader_resource_views
[0] = "1"; shader_views
[0] = 1;
520 case DXGI_FORMAT_UNKNOWN
:
521 switch (dxgi_fmt
->fourcc
)
523 case VLC_CODEC_I420_10L
:
524 psz_sampler
[0] = "SAMPLE_TRIPLANAR10_TO_YUVA";
525 psz_shader_resource_views
[0] = "3"; shader_views
[0] = 3;
527 case VLC_CODEC_I444_16L
:
529 psz_sampler
[0] = "SAMPLE_TRIPLANAR_TO_YUVA";
530 psz_shader_resource_views
[0] = "3"; shader_views
[0] = 3;
533 psz_sampler
[0] = "SAMPLE_PLANAR_YUVA_TO_YUVA";
534 psz_shader_resource_views
[0] = "4"; shader_views
[0] = 4;
537 vlc_assert_unreachable();
541 vlc_assert_unreachable();
545 video_transfer_func_t src_transfer
;
547 if (transfer
!= display
->transfer
)
549 /* we need to go in linear mode */
552 case TRANSFER_FUNC_SMPTE_ST2084
:
553 /* ST2084 to Linear */
554 psz_src_to_linear
= "SRC_TRANSFER_PQ";
555 src_transfer
= TRANSFER_FUNC_LINEAR
;
557 case TRANSFER_FUNC_HLG
:
558 psz_src_to_linear
= "SRC_TRANSFER_HLG";
559 src_transfer
= TRANSFER_FUNC_LINEAR
;
561 case TRANSFER_FUNC_BT709
:
562 psz_src_to_linear
= "SRC_TRANSFER_709";
563 src_transfer
= TRANSFER_FUNC_LINEAR
;
565 case TRANSFER_FUNC_BT470_M
:
566 case TRANSFER_FUNC_SRGB
:
567 psz_src_to_linear
= "SRC_TRANSFER_SRGB";
568 src_transfer
= TRANSFER_FUNC_LINEAR
;
570 case TRANSFER_FUNC_BT470_BG
:
571 psz_src_to_linear
= "SRC_TRANSFER_470BG";
572 src_transfer
= TRANSFER_FUNC_LINEAR
;
575 msg_Dbg(o
, "unhandled source transfer %d", transfer
);
576 src_transfer
= transfer
;
580 switch (display
->transfer
)
582 case TRANSFER_FUNC_SRGB
:
583 if (src_transfer
== TRANSFER_FUNC_LINEAR
)
586 psz_linear_to_display
= "DST_TRANSFER_SRGB";
588 if (transfer
== TRANSFER_FUNC_SMPTE_ST2084
|| transfer
== TRANSFER_FUNC_HLG
)
590 /* HDR tone mapping */
591 psz_tone_mapping
= "TONE_MAP_HABLE";
595 msg_Warn(o
, "don't know how to transfer from %d to sRGB", src_transfer
);
598 case TRANSFER_FUNC_SMPTE_ST2084
:
599 if (src_transfer
== TRANSFER_FUNC_LINEAR
)
601 /* Linear to ST2084 */
602 psz_linear_to_display
= "DST_TRANSFER_PQ";
605 msg_Warn(o
, "don't know how to transfer from %d to SMPTE ST 2084", src_transfer
);
608 msg_Warn(o
, "don't know how to transfer from %d to %d", src_transfer
, display
->transfer
);
613 bool dst_full_range
= display
->b_full_range
;
614 if (!DxgiIsRGBFormat(dxgi_fmt
) && DxgiIsRGBFormat(display
->pixelFormat
))
616 /* the YUV->RGB conversion already output full range */
618 src_full_range
= true; // account for this conversion
622 msg_Warn(o
, "unsupported display full range YUV on studio range RGB");
623 dst_full_range
= false; // force a conversion down
627 int range_adjust
= 0;
628 psz_src_range
= src_full_range
? "FULL_RANGE" : "STUDIO_RANGE";
629 psz_dst_range
= display
->b_full_range
? "FULL_RANGE" : "STUDIO_RANGE";
630 if (dst_full_range
!= src_full_range
) {
632 range_adjust
= 1; /* raise the source to full range */
634 range_adjust
= -1; /* lower the source to studio range */
637 FLOAT black_level
= 0;
638 FLOAT range_factor
= 1.0f
;
639 FLOAT itu_black_level
= 0.f
;
640 FLOAT itu_white_level
= 1.f
;
641 if (range_adjust
!= 0)
643 FLOAT itu_range_factor
;
644 switch (dxgi_fmt
->bitsPerChannel
)
647 /* Rec. ITU-R BT.709-6 §4.6 */
648 itu_black_level
= 16.f
/ 255.f
;
649 itu_white_level
= 235.f
/ 255.f
;
650 itu_range_factor
= (float)(235 - 16) / 255.f
;
653 /* Rec. ITU-R BT.709-6 §4.6 */
654 itu_black_level
= 64.f
/ 1023.f
;
655 itu_white_level
= 940.f
/ 1023.f
;
656 itu_range_factor
= (float)(940 - 64) / 1023.f
;
659 /* Rec. ITU-R BT.2020-2 Table 5 */
660 itu_black_level
= 256.f
/ 4095.f
;
661 itu_white_level
= 3760.f
/ 4095.f
;
662 itu_range_factor
= (float)(3760 - 256) / 4095.f
;
665 /* unknown bitdepth, use approximation for infinite bit depth */
666 itu_black_level
= 16.f
/ 256.f
;
667 itu_white_level
= 235.f
/ 256.f
;
668 itu_range_factor
= (float)(235 - 16) / 256.f
;
672 if (range_adjust
> 0)
674 /* expand the range from studio to full range */
675 black_level
-= itu_black_level
;
676 range_factor
/= itu_range_factor
;
680 /* shrink the range to studio range */
681 black_level
+= itu_black_level
;
682 range_factor
*= itu_range_factor
;
685 char psz_black_level
[20];
686 char psz_range_factor
[20];
687 char psz_min_black
[20];
688 char psz_max_white
[20];
689 snprintf(psz_black_level
, ARRAY_SIZE(psz_black_level
), "%f", black_level
);
690 snprintf(psz_range_factor
, ARRAY_SIZE(psz_range_factor
), "%f", range_factor
);
691 snprintf(psz_min_black
, ARRAY_SIZE(psz_min_black
), "%f", itu_black_level
);
692 snprintf(psz_max_white
, ARRAY_SIZE(psz_max_white
), "%f", itu_white_level
);
695 hr
= CompilePixelShaderBlob(o
, compiler
, feature_level
,
696 psz_sampler
[0], psz_shader_resource_views
[0],
698 psz_linear_to_display
,
700 psz_src_range
, psz_dst_range
,
701 psz_black_level
, psz_range_factor
, psz_min_black
, psz_max_white
,
703 if (SUCCEEDED(hr
) && psz_sampler
[1])
705 hr
= CompilePixelShaderBlob(o
, compiler
, feature_level
,
706 psz_sampler
[1], psz_shader_resource_views
[1],
708 psz_linear_to_display
,
710 psz_src_range
, psz_dst_range
,
711 psz_black_level
, psz_range_factor
, psz_min_black
, psz_max_white
,
714 D3D_ShaderBlobRelease(&pPSBlob
[0]);
720 HRESULT
D3D_CompileVertexShader(vlc_object_t
*obj
, const d3d_shader_compiler_t
*compiler
,
721 D3D_FEATURE_LEVEL feature_level
, bool flat
,
722 d3d_shader_blob
*blob
)
724 D3D_SHADER_MACRO defines
[] = {
725 { "HAS_PROJECTION", flat
? "0" : "1" },
728 return CompileShader(obj
, compiler
, feature_level
, globVertexShader
, false, defines
, blob
);
732 int D3D_InitShaderCompiler(vlc_object_t
*obj
, d3d_shader_compiler_t
*compiler
)
734 #if !VLC_WINSTORE_APP
735 /* d3dcompiler_47 is the latest on windows 10 */
736 for (int i
= 47; i
> 41; --i
)
739 _snwprintf(filename
, ARRAY_SIZE(filename
), TEXT("D3DCOMPILER_%d.dll"), i
);
740 compiler
->compiler_dll
= LoadLibrary(filename
);
741 if (compiler
->compiler_dll
) break;
743 if (compiler
->compiler_dll
)
745 compiler
->OurD3DCompile
= (void *)GetProcAddress(compiler
->compiler_dll
, "D3DCompile");
746 if (!compiler
->OurD3DCompile
) {
747 msg_Err(obj
, "Cannot locate reference to D3DCompile in d3dcompiler DLL");
748 FreeLibrary(compiler
->compiler_dll
);
752 #endif // !VLC_WINSTORE_APP
757 void D3D_ReleaseShaderCompiler(d3d_shader_compiler_t
*compiler
)
759 #if !VLC_WINSTORE_APP
760 if (compiler
->compiler_dll
)
762 FreeLibrary(compiler
->compiler_dll
);
763 compiler
->compiler_dll
= NULL
;
765 compiler
->OurD3DCompile
= NULL
;
766 #endif // !VLC_WINSTORE_APP