Commit e463d0ac authored by Seungha Yang's avatar Seungha Yang 🐑
Browse files

nvenc: Port to GstCudaContext

... and add support CUDA context sharing similar to glcontext sharing.
parent 76406e9f
......@@ -22,6 +22,7 @@
#endif
#include "gstnvbaseenc.h"
#include "gstcudautils.h"
#include <gst/pbutils/codec-utils.h>
......@@ -399,10 +400,9 @@ gst_nv_base_enc_open (GstVideoEncoder * enc)
{
GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
nvenc->cuda_ctx = gst_nvenc_create_cuda_context (nvenc->cuda_device_id);
if (nvenc->cuda_ctx == NULL) {
GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
("Failed to create CUDA context, perhaps CUDA is not supported."));
if (!gst_cuda_ensure_element_context (GST_ELEMENT_CAST (enc),
&nvenc->cuda_ctx, nvenc->cuda_device_id)) {
GST_ERROR_OBJECT (nvenc, "failed to create CUDA context");
return FALSE;
}
......@@ -412,13 +412,12 @@ gst_nv_base_enc_open (GstVideoEncoder * enc)
params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
params.apiVersion = NVENCAPI_VERSION;
params.device = nvenc->cuda_ctx;
params.device = gst_cuda_context_get_context (nvenc->cuda_ctx);
params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
nv_ret = NvEncOpenEncodeSessionEx (&params, &nvenc->encoder);
if (nv_ret != NV_ENC_SUCCESS) {
GST_ERROR ("Failed to create NVENC encoder session, ret=%d", nv_ret);
if (gst_nvenc_destroy_cuda_context (nvenc->cuda_ctx))
nvenc->cuda_ctx = NULL;
gst_clear_object (&nvenc->cuda_ctx);
return FALSE;
}
GST_INFO ("created NVENC encoder %p", nvenc->encoder);
......@@ -437,9 +436,13 @@ gst_nv_base_enc_open (GstVideoEncoder * enc)
static void
gst_nv_base_enc_set_context (GstElement * element, GstContext * context)
{
#if HAVE_NVENC_GST_GL
GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (element);
if (gst_cuda_handle_set_context (element, context,
&nvenc->cuda_ctx, nvenc->cuda_device_id)) {
goto done;
}
#if HAVE_NVENC_GST_GL
gst_gl_handle_set_context (element, context,
(GstGLDisplay **) & nvenc->display,
(GstGLContext **) & nvenc->other_context);
......@@ -448,21 +451,24 @@ gst_nv_base_enc_set_context (GstElement * element, GstContext * context)
SUPPORTED_GL_APIS);
#endif
done:
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
}
static gboolean
gst_nv_base_enc_sink_query (GstVideoEncoder * enc, GstQuery * query)
{
#if HAVE_NVENC_GST_GL
GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
#endif
switch (GST_QUERY_TYPE (query)) {
#if HAVE_NVENC_GST_GL
case GST_QUERY_CONTEXT:{
gboolean ret;
if (gst_cuda_handle_context_query (GST_ELEMENT (nvenc),
query, nvenc->cuda_ctx))
return TRUE;
#if HAVE_NVENC_GST_GL
ret = gst_gl_handle_context_query ((GstElement *) nvenc, query,
nvenc->display, NULL, nvenc->other_context);
if (nvenc->display)
......@@ -471,9 +477,9 @@ gst_nv_base_enc_sink_query (GstVideoEncoder * enc, GstQuery * query)
if (ret)
return ret;
#endif
break;
}
#endif
default:
break;
}
......@@ -629,11 +635,7 @@ gst_nv_base_enc_close (GstVideoEncoder * enc)
nvenc->encoder = NULL;
}
if (nvenc->cuda_ctx) {
if (!gst_nvenc_destroy_cuda_context (nvenc->cuda_ctx))
return FALSE;
nvenc->cuda_ctx = NULL;
}
gst_clear_object (&nvenc->cuda_ctx);
GST_OBJECT_LOCK (nvenc);
if (nvenc->input_formats)
......@@ -974,7 +976,7 @@ gst_nv_base_enc_free_buffers (GstNvBaseEnc * nvenc)
if (nvenc->gl_input) {
struct gl_input_resource *in_gl_resource = nvenc->input_bufs[i];
CuCtxPushCurrent (nvenc->cuda_ctx);
gst_cuda_context_push (nvenc->cuda_ctx);
if (in_gl_resource->mapped) {
GST_LOG_OBJECT (nvenc, "Unmap resource %p", in_gl_resource);
......@@ -1003,7 +1005,7 @@ gst_nv_base_enc_free_buffers (GstNvBaseEnc * nvenc)
}
g_free (in_gl_resource);
CuCtxPopCurrent (NULL);
gst_cuda_context_pop ();
} else
#endif
{
......@@ -1298,7 +1300,7 @@ gst_nv_base_enc_set_format (GstVideoEncoder * enc, GstVideoCodecState * state)
pixel_depth += GST_VIDEO_INFO_COMP_DEPTH (info, i);
}
CuCtxPushCurrent (nvenc->cuda_ctx);
gst_cuda_context_push (nvenc->cuda_ctx);
for (i = 0; i < nvenc->n_bufs; ++i) {
struct gl_input_resource *in_gl_resource =
g_new0 (struct gl_input_resource, 1);
......@@ -1345,7 +1347,7 @@ gst_nv_base_enc_set_format (GstVideoEncoder * enc, GstVideoCodecState * state)
g_async_queue_push (nvenc->in_bufs_pool, nvenc->input_bufs[i]);
}
CuCtxPopCurrent (NULL);
gst_cuda_context_pop ();
} else
#endif
{
......@@ -1494,12 +1496,11 @@ struct map_gl_input
static void
_map_gl_input_buffer (GstGLContext * context, struct map_gl_input *data)
{
cudaError_t cuda_ret;
guint8 *data_pointer;
guint i;
CUDA_MEMCPY2D param;
CuCtxPushCurrent (data->nvenc->cuda_ctx);
gst_cuda_context_push (data->nvenc->cuda_ctx);
data_pointer = data->in_gl_resource->cuda_pointer;
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (data->info); i++) {
guint plane_n_components;
......@@ -1524,30 +1525,28 @@ _map_gl_input_buffer (GstGLContext * context, struct map_gl_input *data)
GST_LOG_OBJECT (data->nvenc, "attempting to copy texture %u into cuda",
gl_mem->mem.tex_id);
cuda_ret =
CuGraphicsGLRegisterBuffer (&data->in_gl_resource->cuda_texture,
gl_buf_obj->id, cudaGraphicsRegisterFlagsReadOnly);
if (cuda_ret != cudaSuccess) {
GST_ERROR_OBJECT (data->nvenc, "failed to register GL texture %u to cuda "
"ret :%d", gl_mem->mem.tex_id, cuda_ret);
if (!gst_cuda_result (CuGraphicsGLRegisterBuffer (&data->
in_gl_resource->cuda_texture, gl_buf_obj->id,
cudaGraphicsRegisterFlagsReadOnly))) {
GST_ERROR_OBJECT (data->nvenc, "failed to register GL texture %u to cuda",
gl_mem->mem.tex_id);
g_assert_not_reached ();
}
cuda_ret =
CuGraphicsMapResources (1, &data->in_gl_resource->cuda_texture, 0);
if (cuda_ret != cudaSuccess) {
GST_ERROR_OBJECT (data->nvenc, "failed to map GL texture %u into cuda "
"ret :%d", gl_mem->mem.tex_id, cuda_ret);
if (!gst_cuda_result (CuGraphicsMapResources (1,
&data->in_gl_resource->cuda_texture, 0))) {
GST_ERROR_OBJECT (data->nvenc, "failed to map GL texture %u into cuda",
gl_mem->mem.tex_id);
g_assert_not_reached ();
}
cuda_ret =
CuGraphicsResourceGetMappedPointer (&data->in_gl_resource->
cuda_plane_pointers[i], &data->in_gl_resource->cuda_num_bytes,
data->in_gl_resource->cuda_texture);
if (cuda_ret != cudaSuccess) {
GST_ERROR_OBJECT (data->nvenc, "failed to get mapped pointer of map GL "
"texture %u in cuda ret :%d", gl_mem->mem.tex_id, cuda_ret);
if (!gst_cuda_result (CuGraphicsResourceGetMappedPointer
(&data->in_gl_resource->cuda_plane_pointers[i],
&data->in_gl_resource->cuda_num_bytes,
data->in_gl_resource->cuda_texture))) {
GST_ERROR_OBJECT (data->nvenc,
"failed to get mapped pointer of map GL texture %u",
gl_mem->mem.tex_id);
g_assert_not_reached ();
}
......@@ -1569,26 +1568,23 @@ _map_gl_input_buffer (GstGLContext * context, struct map_gl_input *data)
param.WidthInBytes = _get_plane_width (data->info, i) * plane_n_components;
param.Height = _get_plane_height (data->info, i);
cuda_ret = CuMemcpy2D (&param);
if (cuda_ret != cudaSuccess) {
GST_ERROR_OBJECT (data->nvenc, "failed to copy GL texture %u into cuda "
"ret :%d", gl_mem->mem.tex_id, cuda_ret);
if (!gst_cuda_result (CuMemcpy2D (&param))) {
GST_ERROR_OBJECT (data->nvenc, "failed to copy GL texture %u into cuda",
gl_mem->mem.tex_id);
g_assert_not_reached ();
}
cuda_ret =
CuGraphicsUnmapResources (1, &data->in_gl_resource->cuda_texture, 0);
if (cuda_ret != cudaSuccess) {
GST_ERROR_OBJECT (data->nvenc, "failed to unmap GL texture %u from cuda "
"ret :%d", gl_mem->mem.tex_id, cuda_ret);
if (!gst_cuda_result (CuGraphicsUnmapResources (1,
&data->in_gl_resource->cuda_texture, 0))) {
GST_ERROR_OBJECT (data->nvenc, "failed to unmap GL texture %u from cuda",
gl_mem->mem.tex_id);
g_assert_not_reached ();
}
cuda_ret =
CuGraphicsUnregisterResource (data->in_gl_resource->cuda_texture);
if (cuda_ret != cudaSuccess) {
GST_ERROR_OBJECT (data->nvenc, "failed to unregister GL texture %u from "
"cuda ret :%d", gl_mem->mem.tex_id, cuda_ret);
if (!gst_cuda_result (CuGraphicsUnregisterResource (data->
in_gl_resource->cuda_texture))) {
GST_ERROR_OBJECT (data->nvenc,
"failed to unregister GL texture %u from cuda", gl_mem->mem.tex_id);
g_assert_not_reached ();
}
......@@ -1597,7 +1593,7 @@ _map_gl_input_buffer (GstGLContext * context, struct map_gl_input *data)
data->in_gl_resource->cuda_stride *
_get_plane_height (&data->nvenc->input_info, i);
}
CuCtxPopCurrent (NULL);
gst_cuda_context_pop ();
}
#endif
......
......@@ -23,6 +23,7 @@
#include "gstnvenc.h"
#include <gst/video/gstvideoencoder.h>
#include "gstcudacontext.h"
#define GST_TYPE_NV_BASE_ENC \
(gst_nv_base_enc_get_type())
......@@ -71,7 +72,7 @@ typedef struct {
guint bitrate;
gint gop_size;
CUcontext cuda_ctx;
GstCudaContext * cuda_ctx;
void * encoder;
/* the supported input formats */
......
......@@ -270,78 +270,6 @@ gst_nvenc_get_nv_buffer_format (GstVideoFormat fmt)
return NV_ENC_BUFFER_FORMAT_UNDEFINED;
}
CUcontext
gst_nvenc_create_cuda_context (guint device_id)
{
CUcontext cuda_ctx, old_ctx;
CUresult cres = CUDA_SUCCESS;
CUdevice cdev = 0, cuda_dev = -1;
int dev_count = 0;
char name[256];
int min = 0, maj = 0;
int i;
GST_INFO ("Initialising CUDA..");
cres = CuInit (0);
if (cres != CUDA_SUCCESS) {
GST_WARNING ("Failed to initialise CUDA, error code: 0x%08x", cres);
return NULL;
}
GST_INFO ("Initialised CUDA");
cres = CuDeviceGetCount (&dev_count);
if (cres != CUDA_SUCCESS || dev_count == 0) {
GST_WARNING ("No CUDA devices detected");
return NULL;
}
GST_INFO ("%d CUDA device(s) detected", dev_count);
for (i = 0; i < dev_count; ++i) {
if (CuDeviceGet (&cdev, i) == CUDA_SUCCESS
&& CuDeviceGetName (name, sizeof (name), cdev) == CUDA_SUCCESS
&& CuDeviceGetAttribute (&maj,
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cdev) == CUDA_SUCCESS
&& CuDeviceGetAttribute (&min,
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR,
cdev) == CUDA_SUCCESS) {
GST_INFO ("GPU #%d supports NVENC: %s (%s) (Compute SM %d.%d)", i,
(((maj << 4) + min) >= 0x30) ? "yes" : "no", name, maj, min);
if (i == device_id) {
cuda_dev = cdev;
}
}
}
if (cuda_dev == -1) {
GST_WARNING ("Device with id %d does not exist or does not support NVENC",
device_id);
return NULL;
}
if (CuCtxCreate (&cuda_ctx, 0, cuda_dev) != CUDA_SUCCESS) {
GST_WARNING ("Failed to create CUDA context for cuda device %d", cuda_dev);
return NULL;
}
if (CuCtxPopCurrent (&old_ctx) != CUDA_SUCCESS) {
return NULL;
}
GST_INFO ("Created CUDA context %p", cuda_ctx);
return cuda_ctx;
}
gboolean
gst_nvenc_destroy_cuda_context (CUcontext ctx)
{
GST_INFO ("Destroying CUDA context %p", ctx);
return (CuCtxDestroy (ctx) == CUDA_SUCCESS);
}
static gboolean
load_nvenc_library (void)
{
......
......@@ -28,10 +28,6 @@
GST_DEBUG_CATEGORY_EXTERN (gst_nvenc_debug);
CUcontext gst_nvenc_create_cuda_context (guint device_id);
gboolean gst_nvenc_destroy_cuda_context (CUcontext ctx);
gboolean gst_nvenc_cmp_guid (GUID g1, GUID g2);
NV_ENC_BUFFER_FORMAT gst_nvenc_get_nv_buffer_format (GstVideoFormat fmt);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment