a90e319c290cbdb4f79bbf44ebd8f68eff73a2d8
[platform/upstream/gstreamer.git] / sys / d3d11 / gstd3d11overlaycompositor.c
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 "gstd3d11overlaycompositor.h"
25 #include "gstd3d11utils.h"
26 #include "gstd3d11device.h"
27 #include "gstd3d11shader.h"
28 #include "gstd3d11format.h"
29
30 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_overlay_compositor_debug);
31 #define GST_CAT_DEFAULT gst_d3d11_overlay_compositor_debug
32
33 /* *INDENT-OFF* */
34 typedef struct
35 {
36   struct {
37     FLOAT x;
38     FLOAT y;
39     FLOAT z;
40   } position;
41   struct {
42     FLOAT x;
43     FLOAT y;
44   } texture;
45 } VertexData;
46
47 static const gchar templ_pixel_shader[] =
48     "Texture2D shaderTexture;\n"
49     "SamplerState samplerState;\n"
50     "\n"
51     "struct PS_INPUT\n"
52     "{\n"
53     "  float4 Position: SV_POSITION;\n"
54     "  float3 Texture: TEXCOORD0;\n"
55     "};\n"
56     "\n"
57     "float4 main(PS_INPUT input): SV_TARGET\n"
58     "{\n"
59     "  return shaderTexture.Sample(samplerState, input.Texture);\n"
60     "}\n";
61
62 static const gchar templ_vertex_shader[] =
63     "struct VS_INPUT\n"
64     "{\n"
65     "  float4 Position : POSITION;\n"
66     "  float4 Texture : TEXCOORD0;\n"
67     "};\n"
68     "\n"
69     "struct VS_OUTPUT\n"
70     "{\n"
71     "  float4 Position: SV_POSITION;\n"
72     "  float4 Texture: TEXCOORD0;\n"
73     "};\n"
74     "\n"
75     "VS_OUTPUT main(VS_INPUT input)\n"
76     "{\n"
77     "  return input;\n"
78     "}\n";
79 /* *INDENT-ON* */
80
81 struct _GstD3D11OverlayCompositor
82 {
83   GstD3D11Device *device;
84   GstVideoInfo out_info;
85
86   D3D11_VIEWPORT viewport;
87
88   ID3D11PixelShader *ps;
89   ID3D11VertexShader *vs;
90   ID3D11InputLayout *layout;
91   ID3D11SamplerState *sampler;
92   ID3D11BlendState *blend;
93   ID3D11Buffer *index_buffer;
94
95   /* GstD3D11CompositionOverlay */
96   GList *overlays;
97 };
98
99 typedef struct
100 {
101   GstVideoOverlayRectangle *overlay_rect;
102   ID3D11Texture2D *texture;
103   ID3D11ShaderResourceView *srv;
104   GstD3D11Quad *quad;
105 } GstD3D11CompositionOverlay;
106
107 static GstD3D11CompositionOverlay *
108 gst_d3d11_composition_overlay_new (GstD3D11OverlayCompositor * self,
109     GstVideoOverlayRectangle * overlay_rect)
110 {
111   GstD3D11CompositionOverlay *overlay = NULL;
112   gint x, y;
113   guint width, height;
114   D3D11_SUBRESOURCE_DATA subresource_data = { 0, };
115   D3D11_TEXTURE2D_DESC texture_desc = { 0, };
116   D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = { 0, };
117   D3D11_BUFFER_DESC buffer_desc = { 0, };
118   ID3D11Buffer *vertex_buffer = NULL;
119   D3D11_MAPPED_SUBRESOURCE map;
120   VertexData *vertex_data;
121   GstBuffer *buf;
122   GstVideoMeta *vmeta;
123   GstMapInfo info;
124   guint8 *data;
125   gint stride;
126   ID3D11Texture2D *texture = NULL;
127   ID3D11ShaderResourceView *srv = NULL;
128   HRESULT hr;
129   ID3D11Device *device_handle;
130   ID3D11DeviceContext *context_handle;
131   GstD3D11Device *device = self->device;
132   const guint index_count = 2 * 3;
133   FLOAT x1, y1, x2, y2;
134
135   g_return_val_if_fail (overlay_rect != NULL, NULL);
136
137   device_handle = gst_d3d11_device_get_device_handle (device);
138   context_handle = gst_d3d11_device_get_device_context_handle (device);
139
140   if (!gst_video_overlay_rectangle_get_render_rectangle (overlay_rect, &x, &y,
141           &width, &height)) {
142     GST_ERROR ("Failed to get render rectangle");
143     return NULL;
144   }
145
146   buf = gst_video_overlay_rectangle_get_pixels_unscaled_argb (overlay_rect,
147       GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
148   if (!buf) {
149     GST_ERROR ("Failed to get overlay buffer");
150     return NULL;
151   }
152
153   vmeta = gst_buffer_get_video_meta (buf);
154   if (!vmeta) {
155     GST_ERROR ("Failed to get video meta");
156     return NULL;
157   }
158
159   if (!gst_video_meta_map (vmeta,
160           0, &info, (gpointer *) & data, &stride, GST_MAP_READ)) {
161     GST_ERROR ("Failed to map");
162     return NULL;
163   }
164
165   /* Do create texture and upload data at once, for create immutable texture */
166   subresource_data.pSysMem = data;
167   subresource_data.SysMemPitch = stride;
168   subresource_data.SysMemSlicePitch = 0;
169
170   texture_desc.Width = width;
171   texture_desc.Height = height;
172   texture_desc.MipLevels = 1;
173   texture_desc.ArraySize = 1;
174   /* FIXME: need to consider non-BGRA ? */
175   texture_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
176   texture_desc.SampleDesc.Count = 1;
177   texture_desc.SampleDesc.Quality = 0;
178   texture_desc.Usage = D3D11_USAGE_IMMUTABLE;
179   texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
180   texture_desc.CPUAccessFlags = 0;
181
182   texture = gst_d3d11_device_create_texture (device,
183       &texture_desc, &subresource_data);
184   gst_video_meta_unmap (vmeta, 0, &info);
185
186   if (!texture) {
187     GST_ERROR ("Failed to create texture");
188     return NULL;
189   }
190
191   srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
192   srv_desc.Texture2D.MipLevels = 1;
193
194   hr = ID3D11Device_CreateShaderResourceView (device_handle,
195       (ID3D11Resource *) texture, &srv_desc, &srv);
196   if (!gst_d3d11_result (hr, device) || !srv) {
197     GST_ERROR ("Failed to create shader resource view");
198     goto clear;
199   }
200
201   buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
202   buffer_desc.ByteWidth = sizeof (VertexData) * 4;
203   buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
204   buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
205
206   hr = ID3D11Device_CreateBuffer (device_handle, &buffer_desc, NULL,
207       &vertex_buffer);
208   if (!gst_d3d11_result (hr, device)) {
209     GST_ERROR ("Couldn't create vertex buffer, hr: 0x%x", (guint) hr);
210     goto clear;
211   }
212
213   gst_d3d11_device_lock (device);
214   hr = ID3D11DeviceContext_Map (context_handle,
215       (ID3D11Resource *) vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
216
217   if (!gst_d3d11_result (hr, device)) {
218     GST_ERROR ("Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
219     gst_d3d11_device_unlock (device);
220     goto clear;
221   }
222
223   vertex_data = (VertexData *) map.pData;
224   x1 = (x / (gfloat) GST_VIDEO_INFO_WIDTH (&self->out_info)) * 2.0f - 1.0f;
225   y1 = (y / (gfloat) GST_VIDEO_INFO_HEIGHT (&self->out_info)) * 2.0f - 1.0f;
226
227   x2 = ((x + width) /
228       (gfloat) GST_VIDEO_INFO_WIDTH (&self->out_info)) * 2.0f - 1.0f;
229   y2 = ((y + height) /
230       (gfloat) GST_VIDEO_INFO_HEIGHT (&self->out_info)) * 2.0f - 1.0f;
231
232   vertex_data[0].position.x = x1;
233   vertex_data[0].position.y = y1;
234   vertex_data[0].position.z = 0.0f;
235   vertex_data[0].texture.x = 0.0f;
236   vertex_data[0].texture.y = 1.0f;
237
238   vertex_data[1].position.x = x1;
239   vertex_data[1].position.y = y2;
240   vertex_data[1].position.z = 0.0f;
241   vertex_data[1].texture.x = 0.0f;
242   vertex_data[1].texture.y = 0.0f;
243
244   vertex_data[2].position.x = x2;
245   vertex_data[2].position.y = y2;
246   vertex_data[2].position.z = 0.0f;
247   vertex_data[2].texture.x = 1.0f;
248   vertex_data[2].texture.y = 0.0f;
249
250   vertex_data[3].position.x = x2;
251   vertex_data[3].position.y = y1;
252   vertex_data[3].position.z = 0.0f;
253   vertex_data[3].texture.x = 1.0f;
254   vertex_data[3].texture.y = 1.0f;
255
256   ID3D11DeviceContext_Unmap (context_handle,
257       (ID3D11Resource *) vertex_buffer, 0);
258   gst_d3d11_device_unlock (device);
259
260   overlay = g_new0 (GstD3D11CompositionOverlay, 1);
261   overlay->overlay_rect = gst_video_overlay_rectangle_ref (overlay_rect);
262   overlay->texture = texture;
263   overlay->srv = srv;
264   overlay->quad = gst_d3d11_quad_new (device,
265       self->ps, self->vs, self->layout, self->sampler, self->blend, NULL, NULL,
266       vertex_buffer, sizeof (VertexData),
267       self->index_buffer, DXGI_FORMAT_R16_UINT, index_count);
268
269 clear:
270   if (!overlay) {
271     if (srv)
272       ID3D11ShaderResourceView_Release (srv);
273     if (texture)
274       ID3D11Texture2D_Release (texture);
275   }
276
277   if (vertex_buffer)
278     ID3D11Buffer_Release (vertex_buffer);
279
280   return overlay;
281 }
282
283 static void
284 gst_d3d11_composition_overlay_free (GstD3D11CompositionOverlay * overlay)
285 {
286   if (!overlay)
287     return;
288
289   if (overlay->overlay_rect)
290     gst_video_overlay_rectangle_unref (overlay->overlay_rect);
291
292   if (overlay->srv)
293     ID3D11ShaderResourceView_Release (overlay->srv);
294
295   if (overlay->texture)
296     ID3D11Texture2D_Release (overlay->texture);
297
298   if (overlay->quad)
299     gst_d3d11_quad_free (overlay->quad);
300
301   g_free (overlay);
302 }
303
304 static gboolean
305 gst_d3d11_overlay_compositor_setup_shader (GstD3D11OverlayCompositor * self,
306     GstD3D11Device * device)
307 {
308   HRESULT hr;
309   D3D11_SAMPLER_DESC sampler_desc = { 0, };
310   D3D11_INPUT_ELEMENT_DESC input_desc[2] = { 0, };
311   D3D11_BUFFER_DESC buffer_desc = { 0, };
312   D3D11_BLEND_DESC blend_desc = { 0, };
313   D3D11_MAPPED_SUBRESOURCE map;
314   WORD *indices;
315   ID3D11Device *device_handle;
316   ID3D11DeviceContext *context_handle;
317   ID3D11PixelShader *ps = NULL;
318   ID3D11VertexShader *vs = NULL;
319   ID3D11InputLayout *layout = NULL;
320   ID3D11SamplerState *sampler = NULL;
321   ID3D11BlendState *blend = NULL;
322   ID3D11Buffer *index_buffer = NULL;
323   const guint index_count = 2 * 3;
324   gboolean ret = TRUE;
325
326   device_handle = gst_d3d11_device_get_device_handle (device);
327   context_handle = gst_d3d11_device_get_device_context_handle (device);
328
329   /* bilinear filtering */
330   sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
331   sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
332   sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
333   sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
334   sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
335   sampler_desc.MinLOD = 0;
336   sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
337
338   hr = ID3D11Device_CreateSamplerState (device_handle, &sampler_desc, &sampler);
339   if (!gst_d3d11_result (hr, device)) {
340     GST_ERROR ("Couldn't create sampler state, hr: 0x%x", (guint) hr);
341     ret = FALSE;
342     goto clear;
343   }
344
345   GST_LOG ("Create Pixel Shader \n%s", templ_pixel_shader);
346
347   if (!gst_d3d11_create_pixel_shader (device, templ_pixel_shader, &ps)) {
348     GST_ERROR ("Couldn't create pixel shader");
349     ret = FALSE;
350     goto clear;
351   }
352
353   input_desc[0].SemanticName = "POSITION";
354   input_desc[0].SemanticIndex = 0;
355   input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
356   input_desc[0].InputSlot = 0;
357   input_desc[0].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
358   input_desc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
359   input_desc[0].InstanceDataStepRate = 0;
360
361   input_desc[1].SemanticName = "TEXCOORD";
362   input_desc[1].SemanticIndex = 0;
363   input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT;
364   input_desc[1].InputSlot = 0;
365   input_desc[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
366   input_desc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
367   input_desc[1].InstanceDataStepRate = 0;
368
369   if (!gst_d3d11_create_vertex_shader (device, templ_vertex_shader,
370           input_desc, G_N_ELEMENTS (input_desc), &vs, &layout)) {
371     GST_ERROR ("Couldn't vertex pixel shader");
372     ret = FALSE;
373     goto clear;
374   }
375
376   blend_desc.AlphaToCoverageEnable = FALSE;
377   blend_desc.IndependentBlendEnable = FALSE;
378   blend_desc.RenderTarget[0].BlendEnable = TRUE;
379   blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
380   blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
381   blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
382   blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
383   blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
384   blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
385   blend_desc.RenderTarget[0].RenderTargetWriteMask =
386       D3D11_COLOR_WRITE_ENABLE_ALL;
387
388   hr = ID3D11Device_CreateBlendState (device_handle, &blend_desc, &blend);
389   if (!gst_d3d11_result (hr, device)) {
390     GST_ERROR ("Couldn't create blend staten, hr: 0x%x", (guint) hr);
391     ret = FALSE;
392     goto clear;
393   }
394
395   buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
396   buffer_desc.ByteWidth = sizeof (WORD) * index_count;
397   buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
398   buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
399
400   hr = ID3D11Device_CreateBuffer (device_handle, &buffer_desc, NULL,
401       &index_buffer);
402   if (!gst_d3d11_result (hr, device)) {
403     GST_ERROR ("Couldn't create index buffer, hr: 0x%x", (guint) hr);
404     ret = FALSE;
405     goto clear;
406   }
407
408   gst_d3d11_device_lock (device);
409   hr = ID3D11DeviceContext_Map (context_handle,
410       (ID3D11Resource *) index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
411
412   if (!gst_d3d11_result (hr, device)) {
413     GST_ERROR ("Couldn't map index buffer, hr: 0x%x", (guint) hr);
414     gst_d3d11_device_unlock (device);
415     ret = FALSE;
416     goto clear;
417   }
418
419   indices = (WORD *) map.pData;
420
421   /* clockwise indexing */
422   indices[0] = 0;               /* bottom left */
423   indices[1] = 1;               /* top left */
424   indices[2] = 2;               /* top right */
425
426   indices[3] = 3;               /* bottom right */
427   indices[4] = 0;               /* bottom left  */
428   indices[5] = 2;               /* top right */
429
430   ID3D11DeviceContext_Unmap (context_handle,
431       (ID3D11Resource *) index_buffer, 0);
432   gst_d3d11_device_unlock (device);
433
434   self->ps = ps;
435   self->vs = vs;
436   self->layout = layout;
437   self->sampler = sampler;
438   self->blend = blend;
439   self->index_buffer = index_buffer;
440
441 clear:
442   if (ret)
443     return TRUE;
444
445   if (ps)
446     ID3D11PixelShader_Release (ps);
447   if (vs)
448     ID3D11VertexShader_Release (vs);
449   if (layout)
450     ID3D11InputLayout_Release (layout);
451   if (sampler)
452     ID3D11SamplerState_Release (sampler);
453   if (blend)
454     ID3D11BlendState_Release (blend);
455   if (index_buffer)
456     ID3D11Buffer_Release (index_buffer);
457
458   return FALSE;
459 }
460
461
462 GstD3D11OverlayCompositor *
463 gst_d3d11_overlay_compositor_new (GstD3D11Device * device,
464     GstVideoInfo * out_info)
465 {
466   GstD3D11OverlayCompositor *compositor = NULL;
467
468   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
469   g_return_val_if_fail (out_info != NULL, NULL);
470
471   compositor = g_new0 (GstD3D11OverlayCompositor, 1);
472
473   if (!gst_d3d11_overlay_compositor_setup_shader (compositor, device)) {
474     gst_d3d11_overlay_compositor_free (compositor);
475     return NULL;
476   }
477
478   compositor->device = gst_object_ref (device);
479   compositor->out_info = *out_info;
480
481   compositor->viewport.TopLeftX = 0;
482   compositor->viewport.TopLeftY = 0;
483   compositor->viewport.Width = GST_VIDEO_INFO_WIDTH (out_info);
484   compositor->viewport.Height = GST_VIDEO_INFO_HEIGHT (out_info);
485   compositor->viewport.MinDepth = 0.0f;
486   compositor->viewport.MaxDepth = 1.0f;
487
488   return compositor;
489 }
490
491 void
492 gst_d3d11_overlay_compositor_free (GstD3D11OverlayCompositor * compositor)
493 {
494   g_return_if_fail (compositor != NULL);
495
496   gst_d3d11_overlay_compositor_free_overlays (compositor);
497
498   if (compositor->ps)
499     ID3D11PixelShader_Release (compositor->ps);
500   if (compositor->vs)
501     ID3D11VertexShader_Release (compositor->vs);
502   if (compositor->layout)
503     ID3D11InputLayout_Release (compositor->layout);
504   if (compositor->sampler)
505     ID3D11SamplerState_Release (compositor->sampler);
506   if (compositor->blend)
507     ID3D11BlendState_Release (compositor->blend);
508   if (compositor->index_buffer)
509     ID3D11Buffer_Release (compositor->index_buffer);
510
511   gst_clear_object (&compositor->device);
512   g_free (compositor);
513 }
514
515 static gint
516 find_in_compositor (const GstD3D11CompositionOverlay * overlay,
517     const GstVideoOverlayRectangle * rect)
518 {
519   return !(overlay->overlay_rect == rect);
520 }
521
522 static gboolean
523 is_in_video_overlay_composition (GstVideoOverlayComposition * voc,
524     GstD3D11CompositionOverlay * overlay)
525 {
526   guint i;
527
528   for (i = 0; i < gst_video_overlay_composition_n_rectangles (voc); i++) {
529     GstVideoOverlayRectangle *rectangle =
530         gst_video_overlay_composition_get_rectangle (voc, i);
531     if (overlay->overlay_rect == rectangle)
532       return TRUE;
533   }
534   return FALSE;
535 }
536
537 gboolean
538 gst_d3d11_overlay_compositor_upload (GstD3D11OverlayCompositor * compositor,
539     GstBuffer * buf)
540 {
541   GstVideoOverlayCompositionMeta *meta;
542   gint i, num_overlays;
543   GList *iter;
544
545   g_return_val_if_fail (compositor != NULL, FALSE);
546   g_return_val_if_fail (GST_IS_BUFFER (buf), FALSE);
547
548   meta = gst_buffer_get_video_overlay_composition_meta (buf);
549
550   if (!meta) {
551     gst_d3d11_overlay_compositor_free_overlays (compositor);
552     return TRUE;
553   }
554
555   num_overlays = gst_video_overlay_composition_n_rectangles (meta->overlay);
556   if (!num_overlays) {
557     gst_d3d11_overlay_compositor_free_overlays (compositor);
558     return TRUE;
559   }
560
561   GST_LOG ("Upload %d overlay rectangles", num_overlays);
562
563   /* Upload new overlay */
564   for (i = 0; i < num_overlays; i++) {
565     GstVideoOverlayRectangle *rectangle =
566         gst_video_overlay_composition_get_rectangle (meta->overlay, i);
567
568     if (!g_list_find_custom (compositor->overlays,
569             rectangle, (GCompareFunc) find_in_compositor)) {
570       GstD3D11CompositionOverlay *overlay = NULL;
571
572       overlay = gst_d3d11_composition_overlay_new (compositor, rectangle);
573
574       if (!overlay)
575         return FALSE;
576
577       compositor->overlays = g_list_append (compositor->overlays, overlay);
578     }
579   }
580
581   /* Remove old overlay */
582   iter = compositor->overlays;
583   while (iter) {
584     GstD3D11CompositionOverlay *overlay =
585         (GstD3D11CompositionOverlay *) iter->data;
586     GList *next = iter->next;
587
588     if (!is_in_video_overlay_composition (meta->overlay, overlay)) {
589       compositor->overlays = g_list_delete_link (compositor->overlays, iter);
590       gst_d3d11_composition_overlay_free (overlay);
591     }
592
593     iter = next;
594   }
595
596   return TRUE;
597 }
598
599 void
600 gst_d3d11_overlay_compositor_free_overlays (GstD3D11OverlayCompositor *
601     compositor)
602 {
603   g_return_if_fail (compositor != NULL);
604
605   if (compositor->overlays) {
606     g_list_free_full (compositor->overlays,
607         (GDestroyNotify) gst_d3d11_composition_overlay_free);
608
609     compositor->overlays = NULL;
610   }
611 }
612
613 gboolean
614 gst_d3d11_overlay_compositor_update_rect (GstD3D11OverlayCompositor *
615     compositor, RECT * rect)
616 {
617   g_return_val_if_fail (compositor != NULL, FALSE);
618   g_return_val_if_fail (rect != NULL, FALSE);
619
620   compositor->viewport.TopLeftX = rect->left;
621   compositor->viewport.TopLeftY = rect->top;
622   compositor->viewport.Width = rect->right - rect->left;
623   compositor->viewport.Height = rect->bottom - rect->top;
624
625   return TRUE;
626 }
627
628 gboolean
629 gst_d3d11_overlay_compositor_draw (GstD3D11OverlayCompositor * compositor,
630     ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES])
631 {
632   gboolean ret = TRUE;
633
634   g_return_val_if_fail (compositor != NULL, FALSE);
635   g_return_val_if_fail (rtv != NULL, FALSE);
636
637   gst_d3d11_device_lock (compositor->device);
638   ret = gst_d3d11_overlay_compositor_draw_unlocked (compositor, rtv);
639   gst_d3d11_device_unlock (compositor->device);
640
641   return ret;
642 }
643
644 gboolean
645 gst_d3d11_overlay_compositor_draw_unlocked (GstD3D11OverlayCompositor *
646     compositor, ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES])
647 {
648   gboolean ret = TRUE;
649   GList *iter;
650
651   g_return_val_if_fail (compositor != NULL, FALSE);
652   g_return_val_if_fail (rtv != NULL, FALSE);
653
654   for (iter = compositor->overlays; iter; iter = g_list_next (iter)) {
655     GstD3D11CompositionOverlay *overlay =
656         (GstD3D11CompositionOverlay *) iter->data;
657
658     ret = gst_d3d11_draw_quad_unlocked (overlay->quad,
659         &compositor->viewport, 1, &overlay->srv, 1, rtv, 1, NULL);
660
661     if (!ret)
662       break;
663   }
664
665   return ret;
666 }