mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-23 09:04:15 +00:00
nvdec: Port to GstCudaGraphicsResource
Make it possible to share registered graphics resource among nvidia encoders and decoders.
This commit is contained in:
parent
da075b94a9
commit
d0846f8eab
1 changed files with 56 additions and 90 deletions
|
@ -50,17 +50,10 @@ gst_nvdec_copy_device_to_system (GstNvDec * nvdec,
|
||||||
CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer);
|
CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer);
|
||||||
|
|
||||||
#ifdef HAVE_NVCODEC_GST_GL
|
#ifdef HAVE_NVCODEC_GST_GL
|
||||||
typedef struct _GstNvDecCudaGraphicsResourceInfo
|
|
||||||
{
|
|
||||||
GstGLContext *gl_context;
|
|
||||||
GstCudaContext *cuda_context;
|
|
||||||
CUgraphicsResource resource;
|
|
||||||
} GstNvDecCudaGraphicsResourceInfo;
|
|
||||||
|
|
||||||
typedef struct _GstNvDecRegisterResourceData
|
typedef struct _GstNvDecRegisterResourceData
|
||||||
{
|
{
|
||||||
GstMemory *mem;
|
GstMemory *mem;
|
||||||
GstNvDecCudaGraphicsResourceInfo *info;
|
GstCudaGraphicsResource *resource;
|
||||||
GstNvDec *nvdec;
|
GstNvDec *nvdec;
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
} GstNvDecRegisterResourceData;
|
} GstNvDecRegisterResourceData;
|
||||||
|
@ -70,10 +63,9 @@ register_cuda_resource (GstGLContext * context,
|
||||||
GstNvDecRegisterResourceData * data)
|
GstNvDecRegisterResourceData * data)
|
||||||
{
|
{
|
||||||
GstMemory *mem = data->mem;
|
GstMemory *mem = data->mem;
|
||||||
GstNvDecCudaGraphicsResourceInfo *cgr_info = data->info;
|
GstCudaGraphicsResource *resource = data->resource;
|
||||||
GstNvDec *nvdec = data->nvdec;
|
GstNvDec *nvdec = data->nvdec;
|
||||||
GstMapInfo map_info = GST_MAP_INFO_INIT;
|
GstMapInfo map_info = GST_MAP_INFO_INIT;
|
||||||
CUresult cuda_ret;
|
|
||||||
GstGLBuffer *gl_buf_obj;
|
GstGLBuffer *gl_buf_obj;
|
||||||
|
|
||||||
data->ret = FALSE;
|
data->ret = FALSE;
|
||||||
|
@ -90,9 +82,11 @@ register_cuda_resource (GstGLContext * context,
|
||||||
GST_LOG_OBJECT (nvdec,
|
GST_LOG_OBJECT (nvdec,
|
||||||
"registure glbuffer %d to CUDA resource", gl_buf_obj->id);
|
"registure glbuffer %d to CUDA resource", gl_buf_obj->id);
|
||||||
|
|
||||||
cuda_ret = CuGraphicsGLRegisterBuffer (&cgr_info->resource, gl_buf_obj->id,
|
/* register resource without read/write only flags, since
|
||||||
CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD);
|
* downstream CUDA elements (e.g., nvenc) might want to access
|
||||||
if (gst_cuda_result (cuda_ret)) {
|
* this resource later. Instead, use map flags during map/unmap */
|
||||||
|
if (gst_cuda_graphics_resource_register_gl_buffer (resource,
|
||||||
|
gl_buf_obj->id, CU_GRAPHICS_REGISTER_FLAGS_NONE)) {
|
||||||
data->ret = TRUE;
|
data->ret = TRUE;
|
||||||
} else {
|
} else {
|
||||||
GST_WARNING_OBJECT (nvdec, "failed to register memory");
|
GST_WARNING_OBJECT (nvdec, "failed to register memory");
|
||||||
|
@ -107,40 +101,11 @@ register_cuda_resource (GstGLContext * context,
|
||||||
GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
|
GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static GstCudaGraphicsResource *
|
||||||
unregister_cuda_resource (GstGLContext * context,
|
|
||||||
GstNvDecCudaGraphicsResourceInfo * cgr_info)
|
|
||||||
{
|
|
||||||
GstCudaContext *cuda_context = cgr_info->cuda_context;
|
|
||||||
|
|
||||||
if (!gst_cuda_context_push (cuda_context)) {
|
|
||||||
GST_WARNING_OBJECT (context, "failed to push CUDA context");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gst_cuda_result (CuGraphicsUnregisterResource (cgr_info->resource)))
|
|
||||||
GST_WARNING_OBJECT (cuda_context, "failed to unregister resource");
|
|
||||||
|
|
||||||
if (!gst_cuda_context_pop (NULL)) {
|
|
||||||
GST_WARNING_OBJECT (cuda_context, "failed to pop CUDA context");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
free_cgr_info (GstNvDecCudaGraphicsResourceInfo * cgr_info)
|
|
||||||
{
|
|
||||||
gst_gl_context_thread_add (cgr_info->gl_context,
|
|
||||||
(GstGLContextThreadFunc) unregister_cuda_resource, cgr_info);
|
|
||||||
gst_object_unref (cgr_info->gl_context);
|
|
||||||
gst_object_unref (cgr_info->cuda_context);
|
|
||||||
g_free (cgr_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CUgraphicsResource
|
|
||||||
ensure_cuda_graphics_resource (GstMemory * mem, GstNvDec * nvdec)
|
ensure_cuda_graphics_resource (GstMemory * mem, GstNvDec * nvdec)
|
||||||
{
|
{
|
||||||
static GQuark quark = 0;
|
GQuark quark;
|
||||||
GstNvDecCudaGraphicsResourceInfo *cgr_info;
|
GstCudaGraphicsResource *cgr_info;
|
||||||
GstNvDecRegisterResourceData data;
|
GstNvDecRegisterResourceData data;
|
||||||
|
|
||||||
if (!gst_is_gl_memory_pbo (mem)) {
|
if (!gst_is_gl_memory_pbo (mem)) {
|
||||||
|
@ -149,34 +114,30 @@ ensure_cuda_graphics_resource (GstMemory * mem, GstNvDec * nvdec)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!quark)
|
quark = gst_cuda_quark_from_id (GST_CUDA_QUARK_GRAPHICS_RESOURCE);
|
||||||
quark = g_quark_from_static_string ("GstNvDecCudaGraphicsResourceInfo");
|
|
||||||
|
|
||||||
cgr_info = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
|
cgr_info = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
|
||||||
if (!cgr_info) {
|
if (!cgr_info) {
|
||||||
cgr_info = g_new0 (GstNvDecCudaGraphicsResourceInfo, 1);
|
cgr_info = gst_cuda_graphics_resource_new (nvdec->cuda_ctx,
|
||||||
cgr_info->gl_context =
|
GST_OBJECT (GST_GL_BASE_MEMORY_CAST (mem)->context),
|
||||||
gst_object_ref (GST_GL_BASE_MEMORY_CAST (mem)->context);
|
GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER);
|
||||||
cgr_info->cuda_context = gst_object_ref (nvdec->cuda_ctx);
|
|
||||||
data.mem = mem;
|
data.mem = mem;
|
||||||
data.info = cgr_info;
|
data.resource = cgr_info;
|
||||||
data.nvdec = nvdec;
|
data.nvdec = nvdec;
|
||||||
gst_gl_context_thread_add (cgr_info->gl_context,
|
gst_gl_context_thread_add ((GstGLContext *) cgr_info->graphics_context,
|
||||||
(GstGLContextThreadFunc) register_cuda_resource, &data);
|
(GstGLContextThreadFunc) register_cuda_resource, &data);
|
||||||
if (!data.ret) {
|
if (!data.ret) {
|
||||||
GST_WARNING_OBJECT (nvdec, "could not register resource");
|
GST_WARNING_OBJECT (nvdec, "could not register resource");
|
||||||
gst_object_unref (cgr_info->gl_context);
|
gst_cuda_graphics_resource_free (cgr_info);
|
||||||
gst_object_unref (cgr_info->cuda_context);
|
|
||||||
g_free (cgr_info);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, cgr_info,
|
gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, cgr_info,
|
||||||
(GDestroyNotify) free_cgr_info);
|
(GDestroyNotify) gst_cuda_graphics_resource_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cgr_info->resource;
|
return cgr_info;
|
||||||
}
|
}
|
||||||
#endif /* HAVE_NVCODEC_GST_GL */
|
#endif /* HAVE_NVCODEC_GST_GL */
|
||||||
|
|
||||||
|
@ -807,9 +768,8 @@ typedef struct
|
||||||
{
|
{
|
||||||
GstNvDec *nvdec;
|
GstNvDec *nvdec;
|
||||||
CUVIDPARSERDISPINFO *dispinfo;
|
CUVIDPARSERDISPINFO *dispinfo;
|
||||||
CUgraphicsResource *resources;
|
|
||||||
guint num_resources;
|
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
GstBuffer *output_buffer;
|
||||||
} GstNvDecCopyToGLData;
|
} GstNvDecCopyToGLData;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -818,8 +778,8 @@ copy_video_frame_to_gl_textures (GstGLContext * context,
|
||||||
{
|
{
|
||||||
GstNvDec *nvdec = data->nvdec;
|
GstNvDec *nvdec = data->nvdec;
|
||||||
CUVIDPARSERDISPINFO *dispinfo = data->dispinfo;
|
CUVIDPARSERDISPINFO *dispinfo = data->dispinfo;
|
||||||
CUgraphicsResource *resources = data->resources;
|
GstCudaGraphicsResource **resources;
|
||||||
guint num_resources = data->num_resources;
|
guint num_resources;
|
||||||
CUVIDPROCPARAMS proc_params = { 0, };
|
CUVIDPROCPARAMS proc_params = { 0, };
|
||||||
guintptr dptr;
|
guintptr dptr;
|
||||||
guint pitch, i;
|
guint pitch, i;
|
||||||
|
@ -834,6 +794,25 @@ copy_video_frame_to_gl_textures (GstGLContext * context,
|
||||||
|
|
||||||
data->ret = TRUE;
|
data->ret = TRUE;
|
||||||
|
|
||||||
|
num_resources = gst_buffer_n_memory (data->output_buffer);
|
||||||
|
resources = g_newa (GstCudaGraphicsResource *, num_resources);
|
||||||
|
|
||||||
|
for (i = 0; i < num_resources; i++) {
|
||||||
|
GstMemory *mem;
|
||||||
|
|
||||||
|
mem = gst_buffer_peek_memory (data->output_buffer, i);
|
||||||
|
resources[i] = ensure_cuda_graphics_resource (mem, nvdec);
|
||||||
|
if (!resources[i]) {
|
||||||
|
GST_WARNING_OBJECT (nvdec, "could not register %dth memory", i);
|
||||||
|
data->ret = FALSE;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need PBO -> texture */
|
||||||
|
GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
|
||||||
|
}
|
||||||
|
|
||||||
if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
|
if (!gst_cuda_context_push (nvdec->cuda_ctx)) {
|
||||||
GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
|
GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
|
||||||
data->ret = FALSE;
|
data->ret = FALSE;
|
||||||
|
@ -847,13 +826,6 @@ copy_video_frame_to_gl_textures (GstGLContext * context,
|
||||||
goto unlock_cuda_context;
|
goto unlock_cuda_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gst_cuda_result (CuGraphicsMapResources (num_resources, resources,
|
|
||||||
nvdec->cuda_stream))) {
|
|
||||||
GST_WARNING_OBJECT (nvdec, "failed to map CUDA resources");
|
|
||||||
data->ret = FALSE;
|
|
||||||
goto unmap_video_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
mcpy2d.srcMemoryType = CU_MEMORYTYPE_DEVICE;
|
mcpy2d.srcMemoryType = CU_MEMORYTYPE_DEVICE;
|
||||||
mcpy2d.srcPitch = pitch;
|
mcpy2d.srcPitch = pitch;
|
||||||
mcpy2d.dstMemoryType = CU_MEMORYTYPE_DEVICE;
|
mcpy2d.dstMemoryType = CU_MEMORYTYPE_DEVICE;
|
||||||
|
@ -861,9 +833,18 @@ copy_video_frame_to_gl_textures (GstGLContext * context,
|
||||||
for (i = 0; i < num_resources; i++) {
|
for (i = 0; i < num_resources; i++) {
|
||||||
CUdeviceptr cuda_ptr;
|
CUdeviceptr cuda_ptr;
|
||||||
gsize size;
|
gsize size;
|
||||||
|
CUgraphicsResource cuda_resource =
|
||||||
|
gst_cuda_graphics_resource_map (resources[i], nvdec->cuda_stream,
|
||||||
|
CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD);
|
||||||
|
|
||||||
|
if (!cuda_resource) {
|
||||||
|
GST_WARNING_OBJECT (nvdec, "failed to map CUDA resources");
|
||||||
|
data->ret = FALSE;
|
||||||
|
goto unmap_video_frame;
|
||||||
|
}
|
||||||
|
|
||||||
if (!gst_cuda_result (CuGraphicsResourceGetMappedPointer (&cuda_ptr, &size,
|
if (!gst_cuda_result (CuGraphicsResourceGetMappedPointer (&cuda_ptr, &size,
|
||||||
resources[i]))) {
|
cuda_resource))) {
|
||||||
GST_WARNING_OBJECT (nvdec, "failed to map CUDA resource");
|
GST_WARNING_OBJECT (nvdec, "failed to map CUDA resource");
|
||||||
data->ret = FALSE;
|
data->ret = FALSE;
|
||||||
break;
|
break;
|
||||||
|
@ -883,13 +864,13 @@ copy_video_frame_to_gl_textures (GstGLContext * context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gst_cuda_result (CuGraphicsUnmapResources (num_resources, resources,
|
|
||||||
nvdec->cuda_stream)))
|
|
||||||
GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA resources");
|
|
||||||
|
|
||||||
gst_cuda_result (CuStreamSynchronize (nvdec->cuda_stream));
|
gst_cuda_result (CuStreamSynchronize (nvdec->cuda_stream));
|
||||||
|
|
||||||
unmap_video_frame:
|
unmap_video_frame:
|
||||||
|
for (i = 0; i < num_resources; i++) {
|
||||||
|
gst_cuda_graphics_resource_unmap (resources[i], nvdec->cuda_stream);
|
||||||
|
}
|
||||||
|
|
||||||
if (!gst_cuda_result (CuvidUnmapVideoFrame (nvdec->decoder, dptr)))
|
if (!gst_cuda_result (CuvidUnmapVideoFrame (nvdec->decoder, dptr)))
|
||||||
GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA video frame");
|
GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA video frame");
|
||||||
|
|
||||||
|
@ -902,26 +883,11 @@ static gboolean
|
||||||
gst_nvdec_copy_device_to_gl (GstNvDec * nvdec,
|
gst_nvdec_copy_device_to_gl (GstNvDec * nvdec,
|
||||||
CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer)
|
CUVIDPARSERDISPINFO * dispinfo, GstBuffer * output_buffer)
|
||||||
{
|
{
|
||||||
guint i;
|
|
||||||
GstMemory *mem;
|
|
||||||
GstNvDecCopyToGLData data = { 0, };
|
GstNvDecCopyToGLData data = { 0, };
|
||||||
|
|
||||||
data.nvdec = nvdec;
|
data.nvdec = nvdec;
|
||||||
data.dispinfo = dispinfo;
|
data.dispinfo = dispinfo;
|
||||||
data.num_resources = gst_buffer_n_memory (output_buffer);
|
data.output_buffer = output_buffer;
|
||||||
data.resources = g_newa (CUgraphicsResource, data.num_resources);
|
|
||||||
|
|
||||||
for (i = 0; i < data.num_resources; i++) {
|
|
||||||
mem = gst_buffer_peek_memory (output_buffer, i);
|
|
||||||
data.resources[i] = ensure_cuda_graphics_resource (mem, nvdec);
|
|
||||||
if (!data.resources[i]) {
|
|
||||||
GST_WARNING_OBJECT (nvdec, "could not register %dth memory", i);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Need PBO -> texture */
|
|
||||||
GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_gl_context_thread_add (nvdec->gl_context,
|
gst_gl_context_thread_add (nvdec->gl_context,
|
||||||
(GstGLContextThreadFunc) copy_video_frame_to_gl_textures, &data);
|
(GstGLContextThreadFunc) copy_video_frame_to_gl_textures, &data);
|
||||||
|
|
Loading…
Reference in a new issue