d3d11decoder: Resurrect zero-copy for fixed-size DPB pool

Enable zero-copy if downstream proposed pool and therefore decoder
can know the amount of buffer required by downstream.
Otherwise decoder will copy when our DPB pool has no sufficient
buffers for later decoding operation.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2097>
This commit is contained in:
Seungha Yang 2021-03-23 13:48:09 +09:00 committed by GStreamer Marge Bot
parent b392ed82ba
commit 90181642a3
3 changed files with 124 additions and 9 deletions

View file

@ -1956,3 +1956,38 @@ gst_d3d11_pool_allocator_acquire_memory (GstD3D11PoolAllocator * allocator,
return result;
}
/**
* gst_d3d11_pool_allocator_get_pool_size:
* @allocator: a #GstD3D11PoolAllocator
* @max_size: (out) (optional): the max size of pool
* @outstanding_size: (out) (optional): the number of outstanding memory
*
* Returns: %TRUE if the size of memory pool is known
*
* Since: 1.20
*/
gboolean
gst_d3d11_pool_allocator_get_pool_size (GstD3D11PoolAllocator * allocator,
guint * max_size, guint * outstanding_size)
{
GstD3D11PoolAllocatorPrivate *priv;
g_return_val_if_fail (GST_IS_D3D11_POOL_ALLOCATOR (allocator), FALSE);
priv = allocator->priv;
if (max_size) {
if (priv->desc.ArraySize > 1) {
*max_size = priv->desc.ArraySize;
} else {
/* For non-texture-array memory, we don't have any limit yet */
*max_size = 0;
}
}
if (outstanding_size)
*outstanding_size = g_atomic_int_get (&priv->outstanding);
return TRUE;
}

View file

@ -267,6 +267,11 @@ GST_D3D11_API
GstFlowReturn gst_d3d11_pool_allocator_acquire_memory (GstD3D11PoolAllocator * allocator,
GstMemory ** memory);
GST_D3D11_API
gboolean gst_d3d11_pool_allocator_get_pool_size (GstD3D11PoolAllocator * allocator,
guint * max_size,
guint * outstanding_size);
G_END_DECLS
#endif /* __GST_D3D11_MEMORY_H__ */

View file

@ -150,6 +150,7 @@ struct _GstD3D11Decoder
gboolean use_array_of_texture;
guint dpb_size;
guint downstream_min_buffers;
gboolean wait_on_pool_full;
/* Used for array-of-texture */
guint8 next_view_id;
@ -921,6 +922,7 @@ gst_d3d11_decoder_open (GstD3D11Decoder * self)
* Actual buffer pool size will be "dpb_size + downstream_min_buffers"
*/
self->downstream_min_buffers = 0;
self->wait_on_pool_full = FALSE;
self->opened = TRUE;
gst_d3d11_device_unlock (self->device);
@ -1511,9 +1513,18 @@ gst_d3d11_decoder_decide_allocation (GstD3D11Decoder * decoder,
gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
/* create our own pool */
if (pool && (use_d3d11_pool && !GST_D3D11_BUFFER_POOL (pool))) {
gst_object_unref (pool);
pool = NULL;
if (pool && use_d3d11_pool) {
if (!GST_D3D11_BUFFER_POOL (pool)) {
GST_DEBUG_OBJECT (videodec,
"Downstream pool is not d3d11, will create new one");
gst_clear_object (&pool);
} else {
GstD3D11BufferPool *dpool = GST_D3D11_BUFFER_POOL (pool);
if (dpool->device != decoder->device) {
GST_DEBUG_OBJECT (videodec, "Different device, will create new one");
gst_clear_object (&pool);
}
}
}
if (!pool) {
@ -1522,7 +1533,6 @@ gst_d3d11_decoder_decide_allocation (GstD3D11Decoder * decoder,
else
pool = gst_video_buffer_pool_new ();
min = max = 0;
size = (guint) vinfo.size;
}
@ -1563,8 +1573,35 @@ gst_d3d11_decoder_decide_allocation (GstD3D11Decoder * decoder,
/* Store min buffer size. We need to take account of the amount of buffers
* which might be held by downstream in case of zero-copy playback */
/* XXX: hardcoded bound 16, to avoid too large pool size */
decoder->downstream_min_buffers = MIN (min, 16);
if (!decoder->internal_pool) {
if (n > 0) {
GST_DEBUG_OBJECT (videodec, "Downstream proposed pool");
decoder->wait_on_pool_full = TRUE;
/* XXX: hardcoded bound 16, to avoid too large pool size */
decoder->downstream_min_buffers = MIN (min, 16);
} else {
GST_DEBUG_OBJECT (videodec, "Downstream didn't propose pool");
decoder->wait_on_pool_full = FALSE;
/* don't know how many buffers would be queued by downstream */
decoder->downstream_min_buffers = 4;
}
} else {
/* We configured our DPB pool already, let's check if our margin can
* cover min size */
decoder->wait_on_pool_full = FALSE;
if (n > 0) {
if (decoder->downstream_min_buffers >= min)
decoder->wait_on_pool_full = TRUE;
GST_DEBUG_OBJECT (videodec,
"Pre-allocated margin %d can%s cover downstream min size %d",
decoder->downstream_min_buffers,
decoder->wait_on_pool_full ? "" : "not", min);
} else {
GST_DEBUG_OBJECT (videodec, "Downstream min size is unknown");
}
}
GST_DEBUG_OBJECT (videodec, "Downstream min buffres: %d", min);
}
@ -1599,12 +1636,50 @@ gboolean
gst_d3d11_decoder_can_direct_render (GstD3D11Decoder * decoder,
GstBuffer * view_buffer, GstMiniObject * picture)
{
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
GstMemory *mem;
GstD3D11PoolAllocator *alloc;
guint max_size = 0, outstanding_size = 0;
if (!decoder->can_direct_rendering || !decoder->downstream_supports_d3d11 ||
!decoder->use_array_of_texture)
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (view_buffer), FALSE);
if (!decoder->can_direct_rendering || !decoder->downstream_supports_d3d11)
return FALSE;
/* we can do direct render in this case, since there is no DPB pool size
* limit */
if (decoder->use_array_of_texture)
return TRUE;
/* Let's believe downstream info */
if (decoder->wait_on_pool_full)
return TRUE;
/* Check if we are about to full */
mem = gst_buffer_peek_memory (view_buffer, 0);
/* something went wrong */
if (!gst_is_d3d11_memory (mem)) {
GST_ERROR_OBJECT (decoder, "Not a D3D11 memory");
return FALSE;
}
alloc = GST_D3D11_POOL_ALLOCATOR (mem->allocator);
if (!gst_d3d11_pool_allocator_get_pool_size (alloc, &max_size,
&outstanding_size)) {
GST_ERROR_OBJECT (decoder, "Couldn't query pool size");
return FALSE;
}
/* 2 buffer margin */
if (max_size <= outstanding_size + 1) {
GST_DEBUG_OBJECT (decoder, "memory pool is about to full (%u/%u)",
outstanding_size, max_size);
return FALSE;
}
GST_LOG_OBJECT (decoder, "Can do direct rendering");
return TRUE;
}