cudautils: Add GstCudaGraphicsResource structure for better openGL interoperability
authorSeungha Yang <seungha.yang@navercorp.com>
Sat, 17 Aug 2019 08:45:44 +0000 (17:45 +0900)
committerSeungha Yang <seungha.yang@navercorp.com>
Thu, 29 Aug 2019 09:04:33 +0000 (18:04 +0900)
Introduce GstCudaGraphicsResource structure to represent registered
CUDA graphics resources and to enable sharing the information among
nvdec and nvenc. This structure can reduce the number of resource
registration which cause high overhead.

sys/nvcodec/gstcudaloader.c
sys/nvcodec/gstcudaloader.h
sys/nvcodec/gstcudautils.c
sys/nvcodec/gstcudautils.h
sys/nvcodec/stub/cuda.h

index de9547f646387fb181859d47a3a69c1d469a5241..2cd7ab23d5cc3a547fbf63d65e91712f183f9081 100644 (file)
@@ -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);
+}
index 62794228ec9ecacd28c51c9c6dceb8523c4bf9f8..1f45831a86938eb123a83a4b2972e27786a2756b 100644 (file)
@@ -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__ */
index c4c9692d6aeb1f2af77dc5642bd79e1c674ece54..fbf5238a3341f30f272237f65054806accb41052 100644 (file)
 #include "gstcudautils.h"
 #include "gstcudacontext.h"
 
+#ifdef HAVE_NVCODEC_GST_GL
+#include <gst/gl/gl.h>
+#include <gst/gl/gstglfuncs.h>
+#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);
+}
index cdb39d8c1b1d7ea29d00204bad3fea4321d4bade..e65b1e4a1615db43136f292457af1751887efaa6 100644 (file)
@@ -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
 
index 1dff9bb7774b516f8787f833df9e826f549c304f..2a75c86270c9f8c7b3236f6b34c8e21e8a8ddf39 100644 (file)
@@ -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