d3d11: Use GRecMutex to protect immediate context and dxgi API call

In some cases, rendering and dxgi (e.g., swapchain) APIs should be
called from window message pump thread, but current design (dedicated d3d11 thread)
make it impossible. To solve it, change concurrency model to locking based one
from single-thread model.
This commit is contained in:
Seungha Yang 2019-12-20 00:17:33 +09:00
parent a0a85cd80c
commit 0788492461
12 changed files with 409 additions and 965 deletions

View file

@ -179,7 +179,7 @@ gst_d3d11_color_convert_init (GstD3D11ColorConvert * self)
}
static void
clear_shader_resource (GstD3D11Device * device, GstD3D11ColorConvert * self)
gst_d3d11_color_convert_clear_shader_resource (GstD3D11ColorConvert * self)
{
gint i;
@ -215,17 +215,6 @@ clear_shader_resource (GstD3D11Device * device, GstD3D11ColorConvert * self)
self->converter = NULL;
}
static void
gst_d3d11_color_convert_clear_shader_resource (GstD3D11ColorConvert * self)
{
GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (self);
if (filter->device) {
gst_d3d11_device_thread_add (filter->device,
(GstD3D11DeviceThreadFunc) clear_shader_resource, self);
}
}
static void
gst_d3d11_color_convert_dispose (GObject * object)
{
@ -781,32 +770,25 @@ format_unknown:
}
}
typedef struct
static GstFlowReturn
gst_d3d11_color_convert_transform (GstBaseTransform * trans,
GstBuffer * inbuf, GstBuffer * outbuf)
{
GstD3D11ColorConvert *self;
GstBuffer *in_buf;
GstBuffer *out_buf;
gboolean ret;
} DoConvertData;
static void
do_convert (GstD3D11Device * device, DoConvertData * data)
{
GstD3D11ColorConvert *self = data->self;
GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (self);
GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (trans);
GstD3D11ColorConvert *self = GST_D3D11_COLOR_CONVERT (trans);
ID3D11DeviceContext *context_handle;
ID3D11ShaderResourceView *resource_view[GST_VIDEO_MAX_PLANES] = { NULL, };
ID3D11RenderTargetView *render_view[GST_VIDEO_MAX_PLANES] = { NULL, };
gint i, j, view_index;
gboolean copy_input = FALSE;
gboolean copy_output = FALSE;
GstD3D11Device *device = filter->device;
context_handle = gst_d3d11_device_get_device_context_handle (device);
view_index = 0;
for (i = 0; i < gst_buffer_n_memory (data->in_buf); i++) {
GstMemory *mem = gst_buffer_peek_memory (data->in_buf, i);
for (i = 0; i < gst_buffer_n_memory (inbuf); i++) {
GstMemory *mem = gst_buffer_peek_memory (inbuf, i);
GstD3D11Memory *d3d11_mem;
GstMapInfo info;
@ -833,8 +815,7 @@ do_convert (GstD3D11Device * device, DoConvertData * data)
if (!create_shader_input_resource (self, device,
self->in_d3d11_format, &filter->in_info)) {
GST_ERROR_OBJECT (self, "Failed to configure fallback input texture");
data->ret = FALSE;
return;
return GST_FLOW_ERROR;
}
break;
}
@ -843,8 +824,9 @@ do_convert (GstD3D11Device * device, DoConvertData * data)
/* if input memory has no resource view,
* copy texture into our fallback texture */
if (copy_input) {
for (i = 0; i < gst_buffer_n_memory (data->in_buf); i++) {
GstMemory *mem = gst_buffer_peek_memory (data->in_buf, i);
gst_d3d11_device_lock (device);
for (i = 0; i < gst_buffer_n_memory (inbuf); i++) {
GstMemory *mem = gst_buffer_peek_memory (inbuf, i);
GstD3D11Memory *d3d11_mem;
g_assert (gst_is_d3d11_memory (mem));
@ -855,11 +837,12 @@ do_convert (GstD3D11Device * device, DoConvertData * data)
(ID3D11Resource *) self->in_texture[i], 0, 0, 0, 0,
(ID3D11Resource *) d3d11_mem->texture, 0, NULL);
}
gst_d3d11_device_unlock (device);
}
view_index = 0;
for (i = 0; i < gst_buffer_n_memory (data->out_buf); i++) {
GstMemory *mem = gst_buffer_peek_memory (data->out_buf, i);
for (i = 0; i < gst_buffer_n_memory (outbuf); i++) {
GstMemory *mem = gst_buffer_peek_memory (outbuf, i);
GstD3D11Memory *d3d11_mem;
g_assert (gst_is_d3d11_memory (mem));
@ -880,20 +863,24 @@ do_convert (GstD3D11Device * device, DoConvertData * data)
if (!create_shader_output_resource (self, device, self->out_d3d11_format,
&filter->out_info)) {
GST_ERROR_OBJECT (self, "Failed to configure fallback output texture");
data->ret = FALSE;
return;
return GST_FLOW_ERROR;
}
break;
}
}
data->ret = gst_d3d11_color_converter_convert (self->converter,
copy_input ? self->shader_resource_view : resource_view,
copy_output ? self->render_target_view : render_view);
if (!gst_d3d11_color_converter_convert (self->converter,
copy_input ? self->shader_resource_view : resource_view,
copy_output ? self->render_target_view : render_view)) {
GST_ERROR_OBJECT (self, "Failed to convert");
if (data->ret && copy_output) {
for (i = 0; i < gst_buffer_n_memory (data->out_buf); i++) {
GstMemory *mem = gst_buffer_peek_memory (data->out_buf, i);
return GST_FLOW_ERROR;
}
if (copy_output) {
gst_d3d11_device_lock (device);
for (i = 0; i < gst_buffer_n_memory (outbuf); i++) {
GstMemory *mem = gst_buffer_peek_memory (outbuf, i);
GstD3D11Memory *d3d11_mem;
g_assert (gst_is_d3d11_memory (mem));
@ -904,27 +891,8 @@ do_convert (GstD3D11Device * device, DoConvertData * data)
(ID3D11Resource *) d3d11_mem->texture, 0, 0, 0, 0,
(ID3D11Resource *) self->out_texture[i], 0, NULL);
}
gst_d3d11_device_unlock (device);
}
}
static GstFlowReturn
gst_d3d11_color_convert_transform (GstBaseTransform * trans,
GstBuffer * inbuf, GstBuffer * outbuf)
{
GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (trans);
GstD3D11ColorConvert *self = GST_D3D11_COLOR_CONVERT (trans);
DoConvertData data;
data.self = self;
data.in_buf = inbuf;
data.out_buf = outbuf;
data.ret = TRUE;
gst_d3d11_device_thread_add (filter->device,
(GstD3D11DeviceThreadFunc) do_convert, &data);
if (!data.ret)
return GST_FLOW_ERROR;
return GST_FLOW_OK;
}

View file

@ -610,12 +610,14 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device,
goto clear;
}
gst_d3d11_device_lock (device);
hr = ID3D11DeviceContext_Map (context_handle,
(ID3D11Resource *) const_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (!gst_d3d11_result (hr)) {
GST_ERROR ("Couldn't map constant buffer, hr: 0x%x", (guint) hr);
data->ret = FALSE;
gst_d3d11_device_unlock (device);
goto clear;
}
@ -624,6 +626,7 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device,
ID3D11DeviceContext_Unmap (context_handle,
(ID3D11Resource *) const_buffer, 0);
gst_d3d11_device_unlock (device);
}
input_desc[0].SemanticName = "POSITION";
@ -678,12 +681,14 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device,
goto clear;
}
gst_d3d11_device_lock (device);
hr = ID3D11DeviceContext_Map (context_handle,
(ID3D11Resource *) vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (!gst_d3d11_result (hr)) {
GST_ERROR ("Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
data->ret = FALSE;
gst_d3d11_device_unlock (device);
goto clear;
}
@ -696,6 +701,7 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device,
GST_ERROR ("Couldn't map index buffer, hr: 0x%x", (guint) hr);
ID3D11DeviceContext_Unmap (context_handle,
(ID3D11Resource *) vertex_buffer, 0);
gst_d3d11_device_unlock (device);
data->ret = FALSE;
goto clear;
}
@ -743,6 +749,7 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Device * device,
(ID3D11Resource *) vertex_buffer, 0);
ID3D11DeviceContext_Unmap (context_handle,
(ID3D11Resource *) index_buffer, 0);
gst_d3d11_device_unlock (device);
self->quad = gst_d3d11_quad_new (device,
ps, vs, layout, sampler, const_buffer, vertex_buffer, sizeof (VertexData),
@ -856,8 +863,7 @@ gst_d3d11_color_converter_new (GstD3D11Device * device,
data.self = converter;
data.in_info = in_info;
data.out_info = out_info;
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) gst_d3d11_color_convert_setup_shader, &data);
gst_d3d11_color_convert_setup_shader (device, &data);
if (!data.ret || !converter->quad) {
GST_ERROR ("Couldn't setup shader");
@ -897,51 +903,17 @@ gst_d3d11_color_converter_free (GstD3D11ColorConverter * converter)
g_free (converter);
}
typedef struct
{
GstD3D11ColorConverter *self;
ID3D11ShaderResourceView *srv[GST_VIDEO_MAX_PLANES];
ID3D11RenderTargetView *rtv[GST_VIDEO_MAX_PLANES];
gboolean ret;
} DoConvertData;
static void
do_convert (GstD3D11Device * device, DoConvertData * data)
{
GstD3D11ColorConverter *self = data->self;
data->ret =
gst_d3d11_draw_quad (self->quad, &self->viewport, 1,
data->srv, self->num_input_view, data->rtv, self->num_output_view);
}
gboolean
gst_d3d11_color_converter_convert (GstD3D11ColorConverter * converter,
ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],
ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES])
{
DoConvertData data = { 0, };
gint i;
g_return_val_if_fail (converter != NULL, FALSE);
g_return_val_if_fail (srv != NULL, FALSE);
g_return_val_if_fail (rtv != NULL, FALSE);
data.self = converter;
for (i = 0; i < converter->num_input_view; i++)
data.srv[i] = srv[i];
for (i = 0; i < converter->num_output_view; i++)
data.rtv[i] = rtv[i];
data.ret = TRUE;
gst_d3d11_device_thread_add (converter->device,
(GstD3D11DeviceThreadFunc) do_convert, &data);
return data.ret;
return gst_d3d11_draw_quad (converter->quad, &converter->viewport, 1,
srv, converter->num_input_view, rtv, converter->num_output_view);
}
gboolean

