nvdec: Add fallback for CUDA/OpenGL interop failure

It happens when local OpenGL context belongs to non-nvidia GPU.
This commit is contained in:
Seungha Yang 2020-03-15 19:20:47 +09:00
parent efcabce98e
commit 22eab50907
4 changed files with 72 additions and 3 deletions

View file

@ -92,6 +92,9 @@ typedef struct _GstNvCodecCudaVTable
CUresult (CUDAAPI * CUresult (CUDAAPI *
CuGraphicsResourceSetMapFlags) (CUgraphicsResource resource, CuGraphicsResourceSetMapFlags) (CUgraphicsResource resource,
unsigned int flags); unsigned int flags);
CUresult (CUDAAPI * CuGLGetDevices) (unsigned int *pCudaDeviceCount,
CUdevice * pCudaDevices, unsigned int cudaDeviceCount,
CUGLDeviceList deviceList);
} GstNvCodecCudaVTable; } GstNvCodecCudaVTable;
static GstNvCodecCudaVTable gst_cuda_vtable = { 0, }; static GstNvCodecCudaVTable gst_cuda_vtable = { 0, };
@ -150,6 +153,7 @@ gst_cuda_load_library (void)
LOAD_SYMBOL (cuGraphicsGLRegisterImage, CuGraphicsGLRegisterImage); LOAD_SYMBOL (cuGraphicsGLRegisterImage, CuGraphicsGLRegisterImage);
LOAD_SYMBOL (cuGraphicsGLRegisterBuffer, CuGraphicsGLRegisterBuffer); LOAD_SYMBOL (cuGraphicsGLRegisterBuffer, CuGraphicsGLRegisterBuffer);
LOAD_SYMBOL (cuGraphicsResourceSetMapFlags, CuGraphicsResourceSetMapFlags); LOAD_SYMBOL (cuGraphicsResourceSetMapFlags, CuGraphicsResourceSetMapFlags);
LOAD_SYMBOL (cuGLGetDevices, CuGLGetDevices);
vtable->loaded = TRUE; vtable->loaded = TRUE;
@ -389,3 +393,13 @@ CuGraphicsResourceSetMapFlags (CUgraphicsResource resource, unsigned int flags)
return gst_cuda_vtable.CuGraphicsResourceSetMapFlags (resource, flags); return gst_cuda_vtable.CuGraphicsResourceSetMapFlags (resource, flags);
} }
CUresult CUDAAPI
CuGLGetDevices (unsigned int *pCudaDeviceCount, CUdevice * pCudaDevices,
unsigned int cudaDeviceCount, CUGLDeviceList deviceList)
{
g_assert (gst_cuda_vtable.CuGLGetDevices != NULL);
return gst_cuda_vtable.CuGLGetDevices (pCudaDeviceCount, pCudaDevices,
cudaDeviceCount, deviceList);
}

View file

@ -142,5 +142,11 @@ G_GNUC_INTERNAL
CUresult CUDAAPI CuGraphicsResourceSetMapFlags (CUgraphicsResource resource, CUresult CUDAAPI CuGraphicsResourceSetMapFlags (CUgraphicsResource resource,
unsigned int flags); unsigned int flags);
G_GNUC_INTERNAL
CUresult CUDAAPI CuGLGetDevices (unsigned int * pCudaDeviceCount,
CUdevice * pCudaDevices,
unsigned int cudaDeviceCount,
CUGLDeviceList deviceList);
G_END_DECLS G_END_DECLS
#endif /* __GST_CUDA_LOADER_H__ */ #endif /* __GST_CUDA_LOADER_H__ */

View file

