qt: playlist: use item title if available
[vlc.git] / modules / video_output / win32 / d3d_dynamic_shader.c
blobf08ff79dedcbdcf23af1817e645f172b679ae549
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 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <windows.h>
28 #include <assert.h>
30 #include <vlc_common.h>
32 #define COBJMACROS
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\
40 {\n\
41 float4x3 Colorspace;\n\
42 float Opacity;\n\
43 float LuminanceScale;\n\
44 float2 Boundary;\n\
45 };\n\
46 Texture2D shaderTexture[TEXTURE_RESOURCES];\n\
47 SamplerState normalSampler : register(s0);\n\
48 SamplerState borderSampler : register(s1);\n\
49 \n\
50 struct PS_INPUT\n\
51 {\n\
52 float4 Position : SV_POSITION;\n\
53 float2 uv : TEXCOORD;\n\
54 };\n\
55 \n\
56 #define TONE_MAP_HABLE 1\n\
57 \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\
63 \n\
64 #define DST_TRANSFER_SRGB 1\n\
65 #define DST_TRANSFER_PQ 2\n\
66 \n\
67 #define FULL_RANGE 1\n\
68 #define STUDIO_RANGE 2\n\
69 \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\
79 \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\
86 \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\
92 }\n\
93 #endif\n\
94 \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\
102 if (x <= 0.5)\n\
103 x = x * x * B67_inv_r2;\n\
104 else\n\
105 x = exp((x - B67_c) / B67_a) + B67_b;\n\
106 return x;\n\
107 }\n\
108 #endif\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\
135 #else\n\
136 return rgb;\n\
137 #endif\n\
138 }\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\
152 #else\n\
153 return rgb;\n\
154 #endif\n\
155 }\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\
162 #endif\n\
163 return rgb;\n\
164 }\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\
169 #else\n\
170 return rgb;\n\
171 #endif\n\
172 }\n\
174 inline float4 sampleTexture(SamplerState samplerState, float2 coords) {\n\
175 float4 sample;\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\
180 sample.a = 1;\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\
185 sample.a = 1;\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\
190 sample.a = 1;\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\
195 sample.a = 1;\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\
200 sample.a = 1;\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\
207 sample.a = 1;\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\
213 sample.a = 1;\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\
221 sample.y = 0.0;\n\
222 sample.z = 0.0;\n\
223 sample.a = 1;\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\
227 sample.z = 0.0;\n\
228 sample.a = 1;\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\
234 sample.z = 0;\n\
235 sample.a = 1;\n\
236 #elif (SAMPLE_TEXTURES==SAMPLE_PLANAR_YUVA_TO_NV_Y)\n\
237 sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n\
238 sample.y = 0.0;\n\
239 sample.z = 0.0;\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\
244 sample.z = 0.0;\n\
245 sample.a = shaderTexture[3].Sample(samplerState, coords).x;\n\
246 #endif\n\
247 return sample;\n\
248 }\n\
250 float4 main( PS_INPUT In ) : SV_TARGET\n\
251 {\n\
252 float4 sample;\n\
254 if (In.uv.x > Boundary.x || In.uv.y > Boundary.y) \n\
255 sample = sampleTexture( borderSampler, In.uv );\n\
256 else\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\
264 }\n\
267 static const char globVertexShader[] = "\n\
268 #if HAS_PROJECTION\n\
269 cbuffer VS_PROJECTION_CONST : register(b0)\n\
270 {\n\
271 float4x4 View;\n\
272 float4x4 Zoom;\n\
273 float4x4 Projection;\n\
274 };\n\
275 #endif\n\
276 struct d3d_vertex_t\n\
277 {\n\
278 float3 Position : POSITION;\n\
279 float2 uv : TEXCOORD;\n\
280 };\n\
282 struct PS_INPUT\n\
283 {\n\
284 float4 Position : SV_POSITION;\n\
285 float2 uv : TEXCOORD;\n\
286 };\n\
288 PS_INPUT main( d3d_vertex_t In )\n\
289 {\n\
290 PS_INPUT Output;\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\
296 #endif\n\
297 Output.Position = pos;\n\
298 Output.uv = In.uv;\n\
299 return Output;\n\
300 }\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;
326 #if VLC_WINSTORE_APP
327 VLC_UNUSED(compiler);
328 #else
329 # define D3DCompile(args...) compiler->OurD3DCompile(args)
330 # if !defined(NDEBUG)
331 if (IsDebuggerPresent())
332 compileFlags += D3DCOMPILE_DEBUG;
333 # endif
334 #endif
335 HRESULT hr;
337 const char *target;
338 if (pixelShader)
340 if (likely(feature_level >= D3D_FEATURE_LEVEL_10_0))
341 target = "ps_4_0";
342 else if (feature_level >= D3D_FEATURE_LEVEL_9_3)
343 target = "ps_4_0_level_9_3";
344 else
345 target = "ps_4_0_level_9_1";
347 else
349 if (likely(feature_level >= D3D_FEATURE_LEVEL_10_0))
350 target = "vs_4_0";
351 else if (feature_level >= D3D_FEATURE_LEVEL_9_3)
352 target = "vs_4_0_level_9_3";
353 else
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;
364 if (SUCCEEDED(hr))
365 msg_Dbg(obj, "%s Shader: %s", pixelShader?"Pixel":"Vertex", err );
366 else
367 msg_Err(obj, "invalid %s Shader (hr=0x%lX): %s", pixelShader?"Pixel":"Vertex", hr, err );
368 if (pErrBlob)
369 ID3D10Blob_Release(pErrBlob);
370 if (FAILED(hr))
371 return hr;
373 if (!pShaderBlob)
374 return E_INVALIDARG;
375 ID3D10BlobtoBlob(pShaderBlob, blob);
376 return S_OK;
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 },
408 { NULL, NULL },
410 #ifndef NDEBUG
411 size_t param=0;
412 while (defines[param].Name)
414 msg_Dbg(o,"%s = %s", defines[param].Name, defines[param].Definition);
415 param++;
417 #endif
419 return CompileShader(o, compiler, feature_level, globPixelShaderDefault, true,
420 defines, pPSBlob);
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,
427 bool src_full_range,
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;
439 shader_views[1] = 0;
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 ?
453 break;
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:
460 /* Y */
461 psz_sampler[0] = "SAMPLE_RGBA_TO_NV_R";
462 psz_shader_resource_views[0] = "1"; shader_views[0] = 1;
463 /* UV */
464 psz_sampler[1] = "SAMPLE_RGBA_TO_NV_GB";
465 psz_shader_resource_views[1] = "1"; shader_views[1] = 1;
466 break;
467 case DXGI_FORMAT_UNKNOWN:
468 switch (dxgi_fmt->fourcc)
470 case VLC_CODEC_YUVA:
471 /* Y */
472 psz_sampler[0] = "SAMPLE_PLANAR_YUVA_TO_NV_Y";
473 psz_shader_resource_views[0] = "4"; shader_views[0] = 4;
474 /* UV */
475 psz_sampler[1] = "SAMPLE_PLANAR_YUVA_TO_NV_UV";
476 psz_shader_resource_views[1] = "4"; shader_views[1] = 4;
477 break;
478 default:
479 vlc_assert_unreachable();
481 break;
482 default:
483 vlc_assert_unreachable();
486 else
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;
494 break;
495 case DXGI_FORMAT_YUY2:
496 psz_sampler[0] = "SAMPLE_YUY2_TO_YUVA";
497 psz_shader_resource_views[0] = "1"; shader_views[0] = 1;
498 break;
499 case DXGI_FORMAT_Y210:
500 psz_sampler[0] = "SAMPLE_Y210_TO_YUVA";
501 psz_shader_resource_views[0] = "1"; shader_views[0] = 1;
502 break;
503 case DXGI_FORMAT_Y410:
504 psz_sampler[0] = "SAMPLE_Y410_TO_YUVA";
505 psz_shader_resource_views[0] = "1"; shader_views[0] = 1;
506 break;
507 case DXGI_FORMAT_AYUV:
508 psz_sampler[0] = "SAMPLE_AYUV_TO_YUVA";
509 psz_shader_resource_views[0] = "1"; shader_views[0] = 1;
510 break;
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;
519 break;
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;
526 break;
527 case VLC_CODEC_I444_16L:
528 case VLC_CODEC_I420:
529 psz_sampler[0] = "SAMPLE_TRIPLANAR_TO_YUVA";
530 psz_shader_resource_views[0] = "3"; shader_views[0] = 3;
531 break;
532 case VLC_CODEC_YUVA:
533 psz_sampler[0] = "SAMPLE_PLANAR_YUVA_TO_YUVA";
534 psz_shader_resource_views[0] = "4"; shader_views[0] = 4;
535 break;
536 default:
537 vlc_assert_unreachable();
539 break;
540 default:
541 vlc_assert_unreachable();
545 video_transfer_func_t src_transfer;
547 if (transfer != display->transfer)
549 /* we need to go in linear mode */
550 switch (transfer)
552 case TRANSFER_FUNC_SMPTE_ST2084:
553 /* ST2084 to Linear */
554 psz_src_to_linear = "SRC_TRANSFER_PQ";
555 src_transfer = TRANSFER_FUNC_LINEAR;
556 break;
557 case TRANSFER_FUNC_HLG:
558 psz_src_to_linear = "SRC_TRANSFER_HLG";
559 src_transfer = TRANSFER_FUNC_LINEAR;
560 break;
561 case TRANSFER_FUNC_BT709:
562 psz_src_to_linear = "SRC_TRANSFER_709";
563 src_transfer = TRANSFER_FUNC_LINEAR;
564 break;
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;
569 break;
570 case TRANSFER_FUNC_BT470_BG:
571 psz_src_to_linear = "SRC_TRANSFER_470BG";
572 src_transfer = TRANSFER_FUNC_LINEAR;
573 break;
574 default:
575 msg_Dbg(o, "unhandled source transfer %d", transfer);
576 src_transfer = transfer;
577 break;
580 switch (display->transfer)
582 case TRANSFER_FUNC_SRGB:
583 if (src_transfer == TRANSFER_FUNC_LINEAR)
585 /* Linear to sRGB */
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";
594 else
595 msg_Warn(o, "don't know how to transfer from %d to sRGB", src_transfer);
596 break;
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";
604 else
605 msg_Warn(o, "don't know how to transfer from %d to SMPTE ST 2084", src_transfer);
606 break;
607 default:
608 msg_Warn(o, "don't know how to transfer from %d to %d", src_transfer, display->transfer);
609 break;
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 */
617 if (!src_full_range)
618 src_full_range = true; // account for this conversion
619 else
621 if (!dst_full_range)
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) {
631 if (!src_full_range)
632 range_adjust = 1; /* raise the source to full range */
633 else
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)
646 case 8:
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;
651 break;
652 case 10:
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;
657 break;
658 case 12:
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;
663 break;
664 default:
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;
669 break;
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;
678 else
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);
694 HRESULT hr;
695 hr = CompilePixelShaderBlob(o, compiler, feature_level,
696 psz_sampler[0], psz_shader_resource_views[0],
697 psz_src_to_linear,
698 psz_linear_to_display,
699 psz_tone_mapping,
700 psz_src_range, psz_dst_range,
701 psz_black_level, psz_range_factor, psz_min_black, psz_max_white,
702 &pPSBlob[0]);
703 if (SUCCEEDED(hr) && psz_sampler[1])
705 hr = CompilePixelShaderBlob(o, compiler, feature_level,
706 psz_sampler[1], psz_shader_resource_views[1],
707 psz_src_to_linear,
708 psz_linear_to_display,
709 psz_tone_mapping,
710 psz_src_range, psz_dst_range,
711 psz_black_level, psz_range_factor, psz_min_black, psz_max_white,
712 &pPSBlob[1]);
713 if (FAILED(hr))
714 D3D_ShaderBlobRelease(&pPSBlob[0]);
717 return hr;
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" },
726 { NULL, NULL },
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)
738 WCHAR filename[19];
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);
749 return VLC_EGENERIC;
752 #endif // !VLC_WINSTORE_APP
754 return VLC_SUCCESS;
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