View file

@ -75,15 +75,7 @@ struct _GstD3D11DevicePrivate
GstD3D11DXGIFactoryVersion factory_ver;
D3D_FEATURE_LEVEL feature_level;
ID3D11VideoDevice *video_device;
ID3D11VideoContext *video_context;
GMutex lock;
GCond cond;
GThread *thread;
GThread *active_thread;
GMainLoop *loop;
GMainContext *main_context;
GRecMutex extern_lock;
#ifdef HAVE_D3D11SDKLAYER_H
ID3D11Debug *debug;
@ -102,8 +94,6 @@ static void gst_d3d11_device_constructed (GObject * object);
static void gst_d3d11_device_dispose (GObject * object);
static void gst_d3d11_device_finalize (GObject * object);
static gpointer gst_d3d11_device_thread_func (gpointer data);
#ifdef HAVE_D3D11SDKLAYER_H
static gboolean
gst_d3d11_device_enable_debug_layer (void)
@ -206,11 +196,7 @@ gst_d3d11_device_init (GstD3D11Device * self)
priv = gst_d3d11_device_get_instance_private (self);
priv->adapter = DEFAULT_ADAPTER;
g_mutex_init (&priv->lock);
g_cond_init (&priv->cond);
priv->main_context = g_main_context_new ();
priv->loop = g_main_loop_new (priv->main_context, FALSE);
g_rec_mutex_init (&priv->extern_lock);
self->priv = priv;
}
@ -332,7 +318,6 @@ gst_d3d11_device_constructed (GObject * object)
priv->factory = factory;
#ifdef HAVE_D3D11SDKLAYER_H
if ((d3d11_flags & D3D11_CREATE_DEVICE_DEBUG) == D3D11_CREATE_DEVICE_DEBUG) {
ID3D11Debug *debug;
@ -351,30 +336,14 @@ gst_d3d11_device_constructed (GObject * object)
hr = ID3D11Device_QueryInterface (priv->device,
&IID_ID3D11InfoQueue, (void **) &info_queue);
if (SUCCEEDED (hr)) {
GSource *source;
GST_DEBUG_OBJECT (self, "D3D11InfoQueue interface available");
priv->info_queue = info_queue;
source = g_idle_source_new ();
g_source_set_callback (source, (GSourceFunc) gst_d3d11_device_get_message,
self, NULL);
g_source_attach (source, priv->main_context);
g_source_unref (source);
}
}
#endif
IDXGIAdapter1_Release (adapter);
g_mutex_lock (&priv->lock);
priv->thread = g_thread_new ("GstD3D11Device",
(GThreadFunc) gst_d3d11_device_thread_func, self);
while (!g_main_loop_is_running (priv->loop))
g_cond_wait (&priv->cond, &priv->lock);
g_mutex_unlock (&priv->lock);
G_OBJECT_CLASS (parent_class)->constructed (object);
return;
@ -458,39 +427,10 @@ gst_d3d11_device_dispose (GObject * object)
priv->device_context = NULL;
}
if (priv->video_device) {
ID3D11VideoDevice_Release (priv->video_device);
priv->video_device = NULL;
}
if (priv->video_context) {
ID3D11VideoContext_Release (priv->video_context);
priv->video_context = NULL;
}
if (priv->factory) {
IDXGIFactory1_Release (priv->factory);
priv->factory = NULL;
}
if (priv->loop) {
g_main_loop_quit (priv->loop);
}
if (priv->thread) {
g_thread_join (priv->thread);
priv->thread = NULL;
}
if (priv->loop) {
g_main_loop_unref (priv->loop);
priv->loop = NULL;
}
if (priv->main_context) {
g_main_context_unref (priv->main_context);
priv->main_context = NULL;
}
#ifdef HAVE_D3D11SDKLAYER_H
if (priv->debug) {
ID3D11Debug_ReportLiveDeviceObjects (priv->debug,
@ -518,53 +458,12 @@ gst_d3d11_device_finalize (GObject * object)
GST_LOG_OBJECT (self, "finalize");
g_mutex_clear (&priv->lock);
g_cond_clear (&priv->cond);
g_rec_mutex_clear (&priv->extern_lock);
g_free (priv->description);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
running_cb (gpointer user_data)
{
GstD3D11Device *self = GST_D3D11_DEVICE (user_data);
GstD3D11DevicePrivate *priv = self->priv;
GST_TRACE_OBJECT (self, "Main loop running now");
g_mutex_lock (&priv->lock);
g_cond_signal (&priv->cond);
g_mutex_unlock (&priv->lock);
return G_SOURCE_REMOVE;
}
static gpointer
gst_d3d11_device_thread_func (gpointer data)
{
GstD3D11Device *self = GST_D3D11_DEVICE (data);
GstD3D11DevicePrivate *priv = self->priv;
GSource *source;
GST_DEBUG_OBJECT (self, "Enter loop");
g_main_context_push_thread_default (priv->main_context);
source = g_idle_source_new ();
g_source_set_callback (source, (GSourceFunc) running_cb, self, NULL);
g_source_attach (source, priv->main_context);
g_source_unref (source);
priv->active_thread = g_thread_self ();
g_main_loop_run (priv->loop);
g_main_context_pop_thread_default (priv->main_context);
GST_DEBUG_OBJECT (self, "Exit loop");
return NULL;
}
/**
* gst_d3d11_device_new:
* @adapter: the index of adapter for creating d3d11 device
@ -642,119 +541,6 @@ gst_d3d11_device_get_chosen_feature_level (GstD3D11Device * device)
return device->priv->feature_level;
}
typedef struct
{
GstD3D11Device *device;
GstD3D11DeviceThreadFunc func;
gpointer data;
gboolean fired;
} MessageData;
static gboolean
gst_d3d11_device_message_callback (MessageData * msg)
{
GstD3D11Device *self = msg->device;
GstD3D11DevicePrivate *priv = self->priv;
msg->func (self, msg->data);
g_mutex_lock (&priv->lock);
msg->fired = TRUE;
g_cond_broadcast (&priv->cond);
g_mutex_unlock (&priv->lock);
return G_SOURCE_REMOVE;
}
/**
* gst_d3d11_device_thread_add:
* @device: a #GstD3D11Device
* @func: (scope call): a #GstD3D11DeviceThreadFunc
* @data: (closure): user data to call @func with
*
* Execute @func in the D3DDevice thread of @device with @data
*
* MT-safe
*/
void
gst_d3d11_device_thread_add (GstD3D11Device * device,
GstD3D11DeviceThreadFunc func, gpointer data)
{
gst_d3d11_device_thread_add_full (device,
G_PRIORITY_DEFAULT, func, data, NULL);
}
/**
* gst_d3d11_device_thread_add_full:
* @device: a #GstD3D11Device
* @priority: the priority at which to run @func
* @func: (scope call): a #GstD3D11DeviceThreadFunc
* @data: (closure): user data to call @func with
* @notify: (nullable): a function to call when @data is no longer in use, or %NULL.
*
* Execute @func in the D3DDevice thread of @device with @data with specified
* @priority
*
* MT-safe
*/
void
gst_d3d11_device_thread_add_full (GstD3D11Device * device,
gint priority, GstD3D11DeviceThreadFunc func, gpointer data,
GDestroyNotify notify)
{
GstD3D11DevicePrivate *priv;
MessageData msg = { 0, };
g_return_if_fail (GST_IS_D3D11_DEVICE (device));
g_return_if_fail (func != NULL);
priv = device->priv;
if (priv->active_thread == g_thread_self ()) {
func (device, data);
return;
}
msg.device = gst_object_ref (device);
msg.func = func;
msg.data = data;
msg.fired = FALSE;
g_main_context_invoke_full (priv->main_context, priority,
(GSourceFunc) gst_d3d11_device_message_callback, &msg, notify);
g_mutex_lock (&priv->lock);
while (!msg.fired)
g_cond_wait (&priv->cond, &priv->lock);
g_mutex_unlock (&priv->lock);
gst_object_unref (device);
}
typedef struct
{
IDXGISwapChain *swap_chain;
const DXGI_SWAP_CHAIN_DESC *desc;
} CreateSwapChainData;
static void
gst_d3d11_device_create_swap_chain_internal (GstD3D11Device * device,
CreateSwapChainData * data)
{
GstD3D11DevicePrivate *priv = device->priv;
HRESULT hr;
hr = IDXGIFactory1_CreateSwapChain (priv->factory, (IUnknown *) priv->device,
(DXGI_SWAP_CHAIN_DESC *) data->desc, &data->swap_chain);
if (!gst_d3d11_result (hr)) {
GST_ERROR_OBJECT (device, "Cannot create SwapChain Object: 0x%x",
(guint) hr);
data->swap_chain = NULL;
}
}
/**
* gst_d3d11_device_create_swap_chain:
* @device: a #GstD3D11Device
@ -770,47 +556,29 @@ IDXGISwapChain *
gst_d3d11_device_create_swap_chain (GstD3D11Device * device,
const DXGI_SWAP_CHAIN_DESC * desc)
{
CreateSwapChainData data = { 0, };
GstD3D11DevicePrivate *priv;
HRESULT hr;
IDXGISwapChain *swap_chain = NULL;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
data.swap_chain = NULL;
data.desc = desc;
priv = device->priv;
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
gst_d3d11_device_create_swap_chain_internal, &data);
return data.swap_chain;
}
#if (DXGI_HEADER_VERSION >= 2)
typedef struct
{
IDXGISwapChain1 *swap_chain;
HWND hwnd;
const DXGI_SWAP_CHAIN_DESC1 *desc;
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc;
IDXGIOutput *output;
} CreateSwapChainForHwndData;
static void
gst_d3d11_device_create_swap_chain_for_hwnd_internal (GstD3D11Device * device,
CreateSwapChainForHwndData * data)
{
GstD3D11DevicePrivate *priv = device->priv;
HRESULT hr;
hr = IDXGIFactory2_CreateSwapChainForHwnd ((IDXGIFactory2 *) priv->factory,
(IUnknown *) priv->device, data->hwnd, data->desc, data->fullscreen_desc,
data->output, &data->swap_chain);
gst_d3d11_device_lock (device);
hr = IDXGIFactory1_CreateSwapChain (priv->factory, (IUnknown *) priv->device,
(DXGI_SWAP_CHAIN_DESC *) desc, &swap_chain);
gst_d3d11_device_unlock (device);
if (!gst_d3d11_result (hr)) {
GST_ERROR_OBJECT (device, "Cannot create SwapChain Object: 0x%x",
(guint) hr);
data->swap_chain = NULL;
swap_chain = NULL;
}
return swap_chain;
}
#if (DXGI_HEADER_VERSION >= 2)
/**
* gst_d3d11_device_create_swap_chain_for_hwnd:
* @device: a #GstD3D11Device
@ -832,68 +600,65 @@ gst_d3d11_device_create_swap_chain_for_hwnd (GstD3D11Device * device,
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC * fullscreen_desc,
IDXGIOutput * output)
{
CreateSwapChainForHwndData data = { 0, };
GstD3D11DevicePrivate *priv;
IDXGISwapChain1 *swap_chain = NULL;
HRESULT hr;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
data.swap_chain = NULL;
data.hwnd = hwnd;
data.desc = desc;
data.fullscreen_desc = fullscreen_desc;
data.output = output;
priv = device->priv;
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
gst_d3d11_device_create_swap_chain_for_hwnd_internal, &data);
gst_d3d11_device_lock (device);
hr = IDXGIFactory2_CreateSwapChainForHwnd ((IDXGIFactory2 *) priv->factory,
(IUnknown *) priv->device, hwnd, desc, fullscreen_desc,
output, &swap_chain);
gst_d3d11_device_unlock (device);
return data.swap_chain;
if (!gst_d3d11_result (hr)) {
GST_ERROR_OBJECT (device, "Cannot create SwapChain Object: 0x%x",
(guint) hr);
swap_chain = NULL;
}
return swap_chain;
}
#endif
static void
gst_d3d11_device_release_swap_chain_internal (GstD3D11Device * device,
IDXGISwapChain * swap_chain)
{
IDXGISwapChain_Release (swap_chain);
}
/**
* gst_d3d11_device_release_swap_chain:
* @device: a #GstD3D11Device
* @swap_chain: a IDXGISwapChain
*
* Release a @swap_chain from device thread
*
*/
void
gst_d3d11_device_release_swap_chain (GstD3D11Device * device,
IDXGISwapChain * swap_chain)
{
g_return_if_fail (GST_IS_D3D11_DEVICE (device));
g_return_if_fail (swap_chain != NULL);
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) gst_d3d11_device_release_swap_chain_internal,
swap_chain);
gst_d3d11_device_lock (device);
IDXGISwapChain_Release (swap_chain);
gst_d3d11_device_unlock (device);
}
typedef struct
ID3D11Texture2D *
gst_d3d11_device_create_texture (GstD3D11Device * device,
const D3D11_TEXTURE2D_DESC * desc,
const D3D11_SUBRESOURCE_DATA * inital_data)
{
ID3D11Texture2D *texture;
const D3D11_TEXTURE2D_DESC *desc;
const D3D11_SUBRESOURCE_DATA *inital_data;
} CreateTextureData;
static void
gst_d3d11_device_create_texture_internal (GstD3D11Device * device,
CreateTextureData * data)
{
GstD3D11DevicePrivate *priv = device->priv;
GstD3D11DevicePrivate *priv;
HRESULT hr;
ID3D11Texture2D *texture;
hr = ID3D11Device_CreateTexture2D (priv->device, data->desc,
data->inital_data, &data->texture);
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
g_return_val_if_fail (desc != NULL, NULL);
priv = device->priv;
hr = ID3D11Device_CreateTexture2D (priv->device, desc, inital_data, &texture);
if (!gst_d3d11_result (hr)) {
const D3D11_TEXTURE2D_DESC *desc = data->desc;
GST_ERROR ("Failed to create texture (0x%x)", (guint) hr);
GST_WARNING ("Direct3D11 Allocation params");
@ -907,35 +672,10 @@ gst_d3d11_device_create_texture_internal (GstD3D11Device * device,
GST_WARNING ("\tBindFlags 0x%x", desc->BindFlags);
GST_WARNING ("\tCPUAccessFlags 0x%x", desc->CPUAccessFlags);
GST_WARNING ("\tMiscFlags 0x%x", desc->MiscFlags);
data->texture = NULL;
texture = NULL;
}
}
ID3D11Texture2D *
gst_d3d11_device_create_texture (GstD3D11Device * device,
const D3D11_TEXTURE2D_DESC * desc,
const D3D11_SUBRESOURCE_DATA * inital_data)
{
CreateTextureData data;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
g_return_val_if_fail (desc != NULL, NULL);
data.texture = NULL;
data.desc = desc;
data.inital_data = inital_data;
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
gst_d3d11_device_create_texture_internal, &data);
return data.texture;
}
static void
gst_d3d11_device_release_texture_internal (GstD3D11Device * device,
ID3D11Texture2D * texture)
{
ID3D11Texture2D_Release (texture);
return texture;
}
void
@ -945,6 +685,32 @@ gst_d3d11_device_release_texture (GstD3D11Device * device,
g_return_if_fail (GST_IS_D3D11_DEVICE (device));
g_return_if_fail (texture != NULL);
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
gst_d3d11_device_release_texture_internal, texture);
ID3D11Texture2D_Release (texture);
}
void
gst_d3d11_device_lock (GstD3D11Device * device)
{
GstD3D11DevicePrivate *priv;
g_return_if_fail (GST_IS_D3D11_DEVICE (device));
priv = device->priv;
GST_TRACE_OBJECT (device, "device locking");
g_rec_mutex_lock (&priv->extern_lock);
GST_TRACE_OBJECT (device, "device locked");
}
void
gst_d3d11_device_unlock (GstD3D11Device * device)
{
GstD3D11DevicePrivate *priv;
g_return_if_fail (GST_IS_D3D11_DEVICE (device));
priv = device->priv;
g_rec_mutex_unlock (&priv->extern_lock);
GST_TRACE_OBJECT (device, "device unlocked");
}

