cudautils: Add GstCudaGraphicsResource structure for better openGL interoperability

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.
This commit is contained in:
Seungha Yang 2019-08-17 17:45:44 +09:00
parent 8dc2b4a393
commit da075b94a9
5 changed files with 324 additions and 2 deletions

View 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);
}

View 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__ */

View file

@ -24,6 +24,11 @@
#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);
}

View 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

View 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