struct _GstD3D11BufferPoolPrivate
{
- GstD3D11Device *device;
- GstD3D11Allocator *allocator;
+ GstD3D11Allocator *alloc[GST_VIDEO_MAX_PLANES];
- gboolean add_videometa;
GstD3D11AllocationParams *d3d11_params;
+ gboolean texture_array_pool;
gint stride[GST_VIDEO_MAX_PLANES];
- gsize size[GST_VIDEO_MAX_PLANES];
gsize offset[GST_VIDEO_MAX_PLANES];
};
static const gchar **gst_d3d11_buffer_pool_get_options (GstBufferPool * pool);
static gboolean gst_d3d11_buffer_pool_set_config (GstBufferPool * pool,
GstStructure * config);
-static GstFlowReturn gst_d3d11_buffer_pool_alloc (GstBufferPool * pool,
+static GstFlowReturn gst_d3d11_buffer_pool_alloc_buffer (GstBufferPool * pool,
GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
-static void gst_d3d11_buffer_pool_flush_start (GstBufferPool * pool);
-static void gst_d3d11_buffer_pool_flush_stop (GstBufferPool * pool);
+static GstFlowReturn gst_d3d11_buffer_pool_acquire_buffer (GstBufferPool * pool,
+ GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
+static void gst_d3d11_buffer_pool_reset_buffer (GstBufferPool * pool,
+ GstBuffer * buffer);
+static gboolean gst_d3d11_buffer_pool_start (GstBufferPool * pool);
+static gboolean gst_d3d11_buffer_pool_stop (GstBufferPool * pool);
static void
gst_d3d11_buffer_pool_class_init (GstD3D11BufferPoolClass * klass)
bufferpool_class->get_options = gst_d3d11_buffer_pool_get_options;
bufferpool_class->set_config = gst_d3d11_buffer_pool_set_config;
- bufferpool_class->alloc_buffer = gst_d3d11_buffer_pool_alloc;
- bufferpool_class->flush_start = gst_d3d11_buffer_pool_flush_start;
- bufferpool_class->flush_stop = gst_d3d11_buffer_pool_flush_stop;
+ bufferpool_class->alloc_buffer = gst_d3d11_buffer_pool_alloc_buffer;
+ bufferpool_class->acquire_buffer = gst_d3d11_buffer_pool_acquire_buffer;
+ bufferpool_class->reset_buffer = gst_d3d11_buffer_pool_reset_buffer;
+ bufferpool_class->start = gst_d3d11_buffer_pool_start;
+ bufferpool_class->stop = gst_d3d11_buffer_pool_stop;
GST_DEBUG_CATEGORY_INIT (gst_d3d11_buffer_pool_debug, "d3d11bufferpool", 0,
"d3d11bufferpool object");
}
static void
+gst_d3d11_buffer_pool_clear_allocator (GstD3D11BufferPool * self)
+{
+ GstD3D11BufferPoolPrivate *priv = self->priv;
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
+ if (priv->alloc[i]) {
+ gst_d3d11_allocator_set_active (priv->alloc[i], FALSE);
+ gst_clear_object (&priv->alloc[i]);
+ }
+ }
+}
+
+static void
gst_d3d11_buffer_pool_dispose (GObject * object)
{
GstD3D11BufferPool *self = GST_D3D11_BUFFER_POOL (object);
GstD3D11BufferPoolPrivate *priv = self->priv;
- if (priv->d3d11_params)
- gst_d3d11_allocation_params_free (priv->d3d11_params);
- priv->d3d11_params = NULL;
-
- gst_clear_object (&priv->device);
- gst_clear_object (&priv->allocator);
+ g_clear_pointer (&priv->d3d11_params, gst_d3d11_allocation_params_free);
+ gst_clear_object (&self->device);
+ gst_d3d11_buffer_pool_clear_allocator (self);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
return options;
}
-static GstBuffer *
-allocate_staging_buffer (GstD3D11Allocator * allocator,
- const GstVideoInfo * info, const GstD3D11Format * format,
- const D3D11_TEXTURE2D_DESC desc[GST_VIDEO_MAX_PLANES],
- gboolean add_videometa)
-{
- GstBuffer *buffer;
- gint i;
- gint stride[GST_VIDEO_MAX_PLANES] = { 0, };
- gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
- GstMemory *mem;
-
- g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), NULL);
- g_return_val_if_fail (info != NULL, NULL);
- g_return_val_if_fail (format != NULL, NULL);
- g_return_val_if_fail (desc != NULL, NULL);
-
- buffer = gst_buffer_new ();
-
- if (format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
- gsize size[GST_VIDEO_MAX_PLANES] = { 0, };
-
- for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
- mem = gst_d3d11_allocator_alloc_staging (allocator, &desc[i], 0,
- &stride[i]);
-
- if (!mem) {
- GST_ERROR_OBJECT (allocator, "Couldn't allocate memory for plane %d",
- i);
- goto error;
- }
-
- size[i] = gst_memory_get_sizes (mem, NULL, NULL);
- if (i > 0)
- offset[i] = offset[i - 1] + size[i - 1];
- gst_buffer_append_memory (buffer, mem);
- }
- } else {
- /* must be YUV semi-planar or single plane */
- g_assert (GST_VIDEO_INFO_N_PLANES (info) <= 2);
-
- mem = gst_d3d11_allocator_alloc_staging (allocator, &desc[0], 0,
- &stride[0]);
-
- if (!mem) {
- GST_ERROR_OBJECT (allocator, "Couldn't allocate memory");
- goto error;
- }
-
- gst_memory_get_sizes (mem, NULL, NULL);
- gst_buffer_append_memory (buffer, mem);
-
- if (GST_VIDEO_INFO_N_PLANES (info) == 2) {
- stride[1] = stride[0];
- offset[1] = stride[0] * desc[0].Height;
- }
- }
-
- if (add_videometa) {
- gst_buffer_add_video_meta_full (buffer, GST_VIDEO_FRAME_FLAG_NONE,
- GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
- GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
- offset, stride);
- }
-
- return buffer;
-
-error:
- gst_buffer_unref (buffer);
-
- return NULL;
-}
-
static gboolean
gst_d3d11_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
{
GstVideoInfo info;
GstCaps *caps = NULL;
guint min_buffers, max_buffers;
- GstAllocator *allocator = NULL;
gboolean ret = TRUE;
D3D11_TEXTURE2D_DESC *desc;
- GstBuffer *staging_buffer;
+ const GstD3D11Format *format;
+ gsize offset = 0;
gint i;
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min_buffers,
GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height,
caps);
- if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
- goto wrong_config;
-
- gst_clear_object (&priv->allocator);
-
- if (allocator) {
- if (!GST_IS_D3D11_ALLOCATOR (allocator)) {
- goto wrong_allocator;
- } else {
- priv->allocator = gst_object_ref (allocator);
- }
- } else {
- priv->allocator = gst_d3d11_allocator_new (priv->device);
- g_assert (priv->allocator);
- }
+ gst_d3d11_buffer_pool_clear_allocator (self);
- priv->add_videometa = gst_buffer_pool_config_has_option (config,
- GST_BUFFER_POOL_OPTION_VIDEO_META);
+ memset (priv->stride, 0, sizeof (priv->stride));
+ memset (priv->offset, 0, sizeof (priv->offset));
if (priv->d3d11_params)
gst_d3d11_allocation_params_free (priv->d3d11_params);
if (!priv->d3d11_params) {
/* allocate memory with resource format by default */
priv->d3d11_params =
- gst_d3d11_allocation_params_new (priv->device, &info, 0, 0);
+ gst_d3d11_allocation_params_new (self->device, &info, 0, 0);
}
desc = priv->d3d11_params->desc;
max_buffers, max_array_size);
max_buffers = max_array_size;
}
- }
-
- staging_buffer = allocate_staging_buffer (priv->allocator,
- &info, priv->d3d11_params->d3d11_format, priv->d3d11_params->desc, TRUE);
- if (!staging_buffer) {
- GST_ERROR_OBJECT (pool, "Couldn't allocated staging buffer");
- return FALSE;
+ priv->texture_array_pool = TRUE;
} else {
- GstVideoMeta *meta = gst_buffer_get_video_meta (staging_buffer);
+ priv->texture_array_pool = FALSE;
+ }
- if (!meta) {
- GST_ERROR_OBJECT (pool, "Buffer doesn't have video meta");
- gst_buffer_unref (staging_buffer);
+ offset = 0;
+ for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
+ GstD3D11Allocator *alloc;
+ GstD3D11PoolAllocator *pool_alloc;
+ GstFlowReturn flow_ret;
+ GstMemory *mem = NULL;
+ guint stride = 0;
+
+ if (desc[i].Format == DXGI_FORMAT_UNKNOWN)
+ break;
+
+ alloc =
+ (GstD3D11Allocator *) gst_d3d11_pool_allocator_new (self->device,
+ &desc[i]);
+ if (!gst_d3d11_allocator_set_active (alloc, TRUE)) {
+ GST_ERROR_OBJECT (self, "Failed to activate allocator");
+ gst_object_unref (alloc);
return FALSE;
}
- for (i = 0; i < gst_buffer_n_memory (staging_buffer); i++) {
- GstMemory *mem = gst_buffer_peek_memory (staging_buffer, i);
+ pool_alloc = GST_D3D11_POOL_ALLOCATOR (alloc);
+ flow_ret = gst_d3d11_pool_allocator_acquire_memory (pool_alloc, &mem);
+ if (flow_ret != GST_FLOW_OK) {
+ GST_ERROR_OBJECT (self, "Failed to allocate initial memory");
+ gst_d3d11_allocator_set_active (alloc, FALSE);
+ gst_object_unref (alloc);
+ return FALSE;
+ }
- priv->size[i] = gst_memory_get_sizes (mem, NULL, NULL);
+ if (!gst_d3d11_memory_get_texture_stride (GST_D3D11_MEMORY_CAST (mem),
+ &stride) || stride < desc[i].Width) {
+ GST_ERROR_OBJECT (self, "Failed to calculate stride");
+
+ gst_d3d11_allocator_set_active (alloc, FALSE);
+ gst_object_unref (alloc);
+ gst_memory_unref (mem);
+
+ return FALSE;
}
- memcpy (priv->offset, meta->offset, sizeof (priv->offset));
- memcpy (priv->stride, meta->stride, sizeof (priv->stride));
+ priv->stride[i] = stride;
+ priv->offset[i] = offset;
+ offset += mem->size;
+
+ priv->alloc[i] = alloc;
+
+ gst_memory_unref (mem);
+ }
+
+ g_assert (priv->d3d11_params->d3d11_format != NULL);
+ format = priv->d3d11_params->d3d11_format;
+ /* single texture semi-planar formats */
+ if (format->dxgi_format != DXGI_FORMAT_UNKNOWN &&
+ GST_VIDEO_INFO_N_PLANES (&info) == 2) {
+ priv->stride[1] = priv->stride[0];
+ priv->offset[1] = priv->stride[0] * desc[0].Height;
}
- self->buffer_size = gst_buffer_get_size (staging_buffer);
- gst_buffer_unref (staging_buffer);
+ self->buffer_size = offset;
gst_buffer_pool_config_set_params (config,
caps, self->buffer_size, min_buffers, max_buffers);
"failed getting geometry from caps %" GST_PTR_FORMAT, caps);
return FALSE;
}
-wrong_allocator:
- {
- GST_WARNING_OBJECT (pool, "Incorrect allocator type for this pool");
- return FALSE;
- }
}
static GstFlowReturn
-gst_d3d11_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
- GstBufferPoolAcquireParams * params)
+gst_d3d11_buffer_pool_fill_buffer (GstD3D11BufferPool * self, GstBuffer * buf)
{
- GstD3D11BufferPool *self = GST_D3D11_BUFFER_POOL (pool);
GstD3D11BufferPoolPrivate *priv = self->priv;
- GstMemory *mem;
- GstBuffer *buf;
- GstD3D11AllocationParams *d3d11_params = priv->d3d11_params;
- GstVideoInfo *info = &d3d11_params->info;
+ GstFlowReturn ret = GST_FLOW_OK;
gint i;
- buf = gst_buffer_new ();
+ for (i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
+ GstMemory *mem = NULL;
+ GstD3D11PoolAllocator *alloc = GST_D3D11_POOL_ALLOCATOR (priv->alloc[i]);
- if (d3d11_params->d3d11_format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
- for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
- mem = gst_d3d11_allocator_alloc (priv->allocator, &d3d11_params->desc[i],
- d3d11_params->flags, priv->size[i]);
- if (!mem)
- goto error;
+ if (!alloc)
+ break;
- gst_buffer_append_memory (buf, mem);
+ ret = gst_d3d11_pool_allocator_acquire_memory (alloc, &mem);
+ if (ret != GST_FLOW_OK) {
+ GST_WARNING_OBJECT (self, "Failed to acquire memory, ret %s",
+ gst_flow_get_name (ret));
+ return ret;
}
- } else {
- mem = gst_d3d11_allocator_alloc (priv->allocator, &d3d11_params->desc[0],
- d3d11_params->flags, priv->size[0]);
-
- if (!mem)
- goto error;
gst_buffer_append_memory (buf, mem);
}
- if (priv->add_videometa) {
- GST_DEBUG_OBJECT (self, "adding GstVideoMeta");
- gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
- GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
- GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
- priv->offset, priv->stride);
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_d3d11_buffer_pool_alloc_buffer (GstBufferPool * pool, GstBuffer ** buffer,
+ GstBufferPoolAcquireParams * params)
+{
+ GstD3D11BufferPool *self = GST_D3D11_BUFFER_POOL (pool);
+ GstD3D11BufferPoolPrivate *priv = self->priv;
+ GstD3D11AllocationParams *d3d11_params = priv->d3d11_params;
+ GstVideoInfo *info = &d3d11_params->info;
+ GstBuffer *buf;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ buf = gst_buffer_new ();
+ /* For texture-array case, we release memory in reset_buffer() so that it can
+ * be returned to allocator. So our acquire_buffer() method is expecting
+ * empty buffer in that case. Don't fill memory here for non-texture-array */
+ if (!priv->texture_array_pool) {
+ ret = gst_d3d11_buffer_pool_fill_buffer (self, buf);
+ if (ret != GST_FLOW_OK) {
+ gst_buffer_unref (buf);
+ return ret;
+ }
}
+ gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
+ GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
+ GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
+ priv->offset, priv->stride);
+
*buffer = buf;
return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_d3d11_buffer_pool_acquire_buffer (GstBufferPool * pool,
+ GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
+{
+ GstD3D11BufferPool *self = GST_D3D11_BUFFER_POOL (pool);
+ GstD3D11BufferPoolPrivate *priv = self->priv;
+ GstFlowReturn ret;
-error:
- gst_buffer_unref (buf);
+ ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (pool,
+ buffer, params);
- GST_ERROR_OBJECT (self, "cannot create texture memory");
+ if (ret != GST_FLOW_OK)
+ return ret;
- return GST_FLOW_ERROR;
+ /* Don't need special handling for non-texture-array case */
+ if (!priv->texture_array_pool)
+ return ret;
+
+ /* Baseclass will hold empty buffer in this case, fill GstMemory */
+ g_assert (gst_buffer_n_memory (*buffer) == 0);
+
+ return gst_d3d11_buffer_pool_fill_buffer (self, *buffer);
}
static void
-gst_d3d11_buffer_pool_flush_start (GstBufferPool * pool)
+gst_d3d11_buffer_pool_reset_buffer (GstBufferPool * pool, GstBuffer * buffer)
{
GstD3D11BufferPool *self = GST_D3D11_BUFFER_POOL (pool);
GstD3D11BufferPoolPrivate *priv = self->priv;
- if (priv->allocator)
- gst_d3d11_allocator_set_flushing (priv->allocator, TRUE);
+ /* if we are using texture array, return memory to allocator, so that
+ * memory pool allocator can wake up if it's waiting for available memory */
+ if (priv->texture_array_pool) {
+ GST_LOG_OBJECT (self, "Returning memory to allocator");
+ gst_buffer_remove_all_memory (buffer);
+ }
+
+ GST_BUFFER_POOL_CLASS (parent_class)->reset_buffer (pool, buffer);
+ GST_BUFFER_FLAGS (buffer) = 0;
}
-static void
-gst_d3d11_buffer_pool_flush_stop (GstBufferPool * pool)
+static gboolean
+gst_d3d11_buffer_pool_start (GstBufferPool * pool)
+{
+ GstD3D11BufferPool *self = GST_D3D11_BUFFER_POOL (pool);
+ GstD3D11BufferPoolPrivate *priv = self->priv;
+ guint i;
+ gboolean ret;
+
+ GST_DEBUG_OBJECT (self, "Start");
+
+ for (i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
+ GstD3D11Allocator *alloc = priv->alloc[i];
+
+ if (!alloc)
+ break;
+
+ if (!gst_d3d11_allocator_set_active (alloc, TRUE)) {
+ GST_ERROR_OBJECT (self, "Failed to activate allocator");
+ return FALSE;
+ }
+ }
+
+ ret = GST_BUFFER_POOL_CLASS (parent_class)->start (pool);
+ if (!ret) {
+ GST_ERROR_OBJECT (self, "Failed to start");
+
+ for (i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
+ GstD3D11Allocator *alloc = priv->alloc[i];
+
+ if (!alloc)
+ break;
+
+ gst_d3d11_allocator_set_active (alloc, FALSE);
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gst_d3d11_buffer_pool_stop (GstBufferPool * pool)
{
GstD3D11BufferPool *self = GST_D3D11_BUFFER_POOL (pool);
GstD3D11BufferPoolPrivate *priv = self->priv;
+ guint i;
+
+ GST_DEBUG_OBJECT (self, "Stop");
+
+ for (i = 0; i < G_N_ELEMENTS (priv->alloc); i++) {
+ GstD3D11Allocator *alloc = priv->alloc[i];
+
+ if (!alloc)
+ break;
+
+ if (!gst_d3d11_allocator_set_active (alloc, FALSE)) {
+ GST_ERROR_OBJECT (self, "Failed to deactivate allocator");
+ return FALSE;
+ }
+ }
- if (priv->allocator)
- gst_d3d11_allocator_set_flushing (priv->allocator, FALSE);
+ return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool);
}
/**
gst_d3d11_buffer_pool_new (GstD3D11Device * device)
{
GstD3D11BufferPool *pool;
- GstD3D11Allocator *alloc;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
pool = g_object_new (GST_TYPE_D3D11_BUFFER_POOL, NULL);
- alloc = gst_d3d11_allocator_new (device);
+ gst_object_ref_sink (pool);
- pool->priv->device = gst_object_ref (device);
- pool->priv->allocator = alloc;
+ pool->device = gst_object_ref (device);
return GST_BUFFER_POOL_CAST (pool);
}
GST_DEBUG_CATEGORY_STATIC (gst_d3d11_allocator_debug);
#define GST_CAT_DEFAULT gst_d3d11_allocator_debug
-#define GST_D3D11_ALLOCATOR_GET_LOCK(a) (&(GST_D3D11_ALLOCATOR_CAST(a)->priv->lock))
-#define GST_D3D11_ALLOCATOR_LOCK(a) g_mutex_lock(GST_D3D11_ALLOCATOR_GET_LOCK(a))
-#define GST_D3D11_ALLOCATOR_UNLOCK(a) g_mutex_unlock(GST_D3D11_ALLOCATOR_GET_LOCK(a))
+static GstAllocator *_d3d11_memory_allocator;
-#define GST_D3D11_MEMORY_CAST(m) ((GstD3D11Memory *) m)
-#define GST_D3D11_MEMORY_GET_LOCK(m) (&(GST_D3D11_MEMORY_CAST(m)->priv->lock))
-#define GST_D3D11_MEMORY_LOCK(m) g_mutex_lock(GST_D3D11_MEMORY_GET_LOCK(m))
-#define GST_D3D11_MEMORY_UNLOCK(m) g_mutex_unlock(GST_D3D11_MEMORY_GET_LOCK(m))
-
-#define GST_D3D11_MEMORY_NAME "D3D11Memory"
+/* GstD3D11AllocationParams */
+static void gst_d3d11_allocation_params_init (GType type);
+G_DEFINE_BOXED_TYPE_WITH_CODE (GstD3D11AllocationParams,
+ gst_d3d11_allocation_params,
+ (GBoxedCopyFunc) gst_d3d11_allocation_params_copy,
+ (GBoxedFreeFunc) gst_d3d11_allocation_params_free,
+ gst_d3d11_allocation_params_init (g_define_type_id));
/**
* gst_d3d11_allocation_params_new:
}
static void
-_init_alloc_params (GType type)
+gst_d3d11_allocation_params_init (GType type)
{
static GstValueTable table = {
0, (GstValueCompareFunc) gst_d3d11_allocation_params_compare,
gst_value_register (&table);
}
-G_DEFINE_BOXED_TYPE_WITH_CODE (GstD3D11AllocationParams,
- gst_d3d11_allocation_params,
- (GBoxedCopyFunc) gst_d3d11_allocation_params_copy,
- (GBoxedFreeFunc) gst_d3d11_allocation_params_free,
- _init_alloc_params (g_define_type_id));
-
-typedef enum
-{
- GST_D3D11_MEMORY_TYPE_TEXTURE = 0,
- GST_D3D11_MEMORY_TYPE_ARRAY = 1,
- GST_D3D11_MEMORY_TYPE_STAGING = 2,
-} GstD3D11MemoryType;
+/* GstD3D11Memory */
+#define GST_D3D11_MEMORY_GET_LOCK(m) (&(GST_D3D11_MEMORY_CAST(m)->priv->lock))
+#define GST_D3D11_MEMORY_LOCK(m) g_mutex_lock(GST_D3D11_MEMORY_GET_LOCK(m))
+#define GST_D3D11_MEMORY_UNLOCK(m) g_mutex_unlock(GST_D3D11_MEMORY_GET_LOCK(m))
struct _GstD3D11MemoryPrivate
{
- GstD3D11MemoryType type;
-
ID3D11Texture2D *texture;
+ ID3D11Texture2D *staging;
+
D3D11_TEXTURE2D_DESC desc;
- /* valid only for array typed memory */
guint subresource_index;
- ID3D11Texture2D *staging;
-
ID3D11ShaderResourceView *shader_resource_view[GST_VIDEO_MAX_PLANES];
guint num_shader_resource_views;
D3D11_MAPPED_SUBRESOURCE map;
- GMutex lock;
- gint cpu_map_count;
-};
-
-struct _GstD3D11AllocatorPrivate
-{
- /* parent texture when array typed memory is used */
- ID3D11Texture2D *texture;
- GArray *array_in_use;
- GArray *decoder_output_view_array;
- GArray *processor_input_view_array;
-
- /* Count the number of array textures in use */
- guint num_array_textures_in_use;
- guint array_texture_size;
GMutex lock;
- GCond cond;
-
- gboolean flushing;
+ gint cpu_map_count;
};
-#define gst_d3d11_allocator_parent_class parent_class
-G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11Allocator,
- gst_d3d11_allocator, GST_TYPE_ALLOCATOR);
+GST_DEFINE_MINI_OBJECT_TYPE (GstD3D11Memory, gst_d3d11_memory);
static inline D3D11_MAP
-gst_map_flags_to_d3d11 (GstMapFlags flags)
+gst_d3d11_map_flags_to_d3d11 (GstMapFlags flags)
{
if ((flags & GST_MAP_READWRITE) == GST_MAP_READWRITE)
return D3D11_MAP_READ_WRITE;
}
static ID3D11Texture2D *
-create_staging_texture (GstD3D11Device * device,
+gst_d3d11_allocate_staging_texture (GstD3D11Device * device,
const D3D11_TEXTURE2D_DESC * ref)
{
D3D11_TEXTURE2D_DESC desc = { 0, };
}
static gboolean
-map_cpu_access_data (GstD3D11Memory * dmem, D3D11_MAP map_type)
+gst_d3d11_memory_map_cpu_access (GstD3D11Memory * dmem, D3D11_MAP map_type)
{
GstD3D11MemoryPrivate *priv = dmem->priv;
HRESULT hr;
- gboolean ret = TRUE;
- ID3D11Resource *texture = (ID3D11Resource *) priv->texture;
ID3D11Resource *staging = (ID3D11Resource *) priv->staging;
ID3D11DeviceContext *device_context =
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, priv->subresource_index, NULL);
- }
-
hr = ID3D11DeviceContext_Map (device_context,
staging, 0, map_type, 0, &priv->map);
+ gst_d3d11_device_unlock (dmem->device);
if (!gst_d3d11_result (hr, dmem->device)) {
GST_ERROR_OBJECT (GST_MEMORY_CAST (dmem)->allocator,
"Failed to map staging texture (0x%x)", (guint) hr);
- ret = FALSE;
+ return FALSE;
}
- gst_d3d11_device_unlock (dmem->device);
-
- return ret;
+ return TRUE;
}
-static gpointer
-gst_d3d11_memory_map_staging (GstMemory * mem, GstMapFlags flags)
+static void
+gst_d3d11_memory_upload (GstD3D11Memory * dmem)
{
- GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
GstD3D11MemoryPrivate *priv = dmem->priv;
+ ID3D11DeviceContext *device_context;
- GST_D3D11_MEMORY_LOCK (dmem);
- if (priv->cpu_map_count == 0) {
- ID3D11DeviceContext *device_context =
- gst_d3d11_device_get_device_context_handle (dmem->device);
- D3D11_MAP map_type;
- HRESULT hr;
- gboolean ret = TRUE;
-
- map_type = gst_map_flags_to_d3d11 (flags);
-
- gst_d3d11_device_lock (dmem->device);
- hr = ID3D11DeviceContext_Map (device_context,
- (ID3D11Resource *) priv->texture, 0, map_type, 0, &priv->map);
- if (!gst_d3d11_result (hr, dmem->device)) {
- GST_ERROR_OBJECT (GST_MEMORY_CAST (dmem)->allocator,
- "Failed to map staging texture (0x%x)", (guint) hr);
- ret = FALSE;
- }
- gst_d3d11_device_unlock (dmem->device);
+ if (!priv->staging || priv->staging == priv->texture ||
+ !GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD))
+ return;
- if (!ret) {
- GST_D3D11_MEMORY_UNLOCK (dmem);
- return NULL;
- }
- }
+ device_context = gst_d3d11_device_get_device_context_handle (dmem->device);
+ gst_d3d11_device_lock (dmem->device);
+ ID3D11DeviceContext_CopySubresourceRegion (device_context,
+ (ID3D11Resource *) priv->texture, priv->subresource_index, 0, 0, 0,
+ (ID3D11Resource *) priv->staging, 0, NULL);
+ gst_d3d11_device_unlock (dmem->device);
+}
- priv->cpu_map_count++;
- GST_D3D11_MEMORY_UNLOCK (dmem);
+static void
+gst_d3d11_memory_download (GstD3D11Memory * dmem)
+{
+ GstD3D11MemoryPrivate *priv = dmem->priv;
+ ID3D11DeviceContext *device_context;
- return dmem->priv->map.pData;
+ if (!priv->staging || priv->staging == priv->texture ||
+ !GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD))
+ return;
+
+ device_context = gst_d3d11_device_get_device_context_handle (dmem->device);
+ gst_d3d11_device_lock (dmem->device);
+ ID3D11DeviceContext_CopySubresourceRegion (device_context,
+ (ID3D11Resource *) priv->staging, 0, 0, 0, 0,
+ (ID3D11Resource *) priv->texture, priv->subresource_index, NULL);
+ gst_d3d11_device_unlock (dmem->device);
}
static gpointer
-gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
+gst_d3d11_memory_map_full (GstMemory * mem, GstMapInfo * info, gsize maxsize)
{
- GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
+ GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
GstD3D11MemoryPrivate *priv = dmem->priv;
-
- if (priv->type == GST_D3D11_MEMORY_TYPE_STAGING) {
- if ((flags & GST_MAP_D3D11) == GST_MAP_D3D11)
- return priv->texture;
-
- return gst_d3d11_memory_map_staging (mem, flags);
- }
+ GstMapFlags flags = info->flags;
GST_D3D11_MEMORY_LOCK (dmem);
if ((flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
- if (priv->staging &&
- GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD)) {
- ID3D11DeviceContext *device_context =
- gst_d3d11_device_get_device_context_handle (dmem->device);
-
- gst_d3d11_device_lock (dmem->device);
- ID3D11DeviceContext_CopySubresourceRegion (device_context,
- (ID3D11Resource *) priv->texture, priv->subresource_index, 0, 0, 0,
- (ID3D11Resource *) priv->staging, 0, NULL);
- gst_d3d11_device_unlock (dmem->device);
- }
-
+ gst_d3d11_memory_upload (dmem);
GST_MEMORY_FLAG_UNSET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD);
if ((flags & GST_MAP_WRITE) == GST_MAP_WRITE)
/* Allocate staging texture for CPU access */
if (!priv->staging) {
- priv->staging = create_staging_texture (dmem->device, &priv->desc);
+ priv->staging = gst_d3d11_allocate_staging_texture (dmem->device,
+ &priv->desc);
if (!priv->staging) {
GST_ERROR_OBJECT (mem->allocator, "Couldn't create staging texture");
GST_D3D11_MEMORY_UNLOCK (dmem);
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
}
- map_type = gst_map_flags_to_d3d11 (flags);
+ gst_d3d11_memory_download (dmem);
+ map_type = gst_d3d11_map_flags_to_d3d11 (flags);
- if (!map_cpu_access_data (dmem, map_type)) {
+ if (!gst_d3d11_memory_map_cpu_access (dmem, map_type)) {
GST_ERROR_OBJECT (mem->allocator, "Couldn't map staging texture");
GST_D3D11_MEMORY_UNLOCK (dmem);
}
}
- if ((flags & GST_MAP_WRITE) == GST_MAP_WRITE)
+ if ((flags & GST_MAP_WRITE) == GST_MAP_WRITE) {
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD);
+ }
GST_MEMORY_FLAG_UNSET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
}
static void
-unmap_cpu_access_data (GstD3D11Memory * dmem)
+gst_d3d11_memory_unmap_cpu_access (GstD3D11Memory * dmem)
{
GstD3D11MemoryPrivate *priv = dmem->priv;
ID3D11Resource *staging = (ID3D11Resource *) priv->staging;
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (dmem->device);
- if (priv->type == GST_D3D11_MEMORY_TYPE_STAGING)
- staging = (ID3D11Resource *) priv->texture;
-
gst_d3d11_device_lock (dmem->device);
ID3D11DeviceContext_Unmap (device_context, staging, 0);
gst_d3d11_device_unlock (dmem->device);
static void
gst_d3d11_memory_unmap_full (GstMemory * mem, GstMapInfo * info)
{
- GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
+ GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
GstD3D11MemoryPrivate *priv = dmem->priv;
GST_D3D11_MEMORY_LOCK (dmem);
if ((info->flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
- if (priv->type != GST_D3D11_MEMORY_TYPE_STAGING &&
- (info->flags & GST_MAP_WRITE) == GST_MAP_WRITE)
+ if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE)
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
GST_D3D11_MEMORY_UNLOCK (dmem);
return;
}
- if (priv->type != GST_D3D11_MEMORY_TYPE_STAGING &&
- (info->flags & GST_MAP_WRITE))
+ if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE)
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD);
priv->cpu_map_count--;
return;
}
- unmap_cpu_access_data (dmem);
-
+ gst_d3d11_memory_unmap_cpu_access (dmem);
GST_D3D11_MEMORY_UNLOCK (dmem);
}
return NULL;
}
-static GstMemory *
-gst_d3d11_allocator_dummy_alloc (GstAllocator * allocator, gsize size,
- GstAllocationParams * params)
+static gboolean
+gst_d3d11_memory_update_size (GstMemory * mem)
{
- g_return_val_if_reached (NULL);
-}
+ GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
+ GstD3D11MemoryPrivate *priv = dmem->priv;
+ gsize offset[GST_VIDEO_MAX_PLANES];
+ gint stride[GST_VIDEO_MAX_PLANES];
+ gsize size;
+ D3D11_TEXTURE2D_DESC *desc = &priv->desc;
-static void
-gst_d3d11_allocator_free (GstAllocator * allocator, GstMemory * mem)
-{
- GstD3D11Allocator *self = GST_D3D11_ALLOCATOR (allocator);
- GstD3D11AllocatorPrivate *priv = self->priv;
- GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
- GstD3D11MemoryPrivate *dmem_priv = dmem->priv;
- gint i;
+ if (!priv->staging) {
+ priv->staging = gst_d3d11_allocate_staging_texture (dmem->device,
+ &priv->desc);
+ if (!priv->staging) {
+ GST_ERROR_OBJECT (mem->allocator, "Couldn't create staging texture");
+ return FALSE;
+ }
- if (priv->array_in_use) {
- GST_D3D11_ALLOCATOR_LOCK (self);
- g_array_index (priv->array_in_use,
- guint8, dmem_priv->subresource_index) = 0;
- priv->num_array_textures_in_use--;
- g_cond_broadcast (&priv->cond);
- GST_D3D11_ALLOCATOR_UNLOCK (self);
+ GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
}
- for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
- if (dmem_priv->render_target_view[i])
- ID3D11RenderTargetView_Release (dmem_priv->render_target_view[i]);
-
- if (dmem_priv->shader_resource_view[i])
- ID3D11ShaderResourceView_Release (dmem_priv->shader_resource_view[i]);
+ if (!gst_d3d11_memory_map_cpu_access (dmem, D3D11_MAP_READ_WRITE)) {
+ GST_ERROR_OBJECT (mem->allocator, "Couldn't map staging texture");
+ return FALSE;
}
- if (dmem_priv->decoder_output_view)
- ID3D11VideoDecoderOutputView_Release (dmem_priv->decoder_output_view);
-
- if (dmem_priv->processor_input_view)
- ID3D11VideoProcessorInputView_Release (dmem_priv->processor_input_view);
-
- if (dmem_priv->processor_output_view)
- ID3D11VideoProcessorOutputView_Release (dmem_priv->processor_output_view);
+ gst_d3d11_memory_unmap_cpu_access (dmem);
- if (dmem_priv->texture)
- ID3D11Texture2D_Release (dmem_priv->texture);
+ if (!gst_d3d11_dxgi_format_get_size (desc->Format, desc->Width, desc->Height,
+ priv->map.RowPitch, offset, stride, &size)) {
+ GST_ERROR_OBJECT (mem->allocator, "Couldn't calculate memory size");
+ return FALSE;
+ }
- if (dmem_priv->staging)
- ID3D11Texture2D_Release (dmem_priv->staging);
+ mem->maxsize = mem->size = size;
- gst_clear_object (&dmem->device);
- g_mutex_clear (&dmem_priv->lock);
- g_free (dmem->priv);
- g_free (dmem);
+ return TRUE;
}
-static void
-gst_d3d11_allocator_dispose (GObject * object)
+/**
+ * gst_is_d3d11_memory:
+ * @mem: a #GstMemory
+ *
+ * Returns: whether @mem is a #GstD3D11Memory
+ *
+ * Since: 1.20
+ */
+gboolean
+gst_is_d3d11_memory (GstMemory * mem)
{
- GstD3D11Allocator *alloc = GST_D3D11_ALLOCATOR (object);
- GstD3D11AllocatorPrivate *priv = alloc->priv;
-
- g_clear_pointer (&priv->decoder_output_view_array, g_array_unref);
- g_clear_pointer (&priv->processor_input_view_array, g_array_unref);
-
- if (priv->texture) {
- ID3D11Texture2D_Release (priv->texture);
- priv->texture = NULL;
- }
-
- gst_clear_object (&alloc->device);
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
+ return mem != NULL && mem->allocator != NULL &&
+ (GST_IS_D3D11_ALLOCATOR (mem->allocator) ||
+ GST_IS_D3D11_POOL_ALLOCATOR (mem->allocator));
}
-static void
-gst_d3d11_allocator_finalize (GObject * object)
+/**
+ * gst_d3d11_memory_init_once:
+ *
+ * Initializes the Direct3D11 Texture allocator. It is safe to call
+ * this function multiple times. This must be called before any other
+ * GstD3D11Memory operation.
+ *
+ * Since: 1.20
+ */
+void
+gst_d3d11_memory_init_once (void)
{
- GstD3D11Allocator *alloc = GST_D3D11_ALLOCATOR (object);
- GstD3D11AllocatorPrivate *priv = alloc->priv;
+ static gsize _init = 0;
- g_mutex_clear (&priv->lock);
- g_cond_clear (&priv->cond);
+ if (g_once_init_enter (&_init)) {
- g_clear_pointer (&priv->array_in_use, g_array_unref);
+ GST_DEBUG_CATEGORY_INIT (gst_d3d11_allocator_debug, "d3d11allocator", 0,
+ "Direct3D11 Texture Allocator");
- G_OBJECT_CLASS (parent_class)->finalize (object);
+ _d3d11_memory_allocator = g_object_new (GST_TYPE_D3D11_ALLOCATOR, NULL);
+ gst_object_ref_sink (_d3d11_memory_allocator);
+
+ gst_allocator_register (GST_D3D11_MEMORY_NAME, _d3d11_memory_allocator);
+ g_once_init_leave (&_init, 1);
+ }
}
-static void
-gst_d3d11_allocator_class_init (GstD3D11AllocatorClass * klass)
+/**
+ * gst_d3d11_memory_get_texture_handle:
+ * @mem: a #GstD3D11Memory
+ *
+ * Returns: (transfer none): a ID3D11Texture2D handle. Caller must not release
+ * returned handle.
+ *
+ * Since: 1.20
+ */
+ID3D11Texture2D *
+gst_d3d11_memory_get_texture_handle (GstD3D11Memory * mem)
{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GstAllocatorClass *allocator_class = GST_ALLOCATOR_CLASS (klass);
-
- gobject_class->dispose = gst_d3d11_allocator_dispose;
- gobject_class->finalize = gst_d3d11_allocator_finalize;
-
- allocator_class->alloc = gst_d3d11_allocator_dummy_alloc;
- allocator_class->free = gst_d3d11_allocator_free;
+ g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
- GST_DEBUG_CATEGORY_INIT (gst_d3d11_allocator_debug, "d3d11allocator", 0,
- "d3d11allocator object");
+ return mem->priv->texture;
}
-static void
-gst_d3d11_allocator_init (GstD3D11Allocator * allocator)
+/**
+ * gst_d3d11_memory_get_subresource_index:
+ * @mem: a #GstD3D11Memory
+ *
+ * Returns: subresource index corresponding to @mem.
+ *
+ * Since: 1.20
+ */
+guint
+gst_d3d11_memory_get_subresource_index (GstD3D11Memory * mem)
{
- GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
- GstD3D11AllocatorPrivate *priv;
-
- alloc->mem_type = GST_D3D11_MEMORY_NAME;
- alloc->mem_map = gst_d3d11_memory_map;
- alloc->mem_unmap_full = gst_d3d11_memory_unmap_full;
- alloc->mem_share = gst_d3d11_memory_share;
- /* fallback copy */
-
- GST_OBJECT_FLAG_SET (alloc, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
-
- priv = gst_d3d11_allocator_get_instance_private (allocator);
- g_mutex_init (&priv->lock);
- g_cond_init (&priv->cond);
- priv->array_texture_size = 1;
+ g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), 0);
- allocator->priv = priv;
+ return mem->priv->subresource_index;
}
/**
- * gst_d3d11_allocator_new:
- * @device: a #GstD3D11Device
+ * gst_d3d11_memory_get_texture_desc:
+ * @mem: a #GstD3D11Memory
+ * @desc: (out): a D3D11_TEXTURE2D_DESC
+ *
+ * Fill @desc with D3D11_TEXTURE2D_DESC for ID3D11Texture2D
*
- * Returns: a newly created #GstD3D11Allocator
+ * Returns: %TRUE if successeed
*
* Since: 1.20
*/
-GstD3D11Allocator *
-gst_d3d11_allocator_new (GstD3D11Device * device)
+gboolean
+gst_d3d11_memory_get_texture_desc (GstD3D11Memory * mem,
+ D3D11_TEXTURE2D_DESC * desc)
{
- GstD3D11Allocator *allocator;
-
- g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
+ g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
+ g_return_val_if_fail (desc != NULL, FALSE);
- allocator = g_object_new (GST_TYPE_D3D11_ALLOCATOR, NULL);
- allocator->device = gst_object_ref (device);
+ *desc = mem->priv->desc;
- return allocator;
+ return TRUE;
}
-static gboolean
-calculate_mem_size (GstD3D11Device * device, ID3D11Texture2D * texture,
- const D3D11_TEXTURE2D_DESC * desc, D3D11_MAP map_type,
- gint stride[GST_VIDEO_MAX_PLANES], gsize * size)
+gboolean
+gst_d3d11_memory_get_texture_stride (GstD3D11Memory * mem, guint * stride)
{
- 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,
- (ID3D11Resource *) texture, 0, map_type, 0, &map);
-
- if (!gst_d3d11_result (hr, device)) {
- GST_ERROR_OBJECT (device, "Failed to map texture (0x%x)", (guint) hr);
- gst_d3d11_device_unlock (device);
- return FALSE;
- }
-
- ret = gst_d3d11_dxgi_format_get_size (desc->Format,
- desc->Width, desc->Height, map.RowPitch, offset, stride, size);
+ g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
+ g_return_val_if_fail (stride != NULL, FALSE);
- ID3D11DeviceContext_Unmap (device_context, (ID3D11Resource *) texture, 0);
- gst_d3d11_device_unlock (device);
+ *stride = mem->priv->map.RowPitch;
- return ret;
+ return TRUE;
}
static gboolean
}
static gboolean
-create_render_target_views (GstD3D11Memory * mem)
+gst_d3d11_memory_ensure_shader_resource_view (GstD3D11Memory * mem)
{
GstD3D11MemoryPrivate *priv = mem->priv;
- gint i;
- HRESULT hr;
- guint num_views = 0;
- ID3D11Device *device_handle;
- D3D11_RENDER_TARGET_VIEW_DESC render_desc = { 0, };
- DXGI_FORMAT formats[GST_VIDEO_MAX_PLANES] = { DXGI_FORMAT_UNKNOWN, };
+ gboolean ret = FALSE;
- device_handle = gst_d3d11_device_get_device_handle (mem->device);
+ if (!(priv->desc.BindFlags & D3D11_BIND_SHADER_RESOURCE)) {
+ GST_LOG_OBJECT (GST_MEMORY_CAST (mem)->allocator,
+ "Need BindFlags, current flag 0x%x", priv->desc.BindFlags);
+ return FALSE;
+ }
- switch (priv->desc.Format) {
- case DXGI_FORMAT_B8G8R8A8_UNORM:
- case DXGI_FORMAT_R8G8B8A8_UNORM:
- case DXGI_FORMAT_R10G10B10A2_UNORM:
- case DXGI_FORMAT_R8_UNORM:
- case DXGI_FORMAT_R8G8_UNORM:
- case DXGI_FORMAT_R16_UNORM:
- case DXGI_FORMAT_R16G16_UNORM:
- num_views = 1;
- formats[0] = priv->desc.Format;
- break;
- case DXGI_FORMAT_AYUV:
- num_views = 1;
- formats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
- break;
- case DXGI_FORMAT_NV12:
- num_views = 2;
- formats[0] = DXGI_FORMAT_R8_UNORM;
- formats[1] = DXGI_FORMAT_R8G8_UNORM;
- break;
- case DXGI_FORMAT_P010:
- case DXGI_FORMAT_P016:
+ GST_D3D11_MEMORY_LOCK (mem);
+ if (priv->num_shader_resource_views) {
+ ret = TRUE;
+ goto done;
+ }
+
+ ret = create_shader_resource_views (mem);
+
+done:
+ GST_D3D11_MEMORY_UNLOCK (mem);
+
+ return ret;
+}
+
+/**
+ * gst_d3d11_memory_get_shader_resource_view_size:
+ * @mem: a #GstD3D11Memory
+ *
+ * Returns: the number of ID3D11ShaderResourceView that can be used
+ * for processing GPU operation with @mem
+ *
+ * Since: 1.20
+ */
+guint
+gst_d3d11_memory_get_shader_resource_view_size (GstD3D11Memory * mem)
+{
+ g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), 0);
+
+ if (!gst_d3d11_memory_ensure_shader_resource_view (mem))
+ return 0;
+
+ return mem->priv->num_shader_resource_views;
+}
+
+/**
+ * gst_d3d11_memory_get_shader_resource_view:
+ * @mem: a #GstD3D11Memory
+ * @index: the index of the ID3D11ShaderResourceView
+ *
+ * Returns: (transfer none) (nullable): a pointer to the
+ * ID3D11ShaderResourceView or %NULL if ID3D11ShaderResourceView is unavailable
+ * for @index
+ *
+ * Since: 1.20
+ */
+ID3D11ShaderResourceView *
+gst_d3d11_memory_get_shader_resource_view (GstD3D11Memory * mem, guint index)
+{
+ GstD3D11MemoryPrivate *priv;
+
+ g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
+
+ if (!gst_d3d11_memory_ensure_shader_resource_view (mem))
+ return NULL;
+
+ priv = mem->priv;
+
+ if (index >= priv->num_shader_resource_views) {
+ GST_ERROR ("Invalid SRV index %d", index);
+ return NULL;
+ }
+
+ return priv->shader_resource_view[index];
+}
+
+static gboolean
+create_render_target_views (GstD3D11Memory * mem)
+{
+ GstD3D11MemoryPrivate *priv = mem->priv;
+ gint i;
+ HRESULT hr;
+ guint num_views = 0;
+ ID3D11Device *device_handle;
+ 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 (mem->device);
+
+ switch (priv->desc.Format) {
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ case DXGI_FORMAT_R10G10B10A2_UNORM:
+ case DXGI_FORMAT_R8_UNORM:
+ case DXGI_FORMAT_R8G8_UNORM:
+ case DXGI_FORMAT_R16_UNORM:
+ case DXGI_FORMAT_R16G16_UNORM:
+ num_views = 1;
+ formats[0] = priv->desc.Format;
+ break;
+ case DXGI_FORMAT_AYUV:
+ num_views = 1;
+ formats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
+ break;
+ case DXGI_FORMAT_NV12:
+ num_views = 2;
+ formats[0] = DXGI_FORMAT_R8_UNORM;
+ formats[1] = DXGI_FORMAT_R8G8_UNORM;
+ break;
+ case DXGI_FORMAT_P010:
+ case DXGI_FORMAT_P016:
num_views = 2;
formats[0] = DXGI_FORMAT_R16_UNORM;
formats[1] = DXGI_FORMAT_R16G16_UNORM;
return FALSE;
}
-static void
-gst_d3d11_decoder_output_view_clear (ID3D11VideoDecoderOutputView ** view)
+static gboolean
+gst_d3d11_memory_ensure_render_target_view (GstD3D11Memory * mem)
{
- if (view && *view) {
- ID3D11VideoDecoderOutputView_Release (*view);
- *view = NULL;
- }
-}
+ GstD3D11MemoryPrivate *priv = mem->priv;
+ gboolean ret = FALSE;
-static void
-gst_d3d11_processor_input_view_clear (ID3D11VideoProcessorInputView ** view)
-{
- if (view && *view) {
- ID3D11VideoProcessorInputView_Release (*view);
- *view = NULL;
+ if (!(priv->desc.BindFlags & D3D11_BIND_RENDER_TARGET)) {
+ GST_WARNING_OBJECT (GST_MEMORY_CAST (mem)->allocator,
+ "Need BindFlags, current flag 0x%x", priv->desc.BindFlags);
+ return FALSE;
}
-}
-static gboolean
-check_bind_flags_for_processor_input_view (guint bind_flags)
-{
- static const guint compatible_flags = (D3D11_BIND_DECODER |
- D3D11_BIND_VIDEO_ENCODER | D3D11_BIND_RENDER_TARGET |
- D3D11_BIND_UNORDERED_ACCESS);
+ GST_D3D11_MEMORY_LOCK (mem);
+ if (priv->num_render_target_views) {
+ ret = TRUE;
+ goto done;
+ }
- if (bind_flags == 0)
- return TRUE;
+ ret = create_render_target_views (mem);
- if ((bind_flags & compatible_flags) != 0)
- return TRUE;
+done:
+ GST_D3D11_MEMORY_UNLOCK (mem);
- return FALSE;
+ return ret;
}
/**
- * gst_d3d11_allocator_alloc:
- * @allocator: a #GstD3D11Allocator
- * @desc: a D3D11_TEXTURE2D_DESC struct
- * @flags: a #GstD3D11AllocationFlags
- * @size: a size of CPU accesible memory
+ * gst_d3d11_memory_get_render_target_view_size:
+ * @mem: a #GstD3D11Memory
*
- * Returns: a newly allocated #GstD3D11Memory with given parameters.
+ * Returns: the number of ID3D11RenderTargetView that can be used
+ * for processing GPU operation with @mem
*
* Since: 1.20
*/
-GstMemory *
-gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
- const D3D11_TEXTURE2D_DESC * desc, GstD3D11AllocationFlags flags,
- gsize size)
+guint
+gst_d3d11_memory_get_render_target_view_size (GstD3D11Memory * mem)
{
- GstD3D11Memory *mem;
- GstD3D11Device *device;
- ID3D11Texture2D *texture = NULL;
- guint index_to_use = 0;
- GstD3D11AllocatorPrivate *priv;
- GstD3D11MemoryType type = GST_D3D11_MEMORY_TYPE_TEXTURE;
- HRESULT hr;
- ID3D11Device *device_handle;
-
- g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), NULL);
- g_return_val_if_fail (desc != NULL, NULL);
- g_return_val_if_fail (size > 0, NULL);
-
- priv = allocator->priv;
- device = allocator->device;
- device_handle = gst_d3d11_device_get_device_handle (device);
-
- if ((flags & GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY)) {
- gint i;
-
- do_again:
- GST_D3D11_ALLOCATOR_LOCK (allocator);
- if (priv->flushing) {
- GST_DEBUG_OBJECT (allocator, "we are flushing");
- GST_D3D11_ALLOCATOR_UNLOCK (allocator);
-
- return NULL;
- }
-
- if (!priv->array_in_use) {
- priv->array_in_use = g_array_sized_new (FALSE,
- TRUE, sizeof (guint8), desc->ArraySize);
- g_array_set_size (priv->array_in_use, desc->ArraySize);
-
- priv->array_texture_size = desc->ArraySize;
-
- if ((desc->BindFlags & D3D11_BIND_DECODER) == D3D11_BIND_DECODER &&
- !priv->decoder_output_view_array) {
- priv->decoder_output_view_array = g_array_sized_new (FALSE,
- TRUE, sizeof (ID3D11VideoDecoderOutputView *), desc->ArraySize);
- g_array_set_clear_func (priv->decoder_output_view_array,
- (GDestroyNotify) gst_d3d11_decoder_output_view_clear);
- g_array_set_size (priv->decoder_output_view_array, desc->ArraySize);
- }
-
- if (check_bind_flags_for_processor_input_view (desc->BindFlags)) {
- priv->processor_input_view_array = g_array_sized_new (FALSE,
- TRUE, sizeof (ID3D11VideoProcessorInputView *), desc->ArraySize);
- g_array_set_clear_func (priv->processor_input_view_array,
- (GDestroyNotify) gst_d3d11_processor_input_view_clear);
- g_array_set_size (priv->processor_input_view_array, desc->ArraySize);
- }
- }
-
- for (i = 0; i < desc->ArraySize; i++) {
- if (!g_array_index (priv->array_in_use, guint8, i)) {
- index_to_use = i;
- break;
- }
- }
-
- if (i == desc->ArraySize) {
- GST_DEBUG_OBJECT (allocator, "All elements in array are used now");
- g_cond_wait (&priv->cond, &priv->lock);
- GST_D3D11_ALLOCATOR_UNLOCK (allocator);
- goto do_again;
- }
-
- g_array_index (priv->array_in_use, guint8, index_to_use) = 1;
- priv->num_array_textures_in_use++;
-
- GST_D3D11_ALLOCATOR_UNLOCK (allocator);
-
- if (!priv->texture) {
- hr = ID3D11Device_CreateTexture2D (device_handle, desc, NULL,
- &priv->texture);
- if (!gst_d3d11_result (hr, device)) {
- GST_ERROR_OBJECT (allocator, "Couldn't create texture");
- goto error;
- }
- }
-
- ID3D11Texture2D_AddRef (priv->texture);
- texture = priv->texture;
-
- type = GST_D3D11_MEMORY_TYPE_ARRAY;
- } else {
- hr = ID3D11Device_CreateTexture2D (device_handle, desc, NULL, &texture);
- if (!gst_d3d11_result (hr, device)) {
- GST_ERROR_OBJECT (allocator, "Couldn't create texture");
- goto error;
- }
- }
-
- mem = g_new0 (GstD3D11Memory, 1);
- mem->priv = g_new0 (GstD3D11MemoryPrivate, 1);
-
- gst_memory_init (GST_MEMORY_CAST (mem),
- 0, GST_ALLOCATOR_CAST (allocator), NULL, size, 0, 0, size);
-
- g_mutex_init (&mem->priv->lock);
- mem->priv->texture = texture;
- mem->priv->desc = *desc;
- mem->priv->type = type;
- mem->priv->subresource_index = index_to_use;
- mem->device = gst_object_ref (device);
-
- return GST_MEMORY_CAST (mem);
+ g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), 0);
-error:
- if (texture)
- ID3D11Texture2D_Release (texture);
+ if (!gst_d3d11_memory_ensure_render_target_view (mem))
+ return 0;
- return NULL;
+ return mem->priv->num_render_target_views;
}
/**
- * gst_d3d11_allocator_alloc_staging:
- * @allocator: a #GstD3D11Allocator
- * @desc: a D3D11_TEXTURE2D_DESC struct
- * @flags: a #GstD3D11AllocationFlags
- * @stride: (out): a stride of CPU accesible memory
+ * gst_d3d11_memory_get_render_target_view:
+ * @mem: a #GstD3D11Memory
+ * @index: the index of the ID3D11RenderTargetView
*
- * Returns: a newly allocated #GstD3D11Memory with given parameters.
- * Returned #GstD3D11Memory can be used only for staging texture.
+ * Returns: (transfer none) (nullable): a pointer to the
+ * ID3D11RenderTargetView or %NULL if ID3D11RenderTargetView is unavailable
+ * for @index
*
* Since: 1.20
*/
-GstMemory *
-gst_d3d11_allocator_alloc_staging (GstD3D11Allocator * allocator,
- const D3D11_TEXTURE2D_DESC * desc, GstD3D11AllocationFlags flags,
- gint * stride)
+ID3D11RenderTargetView *
+gst_d3d11_memory_get_render_target_view (GstD3D11Memory * mem, guint index)
{
- GstD3D11Memory *mem;
- GstD3D11Device *device;
- ID3D11Texture2D *texture = NULL;
- gsize mem_size = 0;
- gint mem_stride[GST_VIDEO_MAX_PLANES];
+ GstD3D11MemoryPrivate *priv;
- g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), NULL);
- g_return_val_if_fail (desc != NULL, NULL);
+ g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
- device = allocator->device;
+ if (!gst_d3d11_memory_ensure_render_target_view (mem))
+ return NULL;
- texture = create_staging_texture (device, desc);
- if (!texture) {
- GST_ERROR_OBJECT (allocator, "Couldn't create staging texture");
- goto error;
- }
+ priv = mem->priv;
- if (!calculate_mem_size (device,
- texture, desc, D3D11_MAP_READ, mem_stride, &mem_size)) {
- GST_ERROR_OBJECT (allocator, "Couldn't calculate staging texture size");
- goto error;
+ if (index >= priv->num_render_target_views) {
+ GST_ERROR ("Invalid RTV index %d", index);
+ return NULL;
}
- mem = g_new0 (GstD3D11Memory, 1);
- mem->priv = g_new0 (GstD3D11MemoryPrivate, 1);
+ return priv->render_target_view[index];
+}
- gst_memory_init (GST_MEMORY_CAST (mem),
- 0, GST_ALLOCATOR_CAST (allocator), NULL, mem_size, 0, 0, mem_size);
+static gboolean
+gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
+ ID3D11VideoDevice * video_device, GUID * decoder_profile)
+{
+ GstD3D11MemoryPrivate *dmem_priv = mem->priv;
+ GstD3D11Allocator *allocator;
+ D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC desc;
+ HRESULT hr;
+ gboolean ret = FALSE;
- g_mutex_init (&mem->priv->lock);
- mem->priv->texture = texture;
- mem->priv->desc = *desc;
- mem->priv->type = GST_D3D11_MEMORY_TYPE_STAGING;
- mem->device = gst_object_ref (device);
+ allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
- /* every plan will have identical size */
- if (stride)
- *stride = mem_stride[0];
+ if (!(dmem_priv->desc.BindFlags & D3D11_BIND_DECODER)) {
+ GST_LOG_OBJECT (allocator,
+ "Need BindFlags, current flag 0x%x", dmem_priv->desc.BindFlags);
+ return FALSE;
+ }
- return GST_MEMORY_CAST (mem);
-
-error:
- if (texture)
- ID3D11Texture2D_Release (texture);
+ GST_D3D11_MEMORY_LOCK (mem);
+ if (dmem_priv->decoder_output_view) {
+ ID3D11VideoDecoderOutputView_GetDesc (dmem_priv->decoder_output_view,
+ &desc);
+ if (IsEqualGUID (&desc.DecodeProfile, decoder_profile)) {
+ goto succeeded;
+ } else {
+ /* Shouldn't happen, but try again anyway */
+ GST_WARNING_OBJECT (allocator,
+ "Existing view has different decoder profile");
+ ID3D11VideoDecoderOutputView_Release (dmem_priv->decoder_output_view);
+ dmem_priv->decoder_output_view = NULL;
+ }
+ }
- return NULL;
-}
+ if (dmem_priv->decoder_output_view)
+ goto succeeded;
-/**
- * gst_d3d11_allocator_set_flushing:
- * @allocator: a #GstD3D11Allocator
- * @flusing: whether to start or stop flusing
- *
- * Enable or disable the flushing state of @allocator.
- *
- * Since: 1.20
- */
-void
-gst_d3d11_allocator_set_flushing (GstD3D11Allocator * allocator,
- gboolean flushing)
-{
- GstD3D11AllocatorPrivate *priv;
+ desc.DecodeProfile = *decoder_profile;
+ desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
+ desc.Texture2D.ArraySlice = dmem_priv->subresource_index;
- g_return_if_fail (GST_IS_D3D11_ALLOCATOR (allocator));
+ hr = ID3D11VideoDevice_CreateVideoDecoderOutputView (video_device,
+ (ID3D11Resource *) dmem_priv->texture, &desc,
+ &dmem_priv->decoder_output_view);
+ if (!gst_d3d11_result (hr, mem->device)) {
+ GST_ERROR_OBJECT (allocator,
+ "Could not create decoder output view, hr: 0x%x", (guint) hr);
+ goto done;
+ }
- priv = allocator->priv;
+succeeded:
+ ret = TRUE;
- GST_D3D11_ALLOCATOR_LOCK (allocator);
- priv->flushing = flushing;
- g_cond_broadcast (&priv->cond);
- GST_D3D11_ALLOCATOR_UNLOCK (allocator);
-}
+done:
+ GST_D3D11_MEMORY_UNLOCK (mem);
-/**
- * gst_is_d3d11_memory:
- * @mem: a #GstMemory
- *
- * Returns: whether @mem is a #GstD3D11Memory
- *
- * Since: 1.20
- */
-gboolean
-gst_is_d3d11_memory (GstMemory * mem)
-{
- return mem != NULL && mem->allocator != NULL &&
- GST_IS_D3D11_ALLOCATOR (mem->allocator);
+ return ret;
}
/**
- * gst_d3d11_memory_get_texture_handle:
+ * gst_d3d11_memory_get_decoder_output_view:
* @mem: a #GstD3D11Memory
*
- * Returns: (transfer none): a ID3D11Texture2D handle. Caller must not release
- * returned handle.
+ * Returns: (transfer none) (nullable): a pointer to the
+ * ID3D11VideoDecoderOutputView or %NULL if ID3D11VideoDecoderOutputView is
+ * unavailable
*
* Since: 1.20
*/
-ID3D11Texture2D *
-gst_d3d11_memory_get_texture_handle (GstD3D11Memory * mem)
+ID3D11VideoDecoderOutputView *
+gst_d3d11_memory_get_decoder_output_view (GstD3D11Memory * mem,
+ ID3D11VideoDevice * video_device, GUID * decoder_profile)
{
g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
+ g_return_val_if_fail (video_device != NULL, NULL);
+ g_return_val_if_fail (decoder_profile != NULL, NULL);
- return mem->priv->texture;
-}
-
-/**
- * gst_d3d11_memory_get_subresource_index:
- * @mem: a #GstD3D11Memory
- *
- * Returns: subresource index corresponding to @mem.
- *
- * Since: 1.20
- */
-guint
-gst_d3d11_memory_get_subresource_index (GstD3D11Memory * mem)
-{
- g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), 0);
+ if (!gst_d3d11_memory_ensure_decoder_output_view (mem,
+ video_device, decoder_profile))
+ return NULL;
- return mem->priv->subresource_index;
+ return mem->priv->decoder_output_view;
}
-/**
- * gst_d3d11_memory_get_texture_desc:
- * @mem: a #GstD3D11Memory
- * @desc: (out): a D3D11_TEXTURE2D_DESC
- *
- * Fill @desc with D3D11_TEXTURE2D_DESC for ID3D11Texture2D
- *
- * Returns: %TRUE if successeed
- *
- * Since: 1.20
- */
-gboolean
-gst_d3d11_memory_get_texture_desc (GstD3D11Memory * mem,
- D3D11_TEXTURE2D_DESC * desc)
+static gboolean
+check_bind_flags_for_processor_input_view (guint bind_flags)
{
- g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
- g_return_val_if_fail (desc != NULL, FALSE);
+ static const guint compatible_flags = (D3D11_BIND_DECODER |
+ D3D11_BIND_VIDEO_ENCODER | D3D11_BIND_RENDER_TARGET |
+ D3D11_BIND_UNORDERED_ACCESS);
- *desc = mem->priv->desc;
+ if (bind_flags == 0)
+ return TRUE;
- return TRUE;
+ if ((bind_flags & compatible_flags) != 0)
+ return TRUE;
+
+ return FALSE;
}
static gboolean
-gst_d3d11_memory_ensure_shader_resource_view (GstD3D11Memory * mem)
+gst_d3d11_memory_ensure_processor_input_view (GstD3D11Memory * mem,
+ ID3D11VideoDevice * video_device,
+ ID3D11VideoProcessorEnumerator * enumerator)
{
- GstD3D11MemoryPrivate *priv = mem->priv;
+ GstD3D11MemoryPrivate *dmem_priv = mem->priv;
+ GstD3D11Allocator *allocator;
+ D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC desc;
+ HRESULT hr;
gboolean ret = FALSE;
- if (!(priv->desc.BindFlags & D3D11_BIND_SHADER_RESOURCE)) {
- GST_LOG_OBJECT (GST_MEMORY_CAST (mem)->allocator,
- "Need BindFlags, current flag 0x%x", priv->desc.BindFlags);
+ allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
+
+ if (!check_bind_flags_for_processor_input_view (dmem_priv->desc.BindFlags)) {
+ GST_LOG_OBJECT (allocator,
+ "Need BindFlags, current flag 0x%x", dmem_priv->desc.BindFlags);
return FALSE;
}
GST_D3D11_MEMORY_LOCK (mem);
- if (priv->num_shader_resource_views) {
- ret = TRUE;
+ if (dmem_priv->processor_input_view)
+ goto succeeded;
+
+ desc.FourCC = 0;
+ desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
+ desc.Texture2D.MipSlice = 0;
+ desc.Texture2D.ArraySlice = dmem_priv->subresource_index;
+
+ hr = ID3D11VideoDevice_CreateVideoProcessorInputView (video_device,
+ (ID3D11Resource *) dmem_priv->texture, enumerator, &desc,
+ &dmem_priv->processor_input_view);
+ if (!gst_d3d11_result (hr, mem->device)) {
+ GST_ERROR_OBJECT (allocator,
+ "Could not create processor input view, hr: 0x%x", (guint) hr);
goto done;
}
- ret = create_shader_resource_views (mem);
+succeeded:
+ ret = TRUE;
done:
GST_D3D11_MEMORY_UNLOCK (mem);
}
/**
- * gst_d3d11_memory_get_shader_resource_view_size:
- * @mem: a #GstD3D11Memory
- *
- * Returns: the number of ID3D11ShaderResourceView that can be used
- * for processing GPU operation with @mem
- *
- * Since: 1.20
- */
-guint
-gst_d3d11_memory_get_shader_resource_view_size (GstD3D11Memory * mem)
-{
- g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), 0);
-
- if (!gst_d3d11_memory_ensure_shader_resource_view (mem))
- return 0;
-
- return mem->priv->num_shader_resource_views;
-}
-
-/**
- * gst_d3d11_memory_get_shader_resource_view:
+ * gst_d3d11_memory_get_processor_input_view:
* @mem: a #GstD3D11Memory
- * @index: the index of the ID3D11ShaderResourceView
+ * @video_device: a #ID3D11VideoDevice
+ * @enumerator: a #ID3D11VideoProcessorEnumerator
*
* Returns: (transfer none) (nullable): a pointer to the
- * ID3D11ShaderResourceView or %NULL if ID3D11ShaderResourceView is unavailable
- * for @index
+ * ID3D11VideoProcessorInputView or %NULL if ID3D11VideoProcessorInputView is
+ * unavailable
*
* Since: 1.20
*/
-ID3D11ShaderResourceView *
-gst_d3d11_memory_get_shader_resource_view (GstD3D11Memory * mem, guint index)
+ID3D11VideoProcessorInputView *
+gst_d3d11_memory_get_processor_input_view (GstD3D11Memory * mem,
+ ID3D11VideoDevice * video_device,
+ ID3D11VideoProcessorEnumerator * enumerator)
{
- GstD3D11MemoryPrivate *priv;
-
g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
+ g_return_val_if_fail (video_device != NULL, NULL);
+ g_return_val_if_fail (enumerator != NULL, NULL);
- if (!gst_d3d11_memory_ensure_shader_resource_view (mem))
- return NULL;
-
- priv = mem->priv;
-
- if (index >= priv->num_shader_resource_views) {
- GST_ERROR ("Invalid SRV index %d", index);
+ if (!gst_d3d11_memory_ensure_processor_input_view (mem, video_device,
+ enumerator))
return NULL;
- }
- return priv->shader_resource_view[index];
+ return mem->priv->processor_input_view;
}
static gboolean
-gst_d3d11_memory_ensure_render_target_view (GstD3D11Memory * mem)
+gst_d3d11_memory_ensure_processor_output_view (GstD3D11Memory * mem,
+ ID3D11VideoDevice * video_device,
+ ID3D11VideoProcessorEnumerator * enumerator)
{
GstD3D11MemoryPrivate *priv = mem->priv;
- gboolean ret = FALSE;
+ GstD3D11Allocator *allocator;
+ D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC desc = { 0, };
+ HRESULT hr;
+ gboolean ret;
+
+ allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
if (!(priv->desc.BindFlags & D3D11_BIND_RENDER_TARGET)) {
- GST_WARNING_OBJECT (GST_MEMORY_CAST (mem)->allocator,
+ GST_LOG_OBJECT (allocator,
"Need BindFlags, current flag 0x%x", priv->desc.BindFlags);
return FALSE;
}
+ /* FIXME: texture array should be supported at some point */
+ if (priv->subresource_index != 0) {
+ GST_FIXME_OBJECT (allocator,
+ "Texture array is not suppoted for processor output view");
+ return FALSE;
+ }
+
GST_D3D11_MEMORY_LOCK (mem);
- if (priv->num_render_target_views) {
- ret = TRUE;
+ if (priv->processor_output_view)
+ goto succeeded;
+
+ desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
+ desc.Texture2D.MipSlice = 0;
+
+ hr = ID3D11VideoDevice_CreateVideoProcessorOutputView (video_device,
+ (ID3D11Resource *) priv->texture, enumerator, &desc,
+ &priv->processor_output_view);
+ if (!gst_d3d11_result (hr, mem->device)) {
+ GST_ERROR_OBJECT (allocator,
+ "Could not create processor input view, hr: 0x%x", (guint) hr);
goto done;
}
- ret = create_render_target_views (mem);
+succeeded:
+ ret = TRUE;
done:
GST_D3D11_MEMORY_UNLOCK (mem);
}
/**
- * gst_d3d11_memory_get_render_target_view_size:
+ * gst_d3d11_memory_get_processor_output_view:
* @mem: a #GstD3D11Memory
+ * @video_device: a #ID3D11VideoDevice
+ * @enumerator: a #ID3D11VideoProcessorEnumerator
*
- * Returns: the number of ID3D11RenderTargetView that can be used
- * for processing GPU operation with @mem
+ * Returns: (transfer none) (nullable): a pointer to the
+ * ID3D11VideoProcessorOutputView or %NULL if ID3D11VideoProcessorOutputView is
+ * unavailable
*
* Since: 1.20
*/
-guint
-gst_d3d11_memory_get_render_target_view_size (GstD3D11Memory * mem)
+ID3D11VideoProcessorOutputView *
+gst_d3d11_memory_get_processor_output_view (GstD3D11Memory * mem,
+ ID3D11VideoDevice * video_device,
+ ID3D11VideoProcessorEnumerator * enumerator)
{
- g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), 0);
+ g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
+ g_return_val_if_fail (video_device != NULL, NULL);
+ g_return_val_if_fail (enumerator != NULL, NULL);
- if (!gst_d3d11_memory_ensure_render_target_view (mem))
- return 0;
+ if (!gst_d3d11_memory_ensure_processor_output_view (mem, video_device,
+ enumerator))
+ return NULL;
- return mem->priv->num_render_target_views;
+ return mem->priv->processor_output_view;
+}
+
+/* GstD3D11Allocator */
+#define gst_d3d11_allocator_parent_class alloc_parent_class
+G_DEFINE_TYPE (GstD3D11Allocator, gst_d3d11_allocator, GST_TYPE_ALLOCATOR);
+
+static GstMemory *gst_d3d11_allocator_dummy_alloc (GstAllocator * allocator,
+ gsize size, GstAllocationParams * params);
+static void gst_d3d11_allocator_free (GstAllocator * allocator,
+ GstMemory * mem);
+
+static void
+gst_d3d11_allocator_class_init (GstD3D11AllocatorClass * klass)
+{
+ GstAllocatorClass *allocator_class = GST_ALLOCATOR_CLASS (klass);
+
+ allocator_class->alloc = gst_d3d11_allocator_dummy_alloc;
+ allocator_class->free = gst_d3d11_allocator_free;
+}
+
+static void
+gst_d3d11_allocator_init (GstD3D11Allocator * allocator)
+{
+ GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
+
+ alloc->mem_type = GST_D3D11_MEMORY_NAME;
+ alloc->mem_map_full = gst_d3d11_memory_map_full;
+ alloc->mem_unmap_full = gst_d3d11_memory_unmap_full;
+ alloc->mem_share = gst_d3d11_memory_share;
+ /* fallback copy */
+
+ GST_OBJECT_FLAG_SET (alloc, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
+}
+
+static GstMemory *
+gst_d3d11_allocator_dummy_alloc (GstAllocator * allocator, gsize size,
+ GstAllocationParams * params)
+{
+ g_return_val_if_reached (NULL);
+}
+
+static void
+gst_d3d11_allocator_free (GstAllocator * allocator, GstMemory * mem)
+{
+ GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
+ GstD3D11MemoryPrivate *dmem_priv = dmem->priv;
+ gint i;
+
+ GST_LOG_OBJECT (allocator, "Free memory %p", mem);
+
+ for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
+ if (dmem_priv->render_target_view[i])
+ ID3D11RenderTargetView_Release (dmem_priv->render_target_view[i]);
+
+ if (dmem_priv->shader_resource_view[i])
+ ID3D11ShaderResourceView_Release (dmem_priv->shader_resource_view[i]);
+ }
+
+ if (dmem_priv->decoder_output_view)
+ ID3D11VideoDecoderOutputView_Release (dmem_priv->decoder_output_view);
+
+ if (dmem_priv->processor_input_view)
+ ID3D11VideoProcessorInputView_Release (dmem_priv->processor_input_view);
+
+ if (dmem_priv->processor_output_view)
+ ID3D11VideoProcessorOutputView_Release (dmem_priv->processor_output_view);
+
+ if (dmem_priv->texture)
+ ID3D11Texture2D_Release (dmem_priv->texture);
+
+ if (dmem_priv->staging)
+ ID3D11Texture2D_Release (dmem_priv->staging);
+
+ gst_clear_object (&dmem->device);
+ g_mutex_clear (&dmem_priv->lock);
+ g_free (dmem->priv);
+ g_free (dmem);
+}
+
+static GstMemory *
+gst_d3d11_allocator_alloc_wrapped (GstD3D11Allocator * self,
+ GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc,
+ ID3D11Texture2D * texture)
+{
+ GstD3D11Memory *mem;
+
+ mem = g_new0 (GstD3D11Memory, 1);
+ mem->priv = g_new0 (GstD3D11MemoryPrivate, 1);
+
+ gst_memory_init (GST_MEMORY_CAST (mem),
+ 0, GST_ALLOCATOR_CAST (self), NULL, 0, 0, 0, 0);
+ g_mutex_init (&mem->priv->lock);
+ mem->priv->texture = texture;
+ mem->priv->desc = *desc;
+ mem->device = gst_object_ref (device);
+
+ /* This is staging texture as well */
+ if (desc->Usage == D3D11_USAGE_STAGING) {
+ mem->priv->staging = texture;
+ ID3D11Texture2D_AddRef (texture);
+ }
+
+ return GST_MEMORY_CAST (mem);
+}
+
+static GstMemory *
+gst_d3d11_allocator_alloc_internal (GstD3D11Allocator * self,
+ GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc)
+{
+ ID3D11Texture2D *texture = NULL;
+ ID3D11Device *device_handle;
+ HRESULT hr;
+
+ device_handle = gst_d3d11_device_get_device_handle (device);
+
+ hr = ID3D11Device_CreateTexture2D (device_handle, desc, NULL, &texture);
+ if (!gst_d3d11_result (hr, device)) {
+ GST_ERROR_OBJECT (self, "Couldn't create texture");
+ return NULL;
+ }
+
+ return gst_d3d11_allocator_alloc_wrapped (self, device, desc, texture);
}
/**
- * gst_d3d11_memory_get_render_target_view:
- * @mem: a #GstD3D11Memory
- * @index: the index of the ID3D11RenderTargetView
+ * gst_d3d11_allocator_alloc:
+ * @allocator: a #GstD3D11Allocator
+ * @device: a #GstD3D11Device
+ * @desc: a D3D11_TEXTURE2D_DESC struct
*
- * Returns: (transfer none) (nullable): a pointer to the
- * ID3D11RenderTargetView or %NULL if ID3D11RenderTargetView is unavailable
- * for @index
+ * Returns: a newly allocated #GstD3D11Memory with given parameters.
*
* Since: 1.20
*/
-ID3D11RenderTargetView *
-gst_d3d11_memory_get_render_target_view (GstD3D11Memory * mem, guint index)
+GstMemory *
+gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
+ GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc)
{
- GstD3D11MemoryPrivate *priv;
+ GstMemory *mem;
- g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
+ g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), NULL);
+ g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
+ g_return_val_if_fail (desc != NULL, NULL);
- if (!gst_d3d11_memory_ensure_render_target_view (mem))
+ mem = gst_d3d11_allocator_alloc_internal (allocator, device, desc);
+ if (!mem)
return NULL;
- priv = mem->priv;
-
- if (index >= priv->num_render_target_views) {
- GST_ERROR ("Invalid RTV index %d", index);
+ if (!gst_d3d11_memory_update_size (mem)) {
+ GST_ERROR_OBJECT (allocator, "Failed to calculate size");
+ gst_memory_unref (mem);
return NULL;
}
- return priv->render_target_view[index];
+ return mem;
}
+gboolean
+gst_d3d11_allocator_set_active (GstD3D11Allocator * allocator, gboolean active)
+{
+ GstD3D11AllocatorClass *klass;
+
+ g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), FALSE);
+
+ klass = GST_D3D11_ALLOCATOR_GET_CLASS (allocator);
+ if (klass->set_actvie)
+ return klass->set_actvie (allocator, active);
+
+ return TRUE;
+}
+
+/* GstD3D11PoolAllocator */
+#define GST_D3D11_POOL_ALLOCATOR_LOCK(alloc) (g_rec_mutex_lock(&alloc->priv->lock))
+#define GST_D3D11_POOL_ALLOCATOR_UNLOCK(alloc) (g_rec_mutex_unlock(&alloc->priv->lock))
+#define GST_D3D11_POOL_ALLOCATOR_IS_FLUSHING(alloc) (g_atomic_int_get (&alloc->priv->flushing))
+
+struct _GstD3D11PoolAllocatorPrivate
+{
+ /* parent texture when array typed memory is used */
+ ID3D11Texture2D *texture;
+ D3D11_TEXTURE2D_DESC desc;
+
+ /* All below member variables are analogous to that of GstBufferPool */
+ GstAtomicQueue *queue;
+ GstPoll *poll;
+
+ /* This lock will protect all below variables apart from atomic ones
+ * (identical to GstBufferPool::priv::rec_lock) */
+ GRecMutex lock;
+ gboolean started;
+ gboolean active;
+
+ /* atomic */
+ gint outstanding;
+ guint max_mems;
+ guint cur_mems;
+ gboolean flushing;
+
+ /* Calculated memory size, based on Direct3D11 staging texture map.
+ * Note that, we cannot know the actually staging texture memory size prior
+ * to map the staging texture because driver will likely require padding */
+ gsize mem_size;
+};
+
+static void gst_d3d11_pool_allocator_dispose (GObject * object);
+static void gst_d3d11_pool_allocator_finalize (GObject * object);
+
static gboolean
-gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
- ID3D11VideoDevice * video_device, GUID * decoder_profile)
+gst_d3d11_pool_allocator_set_active (GstD3D11Allocator * allocator,
+ gboolean active);
+
+static gboolean gst_d3d11_pool_allocator_start (GstD3D11PoolAllocator * self);
+static gboolean gst_d3d11_pool_allocator_stop (GstD3D11PoolAllocator * self);
+static gboolean gst_d3d11_memory_release (GstMiniObject * mini_object);
+
+#define gst_d3d11_pool_allocator_parent_class pool_alloc_parent_class
+G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11PoolAllocator,
+ gst_d3d11_pool_allocator, GST_TYPE_D3D11_ALLOCATOR);
+
+static void
+gst_d3d11_pool_allocator_class_init (GstD3D11PoolAllocatorClass * klass)
{
- GstD3D11MemoryPrivate *dmem_priv = mem->priv;
- GstD3D11Allocator *allocator;
- GstD3D11AllocatorPrivate *priv;
- D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC desc;
- ID3D11VideoDecoderOutputView *view = NULL;
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstD3D11AllocatorClass *d3d11alloc_class = GST_D3D11_ALLOCATOR_CLASS (klass);
+
+ gobject_class->dispose = gst_d3d11_pool_allocator_dispose;
+ gobject_class->finalize = gst_d3d11_pool_allocator_finalize;
+
+ d3d11alloc_class->set_actvie = gst_d3d11_pool_allocator_set_active;
+}
+
+static void
+gst_d3d11_pool_allocator_init (GstD3D11PoolAllocator * allocator)
+{
+ GstD3D11PoolAllocatorPrivate *priv;
+
+ priv = allocator->priv =
+ gst_d3d11_pool_allocator_get_instance_private (allocator);
+ g_rec_mutex_init (&priv->lock);
+
+ priv->poll = gst_poll_new_timer ();
+ priv->queue = gst_atomic_queue_new (16);
+ priv->flushing = 1;
+ priv->active = FALSE;
+ priv->started = FALSE;
+
+ /* 1 control write for flushing - the flush token */
+ gst_poll_write_control (priv->poll);
+ /* 1 control write for marking that we are not waiting for poll - the wait token */
+ gst_poll_write_control (priv->poll);
+}
+
+static void
+gst_d3d11_pool_allocator_dispose (GObject * object)
+{
+ GstD3D11PoolAllocator *self = GST_D3D11_POOL_ALLOCATOR (object);
+
+ gst_clear_object (&self->device);
+
+ G_OBJECT_CLASS (pool_alloc_parent_class)->dispose (object);
+}
+
+static void
+gst_d3d11_pool_allocator_finalize (GObject * object)
+{
+ GstD3D11PoolAllocator *self = GST_D3D11_POOL_ALLOCATOR (object);
+ GstD3D11PoolAllocatorPrivate *priv = self->priv;
+
+ GST_DEBUG_OBJECT (self, "Finalize");
+
+ gst_d3d11_pool_allocator_stop (self);
+ gst_atomic_queue_unref (priv->queue);
+ gst_poll_free (priv->poll);
+ g_rec_mutex_clear (&priv->lock);
+
+ if (priv->texture)
+ ID3D11Texture2D_Release (priv->texture);
+
+ G_OBJECT_CLASS (pool_alloc_parent_class)->finalize (object);
+}
+
+static gboolean
+gst_d3d11_pool_allocator_start (GstD3D11PoolAllocator * self)
+{
+ GstD3D11PoolAllocatorPrivate *priv = self->priv;
+ ID3D11Device *device_handle;
HRESULT hr;
- gboolean ret = FALSE;
+ guint i;
- allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
- priv = allocator->priv;
+ if (priv->started)
+ return TRUE;
- if (!(dmem_priv->desc.BindFlags & D3D11_BIND_DECODER)) {
- GST_LOG_OBJECT (allocator,
- "Need BindFlags, current flag 0x%x", dmem_priv->desc.BindFlags);
- return FALSE;
+ /* Nothing to do */
+ if (priv->desc.ArraySize == 1) {
+ priv->started = TRUE;
+ return TRUE;
}
- GST_D3D11_MEMORY_LOCK (mem);
- if (dmem_priv->decoder_output_view) {
- ID3D11VideoDecoderOutputView_GetDesc (dmem_priv->decoder_output_view,
- &desc);
- if (IsEqualGUID (&desc.DecodeProfile, decoder_profile)) {
- goto succeeded;
+ device_handle = gst_d3d11_device_get_device_handle (self->device);
+
+ if (!priv->texture) {
+ hr = ID3D11Device_CreateTexture2D (device_handle, &priv->desc, NULL,
+ &priv->texture);
+ if (!gst_d3d11_result (hr, self->device)) {
+ GST_ERROR_OBJECT (self, "Failed to allocate texture");
+ return FALSE;
+ }
+ }
+
+ /* Pre-allocate memory objects */
+ for (i = 0; i < priv->desc.ArraySize; i++) {
+ GstMemory *mem;
+
+ ID3D11Texture2D_AddRef (priv->texture);
+ mem =
+ gst_d3d11_allocator_alloc_wrapped (GST_D3D11_ALLOCATOR_CAST
+ (_d3d11_memory_allocator), self->device, &priv->desc, priv->texture);
+
+ if (i == 0) {
+ if (!gst_d3d11_memory_update_size (mem)) {
+ GST_ERROR_OBJECT (self, "Failed to calculate memory size");
+ gst_memory_unref (mem);
+ return FALSE;
+ }
+
+ priv->mem_size = mem->size;
} else {
- /* Shouldn't happen, but try again anyway */
- GST_WARNING_OBJECT (allocator,
- "Existing view has different decoder profile");
- ID3D11VideoDecoderOutputView_Release (dmem_priv->decoder_output_view);
- dmem_priv->decoder_output_view = NULL;
+ mem->size = mem->maxsize = priv->mem_size;
}
+
+ GST_D3D11_MEMORY_CAST (mem)->priv->subresource_index = i;
+
+ g_atomic_int_add (&priv->cur_mems, 1);
+ gst_atomic_queue_push (priv->queue, mem);
+ gst_poll_write_control (priv->poll);
}
- if (priv->decoder_output_view_array) {
- GST_D3D11_ALLOCATOR_LOCK (allocator);
- view = g_array_index (priv->decoder_output_view_array,
- ID3D11VideoDecoderOutputView *, dmem_priv->subresource_index);
-
- if (view) {
- ID3D11VideoDecoderOutputView_GetDesc (view, &desc);
- /* Shouldn't happen because decoder will not reuse this allocator
- * over different codec/profiles */
- if (!IsEqualGUID (&desc.DecodeProfile, decoder_profile)) {
- GST_WARNING_OBJECT (allocator,
- "Existing view has different decoder profile");
- ID3D11VideoDecoderOutputView_Release (view);
- view = NULL;
- g_array_index (priv->decoder_output_view_array,
- ID3D11VideoDecoderOutputView *,
- dmem_priv->subresource_index) = NULL;
+ priv->started = TRUE;
+
+ return TRUE;
+}
+
+static void
+gst_d3d11_pool_allocator_do_set_flushing (GstD3D11PoolAllocator * self,
+ gboolean flushing)
+{
+ GstD3D11PoolAllocatorPrivate *priv = self->priv;
+
+ if (GST_D3D11_POOL_ALLOCATOR_IS_FLUSHING (self) == flushing)
+ return;
+
+ if (flushing) {
+ g_atomic_int_set (&priv->flushing, 1);
+ /* Write the flush token to wake up any waiters */
+ gst_poll_write_control (priv->poll);
+ } else {
+ while (!gst_poll_read_control (priv->poll)) {
+ if (errno == EWOULDBLOCK) {
+ /* This should not really happen unless flushing and unflushing
+ * happens on different threads. Let's wait a bit to get back flush
+ * token from the thread that was setting it to flushing */
+ g_thread_yield ();
+ continue;
} else {
- /* Increase refcount and reuse existing view */
- dmem_priv->decoder_output_view = view;
- ID3D11VideoDecoderOutputView_AddRef (view);
+ /* Critical error but GstPoll already complained */
+ break;
}
}
- GST_D3D11_ALLOCATOR_UNLOCK (allocator);
+
+ g_atomic_int_set (&priv->flushing, 0);
}
+}
- if (dmem_priv->decoder_output_view)
- goto succeeded;
+static gboolean
+gst_d3d11_pool_allocator_set_active (GstD3D11Allocator * allocator,
+ gboolean active)
+{
+ GstD3D11PoolAllocator *self = GST_D3D11_POOL_ALLOCATOR (allocator);
+ GstD3D11PoolAllocatorPrivate *priv = self->priv;
- desc.DecodeProfile = *decoder_profile;
- desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
- desc.Texture2D.ArraySlice = dmem_priv->subresource_index;
+ GST_LOG_OBJECT (self, "active %d", active);
- hr = ID3D11VideoDevice_CreateVideoDecoderOutputView (video_device,
- (ID3D11Resource *) dmem_priv->texture, &desc,
- &dmem_priv->decoder_output_view);
- if (!gst_d3d11_result (hr, mem->device)) {
- GST_ERROR_OBJECT (allocator,
- "Could not create decoder output view, hr: 0x%x", (guint) hr);
- goto done;
+ GST_D3D11_POOL_ALLOCATOR_LOCK (self);
+ /* just return if we are already in the right state */
+ if (priv->active == active)
+ goto was_ok;
+
+ if (active) {
+ if (!gst_d3d11_pool_allocator_start (self))
+ goto start_failed;
+
+ /* flush_stop may release memory objects, setting to active to avoid running
+ * do_stop while activating the pool */
+ priv->active = TRUE;
+
+ gst_d3d11_pool_allocator_do_set_flushing (self, FALSE);
+ } else {
+ gint outstanding;
+
+ /* set to flushing first */
+ gst_d3d11_pool_allocator_do_set_flushing (self, TRUE);
+
+ /* when all memory objects are in the pool, free them. Else they will be
+ * freed when they are released */
+ outstanding = g_atomic_int_get (&priv->outstanding);
+ GST_LOG_OBJECT (self, "outstanding memories %d, (in queue %d)",
+ outstanding, gst_atomic_queue_length (priv->queue));
+ if (outstanding == 0) {
+ if (!gst_d3d11_pool_allocator_stop (self))
+ goto stop_failed;
+ }
+
+ priv->active = FALSE;
}
- /* Store view array for later reuse */
- if (priv->decoder_output_view_array) {
- GST_D3D11_ALLOCATOR_LOCK (allocator);
- view = g_array_index (priv->decoder_output_view_array,
- ID3D11VideoDecoderOutputView *, dmem_priv->subresource_index);
+ GST_D3D11_POOL_ALLOCATOR_UNLOCK (self);
- if (view)
- ID3D11VideoDecoderOutputView_Release (view);
+ return TRUE;
- g_array_index (priv->decoder_output_view_array,
- ID3D11VideoDecoderOutputView *, dmem_priv->subresource_index) =
- dmem_priv->decoder_output_view;
- ID3D11VideoDecoderOutputView_AddRef (dmem_priv->decoder_output_view);
- GST_D3D11_ALLOCATOR_UNLOCK (allocator);
+was_ok:
+ {
+ GST_DEBUG_OBJECT (self, "allocator was in the right state");
+ GST_D3D11_POOL_ALLOCATOR_UNLOCK (self);
+ return TRUE;
}
+start_failed:
+ {
+ GST_ERROR_OBJECT (self, "start failed");
+ GST_D3D11_POOL_ALLOCATOR_UNLOCK (self);
+ return FALSE;
+ }
+stop_failed:
+ {
+ GST_ERROR_OBJECT (self, "stop failed");
+ GST_D3D11_POOL_ALLOCATOR_UNLOCK (self);
+ return FALSE;
+ }
+}
-succeeded:
- ret = TRUE;
+static void
+gst_d3d11_pool_allocator_free_memory (GstD3D11PoolAllocator * self,
+ GstMemory * mem)
+{
+ GstD3D11PoolAllocatorPrivate *priv = self->priv;
-done:
- GST_D3D11_MEMORY_UNLOCK (mem);
+ g_atomic_int_add (&priv->cur_mems, -1);
+ GST_LOG_OBJECT (self, "freeing memory %p (%u left)", mem, priv->cur_mems);
- return ret;
+ GST_MINI_OBJECT_CAST (mem)->dispose = NULL;
+ gst_memory_unref (mem);
}
-/**
- * gst_d3d11_memory_get_decoder_output_view:
- * @mem: a #GstD3D11Memory
- *
- * Returns: (transfer none) (nullable): a pointer to the
- * ID3D11VideoDecoderOutputView or %NULL if ID3D11VideoDecoderOutputView is
- * unavailable
- *
- * Since: 1.20
- */
-ID3D11VideoDecoderOutputView *
-gst_d3d11_memory_get_decoder_output_view (GstD3D11Memory * mem,
- ID3D11VideoDevice * video_device, GUID * decoder_profile)
+/* must be called with the lock */
+static gboolean
+gst_d3d11_pool_allocator_clear_queue (GstD3D11PoolAllocator * self)
{
- g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
- g_return_val_if_fail (video_device != NULL, NULL);
- g_return_val_if_fail (decoder_profile != NULL, NULL);
+ GstD3D11PoolAllocatorPrivate *priv = self->priv;
+ GstMemory *memory;
+
+ GST_LOG_OBJECT (self, "Clearing queue");
+
+ /* clear the pool */
+ while ((memory = gst_atomic_queue_pop (priv->queue))) {
+ while (!gst_poll_read_control (priv->poll)) {
+ if (errno == EWOULDBLOCK) {
+ /* We put the memory into the queue but did not finish writing control
+ * yet, let's wait a bit and retry */
+ g_thread_yield ();
+ continue;
+ } else {
+ /* Critical error but GstPoll already complained */
+ break;
+ }
+ }
+ gst_d3d11_pool_allocator_free_memory (self, memory);
+ }
- if (!gst_d3d11_memory_ensure_decoder_output_view (mem,
- video_device, decoder_profile))
- return NULL;
+ GST_LOG_OBJECT (self, "Clear done");
- return mem->priv->decoder_output_view;
+ return priv->cur_mems == 0;
}
+/* must be called with the lock */
static gboolean
-gst_d3d11_memory_ensure_processor_input_view (GstD3D11Memory * mem,
- ID3D11VideoDevice * video_device,
- ID3D11VideoProcessorEnumerator * enumerator)
+gst_d3d11_pool_allocator_stop (GstD3D11PoolAllocator * self)
{
- GstD3D11MemoryPrivate *dmem_priv = mem->priv;
- GstD3D11Allocator *allocator;
- GstD3D11AllocatorPrivate *priv;
- D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC desc;
- ID3D11VideoProcessorInputView *view = NULL;
- HRESULT hr;
- gboolean ret = FALSE;
+ GstD3D11PoolAllocatorPrivate *priv = self->priv;
- allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
- priv = allocator->priv;
+ GST_DEBUG_OBJECT (self, "Stop");
- if (!check_bind_flags_for_processor_input_view (dmem_priv->desc.BindFlags)) {
- GST_LOG_OBJECT (allocator,
- "Need BindFlags, current flag 0x%x", dmem_priv->desc.BindFlags);
- return FALSE;
- }
+ if (priv->started) {
+ if (!gst_d3d11_pool_allocator_clear_queue (self))
+ return FALSE;
- GST_D3D11_MEMORY_LOCK (mem);
- if (dmem_priv->processor_input_view)
- goto succeeded;
+ priv->started = FALSE;
+ } else {
+ GST_DEBUG_OBJECT (self, "Wasn't started");
+ }
- if (priv->processor_input_view_array) {
- GST_D3D11_ALLOCATOR_LOCK (allocator);
- view = g_array_index (priv->processor_input_view_array,
- ID3D11VideoProcessorInputView *, dmem_priv->subresource_index);
+ return TRUE;
+}
- /* Increase refcount and reuse existing view */
- if (view) {
- dmem_priv->processor_input_view = view;
- ID3D11VideoProcessorInputView_AddRef (view);
+static inline void
+dec_outstanding (GstD3D11PoolAllocator * self)
+{
+ if (g_atomic_int_dec_and_test (&self->priv->outstanding)) {
+ /* all memory objects are returned to the pool, see if we need to free them */
+ if (GST_D3D11_POOL_ALLOCATOR_IS_FLUSHING (self)) {
+ /* take the lock so that set_active is not run concurrently */
+ GST_D3D11_POOL_ALLOCATOR_LOCK (self);
+ /* now that we have the lock, check if we have been de-activated with
+ * outstanding buffers */
+ if (!self->priv->active)
+ gst_d3d11_pool_allocator_stop (self);
+
+ GST_D3D11_POOL_ALLOCATOR_UNLOCK (self);
}
- GST_D3D11_ALLOCATOR_UNLOCK (allocator);
}
+}
- if (dmem_priv->processor_input_view)
- goto succeeded;
+static void
+gst_d3d11_pool_allocator_release_memory (GstD3D11PoolAllocator * self,
+ GstMemory * mem)
+{
+ GST_LOG_OBJECT (self, "Released memory %p", mem);
- desc.FourCC = 0;
- desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
- desc.Texture2D.MipSlice = 0;
- desc.Texture2D.ArraySlice = dmem_priv->subresource_index;
+ GST_MINI_OBJECT_CAST (mem)->dispose = NULL;
+ mem->allocator = gst_object_ref (_d3d11_memory_allocator);
+ gst_object_unref (self);
- hr = ID3D11VideoDevice_CreateVideoProcessorInputView (video_device,
- (ID3D11Resource *) dmem_priv->texture, enumerator, &desc,
- &dmem_priv->processor_input_view);
- if (!gst_d3d11_result (hr, mem->device)) {
- GST_ERROR_OBJECT (allocator,
- "Could not create processor input view, hr: 0x%x", (guint) hr);
- goto done;
- }
+ /* keep it around in our queue */
+ gst_atomic_queue_push (self->priv->queue, mem);
+ gst_poll_write_control (self->priv->poll);
+ dec_outstanding (self);
+}
- /* Store view array for later reuse */
- if (priv->processor_input_view_array) {
- GST_D3D11_ALLOCATOR_LOCK (allocator);
- view = g_array_index (priv->processor_input_view_array,
- ID3D11VideoProcessorInputView *, dmem_priv->subresource_index);
+static gboolean
+gst_d3d11_memory_release (GstMiniObject * mini_object)
+{
+ GstMemory *mem = GST_MEMORY_CAST (mini_object);
+ GstD3D11PoolAllocator *alloc;
- if (view)
- ID3D11VideoProcessorInputView_Release (view);
+ g_assert (mem->allocator != NULL);
- g_array_index (priv->processor_input_view_array,
- ID3D11VideoProcessorInputView *, dmem_priv->subresource_index) =
- dmem_priv->processor_input_view;
- ID3D11VideoProcessorInputView_AddRef (dmem_priv->processor_input_view);
- GST_D3D11_ALLOCATOR_UNLOCK (allocator);
+ if (!GST_IS_D3D11_POOL_ALLOCATOR (mem->allocator)) {
+ GST_LOG_OBJECT (mem->allocator, "Not our memory, free");
+ return TRUE;
}
-succeeded:
- ret = TRUE;
+ alloc = GST_D3D11_POOL_ALLOCATOR (mem->allocator);
+ /* if flushing, free this memory */
+ if (GST_D3D11_POOL_ALLOCATOR_IS_FLUSHING (alloc)) {
+ GST_LOG_OBJECT (alloc, "allocator is flushing, free %p", mem);
+ return TRUE;
+ }
-done:
- GST_D3D11_MEMORY_UNLOCK (mem);
+ /* return the memory to the allocator */
+ gst_memory_ref (mem);
+ gst_d3d11_pool_allocator_release_memory (alloc, mem);
- return ret;
+ return FALSE;
}
-/**
- * gst_d3d11_memory_get_processor_input_view:
- * @mem: a #GstD3D11Memory
- * @video_device: a #ID3D11VideoDevice
- * @enumerator: a #ID3D11VideoProcessorEnumerator
- *
- * Returns: (transfer none) (nullable): a pointer to the
- * ID3D11VideoProcessorInputView or %NULL if ID3D11VideoProcessorInputView is
- * unavailable
- *
- * Since: 1.20
- */
-ID3D11VideoProcessorInputView *
-gst_d3d11_memory_get_processor_input_view (GstD3D11Memory * mem,
- ID3D11VideoDevice * video_device,
- ID3D11VideoProcessorEnumerator * enumerator)
+static GstFlowReturn
+gst_d3d11_pool_allocator_alloc (GstD3D11PoolAllocator * self, GstMemory ** mem)
{
- g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
- g_return_val_if_fail (video_device != NULL, NULL);
- g_return_val_if_fail (enumerator != NULL, NULL);
+ GstD3D11PoolAllocatorPrivate *priv = self->priv;
+ GstMemory *new_mem;
+
+ /* we allcates texture array during start */
+ if (priv->desc.ArraySize > 1)
+ return GST_FLOW_EOS;
+
+ /* increment the allocation counter */
+ g_atomic_int_add (&priv->cur_mems, 1);
+ new_mem =
+ gst_d3d11_allocator_alloc_internal (GST_D3D11_ALLOCATOR_CAST
+ (_d3d11_memory_allocator), self->device, &priv->desc);
+ if (!new_mem) {
+ GST_ERROR_OBJECT (self, "Failed to allocate new memory");
+ g_atomic_int_add (&priv->cur_mems, -1);
+ return GST_FLOW_ERROR;
+ }
- if (!gst_d3d11_memory_ensure_processor_input_view (mem, video_device,
- enumerator))
- return NULL;
+ if (!priv->mem_size) {
+ if (!gst_d3d11_memory_update_size (new_mem)) {
+ GST_ERROR_OBJECT (self, "Failed to calculate size");
+ gst_memory_unref (new_mem);
+ g_atomic_int_add (&priv->cur_mems, -1);
- return mem->priv->processor_input_view;
+ return GST_FLOW_ERROR;
+ }
+
+ priv->mem_size = new_mem->size;
+ }
+
+ new_mem->size = new_mem->maxsize = priv->mem_size;
+
+ *mem = new_mem;
+
+ return GST_FLOW_OK;
}
-static gboolean
-gst_d3d11_memory_ensure_processor_output_view (GstD3D11Memory * mem,
- ID3D11VideoDevice * video_device,
- ID3D11VideoProcessorEnumerator * enumerator)
+static GstFlowReturn
+gst_d3d11_pool_allocator_acquire_memory_internal (GstD3D11PoolAllocator * self,
+ GstMemory ** memory)
{
- GstD3D11MemoryPrivate *priv = mem->priv;
- GstD3D11Allocator *allocator;
- D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC desc = { 0, };
- HRESULT hr;
- gboolean ret;
+ GstFlowReturn result;
+ GstD3D11PoolAllocatorPrivate *priv = self->priv;
+
+ while (TRUE) {
+ if (G_UNLIKELY (GST_D3D11_POOL_ALLOCATOR_IS_FLUSHING (self)))
+ goto flushing;
+
+ /* try to get a memory from the queue */
+ *memory = gst_atomic_queue_pop (priv->queue);
+ if (G_LIKELY (*memory)) {
+ while (!gst_poll_read_control (priv->poll)) {
+ if (errno == EWOULDBLOCK) {
+ /* We put the memory into the queue but did not finish writing control
+ * yet, let's wait a bit and retry */
+ g_thread_yield ();
+ continue;
+ } else {
+ /* Critical error but GstPoll already complained */
+ break;
+ }
+ }
+ result = GST_FLOW_OK;
+ GST_LOG_OBJECT (self, "acquired memory %p", *memory);
+ break;
+ }
- allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
+ /* no memory, try to allocate some more */
+ GST_LOG_OBJECT (self, "no memory, trying to allocate");
+ result = gst_d3d11_pool_allocator_alloc (self, memory);
+ if (G_LIKELY (result == GST_FLOW_OK))
+ /* we have a memory, return it */
+ break;
- if (!(priv->desc.BindFlags & D3D11_BIND_RENDER_TARGET)) {
- GST_LOG_OBJECT (allocator,
- "Need BindFlags, current flag 0x%x", priv->desc.BindFlags);
- return FALSE;
+ if (G_UNLIKELY (result != GST_FLOW_EOS))
+ /* something went wrong, return error */
+ break;
+
+ /* now we release the control socket, we wait for a memory release or
+ * flushing */
+ if (!gst_poll_read_control (priv->poll)) {
+ if (errno == EWOULDBLOCK) {
+ /* This means that we have two threads trying to allocate memory
+ * already, and the other one already got the wait token. This
+ * means that we only have to wait for the poll now and not write the
+ * token afterwards: we will be woken up once the other thread is
+ * woken up and that one will write the wait token it removed */
+ GST_LOG_OBJECT (self, "waiting for free memory or flushing");
+ gst_poll_wait (priv->poll, GST_CLOCK_TIME_NONE);
+ } else {
+ /* This is a critical error, GstPoll already gave a warning */
+ result = GST_FLOW_ERROR;
+ break;
+ }
+ } else {
+ /* We're the first thread waiting, we got the wait token and have to
+ * write it again later
+ * OR
+ * We're a second thread and just consumed the flush token and block all
+ * other threads, in which case we must not wait and give it back
+ * immediately */
+ if (!GST_D3D11_POOL_ALLOCATOR_IS_FLUSHING (self)) {
+ GST_LOG_OBJECT (self, "waiting for free memory or flushing");
+ gst_poll_wait (priv->poll, GST_CLOCK_TIME_NONE);
+ }
+ gst_poll_write_control (priv->poll);
+ }
}
- /* FIXME: texture array should be supported at some point */
- if (priv->subresource_index != 0) {
- GST_FIXME_OBJECT (allocator,
- "Texture array is not suppoted for processor output view");
- return FALSE;
+ return result;
+
+ /* ERRORS */
+flushing:
+ {
+ GST_DEBUG_OBJECT (self, "we are flushing");
+ return GST_FLOW_FLUSHING;
}
+}
- GST_D3D11_MEMORY_LOCK (mem);
- if (priv->processor_output_view)
- goto succeeded;
+/**
+ * gst_d3d11_pool_allocator_new:
+ * @device: a #GstD3D11Device
+ * @desc: a D3D11_TEXTURE2D_DESC for texture allocation
+ *
+ * Creates a new #GstD3D11PoolAllocator instance.
+ *
+ * Returns: (transfer full): a new #GstD3D11PoolAllocator instance
+ */
+GstD3D11PoolAllocator *
+gst_d3d11_pool_allocator_new (GstD3D11Device * device,
+ const D3D11_TEXTURE2D_DESC * desc)
+{
+ GstD3D11PoolAllocator *self;
- desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
- desc.Texture2D.MipSlice = 0;
+ g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
+ g_return_val_if_fail (desc != NULL, NULL);
- hr = ID3D11VideoDevice_CreateVideoProcessorOutputView (video_device,
- (ID3D11Resource *) priv->texture, enumerator, &desc,
- &priv->processor_output_view);
- if (!gst_d3d11_result (hr, mem->device)) {
- GST_ERROR_OBJECT (allocator,
- "Could not create processor input view, hr: 0x%x", (guint) hr);
- goto done;
- }
+ gst_d3d11_memory_init_once ();
-succeeded:
- ret = TRUE;
+ self = g_object_new (GST_TYPE_D3D11_POOL_ALLOCATOR, NULL);
+ gst_object_ref_sink (self);
-done:
- GST_D3D11_MEMORY_UNLOCK (mem);
+ self->device = gst_object_ref (device);
+ self->priv->desc = *desc;
- return ret;
+ return self;
}
/**
- * gst_d3d11_memory_get_processor_output_view:
- * @mem: a #GstD3D11Memory
- * @video_device: a #ID3D11VideoDevice
- * @enumerator: a #ID3D11VideoProcessorEnumerator
+ * gst_d3d11_pool_allocator_acquire_memory:
+ * @allocator: a #GstD3D11PoolAllocator
+ * @memory: (transfer full): a #GstMemory
*
- * Returns: (transfer none) (nullable): a pointer to the
- * ID3D11VideoProcessorOutputView or %NULL if ID3D11VideoProcessorOutputView is
- * unavailable
+ * Acquires a #GstMemory from @allocator. @memory should point to a memory
+ * location that can hold a pointer to the new #GstMemory.
*
- * Since: 1.20
+ * Returns: a #GstFlowReturn such as %GST_FLOW_FLUSHING when the allocator is
+ * inactive.
*/
-ID3D11VideoProcessorOutputView *
-gst_d3d11_memory_get_processor_output_view (GstD3D11Memory * mem,
- ID3D11VideoDevice * video_device,
- ID3D11VideoProcessorEnumerator * enumerator)
+GstFlowReturn
+gst_d3d11_pool_allocator_acquire_memory (GstD3D11PoolAllocator * allocator,
+ GstMemory ** memory)
{
- g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
- g_return_val_if_fail (video_device != NULL, NULL);
- g_return_val_if_fail (enumerator != NULL, NULL);
+ GstD3D11PoolAllocatorPrivate *priv;
+ GstFlowReturn result;
- if (!gst_d3d11_memory_ensure_processor_output_view (mem, video_device,
- enumerator))
- return NULL;
+ g_return_val_if_fail (GST_IS_D3D11_POOL_ALLOCATOR (allocator),
+ GST_FLOW_ERROR);
+ g_return_val_if_fail (memory != NULL, FALSE);
- return mem->priv->processor_output_view;
+ priv = allocator->priv;
+
+ /* assume we'll have one more outstanding buffer we need to do that so
+ * that concurrent set_active doesn't clear the buffers */
+ g_atomic_int_inc (&priv->outstanding);
+ result = gst_d3d11_pool_allocator_acquire_memory_internal (allocator, memory);
+
+ if (result == GST_FLOW_OK) {
+ GstMemory *mem = *memory;
+ /* Replace default allocator with ours */
+ gst_object_unref (mem->allocator);
+ mem->allocator = gst_object_ref (allocator);
+ GST_MINI_OBJECT_CAST (mem)->dispose = gst_d3d11_memory_release;
+ } else {
+ dec_outstanding (allocator);
+ }
+
+ return result;
}