View file

@ -101,16 +101,6 @@ IDXGISwapChain1 * gst_d3d11_device_create_swap_chain_for_hwnd (GstD3D11Devic
void gst_d3d11_device_release_swap_chain (GstD3D11Device * device,
IDXGISwapChain * swap_chain);
void gst_d3d11_device_thread_add (GstD3D11Device * device,
GstD3D11DeviceThreadFunc func,
gpointer data);
void gst_d3d11_device_thread_add_full (GstD3D11Device * device,
gint priority,
GstD3D11DeviceThreadFunc func,
gpointer data,
GDestroyNotify notify);
ID3D11Texture2D * gst_d3d11_device_create_texture (GstD3D11Device * device,
const D3D11_TEXTURE2D_DESC * desc,
const D3D11_SUBRESOURCE_DATA *inital_data);
@ -118,6 +108,10 @@ ID3D11Texture2D * gst_d3d11_device_create_texture (GstD3D11Device * devi
void gst_d3d11_device_release_texture (GstD3D11Device * device,
ID3D11Texture2D * texture);
void gst_d3d11_device_lock (GstD3D11Device * device);
void gst_d3d11_device_unlock (GstD3D11Device * device);
G_END_DECLS
#endif /* __GST_D3D11_DEVICE_H__ */

View file

@ -265,26 +265,19 @@ gst_d3d11_download_decide_allocation (GstBaseTransform * trans,
query);
}
typedef struct
{
GstD3D11BaseFilter *filter;
GstBuffer *inbuf;
GstBuffer *outbuf;
GstFlowReturn ret;
} UploadTransformData;
static void
download_transform (GstD3D11Device * device, UploadTransformData * data)
static GstFlowReturn
gst_d3d11_download_transform (GstBaseTransform * trans, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (trans);
GstVideoFrame in_frame, out_frame;
GstD3D11BaseFilter *filter = data->filter;
gint i;
if (!gst_video_frame_map (&in_frame, &filter->in_info, data->inbuf,
if (!gst_video_frame_map (&in_frame, &filter->in_info, inbuf,
GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF))
goto invalid_buffer;
if (!gst_video_frame_map (&out_frame, &filter->out_info, data->outbuf,
if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf,
GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)) {
gst_video_frame_unmap (&in_frame);
goto invalid_buffer;
@ -293,51 +286,20 @@ download_transform (GstD3D11Device * device, UploadTransformData * data)
for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&in_frame); i++) {
if (!gst_video_frame_copy_plane (&out_frame, &in_frame, i)) {
GST_ERROR_OBJECT (filter, "Couldn't copy %dth plane", i);
data->ret = GST_FLOW_ERROR;
return;
return GST_FLOW_ERROR;
}
}
gst_video_frame_unmap (&out_frame);
gst_video_frame_unmap (&in_frame);
data->ret = GST_FLOW_OK;
return;
return GST_FLOW_OK;
/* ERRORS */
invalid_buffer:
{
GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL),
("invalid video buffer received"));
data->ret = GST_FLOW_ERROR;
return;
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
gst_d3d11_download_transform (GstBaseTransform * trans, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (trans);
GstMemory *mem;
GstD3D11Device *device;
UploadTransformData data;
mem = gst_buffer_peek_memory (inbuf, 0);
if (gst_is_d3d11_memory (mem)) {
GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
device = dmem->device;
} else {
device = filter->device;
}
data.filter = filter;
data.inbuf = inbuf;
data.outbuf = outbuf;
data.ret = GST_FLOW_OK;
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) download_transform, &data);
return data.ret;
}

