#include "gstd3d11memory.h"
#include "gstd3d11device.h"
#include "gstd3d11utils.h"
-#include "gstd3d11_private.h"
+#include "gstd3d11-private.h"
+
+/**
+ * SECTION:gstd3d11memory
+ * @title: GstD3D11Memory
+ * @short_description: Direct3D11 memory abstraction layer
+ *
+ * Since: 1.22
+ */
GST_DEBUG_CATEGORY_STATIC (gst_d3d11_allocator_debug);
#define GST_CAT_DEFAULT gst_d3d11_allocator_debug
-static GstAllocator *_d3d11_memory_allocator;
+static GstD3D11Allocator *_d3d11_memory_allocator;
+
+GType
+gst_d3d11_allocation_flags_get_type (void)
+{
+ static GType type = 0;
+ static const GFlagsValue values[] = {
+ {GST_D3D11_ALLOCATION_FLAG_DEFAULT, "GST_D3D11_ALLOCATION_FLAG_DEFAULT",
+ "default"},
+ {GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY,
+ "GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY", "texture-array"},
+ {0, nullptr, nullptr}
+ };
+
+ GST_D3D11_CALL_ONCE_BEGIN {
+ type = g_flags_register_static ("GstD3D11AllocationFlags", values);
+ } GST_D3D11_CALL_ONCE_END;
+
+ return type;
+}
+
+GType
+gst_d3d11_memory_transfer_get_type (void)
+{
+ static GType type = 0;
+ static const GFlagsValue values[] = {
+ {GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD,
+ "GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD", "need-download"},
+ {GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD,
+ "GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD", "need-upload"},
+ {0, nullptr, nullptr}
+ };
+
+ GST_D3D11_CALL_ONCE_BEGIN {
+ type = g_flags_register_static ("GstD3D11MemoryTransfer", values);
+ } GST_D3D11_CALL_ONCE_END;
+
+ return type;
+}
+
+GType
+gst_d3d11_memory_native_type_get_type (void)
+{
+ static GType type = 0;
+ static const GEnumValue values[] = {
+ {GST_D3D11_MEMORY_NATIVE_TYPE_INVALID,
+ "GST_D3D11_MEMORY_NATIVE_TYPE_INVALID", "invalid"},
+ {GST_D3D11_MEMORY_NATIVE_TYPE_BUFFER, "GST_D3D11_MEMORY_NATIVE_TYPE_BUFFER",
+ "buffer"},
+ {GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D,
+ "GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D", "texture-2d"},
+ {0, nullptr, nullptr}
+ };
+
+ GST_D3D11_CALL_ONCE_BEGIN {
+ type = g_enum_register_static ("GstD3D11MemoryNativeType", values);
+ } GST_D3D11_CALL_ONCE_END;
+
+ return type;
+}
/* GstD3D11AllocationParams */
static void gst_d3d11_allocation_params_init (GType type);
* @device: a #GstD3D11Device
* @info: a #GstVideoInfo
* @flags: a #GstD3D11AllocationFlags
- * @bind_flags: D3D11_BIND_FLAG value used for creating Direct3D11 texture
+ * @bind_flags: D3D11_BIND_FLAG value used for creating texture
+ * @misc_flags: D3D11_RESOURCE_MISC_FLAG value used for creating texture
*
* Create #GstD3D11AllocationParams object which is used by #GstD3D11BufferPool
* and #GstD3D11Allocator in order to allocate new ID3D11Texture2D
* object with given configuration
*
- * Returns: a #GstD3D11AllocationParams or %NULL if @info is not supported
+ * Returns: (transfer full) (nullable): a #GstD3D11AllocationParams or %NULL if @info is not supported
*
- * Since: 1.20
+ * Since: 1.22
*/
GstD3D11AllocationParams *
-gst_d3d11_allocation_params_new (GstD3D11Device * device, GstVideoInfo * info,
- GstD3D11AllocationFlags flags, guint bind_flags)
+gst_d3d11_allocation_params_new (GstD3D11Device * device,
+ const GstVideoInfo * info, GstD3D11AllocationFlags flags, guint bind_flags,
+ guint misc_flags)
{
GstD3D11AllocationParams *ret;
- const GstD3D11Format *d3d11_format;
+ GstD3D11Format d3d11_format;
guint i;
g_return_val_if_fail (info != NULL, NULL);
- d3d11_format = gst_d3d11_device_format_from_gst (device,
- GST_VIDEO_INFO_FORMAT (info));
- if (!d3d11_format) {
+ if (!gst_d3d11_device_get_format (device, GST_VIDEO_INFO_FORMAT (info),
+ &d3d11_format)) {
GST_WARNING ("Couldn't get d3d11 format");
return NULL;
}
*/
/* If corresponding dxgi format is undefined, use resource format instead */
- if (d3d11_format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
+ if (d3d11_format.dxgi_format == DXGI_FORMAT_UNKNOWN) {
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
- g_assert (d3d11_format->resource_format[i] != DXGI_FORMAT_UNKNOWN);
+ g_assert (d3d11_format.resource_format[i] != DXGI_FORMAT_UNKNOWN);
ret->desc[i].Width = GST_VIDEO_INFO_COMP_WIDTH (info, i);
ret->desc[i].Height = GST_VIDEO_INFO_COMP_HEIGHT (info, i);
ret->desc[i].MipLevels = 1;
ret->desc[i].ArraySize = 1;
- ret->desc[i].Format = d3d11_format->resource_format[i];
+ ret->desc[i].Format = d3d11_format.resource_format[i];
ret->desc[i].SampleDesc.Count = 1;
ret->desc[i].SampleDesc.Quality = 0;
ret->desc[i].Usage = D3D11_USAGE_DEFAULT;
ret->desc[i].BindFlags = bind_flags;
+ ret->desc[i].MiscFlags = misc_flags;
}
} else {
ret->desc[0].Width = GST_VIDEO_INFO_WIDTH (info);
ret->desc[0].Height = GST_VIDEO_INFO_HEIGHT (info);
ret->desc[0].MipLevels = 1;
ret->desc[0].ArraySize = 1;
- ret->desc[0].Format = d3d11_format->dxgi_format;
+ ret->desc[0].Format = d3d11_format.dxgi_format;
ret->desc[0].SampleDesc.Count = 1;
ret->desc[0].SampleDesc.Quality = 0;
ret->desc[0].Usage = D3D11_USAGE_DEFAULT;
ret->desc[0].BindFlags = bind_flags;
+ ret->desc[0].MiscFlags = misc_flags;
}
ret->flags = flags;
*
* Returns: %TRUE if alignment could be applied
*
- * Since: 1.20
+ * Since: 1.22
*/
gboolean
gst_d3d11_allocation_params_alignment (GstD3D11AllocationParams * params,
- GstVideoAlignment * align)
+ const GstVideoAlignment * align)
{
guint i;
guint padding_width, padding_height;
* gst_d3d11_allocation_params_copy:
* @src: a #GstD3D11AllocationParams
*
- * Returns: a copy of @src
+ * Returns: (transfer full): a copy of @src
*
- * Since: 1.20
+ * Since: 1.22
*/
GstD3D11AllocationParams *
gst_d3d11_allocation_params_copy (GstD3D11AllocationParams * src)
*
* Free @params
*
- * Since: 1.20
+ * Since: 1.22
*/
void
gst_d3d11_allocation_params_free (GstD3D11AllocationParams * params)
/* GstD3D11Memory */
#define GST_D3D11_MEMORY_GET_LOCK(m) (&(GST_D3D11_MEMORY_CAST(m)->priv->lock))
-#define GST_D3D11_MEMORY_LOCK(m) G_STMT_START { \
- GST_TRACE("Locking %p from thread %p", (m), g_thread_self()); \
- g_mutex_lock(GST_D3D11_MEMORY_GET_LOCK(m)); \
- GST_TRACE("Locked %p from thread %p", (m), g_thread_self()); \
-} G_STMT_END
-
-#define GST_D3D11_MEMORY_UNLOCK(m) G_STMT_START { \
- GST_TRACE("Unlocking %p from thread %p", (m), g_thread_self()); \
- g_mutex_unlock(GST_D3D11_MEMORY_GET_LOCK(m)); \
-} G_STMT_END
struct _GstD3D11MemoryPrivate
{
ID3D11Texture2D *texture;
- ID3D11Texture2D *staging;
+ ID3D11Buffer *buffer;
+
+ GstD3D11MemoryNativeType native_type;
D3D11_TEXTURE2D_DESC desc;
+ D3D11_BUFFER_DESC buffer_desc;
guint subresource_index;
+ /* protected by device lock */
+ ID3D11Resource *staging;
+ D3D11_MAPPED_SUBRESOURCE map;
+ gint cpu_map_count;
+
+ /* protects resource objects */
+ SRWLOCK lock;
ID3D11ShaderResourceView *shader_resource_view[GST_VIDEO_MAX_PLANES];
guint num_shader_resource_views;
guint num_render_target_views;
ID3D11VideoDecoderOutputView *decoder_output_view;
+ ID3D11VideoDecoder *decoder_handle;
+
ID3D11VideoProcessorInputView *processor_input_view;
ID3D11VideoProcessorOutputView *processor_output_view;
- D3D11_MAPPED_SUBRESOURCE map;
-
-
- GMutex lock;
- gint cpu_map_count;
+ GDestroyNotify notify;
+ gpointer user_data;
};
-GST_DEFINE_MINI_OBJECT_TYPE (GstD3D11Memory, gst_d3d11_memory);
-
static inline D3D11_MAP
gst_d3d11_map_flags_to_d3d11 (GstMapFlags flags)
{
{
GstD3D11MemoryPrivate *priv = dmem->priv;
HRESULT hr;
- ID3D11Resource *staging = (ID3D11Resource *) priv->staging;
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (dmem->device);
- hr = device_context->Map (staging, 0, map_type, 0, &priv->map);
+ hr = device_context->Map (priv->staging, 0, map_type, 0, &priv->map);
if (!gst_d3d11_result (hr, dmem->device)) {
GST_ERROR_OBJECT (GST_MEMORY_CAST (dmem)->allocator,
GstD3D11MemoryPrivate *priv = dmem->priv;
ID3D11DeviceContext *device_context;
- if (!priv->staging || priv->staging == priv->texture ||
+ if (!priv->staging ||
!GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD))
return;
GstD3D11MemoryPrivate *priv = dmem->priv;
ID3D11DeviceContext *device_context;
- if (!priv->staging || priv->staging == priv->texture ||
+ if (!priv->staging ||
!GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD))
return;
GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
GstD3D11MemoryPrivate *priv = dmem->priv;
GstMapFlags flags = info->flags;
- gpointer ret = NULL;
+ GstD3D11DeviceLockGuard lk (dmem->device);
- gst_d3d11_device_lock (dmem->device);
- GST_D3D11_MEMORY_LOCK (dmem);
+ memset (info->user_data, 0, sizeof (info->user_data));
+ info->user_data[0] = GUINT_TO_POINTER (dmem->priv->subresource_index);
if ((flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
- gst_d3d11_memory_upload (dmem);
- GST_MEMORY_FLAG_UNSET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD);
+ if (priv->native_type == GST_D3D11_MEMORY_NATIVE_TYPE_BUFFER) {
+ /* FIXME: handle non-staging buffer */
+ g_assert (priv->buffer != nullptr);
+ return priv->buffer;
+ } else {
+ gst_d3d11_memory_upload (dmem);
+ GST_MEMORY_FLAG_UNSET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD);
- if ((flags & GST_MAP_WRITE) == GST_MAP_WRITE)
- GST_MINI_OBJECT_FLAG_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
+ if ((flags & GST_MAP_WRITE) == GST_MAP_WRITE)
+ GST_MINI_OBJECT_FLAG_SET (dmem,
+ GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
- g_assert (priv->texture != NULL);
- ret = priv->texture;
- goto out;
+ g_assert (priv->texture != NULL);
+ return priv->texture;
+ }
}
if (priv->cpu_map_count == 0) {
D3D11_MAP map_type;
- /* Allocate staging texture for CPU access */
- if (!priv->staging) {
- priv->staging = gst_d3d11_allocate_staging_texture (dmem->device,
- &priv->desc);
+ /* FIXME: handle non-staging buffer */
+ if (priv->native_type == GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D) {
+ /* Allocate staging texture for CPU access */
if (!priv->staging) {
- GST_ERROR_OBJECT (mem->allocator, "Couldn't create staging texture");
- goto out;
+ 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 nullptr;
+ }
+
+ /* first memory, always need download to staging */
+ GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
}
- /* first memory, always need download to staging */
- GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
+ gst_d3d11_memory_download (dmem);
}
- gst_d3d11_memory_download (dmem);
map_type = gst_d3d11_map_flags_to_d3d11 (flags);
-
if (!gst_d3d11_memory_map_cpu_access (dmem, map_type)) {
GST_ERROR_OBJECT (mem->allocator, "Couldn't map staging texture");
- goto out;
+ return nullptr;
}
}
GST_MEMORY_FLAG_UNSET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
priv->cpu_map_count++;
- ret = dmem->priv->map.pData;
-
-out:
- GST_D3D11_MEMORY_UNLOCK (dmem);
- gst_d3d11_device_unlock (dmem->device);
-
- return ret;
+ return dmem->priv->map.pData;
}
/* Must be called with d3d11 device lock */
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);
- device_context->Unmap (staging, 0);
+ device_context->Unmap (priv->staging, 0);
}
static void
{
GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
GstD3D11MemoryPrivate *priv = dmem->priv;
-
- gst_d3d11_device_lock (dmem->device);
- GST_D3D11_MEMORY_LOCK (dmem);
+ GstD3D11DeviceLockGuard lk (dmem->device);
if ((info->flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE)
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
- goto out;
+ return;
}
if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE)
priv->cpu_map_count--;
if (priv->cpu_map_count > 0)
- goto out;
+ return;
gst_d3d11_memory_unmap_cpu_access (dmem);
-
-out:
- GST_D3D11_MEMORY_UNLOCK (dmem);
- gst_d3d11_device_unlock (dmem->device);
}
static GstMemory *
gint stride[GST_VIDEO_MAX_PLANES];
gsize size;
D3D11_TEXTURE2D_DESC *desc = &priv->desc;
- gboolean ret = FALSE;
if (!priv->staging) {
priv->staging = gst_d3d11_allocate_staging_texture (dmem->device,
GST_ERROR_OBJECT (mem->allocator, "Couldn't create staging texture");
return FALSE;
}
-
- GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
}
- gst_d3d11_device_lock (dmem->device);
+ GstD3D11DeviceLockGuard lk (dmem->device);
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 (!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");
- goto out;
+ GST_D3D11_CLEAR_COM (priv->staging);
+ return FALSE;
}
+ GST_D3D11_CLEAR_COM (priv->staging);
mem->maxsize = mem->size = size;
- ret = TRUE;
-out:
- gst_d3d11_device_unlock (dmem->device);
- return ret;
+ return TRUE;
}
/**
*
* Returns: whether @mem is a #GstD3D11Memory
*
- * Since: 1.20
+ * Since: 1.22
*/
gboolean
gst_is_d3d11_memory (GstMemory * mem)
}
/**
+ * gst_d3d11_memory_get_native_type:
+ * @mem: a #GstD3D11Memory
+ *
+ * Returns: a #GstD3D11MemoryNativeType
+ *
+ * Since: 1.22
+ */
+GstD3D11MemoryNativeType
+gst_d3d11_memory_get_native_type (GstD3D11Memory * mem)
+{
+ if (!gst_is_d3d11_memory (GST_MEMORY_CAST (mem)))
+ return GST_D3D11_MEMORY_NATIVE_TYPE_INVALID;
+
+ return mem->priv->native_type;
+}
+
+/**
* 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
+ * Since: 1.22
*/
void
gst_d3d11_memory_init_once (void)
{
- static gsize _init = 0;
-
- if (g_once_init_enter (&_init)) {
-
+ GST_D3D11_CALL_ONCE_BEGIN {
GST_DEBUG_CATEGORY_INIT (gst_d3d11_allocator_debug, "d3d11allocator", 0,
"Direct3D11 Texture Allocator");
_d3d11_memory_allocator =
- (GstAllocator *) g_object_new (GST_TYPE_D3D11_ALLOCATOR, NULL);
+ (GstD3D11Allocator *) g_object_new (GST_TYPE_D3D11_ALLOCATOR, NULL);
gst_object_ref_sink (_d3d11_memory_allocator);
+ gst_object_ref (_d3d11_memory_allocator);
- gst_allocator_register (GST_D3D11_MEMORY_NAME, _d3d11_memory_allocator);
- g_once_init_leave (&_init, 1);
- }
+ gst_allocator_register (GST_D3D11_MEMORY_NAME,
+ GST_ALLOCATOR_CAST (_d3d11_memory_allocator));
+ } GST_D3D11_CALL_ONCE_END;
}
/**
- * gst_d3d11_memory_get_texture_handle:
+ * gst_d3d11_memory_get_resource_handle:
* @mem: a #GstD3D11Memory
*
- * Returns: (transfer none): a ID3D11Texture2D handle. Caller must not release
+ * Returns: (transfer none) (nullable): a ID3D11Resource handle. Caller must not release
* returned handle.
*
- * Since: 1.20
+ * Since: 1.22
*/
-ID3D11Texture2D *
-gst_d3d11_memory_get_texture_handle (GstD3D11Memory * mem)
+ID3D11Resource *
+gst_d3d11_memory_get_resource_handle (GstD3D11Memory * mem)
{
g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), NULL);
- return mem->priv->texture;
+ switch (mem->priv->native_type) {
+ case GST_D3D11_MEMORY_NATIVE_TYPE_BUFFER:
+ return mem->priv->buffer;
+ case GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D:
+ return mem->priv->texture;
+ default:
+ break;
+ }
+
+ return nullptr;
}
/**
*
* Returns: subresource index corresponding to @mem.
*
- * Since: 1.20
+ * Since: 1.22
*/
guint
gst_d3d11_memory_get_subresource_index (GstD3D11Memory * mem)
{
g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), 0);
+ if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
+ return 0;
+
return mem->priv->subresource_index;
}
*
* Returns: %TRUE if successeed
*
- * Since: 1.20
+ * Since: 1.22
*/
gboolean
gst_d3d11_memory_get_texture_desc (GstD3D11Memory * mem,
g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
g_return_val_if_fail (desc != NULL, FALSE);
+ if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
+ return FALSE;
+
*desc = mem->priv->desc;
return TRUE;
}
+/**
+ * gst_d3d11_memory_get_buffer_desc:
+ * @mem: a #GstD3D11Memory
+ * @desc: (out): a D3D11_BUFFER_DESC
+ *
+ * Fill @desc with D3D11_BUFFER_DESC for ID3D11Buffer
+ *
+ * Returns: %TRUE if successeed
+ *
+ * Since: 1.22
+ */
+gboolean
+gst_d3d11_memory_get_buffer_desc (GstD3D11Memory * mem,
+ D3D11_BUFFER_DESC * desc)
+{
+ g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
+ g_return_val_if_fail (desc != NULL, FALSE);
+
+ if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_BUFFER)
+ return FALSE;
+
+ *desc = mem->priv->buffer_desc;
+
+ return TRUE;
+}
+
+/**
+ * gst_d3d11_memory_get_resource_stride:
+ * @mem: a #GstD3D11Memory
+ * @stride: (out): stride of resource
+ *
+ * Returns: %TRUE if successeed
+ *
+ * Since: 1.22
+ */
gboolean
-gst_d3d11_memory_get_texture_stride (GstD3D11Memory * mem, guint * stride)
+gst_d3d11_memory_get_resource_stride (GstD3D11Memory * mem, guint * stride)
{
g_return_val_if_fail (gst_is_d3d11_memory (GST_MEMORY_CAST (mem)), FALSE);
g_return_val_if_fail (stride != NULL, FALSE);
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:
- case DXGI_FORMAT_G8R8_G8B8_UNORM:
- case DXGI_FORMAT_R8G8_B8G8_UNORM:
- case DXGI_FORMAT_R16G16B16A16_UNORM:
- num_views = 1;
- formats[0] = priv->desc.Format;
- break;
- case DXGI_FORMAT_AYUV:
- case DXGI_FORMAT_YUY2:
- 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;
- break;
- case DXGI_FORMAT_Y210:
- num_views = 1;
- formats[0] = DXGI_FORMAT_R16G16B16A16_UNORM;
- break;
- case DXGI_FORMAT_Y410:
- num_views = 1;
- formats[0] = DXGI_FORMAT_R10G10B10A2_UNORM;
- break;
- default:
- g_assert_not_reached ();
- return FALSE;
+ num_views = gst_d3d11_dxgi_format_get_resource_format (priv->desc.Format,
+ formats);
+ if (!num_views) {
+ GST_ERROR_OBJECT (GST_MEMORY_CAST (mem)->allocator,
+ "Unknown resource formats for DXGI format %s (%d)",
+ gst_d3d11_dxgi_format_to_string (priv->desc.Format), priv->desc.Format);
+ return FALSE;
}
- if ((priv->desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) ==
- D3D11_BIND_SHADER_RESOURCE) {
+ if ((priv->desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) != 0) {
resource_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
resource_desc.Texture2D.MipLevels = 1;
if (!gst_d3d11_result (hr, mem->device)) {
GST_ERROR_OBJECT (GST_MEMORY_CAST (mem)->allocator,
- "Failed to create %dth resource view (0x%x)", i, (guint) hr);
+ "Failed to create resource DXGI format %s (%d) for plane %d"
+ " view (0x%x)", gst_d3d11_dxgi_format_to_string (formats[i]),
+ formats[i], i, (guint) hr);
goto error;
}
}
gst_d3d11_memory_ensure_shader_resource_view (GstD3D11Memory * mem)
{
GstD3D11MemoryPrivate *priv = mem->priv;
- gboolean ret = FALSE;
+
+ if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
+ return FALSE;
if (!(priv->desc.BindFlags & D3D11_BIND_SHADER_RESOURCE)) {
GST_LOG_OBJECT (GST_MEMORY_CAST (mem)->allocator,
return FALSE;
}
- 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);
+ GstD3D11SRWLockGuard lk (GST_D3D11_MEMORY_GET_LOCK (mem));
+ if (priv->num_shader_resource_views)
+ return TRUE;
- return ret;
+ return create_shader_resource_views (mem);
}
/**
* Returns: the number of ID3D11ShaderResourceView that can be used
* for processing GPU operation with @mem
*
- * Since: 1.20
+ * Since: 1.22
*/
guint
gst_d3d11_memory_get_shader_resource_view_size (GstD3D11Memory * mem)
* ID3D11ShaderResourceView or %NULL if ID3D11ShaderResourceView is unavailable
* for @index
*
- * Since: 1.20
+ * Since: 1.22
*/
ID3D11ShaderResourceView *
gst_d3d11_memory_get_shader_resource_view (GstD3D11Memory * mem, guint index)
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;
- break;
- default:
- g_assert_not_reached ();
- return FALSE;
+ num_views = gst_d3d11_dxgi_format_get_resource_format (priv->desc.Format,
+ formats);
+ if (!num_views) {
+ GST_ERROR_OBJECT (GST_MEMORY_CAST (mem)->allocator,
+ "Unknown resource formats for DXGI format %s (%d)",
+ gst_d3d11_dxgi_format_to_string (priv->desc.Format), priv->desc.Format);
+ return FALSE;
}
- if ((priv->desc.BindFlags & D3D11_BIND_RENDER_TARGET) ==
- D3D11_BIND_RENDER_TARGET) {
+ if ((priv->desc.BindFlags & D3D11_BIND_RENDER_TARGET) != 0) {
render_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
render_desc.Texture2D.MipSlice = 0;
&priv->render_target_view[i]);
if (!gst_d3d11_result (hr, mem->device)) {
GST_ERROR_OBJECT (GST_MEMORY_CAST (mem)->allocator,
- "Failed to create %dth render target view (0x%x)", i, (guint) hr);
+ "Failed to create resource DXGI format %s (%d) for plane %d"
+ " view (0x%x)", gst_d3d11_dxgi_format_to_string (formats[i]),
+ formats[i], i, (guint) hr);
goto error;
}
}
gst_d3d11_memory_ensure_render_target_view (GstD3D11Memory * mem)
{
GstD3D11MemoryPrivate *priv = mem->priv;
- gboolean ret = FALSE;
+
+ if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
+ return FALSE;
if (!(priv->desc.BindFlags & D3D11_BIND_RENDER_TARGET)) {
GST_WARNING_OBJECT (GST_MEMORY_CAST (mem)->allocator,
return FALSE;
}
- GST_D3D11_MEMORY_LOCK (mem);
- if (priv->num_render_target_views) {
- ret = TRUE;
- goto done;
- }
-
- ret = create_render_target_views (mem);
-
-done:
- GST_D3D11_MEMORY_UNLOCK (mem);
+ GstD3D11SRWLockGuard lk (GST_D3D11_MEMORY_GET_LOCK (mem));
+ if (priv->num_render_target_views)
+ return TRUE;
- return ret;
+ return create_render_target_views (mem);
}
/**
* Returns: the number of ID3D11RenderTargetView that can be used
* for processing GPU operation with @mem
*
- * Since: 1.20
+ * Since: 1.22
*/
guint
gst_d3d11_memory_get_render_target_view_size (GstD3D11Memory * mem)
* ID3D11RenderTargetView or %NULL if ID3D11RenderTargetView is unavailable
* for @index
*
- * Since: 1.20
+ * Since: 1.22
*/
ID3D11RenderTargetView *
gst_d3d11_memory_get_render_target_view (GstD3D11Memory * mem, guint index)
static gboolean
gst_d3d11_memory_ensure_decoder_output_view (GstD3D11Memory * mem,
- ID3D11VideoDevice * video_device, GUID * decoder_profile)
+ ID3D11VideoDevice * video_device, ID3D11VideoDecoder * decoder,
+ const GUID * decoder_profile)
{
GstD3D11MemoryPrivate *dmem_priv = mem->priv;
GstD3D11Allocator *allocator;
D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC desc;
HRESULT hr;
- gboolean ret = FALSE;
+
+ if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
+ return FALSE;
allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
return FALSE;
}
- GST_D3D11_MEMORY_LOCK (mem);
+ GstD3D11SRWLockGuard lk (GST_D3D11_MEMORY_GET_LOCK (mem));
if (dmem_priv->decoder_output_view) {
dmem_priv->decoder_output_view->GetDesc (&desc);
- if (IsEqualGUID (desc.DecodeProfile, *decoder_profile)) {
- goto succeeded;
+ if (IsEqualGUID (desc.DecodeProfile, *decoder_profile) &&
+ dmem_priv->decoder_handle == decoder) {
+ return TRUE;
} else {
/* Shouldn't happen, but try again anyway */
GST_WARNING_OBJECT (allocator,
"Existing view has different decoder profile");
GST_D3D11_CLEAR_COM (dmem_priv->decoder_output_view);
+ GST_D3D11_CLEAR_COM (dmem_priv->decoder_handle);
}
}
- if (dmem_priv->decoder_output_view)
- goto succeeded;
-
desc.DecodeProfile = *decoder_profile;
desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
desc.Texture2D.ArraySlice = dmem_priv->subresource_index;
if (!gst_d3d11_result (hr, mem->device)) {
GST_ERROR_OBJECT (allocator,
"Could not create decoder output view, hr: 0x%x", (guint) hr);
- goto done;
+ return FALSE;
}
-succeeded:
- ret = TRUE;
+ /* XXX: decoder output view is bound to video device, not decoder handle
+ * from API point of view. But some driver seems to be unhappy
+ * when decoder handle is released while there are outstanding view objects */
+ dmem_priv->decoder_handle = decoder;
+ decoder->AddRef ();
-done:
- GST_D3D11_MEMORY_UNLOCK (mem);
-
- return ret;
+ return TRUE;
}
/**
* gst_d3d11_memory_get_decoder_output_view:
* @mem: a #GstD3D11Memory
+ * @video_device: (transfer none): a ID3D11VideoDevice handle
+ * @decoder: (transfer none): a ID3D11VideoDecoder handle
+ * @decoder_profile: a DXVA decoder profile GUID
*
* Returns: (transfer none) (nullable): a pointer to the
* ID3D11VideoDecoderOutputView or %NULL if ID3D11VideoDecoderOutputView is
* unavailable
*
- * Since: 1.20
+ * Since: 1.22
*/
ID3D11VideoDecoderOutputView *
gst_d3d11_memory_get_decoder_output_view (GstD3D11Memory * mem,
- ID3D11VideoDevice * video_device, GUID * decoder_profile)
+ ID3D11VideoDevice * video_device, ID3D11VideoDecoder * decoder,
+ const 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 != NULL, NULL);
g_return_val_if_fail (decoder_profile != NULL, NULL);
if (!gst_d3d11_memory_ensure_decoder_output_view (mem,
- video_device, decoder_profile))
+ video_device, decoder, decoder_profile))
return NULL;
return mem->priv->decoder_output_view;
GstD3D11Allocator *allocator;
D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC desc;
HRESULT hr;
- gboolean ret = FALSE;
+
+ if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
+ return FALSE;
allocator = GST_D3D11_ALLOCATOR (GST_MEMORY_CAST (mem)->allocator);
return FALSE;
}
- GST_D3D11_MEMORY_LOCK (mem);
+ GstD3D11SRWLockGuard lk (GST_D3D11_MEMORY_GET_LOCK (mem));
if (dmem_priv->processor_input_view)
- goto succeeded;
+ return TRUE;
desc.FourCC = 0;
desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
if (!gst_d3d11_result (hr, mem->device)) {
GST_ERROR_OBJECT (allocator,
"Could not create processor input view, hr: 0x%x", (guint) hr);
- goto done;
+ return FALSE;
}
-succeeded:
- ret = TRUE;
-
-done:
- GST_D3D11_MEMORY_UNLOCK (mem);
-
- return ret;
+ return TRUE;
}
/**
* ID3D11VideoProcessorInputView or %NULL if ID3D11VideoProcessorInputView is
* unavailable
*
- * Since: 1.20
+ * Since: 1.22
*/
ID3D11VideoProcessorInputView *
gst_d3d11_memory_get_processor_input_view (GstD3D11Memory * mem,
GstD3D11Allocator *allocator;
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC desc;
HRESULT hr;
- gboolean ret;
+
+ if (mem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
+ return FALSE;
memset (&desc, 0, sizeof (D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC));
return FALSE;
}
- GST_D3D11_MEMORY_LOCK (mem);
+ GstD3D11SRWLockGuard lk (GST_D3D11_MEMORY_GET_LOCK (mem));
if (priv->processor_output_view)
- goto succeeded;
+ return TRUE;
desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
desc.Texture2D.MipSlice = 0;
if (!gst_d3d11_result (hr, mem->device)) {
GST_ERROR_OBJECT (allocator,
"Could not create processor input view, hr: 0x%x", (guint) hr);
- goto done;
+ return FALSE;
}
-succeeded:
- ret = TRUE;
-
-done:
- GST_D3D11_MEMORY_UNLOCK (mem);
-
- return ret;
+ return TRUE;
}
/**
* ID3D11VideoProcessorOutputView or %NULL if ID3D11VideoProcessorOutputView is
* unavailable
*
- * Since: 1.20
+ * Since: 1.22
*/
ID3D11VideoProcessorOutputView *
gst_d3d11_memory_get_processor_output_view (GstD3D11Memory * mem,
static GstMemory *gst_d3d11_allocator_dummy_alloc (GstAllocator * allocator,
gsize size, GstAllocationParams * params);
static GstMemory *gst_d3d11_allocator_alloc_internal (GstD3D11Allocator * self,
- GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc);
+ GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc,
+ ID3D11Texture2D * texture);
static void gst_d3d11_allocator_free (GstAllocator * allocator,
GstMemory * mem);
GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
GstD3D11Memory *copy_dmem;
GstD3D11Device *device = dmem->device;
- ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device);
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (device);
D3D11_TEXTURE2D_DESC dst_desc = { 0, };
D3D11_TEXTURE2D_DESC src_desc = { 0, };
GstMemory *copy = NULL;
GstMapInfo info;
- HRESULT hr;
- UINT bind_flags = 0;
- UINT supported_flags = 0;
+
+ if (dmem->priv->native_type != GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D)
+ return priv->fallback_copy (mem, offset, size);
/* non-zero offset or different size is not supported */
if (offset != 0 || (size != -1 && (gsize) size != mem->size)) {
return priv->fallback_copy (mem, offset, size);
}
- gst_d3d11_device_lock (device);
+ GstD3D11DeviceLockGuard lk (device);
+
if (!gst_memory_map (mem, &info,
(GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
- gst_d3d11_device_unlock (device);
GST_WARNING_OBJECT (alloc, "Failed to map memory, try fallback copy");
dst_desc.SampleDesc.Count = 1;
dst_desc.ArraySize = 1;
dst_desc.Usage = D3D11_USAGE_DEFAULT;
+ dst_desc.BindFlags = src_desc.BindFlags;
- /* If supported, use bind flags for SRV/RTV */
- hr = device_handle->CheckFormatSupport (src_desc.Format, &supported_flags);
- if (gst_d3d11_result (hr, device)) {
- if ((supported_flags & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE) ==
- D3D11_FORMAT_SUPPORT_SHADER_SAMPLE) {
- bind_flags |= D3D11_BIND_SHADER_RESOURCE;
- }
-
- if ((supported_flags & D3D11_FORMAT_SUPPORT_RENDER_TARGET) ==
- D3D11_FORMAT_SUPPORT_RENDER_TARGET) {
- bind_flags |= D3D11_BIND_RENDER_TARGET;
- }
- }
-
- copy = gst_d3d11_allocator_alloc_internal (alloc, device, &dst_desc);
+ copy = gst_d3d11_allocator_alloc_internal (alloc, device, &dst_desc, nullptr);
if (!copy) {
gst_memory_unmap (mem, &info);
- gst_d3d11_device_unlock (device);
GST_WARNING_OBJECT (alloc,
"Failed to allocate new d3d11 map memory, try fallback copy");
dmem->priv->texture, dmem->priv->subresource_index, NULL);
copy->maxsize = copy->size = mem->maxsize;
gst_memory_unmap (mem, &info);
- gst_d3d11_device_unlock (device);
/* newly allocated memory holds valid image data. We need download this
* pixel data into staging memory for CPU access */
GST_D3D11_CLEAR_COM (dmem_priv->processor_output_view);
GST_D3D11_CLEAR_COM (dmem_priv->texture);
GST_D3D11_CLEAR_COM (dmem_priv->staging);
+ GST_D3D11_CLEAR_COM (dmem_priv->buffer);
+
+ GST_D3D11_CLEAR_COM (dmem_priv->decoder_handle);
gst_clear_object (&dmem->device);
- g_mutex_clear (&dmem_priv->lock);
+
+ if (dmem_priv->notify)
+ dmem_priv->notify (dmem_priv->user_data);
+
g_free (dmem->priv);
g_free (dmem);
}
static GstMemory *
-gst_d3d11_allocator_alloc_wrapped (GstD3D11Allocator * self,
+gst_d3d11_allocator_alloc_wrapped_internal (GstD3D11Allocator * self,
GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc,
ID3D11Texture2D * texture)
{
gst_memory_init (GST_MEMORY_CAST (mem),
(GstMemoryFlags) 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->priv->native_type = GST_D3D11_MEMORY_NATIVE_TYPE_TEXTURE_2D;
mem->device = (GstD3D11Device *) gst_object_ref (device);
- /* This is staging texture as well */
- if (desc->Usage == D3D11_USAGE_STAGING) {
- mem->priv->staging = texture;
- texture->AddRef ();
- }
-
return GST_MEMORY_CAST (mem);
}
+typedef void (*GstD3D11ClearRTVFunc) (ID3D11DeviceContext * context_handle,
+ ID3D11RenderTargetView * rtv);
+
+static void
+clear_rtv_chroma (ID3D11DeviceContext * context_handle,
+ ID3D11RenderTargetView * rtv)
+{
+ const FLOAT clear_color[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
+
+ context_handle->ClearRenderTargetView (rtv, clear_color);
+}
+
+static void
+clear_rtv_vuya (ID3D11DeviceContext * context_handle,
+ ID3D11RenderTargetView * rtv)
+{
+ const FLOAT clear_color[4] = { 0.5f, 0.5f, 0.0f, 1.0f };
+
+ context_handle->ClearRenderTargetView (rtv, clear_color);
+}
+
static GstMemory *
gst_d3d11_allocator_alloc_internal (GstD3D11Allocator * self,
- GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc)
+ GstD3D11Device * device, const D3D11_TEXTURE2D_DESC * desc,
+ ID3D11Texture2D * texture)
{
- ID3D11Texture2D *texture = NULL;
ID3D11Device *device_handle;
+ ID3D11DeviceContext *context_handle;
HRESULT hr;
+ GstMemory *mem;
+ GstD3D11Memory *dmem;
+ ID3D11RenderTargetView *rtv = nullptr;
+ GstD3D11ClearRTVFunc clear_func = nullptr;
+ gboolean is_new_texture = TRUE;
device_handle = gst_d3d11_device_get_device_handle (device);
- hr = device_handle->CreateTexture2D (desc, NULL, &texture);
- if (!gst_d3d11_result (hr, device)) {
- GST_ERROR_OBJECT (self, "Couldn't create texture");
- return NULL;
+ if (!texture) {
+ hr = device_handle->CreateTexture2D (desc, nullptr, &texture);
+ if (!gst_d3d11_result (hr, device)) {
+ GST_ERROR_OBJECT (self, "Couldn't create texture");
+ return nullptr;
+ }
+ } else {
+ is_new_texture = FALSE;
+ }
+
+ mem =
+ gst_d3d11_allocator_alloc_wrapped_internal (self, device, desc, texture);
+ if (!mem)
+ return nullptr;
+
+ /* Don't clear external texture */
+ if (!is_new_texture)
+ return mem;
+
+ /* Clear with YUV black if needed and possible
+ * TODO: do this using UAV if RTV is not allowed (e.g., packed YUV formats) */
+ if ((desc->BindFlags & D3D11_BIND_RENDER_TARGET) == 0)
+ return mem;
+
+ dmem = GST_D3D11_MEMORY_CAST (mem);
+ switch (desc->Format) {
+ case DXGI_FORMAT_NV12:
+ case DXGI_FORMAT_P010:
+ case DXGI_FORMAT_P016:
+ /* Y component will be zero already */
+ rtv = gst_d3d11_memory_get_render_target_view (dmem, 1);
+ clear_func = (GstD3D11ClearRTVFunc) clear_rtv_chroma;
+ break;
+ case DXGI_FORMAT_AYUV:
+ rtv = gst_d3d11_memory_get_render_target_view (dmem, 0);
+ clear_func = (GstD3D11ClearRTVFunc) clear_rtv_vuya;
+ break;
+ default:
+ return mem;
}
- return gst_d3d11_allocator_alloc_wrapped (self, device, desc, texture);
+ if (!rtv)
+ return mem;
+
+ context_handle = gst_d3d11_device_get_device_context_handle (device);
+ GstD3D11DeviceLockGuard lk (device);
+ clear_func (context_handle, rtv);
+
+ return mem;
}
/**
* gst_d3d11_allocator_alloc:
- * @allocator: a #GstD3D11Allocator
- * @device: a #GstD3D11Device
+ * @allocator: (transfer none) (allow-none): a #GstD3D11Allocator
+ * @device: (transfer none): a #GstD3D11Device
* @desc: a D3D11_TEXTURE2D_DESC struct
*
- * Returns: a newly allocated #GstD3D11Memory with given parameters.
+ * Returns: (transfer full) (nullable): a newly allocated #GstD3D11Memory with given parameters.
*
- * Since: 1.20
+ * Since: 1.22
*/
GstMemory *
gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
{
GstMemory *mem;
+ if (!allocator) {
+ gst_d3d11_memory_init_once ();
+ allocator = _d3d11_memory_allocator;
+ }
+
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);
- mem = gst_d3d11_allocator_alloc_internal (allocator, device, desc);
+ mem = gst_d3d11_allocator_alloc_internal (allocator, device, desc, nullptr);
if (!mem)
return NULL;
return mem;
}
+/**
+ * gst_d3d11_allocator_alloc_buffer:
+ * @allocator: (transfer none) (allow-none): a #GstD3D11Allocator
+ * @device: (transfer none): a #GstD3D11Device
+ * @desc: a D3D11_BUFFER_DESC struct
+ *
+ * Returns: (transfer full) (nullable): a newly allocated #GstD3D11Memory with given parameters.
+ *
+ * Since: 1.22
+ */
+GstMemory *
+gst_d3d11_allocator_alloc_buffer (GstD3D11Allocator * allocator,
+ GstD3D11Device * device, const D3D11_BUFFER_DESC * desc)
+{
+ GstD3D11Memory *mem;
+ ID3D11Buffer *buffer;
+ ID3D11Device *device_handle;
+ HRESULT hr;
+
+ if (!allocator) {
+ gst_d3d11_memory_init_once ();
+ allocator = _d3d11_memory_allocator;
+ }
+
+ g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), nullptr);
+ g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
+ g_return_val_if_fail (desc != nullptr, nullptr);
+
+ if (desc->Usage != D3D11_USAGE_STAGING) {
+ GST_FIXME_OBJECT (allocator, "Non staging buffer is not supported");
+ return nullptr;
+ }
+
+ device_handle = gst_d3d11_device_get_device_handle (device);
+
+ hr = device_handle->CreateBuffer (desc, nullptr, &buffer);
+ if (!gst_d3d11_result (hr, device)) {
+ GST_ERROR_OBJECT (allocator, "Couldn't create buffer");
+ return nullptr;
+ }
+
+ mem = g_new0 (GstD3D11Memory, 1);
+ mem->priv = g_new0 (GstD3D11MemoryPrivate, 1);
+
+ gst_memory_init (GST_MEMORY_CAST (mem),
+ (GstMemoryFlags) 0, GST_ALLOCATOR_CAST (allocator), nullptr, 0, 0, 0, 0);
+ mem->priv->buffer = buffer;
+ mem->priv->buffer_desc = *desc;
+ mem->priv->native_type = GST_D3D11_MEMORY_NATIVE_TYPE_BUFFER;
+ mem->device = (GstD3D11Device *) gst_object_ref (device);
+
+ GST_MEMORY_CAST (mem)->maxsize = GST_MEMORY_CAST (mem)->size =
+ desc->ByteWidth;
+
+ return GST_MEMORY_CAST (mem);
+}
+
+/**
+ * gst_d3d11_allocator_alloc_wrapped:
+ * @allocator: (transfer none) (allow-none): a #GstD3D11Allocator
+ * @device: (transfer none): a #GstD3D11Device
+ * @texture: a ID3D11Texture2D
+ * @size: CPU accessible memory size
+ * @user_data: (allow-none): user data
+ * @notify: (allow-none): called with @user_data when the memory is freed
+ *
+ * Allocates memory object with @texture. The refcount of @texture
+ * will be increased by one.
+ *
+ * Caller should set valid CPU acessible memory value to @size
+ * (which is typically calculated by using staging texture and Map/Unmap)
+ * or zero is allowed. In that case, allocator will create a temporary staging
+ * texture to get the size and the temporary staging texture will be released.
+ *
+ * Caller must not be confused that @size is CPU accessible size, not raw
+ * texture size.
+ *
+ * Returns: (transfer full) (nullable): a newly allocated #GstD3D11Memory with given @texture
+ * if successful, or %NULL if @texture is not a valid handle or configuration
+ * is not supported.
+ *
+ * Since: 1.22
+ */
+GstMemory *
+gst_d3d11_allocator_alloc_wrapped (GstD3D11Allocator * allocator,
+ GstD3D11Device * device, ID3D11Texture2D * texture, gsize size,
+ gpointer user_data, GDestroyNotify notify)
+{
+ GstMemory *mem;
+ GstD3D11Memory *dmem;
+ D3D11_TEXTURE2D_DESC desc = { 0, };
+ ID3D11Texture2D *tex = nullptr;
+ HRESULT hr;
+
+ if (!allocator) {
+ gst_d3d11_memory_init_once ();
+ allocator = _d3d11_memory_allocator;
+ }
+
+ g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), nullptr);
+ g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
+ g_return_val_if_fail (texture != nullptr, nullptr);
+
+ hr = texture->QueryInterface (IID_PPV_ARGS (&tex));
+ if (FAILED (hr)) {
+ GST_WARNING_OBJECT (allocator, "Not a valid texture handle");
+ return nullptr;
+ }
+
+ tex->GetDesc (&desc);
+ mem = gst_d3d11_allocator_alloc_internal (allocator, device, &desc, tex);
+
+ if (!mem)
+ return nullptr;
+
+ if (size == 0) {
+ if (!gst_d3d11_memory_update_size (mem)) {
+ GST_ERROR_OBJECT (allocator, "Failed to calculate size");
+ gst_memory_unref (mem);
+ return nullptr;
+ }
+ } else {
+ mem->maxsize = mem->size = size;
+ }
+
+ dmem = GST_D3D11_MEMORY_CAST (mem);
+
+ dmem->priv->user_data = user_data;
+ dmem->priv->notify = notify;
+
+ return mem;
+}
+
+/**
+ * gst_d3d11_allocator_set_active:
+ * @allocator: a #GstD3D11Allocator
+ * @active: the new active state
+ *
+ * Controls the active state of @allocator. Default #GstD3D11Allocator is
+ * stateless and therefore active state is ignored, but subclass implementation
+ * (e.g., #GstD3D11PoolAllocator) will require explicit active state control
+ * for its internal resource management.
+ *
+ * This method is conceptually identical to gst_buffer_pool_set_active method.
+ *
+ * Returns: %TRUE if active state of @allocator was successfully updated.
+ *
+ * Since: 1.22
+ */
gboolean
gst_d3d11_allocator_set_active (GstD3D11Allocator * allocator, gboolean active)
{
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);
+ if (klass->set_active)
+ return klass->set_active (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_GET_LOCK(alloc) \
+ (&(GST_D3D11_POOL_ALLOCATOR_CAST(alloc)->priv->lock))
#define GST_D3D11_POOL_ALLOCATOR_IS_FLUSHING(alloc) (g_atomic_int_get (&alloc->priv->flushing))
struct _GstD3D11PoolAllocatorPrivate
/* This lock will protect all below variables apart from atomic ones
* (identical to GstBufferPool::priv::rec_lock) */
- GRecMutex lock;
+ CRITICAL_SECTION lock;
gboolean started;
gboolean active;
gsize mem_size;
};
-static void gst_d3d11_pool_allocator_dispose (GObject * object);
static void gst_d3d11_pool_allocator_finalize (GObject * object);
static gboolean
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;
+ d3d11alloc_class->set_active = gst_d3d11_pool_allocator_set_active;
}
static void
priv = allocator->priv = (GstD3D11PoolAllocatorPrivate *)
gst_d3d11_pool_allocator_get_instance_private (allocator);
- g_rec_mutex_init (&priv->lock);
+
+ InitializeCriticalSection (&priv->lock);
priv->poll = gst_poll_new_timer ();
priv->queue = gst_atomic_queue_new (16);
}
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);
gst_d3d11_pool_allocator_stop (self);
gst_atomic_queue_unref (priv->queue);
gst_poll_free (priv->poll);
- g_rec_mutex_clear (&priv->lock);
+ DeleteCriticalSection (&priv->lock);
GST_D3D11_CLEAR_COM (priv->texture);
+ gst_clear_object (&self->device);
+
G_OBJECT_CLASS (pool_alloc_parent_class)->finalize (object);
}
GstMemory *mem;
priv->texture->AddRef ();
- mem =
- gst_d3d11_allocator_alloc_wrapped (GST_D3D11_ALLOCATOR_CAST
- (_d3d11_memory_allocator), self->device, &priv->desc, priv->texture);
+ mem = gst_d3d11_allocator_alloc_wrapped_internal (_d3d11_memory_allocator,
+ self->device, &priv->desc, priv->texture);
if (i == 0) {
if (!gst_d3d11_memory_update_size (mem)) {
GST_LOG_OBJECT (self, "active %d", active);
- GST_D3D11_POOL_ALLOCATOR_LOCK (self);
+ GstD3D11CSLockGuard lk (GST_D3D11_POOL_ALLOCATOR_GET_LOCK (self));
/* just return if we are already in the right state */
if (priv->active == active)
- goto was_ok;
+ return TRUE;
if (active) {
- if (!gst_d3d11_pool_allocator_start (self))
- goto start_failed;
+ if (!gst_d3d11_pool_allocator_start (self)) {
+ GST_ERROR_OBJECT (self, "start failed");
+ return FALSE;
+ }
/* flush_stop may release memory objects, setting to active to avoid running
* do_stop while activating the pool */
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;
+ if (!gst_d3d11_pool_allocator_stop (self)) {
+ GST_ERROR_OBJECT (self, "stop failed");
+ return FALSE;
+ }
}
priv->active = FALSE;
}
- GST_D3D11_POOL_ALLOCATOR_UNLOCK (self);
-
return TRUE;
-
-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;
- }
}
static void
/* 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);
+ GstD3D11CSLockGuard lk (GST_D3D11_POOL_ALLOCATOR_GET_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_MINI_OBJECT_CAST (mem)->dispose = NULL;
mem->allocator = (GstAllocator *) gst_object_ref (_d3d11_memory_allocator);
- gst_object_unref (self);
/* keep it around in our queue */
gst_atomic_queue_push (self->priv->queue, mem);
gst_poll_write_control (self->priv->poll);
dec_outstanding (self);
+
+ gst_object_unref (self);
}
static gboolean
/* 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);
+ new_mem = gst_d3d11_allocator_alloc_internal (_d3d11_memory_allocator,
+ self->device, &priv->desc, nullptr);
if (!new_mem) {
GST_ERROR_OBJECT (self, "Failed to allocate new memory");
g_atomic_int_add (&priv->cur_mems, -1);
* Creates a new #GstD3D11PoolAllocator instance.
*
* Returns: (transfer full): a new #GstD3D11PoolAllocator instance
+ *
+ * Since: 1.22
*/
GstD3D11PoolAllocator *
gst_d3d11_pool_allocator_new (GstD3D11Device * device,
/**
* gst_d3d11_pool_allocator_acquire_memory:
* @allocator: a #GstD3D11PoolAllocator
- * @memory: (transfer full): a #GstMemory
+ * @memory: (out): a #GstMemory
*
* Acquires a #GstMemory from @allocator. @memory should point to a memory
* location that can hold a pointer to the new #GstMemory.
*
* Returns: %TRUE if the size of memory pool is known
*
- * Since: 1.20
+ * Since: 1.22
*/
gboolean
gst_d3d11_pool_allocator_get_pool_size (GstD3D11PoolAllocator * allocator,