d3d11: pass the source primaries when compiling the shaders
[vlc.git] / modules / video_output / win32 / d3d11_shaders.c
blob647d612f6fde61288676bed0f86702e058351eea
1 /*****************************************************************************
2 * d3d11_shaders.c: Direct3D11 Shaders
3 *****************************************************************************
4 * Copyright (C) 2017 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 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < _WIN32_WINNT_WIN7
24 # undef _WIN32_WINNT
25 # define _WIN32_WINNT _WIN32_WINNT_WIN7
26 #endif
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <vlc_common.h>
34 #include <assert.h>
36 #define COBJMACROS
37 #include <d3d11.h>
39 #include "d3d11_shaders.h"
41 #if !VLC_WINSTORE_APP
42 # define D3DCompile(args...) hd3d->OurD3DCompile(args)
43 #endif
45 #define ST2084_PQ_CONSTANTS "const float ST2084_m1 = 2610.0 / (4096.0 * 4);\n\
46 const float ST2084_m2 = (2523.0 / 4096.0) * 128.0;\n\
47 const float ST2084_c1 = 3424.0 / 4096.0;\n\
48 const float ST2084_c2 = (2413.0 / 4096.0) * 32.0;\n\
49 const float ST2084_c3 = (2392.0 / 4096.0) * 32.0;\n"
51 #define STRINGIZE2(s) #s
52 #define STRINGIZE(s) STRINGIZE2(s)
54 static const char* globPixelShaderDefault = "\
55 cbuffer PS_CONSTANT_BUFFER : register(b0)\n\
56 {\n\
57 float Opacity;\n\
58 float BoundaryX;\n\
59 float BoundaryY;\n\
60 float LuminanceScale;\n\
61 };\n\
62 cbuffer PS_COLOR_TRANSFORM : register(b1)\n\
63 {\n\
64 float4x4 WhitePoint;\n\
65 float4x4 Colorspace;\n\
66 float3x3 Primaries;\n\
67 };\n\
68 Texture2D%s shaderTexture[" STRINGIZE(D3D11_MAX_SHADER_VIEW) "];\n\
69 SamplerState SamplerStates[2];\n\
70 \n\
71 struct PS_INPUT\n\
72 {\n\
73 float4 Position : SV_POSITION;\n\
74 float3 Texture : TEXCOORD0;\n\
75 };\n\
76 \n\
77 /* see http://filmicworlds.com/blog/filmic-tonemapping-operators/ */\n\
78 inline float3 hable(float3 x) {\n\
79 const float A = 0.15, B = 0.50, C = 0.10, D = 0.20, E = 0.02, F = 0.30;\n\
80 return ((x * (A*x + (C*B))+(D*E))/(x * (A*x + B) + (D*F))) - E/F;\n\
81 }\n\
82 \n\
83 /* https://en.wikipedia.org/wiki/Hybrid_Log-Gamma#Technical_details */\n\
84 inline float inverse_HLG(float x){\n\
85 const float B67_a = 0.17883277;\n\
86 const float B67_b = 0.28466892;\n\
87 const float B67_c = 0.55991073;\n\
88 const float B67_inv_r2 = 4.0; /* 1/0.5² */\n\
89 if (x <= 0.5)\n\
90 x = x * x * B67_inv_r2;\n\
91 else\n\
92 x = exp((x - B67_c) / B67_a) + B67_b;\n\
93 return x;\n\
94 }\n\
95 \n\
96 inline float3 sourceToLinear(float3 rgb) {\n\
97 %s;\n\
98 }\n\
99 \n\
100 inline float3 linearToDisplay(float3 rgb) {\n\
101 %s;\n\
102 }\n\
104 inline float3 transformPrimaries(float3 rgb) {\n\
105 %s;\n\
106 }\n\
108 inline float3 toneMapping(float3 rgb) {\n\
109 %s;\n\
110 }\n\
112 inline float3 adjustRange(float3 rgb) {\n\
113 %s;\n\
114 }\n\
116 inline float3 reorderPlanes(float3 rgb) {\n\
117 %s;\n\
118 }\n\
120 inline float4 sampleTexture(SamplerState samplerState, float3 coords) {\n\
121 float4 sample;\n\
122 %s /* sampling routine in sample */\n\
123 return sample;\n\
124 }\n\
126 float4 main( PS_INPUT In ) : SV_TARGET\n\
127 {\n\
128 float4 sample;\n\
130 if (In.Texture.x > BoundaryX || In.Texture.y > BoundaryY) \n\
131 sample = sampleTexture( SamplerStates[1], In.Texture );\n\
132 else\n\
133 sample = sampleTexture( SamplerStates[0], In.Texture );\n\
134 float4 rgba = mul(mul(sample, WhitePoint), Colorspace);\n\
135 float opacity = rgba.a * Opacity;\n\
136 float3 rgb = (float3)rgba;\n\
137 rgb = sourceToLinear(rgb);\n\
138 rgb = transformPrimaries(rgb);\n\
139 rgb = toneMapping(rgb);\n\
140 rgb = linearToDisplay(rgb);\n\
141 rgb = adjustRange(rgb);\n\
142 rgb = reorderPlanes(rgb);\n\
143 return float4(rgb, saturate(opacity));\n\
144 }\n\
147 const char* globVertexShaderFlat = "\
148 struct VS_INPUT\n\
149 {\n\
150 float4 Position : POSITION;\n\
151 float4 Texture : TEXCOORD0;\n\
152 };\n\
154 struct VS_OUTPUT\n\
155 {\n\
156 float4 Position : SV_POSITION;\n\
157 float4 Texture : TEXCOORD0;\n\
158 };\n\
160 VS_OUTPUT main( VS_INPUT In )\n\
161 {\n\
162 return In;\n\
163 }\n\
166 const char* globVertexShaderProjection = "\n\
167 cbuffer VS_PROJECTION_CONST : register(b0)\n\
168 {\n\
169 float4x4 RotX;\n\
170 float4x4 RotY;\n\
171 float4x4 RotZ;\n\
172 float4x4 View;\n\
173 float4x4 Projection;\n\
174 };\n\
175 struct VS_INPUT\n\
176 {\n\
177 float4 Position : POSITION;\n\
178 float4 Texture : TEXCOORD0;\n\
179 };\n\
181 struct VS_OUTPUT\n\
182 {\n\
183 float4 Position : SV_POSITION;\n\
184 float4 Texture : TEXCOORD0;\n\
185 };\n\
187 VS_OUTPUT main( VS_INPUT In )\n\
188 {\n\
189 VS_OUTPUT Output;\n\
190 float4 pos = In.Position;\n\
191 pos = mul(RotY, pos);\n\
192 pos = mul(RotX, pos);\n\
193 pos = mul(RotZ, pos);\n\
194 pos = mul(View, pos);\n\
195 pos = mul(Projection, pos);\n\
196 Output.Position = pos;\n\
197 Output.Texture = In.Texture;\n\
198 return Output;\n\
199 }\n\
202 bool IsRGBShader(const d3d_format_t *cfg)
204 return cfg->resourceFormat[0] != DXGI_FORMAT_R8_UNORM &&
205 cfg->resourceFormat[0] != DXGI_FORMAT_R16_UNORM &&
206 cfg->formatTexture != DXGI_FORMAT_YUY2;
209 static HRESULT CompileTargetShader(vlc_object_t *o, d3d11_handle_t *hd3d, bool legacy_shader,
210 d3d11_device_t *d3d_dev,
211 const char *psz_sampler,
212 const char *psz_src_transform,
213 const char *psz_primaries_transform,
214 const char *psz_display_transform,
215 const char *psz_tone_mapping,
216 const char *psz_adjust_range, const char *psz_move_planes,
217 ID3D11PixelShader **output)
219 char *shader = malloc(strlen(globPixelShaderDefault) + 32 + strlen(psz_sampler) +
220 strlen(psz_src_transform) + strlen(psz_primaries_transform) + strlen(psz_display_transform) +
221 strlen(psz_tone_mapping) + strlen(psz_adjust_range) + strlen(psz_move_planes));
222 if (!shader)
224 msg_Err(o, "no room for the Pixel Shader");
225 return E_OUTOFMEMORY;
227 sprintf(shader, globPixelShaderDefault, legacy_shader ? "" : "Array", psz_src_transform,
228 psz_display_transform, psz_primaries_transform, psz_tone_mapping,
229 psz_adjust_range, psz_move_planes, psz_sampler);
230 if (var_InheritInteger(o, "verbose") >= 4)
231 msg_Dbg(o, "shader %s", shader);
232 #ifndef NDEBUG
233 else {
234 msg_Dbg(o,"psz_src_transform %s", psz_src_transform);
235 msg_Dbg(o,"psz_primaries_transform %s", psz_primaries_transform);
236 msg_Dbg(o,"psz_tone_mapping %s", psz_tone_mapping);
237 msg_Dbg(o,"psz_display_transform %s", psz_display_transform);
238 msg_Dbg(o,"psz_adjust_range %s", psz_adjust_range);
239 msg_Dbg(o,"psz_sampler %s", psz_sampler);
240 msg_Dbg(o,"psz_move_planes %s", psz_move_planes);
242 #endif
244 ID3DBlob *pPSBlob = D3D11_CompileShader(o, hd3d, d3d_dev, shader, true);
245 free(shader);
246 if (!pPSBlob)
247 return E_INVALIDARG;
249 HRESULT hr = ID3D11Device_CreatePixelShader(d3d_dev->d3ddevice,
250 (void *)ID3D10Blob_GetBufferPointer(pPSBlob),
251 ID3D10Blob_GetBufferSize(pPSBlob), NULL, output);
253 ID3D10Blob_Release(pPSBlob);
254 return hr;
257 #undef D3D11_CompilePixelShader
258 HRESULT D3D11_CompilePixelShader(vlc_object_t *o, d3d11_handle_t *hd3d, bool legacy_shader,
259 d3d11_device_t *d3d_dev,
260 const display_info_t *display,
261 video_transfer_func_t transfer,
262 video_color_primaries_t primaries, bool src_full_range,
263 d3d_quad_t *quad)
265 static const char *DEFAULT_NOOP = "return rgb";
266 const char *psz_sampler[2] = {NULL, NULL};
267 const char *psz_src_transform = DEFAULT_NOOP;
268 const char *psz_display_transform = DEFAULT_NOOP;
269 const char *psz_primaries_transform = DEFAULT_NOOP;
270 const char *psz_tone_mapping = DEFAULT_NOOP;
271 const char *psz_adjust_range = DEFAULT_NOOP;
272 const char *psz_move_planes[2] = {DEFAULT_NOOP, DEFAULT_NOOP};
273 char *psz_range = NULL;
275 D3D11_SAMPLER_DESC sampDesc;
276 memset(&sampDesc, 0, sizeof(sampDesc));
277 sampDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
278 sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
279 sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
280 sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
281 sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
282 sampDesc.MinLOD = 0;
283 sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
285 HRESULT hr;
286 hr = ID3D11Device_CreateSamplerState(d3d_dev->d3ddevice, &sampDesc, &quad->d3dsampState[0]);
287 if (FAILED(hr)) {
288 msg_Err(o, "Could not Create the D3d11 Sampler State. (hr=0x%lX)", hr);
289 return hr;
292 sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
293 hr = ID3D11Device_CreateSamplerState(d3d_dev->d3ddevice, &sampDesc, &quad->d3dsampState[1]);
294 if (FAILED(hr)) {
295 msg_Err(o, "Could not Create the D3d11 Sampler State. (hr=0x%lX)", hr);
296 ID3D11SamplerState_Release(quad->d3dsampState[0]);
297 return hr;
300 if ( display->pixelFormat->formatTexture == DXGI_FORMAT_NV12 ||
301 display->pixelFormat->formatTexture == DXGI_FORMAT_P010 )
303 /* we need 2 shaders, one for the Y target, one for the UV target */
304 switch (quad->textureFormat->formatTexture)
306 case DXGI_FORMAT_NV12:
307 case DXGI_FORMAT_P010:
308 psz_sampler[0] =
309 "sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n"
310 "sample.y = 0.0;\n"
311 "sample.z = 0.0;\n"
312 "sample.a = 1;";
313 psz_sampler[1] =
314 "sample.xy = shaderTexture[1].Sample(samplerState, coords).xy;\n"
315 "sample.z = 0.0;\n"
316 "sample.a = 1;";
317 break;
318 case DXGI_FORMAT_R8G8B8A8_UNORM:
319 case DXGI_FORMAT_B8G8R8A8_UNORM:
320 case DXGI_FORMAT_B8G8R8X8_UNORM:
321 case DXGI_FORMAT_R10G10B10A2_UNORM:
322 case DXGI_FORMAT_R16G16B16A16_UNORM:
323 case DXGI_FORMAT_B5G6R5_UNORM:
324 /* Y */
325 psz_sampler[0] =
326 "sample = shaderTexture[0].Sample(samplerState, coords);\n";
327 psz_move_planes[0] = "return rgb";
328 /* UV */
329 psz_sampler[1] =
330 "sample = shaderTexture[0].Sample(samplerState, coords);\n";
331 psz_move_planes[1] =
332 "rgb.x = rgb.y;\n"
333 "rgb.y = rgb.z;\n"
334 "rgb.z = 0;\n"
335 "return rgb";
336 break;
337 case DXGI_FORMAT_UNKNOWN:
338 switch (quad->textureFormat->fourcc)
340 case VLC_CODEC_YUVA:
341 /* Y */
342 psz_sampler[0] =
343 "sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n"
344 "sample.y = 0.0;\n"
345 "sample.z = 0.0;\n"
346 "sample.a = shaderTexture[3].Sample(samplerState, coords).x;";
347 /* UV */
348 psz_sampler[1] =
349 "sample.x = shaderTexture[1].Sample(samplerState, coords).x;\n"
350 "sample.y = shaderTexture[2].Sample(samplerState, coords).x;\n"
351 "sample.z = 0.0;\n"
352 "sample.a = shaderTexture[3].Sample(samplerState, coords).x;";
353 break;
354 default:
355 vlc_assert_unreachable();
357 break;
358 default:
359 vlc_assert_unreachable();
362 else
364 switch (quad->textureFormat->formatTexture)
366 case DXGI_FORMAT_NV12:
367 case DXGI_FORMAT_P010:
368 psz_sampler[0] =
369 "sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n"
370 "sample.yz = shaderTexture[1].Sample(samplerState, coords).xy;\n"
371 "sample.a = 1;";
372 break;
373 case DXGI_FORMAT_YUY2:
374 psz_sampler[0] =
375 "sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n"
376 "sample.y = shaderTexture[0].Sample(samplerState, coords).y;\n"
377 "sample.z = shaderTexture[0].Sample(samplerState, coords).a;\n"
378 "sample.a = 1;";
379 break;
380 case DXGI_FORMAT_AYUV:
381 psz_sampler[0] =
382 "sample.x = shaderTexture[0].Sample(SampleType, coords).z;\n"
383 "sample.y = shaderTexture[0].Sample(SampleType, coords).y;\n"
384 "sample.z = shaderTexture[0].Sample(SampleType, coords).x;\n"
385 "sample.a = shaderTexture[0].Sample(SampleType, coords).a;";
386 break;
387 case DXGI_FORMAT_R8G8B8A8_UNORM:
388 case DXGI_FORMAT_B8G8R8A8_UNORM:
389 case DXGI_FORMAT_B8G8R8X8_UNORM:
390 case DXGI_FORMAT_R10G10B10A2_UNORM:
391 case DXGI_FORMAT_R16G16B16A16_UNORM:
392 case DXGI_FORMAT_B5G6R5_UNORM:
393 psz_sampler[0] =
394 "sample = shaderTexture[0].Sample(samplerState, coords);";
395 break;
396 case DXGI_FORMAT_UNKNOWN:
397 switch (quad->textureFormat->fourcc)
399 case VLC_CODEC_I420_10L:
400 psz_sampler[0] =
401 "sample.x = shaderTexture[0].Sample(samplerState, coords).x * 64;\n"
402 "sample.y = shaderTexture[1].Sample(samplerState, coords).x * 64;\n"
403 "sample.z = shaderTexture[2].Sample(samplerState, coords).x * 64;\n"
404 "sample.a = 1;";
405 break;
406 case VLC_CODEC_I420:
407 psz_sampler[0] =
408 "sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n"
409 "sample.y = shaderTexture[1].Sample(samplerState, coords).x;\n"
410 "sample.z = shaderTexture[2].Sample(samplerState, coords).x;\n"
411 "sample.a = 1;";
412 break;
413 case VLC_CODEC_YUVA:
414 psz_sampler[0] =
415 "sample.x = shaderTexture[0].Sample(samplerState, coords).x;\n"
416 "sample.y = shaderTexture[1].Sample(samplerState, coords).x;\n"
417 "sample.z = shaderTexture[2].Sample(samplerState, coords).x;\n"
418 "sample.a = shaderTexture[3].Sample(samplerState, coords).x;";
419 break;
420 default:
421 vlc_assert_unreachable();
423 break;
424 default:
425 vlc_assert_unreachable();
429 video_transfer_func_t src_transfer;
431 if (transfer != display->colorspace->transfer)
433 /* we need to go in linear mode */
434 switch (transfer)
436 case TRANSFER_FUNC_SMPTE_ST2084:
437 /* ST2084 to Linear */
438 psz_src_transform =
439 ST2084_PQ_CONSTANTS
440 "rgb = pow(rgb, 1.0/ST2084_m2);\n"
441 "rgb = max(rgb - ST2084_c1, 0.0) / (ST2084_c2 - ST2084_c3 * rgb);\n"
442 "rgb = pow(rgb, 1.0/ST2084_m1);\n"
443 "return rgb";
444 src_transfer = TRANSFER_FUNC_LINEAR;
445 break;
446 case TRANSFER_FUNC_HLG:
447 /* HLG to Linear */
448 psz_src_transform =
449 "rgb.r = inverse_HLG(rgb.r);\n"
450 "rgb.g = inverse_HLG(rgb.g);\n"
451 "rgb.b = inverse_HLG(rgb.b);\n"
452 "return rgb / 20.0";
453 src_transfer = TRANSFER_FUNC_LINEAR;
454 break;
455 case TRANSFER_FUNC_BT709:
456 psz_src_transform = "return pow(rgb, 1.0 / 0.45)";
457 src_transfer = TRANSFER_FUNC_LINEAR;
458 break;
459 case TRANSFER_FUNC_BT470_M:
460 case TRANSFER_FUNC_SRGB:
461 psz_src_transform = "return pow(rgb, 2.2)";
462 src_transfer = TRANSFER_FUNC_LINEAR;
463 break;
464 case TRANSFER_FUNC_BT470_BG:
465 psz_src_transform = "return pow(rgb, 2.8)";
466 src_transfer = TRANSFER_FUNC_LINEAR;
467 break;
468 default:
469 msg_Dbg(o, "unhandled source transfer %d", transfer);
470 src_transfer = transfer;
471 break;
474 switch (display->colorspace->transfer)
476 case TRANSFER_FUNC_SRGB:
477 if (src_transfer == TRANSFER_FUNC_LINEAR)
479 /* Linear to sRGB */
480 psz_display_transform = "return pow(rgb, 1.0 / 2.2)";
482 if (transfer == TRANSFER_FUNC_SMPTE_ST2084 || transfer == TRANSFER_FUNC_HLG)
484 /* HDR tone mapping */
485 psz_tone_mapping =
486 "static const float3 HABLE_DIV = hable(11.2);\n"
487 "rgb = hable(rgb * LuminanceScale) / HABLE_DIV;\n"
488 "return rgb";
491 else
492 msg_Warn(o, "don't know how to transfer from %d to sRGB", src_transfer);
493 break;
495 case TRANSFER_FUNC_SMPTE_ST2084:
496 if (src_transfer == TRANSFER_FUNC_LINEAR)
498 /* Linear to ST2084 */
499 psz_display_transform =
500 ST2084_PQ_CONSTANTS
501 "rgb = pow(rgb, ST2084_m1);\n"
502 "rgb = (ST2084_c1 + ST2084_c2 * rgb) / (1 + ST2084_c3 * rgb);\n"
503 "rgb = pow(rgb, ST2084_m2);\n"
504 "return rgb";
506 else
507 msg_Warn(o, "don't know how to transfer from %d to SMPTE ST 2084", src_transfer);
508 break;
509 default:
510 msg_Warn(o, "don't know how to transfer from %d to %d", src_transfer, display->colorspace->transfer);
511 break;
515 int range_adjust = 0;
516 if (display->colorspace->b_full_range) {
517 if (!src_full_range)
518 range_adjust = 1; /* raise the source to full range */
519 } else {
520 if (src_full_range)
521 range_adjust = -1; /* lower the source to studio range */
523 if (!IsRGBShader(quad->textureFormat) && !src_full_range)
524 range_adjust--; /* the YUV->RGB conversion already output full range */
526 if (range_adjust != 0)
528 psz_range = malloc(256);
529 if (likely(psz_range))
531 FLOAT itu_black_level;
532 FLOAT itu_range_factor;
533 FLOAT itu_white_level;
534 switch (quad->textureFormat->bitsPerChannel)
536 case 8:
537 /* Rec. ITU-R BT.709-6 §4.6 */
538 itu_black_level = 16.f / 255.f;
539 itu_white_level = 235.f / 255.f;
540 itu_range_factor = (float)(235 - 16) / 255.f;
541 break;
542 case 10:
543 /* Rec. ITU-R BT.709-6 §4.6 */
544 itu_black_level = 64.f / 1023.f;
545 itu_white_level = 940.f / 1023.f;
546 itu_range_factor = (float)(940 - 64) / 1023.f;
547 break;
548 case 12:
549 /* Rec. ITU-R BT.2020-2 Table 5 */
550 itu_black_level = 256.f / 4095.f;
551 itu_white_level = 3760.f / 4095.f;
552 itu_range_factor = (float)(3760 - 256) / 4095.f;
553 break;
554 default:
555 /* unknown bitdepth, use approximation for infinite bit depth */
556 itu_black_level = 16.f / 256.f;
557 itu_white_level = 235.f / 256.f;
558 itu_range_factor = (float)(235 - 16) / 256.f;
559 break;
562 FLOAT black_level = 0;
563 FLOAT range_factor = 1.0f;
564 if (range_adjust > 0)
566 /* expand the range from studio to full range */
567 while (range_adjust--)
569 black_level -= itu_black_level;
570 range_factor /= itu_range_factor;
572 sprintf(psz_range, "return max(0,min(1,(rgb + %f) * %f))",
573 black_level, range_factor);
575 else
577 /* shrink the range to studio range */
578 while (range_adjust++)
580 black_level += itu_black_level;
581 range_factor *= itu_range_factor;
583 sprintf(psz_range, "return clamp(rgb + %f * %f,%f,%f)",
584 black_level, range_factor, itu_black_level, itu_white_level);
586 psz_adjust_range = psz_range;
590 hr = CompileTargetShader(o, hd3d, legacy_shader, d3d_dev,
591 psz_sampler[0], psz_src_transform,
592 psz_primaries_transform,
593 psz_display_transform, psz_tone_mapping,
594 psz_adjust_range, psz_move_planes[0], &quad->d3dpixelShader[0]);
595 if (!FAILED(hr) && psz_sampler[1])
596 hr = CompileTargetShader(o, hd3d, legacy_shader, d3d_dev,
597 psz_sampler[1], psz_src_transform,
598 psz_primaries_transform,
599 psz_display_transform, psz_tone_mapping,
600 psz_adjust_range, psz_move_planes[1], &quad->d3dpixelShader[1]);
601 free(psz_range);
603 return hr;
606 void D3D11_ReleasePixelShader(d3d_quad_t *quad)
608 for (size_t i=0; i<D3D11_MAX_SHADER_VIEW; i++)
610 if (quad->d3dpixelShader[i])
612 ID3D11PixelShader_Release(quad->d3dpixelShader[i]);
613 quad->d3dpixelShader[i] = NULL;
618 #undef D3D11_CompileShader
619 ID3DBlob* D3D11_CompileShader(vlc_object_t *obj, const d3d11_handle_t *hd3d, const d3d11_device_t *d3d_dev,
620 const char *psz_shader, bool pixel)
622 ID3DBlob* pShaderBlob = NULL, *pErrBlob;
623 const char *target;
624 if (pixel)
626 if (likely(d3d_dev->feature_level >= D3D_FEATURE_LEVEL_10_0))
627 target = "ps_4_0";
628 else if (d3d_dev->feature_level >= D3D_FEATURE_LEVEL_9_3)
629 target = "ps_4_0_level_9_3";
630 else
631 target = "ps_4_0_level_9_1";
633 else
635 if (likely(d3d_dev->feature_level >= D3D_FEATURE_LEVEL_10_0))
636 target = "vs_4_0";
637 else if (d3d_dev->feature_level >= D3D_FEATURE_LEVEL_9_3)
638 target = "vs_4_0_level_9_3";
639 else
640 target = "vs_4_0_level_9_1";
643 HRESULT hr = D3DCompile(psz_shader, strlen(psz_shader),
644 NULL, NULL, NULL, "main", target,
645 0, 0, &pShaderBlob, &pErrBlob);
647 if (FAILED(hr)) {
648 char *err = pErrBlob ? ID3D10Blob_GetBufferPointer(pErrBlob) : NULL;
649 msg_Err(obj, "invalid %s Shader (hr=0x%lX): %s", pixel?"Pixel":"Vertex", hr, err );
650 if (pErrBlob)
651 ID3D10Blob_Release(pErrBlob);
652 return NULL;
654 return pShaderBlob;
657 #undef GetFormatLuminance
658 float GetFormatLuminance(vlc_object_t *o, const video_format_t *fmt)
660 switch (fmt->transfer)
662 case TRANSFER_FUNC_SMPTE_ST2084:
663 /* that's the default PQ value if the metadata are not set */
664 return MAX_PQ_BRIGHTNESS;
665 case TRANSFER_FUNC_HLG:
666 return 2000;
667 case TRANSFER_FUNC_BT470_BG:
668 case TRANSFER_FUNC_BT470_M:
669 case TRANSFER_FUNC_BT709:
670 case TRANSFER_FUNC_SRGB:
671 return DEFAULT_BRIGHTNESS;
672 default:
673 msg_Dbg(o, "unhandled source transfer %d", fmt->transfer);
674 return DEFAULT_BRIGHTNESS;
678 HRESULT D3D11_CreateRenderTargets( d3d11_device_t *d3d_dev, ID3D11Resource *texture,
679 const d3d_format_t *cfg, ID3D11RenderTargetView *output[D3D11_MAX_SHADER_VIEW] )
681 D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
682 renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
683 renderTargetViewDesc.Texture2D.MipSlice = 0;
685 for (size_t i=0; i<D3D11_MAX_SHADER_VIEW; i++)
687 if (cfg->resourceFormat[i])
689 renderTargetViewDesc.Format = cfg->resourceFormat[i];
690 HRESULT hr = ID3D11Device_CreateRenderTargetView(d3d_dev->d3ddevice, texture,
691 &renderTargetViewDesc, &output[i]);
692 if (FAILED(hr))
694 return hr;
698 return S_OK;
701 void D3D11_ClearRenderTargets(d3d11_device_t *d3d_dev, const d3d_format_t *cfg,
702 ID3D11RenderTargetView *targets[D3D11_MAX_SHADER_VIEW])
704 static const FLOAT blackY[1] = {0.0f};
705 static const FLOAT blackUV[2] = {0.5f, 0.5f};
706 static const FLOAT blackRGBA[4] = {0.0f, 0.0f, 0.0f, 1.0f};
707 static const FLOAT blackYUY2[4] = {0.0f, 0.5f, 0.0f, 0.5f};
708 static const FLOAT blackVUYA[4] = {0.5f, 0.5f, 0.0f, 1.0f};
710 switch (cfg->formatTexture)
712 case DXGI_FORMAT_NV12:
713 case DXGI_FORMAT_P010:
714 ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0], blackY);
715 ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[1], blackUV);
716 break;
717 case DXGI_FORMAT_R8G8B8A8_UNORM:
718 case DXGI_FORMAT_B8G8R8A8_UNORM:
719 case DXGI_FORMAT_B8G8R8X8_UNORM:
720 case DXGI_FORMAT_R10G10B10A2_UNORM:
721 case DXGI_FORMAT_B5G6R5_UNORM:
722 ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0], blackRGBA);
723 break;
724 case DXGI_FORMAT_YUY2:
725 ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0], blackYUY2);
726 break;
727 case DXGI_FORMAT_AYUV:
728 ID3D11DeviceContext_ClearRenderTargetView( d3d_dev->d3dcontext, targets[0], blackVUYA);
729 break;
730 default:
731 vlc_assert_unreachable();
735 static HRESULT D3D11_CompileVertexShader(vlc_object_t *obj, d3d11_handle_t *hd3d,
736 d3d11_device_t *d3d_dev, const char *psz_shader,
737 d3d_vshader_t *output)
739 HRESULT hr = E_FAIL;
740 ID3DBlob *pVSBlob = D3D11_CompileShader(obj, hd3d, d3d_dev, psz_shader, false);
741 if (!pVSBlob)
742 goto error;
744 hr = ID3D11Device_CreateVertexShader(d3d_dev->d3ddevice, (void *)ID3D10Blob_GetBufferPointer(pVSBlob),
745 ID3D10Blob_GetBufferSize(pVSBlob), NULL, &output->shader);
747 if(FAILED(hr)) {
748 msg_Err(obj, "Failed to create the flat vertex shader. (hr=0x%lX)", hr);
749 goto error;
752 static D3D11_INPUT_ELEMENT_DESC layout[] = {
753 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
754 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
757 hr = ID3D11Device_CreateInputLayout(d3d_dev->d3ddevice, layout, 2, (void *)ID3D10Blob_GetBufferPointer(pVSBlob),
758 ID3D10Blob_GetBufferSize(pVSBlob), &output->layout);
760 ID3D10Blob_Release(pVSBlob);
761 pVSBlob = NULL;
762 if(FAILED(hr)) {
763 msg_Err(obj, "Failed to create the vertex input layout. (hr=0x%lX)", hr);
764 goto error;
767 return S_OK;
768 error:
769 return hr;
772 void D3D11_SetVertexShader(d3d_vshader_t *dst, d3d_vshader_t *src)
774 dst->layout = src->layout;
775 ID3D11InputLayout_AddRef(dst->layout);
776 dst->shader = src->shader;
777 ID3D11VertexShader_AddRef(dst->shader);
780 void D3D11_ReleaseVertexShader(d3d_vshader_t *shader)
782 if (shader->layout)
784 ID3D11InputLayout_Release(shader->layout);
785 shader->layout = NULL;
787 if (shader->shader)
789 ID3D11VertexShader_Release(shader->shader);
790 shader->shader = NULL;
794 #undef D3D11_CompileFlatVertexShader
795 HRESULT D3D11_CompileFlatVertexShader(vlc_object_t *obj, d3d11_handle_t *hd3d,
796 d3d11_device_t *d3d_dev, d3d_vshader_t *output)
798 return D3D11_CompileVertexShader(obj, hd3d, d3d_dev, globVertexShaderFlat, output);
801 #undef D3D11_CompileProjectionVertexShader
802 HRESULT D3D11_CompileProjectionVertexShader(vlc_object_t *obj, d3d11_handle_t *hd3d,
803 d3d11_device_t *d3d_dev, d3d_vshader_t *output)
805 return D3D11_CompileVertexShader(obj, hd3d, d3d_dev, globVertexShaderProjection, output);