View file

@ -208,15 +208,18 @@ gst_d3d11_format_from_gst (GstVideoFormat format)
return NULL;
}
typedef struct
{
GstCaps *caps;
D3D11_FORMAT_SUPPORT flags;
} SupportCapsData;
static void
gst_d3d11_device_get_supported_caps_internal (GstD3D11Device * device,
SupportCapsData * data)
/**
* gst_d3d11_device_get_supported_caps:
* @device: a #GstD3DDevice
* @flags: D3D11_FORMAT_SUPPORT flags
*
* Check supported format with given flags
*
* Returns: a #GstCaps representing supported format
*/
GstCaps *
gst_d3d11_device_get_supported_caps (GstD3D11Device * device,
D3D11_FORMAT_SUPPORT flags)
{
ID3D11Device *d3d11_device;
HRESULT hr;
@ -225,6 +228,8 @@ gst_d3d11_device_get_supported_caps_internal (GstD3D11Device * device,
GstCaps *supported_caps;
GstD3D11Format *format_list;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
d3d11_device = gst_d3d11_device_get_device_handle (device);
g_value_init (&v_list, GST_TYPE_LIST);
@ -241,12 +246,12 @@ gst_d3d11_device_get_supported_caps_internal (GstD3D11Device * device,
hr = ID3D11Device_CheckFormatSupport (d3d11_device,
format_list[i].dxgi_format, &format_support);
if (SUCCEEDED (hr) && ((format_support & data->flags) == data->flags)) {
if (SUCCEEDED (hr) && ((format_support & flags) == flags)) {
GValue v_str = G_VALUE_INIT;
g_value_init (&v_str, G_TYPE_STRING);
GST_LOG_OBJECT (device, "d3d11 device can support %s with flags 0x%x",
gst_video_format_to_string (format), data->flags);
gst_video_format_to_string (format), flags);
g_value_set_string (&v_str, gst_video_format_to_string (format));
gst_value_list_append_and_take_value (&v_list, &v_str);
}
@ -262,31 +267,5 @@ gst_d3d11_device_get_supported_caps_internal (GstD3D11Device * device,
gst_caps_set_features_simple (supported_caps,
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY));
data->caps = supported_caps;
}
/**
* gst_d3d11_device_get_supported_caps:
* @device: a #GstD3DDevice
* @flags: D3D11_FORMAT_SUPPORT flags
*
* Check supported format with given flags
*
* Returns: a #GstCaps representing supported format
*/
GstCaps *
gst_d3d11_device_get_supported_caps (GstD3D11Device * device,
D3D11_FORMAT_SUPPORT flags)
{
SupportCapsData data;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
data.caps = NULL;
data.flags = flags;
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
gst_d3d11_device_get_supported_caps_internal, &data);
return data.caps;
return supported_caps;
}

View file

@ -199,55 +199,34 @@ create_staging_texture (GstD3D11Device * device,
return gst_d3d11_device_create_texture (device, &desc, NULL);
}
typedef struct
static gboolean
map_cpu_access_data (GstD3D11Memory * dmem, D3D11_MAP map_type)
{
ID3D11Resource *dst;
ID3D11Resource *src;
} D3D11CopyTextureData;
static void
copy_texture (GstD3D11Device * device, D3D11CopyTextureData * data)
{
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (device);
ID3D11DeviceContext_CopySubresourceRegion (device_context,
data->dst, 0, 0, 0, 0, data->src, 0, NULL);
}
typedef struct
{
GstD3D11Memory *mem;
D3D11_MAP map_type;
gboolean ret;
} D3D11MapData;
static void
map_cpu_access_data (GstD3D11Device * device, D3D11MapData * map_data)
{
GstD3D11Memory *dmem = map_data->mem;
HRESULT hr;
gboolean ret = TRUE;
ID3D11Resource *texture = (ID3D11Resource *) dmem->texture;
ID3D11Resource *staging = (ID3D11Resource *) dmem->staging;
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (device);
gst_d3d11_device_get_device_context_handle (dmem->device);
gst_d3d11_device_lock (dmem->device);
if (GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD)) {
ID3D11DeviceContext_CopySubresourceRegion (device_context,
staging, 0, 0, 0, 0, texture, 0, NULL);
}
hr = ID3D11DeviceContext_Map (device_context,
staging, 0, map_data->map_type, 0, &dmem->map);
staging, 0, map_type, 0, &dmem->map);
if (!gst_d3d11_result (hr)) {
GST_ERROR_OBJECT (GST_MEMORY_CAST (dmem)->allocator,
"Failed to map staging texture (0x%x)", (guint) hr);
map_data->ret = FALSE;
ret = FALSE;
}
map_data->ret = TRUE;
gst_d3d11_device_unlock (dmem->device);
return ret;
}
static gpointer
@ -265,13 +244,14 @@ gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
if ((flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
if (dmem->staging &&
GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD)) {
D3D11CopyTextureData data;
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (dmem->device);
data.dst = (ID3D11Resource *) dmem->texture;
data.src = (ID3D11Resource *) dmem->staging;
gst_d3d11_device_thread_add (dmem->device,
(GstD3D11DeviceThreadFunc) copy_texture, &data);
gst_d3d11_device_lock (dmem->device);
ID3D11DeviceContext_CopySubresourceRegion (device_context,
(ID3D11Resource *) dmem->texture, 0, 0, 0, 0,
(ID3D11Resource *) dmem->staging, 0, NULL);
gst_d3d11_device_unlock (dmem->device);
}
GST_MEMORY_FLAG_UNSET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD);
@ -286,7 +266,7 @@ gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
}
if (dmem->cpu_map_count == 0) {
D3D11MapData map_data;
D3D11_MAP map_type;
/* Allocate staging texture for CPU access */
if (!dmem->staging) {
@ -302,13 +282,9 @@ gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
}
map_data.mem = dmem;
map_data.map_type = gst_map_flags_to_d3d11 (flags);
map_type = gst_map_flags_to_d3d11 (flags);
gst_d3d11_device_thread_add (dmem->device, (GstD3D11DeviceThreadFunc)
map_cpu_access_data, &map_data);
if (!map_data.ret) {
if (!map_cpu_access_data (dmem, map_type)) {
GST_ERROR_OBJECT (mem->allocator, "Couldn't map staging texture");
g_mutex_unlock (&dmem->lock);
@ -328,14 +304,15 @@ gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
}
static void
unmap_cpu_access_data (GstD3D11Device * device, gpointer data)
unmap_cpu_access_data (GstD3D11Memory * dmem)
{
GstD3D11Memory *dmem = (GstD3D11Memory *) data;
ID3D11Resource *staging = (ID3D11Resource *) dmem->staging;
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (device);
gst_d3d11_device_get_device_context_handle (dmem->device);
gst_d3d11_device_lock (dmem->device);
ID3D11DeviceContext_Unmap (device_context, staging, 0);
gst_d3d11_device_unlock (dmem->device);
}
static void
@ -367,8 +344,7 @@ gst_d3d11_memory_unmap_full (GstMemory * mem, GstMapInfo * info)
return;
}
gst_d3d11_device_thread_add (dmem->device, (GstD3D11DeviceThreadFunc)
unmap_cpu_access_data, dmem);
unmap_cpu_access_data (dmem);
g_mutex_unlock (&dmem->lock);
}
@ -387,38 +363,29 @@ gst_d3d11_allocator_dummy_alloc (GstAllocator * allocator, gsize size,
g_return_val_if_reached (NULL);
}
static void
release_texture (GstD3D11Device * device, GstD3D11Memory * mem)
{
gint i;
for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
if (mem->render_target_view[i])
ID3D11RenderTargetView_Release (mem->render_target_view[i]);
mem->render_target_view[i] = NULL;
if (mem->shader_resource_view[i])
ID3D11ShaderResourceView_Release (mem->shader_resource_view[i]);
mem->shader_resource_view[i] = NULL;
}
if (mem->texture)
ID3D11Texture2D_Release (mem->texture);
if (mem->staging)
ID3D11Texture2D_Release (mem->staging);
}
static void
gst_d3d11_allocator_free (GstAllocator * allocator, GstMemory * mem)
{
GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
GstD3D11Device *device = dmem->device;
gint i;
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) release_texture, dmem);
for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
if (dmem->render_target_view[i])
ID3D11RenderTargetView_Release (dmem->render_target_view[i]);
dmem->render_target_view[i] = NULL;
gst_object_unref (device);
if (dmem->shader_resource_view[i])
ID3D11ShaderResourceView_Release (dmem->shader_resource_view[i]);
dmem->shader_resource_view[i] = NULL;
}
if (dmem->texture)
ID3D11Texture2D_Release (dmem->texture);
if (dmem->staging)
ID3D11Texture2D_Release (dmem->staging);
gst_clear_object (&dmem->device);
g_mutex_clear (&dmem->lock);
g_free (dmem);
@ -476,44 +443,39 @@ gst_d3d11_allocator_new (GstD3D11Device * device)
return allocator;
}
typedef struct
{
ID3D11Resource *texture;
D3D11_TEXTURE2D_DESC *desc;
D3D11_MAP map_mode;
gint stride[GST_VIDEO_MAX_PLANES];
gsize size;
gboolean ret;
} CalSizeData;
static void
calculate_mem_size (GstD3D11Device * device, CalSizeData * data)
static gboolean
calculate_mem_size (GstD3D11Device * device, ID3D11Texture2D * texture,
D3D11_TEXTURE2D_DESC * desc, D3D11_MAP map_type,
gint stride[GST_VIDEO_MAX_PLANES], gsize * size)
{
HRESULT hr;
gboolean ret = TRUE;
D3D11_MAPPED_SUBRESOURCE map;
gsize offset[GST_VIDEO_MAX_PLANES];
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (device);
gst_d3d11_device_lock (device);
hr = ID3D11DeviceContext_Map (device_context,
data->texture, 0, data->map_mode, 0, &map);
(ID3D11Resource *) texture, 0, map_type, 0, &map);
if (!gst_d3d11_result (hr)) {
GST_ERROR_OBJECT (device, "Failed to map texture (0x%x)", (guint) hr);
data->ret = FALSE;
gst_d3d11_device_unlock (device);
return FALSE;
}
data->ret = gst_d3d11_dxgi_format_get_size (data->desc->Format,
data->desc->Width, data->desc->Height, map.RowPitch,
offset, data->stride, &data->size);
ret = gst_d3d11_dxgi_format_get_size (desc->Format,
desc->Width, desc->Height, map.RowPitch, offset, stride, size);
ID3D11DeviceContext_Unmap (device_context, data->texture, 0);
ID3D11DeviceContext_Unmap (device_context, (ID3D11Resource *) texture, 0);
gst_d3d11_device_unlock (device);
return ret;
}
static void
create_shader_resource_views (GstD3D11Device * device, GstD3D11Memory * mem)
create_shader_resource_views (GstD3D11Memory * mem)
{
gint i;
HRESULT hr;
@ -522,7 +484,7 @@ create_shader_resource_views (GstD3D11Device * device, GstD3D11Memory * mem)
D3D11_SHADER_RESOURCE_VIEW_DESC resource_desc = { 0, };
DXGI_FORMAT formats[GST_VIDEO_MAX_PLANES] = { DXGI_FORMAT_UNKNOWN, };
device_handle = gst_d3d11_device_get_device_handle (device);
device_handle = gst_d3d11_device_get_device_handle (mem->device);
switch (mem->desc.Format) {
case DXGI_FORMAT_B8G8R8A8_UNORM:
@ -566,7 +528,7 @@ create_shader_resource_views (GstD3D11Device * device, GstD3D11Memory * mem)
&mem->shader_resource_view[i]);
if (!gst_d3d11_result (hr)) {
GST_ERROR_OBJECT (device,
GST_ERROR_OBJECT (GST_MEMORY_CAST (mem)->allocator,
"Failed to create %dth resource view (0x%x)", i, (guint) hr);
goto error;
}
@ -588,7 +550,7 @@ error:
}
static void
create_render_target_views (GstD3D11Device * device, GstD3D11Memory * mem)
create_render_target_views (GstD3D11Memory * mem)
{
gint i;
HRESULT hr;
@ -597,7 +559,7 @@ create_render_target_views (GstD3D11Device * device, GstD3D11Memory * mem)
D3D11_RENDER_TARGET_VIEW_DESC render_desc = { 0, };
DXGI_FORMAT formats[GST_VIDEO_MAX_PLANES] = { DXGI_FORMAT_UNKNOWN, };
device_handle = gst_d3d11_device_get_device_handle (device);
device_handle = gst_d3d11_device_get_device_handle (mem->device);
switch (mem->desc.Format) {
case DXGI_FORMAT_B8G8R8A8_UNORM:
@ -641,7 +603,7 @@ create_render_target_views (GstD3D11Device * device, GstD3D11Memory * mem)
(ID3D11Resource *) mem->texture, &render_desc,
&mem->render_target_view[i]);
if (!gst_d3d11_result (hr)) {
GST_ERROR_OBJECT (device,
GST_ERROR_OBJECT (GST_MEMORY_CAST (mem)->allocator,
"Failed to create %dth render target view (0x%x)", i, (guint) hr);
goto error;
}
@ -704,8 +666,11 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
/* per plane, allocated staging texture to calculate actual size,
* stride, and offset */
if (is_first) {
CalSizeData data;
ID3D11Texture2D *target;
D3D11_MAP map_type;
gint num_plane;
gint stride[GST_VIDEO_MAX_PLANES];
gsize mem_size;
gint i;
if (desc->Usage == D3D11_USAGE_DEFAULT) {
@ -715,27 +680,25 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
goto error;
}
data.texture = (ID3D11Resource *) staging;
data.map_mode = D3D11_MAP_READ;
target = staging;
map_type = D3D11_MAP_READ;
} else if (desc->Usage == D3D11_USAGE_DYNAMIC) {
data.texture = (ID3D11Resource *) texture;
data.map_mode = D3D11_MAP_WRITE_DISCARD;
target = texture;
map_type = D3D11_MAP_WRITE_DISCARD;
} else {
g_assert_not_reached ();
}
data.desc = desc;
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) calculate_mem_size, &data);
if (!calculate_mem_size (device, target, desc, map_type, stride, &mem_size))
goto error;
num_plane = gst_d3d11_dxgi_format_n_planes (desc->Format);
for (i = 0; i < num_plane; i++) {
params->stride[params->plane + i] = data.stride[i];
params->stride[params->plane + i] = stride[i];
}
*size = data.size;
*size = mem_size;
}
mem = g_new0 (GstD3D11Memory, 1);
@ -788,8 +751,7 @@ gst_d3d11_memory_ensure_shader_resource_view (GstD3D11Memory * mem)
return FALSE;
}
gst_d3d11_device_thread_add (mem->device,
(GstD3D11DeviceThreadFunc) create_shader_resource_views, mem);
create_shader_resource_views (mem);
return ! !mem->num_shader_resource_views;
}
@ -809,8 +771,7 @@ gst_d3d11_memory_ensure_render_target_view (GstD3D11Memory * mem)
return FALSE;
}
gst_d3d11_device_thread_add (mem->device,
(GstD3D11DeviceThreadFunc) create_render_target_views, mem);
create_render_target_views (mem);
return ! !mem->num_render_target_views;
}

