nvdec: Port to GstCudaGraphicsResource

Make it possible to share registered graphics resource among nvidia encoders
and decoders.
This commit is contained in:
Seungha Yang 2019-08-18 13:27:38 +09:00
parent da075b94a9
commit d0846f8eab

View file

@ -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);