@ -479,7 +479,7 @@ gst_nvdec_negotiate (GstVideoDecoder * decoder)
if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_GL && if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_GL &&
!gst_nvdec_ensure_gl_context (nvdec)) { !gst_nvdec_ensure_gl_context (nvdec)) {
GST_WARNING_OBJECT (nvdec, GST_WARNING_OBJECT (nvdec,
"OpenGL context cannot support PBO memory, fallback to system memory"); "OpenGL context is not CUDA-compatible, fallback to system memory");
nvdec->mem_type = GST_NVDEC_MEM_TYPE_SYSTEM; nvdec->mem_type = GST_NVDEC_MEM_TYPE_SYSTEM;
} }
@ -579,7 +579,7 @@ parser_display_callback (GstNvDec * nvdec, CUVIDPARSERDISPINFO * dispinfo)
GstVideoCodecFrame *frame = NULL; GstVideoCodecFrame *frame = NULL;
GstBuffer *output_buffer = NULL; GstBuffer *output_buffer = NULL;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
gboolean copy_ret; gboolean copy_ret = FALSE;
GST_LOG_OBJECT (nvdec, "picture index: %u", dispinfo->picture_index); GST_LOG_OBJECT (nvdec, "picture index: %u", dispinfo->picture_index);
@ -639,7 +639,19 @@ parser_display_callback (GstNvDec * nvdec, CUVIDPARSERDISPINFO * dispinfo)
#ifdef HAVE_NVCODEC_GST_GL #ifdef HAVE_NVCODEC_GST_GL
if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_GL) { if (nvdec->mem_type == GST_NVDEC_MEM_TYPE_GL) {
copy_ret = gst_nvdec_copy_device_to_gl (nvdec, dispinfo, output_buffer); copy_ret = gst_nvdec_copy_device_to_gl (nvdec, dispinfo, output_buffer);
} else
/* FIXME: This is the case where OpenGL context of downstream glbufferpool
* belongs to non-nvidia (or different device).
* There should be enhancement to ensure nvdec has compatible OpenGL context
*/
if (!copy_ret) {
GST_WARNING_OBJECT (nvdec,
"Couldn't copy frame to GL memory, fallback to system memory");
nvdec->mem_type = GST_NVDEC_MEM_TYPE_SYSTEM;
}
}
if (!copy_ret)
#endif #endif
{ {
copy_ret = gst_nvdec_copy_device_to_system (nvdec, dispinfo, output_buffer); copy_ret = gst_nvdec_copy_device_to_system (nvdec, dispinfo, output_buffer);
@ -1203,9 +1215,32 @@ gst_nvdec_finish (GstVideoDecoder * decoder)
} }
#ifdef HAVE_NVCODEC_GST_GL #ifdef HAVE_NVCODEC_GST_GL
static void
gst_nvdec_check_cuda_device_from_context (GstGLContext * context,
gboolean * ret)
{
guint device_count = 0;
CUdevice device_list[1] = { 0, };
CUresult cuda_ret;
*ret = FALSE;
cuda_ret = CuGLGetDevices (&device_count,
device_list, 1, CU_GL_DEVICE_LIST_ALL);
if (!gst_cuda_result (cuda_ret) || device_count == 0)
return;
*ret = TRUE;
return;
}
static gboolean static gboolean
gst_nvdec_ensure_gl_context (GstNvDec * nvdec) gst_nvdec_ensure_gl_context (GstNvDec * nvdec)
{ {
gboolean ret;
if (!nvdec->gl_display) { if (!nvdec->gl_display) {
GST_DEBUG_OBJECT (nvdec, "No available OpenGL display"); GST_DEBUG_OBJECT (nvdec, "No available OpenGL display");
return FALSE; return FALSE;
@ -1241,6 +1276,14 @@ gst_nvdec_ensure_gl_context (GstNvDec * nvdec)
return FALSE; return FALSE;
} }
gst_gl_context_thread_add (nvdec->gl_context,
(GstGLContextThreadFunc) gst_nvdec_check_cuda_device_from_context, &ret);
if (!ret) {
GST_WARNING_OBJECT (nvdec, "Current OpenGL context is not CUDA-compatible");
return FALSE;
}
return TRUE; return TRUE;
} }

View file

@ -92,6 +92,11 @@ typedef struct
gsize Height; gsize Height;
} CUDA_MEMCPY2D; } CUDA_MEMCPY2D;
typedef enum
{
CU_GL_DEVICE_LIST_ALL = 0x01,
} CUGLDeviceList;
#define CUDA_VERSION 10000 #define CUDA_VERSION 10000
#ifdef _WIN32 #ifdef _WIN32
@ -112,6 +117,7 @@ typedef struct
#define cuMemcpy2D cuMemcpy2D_v2 #define cuMemcpy2D cuMemcpy2D_v2
#define cuMemcpy2DAsync cuMemcpy2DAsync_v2 #define cuMemcpy2DAsync cuMemcpy2DAsync_v2
#define cuMemFree cuMemFree_v2 #define cuMemFree cuMemFree_v2
#define cuGLGetDevices cuGLGetDevices_v2
G_END_DECLS G_END_DECLS