View file

@ -73,88 +73,68 @@ compile_shader (GstD3D11Device * device, const gchar * shader_source,
return ret;
}
typedef struct
{
const gchar *source;
ID3D11PixelShader *shader;
gboolean ret;
} CreatePSData;
static void
create_pixel_shader (GstD3D11Device * device, CreatePSData * data)
gboolean
gst_d3d11_create_pixel_shader (GstD3D11Device * device,
const gchar * source, ID3D11PixelShader ** shader)
{
ID3DBlob *ps_blob;
ID3D11Device *device_handle;
HRESULT hr;
data->ret = TRUE;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
g_return_val_if_fail (source != NULL, FALSE);
g_return_val_if_fail (shader != NULL, FALSE);
ps_blob = compile_shader (device, data->source, TRUE);
gst_d3d11_device_lock (device);
ps_blob = compile_shader (device, source, TRUE);
if (!ps_blob) {
GST_ERROR ("Failed to compile pixel shader");
data->ret = FALSE;
return;
gst_d3d11_device_unlock (device);
return FALSE;
}
device_handle = gst_d3d11_device_get_device_handle (device);
hr = ID3D11Device_CreatePixelShader (device_handle,
(gpointer) ID3D10Blob_GetBufferPointer (ps_blob),
ID3D10Blob_GetBufferSize (ps_blob), NULL, &data->shader);
ID3D10Blob_GetBufferSize (ps_blob), NULL, shader);
if (!gst_d3d11_result (hr)) {
GST_ERROR ("could not create pixel shader, hr: 0x%x", (guint) hr);
data->ret = FALSE;
gst_d3d11_device_unlock (device);
return FALSE;
}
ID3D10Blob_Release (ps_blob);
gst_d3d11_device_unlock (device);
return TRUE;
}
gboolean
gst_d3d11_create_pixel_shader (GstD3D11Device * device,
const gchar * source, ID3D11PixelShader ** shader)
{
CreatePSData data = { 0, };
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
g_return_val_if_fail (source != NULL, FALSE);
g_return_val_if_fail (shader != NULL, FALSE);
data.source = source;
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) create_pixel_shader, &data);
*shader = data.shader;
return data.ret;
}
typedef struct
{
const gchar *source;
const D3D11_INPUT_ELEMENT_DESC *input_desc;
guint desc_len;
ID3D11VertexShader *shader;
ID3D11InputLayout *layout;
gboolean ret;
} CreateVSData;
static void
create_vertex_shader (GstD3D11Device * device, CreateVSData * data)
gst_d3d11_create_vertex_shader (GstD3D11Device * device, const gchar * source,
const D3D11_INPUT_ELEMENT_DESC * input_desc, guint desc_len,
ID3D11VertexShader ** shader, ID3D11InputLayout ** layout)
{
ID3DBlob *vs_blob;
ID3D11Device *device_handle;
HRESULT hr;
ID3D11VertexShader *vshader = NULL;
ID3D11InputLayout *in_layout = NULL;
gboolean ret = FALSE;
data->ret = TRUE;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
g_return_val_if_fail (source != NULL, FALSE);
g_return_val_if_fail (input_desc != NULL, FALSE);
g_return_val_if_fail (desc_len > 0, FALSE);
g_return_val_if_fail (shader != NULL, FALSE);
g_return_val_if_fail (layout != NULL, FALSE);
vs_blob = compile_shader (device, data->source, FALSE);
gst_d3d11_device_lock (device);
vs_blob = compile_shader (device, source, FALSE);
if (!vs_blob) {
GST_ERROR ("Failed to compile shader code");
data->ret = FALSE;
return;
goto done;
}
device_handle = gst_d3d11_device_get_device_handle (device);
@ -166,52 +146,31 @@ create_vertex_shader (GstD3D11Device * device, CreateVSData * data)
if (!gst_d3d11_result (hr)) {
GST_ERROR ("could not create vertex shader, hr: 0x%x", (guint) hr);
ID3D10Blob_Release (vs_blob);
data->ret = FALSE;
return;
goto done;
}
hr = ID3D11Device_CreateInputLayout (device_handle, data->input_desc,
data->desc_len, (gpointer) ID3D10Blob_GetBufferPointer (vs_blob),
hr = ID3D11Device_CreateInputLayout (device_handle, input_desc,
desc_len, (gpointer) ID3D10Blob_GetBufferPointer (vs_blob),
ID3D10Blob_GetBufferSize (vs_blob), &in_layout);
if (!gst_d3d11_result (hr)) {
GST_ERROR ("could not create input layout shader, hr: 0x%x", (guint) hr);
ID3D10Blob_Release (vs_blob);
ID3D11VertexShader_Release (vshader);
data->ret = FALSE;
return;
goto done;
}
ID3D10Blob_Release (vs_blob);
data->shader = vshader;
data->layout = in_layout;
}
*shader = vshader;
*layout = in_layout;
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)
{
CreateVSData data = { 0, };
ret = TRUE;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
g_return_val_if_fail (source != NULL, FALSE);
g_return_val_if_fail (input_desc != NULL, FALSE);
g_return_val_if_fail (desc_len > 0, FALSE);
g_return_val_if_fail (shader != NULL, FALSE);
g_return_val_if_fail (layout != NULL, FALSE);
done:
gst_d3d11_device_unlock (device);
data.source = source;
data.input_desc = input_desc;
data.desc_len = desc_len;
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) create_vertex_shader, &data);
*shader = data.shader;
*layout = data.layout;
return data.ret;
return ret;
}
struct _GstD3D11Quad
@ -281,9 +240,11 @@ gst_d3d11_quad_new (GstD3D11Device * device, ID3D11PixelShader * pixel_shader,
return quad;
}
static void
quad_free (GstD3D11Device * device, GstD3D11Quad * quad)
void
gst_d3d11_quad_free (GstD3D11Quad * quad)
{
g_return_if_fail (quad != NULL);
if (quad->ps)
ID3D11PixelShader_Release (quad->ps);
if (quad->vs)
@ -298,43 +259,46 @@ quad_free (GstD3D11Device * device, GstD3D11Quad * quad)
ID3D11Buffer_Release (quad->vertex_buffer);
if (quad->index_buffer)
ID3D11Buffer_Release (quad->index_buffer);
}
void
gst_d3d11_quad_free (GstD3D11Quad * quad)
{
g_return_if_fail (quad != NULL);
if (quad->device) {
gst_d3d11_device_thread_add (quad->device,
(GstD3D11DeviceThreadFunc) quad_free, quad);
gst_object_unref (quad->device);
}
gst_clear_object (&quad->device);
g_free (quad);
}
typedef struct
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)
{
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;
gboolean ret;
} DrawQuadData;
static void
gst_d3d11_draw_quad_internal (GstD3D11Device * device, DrawQuadData * data)
g_return_val_if_fail (quad != NULL, FALSE);
gst_d3d11_device_lock (quad->device);
ret = gst_d3d11_draw_quad_unlocked (quad, viewport, num_viewport,
srv, num_srv, rtv, num_viewport);
gst_d3d11_device_unlock (quad->device);
return ret;
}
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)
{
ID3D11DeviceContext *context_handle;
UINT offsets = 0;
ID3D11ShaderResourceView *clear_view[GST_VIDEO_MAX_PLANES] = { NULL, };
GstD3D11Quad *quad = data->quad;
g_return_val_if_fail (quad != NULL, FALSE);
g_return_val_if_fail (viewport != NULL, FALSE);
g_return_val_if_fail (num_viewport <= GST_VIDEO_MAX_PLANES, FALSE);
g_return_val_if_fail (srv != NULL, FALSE);
g_return_val_if_fail (num_srv <= GST_VIDEO_MAX_PLANES, FALSE);
g_return_val_if_fail (rtv != NULL, FALSE);
g_return_val_if_fail (num_rtv <= GST_VIDEO_MAX_PLANES, FALSE);
context_handle = gst_d3d11_device_get_device_context_handle (quad->device);
@ -349,60 +313,20 @@ gst_d3d11_draw_quad_internal (GstD3D11Device * device, DrawQuadData * data)
ID3D11DeviceContext_PSSetSamplers (context_handle, 0, 1, &quad->sampler);
ID3D11DeviceContext_VSSetShader (context_handle, quad->vs, NULL, 0);
ID3D11DeviceContext_PSSetShader (context_handle, quad->ps, NULL, 0);
ID3D11DeviceContext_RSSetViewports (context_handle,
data->num_viewport, data->viewport);
ID3D11DeviceContext_RSSetViewports (context_handle, num_viewport, viewport);
if (quad->const_buffer)
ID3D11DeviceContext_PSSetConstantBuffers (context_handle,
0, 1, &quad->const_buffer);
ID3D11DeviceContext_PSSetShaderResources (context_handle,
0, data->num_srv, data->srv);
ID3D11DeviceContext_OMSetRenderTargets (context_handle,
data->num_rtv, data->rtv, NULL);
ID3D11DeviceContext_PSSetShaderResources (context_handle, 0, num_srv, srv);
ID3D11DeviceContext_OMSetRenderTargets (context_handle, num_rtv, rtv, NULL);
ID3D11DeviceContext_DrawIndexed (context_handle, quad->index_count, 0, 0);
ID3D11DeviceContext_PSSetShaderResources (context_handle,
0, data->num_srv, clear_view);
0, num_srv, clear_view);
ID3D11DeviceContext_OMSetRenderTargets (context_handle, 0, NULL, NULL);
data->ret = TRUE;
}
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)
{
DrawQuadData data = { 0, };
gint i;
g_return_val_if_fail (quad != NULL, FALSE);
g_return_val_if_fail (viewport != NULL, FALSE);
g_return_val_if_fail (num_viewport <= GST_VIDEO_MAX_PLANES, FALSE);
g_return_val_if_fail (srv != NULL, FALSE);
g_return_val_if_fail (num_srv <= GST_VIDEO_MAX_PLANES, FALSE);
g_return_val_if_fail (rtv != NULL, FALSE);
g_return_val_if_fail (num_rtv <= GST_VIDEO_MAX_PLANES, FALSE);
data.quad = quad;
for (i = 0; i < num_viewport; i++)
data.viewport[i] = viewport[i];
data.num_viewport = num_viewport;
for (i = 0; i < num_srv; i++)
data.srv[i] = srv[i];
data.num_srv = num_srv;
for (i = 0; i < num_rtv; i++)
data.rtv[i] = rtv[i];
data.num_rtv = num_rtv;
data.ret = TRUE;
gst_d3d11_device_thread_add (quad->device,
(GstD3D11DeviceThreadFunc) gst_d3d11_draw_quad_internal, &data);
return data.ret;
return TRUE;
}

