gst: don't use volatile to mean atomic
[platform/upstream/gstreamer.git] / sys / d3d11 / gstd3d11shader.cpp
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
32 G_BEGIN_DECLS
33
34 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_shader_debug);
35 #define GST_CAT_DEFAULT gst_d3d11_shader_debug
36
37 G_END_DECLS
38 /* *INDENT-ON* */
39
40 static GModule *d3d_compiler_module = NULL;
41 static pD3DCompile GstD3DCompileFunc = NULL;
42
43 gboolean
44 gst_d3d11_shader_init (void)
45 {
46   static gsize _init = 0;
47
48   if (g_once_init_enter (&_init)) {
49 #if GST_D3D11_WINAPI_ONLY_APP
50     /* Assuming that d3d compiler library is available */
51     GstD3DCompileFunc = D3DCompile;
52 #else
53     static const gchar *d3d_compiler_names[] = {
54       "d3dcompiler_47.dll",
55       "d3dcompiler_46.dll",
56       "d3dcompiler_45.dll",
57       "d3dcompiler_44.dll",
58       "d3dcompiler_43.dll",
59     };
60     guint i;
61     for (i = 0; i < G_N_ELEMENTS (d3d_compiler_names); i++) {
62       d3d_compiler_module =
63           g_module_open (d3d_compiler_names[i], G_MODULE_BIND_LAZY);
64
65       if (d3d_compiler_module) {
66         GST_INFO ("D3D compiler %s is available", d3d_compiler_names[i]);
67         if (!g_module_symbol (d3d_compiler_module, "D3DCompile",
68                 (gpointer *) & GstD3DCompileFunc)) {
69           GST_ERROR ("Cannot load D3DCompile symbol from %s",
70               d3d_compiler_names[i]);
71           g_module_close (d3d_compiler_module);
72           d3d_compiler_module = NULL;
73           GstD3DCompileFunc = NULL;
74         } else {
75           break;
76         }
77       }
78     }
79
80     if (!GstD3DCompileFunc)
81       GST_WARNING ("D3D11 compiler library is unavailable");
82 #endif
83
84     g_once_init_leave (&_init, 1);
85   }
86
87   return !!GstD3DCompileFunc;
88 }
89
90 static gboolean
91 compile_shader (GstD3D11Device * device, const gchar * shader_source,
92     gboolean is_pixel_shader, ID3DBlob ** blob)
93 {
94   const gchar *shader_target;
95   D3D_FEATURE_LEVEL feature_level;
96   HRESULT hr;
97   ID3D11Device *device_handle;
98   /* *INDENT-OFF* */
99   ComPtr<ID3DBlob> ret;
100   ComPtr<ID3DBlob> error;
101   /* *INDENT-ON* */
102
103   if (!gst_d3d11_shader_init ()) {
104     GST_ERROR ("D3DCompiler is unavailable");
105     return FALSE;
106   }
107
108   device_handle = gst_d3d11_device_get_device_handle (device);
109   feature_level = device_handle->GetFeatureLevel ();
110
111   if (is_pixel_shader) {
112     if (feature_level >= D3D_FEATURE_LEVEL_10_0)
113       shader_target = "ps_4_0";
114     else if (feature_level >= D3D_FEATURE_LEVEL_9_3)
115       shader_target = "ps_4_0_level_9_3";
116     else
117       shader_target = "ps_4_0_level_9_1";
118   } else {
119     if (feature_level >= D3D_FEATURE_LEVEL_10_0)
120       shader_target = "vs_4_0";
121     else if (feature_level >= D3D_FEATURE_LEVEL_9_3)
122       shader_target = "vs_4_0_level_9_3";
123     else
124       shader_target = "vs_4_0_level_9_1";
125   }
126
127   g_assert (GstD3DCompileFunc);
128
129   GST_TRACE ("Compile code \n%s", shader_source);
130
131   hr = GstD3DCompileFunc (shader_source, strlen (shader_source), NULL, NULL,
132       NULL, "main", shader_target, 0, 0, &ret, &error);
133
134   if (!gst_d3d11_result (hr, device)) {
135     const gchar *err = NULL;
136
137     if (error)
138       err = (const gchar *) error->GetBufferPointer ();
139
140     GST_ERROR ("could not compile source, hr: 0x%x, error detail %s",
141         (guint) hr, GST_STR_NULL (err));
142     return FALSE;
143   }
144
145   if (error) {
146     const gchar *err = (const gchar *) error->GetBufferPointer ();
147
148     GST_DEBUG ("HLSL compiler warnings:\n%s\nShader code:\n%s",
149         GST_STR_NULL (err), GST_STR_NULL (shader_source));
150   }
151
152   *blob = ret.Detach ();
153
154   return TRUE;
155 }
156
157 gboolean
158 gst_d3d11_create_pixel_shader (GstD3D11Device * device,
159     const gchar * source, ID3D11PixelShader ** shader)
160 {
161   ID3D11Device *device_handle;
162   HRESULT hr;
163   /* *INDENT-OFF* */
164   ComPtr<ID3DBlob> ps_blob;
165   /* *INDENT-ON* */
166
167   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
168   g_return_val_if_fail (source != NULL, FALSE);
169   g_return_val_if_fail (shader != NULL, FALSE);
170
171   if (!compile_shader (device, source, TRUE, &ps_blob)) {
172     GST_ERROR ("Failed to compile pixel shader");
173     return FALSE;
174   }
175
176   device_handle = gst_d3d11_device_get_device_handle (device);
177   hr = device_handle->CreatePixelShader (ps_blob->GetBufferPointer (),
178       ps_blob->GetBufferSize (), NULL, shader);
179   if (!gst_d3d11_result (hr, device)) {
180     GST_ERROR ("could not create pixel shader, hr: 0x%x", (guint) hr);
181     return FALSE;
182   }
183
184   return TRUE;
185 }
186
187 gboolean
188 gst_d3d11_create_vertex_shader (GstD3D11Device * device, const gchar * source,
189     const D3D11_INPUT_ELEMENT_DESC * input_desc, guint desc_len,
190     ID3D11VertexShader ** shader, ID3D11InputLayout ** layout)
191 {
192   ID3D11Device *device_handle;
193   HRESULT hr;
194   /* *INDENT-OFF* */
195   ComPtr<ID3DBlob> vs_blob;
196   ComPtr<ID3D11VertexShader> vs;
197   ComPtr<ID3D11InputLayout> in_layout;
198   /* *INDENT-ON* */
199
200   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
201   g_return_val_if_fail (source != NULL, FALSE);
202   g_return_val_if_fail (input_desc != NULL, FALSE);
203   g_return_val_if_fail (desc_len > 0, FALSE);
204   g_return_val_if_fail (shader != NULL, FALSE);
205   g_return_val_if_fail (layout != NULL, FALSE);
206
207   if (!compile_shader (device, source, FALSE, &vs_blob)) {
208     GST_ERROR ("Failed to compile shader code");
209     return FALSE;
210   }
211
212   device_handle = gst_d3d11_device_get_device_handle (device);
213   hr = device_handle->CreateVertexShader (vs_blob->GetBufferPointer (),
214       vs_blob->GetBufferSize (), NULL, &vs);
215   if (!gst_d3d11_result (hr, device)) {
216     GST_ERROR ("could not create vertex shader, hr: 0x%x", (guint) hr);
217     return FALSE;
218   }
219
220   hr = device_handle->CreateInputLayout (input_desc,
221       desc_len, vs_blob->GetBufferPointer (),
222       vs_blob->GetBufferSize (), &in_layout);
223   if (!gst_d3d11_result (hr, device)) {
224     GST_ERROR ("could not create input layout shader, hr: 0x%x", (guint) hr);
225     return FALSE;
226   }
227
228   *shader = vs.Detach ();
229   *layout = in_layout.Detach ();
230
231   return TRUE;
232 }
233
234 struct _GstD3D11Quad
235 {
236   GstD3D11Device *device;
237   ID3D11PixelShader *ps;
238   ID3D11VertexShader *vs;
239   ID3D11InputLayout *layout;
240   ID3D11SamplerState *sampler;
241   ID3D11BlendState *blend;
242   ID3D11DepthStencilState *depth_stencil;
243   ID3D11Buffer *const_buffer;
244   ID3D11Buffer *vertex_buffer;
245   guint vertex_stride;
246   ID3D11Buffer *index_buffer;
247   DXGI_FORMAT index_format;
248   guint index_count;
249   D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES];
250   ID3D11ShaderResourceView *srv[GST_VIDEO_MAX_PLANES];
251   guint num_srv;
252   ID3D11RenderTargetView *rtv[GST_VIDEO_MAX_PLANES];
253   guint num_rtv;
254 };
255
256 GstD3D11Quad *
257 gst_d3d11_quad_new (GstD3D11Device * device, ID3D11PixelShader * pixel_shader,
258     ID3D11VertexShader * vertex_shader, ID3D11InputLayout * layout,
259     ID3D11SamplerState * sampler, ID3D11BlendState * blend,
260     ID3D11DepthStencilState * depth_stencil,
261     ID3D11Buffer * const_buffer,
262     ID3D11Buffer * vertex_buffer, guint vertex_stride,
263     ID3D11Buffer * index_buffer, DXGI_FORMAT index_format, guint index_count)
264 {
265   GstD3D11Quad *quad;
266
267   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
268   g_return_val_if_fail (pixel_shader != NULL, NULL);
269   g_return_val_if_fail (vertex_shader != NULL, NULL);
270   g_return_val_if_fail (layout != NULL, NULL);
271   g_return_val_if_fail (vertex_buffer != NULL, NULL);
272   g_return_val_if_fail (vertex_stride > 0, NULL);
273   g_return_val_if_fail (index_buffer != NULL, NULL);
274   g_return_val_if_fail (index_format != DXGI_FORMAT_UNKNOWN, NULL);
275
276   quad = g_new0 (GstD3D11Quad, 1);
277
278   quad->device = (GstD3D11Device *) gst_object_ref (device);
279   quad->ps = pixel_shader;
280   quad->vs = vertex_shader;
281   quad->layout = layout;
282   quad->sampler = sampler;
283   quad->blend = blend;
284   quad->depth_stencil = depth_stencil;
285   quad->vertex_buffer = vertex_buffer;
286   quad->vertex_stride = vertex_stride;
287   quad->index_buffer = index_buffer;
288   quad->index_format = index_format;
289   quad->index_count = index_count;
290
291   pixel_shader->AddRef ();
292   vertex_shader->AddRef ();
293   layout->AddRef ();
294   vertex_buffer->AddRef ();
295   index_buffer->AddRef ();
296
297   if (sampler)
298     sampler->AddRef ();
299
300   if (blend)
301     blend->AddRef ();
302
303   if (depth_stencil)
304     depth_stencil->AddRef ();
305
306   if (const_buffer) {
307     quad->const_buffer = const_buffer;
308     const_buffer->AddRef ();
309   }
310
311   return quad;
312 }
313
314 void
315 gst_d3d11_quad_free (GstD3D11Quad * quad)
316 {
317   g_return_if_fail (quad != NULL);
318
319   GST_D3D11_CLEAR_COM (quad->ps);
320   GST_D3D11_CLEAR_COM (quad->vs);
321   GST_D3D11_CLEAR_COM (quad->layout);
322   GST_D3D11_CLEAR_COM (quad->sampler);
323   GST_D3D11_CLEAR_COM (quad->blend);
324   GST_D3D11_CLEAR_COM (quad->depth_stencil);
325   GST_D3D11_CLEAR_COM (quad->const_buffer);
326   GST_D3D11_CLEAR_COM (quad->vertex_buffer);
327   GST_D3D11_CLEAR_COM (quad->index_buffer);
328
329   gst_clear_object (&quad->device);
330   g_free (quad);
331 }
332
333 gboolean
334 gst_d3d11_draw_quad (GstD3D11Quad * quad,
335     D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES], guint num_viewport,
336     ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES], guint num_srv,
337     ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES], guint num_rtv,
338     ID3D11DepthStencilView * dsv, ID3D11BlendState * blend,
339     gfloat blend_factor[4])
340 {
341   gboolean ret;
342
343   g_return_val_if_fail (quad != NULL, FALSE);
344
345   gst_d3d11_device_lock (quad->device);
346   ret = gst_d3d11_draw_quad_unlocked (quad, viewport, num_viewport,
347       srv, num_srv, rtv, num_viewport, dsv, blend, blend_factor);
348   gst_d3d11_device_unlock (quad->device);
349
350   return ret;
351 }
352
353 gboolean
354 gst_d3d11_draw_quad_unlocked (GstD3D11Quad * quad,
355     D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES], guint num_viewport,
356     ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES], guint num_srv,
357     ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES], guint num_rtv,
358     ID3D11DepthStencilView * dsv, ID3D11BlendState * blend,
359     gfloat blend_factor[4])
360 {
361   ID3D11DeviceContext *context;
362   UINT offsets = 0;
363   ID3D11ShaderResourceView *clear_view[GST_VIDEO_MAX_PLANES] = { NULL, };
364   ID3D11BlendState *blend_state = blend;
365
366   g_return_val_if_fail (quad != NULL, FALSE);
367   g_return_val_if_fail (viewport != NULL, FALSE);
368   g_return_val_if_fail (num_viewport <= GST_VIDEO_MAX_PLANES, FALSE);
369   g_return_val_if_fail (rtv != NULL, FALSE);
370   g_return_val_if_fail (num_rtv <= GST_VIDEO_MAX_PLANES, FALSE);
371
372   context = gst_d3d11_device_get_device_context_handle (quad->device);
373
374   context->IASetPrimitiveTopology (D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
375   context->IASetInputLayout (quad->layout);
376   context->IASetVertexBuffers (0, 1, &quad->vertex_buffer, &quad->vertex_stride,
377       &offsets);
378   context->IASetIndexBuffer (quad->index_buffer, quad->index_format, 0);
379
380   if (quad->sampler)
381     context->PSSetSamplers (0, 1, &quad->sampler);
382   context->VSSetShader (quad->vs, NULL, 0);
383   context->PSSetShader (quad->ps, NULL, 0);
384   context->RSSetViewports (num_viewport, viewport);
385
386   if (quad->const_buffer)
387     context->PSSetConstantBuffers (0, 1, &quad->const_buffer);
388
389   if (srv)
390     context->PSSetShaderResources (0, num_srv, srv);
391   context->OMSetRenderTargets (num_rtv, rtv, dsv);
392   if (!blend_state)
393     blend_state = quad->blend;
394   context->OMSetBlendState (blend_state, blend_factor, 0xffffffff);
395   context->OMSetDepthStencilState (quad->depth_stencil, 1);
396
397   context->DrawIndexed (quad->index_count, 0, 0);
398
399   if (srv)
400     context->PSSetShaderResources (0, num_srv, clear_view);
401   context->OMSetRenderTargets (0, NULL, NULL);
402
403   return TRUE;
404 }