1 /* GStreamer
2 * Copyright (C) <2019> Seungha Yang <seungha.yang@navercorp.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "gstd3d11shader.h"
25 #include "gstd3d11pluginutils.h"
26 #include <gmodule.h>
27 #include <wrl.h>
28
29 /* *INDENT-OFF* */
30 using namespace Microsoft::WRL;
31 /* *INDENT-ON* */
32
33 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_shader_debug);
34 #define GST_CAT_DEFAULT gst_d3d11_shader_debug
35
36 /* too many const buffers doesn't make sense */
37 #define MAX_CONST_BUFFERS 16
38
39 static GModule *d3d_compiler_module = NULL;
40 static pD3DCompile GstD3DCompileFunc = NULL;
41
42 gboolean
gst_d3d11_shader_init(void)43 gst_d3d11_shader_init (void)
44 {
45 static gsize _init = 0;
46
47 if (g_once_init_enter (&_init)) {
48 #if GST_D3D11_WINAPI_ONLY_APP
49 /* Assuming that d3d compiler library is available */
50 GstD3DCompileFunc = D3DCompile;
51 #else
52 static const gchar *d3d_compiler_names[] = {
53 "d3dcompiler_47.dll",
54 "d3dcompiler_46.dll",
55 "d3dcompiler_45.dll",
56 "d3dcompiler_44.dll",
57 "d3dcompiler_43.dll",
58 };
59 guint i;
60 for (i = 0; i < G_N_ELEMENTS (d3d_compiler_names); i++) {
61 d3d_compiler_module =
62 g_module_open (d3d_compiler_names[i], G_MODULE_BIND_LAZY);
63
64 if (d3d_compiler_module) {
65 GST_INFO ("D3D compiler %s is available", d3d_compiler_names[i]);
66 if (!g_module_symbol (d3d_compiler_module, "D3DCompile",
67 (gpointer *) & GstD3DCompileFunc)) {
68 GST_ERROR ("Cannot load D3DCompile symbol from %s",
69 d3d_compiler_names[i]);
70 g_module_close (d3d_compiler_module);
71 d3d_compiler_module = NULL;
72 GstD3DCompileFunc = NULL;
73 } else {
74 break;
75 }
76 }
77 }
78
79 if (!GstD3DCompileFunc)
80 GST_WARNING ("D3D11 compiler library is unavailable");
81 #endif
82
83 g_once_init_leave (&_init, 1);
84 }
85
86 return !!GstD3DCompileFunc;
87 }
88
89 static gboolean
compile_shader(GstD3D11Device * device,const gchar * shader_source,gboolean is_pixel_shader,ID3DBlob ** blob)90 compile_shader (GstD3D11Device * device, const gchar * shader_source,
91 gboolean is_pixel_shader, ID3DBlob ** blob)
92 {
93 const gchar *shader_target;
94 D3D_FEATURE_LEVEL feature_level;
95 HRESULT hr;
96 ID3D11Device *device_handle;
97 /* *INDENT-OFF* */
98 ComPtr<ID3DBlob> ret;
99 ComPtr<ID3DBlob> error;
100 /* *INDENT-ON* */
101
102 if (!gst_d3d11_shader_init ()) {
103 GST_ERROR ("D3DCompiler is unavailable");
104 return FALSE;
105 }
106
107 device_handle = gst_d3d11_device_get_device_handle (device);
108 feature_level = device_handle->GetFeatureLevel ();
109
110 if (is_pixel_shader) {
111 if (feature_level >= D3D_FEATURE_LEVEL_10_0)
112 shader_target = "ps_4_0";
113 else if (feature_level >= D3D_FEATURE_LEVEL_9_3)
114 shader_target = "ps_4_0_level_9_3";
115 else
116 shader_target = "ps_4_0_level_9_1";
117 } else {
118 if (feature_level >= D3D_FEATURE_LEVEL_10_0)
119 shader_target = "vs_4_0";
120 else if (feature_level >= D3D_FEATURE_LEVEL_9_3)
121 shader_target = "vs_4_0_level_9_3";
122 else
123 shader_target = "vs_4_0_level_9_1";
124 }
125
126 g_assert (GstD3DCompileFunc);
127
128 GST_TRACE ("Compile code \n%s", shader_source);
129
130 hr = GstD3DCompileFunc (shader_source, strlen (shader_source), NULL, NULL,
131 NULL, "main", shader_target, 0, 0, &ret, &error);
132
133 if (!gst_d3d11_result (hr, device)) {
134 const gchar *err = NULL;
135
136 if (error)
137 err = (const gchar *) error->GetBufferPointer ();
138
139 GST_ERROR ("could not compile source, hr: 0x%x, error detail %s",
140 (guint) hr, GST_STR_NULL (err));
141 return FALSE;
142 }
143
144 if (error) {
145 const gchar *err = (const gchar *) error->GetBufferPointer ();
146
147 GST_DEBUG ("HLSL compiler warnings:\n%s\nShader code:\n%s",
148 GST_STR_NULL (err), GST_STR_NULL (shader_source));
149 }
150
151 *blob = ret.Detach ();
152
153 return TRUE;
154 }
155
156 gboolean
gst_d3d11_create_pixel_shader(GstD3D11Device * device,const gchar * source,ID3D11PixelShader ** shader)157 gst_d3d11_create_pixel_shader (GstD3D11Device * device,
158 const gchar * source, ID3D11PixelShader ** shader)
159 {
160 ID3D11Device *device_handle;
161 HRESULT hr;
162 /* *INDENT-OFF* */
163 ComPtr<ID3DBlob> ps_blob;
164 /* *INDENT-ON* */
165
166 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
167 g_return_val_if_fail (source != NULL, FALSE);
168 g_return_val_if_fail (shader != NULL, FALSE);
169
170 if (!compile_shader (device, source, TRUE, &ps_blob)) {
171 GST_ERROR ("Failed to compile pixel shader");
172 return FALSE;
173 }
174
175 device_handle = gst_d3d11_device_get_device_handle (device);
176 hr = device_handle->CreatePixelShader (ps_blob->GetBufferPointer (),
177 ps_blob->GetBufferSize (), NULL, shader);
178 if (!gst_d3d11_result (hr, device)) {
179 GST_ERROR ("could not create pixel shader, hr: 0x%x", (guint) hr);
180 return FALSE;
181 }
182
183 return TRUE;
184 }
185
186 gboolean
gst_d3d11_create_vertex_shader(GstD3D11Device * device,const gchar * source,const D3D11_INPUT_ELEMENT_DESC * input_desc,guint desc_len,ID3D11VertexShader ** shader,ID3D11InputLayout ** layout)187 gst_d3d11_create_vertex_shader (GstD3D11Device * device, const gchar * source,
188 const D3D11_INPUT_ELEMENT_DESC * input_desc, guint desc_len,
189 ID3D11VertexShader ** shader, ID3D11InputLayout ** layout)
190 {
191 ID3D11Device *device_handle;
192 HRESULT hr;
193 /* *INDENT-OFF* */
194 ComPtr<ID3DBlob> vs_blob;
195 ComPtr<ID3D11VertexShader> vs;
196 ComPtr<ID3D11InputLayout> in_layout;
197 /* *INDENT-ON* */
198
199 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
200 g_return_val_if_fail (source != NULL, FALSE);
201 g_return_val_if_fail (input_desc != NULL, FALSE);
202 g_return_val_if_fail (desc_len > 0, FALSE);
203 g_return_val_if_fail (shader != NULL, FALSE);
204 g_return_val_if_fail (layout != NULL, FALSE);
205
206 if (!compile_shader (device, source, FALSE, &vs_blob)) {
207 GST_ERROR ("Failed to compile shader code");
208 return FALSE;
209 }
210
211 device_handle = gst_d3d11_device_get_device_handle (device);
212 hr = device_handle->CreateVertexShader (vs_blob->GetBufferPointer (),
213 vs_blob->GetBufferSize (), NULL, &vs);
214 if (!gst_d3d11_result (hr, device)) {
215 GST_ERROR ("could not create vertex shader, hr: 0x%x", (guint) hr);
216 return FALSE;
217 }
218
219 hr = device_handle->CreateInputLayout (input_desc,
220 desc_len, vs_blob->GetBufferPointer (),
221 vs_blob->GetBufferSize (), &in_layout);
222 if (!gst_d3d11_result (hr, device)) {
223 GST_ERROR ("could not create input layout shader, hr: 0x%x", (guint) hr);
224 return FALSE;
225 }
226
227 *shader = vs.Detach ();
228 *layout = in_layout.Detach ();
229
230 return TRUE;
231 }
232
233 struct _GstD3D11Quad
234 {
235 GstD3D11Device *device;
236 ID3D11PixelShader *ps;
237 ID3D11VertexShader *vs;
238 ID3D11InputLayout *layout;
239 ID3D11Buffer *const_buffer[MAX_CONST_BUFFERS];
240 guint num_const_buffers;
241 ID3D11Buffer *vertex_buffer;
242 guint vertex_stride;
243 ID3D11Buffer *index_buffer;
244 DXGI_FORMAT index_format;
245 guint index_count;
246 D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES];
247 ID3D11ShaderResourceView *srv[GST_VIDEO_MAX_PLANES];
248 guint num_srv;
249 ID3D11RenderTargetView *rtv[GST_VIDEO_MAX_PLANES];
250 guint num_rtv;
251 };
252
253 GstD3D11Quad *
gst_d3d11_quad_new(GstD3D11Device * device,ID3D11PixelShader * pixel_shader,ID3D11VertexShader * vertex_shader,ID3D11InputLayout * layout,ID3D11Buffer ** const_buffers,guint num_const_buffers,ID3D11Buffer * vertex_buffer,guint vertex_stride,ID3D11Buffer * index_buffer,DXGI_FORMAT index_format,guint index_count)254 gst_d3d11_quad_new (GstD3D11Device * device, ID3D11PixelShader * pixel_shader,
255 ID3D11VertexShader * vertex_shader, ID3D11InputLayout * layout,
256 ID3D11Buffer ** const_buffers, guint num_const_buffers,
257 ID3D11Buffer * vertex_buffer, guint vertex_stride,
258 ID3D11Buffer * index_buffer, DXGI_FORMAT index_format, guint index_count)
259 {
260 GstD3D11Quad *quad;
261
262 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
263 g_return_val_if_fail (pixel_shader != NULL, NULL);
264 g_return_val_if_fail (vertex_shader != NULL, NULL);
265 g_return_val_if_fail (layout != NULL, NULL);
266 g_return_val_if_fail (num_const_buffers <= MAX_CONST_BUFFERS, NULL);
267 g_return_val_if_fail (vertex_buffer != NULL, NULL);
268 g_return_val_if_fail (vertex_stride > 0, NULL);
269 g_return_val_if_fail (index_buffer != NULL, NULL);
270 g_return_val_if_fail (index_format != DXGI_FORMAT_UNKNOWN, NULL);
271
272 quad = g_new0 (GstD3D11Quad, 1);
273
274 quad->device = (GstD3D11Device *) gst_object_ref (device);
275 quad->ps = pixel_shader;
276 quad->vs = vertex_shader;
277 quad->layout = layout;
278 quad->vertex_buffer = vertex_buffer;
279 quad->vertex_stride = vertex_stride;
280 quad->index_buffer = index_buffer;
281 quad->index_format = index_format;
282 quad->index_count = index_count;
283
284 pixel_shader->AddRef ();
285 vertex_shader->AddRef ();
286 layout->AddRef ();
287 vertex_buffer->AddRef ();
288 index_buffer->AddRef ();
289
290 if (num_const_buffers > 0) {
291 guint i;
292
293 g_assert (const_buffers);
294
295 for (i = 0; i < num_const_buffers; i++) {
296 quad->const_buffer[i] = const_buffers[i];
297 quad->const_buffer[i]->AddRef ();
298 }
299
300 quad->num_const_buffers = num_const_buffers;
301 }
302
303 return quad;
304 }
305
306 void
gst_d3d11_quad_free(GstD3D11Quad * quad)307 gst_d3d11_quad_free (GstD3D11Quad * quad)
308 {
309 guint i;
310
311 g_return_if_fail (quad != NULL);
312
313 GST_D3D11_CLEAR_COM (quad->ps);
314 GST_D3D11_CLEAR_COM (quad->vs);
315 GST_D3D11_CLEAR_COM (quad->layout);
316 for (i = 0; i < quad->num_const_buffers; i++)
317 quad->const_buffer[i]->Release ();
318 GST_D3D11_CLEAR_COM (quad->vertex_buffer);
319 GST_D3D11_CLEAR_COM (quad->index_buffer);
320
321 gst_clear_object (&quad->device);
322 g_free (quad);
323 }
324
325 gboolean
gst_d3d11_draw_quad(GstD3D11Quad * quad,D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES],guint num_viewport,ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],guint num_srv,ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES],guint num_rtv,ID3D11BlendState * blend,gfloat blend_factor[4],ID3D11SamplerState ** sampler,guint num_sampler)326 gst_d3d11_draw_quad (GstD3D11Quad * quad,
327 D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES], guint num_viewport,
328 ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES], guint num_srv,
329 ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES], guint num_rtv,
330 ID3D11BlendState * blend, gfloat blend_factor[4],
331 ID3D11SamplerState ** sampler, guint num_sampler)
332 {
333 gboolean ret;
334
335 g_return_val_if_fail (quad != NULL, FALSE);
336
337 gst_d3d11_device_lock (quad->device);
338 ret = gst_d3d11_draw_quad_unlocked (quad, viewport, num_viewport,
339 srv, num_srv, rtv, num_viewport, blend, blend_factor, sampler,
340 num_sampler);
341 gst_d3d11_device_unlock (quad->device);
342
343 return ret;
344 }
345
346 gboolean
gst_d3d11_draw_quad_unlocked(GstD3D11Quad * quad,D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES],guint num_viewport,ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],guint num_srv,ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES],guint num_rtv,ID3D11BlendState * blend,gfloat blend_factor[4],ID3D11SamplerState ** sampler,guint num_sampler)347 gst_d3d11_draw_quad_unlocked (GstD3D11Quad * quad,
348 D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES], guint num_viewport,
349 ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES], guint num_srv,
350 ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES], guint num_rtv,
351 ID3D11BlendState * blend, gfloat blend_factor[4],
352 ID3D11SamplerState ** sampler, guint num_sampler)
353 {
354 ID3D11DeviceContext *context;
355 UINT offsets = 0;
356 ID3D11ShaderResourceView *clear_view[GST_VIDEO_MAX_PLANES] = { NULL, };
357 ID3D11BlendState *blend_state = blend;
358
359 g_return_val_if_fail (quad != NULL, FALSE);
360 g_return_val_if_fail (viewport != NULL, FALSE);
361 g_return_val_if_fail (num_viewport <= GST_VIDEO_MAX_PLANES, FALSE);
362 g_return_val_if_fail (rtv != NULL, FALSE);
363 g_return_val_if_fail (num_rtv <= GST_VIDEO_MAX_PLANES, FALSE);
364
365 context = gst_d3d11_device_get_device_context_handle (quad->device);
366
367 context->IASetPrimitiveTopology (D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
368 context->IASetInputLayout (quad->layout);
369 context->IASetVertexBuffers (0, 1, &quad->vertex_buffer, &quad->vertex_stride,
370 &offsets);
371 context->IASetIndexBuffer (quad->index_buffer, quad->index_format, 0);
372
373 if (sampler)
374 context->PSSetSamplers (0, num_sampler, sampler);
375 context->VSSetShader (quad->vs, NULL, 0);
376 context->PSSetShader (quad->ps, NULL, 0);
377 context->RSSetViewports (num_viewport, viewport);
378
379 if (quad->num_const_buffers) {
380 context->PSSetConstantBuffers (0, quad->num_const_buffers,
381 quad->const_buffer);
382 }
383
384 if (srv)
385 context->PSSetShaderResources (0, num_srv, srv);
386 context->OMSetRenderTargets (num_rtv, rtv, NULL);
387 context->OMSetBlendState (blend_state, blend_factor, 0xffffffff);
388
389 context->DrawIndexed (quad->index_count, 0, 0);
390
391 if (srv)
392 context->PSSetShaderResources (0, num_srv, clear_view);
393 context->OMSetRenderTargets (0, NULL, NULL);
394
395 return TRUE;
396 }
397