#include "gstd3d11bufferpool.h"
#include "gstd3d11memory.h"
#include "gstd3d11device.h"
+#include "gstd3d11utils.h"
+
+#include <string.h>
GST_DEBUG_CATEGORY_STATIC (gst_d3d11_buffer_pool_debug);
#define GST_CAT_DEFAULT gst_d3d11_buffer_pool_debug
GstD3D11Device *device;
GstD3D11Allocator *allocator;
- /* initial buffer used for calculating buffer size */
- GstBuffer *initial_buffer;
-
gboolean add_videometa;
GstD3D11AllocationParams *d3d11_params;
+
+ gint stride[GST_VIDEO_MAX_PLANES];
+ gsize size[GST_VIDEO_MAX_PLANES];
+ gsize offset[GST_VIDEO_MAX_PLANES];
};
#define gst_d3d11_buffer_pool_parent_class parent_class
gst_d3d11_allocation_params_free (priv->d3d11_params);
priv->d3d11_params = NULL;
- gst_clear_buffer (&priv->initial_buffer);
gst_clear_object (&priv->device);
gst_clear_object (&priv->allocator);
GstAllocator *allocator = NULL;
gboolean ret = TRUE;
D3D11_TEXTURE2D_DESC *desc;
+ GstBuffer *staging_buffer;
gint i;
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min_buffers,
if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
goto wrong_config;
- gst_clear_buffer (&priv->initial_buffer);
gst_clear_object (&priv->allocator);
if (allocator) {
}
}
- gst_d3d11_buffer_pool_alloc (pool, &priv->initial_buffer, NULL);
+ staging_buffer = gst_d3d11_allocate_staging_buffer (priv->allocator,
+ &info, priv->d3d11_params->d3d11_format, priv->d3d11_params->desc, TRUE);
- if (!priv->initial_buffer) {
- GST_ERROR_OBJECT (pool, "Could not create initial buffer");
+ if (!staging_buffer) {
+ GST_ERROR_OBJECT (pool, "Couldn't allocated staging buffer");
return FALSE;
+ } else {
+ GstVideoMeta *meta = gst_buffer_get_video_meta (staging_buffer);
+
+ if (!meta) {
+ GST_ERROR_OBJECT (pool, "Buffer doesn't have video meta");
+ gst_buffer_unref (staging_buffer);
+ return FALSE;
+ }
+
+ for (i = 0; i < gst_buffer_n_memory (staging_buffer); i++) {
+ GstMemory *mem = gst_buffer_peek_memory (staging_buffer, i);
+
+ priv->size[i] = gst_memory_get_sizes (mem, NULL, NULL);
+ }
+
+ memcpy (priv->offset, meta->offset, sizeof (priv->offset));
+ memcpy (priv->stride, meta->stride, sizeof (priv->stride));
}
- self->buffer_size = gst_buffer_get_size (priv->initial_buffer);
+ self->buffer_size = gst_buffer_get_size (staging_buffer);
+ gst_buffer_unref (staging_buffer);
gst_buffer_pool_config_set_params (config,
caps, self->buffer_size, min_buffers, max_buffers);
GstBuffer *buf;
GstD3D11AllocationParams *d3d11_params = priv->d3d11_params;
GstVideoInfo *info = &d3d11_params->info;
- GstVideoInfo *aligned_info = &d3d11_params->aligned_info;
- gint n_texture = 0;
gint i;
- gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
-
- /* consume pre-allocated buffer if any */
- if (G_UNLIKELY (priv->initial_buffer)) {
- *buffer = priv->initial_buffer;
- priv->initial_buffer = NULL;
-
- return GST_FLOW_OK;
- }
buf = gst_buffer_new ();
if (d3d11_params->d3d11_format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
- for (n_texture = 0; n_texture < GST_VIDEO_INFO_N_PLANES (info); n_texture++) {
- d3d11_params->plane = n_texture;
- mem = gst_d3d11_allocator_alloc (priv->allocator, d3d11_params);
+ 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;
gst_buffer_append_memory (buf, mem);
}
} else {
- d3d11_params->plane = 0;
- mem = gst_d3d11_allocator_alloc (priv->allocator, priv->d3d11_params);
- n_texture++;
+ 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);
}
- /* calculate offset */
- for (i = 0; i < n_texture && i < GST_VIDEO_MAX_PLANES - 1; i++) {
- offset[i + 1] = offset[i] +
- d3d11_params->stride[i] * GST_VIDEO_INFO_COMP_HEIGHT (aligned_info, i);
- }
-
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),
- offset, d3d11_params->stride);
+ priv->offset, priv->stride);
}
*buffer = buf;
}
static gpointer
+gst_d3d11_memory_map_staging (GstMemory * mem, GstMapFlags flags)
+{
+ GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
+
+ g_mutex_lock (&dmem->lock);
+ if (dmem->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 *) dmem->texture, 0, map_type, 0, &dmem->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 (!ret) {
+ g_mutex_unlock (&dmem->lock);
+ return NULL;
+ }
+ }
+
+ dmem->cpu_map_count++;
+ g_mutex_unlock (&dmem->lock);
+
+ return dmem->map.pData;
+}
+
+static gpointer
gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
{
GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
+ if (dmem->type == GST_D3D11_MEMORY_TYPE_STAGING) {
+ if ((flags & GST_MAP_D3D11) == GST_MAP_D3D11)
+ return dmem->texture;
+
+ return gst_d3d11_memory_map_staging (mem, flags);
+ }
+
g_mutex_lock (&dmem->lock);
if ((flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
if (dmem->staging &&
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (dmem->device);
+ if (dmem->type == GST_D3D11_MEMORY_TYPE_STAGING)
+ staging = (ID3D11Resource *) dmem->texture;
+
gst_d3d11_device_lock (dmem->device);
ID3D11DeviceContext_Unmap (device_context, staging, 0);
gst_d3d11_device_unlock (dmem->device);
g_mutex_lock (&dmem->lock);
if ((info->flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
- if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE)
+ if (dmem->type != GST_D3D11_MEMORY_TYPE_STAGING &&
+ (info->flags & GST_MAP_WRITE) == GST_MAP_WRITE)
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
g_mutex_unlock (&dmem->lock);
return;
}
- if ((info->flags & GST_MAP_WRITE))
+ if (dmem->type != GST_D3D11_MEMORY_TYPE_STAGING &&
+ (info->flags & GST_MAP_WRITE))
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD);
dmem->cpu_map_count--;
static gboolean
calculate_mem_size (GstD3D11Device * device, ID3D11Texture2D * texture,
- D3D11_TEXTURE2D_DESC * desc, D3D11_MAP map_type,
+ const D3D11_TEXTURE2D_DESC * desc, D3D11_MAP map_type,
gint stride[GST_VIDEO_MAX_PLANES], gsize * size)
{
HRESULT hr;
GstMemory *
gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
- GstD3D11AllocationParams * params)
+ const D3D11_TEXTURE2D_DESC * desc, GstD3D11AllocationFlags flags,
+ gsize size)
{
GstD3D11Memory *mem;
GstD3D11Device *device;
ID3D11Texture2D *texture = NULL;
- ID3D11Texture2D *staging = NULL;
- D3D11_TEXTURE2D_DESC *desc;
- gsize *size;
- gboolean is_first = FALSE;
guint index_to_use = 0;
GstD3D11AllocatorPrivate *priv;
GstD3D11MemoryType type = GST_D3D11_MEMORY_TYPE_TEXTURE;
g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), NULL);
- g_return_val_if_fail (params != NULL, NULL);
+ g_return_val_if_fail (desc != NULL, NULL);
+ g_return_val_if_fail (size > 0, NULL);
priv = allocator->priv;
device = allocator->device;
- desc = ¶ms->desc[params->plane];
- size = ¶ms->size[params->plane];
-
- if (*size == 0)
- is_first = TRUE;
- if ((params->flags & GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY)) {
+ if ((flags & GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY)) {
gint i;
do_again:
}
}
- /* per plane, allocated staging texture to calculate actual size,
- * stride, and offset */
- if (is_first) {
- gint num_plane;
- gint stride[GST_VIDEO_MAX_PLANES];
- gsize mem_size;
- gint i;
+ mem = g_new0 (GstD3D11Memory, 1);
- staging = create_staging_texture (device, desc);
- if (!staging) {
- GST_ERROR_OBJECT (allocator, "Couldn't create staging texture");
- goto error;
- }
+ gst_memory_init (GST_MEMORY_CAST (mem),
+ 0, GST_ALLOCATOR_CAST (allocator), NULL, size, 0, 0, size);
- if (!calculate_mem_size (device,
- staging, desc, D3D11_MAP_READ, stride, &mem_size))
- goto error;
+ g_mutex_init (&mem->lock);
+ mem->desc = *desc;
+ mem->texture = texture;
+ mem->device = gst_object_ref (device);
+ mem->type = type;
+ mem->subresource_index = index_to_use;
- num_plane = gst_d3d11_dxgi_format_n_planes (desc->Format);
+ return GST_MEMORY_CAST (mem);
- for (i = 0; i < num_plane; i++) {
- params->stride[params->plane + i] = stride[i];
- }
+error:
+ if (texture)
+ gst_d3d11_device_release_texture (device, texture);
+
+ return NULL;
+}
- *size = mem_size;
+GstMemory *
+gst_d3d11_allocator_alloc_staging (GstD3D11Allocator * allocator,
+ const D3D11_TEXTURE2D_DESC * desc, GstD3D11AllocationFlags flags,
+ gint * stride)
+{
+ GstD3D11Memory *mem;
+ GstD3D11Device *device;
+ ID3D11Texture2D *texture = NULL;
+ gsize mem_size = 0;
+ gint mem_stride[GST_VIDEO_MAX_PLANES];
+
+ g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), NULL);
+ g_return_val_if_fail (desc != NULL, NULL);
+
+ device = allocator->device;
+
+ texture = create_staging_texture (device, desc);
+ if (!texture) {
+ GST_ERROR_OBJECT (allocator, "Couldn't create staging texture");
+ goto error;
+ }
+
+ 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;
}
mem = g_new0 (GstD3D11Memory, 1);
gst_memory_init (GST_MEMORY_CAST (mem),
- 0, GST_ALLOCATOR_CAST (allocator), NULL, *size, 0, 0, *size);
+ 0, GST_ALLOCATOR_CAST (allocator), NULL, mem_size, 0, 0, mem_size);
g_mutex_init (&mem->lock);
- mem->info = params->info;
- mem->plane = params->plane;
mem->desc = *desc;
mem->texture = texture;
- mem->staging = staging;
mem->device = gst_object_ref (device);
- mem->type = type;
- mem->subresource_index = index_to_use;
+ mem->type = GST_D3D11_MEMORY_TYPE_STAGING;
- if (staging)
- GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
+ /* every plan will have identical size */
+ if (stride)
+ *stride = mem_stride[0];
return GST_MEMORY_CAST (mem);
if (texture)
gst_d3d11_device_release_texture (device, texture);
- if (staging)
- gst_d3d11_device_release_texture (device, texture);
-
return NULL;
}
GstVideoInfo aligned_info;
const GstD3D11Format *d3d11_format;
- /* size and stride of staging texture, set by allocator */
- gint stride[GST_VIDEO_MAX_PLANES];
- gsize size[GST_VIDEO_MAX_PLANES];
-
- /* Current target plane for allocation */
- guint plane;
-
GstD3D11AllocationFlags flags;
/*< private >*/
{
GST_D3D11_MEMORY_TYPE_TEXTURE = 0,
GST_D3D11_MEMORY_TYPE_ARRAY = 1,
+ GST_D3D11_MEMORY_TYPE_STAGING = 2,
} GstD3D11MemoryType;
struct _GstD3D11Memory
ID3D11RenderTargetView *render_target_view[GST_VIDEO_MAX_PLANES];
guint num_render_target_views;
- GstVideoInfo info;
-
- guint plane;
GstD3D11MemoryType type;
/* > 0 if this is Array typed memory */
GstD3D11Allocator * gst_d3d11_allocator_new (GstD3D11Device *device);
GstMemory * gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
- GstD3D11AllocationParams * params);
+ const D3D11_TEXTURE2D_DESC * desc,
+ GstD3D11AllocationFlags flags,
+ gsize size);
+
+GstMemory * gst_d3d11_allocator_alloc_staging (GstD3D11Allocator * allocator,
+ const D3D11_TEXTURE2D_DESC * desc,
+ GstD3D11AllocationFlags flags,
+ gint * stride);
+
void gst_d3d11_allocator_set_flushing (GstD3D11Allocator * allocator,
gboolean flushing);
#include "gstd3d11utils.h"
#include "gstd3d11device.h"
+#include "gstd3d11memory.h"
#include <windows.h>
#include <versionhelpers.h>
return vendor;
}
+GstBuffer *
+gst_d3d11_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;
+}
+
gboolean
_gst_d3d11_result (HRESULT hr, GstD3D11Device * device, GstDebugCategory * cat,
const gchar * file, const gchar * function, gint line)
GstD3D11DeviceVendor gst_d3d11_get_device_vendor (GstD3D11Device * device);
+GstBuffer * gst_d3d11_allocate_staging_buffer (GstD3D11Allocator * allocator,
+ const GstVideoInfo * info,
+ const GstD3D11Format * format,
+ const D3D11_TEXTURE2D_DESC desc[GST_VIDEO_MAX_PLANES],
+ gboolean add_videometa);
+
gboolean _gst_d3d11_result (HRESULT hr,
GstD3D11Device * device,
GstDebugCategory * cat,