• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <2019> Seungha Yang <seungha.yang@navercorp.com>
3  * Copyright (C) <2019> Jeongki Kim <jeongki.kim@jeongki.kim>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24 
25 #include "gstd3d11converter.h"
26 #include "gstd3d11shader.h"
27 #include "gstd3d11pluginutils.h"
28 #include <wrl.h>
29 #include <string.h>
30 
31 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_converter_debug);
32 #define GST_CAT_DEFAULT gst_d3d11_converter_debug
33 
34 /* *INDENT-OFF* */
35 using namespace Microsoft::WRL;
36 /* *INDENT-ON* */
37 
38 #define CONVERTER_MAX_QUADS 2
39 
40 /* *INDENT-OFF* */
41 typedef struct
42 {
43   FLOAT trans_matrix[12];
44   FLOAT padding[4];
45 } PixelShaderColorTransform;
46 
47 typedef struct
48 {
49   FLOAT alpha_mul;
50   FLOAT padding[3];
51 } AlphaConstBuffer;
52 
53 typedef struct
54 {
55   struct {
56     FLOAT x;
57     FLOAT y;
58     FLOAT z;
59   } position;
60   struct {
61     FLOAT x;
62     FLOAT y;
63   } texture;
64 } VertexData;
65 
66 typedef struct
67 {
68   gboolean has_transform;
69   gboolean has_alpha;
70   const gchar *func;
71 } PixelShaderTemplate;
72 
73 static const gchar templ_color_transform_const_buffer[] =
74     "cbuffer PixelShaderColorTransform : register(b%u)\n"
75     "{\n"
76     "  float3x4 trans_matrix;\n"
77     "  float3 padding;\n"
78     "};";
79 
80 static const gchar templ_alpha_const_buffer[] =
81     "cbuffer AlphaConstBuffer : register(b%u)\n"
82     "{\n"
83     "  float alpha_mul;\n"
84     "  float3 padding;\n"
85     "};";
86 
87 #define HLSL_FUNC_YUV_TO_RGB \
88     "float3 yuv_to_rgb (float3 yuv)\n" \
89     "{\n" \
90     "  yuv += float3(-0.062745f, -0.501960f, -0.501960f);\n" \
91     "  yuv = mul(yuv, trans_matrix);\n" \
92     "  return saturate(yuv);\n" \
93     "}\n"
94 
95 #define HLSL_FUNC_RGB_TO_YUV \
96     "float3 rgb_to_yuv (float3 rgb)\n" \
97     "{\n" \
98     "  float3 yuv;\n" \
99     "  yuv = mul(rgb, trans_matrix);\n" \
100     "  yuv += float3(0.062745f, 0.501960f, 0.501960f);\n" \
101     "  return saturate(yuv);\n" \
102     "}\n"
103 
104 #define HLSL_PS_OUTPUT_ONE_PLANE_BODY \
105     "  float4 Plane_0: SV_TARGET0;"
106 
107 #define HLSL_PS_OUTPUT_TWO_PLANES_BODY \
108     "  float4 Plane_0: SV_TARGET0;\n" \
109     "  float4 Plane_1: SV_TARGET1;"
110 
111 static const PixelShaderTemplate templ_REORDER =
112     { FALSE, TRUE, NULL };
113 
114 static const PixelShaderTemplate templ_REORDER_NO_ALPHA =
115     { FALSE, FALSE, NULL };
116 
117 static const PixelShaderTemplate templ_YUV_to_RGB =
118     { TRUE, FALSE, HLSL_FUNC_YUV_TO_RGB };
119 
120 static const PixelShaderTemplate templ_RGB_to_YUV =
121     { TRUE, FALSE, HLSL_FUNC_RGB_TO_YUV };
122 
123 static const gchar templ_REORDER_BODY[] =
124     "  float4 xyza;\n"
125     "  xyza.xyz = shaderTexture[0].Sample(samplerState, input.Texture).xyz;\n"
126     "  xyza.a = shaderTexture[0].Sample(samplerState, input.Texture).a * alpha_mul;\n"
127     "  output.Plane_0 = xyza;\n";
128 
129 static const gchar templ_VUYA_to_RGB_BODY[] =
130     "  float4 sample, rgba;\n"
131     "  sample.x  = shaderTexture[0].Sample(samplerState, input.Texture).z;\n"
132     "  sample.y  = shaderTexture[0].Sample(samplerState, input.Texture).y;\n"
133     "  sample.z  = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
134     "  sample.a  = shaderTexture[0].Sample(samplerState, input.Texture).a;\n"
135     "  rgba.rgb = yuv_to_rgb (sample.xyz);\n"
136     "  rgba.a = sample.a;\n"
137     "  output.Plane_0 = rgba;\n";
138 
139 static const gchar templ_RGB_to_VUYA_BODY[] =
140     "  float4 sample, vuya;\n"
141     "  sample = shaderTexture[0].Sample(samplerState, input.Texture);\n"
142     "  vuya.zyx = rgb_to_yuv (sample.rgb);\n"
143     "  vuya.a = sample.a;\n"
144     "  output.Plane_0 = vuya;\n";
145 
146 static const gchar templ_PACKED_YUV_to_RGB_BODY[] =
147     "  float4 sample, rgba;\n"
148     "  sample.x  = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
149     "  sample.y  = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
150     "  sample.z  = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
151     "  rgba.rgb = yuv_to_rgb (sample.xyz);\n"
152     "  rgba.a = 1;\n"
153     "  output.Plane_0 = rgba;\n";
154 
155 /* YUV to RGB conversion */
156 static const gchar templ_PLANAR_YUV_to_RGB_BODY[] =
157     "  float4 sample, rgba;\n"
158     "  sample.x  = shaderTexture[0].Sample(samplerState, input.Texture).x * %u;\n"
159     "  sample.%c  = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
160     "  sample.%c  = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
161     "  rgba.rgb = yuv_to_rgb (sample.xyz);\n"
162     "  rgba.a = 1.0;\n"
163     "  output.Plane_0 = rgba;\n";
164 
165 static const gchar templ_SEMI_PLANAR_to_RGB_BODY[] =
166     "  float4 sample, rgba;\n"
167     "  sample.x  = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
168     "  sample.yz = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
169     "  rgba.rgb = yuv_to_rgb (sample.xyz);\n"
170     "  rgba.a = 1.0;\n"
171     "  output.Plane_0 = rgba;\n";
172 
173 /* RGB to YUV conversion */
174 static const gchar templ_RGB_to_LUMA_BODY[] =
175     "  float4 sample, rgba;\n"
176     "  rgba.rgb = shaderTexture[0].Sample(samplerState, input.Texture).rgb;\n"
177     "  sample.xyz = rgb_to_yuv (rgba.rgb);\n"
178     "  sample.y = 0.0;\n"
179     "  sample.z = 0.0;\n"
180     "  sample.a = 0.0;\n"
181     "  sample.x = sample.x / %d;\n"
182     "  output.Plane_0 = sample;\n";
183 
184 static const gchar templ_RGB_to_SEMI_PLANAR_CHROMA_BODY[] =
185     "  float4 sample, rgba;\n"
186     "  rgba.rgb = shaderTexture[0].Sample(samplerState, input.Texture).rgb;\n"
187     "  sample.xyz = rgb_to_yuv (rgba.rgb);\n"
188     "  sample.%c = sample.y;\n"
189     "  sample.%c = sample.z;\n"
190     "  sample.z = 0.0;\n"
191     "  sample.a = 0.0;\n"
192     "  output.Plane_0 = sample;\n";
193 
194 static const gchar templ_RGB_to_PLANAR_CHROMA_BODY[] =
195     "  float4 sample, rgba;\n"
196     "  rgba.rgb = shaderTexture[0].Sample(samplerState, input.Texture).rgb;\n"
197     "  sample.xyz = rgb_to_yuv (rgba.rgb);\n"
198     "  output.Plane_0 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n"
199     "  output.Plane_1 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n";
200 
201 /* YUV to YUV conversion */
202 static const gchar templ_LUMA_to_LUMA_BODY[] =
203     "  float4 sample;\n"
204     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x * %u;\n"
205     "  output.Plane_0 = float4(sample.x / %u, 0.0, 0.0, 0.0);\n";
206 
207 static const gchar templ_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY[] =
208     "  float4 in_sample;\n"
209     "  float4 out_sample;\n"
210     "  in_sample.%c = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
211     "  in_sample.%c = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
212     "  out_sample.xy = in_sample.yz;\n"
213     "  output.Plane_0 = float4(out_sample.%c%c, 0.0, 0.0);\n";
214 
215 static const gchar templ_SEMI_PLANAR_TO_PLANAR_CHROMA_BODY[] =
216     "  float4 sample;\n"
217     "  sample.yz = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
218     "  output.Plane_0 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n"
219     "  output.Plane_1 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n";
220 
221 static const gchar templ_SEMI_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY[] =
222     "  float4 sample;\n"
223     "  sample.xy = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
224     "  output.Plane_0 = float4(sample.%c%c, 0.0, 0.0);\n";
225 
226 static const gchar templ_PLANAR_TO_PLANAR_CHROMA_BODY[] =
227     "  float4 sample;\n"
228     "  sample.%c = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
229     "  sample.%c = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
230     "  output.Plane_0 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n"
231     "  output.Plane_1 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n";
232 
233 /* VUYA to YUV */
234 static const gchar templ_VUYA_to_LUMA_BODY[] =
235     "  float4 sample;\n"
236     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).z;\n"
237     "  output.Plane_0 = float4(sample.x / %u, 0.0, 0.0, 0.0);\n";
238 
239 static const gchar templ_VUYA_TO_PLANAR_CHROMA_BODY[] =
240     "  float4 sample;\n"
241     "  sample.yz = shaderTexture[0].Sample(samplerState, input.Texture).yx;\n"
242     "  output.Plane_0 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n"
243     "  output.Plane_1 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n";
244 
245 static const gchar templ_VUYA_TO_SEMI_PLANAR_CHROMA_BODY[] =
246     "  float2 sample;\n"
247     "  sample.xy = shaderTexture[0].Sample(samplerState, input.Texture).%c%c;\n"
248     "  output.Plane_0 = float4(sample.xy, 0.0, 0.0);\n";
249 
250 /* YUV to VUYA */
251 static const gchar templ_PLANAR_to_VUYA_BODY[] =
252     "  float4 sample;\n"
253     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x * %u;\n"
254     "  sample.%c = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
255     "  sample.%c = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
256     "  output.Plane_0 = float4(sample.zyx, 1.0f);\n";
257 
258 static const gchar templ_SEMI_PLANAR_to_VUYA_BODY[] =
259     "  float4 sample;\n"
260     "  sample.z = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
261     "  sample.xy = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
262     "  output.Plane_0 = float4(sample.xyz, 1.0f);\n";
263 
264 static const gchar templ_PACKED_YUV_to_VUYA_BODY[] =
265     "  float4 sample;\n"
266     "  sample.z = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
267     "  sample.y = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
268     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
269     "  output.Plane_0 = float4(sample.xyz, 1.0f);\n";
270 
271 /* packed YUV to (semi) planar YUV */
272 static const gchar templ_PACKED_YUV_to_LUMA_BODY[] =
273     "  float4 sample;\n"
274     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
275     "  output.Plane_0 = float4(sample.x / %u, 0.0, 0.0, 0.0);\n";
276 
277 static const gchar templ_PACKED_YUV_TO_PLANAR_CHROMA_BODY[] =
278     "  float4 sample;\n"
279     "  sample.y = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
280     "  sample.z = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
281     "  output.Plane_0 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n"
282     "  output.Plane_1 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n";
283 
284 static const gchar templ_PACKED_YUV_TO_SEMI_PLANAR_CHROMA_BODY[] =
285     "  float4 sample;\n"
286     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
287     "  sample.y = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
288     "  output.Plane_0 = float4(sample.%c%c, 0.0, 0.0);\n";
289 
290 /* to GRAY */
291 static const gchar templ_RGB_to_GRAY_BODY[] =
292     "  float4 sample, rgba;\n"
293     "  rgba.rgb = shaderTexture[0].Sample(samplerState, input.Texture).rgb;\n"
294     "  sample.x = rgb_to_yuv (rgba.rgb).x;\n"
295     "  sample.y = 0.0;\n"
296     "  sample.z = 0.0;\n"
297     "  sample.a = 0.0;\n"
298     "  output.Plane_0 = sample;\n";
299 
300 static const gchar templ_VUYA_to_GRAY_BODY[] =
301     "  float4 sample;\n"
302     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).z;\n"
303     "  sample.y = 0.0;\n"
304     "  sample.z = 0.0;\n"
305     "  sample.a = 0.0;\n"
306     "  output.Plane_0 = sample;\n";
307 
308 static const gchar templ_YUV_to_GRAY_BODY[] =
309     "  float4 sample;\n"
310     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x * %u;\n"
311     "  sample.y = 0.0;\n"
312     "  sample.z = 0.0;\n"
313     "  sample.a = 0.0;\n"
314     "  output.Plane_0 = sample;\n";
315 
316 static const gchar templ_PACKED_YUV_TO_GRAY[] =
317     "  float4 sample;\n"
318     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
319     "  sample.y = 0.0;\n"
320     "  sample.z = 0.0;\n"
321     "  sample.a = 0.0;\n"
322     "  output.Plane_0 = sample;\n";
323 
324 static const gchar templ_GRAY_to_GRAY_BODY[] =
325     "  float4 sample;\n"
326     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
327     "  sample.y = 0.0;\n"
328     "  sample.z = 0.0;\n"
329     "  sample.a = 0.0;\n"
330     "  output.Plane_0 = sample;\n";
331 
332 /* from GRAY */
333 static const gchar templ_GRAY_to_RGB_BODY[] =
334     "  float4 sample, rgba;\n"
335     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
336     "  sample.y = sample.x;\n"
337     "  sample.z = sample.x;\n"
338     "  sample.a = 1.0;\n"
339     "  output.Plane_0 = sample;\n";
340 
341 static const gchar templ_GRAY_to_VUYA_BODY[] =
342     "  float4 sample;\n"
343     "  sample.z = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
344     "  sample.x = 0.5;\n"
345     "  sample.y = 0.5;\n"
346     "  sample.a = 1.0;\n"
347     "  output.Plane_0 = sample;\n";
348 
349 static const gchar templ_GRAY_to_LUMA_BODY[] =
350     "  float4 sample;\n"
351     "  sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x / %u;\n"
352     "  sample.y = 0.0;\n"
353     "  sample.z = 0.0;\n"
354     "  sample.a = 0.0;\n"
355     "  output.Plane_0 = sample;\n";
356 
357 static const gchar templ_GRAY_to_PLANAR_CHROMA_BODY[] =
358     "  float val = 0.5 / %u;\n"
359     "  output.Plane_0 = float4(val, 0.0, 0.0, 0.0);\n"
360     "  output.Plane_1 = float4(val, 0.0, 0.0, 0.0);\n";
361 
362 static const gchar templ_GRAY_to_SEMI_PLANAR_CHROMA_BODY[] =
363     "  output.Plane_0 = float4(0.5, 0.5, 0.0, 0.0);\n";
364 
365 static const gchar templ_pixel_shader[] =
366     /* constant buffer */
367     "%s\n"
368     "%s\n"
369     "Texture2D shaderTexture[4];\n"
370     "SamplerState samplerState;\n"
371     "\n"
372     "struct PS_INPUT\n"
373     "{\n"
374     "  float4 Position: SV_POSITION;\n"
375     "  float3 Texture: TEXCOORD0;\n"
376     "};\n"
377     "\n"
378     "struct PS_OUTPUT\n"
379     "{\n"
380     "  %s\n"
381     "};\n"
382     "\n"
383     /* rgb <-> yuv function */
384     "%s\n"
385     "PS_OUTPUT main(PS_INPUT input)\n"
386     "{\n"
387     "  PS_OUTPUT output;\n"
388     "%s"
389     "  return output;\n"
390     "}\n";
391 
392 static const gchar templ_vertex_shader[] =
393     "struct VS_INPUT\n"
394     "{\n"
395     "  float4 Position : POSITION;\n"
396     "  float4 Texture : TEXCOORD0;\n"
397     "};\n"
398     "\n"
399     "struct VS_OUTPUT\n"
400     "{\n"
401     "  float4 Position: SV_POSITION;\n"
402     "  float4 Texture: TEXCOORD0;\n"
403     "};\n"
404     "\n"
405     "VS_OUTPUT main(VS_INPUT input)\n"
406     "{\n"
407     "  return input;\n"
408     "}\n";
409 
410 /* *INDENT-ON* */
411 
412 typedef struct
413 {
414   const PixelShaderTemplate *templ;
415   gchar *ps_body[CONVERTER_MAX_QUADS];
416   const gchar *ps_output[CONVERTER_MAX_QUADS];
417   PixelShaderColorTransform transform;
418 } ConvertInfo;
419 
420 struct _GstD3D11Converter
421 {
422   GstD3D11Device *device;
423   GstVideoInfo in_info;
424   GstVideoInfo out_info;
425   gdouble alpha;
426 
427   const GstD3D11Format *in_d3d11_format;
428   const GstD3D11Format *out_d3d11_format;
429 
430   guint num_input_view;
431   guint num_output_view;
432 
433   GstD3D11Quad *quad[CONVERTER_MAX_QUADS];
434 
435   D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES];
436 
437   RECT src_rect;
438   RECT dest_rect;
439   gint input_texture_width;
440   gint input_texture_height;
441   ID3D11Buffer *vertex_buffer;
442   ID3D11Buffer *alpha_const_buffer;
443   gboolean update_vertex;
444   gboolean update_alpha;
445 
446   ID3D11SamplerState *linear_sampler;
447 
448   ConvertInfo convert_info;
449 
450   GstStructure *config;
451 };
452 
453 static gdouble
get_opt_double(GstD3D11Converter * self,const gchar * opt,gdouble def)454 get_opt_double (GstD3D11Converter * self, const gchar * opt, gdouble def)
455 {
456   gdouble res;
457   if (!gst_structure_get_double (self->config, opt, &res))
458     res = def;
459 
460   return res;
461 }
462 
463 #define DEFAULT_OPT_ALPHA_VALUE 1.0
464 
465 #define GET_OPT_ALPHA_VALUE(c) get_opt_double(c, \
466     GST_D3D11_CONVERTER_OPT_ALPHA_VALUE, DEFAULT_OPT_ALPHA_VALUE);
467 
468 /* from video-converter.c */
469 typedef struct
470 {
471   gfloat dm[4][4];
472 } MatrixData;
473 
474 static void
color_matrix_set_identity(MatrixData * m)475 color_matrix_set_identity (MatrixData * m)
476 {
477   gint i, j;
478 
479   for (i = 0; i < 4; i++) {
480     for (j = 0; j < 4; j++) {
481       m->dm[i][j] = (i == j);
482     }
483   }
484 }
485 
486 static void
color_matrix_copy(MatrixData * d,const MatrixData * s)487 color_matrix_copy (MatrixData * d, const MatrixData * s)
488 {
489   gint i, j;
490 
491   for (i = 0; i < 4; i++)
492     for (j = 0; j < 4; j++)
493       d->dm[i][j] = s->dm[i][j];
494 }
495 
496 /* Perform 4x4 matrix multiplication:
497  *  - @dst@ = @a@ * @b@
498  *  - @dst@ may be a pointer to @a@ andor @b@
499  */
500 static void
color_matrix_multiply(MatrixData * dst,MatrixData * a,MatrixData * b)501 color_matrix_multiply (MatrixData * dst, MatrixData * a, MatrixData * b)
502 {
503   MatrixData tmp;
504   gint i, j, k;
505 
506   for (i = 0; i < 4; i++) {
507     for (j = 0; j < 4; j++) {
508       gfloat x = 0;
509       for (k = 0; k < 4; k++) {
510         x += a->dm[i][k] * b->dm[k][j];
511       }
512       tmp.dm[i][j] = x;
513     }
514   }
515   color_matrix_copy (dst, &tmp);
516 }
517 
518 static void
color_matrix_offset_components(MatrixData * m,gfloat a1,gfloat a2,gfloat a3)519 color_matrix_offset_components (MatrixData * m, gfloat a1, gfloat a2, gfloat a3)
520 {
521   MatrixData a;
522 
523   color_matrix_set_identity (&a);
524   a.dm[0][3] = a1;
525   a.dm[1][3] = a2;
526   a.dm[2][3] = a3;
527   color_matrix_multiply (m, &a, m);
528 }
529 
530 static void
color_matrix_scale_components(MatrixData * m,gfloat a1,gfloat a2,gfloat a3)531 color_matrix_scale_components (MatrixData * m, gfloat a1, gfloat a2, gfloat a3)
532 {
533   MatrixData a;
534 
535   color_matrix_set_identity (&a);
536   a.dm[0][0] = a1;
537   a.dm[1][1] = a2;
538   a.dm[2][2] = a3;
539   color_matrix_multiply (m, &a, m);
540 }
541 
542 static void
color_matrix_debug(GstD3D11Converter * self,const MatrixData * s)543 color_matrix_debug (GstD3D11Converter * self, const MatrixData * s)
544 {
545   GST_DEBUG ("[%f %f %f %f]",
546       s->dm[0][0], s->dm[0][1], s->dm[0][2], s->dm[0][3]);
547   GST_DEBUG ("[%f %f %f %f]",
548       s->dm[1][0], s->dm[1][1], s->dm[1][2], s->dm[1][3]);
549   GST_DEBUG ("[%f %f %f %f]",
550       s->dm[2][0], s->dm[2][1], s->dm[2][2], s->dm[2][3]);
551   GST_DEBUG ("[%f %f %f %f]",
552       s->dm[3][0], s->dm[3][1], s->dm[3][2], s->dm[3][3]);
553 }
554 
555 static void
color_matrix_YCbCr_to_RGB(MatrixData * m,gfloat Kr,gfloat Kb)556 color_matrix_YCbCr_to_RGB (MatrixData * m, gfloat Kr, gfloat Kb)
557 {
558   gfloat Kg = 1.0 - Kr - Kb;
559   MatrixData k = {
560     {
561           {1., 0., 2 * (1 - Kr), 0.},
562           {1., -2 * Kb * (1 - Kb) / Kg, -2 * Kr * (1 - Kr) / Kg, 0.},
563           {1., 2 * (1 - Kb), 0., 0.},
564           {0., 0., 0., 1.},
565         }
566   };
567 
568   color_matrix_multiply (m, &k, m);
569 }
570 
571 static void
color_matrix_RGB_to_YCbCr(MatrixData * m,gfloat Kr,gfloat Kb)572 color_matrix_RGB_to_YCbCr (MatrixData * m, gfloat Kr, gfloat Kb)
573 {
574   gfloat Kg = 1.0 - Kr - Kb;
575   MatrixData k;
576   gfloat x;
577 
578   k.dm[0][0] = Kr;
579   k.dm[0][1] = Kg;
580   k.dm[0][2] = Kb;
581   k.dm[0][3] = 0;
582 
583   x = 1 / (2 * (1 - Kb));
584   k.dm[1][0] = -x * Kr;
585   k.dm[1][1] = -x * Kg;
586   k.dm[1][2] = x * (1 - Kb);
587   k.dm[1][3] = 0;
588 
589   x = 1 / (2 * (1 - Kr));
590   k.dm[2][0] = x * (1 - Kr);
591   k.dm[2][1] = -x * Kg;
592   k.dm[2][2] = -x * Kb;
593   k.dm[2][3] = 0;
594 
595   k.dm[3][0] = 0;
596   k.dm[3][1] = 0;
597   k.dm[3][2] = 0;
598   k.dm[3][3] = 1;
599 
600   color_matrix_multiply (m, &k, m);
601 }
602 
603 static void
compute_matrix_to_RGB(GstD3D11Converter * self,MatrixData * data,GstVideoInfo * info)604 compute_matrix_to_RGB (GstD3D11Converter * self, MatrixData * data,
605     GstVideoInfo * info)
606 {
607   gdouble Kr = 0, Kb = 0;
608   gint offset[4], scale[4];
609 
610   /* bring color components to [0..1.0] range */
611   gst_video_color_range_offsets (info->colorimetry.range, info->finfo, offset,
612       scale);
613 
614   color_matrix_offset_components (data, -offset[0], -offset[1], -offset[2]);
615   color_matrix_scale_components (data, 1 / ((float) scale[0]),
616       1 / ((float) scale[1]), 1 / ((float) scale[2]));
617 
618   if (!GST_VIDEO_INFO_IS_RGB (info)) {
619     /* bring components to R'G'B' space */
620     if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
621       color_matrix_YCbCr_to_RGB (data, Kr, Kb);
622   }
623   color_matrix_debug (self, data);
624 }
625 
626 static void
compute_matrix_to_YUV(GstD3D11Converter * self,MatrixData * data,GstVideoInfo * info)627 compute_matrix_to_YUV (GstD3D11Converter * self, MatrixData * data,
628     GstVideoInfo * info)
629 {
630   gdouble Kr = 0, Kb = 0;
631   gint offset[4], scale[4];
632 
633   if (!GST_VIDEO_INFO_IS_RGB (info)) {
634     /* bring components to YCbCr space */
635     if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
636       color_matrix_RGB_to_YCbCr (data, Kr, Kb);
637   }
638 
639   /* bring color components to nominal range */
640   gst_video_color_range_offsets (info->colorimetry.range, info->finfo, offset,
641       scale);
642 
643   color_matrix_scale_components (data, (float) scale[0], (float) scale[1],
644       (float) scale[2]);
645   color_matrix_offset_components (data, offset[0], offset[1], offset[2]);
646 
647   color_matrix_debug (self, data);
648 }
649 
650 static gboolean
converter_get_matrix(GstD3D11Converter * self,MatrixData * matrix,GstVideoInfo * in_info,GstVideoInfo * out_info)651 converter_get_matrix (GstD3D11Converter * self, MatrixData * matrix,
652     GstVideoInfo * in_info, GstVideoInfo * out_info)
653 {
654   gboolean same_matrix;
655   guint in_bits, out_bits;
656 
657   in_bits = GST_VIDEO_INFO_COMP_DEPTH (in_info, 0);
658   out_bits = GST_VIDEO_INFO_COMP_DEPTH (out_info, 0);
659 
660   same_matrix = in_info->colorimetry.matrix == out_info->colorimetry.matrix;
661 
662   GST_DEBUG ("matrix %d -> %d (%d)", in_info->colorimetry.matrix,
663       out_info->colorimetry.matrix, same_matrix);
664 
665   color_matrix_set_identity (matrix);
666 
667   if (same_matrix) {
668     GST_DEBUG ("conversion matrix is not required");
669     return FALSE;
670   }
671 
672   if (in_bits < out_bits) {
673     gint scale = 1 << (out_bits - in_bits);
674     color_matrix_scale_components (matrix,
675         1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
676   }
677 
678   GST_DEBUG ("to RGB matrix");
679   compute_matrix_to_RGB (self, matrix, in_info);
680   GST_DEBUG ("current matrix");
681   color_matrix_debug (self, matrix);
682 
683   GST_DEBUG ("to YUV matrix");
684   compute_matrix_to_YUV (self, matrix, out_info);
685   GST_DEBUG ("current matrix");
686   color_matrix_debug (self, matrix);
687 
688   if (in_bits > out_bits) {
689     gint scale = 1 << (in_bits - out_bits);
690     color_matrix_scale_components (matrix,
691         (float) scale, (float) scale, (float) scale);
692   }
693 
694   GST_DEBUG ("final matrix");
695   color_matrix_debug (self, matrix);
696 
697   return TRUE;
698 }
699 
700 static gboolean
setup_convert_info_rgb_to_rgb(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)701 setup_convert_info_rgb_to_rgb (GstD3D11Converter * self,
702     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
703 {
704   ConvertInfo *convert_info = &self->convert_info;
705 
706   convert_info->templ = &templ_REORDER;
707   convert_info->ps_body[0] = g_strdup_printf (templ_REORDER_BODY);
708   convert_info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
709 
710   return TRUE;
711 }
712 
713 static gboolean
get_packed_yuv_components(GstD3D11Converter * self,GstVideoFormat format,gchar * y,gchar * u,gchar * v)714 get_packed_yuv_components (GstD3D11Converter * self, GstVideoFormat
715     format, gchar * y, gchar * u, gchar * v)
716 {
717   switch (format) {
718     case GST_VIDEO_FORMAT_YUY2:
719     {
720       const GstD3D11Format *d3d11_format =
721           gst_d3d11_device_format_from_gst (self->device,
722           GST_VIDEO_FORMAT_YUY2);
723 
724       g_assert (d3d11_format != NULL);
725 
726       if (d3d11_format->resource_format[0] == DXGI_FORMAT_R8G8B8A8_UNORM) {
727         *y = 'x';
728         *u = 'y';
729         *v = 'a';
730       } else if (d3d11_format->resource_format[0] ==
731           DXGI_FORMAT_G8R8_G8B8_UNORM) {
732         *y = 'y';
733         *u = 'x';
734         *v = 'z';
735       } else {
736         g_assert_not_reached ();
737         return FALSE;
738       }
739       break;
740     }
741     case GST_VIDEO_FORMAT_UYVY:
742       *y = 'y';
743       *u = 'x';
744       *v = 'z';
745       break;
746     case GST_VIDEO_FORMAT_VYUY:
747       *y = 'y';
748       *u = 'z';
749       *v = 'x';
750       break;
751     case GST_VIDEO_FORMAT_Y210:
752       *y = 'r';
753       *u = 'g';
754       *v = 'a';
755       break;
756     case GST_VIDEO_FORMAT_Y410:
757       *y = 'g';
758       *u = 'r';
759       *v = 'b';
760       break;
761     default:
762       g_assert_not_reached ();
763       return FALSE;
764   }
765 
766   return TRUE;
767 }
768 
769 static void
get_planar_component(const GstVideoInfo * info,gchar * u,gchar * v,guint * scale)770 get_planar_component (const GstVideoInfo * info, gchar * u, gchar * v,
771     guint * scale)
772 {
773   switch (GST_VIDEO_INFO_FORMAT (info)) {
774     case GST_VIDEO_FORMAT_I420_10LE:
775     case GST_VIDEO_FORMAT_I422_10LE:
776     case GST_VIDEO_FORMAT_Y444_10LE:
777       *scale = (1 << 6);
778       break;
779     case GST_VIDEO_FORMAT_I420_12LE:
780     case GST_VIDEO_FORMAT_I422_12LE:
781     case GST_VIDEO_FORMAT_Y444_12LE:
782       *scale = (1 << 4);
783       break;
784     default:
785       *scale = 1;
786       break;
787   }
788 
789   if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_YV12) {
790     *u = 'z';
791     *v = 'y';
792   } else {
793     *u = 'y';
794     *v = 'z';
795   }
796 }
797 
798 static void
get_semi_planar_component(const GstVideoInfo * info,gchar * u,gchar * v)799 get_semi_planar_component (const GstVideoInfo * info, gchar * u, gchar * v)
800 {
801   if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_NV21) {
802     *u = 'y';
803     *v = 'x';
804   } else {
805     *u = 'x';
806     *v = 'y';
807   }
808 }
809 
810 static gboolean
setup_convert_info_yuv_to_rgb(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)811 setup_convert_info_yuv_to_rgb (GstD3D11Converter * self,
812     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
813 {
814   ConvertInfo *info = &self->convert_info;
815 
816   info->templ = &templ_YUV_to_RGB;
817   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
818 
819   switch (GST_VIDEO_INFO_FORMAT (in_info)) {
820     case GST_VIDEO_FORMAT_VUYA:
821       info->ps_body[0] = g_strdup_printf (templ_VUYA_to_RGB_BODY);
822       break;
823     case GST_VIDEO_FORMAT_YUY2:
824     case GST_VIDEO_FORMAT_UYVY:
825     case GST_VIDEO_FORMAT_VYUY:
826     case GST_VIDEO_FORMAT_Y210:
827     case GST_VIDEO_FORMAT_Y410:
828     {
829       gchar y, u, v;
830       if (!get_packed_yuv_components (self, GST_VIDEO_INFO_FORMAT (in_info),
831               &y, &u, &v)) {
832         return FALSE;
833       }
834 
835       info->ps_body[0] =
836           g_strdup_printf (templ_PACKED_YUV_to_RGB_BODY, y, u, v);
837       break;
838     }
839     case GST_VIDEO_FORMAT_I420:
840     case GST_VIDEO_FORMAT_YV12:
841     case GST_VIDEO_FORMAT_I420_10LE:
842     case GST_VIDEO_FORMAT_I420_12LE:
843     case GST_VIDEO_FORMAT_Y42B:
844     case GST_VIDEO_FORMAT_I422_10LE:
845     case GST_VIDEO_FORMAT_I422_12LE:
846     case GST_VIDEO_FORMAT_Y444:
847     case GST_VIDEO_FORMAT_Y444_10LE:
848     case GST_VIDEO_FORMAT_Y444_12LE:
849     case GST_VIDEO_FORMAT_Y444_16LE:
850     {
851       guint mul;
852       gchar u, v;
853 
854       get_planar_component (in_info, &u, &v, &mul);
855 
856       info->ps_body[0] =
857           g_strdup_printf (templ_PLANAR_YUV_to_RGB_BODY, mul, u, mul, v, mul);
858       break;
859     }
860     case GST_VIDEO_FORMAT_NV12:
861     case GST_VIDEO_FORMAT_NV21:
862     case GST_VIDEO_FORMAT_P010_10LE:
863     case GST_VIDEO_FORMAT_P012_LE:
864     case GST_VIDEO_FORMAT_P016_LE:
865     {
866       gchar u, v;
867 
868       get_semi_planar_component (in_info, &u, &v);
869 
870       info->ps_body[0] = g_strdup_printf (templ_SEMI_PLANAR_to_RGB_BODY, u, v);
871       break;
872     }
873     default:
874       GST_ERROR ("Unhandled input format %s",
875           gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
876       return FALSE;
877   }
878 
879   return TRUE;
880 }
881 
882 static gboolean
setup_convert_info_rgb_to_yuv(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)883 setup_convert_info_rgb_to_yuv (GstD3D11Converter * self,
884     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
885 {
886   ConvertInfo *info = &self->convert_info;
887 
888   info->templ = &templ_RGB_to_YUV;
889   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
890 
891   switch (GST_VIDEO_INFO_FORMAT (out_info)) {
892     case GST_VIDEO_FORMAT_VUYA:
893       info->ps_body[0] = g_strdup_printf (templ_RGB_to_VUYA_BODY);
894       break;
895     case GST_VIDEO_FORMAT_NV12:
896     case GST_VIDEO_FORMAT_NV21:
897     case GST_VIDEO_FORMAT_P010_10LE:
898     case GST_VIDEO_FORMAT_P012_LE:
899     case GST_VIDEO_FORMAT_P016_LE:
900     {
901       gchar u, v;
902 
903       get_semi_planar_component (out_info, &u, &v);
904 
905       info->ps_body[0] = g_strdup_printf (templ_RGB_to_LUMA_BODY, 1);
906       info->ps_body[1] = g_strdup_printf (templ_RGB_to_SEMI_PLANAR_CHROMA_BODY,
907           u, v);
908       info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
909       break;
910     }
911     case GST_VIDEO_FORMAT_I420:
912     case GST_VIDEO_FORMAT_YV12:
913     case GST_VIDEO_FORMAT_I420_10LE:
914     case GST_VIDEO_FORMAT_I420_12LE:
915     case GST_VIDEO_FORMAT_Y42B:
916     case GST_VIDEO_FORMAT_I422_10LE:
917     case GST_VIDEO_FORMAT_I422_12LE:
918     case GST_VIDEO_FORMAT_Y444:
919     case GST_VIDEO_FORMAT_Y444_10LE:
920     case GST_VIDEO_FORMAT_Y444_12LE:
921     case GST_VIDEO_FORMAT_Y444_16LE:
922     {
923       guint div;
924       gchar u, v;
925 
926       get_planar_component (out_info, &u, &v, &div);
927 
928       info->ps_body[0] = g_strdup_printf (templ_RGB_to_LUMA_BODY, div);
929       info->ps_body[1] =
930           g_strdup_printf (templ_RGB_to_PLANAR_CHROMA_BODY, u, div, v, div);
931       info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
932       break;
933     }
934     default:
935       GST_ERROR ("Unhandled output format %s",
936           gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
937       return FALSE;
938   }
939 
940   return TRUE;
941 }
942 
943 static gboolean
setup_convert_info_planar_to_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)944 setup_convert_info_planar_to_planar (GstD3D11Converter * self,
945     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
946 {
947   ConvertInfo *info = &self->convert_info;
948   guint in_scale, out_scale;
949   gchar in_u, in_v, out_u, out_v;
950 
951   info->templ = &templ_REORDER;
952   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
953   info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
954 
955   get_planar_component (in_info, &in_u, &in_v, &in_scale);
956   get_planar_component (out_info, &out_u, &out_v, &out_scale);
957 
958   info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY,
959       in_scale, out_scale);
960   info->ps_body[1] =
961       g_strdup_printf (templ_PLANAR_TO_PLANAR_CHROMA_BODY,
962       in_u, in_scale, in_v, in_scale, out_u, out_scale, out_v, out_scale);
963 
964   return TRUE;
965 }
966 
967 static gboolean
setup_convert_info_planar_to_semi_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)968 setup_convert_info_planar_to_semi_planar (GstD3D11Converter * self,
969     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
970 {
971   ConvertInfo *info = &self->convert_info;
972   guint in_scale;
973   gchar in_u, in_v, out_u, out_v;
974 
975   info->templ = &templ_REORDER;
976   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
977   info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
978 
979   get_planar_component (in_info, &in_u, &in_v, &in_scale);
980   get_semi_planar_component (out_info, &out_u, &out_v);
981 
982   info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, in_scale, 1);
983   info->ps_body[1] =
984       g_strdup_printf (templ_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY,
985       in_u, in_scale, in_v, in_scale, out_u, out_v);
986 
987   return TRUE;
988 }
989 
990 static gboolean
setup_convert_info_semi_planar_to_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)991 setup_convert_info_semi_planar_to_planar (GstD3D11Converter * self,
992     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
993 {
994   ConvertInfo *info = &self->convert_info;
995   gchar in_u, in_v, out_u, out_v;
996   guint div = 1;
997 
998   info->templ = &templ_REORDER;
999   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1000   info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
1001 
1002   get_semi_planar_component (in_info, &in_u, &in_v);
1003   get_planar_component (out_info, &out_u, &out_v, &div);
1004 
1005   info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, 1, div);
1006   info->ps_body[1] =
1007       g_strdup_printf (templ_SEMI_PLANAR_TO_PLANAR_CHROMA_BODY,
1008       in_u, in_v, out_u, div, out_v, div);
1009 
1010   return TRUE;
1011 }
1012 
1013 static gboolean
setup_convert_info_semi_planar_to_semi_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1014 setup_convert_info_semi_planar_to_semi_planar (GstD3D11Converter * self,
1015     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1016 {
1017   ConvertInfo *info = &self->convert_info;
1018   gchar in_u, in_v, out_u, out_v;
1019 
1020   info->templ = &templ_REORDER;
1021   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1022   info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1023 
1024   get_semi_planar_component (in_info, &in_u, &in_v);
1025   get_semi_planar_component (out_info, &out_u, &out_v);
1026 
1027   info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, 1, 1);
1028   info->ps_body[1] =
1029       g_strdup_printf (templ_SEMI_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY,
1030       in_u, in_v, out_u, out_v);
1031 
1032   return TRUE;
1033 }
1034 
1035 static gboolean
setup_convert_info_vuya_to_vuya(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1036 setup_convert_info_vuya_to_vuya (GstD3D11Converter * self,
1037     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1038 {
1039   ConvertInfo *info = &self->convert_info;
1040 
1041   info->templ = &templ_REORDER;
1042   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1043 
1044   info->ps_body[0] = g_strdup_printf (templ_REORDER_BODY);
1045 
1046   return TRUE;
1047 }
1048 
1049 static gboolean
setup_convert_info_vuya_to_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1050 setup_convert_info_vuya_to_planar (GstD3D11Converter * self,
1051     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1052 {
1053   ConvertInfo *info = &self->convert_info;
1054   guint div;
1055   gchar u, v;
1056 
1057   info->templ = &templ_REORDER;
1058   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1059   info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
1060 
1061   get_planar_component (out_info, &u, &v, &div);
1062 
1063   info->ps_body[0] = g_strdup_printf (templ_VUYA_to_LUMA_BODY, div);
1064   info->ps_body[1] =
1065       g_strdup_printf (templ_VUYA_TO_PLANAR_CHROMA_BODY, u, div, v, div);
1066 
1067   return TRUE;
1068 }
1069 
1070 static gboolean
setup_convert_info_vuya_to_semi_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1071 setup_convert_info_vuya_to_semi_planar (GstD3D11Converter * self,
1072     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1073 {
1074   ConvertInfo *info = &self->convert_info;
1075   guint div = 1;
1076   gchar u, v;
1077 
1078   info->templ = &templ_REORDER;
1079   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1080   info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1081 
1082   get_semi_planar_component (out_info, &u, &v);
1083 
1084   info->ps_body[0] = g_strdup_printf (templ_VUYA_to_LUMA_BODY, div);
1085   info->ps_body[1] =
1086       g_strdup_printf (templ_VUYA_TO_SEMI_PLANAR_CHROMA_BODY, v, u);
1087 
1088   return TRUE;
1089 }
1090 
1091 static gboolean
setup_convert_info_planar_to_vuya(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1092 setup_convert_info_planar_to_vuya (GstD3D11Converter * self,
1093     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1094 {
1095   ConvertInfo *info = &self->convert_info;
1096   guint mul;
1097   gchar u, v;
1098 
1099   get_planar_component (in_info, &u, &v, &mul);
1100 
1101   info->templ = &templ_REORDER;
1102   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1103 
1104   info->ps_body[0] =
1105       g_strdup_printf (templ_PLANAR_to_VUYA_BODY, mul, u, mul, v, mul);
1106 
1107   return TRUE;
1108 }
1109 
1110 static gboolean
setup_convert_info_packed_yuv_to_vuya(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1111 setup_convert_info_packed_yuv_to_vuya (GstD3D11Converter * self,
1112     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1113 {
1114   ConvertInfo *info = &self->convert_info;
1115   gchar y, u, v;
1116 
1117   info->templ = &templ_REORDER;
1118   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1119 
1120   if (!get_packed_yuv_components (self, GST_VIDEO_INFO_FORMAT (in_info),
1121           &y, &u, &v)) {
1122     return FALSE;
1123   }
1124 
1125   info->ps_body[0] = g_strdup_printf (templ_PACKED_YUV_to_VUYA_BODY, y, u, v);
1126 
1127   return TRUE;
1128 }
1129 
1130 static gboolean
setup_convert_info_semi_planar_to_vuya(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1131 setup_convert_info_semi_planar_to_vuya (GstD3D11Converter * self,
1132     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1133 {
1134   ConvertInfo *info = &self->convert_info;
1135   gchar u, v;
1136 
1137   get_semi_planar_component (in_info, &u, &v);
1138 
1139   info->templ = &templ_REORDER;
1140   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1141 
1142   info->ps_body[0] = g_strdup_printf (templ_SEMI_PLANAR_to_VUYA_BODY, v, u);
1143 
1144   return TRUE;
1145 }
1146 
1147 static gboolean
setup_convert_info_packed_yuv_to_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1148 setup_convert_info_packed_yuv_to_planar (GstD3D11Converter * self,
1149     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1150 {
1151   ConvertInfo *info = &self->convert_info;
1152   gchar in_y, in_u, in_v;
1153   gchar out_u, out_v;
1154   guint out_scale;
1155 
1156   info->templ = &templ_REORDER;
1157   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1158   info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
1159 
1160   if (!get_packed_yuv_components (self, GST_VIDEO_INFO_FORMAT (in_info),
1161           &in_y, &in_u, &in_v)) {
1162     return FALSE;
1163   }
1164 
1165   get_planar_component (out_info, &out_u, &out_v, &out_scale);
1166 
1167   info->ps_body[0] =
1168       g_strdup_printf (templ_PACKED_YUV_to_LUMA_BODY, in_y, out_scale);
1169   info->ps_body[1] =
1170       g_strdup_printf (templ_PACKED_YUV_TO_PLANAR_CHROMA_BODY, in_u, in_v,
1171       out_u, out_scale, out_v, out_scale);
1172 
1173   return TRUE;
1174 }
1175 
1176 static gboolean
setup_convert_info_packed_yuv_to_semi_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1177 setup_convert_info_packed_yuv_to_semi_planar (GstD3D11Converter * self,
1178     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1179 {
1180   ConvertInfo *info = &self->convert_info;
1181   gchar in_y, in_u, in_v;
1182   gchar out_u, out_v;
1183 
1184   info->templ = &templ_REORDER;
1185   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1186   info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1187 
1188   if (!get_packed_yuv_components (self, GST_VIDEO_INFO_FORMAT (in_info),
1189           &in_y, &in_u, &in_v)) {
1190     return FALSE;
1191   }
1192 
1193   get_semi_planar_component (out_info, &out_u, &out_v);
1194 
1195   info->ps_body[0] = g_strdup_printf (templ_PACKED_YUV_to_LUMA_BODY, in_y, 1);
1196   info->ps_body[1] =
1197       g_strdup_printf (templ_PACKED_YUV_TO_SEMI_PLANAR_CHROMA_BODY,
1198       in_u, in_v, out_u, out_v);
1199 
1200   return TRUE;
1201 }
1202 
1203 static gboolean
is_planar_format(const GstVideoInfo * info)1204 is_planar_format (const GstVideoInfo * info)
1205 {
1206   switch (GST_VIDEO_INFO_FORMAT (info)) {
1207     case GST_VIDEO_FORMAT_I420:
1208     case GST_VIDEO_FORMAT_YV12:
1209     case GST_VIDEO_FORMAT_I420_10LE:
1210     case GST_VIDEO_FORMAT_I420_12LE:
1211     case GST_VIDEO_FORMAT_Y42B:
1212     case GST_VIDEO_FORMAT_I422_10LE:
1213     case GST_VIDEO_FORMAT_I422_12LE:
1214     case GST_VIDEO_FORMAT_Y444:
1215     case GST_VIDEO_FORMAT_Y444_10LE:
1216     case GST_VIDEO_FORMAT_Y444_12LE:
1217     case GST_VIDEO_FORMAT_Y444_16LE:
1218       return TRUE;
1219     default:
1220       break;
1221   }
1222 
1223   return FALSE;
1224 }
1225 
1226 static gboolean
setup_convert_info_yuv_to_yuv(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1227 setup_convert_info_yuv_to_yuv (GstD3D11Converter * self,
1228     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1229 {
1230   gboolean in_planar, out_planar;
1231   gboolean in_vuya, out_vuya;
1232   gboolean in_packed;
1233 
1234   in_vuya = GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_VUYA;
1235   out_vuya = GST_VIDEO_INFO_FORMAT (out_info) == GST_VIDEO_FORMAT_VUYA;
1236   in_planar = is_planar_format (in_info);
1237   in_packed = (GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_YUY2 ||
1238       GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_UYVY ||
1239       GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_VYUY ||
1240       GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_Y210 ||
1241       GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_Y410);
1242   out_planar = is_planar_format (out_info);
1243 
1244   /* From/to VUYA */
1245   if (in_vuya && out_vuya) {
1246     return setup_convert_info_vuya_to_vuya (self, in_info, out_info);
1247   } else if (in_vuya) {
1248     if (out_planar)
1249       return setup_convert_info_vuya_to_planar (self, in_info, out_info);
1250     else
1251       return setup_convert_info_vuya_to_semi_planar (self, in_info, out_info);
1252   } else if (out_vuya) {
1253     if (in_planar)
1254       return setup_convert_info_planar_to_vuya (self, in_info, out_info);
1255     else if (in_packed)
1256       return setup_convert_info_packed_yuv_to_vuya (self, in_info, out_info);
1257     else
1258       return setup_convert_info_semi_planar_to_vuya (self, in_info, out_info);
1259   }
1260 
1261   if (in_planar) {
1262     if (out_planar)
1263       return setup_convert_info_planar_to_planar (self, in_info, out_info);
1264     else
1265       return setup_convert_info_planar_to_semi_planar (self, in_info, out_info);
1266   } else if (in_packed) {
1267     if (out_planar)
1268       return setup_convert_info_packed_yuv_to_planar (self, in_info, out_info);
1269     else
1270       return setup_convert_info_packed_yuv_to_semi_planar (self, in_info,
1271           out_info);
1272   } else {
1273     if (out_planar)
1274       return setup_convert_info_semi_planar_to_planar (self, in_info, out_info);
1275     else
1276       return setup_convert_info_semi_planar_to_semi_planar (self, in_info,
1277           out_info);
1278   }
1279 
1280   return FALSE;
1281 }
1282 
1283 static gboolean
setup_convert_info_rgb_to_gray(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1284 setup_convert_info_rgb_to_gray (GstD3D11Converter * self,
1285     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1286 {
1287   ConvertInfo *info = &self->convert_info;
1288 
1289   info->templ = &templ_RGB_to_YUV;
1290   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1291 
1292   switch (GST_VIDEO_INFO_FORMAT (out_info)) {
1293     case GST_VIDEO_FORMAT_GRAY8:
1294     case GST_VIDEO_FORMAT_GRAY16_LE:
1295       info->ps_body[0] = g_strdup_printf (templ_RGB_to_GRAY_BODY);
1296       break;
1297     default:
1298       GST_ERROR ("Unhandled output format %s",
1299           gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
1300       return FALSE;
1301   }
1302 
1303   return TRUE;
1304 }
1305 
1306 static gboolean
setup_convert_info_yuv_to_gray(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1307 setup_convert_info_yuv_to_gray (GstD3D11Converter * self,
1308     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1309 {
1310   ConvertInfo *info = &self->convert_info;
1311 
1312   info->templ = &templ_REORDER_NO_ALPHA;
1313   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1314 
1315   if (GST_VIDEO_INFO_FORMAT (out_info) != GST_VIDEO_FORMAT_GRAY8 &&
1316       GST_VIDEO_INFO_FORMAT (out_info) != GST_VIDEO_FORMAT_GRAY16_LE)
1317     return FALSE;
1318 
1319   switch (GST_VIDEO_INFO_FORMAT (in_info)) {
1320     case GST_VIDEO_FORMAT_VUYA:
1321       info->ps_body[0] = g_strdup_printf (templ_VUYA_to_GRAY_BODY);
1322       break;
1323     case GST_VIDEO_FORMAT_I420:
1324     case GST_VIDEO_FORMAT_YV12:
1325     case GST_VIDEO_FORMAT_I420_10LE:
1326     case GST_VIDEO_FORMAT_I420_12LE:
1327     case GST_VIDEO_FORMAT_Y42B:
1328     case GST_VIDEO_FORMAT_I422_10LE:
1329     case GST_VIDEO_FORMAT_I422_12LE:
1330     case GST_VIDEO_FORMAT_Y444:
1331     case GST_VIDEO_FORMAT_Y444_10LE:
1332     case GST_VIDEO_FORMAT_Y444_12LE:
1333     case GST_VIDEO_FORMAT_Y444_16LE:
1334     case GST_VIDEO_FORMAT_NV12:
1335     case GST_VIDEO_FORMAT_NV21:
1336     case GST_VIDEO_FORMAT_P010_10LE:
1337     case GST_VIDEO_FORMAT_P012_LE:
1338     case GST_VIDEO_FORMAT_P016_LE:
1339     {
1340       gchar u, v;
1341       guint scale;
1342 
1343       get_planar_component (in_info, &u, &v, &scale);
1344 
1345       info->ps_body[0] = g_strdup_printf (templ_YUV_to_GRAY_BODY, scale);
1346       break;
1347     }
1348     case GST_VIDEO_FORMAT_Y410:
1349     {
1350       gchar y, u, v;
1351       get_packed_yuv_components (self, GST_VIDEO_FORMAT_Y410, &y, &u, &v);
1352 
1353       info->ps_body[0] = g_strdup_printf (templ_PACKED_YUV_TO_GRAY, y);
1354       break;
1355     }
1356     default:
1357       GST_ERROR ("Unhandled input format %s",
1358           gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
1359       return FALSE;
1360   }
1361 
1362   return TRUE;
1363 }
1364 
1365 static gboolean
setup_convert_info_gray_to_gray(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1366 setup_convert_info_gray_to_gray (GstD3D11Converter * self,
1367     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1368 {
1369   ConvertInfo *info = &self->convert_info;
1370 
1371   info->templ = &templ_REORDER_NO_ALPHA;
1372   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1373 
1374   if (GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY8 &&
1375       GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY16_LE)
1376     return FALSE;
1377 
1378   if (GST_VIDEO_INFO_FORMAT (out_info) != GST_VIDEO_FORMAT_GRAY8 &&
1379       GST_VIDEO_INFO_FORMAT (out_info) != GST_VIDEO_FORMAT_GRAY16_LE)
1380     return FALSE;
1381 
1382   info->ps_body[0] = g_strdup_printf (templ_GRAY_to_GRAY_BODY);
1383 
1384   return TRUE;
1385 }
1386 
1387 static gboolean
setup_convert_info_gray_to_rgb(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1388 setup_convert_info_gray_to_rgb (GstD3D11Converter * self,
1389     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1390 {
1391   ConvertInfo *info = &self->convert_info;
1392 
1393   info->templ = &templ_REORDER_NO_ALPHA;
1394   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1395 
1396   if (GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY8 &&
1397       GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY16_LE)
1398     return FALSE;
1399 
1400   info->ps_body[0] = g_strdup_printf (templ_GRAY_to_RGB_BODY);
1401 
1402   return TRUE;
1403 }
1404 
1405 static gboolean
setup_convert_info_gray_to_yuv(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1406 setup_convert_info_gray_to_yuv (GstD3D11Converter * self,
1407     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1408 {
1409   ConvertInfo *info = &self->convert_info;
1410 
1411   info->templ = &templ_REORDER_NO_ALPHA;
1412   info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1413 
1414   if (GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY8 &&
1415       GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY16_LE)
1416     return FALSE;
1417 
1418   switch (GST_VIDEO_INFO_FORMAT (out_info)) {
1419     case GST_VIDEO_FORMAT_VUYA:
1420       info->ps_body[0] = g_strdup_printf (templ_GRAY_to_VUYA_BODY);
1421       break;
1422     case GST_VIDEO_FORMAT_I420:
1423     case GST_VIDEO_FORMAT_YV12:
1424     case GST_VIDEO_FORMAT_I420_10LE:
1425     case GST_VIDEO_FORMAT_I420_12LE:
1426     case GST_VIDEO_FORMAT_Y42B:
1427     case GST_VIDEO_FORMAT_I422_10LE:
1428     case GST_VIDEO_FORMAT_I422_12LE:
1429     case GST_VIDEO_FORMAT_Y444:
1430     case GST_VIDEO_FORMAT_Y444_10LE:
1431     case GST_VIDEO_FORMAT_Y444_12LE:
1432     case GST_VIDEO_FORMAT_Y444_16LE:
1433     {
1434       gchar u, v;
1435       guint div;
1436 
1437       get_planar_component (out_info, &u, &v, &div);
1438       info->ps_body[0] = g_strdup_printf (templ_GRAY_to_LUMA_BODY, div);
1439       info->ps_body[1] =
1440           g_strdup_printf (templ_GRAY_to_PLANAR_CHROMA_BODY, div);
1441       info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
1442       break;
1443     }
1444     case GST_VIDEO_FORMAT_NV12:
1445     case GST_VIDEO_FORMAT_NV21:
1446     case GST_VIDEO_FORMAT_P010_10LE:
1447     case GST_VIDEO_FORMAT_P012_LE:
1448     case GST_VIDEO_FORMAT_P016_LE:
1449       info->ps_body[0] = g_strdup_printf (templ_GRAY_to_LUMA_BODY, 1);
1450       info->ps_body[1] =
1451           g_strdup_printf (templ_GRAY_to_SEMI_PLANAR_CHROMA_BODY);
1452       info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1453       break;
1454     default:
1455       GST_ERROR ("Unhandled output format %s",
1456           gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
1457       return FALSE;
1458   }
1459 
1460   return TRUE;
1461 }
1462 
1463 static gboolean
gst_d3d11_color_convert_setup_shader(GstD3D11Converter * self,GstD3D11Device * device,GstVideoInfo * in_info,GstVideoInfo * out_info)1464 gst_d3d11_color_convert_setup_shader (GstD3D11Converter * self,
1465     GstD3D11Device * device, GstVideoInfo * in_info, GstVideoInfo * out_info)
1466 {
1467   HRESULT hr;
1468   D3D11_SAMPLER_DESC sampler_desc;
1469   D3D11_INPUT_ELEMENT_DESC input_desc[2];
1470   D3D11_BUFFER_DESC buffer_desc;
1471   D3D11_MAPPED_SUBRESOURCE map;
1472   VertexData *vertex_data;
1473   WORD *indices;
1474   ID3D11Device *device_handle;
1475   ID3D11DeviceContext *context_handle;
1476   ConvertInfo *convert_info = &self->convert_info;
1477   /* *INDENT-OFF* */
1478   ComPtr<ID3D11PixelShader> ps[CONVERTER_MAX_QUADS];
1479   ComPtr<ID3D11VertexShader> vs;
1480   ComPtr<ID3D11InputLayout> layout;
1481   ComPtr<ID3D11SamplerState> linear_sampler;
1482   ComPtr<ID3D11Buffer> transform_const_buffer;
1483   ComPtr<ID3D11Buffer> alpha_const_buffer;
1484   ComPtr<ID3D11Buffer> vertex_buffer;
1485   ComPtr<ID3D11Buffer> index_buffer;
1486   /* *INDENT-ON* */
1487   const guint index_count = 2 * 3;
1488   gint i;
1489   gboolean ret;
1490   ID3D11Buffer *const_buffers[2] = { nullptr, nullptr };
1491   guint num_const_buffers = 0;
1492 
1493   memset (&sampler_desc, 0, sizeof (sampler_desc));
1494   memset (input_desc, 0, sizeof (input_desc));
1495   memset (&buffer_desc, 0, sizeof (buffer_desc));
1496 
1497   device_handle = gst_d3d11_device_get_device_handle (device);
1498   context_handle = gst_d3d11_device_get_device_context_handle (device);
1499 
1500   /* bilinear filtering */
1501   sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
1502   sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
1503   sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
1504   sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
1505   sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
1506   sampler_desc.MinLOD = 0;
1507   sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
1508 
1509   hr = device_handle->CreateSamplerState (&sampler_desc, &linear_sampler);
1510   if (!gst_d3d11_result (hr, device)) {
1511     GST_ERROR ("Couldn't create sampler state, hr: 0x%x", (guint) hr);
1512     return FALSE;
1513   }
1514 
1515   for (i = 0; i < CONVERTER_MAX_QUADS; i++) {
1516     gchar *shader_code = NULL;
1517 
1518     if (convert_info->ps_body[i]) {
1519       gchar *transform_const_buffer = nullptr;
1520       gchar *alpha_const_buffer = nullptr;
1521       guint register_idx = 0;
1522 
1523       g_assert (convert_info->ps_output[i] != NULL);
1524 
1525       if (convert_info->templ->has_transform) {
1526         transform_const_buffer =
1527             g_strdup_printf (templ_color_transform_const_buffer, register_idx);
1528         register_idx++;
1529       }
1530 
1531       if (convert_info->templ->has_alpha) {
1532         alpha_const_buffer =
1533             g_strdup_printf (templ_alpha_const_buffer, register_idx);
1534         register_idx++;
1535       }
1536 
1537       shader_code = g_strdup_printf (templ_pixel_shader,
1538           transform_const_buffer ? transform_const_buffer : "",
1539           alpha_const_buffer ? alpha_const_buffer : "",
1540           convert_info->ps_output[i],
1541           convert_info->templ->func ? convert_info->templ->func : "",
1542           convert_info->ps_body[i]);
1543       g_free (transform_const_buffer);
1544       g_free (alpha_const_buffer);
1545 
1546       ret = gst_d3d11_create_pixel_shader (device, shader_code, &ps[i]);
1547       g_free (shader_code);
1548       if (!ret) {
1549         return FALSE;
1550       }
1551     }
1552   }
1553 
1554   if (convert_info->templ->has_transform) {
1555     D3D11_BUFFER_DESC const_buffer_desc = { 0, };
1556 
1557     G_STATIC_ASSERT (sizeof (PixelShaderColorTransform) % 16 == 0);
1558 
1559     const_buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1560     const_buffer_desc.ByteWidth = sizeof (PixelShaderColorTransform);
1561     const_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
1562     const_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1563     const_buffer_desc.MiscFlags = 0;
1564     const_buffer_desc.StructureByteStride = 0;
1565 
1566     hr = device_handle->CreateBuffer (&const_buffer_desc, nullptr,
1567         &transform_const_buffer);
1568     if (!gst_d3d11_result (hr, device)) {
1569       GST_ERROR ("Couldn't create constant buffer, hr: 0x%x", (guint) hr);
1570       return FALSE;
1571     }
1572 
1573     gst_d3d11_device_lock (device);
1574     hr = context_handle->Map (transform_const_buffer.Get (),
1575         0, D3D11_MAP_WRITE_DISCARD, 0, &map);
1576 
1577     if (!gst_d3d11_result (hr, device)) {
1578       GST_ERROR ("Couldn't map constant buffer, hr: 0x%x", (guint) hr);
1579       gst_d3d11_device_unlock (device);
1580       return FALSE;
1581     }
1582 
1583     memcpy (map.pData, &convert_info->transform,
1584         sizeof (PixelShaderColorTransform));
1585 
1586     context_handle->Unmap (transform_const_buffer.Get (), 0);
1587     gst_d3d11_device_unlock (device);
1588 
1589     const_buffers[num_const_buffers] = transform_const_buffer.Get ();
1590     num_const_buffers++;
1591   }
1592 
1593   if (convert_info->templ->has_alpha) {
1594     D3D11_BUFFER_DESC const_buffer_desc = { 0, };
1595     AlphaConstBuffer *alpha_const;
1596 
1597     G_STATIC_ASSERT (sizeof (AlphaConstBuffer) % 16 == 0);
1598 
1599     const_buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1600     const_buffer_desc.ByteWidth = sizeof (AlphaConstBuffer);
1601     const_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
1602     const_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1603     const_buffer_desc.MiscFlags = 0;
1604     const_buffer_desc.StructureByteStride = 0;
1605 
1606     hr = device_handle->CreateBuffer (&const_buffer_desc,
1607         nullptr, &alpha_const_buffer);
1608     if (!gst_d3d11_result (hr, device)) {
1609       GST_ERROR ("Couldn't create constant buffer, hr: 0x%x", (guint) hr);
1610       return FALSE;
1611     }
1612 
1613     gst_d3d11_device_lock (device);
1614     hr = context_handle->Map (alpha_const_buffer.Get (),
1615         0, D3D11_MAP_WRITE_DISCARD, 0, &map);
1616 
1617     if (!gst_d3d11_result (hr, device)) {
1618       GST_ERROR ("Couldn't map constant buffer, hr: 0x%x", (guint) hr);
1619       gst_d3d11_device_unlock (device);
1620       return FALSE;
1621     }
1622 
1623     alpha_const = (AlphaConstBuffer *) map.pData;
1624     memset (alpha_const, 0, sizeof (AlphaConstBuffer));
1625     alpha_const->alpha_mul = (FLOAT) self->alpha;
1626 
1627     context_handle->Unmap (alpha_const_buffer.Get (), 0);
1628     gst_d3d11_device_unlock (device);
1629 
1630     self->alpha_const_buffer = alpha_const_buffer.Get ();
1631     /* We will hold this buffer and update later */
1632     self->alpha_const_buffer->AddRef ();
1633     const_buffers[num_const_buffers] = alpha_const_buffer.Get ();
1634     num_const_buffers++;
1635   }
1636 
1637   input_desc[0].SemanticName = "POSITION";
1638   input_desc[0].SemanticIndex = 0;
1639   input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
1640   input_desc[0].InputSlot = 0;
1641   input_desc[0].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
1642   input_desc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
1643   input_desc[0].InstanceDataStepRate = 0;
1644 
1645   input_desc[1].SemanticName = "TEXCOORD";
1646   input_desc[1].SemanticIndex = 0;
1647   input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT;
1648   input_desc[1].InputSlot = 0;
1649   input_desc[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
1650   input_desc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
1651   input_desc[1].InstanceDataStepRate = 0;
1652 
1653   if (!gst_d3d11_create_vertex_shader (device, templ_vertex_shader,
1654           input_desc, G_N_ELEMENTS (input_desc), &vs, &layout)) {
1655     GST_ERROR ("Couldn't vertex pixel shader");
1656     return FALSE;
1657   }
1658 
1659   /* setup vertext buffer and index buffer */
1660   buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1661   buffer_desc.ByteWidth = sizeof (VertexData) * 4;
1662   buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1663   buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1664 
1665   hr = device_handle->CreateBuffer (&buffer_desc, NULL, &vertex_buffer);
1666   if (!gst_d3d11_result (hr, device)) {
1667     GST_ERROR ("Couldn't create vertex buffer, hr: 0x%x", (guint) hr);
1668     return FALSE;
1669   }
1670 
1671   buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1672   buffer_desc.ByteWidth = sizeof (WORD) * index_count;
1673   buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
1674   buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1675 
1676   hr = device_handle->CreateBuffer (&buffer_desc, NULL, &index_buffer);
1677   if (!gst_d3d11_result (hr, device)) {
1678     GST_ERROR ("Couldn't create index buffer, hr: 0x%x", (guint) hr);
1679     return FALSE;
1680   }
1681 
1682   gst_d3d11_device_lock (device);
1683   hr = context_handle->Map (vertex_buffer.Get (), 0, D3D11_MAP_WRITE_DISCARD, 0,
1684       &map);
1685   if (!gst_d3d11_result (hr, device)) {
1686     GST_ERROR ("Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
1687     gst_d3d11_device_unlock (device);
1688     return FALSE;
1689   }
1690 
1691   vertex_data = (VertexData *) map.pData;
1692 
1693   hr = context_handle->Map (index_buffer.Get (), 0, D3D11_MAP_WRITE_DISCARD, 0,
1694       &map);
1695   if (!gst_d3d11_result (hr, device)) {
1696     GST_ERROR ("Couldn't map index buffer, hr: 0x%x", (guint) hr);
1697     context_handle->Unmap (vertex_buffer.Get (), 0);
1698     gst_d3d11_device_unlock (device);
1699     return FALSE;
1700   }
1701 
1702   indices = (WORD *) map.pData;
1703 
1704   /* bottom left */
1705   vertex_data[0].position.x = -1.0f;
1706   vertex_data[0].position.y = -1.0f;
1707   vertex_data[0].position.z = 0.0f;
1708   vertex_data[0].texture.x = 0.0f;
1709   vertex_data[0].texture.y = 1.0f;
1710 
1711   /* top left */
1712   vertex_data[1].position.x = -1.0f;
1713   vertex_data[1].position.y = 1.0f;
1714   vertex_data[1].position.z = 0.0f;
1715   vertex_data[1].texture.x = 0.0f;
1716   vertex_data[1].texture.y = 0.0f;
1717 
1718   /* top right */
1719   vertex_data[2].position.x = 1.0f;
1720   vertex_data[2].position.y = 1.0f;
1721   vertex_data[2].position.z = 0.0f;
1722   vertex_data[2].texture.x = 1.0f;
1723   vertex_data[2].texture.y = 0.0f;
1724 
1725   /* bottom right */
1726   vertex_data[3].position.x = 1.0f;
1727   vertex_data[3].position.y = -1.0f;
1728   vertex_data[3].position.z = 0.0f;
1729   vertex_data[3].texture.x = 1.0f;
1730   vertex_data[3].texture.y = 1.0f;
1731 
1732   /* clockwise indexing */
1733   indices[0] = 0;               /* bottom left */
1734   indices[1] = 1;               /* top left */
1735   indices[2] = 2;               /* top right */
1736 
1737   indices[3] = 3;               /* bottom right */
1738   indices[4] = 0;               /* bottom left  */
1739   indices[5] = 2;               /* top right */
1740 
1741   context_handle->Unmap (vertex_buffer.Get (), 0);
1742   context_handle->Unmap (index_buffer.Get (), 0);
1743   gst_d3d11_device_unlock (device);
1744 
1745   self->quad[0] = gst_d3d11_quad_new (device,
1746       ps[0].Get (), vs.Get (), layout.Get (),
1747       const_buffers, num_const_buffers,
1748       vertex_buffer.Get (), sizeof (VertexData),
1749       index_buffer.Get (), DXGI_FORMAT_R16_UINT, index_count);
1750 
1751   if (ps[1]) {
1752     self->quad[1] = gst_d3d11_quad_new (device,
1753         ps[1].Get (), vs.Get (), layout.Get (),
1754         const_buffers, num_const_buffers,
1755         vertex_buffer.Get (), sizeof (VertexData),
1756         index_buffer.Get (), DXGI_FORMAT_R16_UINT, index_count);
1757   }
1758 
1759   self->num_input_view = GST_VIDEO_INFO_N_PLANES (in_info);
1760   self->num_output_view = GST_VIDEO_INFO_N_PLANES (out_info);
1761 
1762   /* holds vertex buffer for crop rect update */
1763   self->vertex_buffer = vertex_buffer.Detach ();
1764 
1765   self->src_rect.left = 0;
1766   self->src_rect.top = 0;
1767   self->src_rect.right = GST_VIDEO_INFO_WIDTH (in_info);
1768   self->src_rect.bottom = GST_VIDEO_INFO_HEIGHT (in_info);
1769 
1770   self->dest_rect.left = 0;
1771   self->dest_rect.top = 0;
1772   self->dest_rect.right = GST_VIDEO_INFO_WIDTH (out_info);
1773   self->dest_rect.bottom = GST_VIDEO_INFO_HEIGHT (out_info);
1774 
1775   self->input_texture_width = GST_VIDEO_INFO_WIDTH (in_info);
1776   self->input_texture_height = GST_VIDEO_INFO_HEIGHT (in_info);
1777 
1778   self->linear_sampler = linear_sampler.Detach ();
1779 
1780   return TRUE;
1781 }
1782 
1783 static gboolean
copy_config(GQuark field_id,const GValue * value,GstD3D11Converter * self)1784 copy_config (GQuark field_id, const GValue * value, GstD3D11Converter * self)
1785 {
1786   gst_structure_id_set_value (self->config, field_id, value);
1787 
1788   return TRUE;
1789 }
1790 
1791 static gboolean
gst_d3d11_converter_set_config(GstD3D11Converter * converter,GstStructure * config)1792 gst_d3d11_converter_set_config (GstD3D11Converter * converter,
1793     GstStructure * config)
1794 {
1795   gst_structure_foreach (config, (GstStructureForeachFunc) copy_config,
1796       converter);
1797   gst_structure_free (config);
1798 
1799   return TRUE;
1800 }
1801 
1802 GstD3D11Converter *
gst_d3d11_converter_new(GstD3D11Device * device,GstVideoInfo * in_info,GstVideoInfo * out_info,GstStructure * config)1803 gst_d3d11_converter_new (GstD3D11Device * device,
1804     GstVideoInfo * in_info, GstVideoInfo * out_info, GstStructure * config)
1805 {
1806   const GstVideoInfo *unknown_info;
1807   const GstD3D11Format *in_d3d11_format;
1808   const GstD3D11Format *out_d3d11_format;
1809   gboolean is_supported = FALSE;
1810   MatrixData matrix;
1811   GstD3D11Converter *converter = NULL;
1812   gboolean ret;
1813   guint i;
1814 
1815   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1816   g_return_val_if_fail (in_info != NULL, NULL);
1817   g_return_val_if_fail (out_info != NULL, NULL);
1818 
1819   GST_DEBUG ("Setup convert with format %s -> %s",
1820       gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)),
1821       gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
1822 
1823   in_d3d11_format =
1824       gst_d3d11_device_format_from_gst (device,
1825       GST_VIDEO_INFO_FORMAT (in_info));
1826   if (!in_d3d11_format) {
1827     unknown_info = in_info;
1828     goto format_unknown;
1829   }
1830 
1831   out_d3d11_format =
1832       gst_d3d11_device_format_from_gst (device,
1833       GST_VIDEO_INFO_FORMAT (out_info));
1834   if (!out_d3d11_format) {
1835     unknown_info = out_info;
1836     goto format_unknown;
1837   }
1838 
1839   converter = g_new0 (GstD3D11Converter, 1);
1840   converter->device = (GstD3D11Device *) gst_object_ref (device);
1841   converter->config = gst_structure_new_empty ("GstD3D11Converter-Config");
1842   if (config)
1843     gst_d3d11_converter_set_config (converter, config);
1844 
1845   converter->alpha = GET_OPT_ALPHA_VALUE (converter);
1846 
1847   if (GST_VIDEO_INFO_IS_RGB (in_info)) {
1848     if (GST_VIDEO_INFO_IS_RGB (out_info)) {
1849       is_supported =
1850           setup_convert_info_rgb_to_rgb (converter, in_info, out_info);
1851     } else if (GST_VIDEO_INFO_IS_YUV (out_info)) {
1852       is_supported =
1853           setup_convert_info_rgb_to_yuv (converter, in_info, out_info);
1854     } else if (GST_VIDEO_INFO_IS_GRAY (out_info)) {
1855       is_supported =
1856           setup_convert_info_rgb_to_gray (converter, in_info, out_info);
1857     }
1858   } else if (GST_VIDEO_INFO_IS_YUV (in_info)) {
1859     if (GST_VIDEO_INFO_IS_RGB (out_info)) {
1860       is_supported =
1861           setup_convert_info_yuv_to_rgb (converter, in_info, out_info);
1862     } else if (GST_VIDEO_INFO_IS_YUV (out_info)) {
1863       is_supported =
1864           setup_convert_info_yuv_to_yuv (converter, in_info, out_info);
1865     } else if (GST_VIDEO_INFO_IS_GRAY (out_info)) {
1866       is_supported =
1867           setup_convert_info_yuv_to_gray (converter, in_info, out_info);
1868     }
1869   } else if (GST_VIDEO_INFO_IS_GRAY (in_info)) {
1870     if (GST_VIDEO_INFO_IS_RGB (out_info)) {
1871       is_supported =
1872           setup_convert_info_gray_to_rgb (converter, in_info, out_info);
1873     } else if (GST_VIDEO_INFO_IS_YUV (out_info)) {
1874       is_supported =
1875           setup_convert_info_gray_to_yuv (converter, in_info, out_info);
1876     } else if (GST_VIDEO_INFO_IS_GRAY (out_info)) {
1877       is_supported =
1878           setup_convert_info_gray_to_gray (converter, in_info, out_info);
1879     }
1880   }
1881 
1882   if (!is_supported) {
1883     goto conversion_not_supported;
1884   }
1885 
1886   if (converter_get_matrix (converter, &matrix, in_info, out_info)) {
1887     PixelShaderColorTransform *transform = &converter->convert_info.transform;
1888 
1889     /* padding the last column for 16bytes alignment */
1890     transform->trans_matrix[0] = matrix.dm[0][0];
1891     transform->trans_matrix[1] = matrix.dm[0][1];
1892     transform->trans_matrix[2] = matrix.dm[0][2];
1893     transform->trans_matrix[3] = 0;
1894     transform->trans_matrix[4] = matrix.dm[1][0];
1895     transform->trans_matrix[5] = matrix.dm[1][1];
1896     transform->trans_matrix[6] = matrix.dm[1][2];
1897     transform->trans_matrix[7] = 0;
1898     transform->trans_matrix[8] = matrix.dm[2][0];
1899     transform->trans_matrix[9] = matrix.dm[2][1];
1900     transform->trans_matrix[10] = matrix.dm[2][2];
1901     transform->trans_matrix[11] = 0;
1902   }
1903 
1904   for (i = 0; i < GST_VIDEO_INFO_N_PLANES (out_info); i++) {
1905     converter->viewport[i].TopLeftX = 0;
1906     converter->viewport[i].TopLeftY = 0;
1907     converter->viewport[i].Width = GST_VIDEO_INFO_COMP_WIDTH (out_info, i);
1908     converter->viewport[i].Height = GST_VIDEO_INFO_COMP_HEIGHT (out_info, i);
1909     converter->viewport[i].MinDepth = 0.0f;
1910     converter->viewport[i].MaxDepth = 1.0f;
1911   }
1912 
1913   ret = gst_d3d11_color_convert_setup_shader (converter,
1914       device, in_info, out_info);
1915 
1916   if (!ret) {
1917     GST_ERROR ("Couldn't setup shader");
1918     gst_d3d11_converter_free (converter);
1919     converter = NULL;
1920   } else {
1921     converter->in_info = *in_info;
1922     converter->out_info = *out_info;
1923   }
1924 
1925   return converter;
1926 
1927   /* ERRORS */
1928 format_unknown:
1929   {
1930     GST_ERROR ("%s couldn't be converted to d3d11 format",
1931         gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (unknown_info)));
1932     if (config)
1933       gst_structure_free (config);
1934 
1935     return NULL;
1936   }
1937 conversion_not_supported:
1938   {
1939     GST_ERROR ("Conversion %s to %s not supported",
1940         gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)),
1941         gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
1942     gst_d3d11_converter_free (converter);
1943     return NULL;
1944   }
1945 }
1946 
1947 void
gst_d3d11_converter_free(GstD3D11Converter * converter)1948 gst_d3d11_converter_free (GstD3D11Converter * converter)
1949 {
1950   gint i;
1951 
1952   g_return_if_fail (converter != NULL);
1953 
1954   for (i = 0; i < CONVERTER_MAX_QUADS; i++) {
1955     if (converter->quad[i])
1956       gst_d3d11_quad_free (converter->quad[i]);
1957 
1958     g_free (converter->convert_info.ps_body[i]);
1959   }
1960 
1961   GST_D3D11_CLEAR_COM (converter->vertex_buffer);
1962   GST_D3D11_CLEAR_COM (converter->linear_sampler);
1963   GST_D3D11_CLEAR_COM (converter->alpha_const_buffer);
1964 
1965   gst_clear_object (&converter->device);
1966 
1967   if (converter->config)
1968     gst_structure_free (converter->config);
1969 
1970   g_free (converter);
1971 }
1972 
1973 /* must be called with gst_d3d11_device_lock since ID3D11DeviceContext is not
1974  * thread-safe */
1975 static gboolean
gst_d3d11_converter_update_vertex_buffer(GstD3D11Converter * self)1976 gst_d3d11_converter_update_vertex_buffer (GstD3D11Converter * self)
1977 {
1978   D3D11_MAPPED_SUBRESOURCE map;
1979   VertexData *vertex_data;
1980   ID3D11DeviceContext *context_handle;
1981   HRESULT hr;
1982   FLOAT x1, y1, x2, y2;
1983   FLOAT u, v;
1984   const RECT *src_rect = &self->src_rect;
1985   const RECT *dest_rect = &self->dest_rect;
1986   gint texture_width = self->input_texture_width;
1987   gint texture_height = self->input_texture_height;
1988   gdouble val;
1989 
1990   context_handle = gst_d3d11_device_get_device_context_handle (self->device);
1991 
1992   hr = context_handle->Map (self->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD,
1993       0, &map);
1994 
1995   if (!gst_d3d11_result (hr, self->device)) {
1996     GST_ERROR ("Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
1997     return FALSE;
1998   }
1999 
2000   vertex_data = (VertexData *) map.pData;
2001   /* bottom left */
2002   gst_util_fraction_to_double (dest_rect->left,
2003       GST_VIDEO_INFO_WIDTH (&self->out_info), &val);
2004   x1 = (val * 2.0f) - 1.0f;
2005 
2006   gst_util_fraction_to_double (dest_rect->bottom,
2007       GST_VIDEO_INFO_HEIGHT (&self->out_info), &val);
2008   y1 = (val * -2.0f) + 1.0f;
2009 
2010   /* top right */
2011   gst_util_fraction_to_double (dest_rect->right,
2012       GST_VIDEO_INFO_WIDTH (&self->out_info), &val);
2013   x2 = (val * 2.0f) - 1.0f;
2014 
2015   gst_util_fraction_to_double (dest_rect->top,
2016       GST_VIDEO_INFO_HEIGHT (&self->out_info), &val);
2017   y2 = (val * -2.0f) + 1.0f;
2018 
2019   /* bottom left */
2020   u = (src_rect->left / (gfloat) texture_width) - 0.5f / texture_width;
2021   v = (src_rect->bottom / (gfloat) texture_height) - 0.5f / texture_height;
2022 
2023   vertex_data[0].position.x = x1;
2024   vertex_data[0].position.y = y1;
2025   vertex_data[0].position.z = 0.0f;
2026   vertex_data[0].texture.x = u;
2027   vertex_data[0].texture.y = v;
2028 
2029   /* top left */
2030   u = (src_rect->left / (gfloat) texture_width) - 0.5f / texture_width;
2031   v = (src_rect->top / (gfloat) texture_height) - 0.5f / texture_height;
2032 
2033   vertex_data[1].position.x = x1;
2034   vertex_data[1].position.y = y2;
2035   vertex_data[1].position.z = 0.0f;
2036   vertex_data[1].texture.x = u;
2037   vertex_data[1].texture.y = v;
2038 
2039   /* top right */
2040   u = (src_rect->right / (gfloat) texture_width) - 0.5f / texture_width;
2041   v = (src_rect->top / (gfloat) texture_height) - 0.5f / texture_height;
2042 
2043   vertex_data[2].position.x = x2;
2044   vertex_data[2].position.y = y2;
2045   vertex_data[2].position.z = 0.0f;
2046   vertex_data[2].texture.x = u;
2047   vertex_data[2].texture.y = v;
2048 
2049   /* bottom right */
2050   u = (src_rect->right / (gfloat) texture_width) - 0.5f / texture_width;
2051   v = (src_rect->bottom / (gfloat) texture_height) - 0.5f / texture_height;
2052 
2053   vertex_data[3].position.x = x2;
2054   vertex_data[3].position.y = y1;
2055   vertex_data[3].position.z = 0.0f;
2056   vertex_data[3].texture.x = u;
2057   vertex_data[3].texture.y = v;
2058 
2059   context_handle->Unmap (self->vertex_buffer, 0);
2060 
2061   self->update_vertex = FALSE;
2062 
2063   return TRUE;
2064 }
2065 
2066 gboolean
gst_d3d11_converter_convert(GstD3D11Converter * converter,ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES],ID3D11BlendState * blend,gfloat blend_factor[4])2067 gst_d3d11_converter_convert (GstD3D11Converter * converter,
2068     ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],
2069     ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES],
2070     ID3D11BlendState * blend, gfloat blend_factor[4])
2071 {
2072   gboolean ret;
2073 
2074   g_return_val_if_fail (converter != NULL, FALSE);
2075   g_return_val_if_fail (srv != NULL, FALSE);
2076   g_return_val_if_fail (rtv != NULL, FALSE);
2077 
2078   gst_d3d11_device_lock (converter->device);
2079   ret = gst_d3d11_converter_convert_unlocked (converter,
2080       srv, rtv, blend, blend_factor);
2081   gst_d3d11_device_unlock (converter->device);
2082 
2083   return ret;
2084 }
2085 
2086 gboolean
gst_d3d11_converter_convert_unlocked(GstD3D11Converter * converter,ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES],ID3D11BlendState * blend,gfloat blend_factor[4])2087 gst_d3d11_converter_convert_unlocked (GstD3D11Converter * converter,
2088     ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],
2089     ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES],
2090     ID3D11BlendState * blend, gfloat blend_factor[4])
2091 {
2092   gboolean ret;
2093   /* *INDENT-OFF* */
2094   ComPtr<ID3D11Resource> resource;
2095   ComPtr<ID3D11Texture2D> texture;
2096   /* *INDENT-ON* */
2097   D3D11_TEXTURE2D_DESC desc;
2098 
2099   g_return_val_if_fail (converter != NULL, FALSE);
2100   g_return_val_if_fail (srv != NULL, FALSE);
2101   g_return_val_if_fail (rtv != NULL, FALSE);
2102 
2103   /* check texture resolution and update crop area */
2104   srv[0]->GetResource (&resource);
2105   resource.As (&texture);
2106   texture->GetDesc (&desc);
2107 
2108   if (converter->update_vertex ||
2109       desc.Width != (guint) converter->input_texture_width ||
2110       desc.Height != (guint) converter->input_texture_height) {
2111     GST_DEBUG ("Update vertext buffer, texture resolution: %dx%d",
2112         desc.Width, desc.Height);
2113 
2114     converter->input_texture_width = desc.Width;
2115     converter->input_texture_height = desc.Height;
2116 
2117     if (!gst_d3d11_converter_update_vertex_buffer (converter)) {
2118       GST_ERROR ("Cannot update vertex buffer");
2119       return FALSE;
2120     }
2121   }
2122 
2123   if (converter->update_alpha) {
2124     D3D11_MAPPED_SUBRESOURCE map;
2125     ID3D11DeviceContext *context_handle;
2126     AlphaConstBuffer *alpha_const;
2127     HRESULT hr;
2128 
2129     g_assert (converter->alpha_const_buffer != nullptr);
2130 
2131     context_handle =
2132         gst_d3d11_device_get_device_context_handle (converter->device);
2133 
2134     hr = context_handle->Map (converter->alpha_const_buffer,
2135         0, D3D11_MAP_WRITE_DISCARD, 0, &map);
2136 
2137     if (!gst_d3d11_result (hr, converter->device)) {
2138       GST_ERROR ("Couldn't map constant buffer, hr: 0x%x", (guint) hr);
2139       return FALSE;
2140     }
2141 
2142     alpha_const = (AlphaConstBuffer *) map.pData;
2143     alpha_const->alpha_mul = (FLOAT) converter->alpha;
2144 
2145     context_handle->Unmap (converter->alpha_const_buffer, 0);
2146     converter->update_alpha = FALSE;
2147   }
2148 
2149   ret = gst_d3d11_draw_quad_unlocked (converter->quad[0], converter->viewport,
2150       1, srv, converter->num_input_view, rtv, 1, blend, blend_factor,
2151       &converter->linear_sampler, 1);
2152 
2153   if (!ret)
2154     return FALSE;
2155 
2156   if (converter->quad[1]) {
2157     ret = gst_d3d11_draw_quad_unlocked (converter->quad[1],
2158         &converter->viewport[1], converter->num_output_view - 1,
2159         srv, converter->num_input_view, &rtv[1], converter->num_output_view - 1,
2160         blend, blend_factor, &converter->linear_sampler, 1);
2161 
2162     if (!ret)
2163       return FALSE;
2164   }
2165 
2166   return TRUE;
2167 }
2168 
2169 gboolean
gst_d3d11_converter_update_viewport(GstD3D11Converter * converter,D3D11_VIEWPORT * viewport)2170 gst_d3d11_converter_update_viewport (GstD3D11Converter * converter,
2171     D3D11_VIEWPORT * viewport)
2172 {
2173   g_return_val_if_fail (converter != NULL, FALSE);
2174   g_return_val_if_fail (viewport != NULL, FALSE);
2175 
2176   converter->viewport[0] = *viewport;
2177 
2178   switch (GST_VIDEO_INFO_FORMAT (&converter->out_info)) {
2179     case GST_VIDEO_FORMAT_NV12:
2180     case GST_VIDEO_FORMAT_NV21:
2181     case GST_VIDEO_FORMAT_P010_10LE:
2182     case GST_VIDEO_FORMAT_P012_LE:
2183     case GST_VIDEO_FORMAT_P016_LE:
2184     case GST_VIDEO_FORMAT_I420:
2185     case GST_VIDEO_FORMAT_YV12:
2186     case GST_VIDEO_FORMAT_I420_10LE:
2187     case GST_VIDEO_FORMAT_I420_12LE:
2188     {
2189       guint i;
2190       converter->viewport[1].TopLeftX = converter->viewport[0].TopLeftX / 2;
2191       converter->viewport[1].TopLeftY = converter->viewport[0].TopLeftY / 2;
2192       converter->viewport[1].Width = converter->viewport[0].Width / 2;
2193       converter->viewport[1].Height = converter->viewport[0].Height / 2;
2194 
2195       for (i = 2; i < GST_VIDEO_INFO_N_PLANES (&converter->out_info); i++)
2196         converter->viewport[i] = converter->viewport[1];
2197 
2198       break;
2199     }
2200     case GST_VIDEO_FORMAT_Y42B:
2201     case GST_VIDEO_FORMAT_I422_10LE:
2202     case GST_VIDEO_FORMAT_I422_12LE:
2203     {
2204       guint i;
2205       converter->viewport[1].TopLeftX = converter->viewport[0].TopLeftX / 2;
2206       converter->viewport[1].TopLeftY = converter->viewport[0].TopLeftY;
2207       converter->viewport[1].Width = converter->viewport[0].Width / 2;
2208       converter->viewport[1].Height = converter->viewport[0].Height;
2209 
2210       for (i = 2; i < GST_VIDEO_INFO_N_PLANES (&converter->out_info); i++)
2211         converter->viewport[i] = converter->viewport[1];
2212 
2213       break;
2214     }
2215     case GST_VIDEO_FORMAT_Y444:
2216     case GST_VIDEO_FORMAT_Y444_10LE:
2217     case GST_VIDEO_FORMAT_Y444_12LE:
2218     case GST_VIDEO_FORMAT_Y444_16LE:
2219     {
2220       guint i;
2221       for (i = 1; i < GST_VIDEO_INFO_N_PLANES (&converter->out_info); i++)
2222         converter->viewport[i] = converter->viewport[1];
2223       break;
2224     }
2225     default:
2226       if (converter->num_output_view > 1)
2227         g_assert_not_reached ();
2228       break;
2229   }
2230 
2231   return TRUE;
2232 }
2233 
2234 gboolean
gst_d3d11_converter_update_src_rect(GstD3D11Converter * converter,RECT * src_rect)2235 gst_d3d11_converter_update_src_rect (GstD3D11Converter * converter,
2236     RECT * src_rect)
2237 {
2238   g_return_val_if_fail (converter != NULL, FALSE);
2239   g_return_val_if_fail (src_rect != NULL, FALSE);
2240 
2241   gst_d3d11_device_lock (converter->device);
2242   if (converter->src_rect.left != src_rect->left ||
2243       converter->src_rect.top != src_rect->top ||
2244       converter->src_rect.right != src_rect->right ||
2245       converter->src_rect.bottom != src_rect->bottom) {
2246     converter->src_rect = *src_rect;
2247 
2248     /* vertex buffer will be updated on next convert() call */
2249     converter->update_vertex = TRUE;
2250   }
2251   gst_d3d11_device_unlock (converter->device);
2252 
2253   return TRUE;
2254 }
2255 
2256 gboolean
gst_d3d11_converter_update_dest_rect(GstD3D11Converter * converter,RECT * dest_rect)2257 gst_d3d11_converter_update_dest_rect (GstD3D11Converter * converter,
2258     RECT * dest_rect)
2259 {
2260   g_return_val_if_fail (converter != NULL, FALSE);
2261   g_return_val_if_fail (dest_rect != NULL, FALSE);
2262 
2263   gst_d3d11_device_lock (converter->device);
2264   if (converter->dest_rect.left != dest_rect->left ||
2265       converter->dest_rect.top != dest_rect->top ||
2266       converter->dest_rect.right != dest_rect->right ||
2267       converter->dest_rect.bottom != dest_rect->bottom) {
2268     converter->dest_rect = *dest_rect;
2269 
2270     /* vertex buffer will be updated on next convert() call */
2271     converter->update_vertex = TRUE;
2272   }
2273   gst_d3d11_device_unlock (converter->device);
2274 
2275   return TRUE;
2276 }
2277 
2278 gboolean
gst_d3d11_converter_update_config(GstD3D11Converter * converter,GstStructure * config)2279 gst_d3d11_converter_update_config (GstD3D11Converter * converter,
2280     GstStructure * config)
2281 {
2282   g_return_val_if_fail (converter != nullptr, FALSE);
2283   g_return_val_if_fail (config != nullptr, FALSE);
2284 
2285   gst_d3d11_device_lock (converter->device);
2286   gst_d3d11_converter_set_config (converter, config);
2287 
2288   /* Check whether options are updated or not */
2289   if (converter->alpha_const_buffer) {
2290     gdouble alpha = GET_OPT_ALPHA_VALUE (converter);
2291 
2292     if (alpha != converter->alpha) {
2293       GST_DEBUG ("Updating alpha %lf -> %lf", converter->alpha, alpha);
2294       converter->alpha = alpha;
2295       converter->update_alpha = TRUE;
2296     }
2297   }
2298   gst_d3d11_device_unlock (converter->device);
2299 
2300   return TRUE;
2301 }
2302