diff --git a/sys/nvcodec/gstcudaloader.c b/sys/nvcodec/gstcudaloader.c index de9547f646..2cd7ab23d5 100644 --- a/sys/nvcodec/gstcudaloader.c +++ b/sys/nvcodec/gstcudaloader.c @@ -82,6 +82,8 @@ typedef struct _GstNvCodecCudaVTable unsigned int image, unsigned int target, unsigned int Flags); CUresult (*CuGraphicsGLRegisterBuffer) (CUgraphicsResource * pCudaResource, unsigned int buffer, unsigned int Flags); + CUresult (*CuGraphicsResourceSetMapFlags) (CUgraphicsResource resource, + unsigned int flags); } GstNvCodecCudaVTable; static GstNvCodecCudaVTable gst_cuda_vtable = { 0, }; @@ -139,6 +141,7 @@ gst_cuda_load_library (void) /* cudaGL.h */ LOAD_SYMBOL (cuGraphicsGLRegisterImage, CuGraphicsGLRegisterImage); LOAD_SYMBOL (cuGraphicsGLRegisterBuffer, CuGraphicsGLRegisterBuffer); + LOAD_SYMBOL (cuGraphicsResourceSetMapFlags, CuGraphicsResourceSetMapFlags); vtable->loaded = TRUE; @@ -370,3 +373,11 @@ CuGraphicsGLRegisterBuffer (CUgraphicsResource * pCudaResource, return gst_cuda_vtable.CuGraphicsGLRegisterBuffer (pCudaResource, buffer, Flags); } + +CUresult +CuGraphicsResourceSetMapFlags (CUgraphicsResource resource, unsigned int flags) +{ + g_assert (gst_cuda_vtable.CuGraphicsResourceSetMapFlags != NULL); + + return gst_cuda_vtable.CuGraphicsResourceSetMapFlags (resource, flags); +} diff --git a/sys/nvcodec/gstcudaloader.h b/sys/nvcodec/gstcudaloader.h index 62794228ec..1f45831a86 100644 --- a/sys/nvcodec/gstcudaloader.h +++ b/sys/nvcodec/gstcudaloader.h @@ -137,5 +137,9 @@ CUresult CuGraphicsGLRegisterBuffer (CUgraphicsResource * pCudaResource, unsigned int buffer, unsigned int Flags); +G_GNUC_INTERNAL +CUresult CuGraphicsResourceSetMapFlags (CUgraphicsResource resource, + unsigned int flags); + G_END_DECLS #endif /* __GST_CUDA_LOADER_H__ */ diff --git a/sys/nvcodec/gstcudautils.c b/sys/nvcodec/gstcudautils.c index c4c9692d6a..fbf5238a33 100644 --- a/sys/nvcodec/gstcudautils.c +++ b/sys/nvcodec/gstcudautils.c @@ -24,6 +24,11 @@ #include "gstcudautils.h" #include "gstcudacontext.h" +#ifdef HAVE_NVCODEC_GST_GL +#include +#include +#endif + GST_DEBUG_CATEGORY_STATIC (gst_cuda_utils_debug); #define GST_CAT_DEFAULT gst_cuda_utils_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT); @@ -340,3 +345,241 @@ gst_context_new_cuda_context (GstCudaContext * cuda_ctx) return context; } + +static const gchar *gst_cuda_quark_strings[] = + { "GstCudaQuarkGraphicsResource" }; + +static GQuark gst_cuda_quark_table[GST_CUDA_QUARK_MAX]; + +static void +init_cuda_quark_once (void) +{ + static volatile gsize once_init = 0; + + if (g_once_init_enter (&once_init)) { + gint i; + + for (i = 0; i < GST_CUDA_QUARK_MAX; i++) { + gst_cuda_quark_table[i] = + g_quark_from_static_string (gst_cuda_quark_strings[i]); + + g_once_init_leave (&once_init, 1); + } + } +} + +/** + * gst_cuda_quark_from_id: (skip) + * @id: a #GstCudaQuarkId + * + * Returns: the GQuark for given @id or 0 if @id is unknown value + */ +GQuark +gst_cuda_quark_from_id (GstCudaQuarkId id) +{ + g_return_val_if_fail (id < GST_CUDA_QUARK_MAX, 0); + + init_cuda_quark_once (); + _init_debug (); + + return gst_cuda_quark_table[id]; +} + +/** + * gst_cuda_graphics_resource_new: (skip) + * @context: (transfer none): a #GstCudaContext + * @graphics_context: (transfer none) (nullable): a grapics API specific context object + * @type: a #GstCudaGraphicsResourceType of resource registration + * + * Create new #GstCudaGraphicsResource with given @context and @type + * + * Returns: a new #GstCudaGraphicsResource. + * Free with gst_cuda_graphics_resource_free + */ +GstCudaGraphicsResource * +gst_cuda_graphics_resource_new (GstCudaContext * + context, GstObject * graphics_context, GstCudaGraphicsResourceType type) +{ + GstCudaGraphicsResource *resource; + + g_return_val_if_fail (GST_IS_CUDA_CONTEXT (context), NULL); + + _init_debug (); + + resource = g_new0 (GstCudaGraphicsResource, 1); + resource->cuda_context = gst_object_ref (context); + if (graphics_context) + resource->graphics_context = gst_object_ref (graphics_context); + + return resource; +} + +/** + * gst_cuda_graphics_resource_register_gl_buffer: (skip) + * @resource a #GstCudaGraphicsResource + * @buffer: a GL buffer object + * @flags: a #CUgraphicsRegisterFlags + * + * Register the @buffer for access by CUDA. + * Must be called from the gl context thread with current cuda context was + * pushed on the current thread + * + * Returns: whether @buffer was registered or not + */ +gboolean +gst_cuda_graphics_resource_register_gl_buffer (GstCudaGraphicsResource * + resource, guint buffer, CUgraphicsRegisterFlags flags) +{ + CUresult cuda_ret; + + g_return_val_if_fail (resource != NULL, FALSE); + g_return_val_if_fail (resource->registered == FALSE, FALSE); + + _init_debug (); + + cuda_ret = CuGraphicsGLRegisterBuffer (&resource->resource, buffer, flags); + + if (!gst_cuda_result (cuda_ret)) + return FALSE; + + resource->registered = TRUE; + resource->type = GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER; + resource->flags = flags; + + return TRUE; +} + +/** + * gst_cuda_graphics_resource_unregister: (skip) + * @resource: a #GstCudaGraphicsResource + * + * Unregister previously registered resource. + * For GL resource, this method must be called from gl context thread. + * Also, current cuda context should be pushed on the current thread + * before calling this method. + */ +void +gst_cuda_graphics_resource_unregister (GstCudaGraphicsResource * resource) +{ + g_return_if_fail (resource != NULL); + + _init_debug (); + + if (!resource->registered) + return; + + gst_cuda_result (CuGraphicsUnregisterResource (resource->resource)); + resource->resource = NULL; + resource->registered = FALSE; + + return; +} + +/** + * gst_cuda_graphics_resource_map: (skip) + * @resource: a #GstCudaGraphicsResource + * @stream: a #CUstream + * @flags: a #CUgraphicsMapResourceFlags + * + * Map previously registered resource with map flags + * + * Returns: the #CUgraphicsResource if successful or %NULL when failed + */ +CUgraphicsResource +gst_cuda_graphics_resource_map (GstCudaGraphicsResource * resource, + CUstream stream, CUgraphicsMapResourceFlags flags) +{ + CUresult cuda_ret; + + g_return_val_if_fail (resource != NULL, NULL); + g_return_val_if_fail (resource->registered != FALSE, NULL); + + _init_debug (); + + cuda_ret = CuGraphicsResourceSetMapFlags (resource->resource, flags); + if (!gst_cuda_result (cuda_ret)) + return NULL; + + cuda_ret = CuGraphicsMapResources (1, &resource->resource, stream); + if (!gst_cuda_result (cuda_ret)) + return NULL; + + resource->mapped = TRUE; + + return resource->resource; +} + +/** + * gst_cuda_graphics_resource_unmap: (skip) + * @resource: a #GstCudaGraphicsResource + * @stream: a #CUstream + * + * Unmap previously mapped resource + */ +void +gst_cuda_graphics_resource_unmap (GstCudaGraphicsResource * resource, + CUstream stream) +{ + g_return_if_fail (resource != NULL); + g_return_if_fail (resource->registered != FALSE); + + _init_debug (); + + if (!resource->mapped) + return; + + gst_cuda_result (CuGraphicsUnmapResources (1, &resource->resource, stream)); + + resource->mapped = FALSE; +} + +#ifdef HAVE_NVCODEC_GST_GL +static void +unregister_resource_from_gl_thread (GstGLContext * gl_context, + GstCudaGraphicsResource * resource) +{ + GstCudaContext *cuda_context = resource->cuda_context; + + if (!gst_cuda_context_push (cuda_context)) { + GST_WARNING_OBJECT (cuda_context, "failed to push CUDA context"); + return; + } + + gst_cuda_graphics_resource_unregister (resource); + + if (!gst_cuda_context_pop (NULL)) { + GST_WARNING_OBJECT (cuda_context, "failed to pop CUDA context"); + } +} +#endif + +/** + * gst_cuda_graphics_resource_free: (skip) + * @resource: a #GstCudaGraphicsResource + * + * Free @resource + */ +void +gst_cuda_graphics_resource_free (GstCudaGraphicsResource * resource) +{ + g_return_if_fail (resource != NULL); + + if (resource->registered) { +#ifdef HAVE_NVCODEC_GST_GL + if (resource->type == GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER) { + gst_gl_context_thread_add ((GstGLContext *) resource->graphics_context, + (GstGLContextThreadFunc) unregister_resource_from_gl_thread, + resource); + } else +#endif + { + /* FIXME: currently opengl only */ + g_assert_not_reached (); + } + } + + gst_object_unref (resource->cuda_context); + if (resource->graphics_context) + gst_object_unref (resource->graphics_context); + g_free (resource); +} diff --git a/sys/nvcodec/gstcudautils.h b/sys/nvcodec/gstcudautils.h index cdb39d8c1b..e65b1e4a16 100644 --- a/sys/nvcodec/gstcudautils.h +++ b/sys/nvcodec/gstcudautils.h @@ -71,6 +71,34 @@ _gst_cuda_debug(CUresult result, GstDebugCategory * category, _gst_cuda_debug(result, NULL, __FILE__, GST_FUNCTION, __LINE__) #endif +typedef enum +{ + GST_CUDA_QUARK_GRAPHICS_RESOURCE = 0, + + /* end of quark list */ + GST_CUDA_QUARK_MAX = 1 +} GstCudaQuarkId; + +typedef enum +{ + GST_CUDA_GRAPHICS_RESOURCE_NONE = 0, + GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER = 1, +} GstCudaGraphicsResourceType; + +typedef struct _GstCudaGraphicsResource +{ + GstCudaContext *cuda_context; + /* GL context (or d3d11 context in the future) */ + GstObject *graphics_context; + + GstCudaGraphicsResourceType type; + CUgraphicsResource resource; + CUgraphicsRegisterFlags flags; + + gboolean registered; + gboolean mapped; +} GstCudaGraphicsResource; + G_GNUC_INTERNAL gboolean gst_cuda_ensure_element_context (GstElement * element, gint device_id, @@ -90,6 +118,33 @@ gboolean gst_cuda_handle_context_query (GstElement * element, G_GNUC_INTERNAL GstContext * gst_context_new_cuda_context (GstCudaContext * context); +G_GNUC_INTERNAL +GQuark gst_cuda_quark_from_id (GstCudaQuarkId id); + +G_GNUC_INTERNAL +GstCudaGraphicsResource * gst_cuda_graphics_resource_new (GstCudaContext * context, + GstObject * graphics_context, + GstCudaGraphicsResourceType type); + +G_GNUC_INTERNAL +gboolean gst_cuda_graphics_resource_register_gl_buffer (GstCudaGraphicsResource * resource, + guint buffer, + CUgraphicsRegisterFlags flags); + +G_GNUC_INTERNAL +void gst_cuda_graphics_resource_unregister (GstCudaGraphicsResource * resource); + +G_GNUC_INTERNAL +CUgraphicsResource gst_cuda_graphics_resource_map (GstCudaGraphicsResource * resource, + CUstream stream, + CUgraphicsMapResourceFlags flags); + +G_GNUC_INTERNAL +void gst_cuda_graphics_resource_unmap (GstCudaGraphicsResource * resource, + CUstream stream); + +G_GNUC_INTERNAL +void gst_cuda_graphics_resource_free (GstCudaGraphicsResource * resource); G_END_DECLS diff --git a/sys/nvcodec/stub/cuda.h b/sys/nvcodec/stub/cuda.h index 1dff9bb777..2a75c86270 100644 --- a/sys/nvcodec/stub/cuda.h +++ b/sys/nvcodec/stub/cuda.h @@ -52,10 +52,18 @@ typedef enum typedef enum { - CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY = 1, - CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD = 2 + CU_GRAPHICS_REGISTER_FLAGS_NONE = 0x00, + CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY = 0x01, + CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD = 0x02, } CUgraphicsRegisterFlags; +typedef enum +{ + CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE = 0x00, + CU_GRAPHICS_MAP_RESOURCE_FLAGS_READ_ONLY = 0x01, + CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD = 0x02, +} CUgraphicsMapResourceFlags; + typedef enum { CU_STREAM_DEFAULT = 0x0, @@ -92,6 +100,7 @@ typedef struct #define cuCtxPopCurrent cuCtxPopCurrent_v2 #define cuCtxPushCurrent cuCtxPushCurrent_v2 #define cuGraphicsResourceGetMappedPointer cuGraphicsResourceGetMappedPointer_v2 +#define cuGraphicsResourceSetMapFlags cuGraphicsResourceSetMapFlags_v2 #define cuMemAlloc cuMemAlloc_v2 #define cuMemAllocPitch cuMemAllocPitch_v2