View file

@ -63,6 +63,14 @@ gboolean gst_d3d11_draw_quad (GstD3D11Quad * quad,
ID3D11RenderTargetView *rtv[GST_VIDEO_MAX_PLANES],
guint num_rtv);
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);
G_END_DECLS
#endif /* __GST_D3D11_SHADER_H__ */

View file

@ -314,32 +314,24 @@ gst_d3d11_upload_decide_allocation (GstBaseTransform * trans, GstQuery * query)
query);
}
typedef struct
{
GstD3D11BaseFilter *filter;
GstBuffer *inbuf;
GstBuffer *outbuf;
GstFlowReturn ret;
} UploadTransformData;
static void
upload_transform_dynamic (GstD3D11Device * device, UploadTransformData * data)
static GstFlowReturn
upload_transform_dynamic (GstD3D11BaseFilter * filter,
GstD3D11Device * device, GstBuffer * inbuf, GstBuffer * outbuf)
{
GstVideoFrame in_frame;
GstD3D11BaseFilter *filter = data->filter;
gint i, j, k;
GstFlowReturn ret = GST_FLOW_OK;
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (device);
data->ret = GST_FLOW_OK;
if (!gst_video_frame_map (&in_frame, &filter->in_info, data->inbuf,
if (!gst_video_frame_map (&in_frame, &filter->in_info, inbuf,
GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF))
goto invalid_buffer;
for (i = 0, j = 0; i < gst_buffer_n_memory (data->outbuf); i++) {
gst_d3d11_device_lock (device);
for (i = 0, j = 0; i < gst_buffer_n_memory (outbuf); i++) {
GstD3D11Memory *dmem =
(GstD3D11Memory *) gst_buffer_peek_memory (data->outbuf, i);
(GstD3D11Memory *) gst_buffer_peek_memory (outbuf, i);
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr;
D3D11_TEXTURE2D_DESC *desc = &dmem->desc;
@ -353,7 +345,8 @@ upload_transform_dynamic (GstD3D11Device * device, UploadTransformData * data)
if (!gst_d3d11_result (hr)) {
GST_ERROR_OBJECT (filter,
"Failed to map staging texture (0x%x)", (guint) hr);
data->ret = GST_FLOW_ERROR;
gst_d3d11_device_unlock (device);
ret = GST_FLOW_ERROR;
goto done;
}
@ -381,35 +374,35 @@ upload_transform_dynamic (GstD3D11Device * device, UploadTransformData * data)
ID3D11DeviceContext_Unmap (device_context,
(ID3D11Resource *) dmem->texture, 0);
}
gst_d3d11_device_unlock (device);
done:
gst_video_frame_unmap (&in_frame);
data->ret = GST_FLOW_OK;
return;
return ret;
/* ERRORS */
invalid_buffer:
{
GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL),
("invalid video buffer received"));
data->ret = GST_FLOW_ERROR;
return;
return GST_FLOW_ERROR;
}
}
static void
upload_transform (GstD3D11Device * device, UploadTransformData * data)
static GstFlowReturn
upload_transform (GstD3D11BaseFilter * filter, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstVideoFrame in_frame, out_frame;
GstD3D11BaseFilter *filter = data->filter;
gint i;
GstFlowReturn ret = GST_FLOW_OK;
if (!gst_video_frame_map (&in_frame, &filter->in_info, data->inbuf,
if (!gst_video_frame_map (&in_frame, &filter->in_info, inbuf,
GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF))
goto invalid_buffer;
if (!gst_video_frame_map (&out_frame, &filter->out_info, data->outbuf,
if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf,
GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)) {
gst_video_frame_unmap (&in_frame);
goto invalid_buffer;
@ -418,24 +411,22 @@ upload_transform (GstD3D11Device * device, UploadTransformData * data)
for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&in_frame); i++) {
if (!gst_video_frame_copy_plane (&out_frame, &in_frame, i)) {
GST_ERROR_OBJECT (filter, "Couldn't copy %dth plane", i);
data->ret = GST_FLOW_ERROR;
return;
ret = GST_FLOW_ERROR;
break;
}
}
gst_video_frame_unmap (&out_frame);
gst_video_frame_unmap (&in_frame);
data->ret = GST_FLOW_OK;
return;
return ret;
/* ERRORS */
invalid_buffer:
{
GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL),
("invalid video buffer received"));
data->ret = GST_FLOW_ERROR;
return;
return GST_FLOW_ERROR;
}
}
@ -446,32 +437,16 @@ gst_d3d11_upload_transform (GstBaseTransform * trans, GstBuffer * inbuf,
GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (trans);
GstMemory *mem;
GstD3D11Device *device;
UploadTransformData data;
gboolean to_dynamic = FALSE;
mem = gst_buffer_peek_memory (outbuf, 0);
if (gst_is_d3d11_memory (mem)) {
GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
device = dmem->device;
if (dmem->desc.Usage == D3D11_USAGE_DYNAMIC)
to_dynamic = TRUE;
} else {
device = filter->device;
if (dmem->desc.Usage == D3D11_USAGE_DYNAMIC) {
return upload_transform_dynamic (filter, device, inbuf, outbuf);
}
}
data.filter = filter;
data.inbuf = inbuf;
data.outbuf = outbuf;
data.ret = GST_FLOW_OK;
if (to_dynamic) {
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) upload_transform_dynamic, &data);
} else {
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) upload_transform, &data);
}
return data.ret;
return upload_transform (filter, inbuf, outbuf);
}

