3 * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
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.
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.
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.
25 #include "gstd3d11window_dummy.h"
26 #include "gstd3d11pluginutils.h"
30 using namespace Microsoft::WRL;
33 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_window_debug);
34 #define GST_CAT_DEFAULT gst_d3d11_window_debug
36 struct _GstD3D11WindowDummy
38 GstD3D11Window parent;
40 ID3D11Texture2D *fallback_texture;
41 ID3D11VideoProcessorOutputView *fallback_pov;
42 ID3D11RenderTargetView *fallback_rtv;
45 #define gst_d3d11_window_dummy_parent_class parent_class
46 G_DEFINE_TYPE (GstD3D11WindowDummy, gst_d3d11_window_dummy,
47 GST_TYPE_D3D11_WINDOW);
49 static void gst_d3d11_window_dummy_on_resize (GstD3D11Window * window,
50 guint width, guint height);
51 static gboolean gst_d3d11_window_dummy_prepare (GstD3D11Window * window,
52 guint display_width, guint display_height, GstCaps * caps, GError ** error);
54 gst_d3d11_window_dummy_open_shared_handle (GstD3D11Window * window,
55 GstD3D11WindowSharedHandleData * data);
57 gst_d3d11_window_dummy_release_shared_handle (GstD3D11Window * window,
58 GstD3D11WindowSharedHandleData * data);
61 gst_d3d11_window_dummy_class_init (GstD3D11WindowDummyClass * klass)
63 GstD3D11WindowClass *window_class = GST_D3D11_WINDOW_CLASS (klass);
65 window_class->on_resize =
66 GST_DEBUG_FUNCPTR (gst_d3d11_window_dummy_on_resize);
67 window_class->prepare = GST_DEBUG_FUNCPTR (gst_d3d11_window_dummy_prepare);
68 window_class->open_shared_handle =
69 GST_DEBUG_FUNCPTR (gst_d3d11_window_dummy_open_shared_handle);
70 window_class->release_shared_handle =
71 GST_DEBUG_FUNCPTR (gst_d3d11_window_dummy_release_shared_handle);
75 gst_d3d11_window_dummy_init (GstD3D11WindowDummy * self)
80 gst_d3d11_window_dummy_prepare (GstD3D11Window * window,
81 guint display_width, guint display_height, GstCaps * caps, GError ** error)
83 GstD3D11ConverterMethod method = GST_D3D11_CONVERTER_METHOD_SHADER;
85 if (!window->allocator) {
87 (GstD3D11Allocator *) gst_allocator_find (GST_D3D11_MEMORY_NAME);
88 if (!window->allocator) {
89 GST_ERROR_OBJECT (window, "Allocator is unavailable");
94 gst_clear_object (&window->compositor);
95 gst_clear_object (&window->converter);
97 /* We are supporting only RGBA, BGRA or RGB10A2_LE formats but we don't know
98 * which format texture will be used at this moment */
100 gst_video_info_from_caps (&window->info, caps);
101 window->render_rect.left = 0;
102 window->render_rect.top = 0;
103 window->render_rect.right = display_width;
104 window->render_rect.bottom = display_height;
106 window->input_rect.left = 0;
107 window->input_rect.top = 0;
108 window->input_rect.right = GST_VIDEO_INFO_WIDTH (&window->info);
109 window->input_rect.bottom = GST_VIDEO_INFO_HEIGHT (&window->info);
111 gst_video_info_set_format (&window->render_info,
112 GST_VIDEO_FORMAT_BGRA, display_width, display_height);
114 /* TODO: not sure which colorspace should be used, let's use BT709 since
115 * it's default and most common one */
116 window->render_info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
117 window->render_info.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
118 window->render_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
120 gst_d3d11_device_lock (window->device);
121 window->converter = gst_d3d11_converter_new (window->device, &window->info,
122 &window->render_info, &method);
124 if (!window->converter) {
125 GST_ERROR_OBJECT (window, "Cannot create converter");
126 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
127 "Cannot create converter");
132 gst_d3d11_overlay_compositor_new (window->device, &window->render_info);
133 if (!window->compositor) {
134 GST_ERROR_OBJECT (window, "Cannot create overlay compositor");
135 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
136 "Cannot create overlay compositor");
140 gst_d3d11_device_unlock (window->device);
145 gst_d3d11_device_unlock (window->device);
151 gst_d3d11_window_dummy_on_resize (GstD3D11Window * window,
152 guint width, guint height)
154 GstVideoRectangle src_rect, dst_rect, rst_rect;
161 if (window->force_aspect_ratio) {
164 src_rect.w = GST_VIDEO_INFO_WIDTH (&window->render_info);
165 src_rect.h = GST_VIDEO_INFO_HEIGHT (&window->render_info);
167 gst_video_sink_center_rect (src_rect, dst_rect, &rst_rect, TRUE);
172 window->render_rect.left = rst_rect.x;
173 window->render_rect.top = rst_rect.y;
174 window->render_rect.right = rst_rect.x + rst_rect.w;
175 window->render_rect.bottom = rst_rect.y + rst_rect.h;
177 window->first_present = TRUE;
181 gst_d3d11_window_dummy_open_shared_handle (GstD3D11Window * window,
182 GstD3D11WindowSharedHandleData * data)
184 GstD3D11Device *device = window->device;
185 ID3D11Device *device_handle;
187 ComPtr < ID3D11Texture2D > texture;
188 ComPtr < IDXGIKeyedMutex > keyed_mutex;
189 ID3D11RenderTargetView *rtv;
191 GstD3D11Memory *dmem;
192 D3D11_TEXTURE2D_DESC desc;
193 gboolean use_keyed_mutex = FALSE;
195 device_handle = gst_d3d11_device_get_device_handle (device);
197 if ((data->texture_misc_flags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE) ==
198 D3D11_RESOURCE_MISC_SHARED_NTHANDLE) {
199 ComPtr < ID3D11Device1 > device1_handle;
201 hr = device_handle->QueryInterface (IID_PPV_ARGS (&device1_handle));
202 if (!gst_d3d11_result (hr, device))
205 hr = device1_handle->OpenSharedResource1 (data->shared_handle,
206 IID_PPV_ARGS (&texture));
208 hr = device_handle->OpenSharedResource (data->shared_handle,
209 IID_PPV_ARGS (&texture));
212 if (!gst_d3d11_result (hr, device))
215 texture->GetDesc (&desc);
216 use_keyed_mutex = (desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX) ==
217 D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
219 if (use_keyed_mutex) {
220 hr = texture->QueryInterface (IID_PPV_ARGS (&keyed_mutex));
221 if (!gst_d3d11_result (hr, device)) {
222 GST_ERROR_OBJECT (window, "Keyed mutex is unavailable");
227 mem = gst_d3d11_allocator_alloc_wrapped_native_size (window->allocator,
228 device, texture.Get (), nullptr, nullptr);
230 GST_ERROR_OBJECT (window, "Couldn't allocate memory");
234 dmem = GST_D3D11_MEMORY_CAST (mem);
235 rtv = gst_d3d11_memory_get_render_target_view (dmem, 0);
237 GST_ERROR_OBJECT (window, "Render target view is unavailable");
238 gst_memory_unref (mem);
243 hr = keyed_mutex->AcquireSync (data->acquire_key, INFINITE);
244 if (!gst_d3d11_result (hr, device)) {
245 GST_ERROR_OBJECT (window, "Couldn't acquire sync");
246 gst_memory_unref (mem);
251 /* Everything is prepared now */
252 gst_d3d11_window_dummy_on_resize (window, desc.Width, desc.Height);
254 /* Move owned resources */
255 data->render_target = gst_buffer_new ();
256 gst_buffer_append_memory (data->render_target, mem);
258 data->keyed_mutex = keyed_mutex.Detach ();
264 gst_d3d11_window_dummy_release_shared_handle (GstD3D11Window * window,
265 GstD3D11WindowSharedHandleData * data)
267 GstD3D11WindowDummy *self = GST_D3D11_WINDOW_DUMMY (window);
268 GstD3D11Device *device = window->device;
271 /* TODO: cache owned resource for the later reuse? */
272 if (data->keyed_mutex) {
273 hr = data->keyed_mutex->ReleaseSync (data->release_key);
274 gst_d3d11_result (hr, device);
276 GST_D3D11_CLEAR_COM (data->keyed_mutex);
279 ComPtr<ID3D11Query> query;
281 D3D11_QUERY_DESC query_desc;
282 ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device);
283 ID3D11DeviceContext *context_handle =
284 gst_d3d11_device_get_device_context_handle (device);
285 BOOL sync_done = FALSE;
287 /* If keyed mutex is not used, let's handle sync manually by using
288 * ID3D11Query. Issued GPU commands might not be finished yet */
289 query_desc.Query = D3D11_QUERY_EVENT;
290 query_desc.MiscFlags = 0;
292 hr = device_handle->CreateQuery (&query_desc, &query);
293 if (!gst_d3d11_result (hr, device)) {
294 GST_ERROR_OBJECT (self, "Couldn't Create event query");
298 context_handle->End (query.Get ());
300 /* Wait until all issued GPU commands are finished */
302 hr = context_handle->GetData (query.Get (), &sync_done, sizeof (BOOL), 0);
303 } while (!sync_done && (hr == S_OK || hr == S_FALSE));
305 if (!gst_d3d11_result (hr, device)) {
306 GST_ERROR_OBJECT (self, "Couldn't sync GPU operation");
311 gst_clear_buffer (&data->render_target);
317 gst_d3d11_window_dummy_new (GstD3D11Device * device)
319 GstD3D11Window *window;
321 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
323 window = (GstD3D11Window *)
324 g_object_new (GST_TYPE_D3D11_WINDOW_DUMMY, "d3d11device", device, NULL);
326 window->initialized = TRUE;
327 g_object_ref_sink (window);