View file

@ -70,15 +70,6 @@ GST_DEBUG_CATEGORY_STATIC (gst_d3d11_window_debug);
#define gst_d3d11_window_parent_class parent_class
G_DEFINE_TYPE (GstD3D11Window, gst_d3d11_window, GST_TYPE_OBJECT);
typedef struct
{
GstD3D11Window *window;
GstVideoRectangle *rect;
GstBuffer *buffer;
GstFlowReturn ret;
} FramePresentData;
static void gst_d3d11_window_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_d3d11_window_get_property (GObject * object, guint prop_id,
@ -87,12 +78,11 @@ static void gst_d3d11_window_constructed (GObject * object);
static void gst_d3d11_window_dispose (GObject * object);
static void gst_d3d11_window_finalize (GObject * object);
static gpointer gst_d3d11_window_thread_func (gpointer data);
static gboolean _create_window (GstD3D11Window * self);
static void _open_window (GstD3D11Window * self);
static void _close_window (GstD3D11Window * self);
static gboolean gst_d3d11_window_create_internal_window (GstD3D11Window * self);
static void gst_d3d11_window_close_internal_window (GstD3D11Window * self);
static void release_external_win_id (GstD3D11Window * self);
static void _present_on_device_thread (GstD3D11Device * device,
FramePresentData * data);
static GstFlowReturn gst_d3d111_window_present (GstD3D11Window * self,
GstBuffer * buffer);
static void
gst_d3d11_window_class_init (GstD3D11WindowClass * klass)
@ -268,8 +258,7 @@ gst_d3d11_window_dispose (GObject * object)
}
if (self->device) {
gst_d3d11_device_thread_add (self->device,
(GstD3D11DeviceThreadFunc) gst_d3d11_window_release_resources, self);
gst_d3d11_window_release_resources (self->device, self);
}
if (self->converter) {
@ -317,20 +306,16 @@ gst_d3d11_window_thread_func (gpointer data)
GST_DEBUG_OBJECT (self, "Enter loop");
g_main_context_push_thread_default (self->main_context);
self->created = _create_window (self);
self->created = gst_d3d11_window_create_internal_window (self);
source = g_idle_source_new ();
g_source_set_callback (source, (GSourceFunc) running_cb, self, NULL);
g_source_attach (source, self->main_context);
g_source_unref (source);
if (self->created)
_open_window (self);
g_main_loop_run (self->loop);
if (self->created)
_close_window (self);
gst_d3d11_window_close_internal_window (self);
g_main_context_pop_thread_default (self->main_context);
@ -354,16 +339,7 @@ msg_cb (GIOChannel * source, GIOCondition condition, gpointer data)
}
static void
_open_window (GstD3D11Window * self)
{
self->msg_io_channel = g_io_channel_win32_new_messages (0);
self->msg_source = g_io_create_watch (self->msg_io_channel, G_IO_IN);
g_source_set_callback (self->msg_source, (GSourceFunc) msg_cb, self, NULL);
g_source_attach (self->msg_source, self->main_context);
}
static void
_close_window (GstD3D11Window * self)
gst_d3d11_window_close_internal_window (GstD3D11Window * self)
{
if (self->internal_win_id) {
RemoveProp (self->internal_win_id, D3D11_WINDOW_PROP_NAME);
@ -451,7 +427,7 @@ release_external_win_id (GstD3D11Window * self)
}
static gboolean
_create_window (GstD3D11Window * self)
gst_d3d11_window_create_internal_window (GstD3D11Window * self)
{
WNDCLASSEX wc;
ATOM atom = 0;
@ -519,36 +495,45 @@ _create_window (GstD3D11Window * self)
GST_LOG_OBJECT (self,
"Created a internal d3d11 window %p", self->internal_win_id);
self->msg_io_channel =
g_io_channel_win32_new_messages ((guintptr) self->internal_win_id);
self->msg_source = g_io_create_watch (self->msg_io_channel, G_IO_IN);
g_source_set_callback (self->msg_source, (GSourceFunc) msg_cb, self, NULL);
g_source_attach (self->msg_source, self->main_context);
return TRUE;
}
static void
gst_d3d11_window_on_resize (GstD3D11Device * device, GstD3D11Window * window)
gst_d3d11_window_on_resize (GstD3D11Window * window, gboolean redraw)
{
HRESULT hr;
ID3D11Device *d3d11_dev;
guint width, height;
D3D11_TEXTURE2D_DESC desc;
DXGI_SWAP_CHAIN_DESC swap_desc;
ID3D11Texture2D *backbuffer;
ID3D11Texture2D *backbuffer = NULL;
gst_d3d11_device_lock (window->device);
if (!window->swap_chain)
return;
goto done;
d3d11_dev = gst_d3d11_device_get_device_handle (device);
d3d11_dev = gst_d3d11_device_get_device_handle (window->device);
if (window->rtv) {
ID3D11RenderTargetView_Release (window->rtv);
window->rtv = NULL;
}
window->pending_resize = FALSE;
/* Set zero width and height here. dxgi will decide client area by itself */
IDXGISwapChain_GetDesc (window->swap_chain, &swap_desc);
hr = IDXGISwapChain_ResizeBuffers (window->swap_chain,
0, 0, 0, DXGI_FORMAT_UNKNOWN, swap_desc.Flags);
if (!gst_d3d11_result (hr)) {
GST_ERROR_OBJECT (window, "Couldn't resize buffers, hr: 0x%x", (guint) hr);
return;
goto done;
}
hr = IDXGISwapChain_GetBuffer (window->swap_chain,
@ -556,7 +541,7 @@ gst_d3d11_window_on_resize (GstD3D11Device * device, GstD3D11Window * window)
if (!gst_d3d11_result (hr)) {
GST_ERROR_OBJECT (window,
"Cannot get backbuffer from swapchain, hr: 0x%x", (guint) hr);
return;
goto done;
}
ID3D11Texture2D_GetDesc (backbuffer, &desc);
@ -604,27 +589,14 @@ gst_d3d11_window_on_resize (GstD3D11Device * device, GstD3D11Window * window)
goto done;
}
if (window->cached_buffer) {
FramePresentData present_data = { 0, };
present_data.window = window;
present_data.rect = &window->rect;
present_data.buffer = window->cached_buffer;
GST_DEBUG_OBJECT (window, "redraw cached buffer");
_present_on_device_thread (window->device, &present_data);
}
if (redraw)
gst_d3d111_window_present (window, NULL);
done:
ID3D11Texture2D_Release (backbuffer);
}
if (backbuffer)
ID3D11Texture2D_Release (backbuffer);
static void
gst_d3d11_window_on_size (GstD3D11Window * self,
HWND hWnd, WPARAM wParam, LPARAM lParam)
{
gst_d3d11_device_thread_add_full (self->device, G_PRIORITY_HIGH,
(GstD3D11DeviceThreadFunc) gst_d3d11_window_on_resize, self, NULL);
gst_d3d11_device_unlock (window->device);
}
static void
@ -707,12 +679,12 @@ gst_d3d11_window_handle_window_proc (GstD3D11Window * self,
{
switch (uMsg) {
case WM_SIZE:
gst_d3d11_window_on_size (self, hWnd, wParam, lParam);
gst_d3d11_window_on_resize (self, TRUE);
break;
case WM_CLOSE:
if (self->internal_win_id) {
ShowWindow (self->internal_win_id, SW_HIDE);
_close_window (self);
gst_d3d11_window_close_internal_window (self);
}
break;
case WM_KEYDOWN:
@ -760,6 +732,9 @@ window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
gst_d3d11_window_handle_window_proc (self, hWnd, uMsg, wParam, lParam);
}
if (uMsg == WM_SIZE)
return 0;
return DefWindowProc (hWnd, uMsg, wParam, lParam);
}
@ -964,33 +939,26 @@ gst_d3d11_window_color_space_from_video_info (GstD3D11Window * self,
}
#endif
typedef struct
{
GstD3D11Window *self;
HWND hwnd;
IDXGISwapChain *swap_chain;
} MakeWindowAssociationData;
static void
gst_d3d11_window_disable_alt_enter (GstD3D11Device * device,
MakeWindowAssociationData * data)
gst_d3d11_window_disable_alt_enter (GstD3D11Window * window,
IDXGISwapChain * swap_chain, HWND hwnd)
{
IDXGIFactory1 *factory = NULL;
HRESULT hr;
hr = IDXGISwapChain_GetParent (data->swap_chain, &IID_IDXGIFactory1,
hr = IDXGISwapChain_GetParent (swap_chain, &IID_IDXGIFactory1,
(void **) &factory);
if (!gst_d3d11_result (hr) || !factory) {
GST_WARNING_OBJECT (data->self,
GST_WARNING_OBJECT (window,
"Cannot get parent dxgi factory for swapchain %p, hr: 0x%x",
data->swap_chain, (guint) hr);
swap_chain, (guint) hr);
return;
}
hr = IDXGIFactory1_MakeWindowAssociation (factory,
data->hwnd, DXGI_MWA_NO_ALT_ENTER);
hwnd, DXGI_MWA_NO_ALT_ENTER);
if (!gst_d3d11_result (hr)) {
GST_WARNING_OBJECT (data->self,
GST_WARNING_OBJECT (window,
"MakeWindowAssociation failure, hr: 0x%x", (guint) hr);
}
@ -1003,7 +971,6 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height,
{
DXGI_SWAP_CHAIN_DESC desc = { 0, };
GstCaps *render_caps;
MakeWindowAssociationData mwa_data = { 0, };
UINT swapchain_flags = 0;
DXGI_SWAP_EFFECT swap_effect = DXGI_SWAP_EFFECT_DISCARD;
#if (DXGI_HEADER_VERSION >= 5)
@ -1112,8 +1079,9 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height,
#endif
if (window->swap_chain) {
gst_d3d11_device_thread_add (window->device,
(GstD3D11DeviceThreadFunc) gst_d3d11_window_release_resources, window);
gst_d3d11_device_lock (window->device);
gst_d3d11_window_release_resources (window->device, window);
gst_d3d11_device_unlock (window->device);
}
window->aspect_ratio_n = aspect_ratio_n;
@ -1205,11 +1173,10 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height,
}
/* disable alt+enter here. It should be manually handled */
mwa_data.self = window;
mwa_data.swap_chain = window->swap_chain;
mwa_data.hwnd = desc.OutputWindow;
gst_d3d11_device_thread_add (window->device,
(GstD3D11DeviceThreadFunc) gst_d3d11_window_disable_alt_enter, &mwa_data);
gst_d3d11_device_lock (window->device);
gst_d3d11_window_disable_alt_enter (window,
window->swap_chain, desc.OutputWindow);
gst_d3d11_device_unlock (window->device);
#if (DXGI_HEADER_VERSION >= 5)
if (swapchain4_available) {
@ -1252,12 +1219,10 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height,
}
#endif
gst_d3d11_device_thread_add (window->device,
(GstD3D11DeviceThreadFunc) gst_d3d11_window_on_resize, window);
gst_d3d11_window_on_resize (window, FALSE);
if (!window->rtv) {
gst_d3d11_device_thread_add (window->device,
(GstD3D11DeviceThreadFunc) gst_d3d11_window_release_resources, window);
gst_d3d11_window_release_resources (window->device, window);
GST_ERROR_OBJECT (window, "Failed to setup internal resources");
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
"Failed to setup internal resources");
@ -1337,28 +1302,15 @@ gst_d3d11_window_set_render_rectangle (GstD3D11Window * window, gint x, gint y,
/* TODO: resize window and view */
}
void
gst_d3d11_window_get_surface_dimensions (GstD3D11Window * window,
guint * width, guint * height)
static GstFlowReturn
gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer)
{
g_return_if_fail (GST_IS_D3D11_WINDOW (window));
if (width)
*width = window->surface_width;
if (height)
*height = window->surface_height;
}
static void
_present_on_device_thread (GstD3D11Device * device, FramePresentData * data)
{
GstD3D11Window *self = data->window;
ID3D11DeviceContext *device_context;
HRESULT hr;
UINT present_flags = DXGI_PRESENT_DO_NOT_WAIT;
UINT present_flags = 0;
device_context = gst_d3d11_device_get_device_context_handle (device);
gst_buffer_replace (&self->cached_buffer, data->buffer);
if (buffer) {
gst_buffer_replace (&self->cached_buffer, buffer);
}
if (self->cached_buffer) {
ID3D11ShaderResourceView *srv[GST_VIDEO_MAX_PLANES];
@ -1381,29 +1333,30 @@ _present_on_device_thread (GstD3D11Device * device, FramePresentData * data)
gst_d3d11_color_converter_update_rect (self->converter, &rect);
gst_d3d11_color_converter_convert (self->converter, srv, &self->rtv);
}
#if (DXGI_HEADER_VERSION >= 5)
if (self->allow_tearing) {
present_flags |= DXGI_PRESENT_ALLOW_TEARING;
}
if (self->allow_tearing) {
present_flags |= DXGI_PRESENT_ALLOW_TEARING;
}
#endif
hr = IDXGISwapChain_Present (self->swap_chain, 0, present_flags);
hr = IDXGISwapChain_Present (self->swap_chain, 0, present_flags);
if (!gst_d3d11_result (hr)) {
GST_WARNING_OBJECT (self, "Direct3D cannot present texture, hr: 0x%x",
(guint) hr);
if (!gst_d3d11_result (hr)) {
GST_WARNING_OBJECT (self, "Direct3D cannot present texture, hr: 0x%x",
(guint) hr);
}
}
data->ret = GST_FLOW_OK;
return GST_FLOW_OK;
}
GstFlowReturn
gst_d3d11_window_render (GstD3D11Window * window, GstBuffer * buffer,
GstVideoRectangle * rect)
{
FramePresentData data;
GstMemory *mem;
GstFlowReturn ret;
g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), GST_FLOW_ERROR);
g_return_val_if_fail (rect != NULL, GST_FLOW_ERROR);
@ -1428,28 +1381,15 @@ gst_d3d11_window_render (GstD3D11Window * window, GstBuffer * buffer,
GST_OBJECT_LOCK (window);
if (window->pending_resize) {
gst_d3d11_device_thread_add (window->device,
(GstD3D11DeviceThreadFunc) gst_d3d11_window_on_resize, window);
window->pending_resize = FALSE;
gst_d3d11_window_on_resize (window, FALSE);
}
GST_OBJECT_UNLOCK (window);
data.window = window;
data.rect = rect;
data.buffer = buffer;
data.ret = GST_FLOW_OK;
gst_d3d11_device_lock (window->device);
ret = gst_d3d111_window_present (window, buffer);
gst_d3d11_device_unlock (window->device);
gst_d3d11_device_thread_add (window->device,
(GstD3D11DeviceThreadFunc) _present_on_device_thread, &data);
return data.ret;
}
static void
gst_d3d11_window_flush_internal (GstD3D11Device * device,
GstD3D11Window * window)
{
gst_clear_buffer (&window->cached_buffer);
return ret;
}
gboolean
@ -1457,8 +1397,7 @@ gst_d3d11_window_flush (GstD3D11Window * window)
{
g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), FALSE);
gst_d3d11_device_thread_add (window->device,
(GstD3D11DeviceThreadFunc) gst_d3d11_window_flush_internal, window);
gst_clear_buffer (&window->cached_buffer);
return TRUE;
}

View file

@ -128,10 +128,6 @@ void gst_d3d11_window_set_render_rectangle (GstD3D11Window * window
gint x, gint y,
gint width, gint height);
void gst_d3d11_window_get_surface_dimensions (GstD3D11Window * window,
guint * width,
guint * height);
gboolean gst_d3d11_window_prepare (GstD3D11Window * window,
guint width,
guint height,