From 19d3d0c0570981ddc8a224f07d734ff75d76e234 Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Sat, 10 Nov 2018 22:47:28 -0800 Subject: avutil/hwcontext_cuda: Define and use common CHECK_CU() We have a pattern of wrapping CUDA calls to print errors and normalise return values that is used in a couple of places. To avoid duplication and increase consistency, let's put the wrapper implementation in a shared place and use it everywhere. Affects: * avcodec/cuviddec * avcodec/nvdec * avcodec/nvenc * avfilter/vf_scale_cuda * avfilter/vf_scale_npp * avfilter/vf_thumbnail_cuda * avfilter/vf_transpose_npp * avfilter/vf_yadif_cuda --- libavutil/Makefile | 5 +- libavutil/cuda_check.c | 45 ++++++++++++++ libavutil/cuda_check.h | 43 +++++++++++++ libavutil/hwcontext_cuda.c | 148 +++++++++++++++++++++------------------------ 4 files changed, 161 insertions(+), 80 deletions(-) create mode 100644 libavutil/cuda_check.c create mode 100644 libavutil/cuda_check.h (limited to 'libavutil') diff --git a/libavutil/Makefile b/libavutil/Makefile index 9ed24cfc82..b772111695 100644 --- a/libavutil/Makefile +++ b/libavutil/Makefile @@ -157,7 +157,7 @@ OBJS = adler32.o \ xtea.o \ tea.o \ -OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o +OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o cuda_check.o OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o OBJS-$(CONFIG_LIBDRM) += hwcontext_drm.o @@ -175,7 +175,8 @@ OBJS += $(COMPAT_OBJS:%=../compat/%) SLIBOBJS-$(HAVE_GNU_WINDRES) += avutilres.o SKIPHEADERS-$(HAVE_CUDA_H) += hwcontext_cuda.h -SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h +SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h \ + cuda_check.h SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h diff --git a/libavutil/cuda_check.c b/libavutil/cuda_check.c new file mode 100644 index 0000000000..95c0256d12 --- /dev/null +++ b/libavutil/cuda_check.c @@ -0,0 +1,45 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "compat/cuda/dynlink_loader.h" +#include "libavutil/cuda_check.h" + +int ff_cuda_check(void *avctx, + void *cuGetErrorName_fn, + void *cuGetErrorString_fn, + CUresult err, const char *func) +{ + const char *err_name; + const char *err_string; + + av_log(avctx, AV_LOG_TRACE, "Calling %s\n", func); + + if (err == CUDA_SUCCESS) + return 0; + + ((tcuGetErrorName *)cuGetErrorName_fn)(err, &err_name); + ((tcuGetErrorString *)cuGetErrorString_fn)(err, &err_string); + + av_log(avctx, AV_LOG_ERROR, "%s failed", func); + if (err_name && err_string) + av_log(avctx, AV_LOG_ERROR, " -> %s: %s", err_name, err_string); + av_log(avctx, AV_LOG_ERROR, "\n"); + + return AVERROR_EXTERNAL; +} + diff --git a/libavutil/cuda_check.h b/libavutil/cuda_check.h new file mode 100644 index 0000000000..0d45538c2f --- /dev/null +++ b/libavutil/cuda_check.h @@ -0,0 +1,43 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef FF_CUDA_CHECK_H +#define FF_CUDA_CHECK_H + +/** + * Wrap a CUDA function call and print error information if it fails. + */ + +int ff_cuda_check(void *avctx, + void *cuGetErrorName_fn, void *cuGetErrorString_fn, + CUresult err, const char *func); + +/** + * Convenience wrapper for ff_cuda_check when directly linking libcuda. + */ + +#define FF_CUDA_CHECK(avclass, x) ff_cuda_check(avclass, cuGetErrorName, cuGetErrorString, (x), #x) + +/** + * Convenience wrapper for ff_cuda_check when dynamically loading cuda symbols. + */ + +#define FF_CUDA_CHECK_DL(avclass, cudl, x) ff_cuda_check(avclass, cudl->cuGetErrorName, cudl->cuGetErrorString, (x), #x) + +#endif /* FF_CUDA_CHECK_H */ diff --git a/libavutil/hwcontext_cuda.c b/libavutil/hwcontext_cuda.c index 3b1d53e799..540a7610ef 100644 --- a/libavutil/hwcontext_cuda.c +++ b/libavutil/hwcontext_cuda.c @@ -21,6 +21,7 @@ #include "hwcontext.h" #include "hwcontext_internal.h" #include "hwcontext_cuda_internal.h" +#include "cuda_check.h" #include "mem.h" #include "pixdesc.h" #include "pixfmt.h" @@ -43,6 +44,8 @@ static const enum AVPixelFormat supported_formats[] = { AV_PIX_FMT_0BGR32, }; +#define CHECK_CU(x) FF_CUDA_CHECK_DL(device_ctx, cu, x) + static int cuda_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints) @@ -70,48 +73,48 @@ static int cuda_frames_get_constraints(AVHWDeviceContext *ctx, static void cuda_buffer_free(void *opaque, uint8_t *data) { - AVHWFramesContext *ctx = opaque; - AVCUDADeviceContext *hwctx = ctx->device_ctx->hwctx; - CudaFunctions *cu = hwctx->internal->cuda_dl; + AVHWFramesContext *ctx = opaque; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; CUcontext dummy; - cu->cuCtxPushCurrent(hwctx->cuda_ctx); + CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); - cu->cuMemFree((CUdeviceptr)data); + CHECK_CU(cu->cuMemFree((CUdeviceptr)data)); - cu->cuCtxPopCurrent(&dummy); + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); } static AVBufferRef *cuda_pool_alloc(void *opaque, int size) { - AVHWFramesContext *ctx = opaque; - AVCUDADeviceContext *hwctx = ctx->device_ctx->hwctx; - CudaFunctions *cu = hwctx->internal->cuda_dl; + AVHWFramesContext *ctx = opaque; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; AVBufferRef *ret = NULL; CUcontext dummy = NULL; CUdeviceptr data; - CUresult err; + int err; - err = cu->cuCtxPushCurrent(hwctx->cuda_ctx); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error setting current CUDA context\n"); + err = CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); + if (err < 0) return NULL; - } - err = cu->cuMemAlloc(&data, size); - if (err != CUDA_SUCCESS) + err = CHECK_CU(cu->cuMemAlloc(&data, size)); + if (err < 0) goto fail; ret = av_buffer_create((uint8_t*)data, size, cuda_buffer_free, ctx, 0); if (!ret) { - cu->cuMemFree(data); + CHECK_CU(cu->cuMemFree(data)); goto fail; } fail: - cu->cuCtxPopCurrent(&dummy); + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); return ret; } @@ -194,17 +197,17 @@ static int cuda_transfer_get_formats(AVHWFramesContext *ctx, static int cuda_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src) { - CUDAFramesContext *priv = ctx->internal->priv; - AVCUDADeviceContext *device_hwctx = ctx->device_ctx->hwctx; - CudaFunctions *cu = device_hwctx->internal->cuda_dl; + CUDAFramesContext *priv = ctx->internal->priv; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; CUcontext dummy; - CUresult err; - int i; + int i, ret; - err = cu->cuCtxPushCurrent(device_hwctx->cuda_ctx); - if (err != CUDA_SUCCESS) - return AVERROR_UNKNOWN; + ret = CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); + if (ret < 0) + return ret; for (i = 0; i < FF_ARRAY_ELEMS(src->data) && src->data[i]; i++) { CUDA_MEMCPY2D cpy = { @@ -218,20 +221,17 @@ static int cuda_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, .Height = src->height >> (i ? priv->shift_height : 0), }; - err = cu->cuMemcpy2DAsync(&cpy, device_hwctx->stream); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error transferring the data from the CUDA frame\n"); - return AVERROR_UNKNOWN; - } + ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, hwctx->stream)); + if (ret < 0) + goto exit; } - err = cu->cuStreamSynchronize(device_hwctx->stream); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error synchronizing CUDA stream\n"); - return AVERROR_UNKNOWN; - } + ret = CHECK_CU(cu->cuStreamSynchronize(hwctx->stream)); + if (ret < 0) + goto exit; - cu->cuCtxPopCurrent(&dummy); +exit: + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); return 0; } @@ -239,17 +239,17 @@ static int cuda_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, static int cuda_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src) { - CUDAFramesContext *priv = ctx->internal->priv; - AVCUDADeviceContext *device_hwctx = ctx->device_ctx->hwctx; - CudaFunctions *cu = device_hwctx->internal->cuda_dl; + CUDAFramesContext *priv = ctx->internal->priv; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; CUcontext dummy; - CUresult err; - int i; + int i, ret; - err = cu->cuCtxPushCurrent(device_hwctx->cuda_ctx); - if (err != CUDA_SUCCESS) - return AVERROR_UNKNOWN; + ret = CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); + if (ret < 0) + return ret; for (i = 0; i < FF_ARRAY_ELEMS(src->data) && src->data[i]; i++) { CUDA_MEMCPY2D cpy = { @@ -263,31 +263,29 @@ static int cuda_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, .Height = src->height >> (i ? priv->shift_height : 0), }; - err = cu->cuMemcpy2DAsync(&cpy, device_hwctx->stream); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error transferring the data to the CUDA frame\n"); - return AVERROR_UNKNOWN; - } + ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, hwctx->stream)); + if (ret < 0) + goto exit; } - err = cu->cuStreamSynchronize(device_hwctx->stream); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error synchronizing CUDA stream\n"); - return AVERROR_UNKNOWN; - } + ret = CHECK_CU(cu->cuStreamSynchronize(hwctx->stream)); + if (ret < 0) + goto exit; - cu->cuCtxPopCurrent(&dummy); +exit: + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); return 0; } -static void cuda_device_uninit(AVHWDeviceContext *ctx) +static void cuda_device_uninit(AVHWDeviceContext *device_ctx) { - AVCUDADeviceContext *hwctx = ctx->hwctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; if (hwctx->internal) { + CudaFunctions *cu = hwctx->internal->cuda_dl; if (hwctx->internal->is_allocated && hwctx->cuda_ctx) { - hwctx->internal->cuda_dl->cuCtxDestroy(hwctx->cuda_ctx); + CHECK_CU(cu->cuCtxDestroy(hwctx->cuda_ctx)); hwctx->cuda_ctx = NULL; } cuda_free_functions(&hwctx->internal->cuda_dl); @@ -322,53 +320,47 @@ error: return ret; } -static int cuda_device_create(AVHWDeviceContext *ctx, const char *device, +static int cuda_device_create(AVHWDeviceContext *device_ctx, + const char *device, AVDictionary *opts, int flags) { - AVCUDADeviceContext *hwctx = ctx->hwctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; CudaFunctions *cu; CUdevice cu_device; CUcontext dummy; - CUresult err; - int device_idx = 0; + int ret, device_idx = 0; if (device) device_idx = strtol(device, NULL, 0); - if (cuda_device_init(ctx) < 0) + if (cuda_device_init(device_ctx) < 0) goto error; cu = hwctx->internal->cuda_dl; - err = cu->cuInit(0); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Could not initialize the CUDA driver API\n"); + ret = CHECK_CU(cu->cuInit(0)); + if (ret < 0) goto error; - } - err = cu->cuDeviceGet(&cu_device, device_idx); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Could not get the device number %d\n", device_idx); + ret = CHECK_CU(cu->cuDeviceGet(&cu_device, device_idx)); + if (ret < 0) goto error; - } - err = cu->cuCtxCreate(&hwctx->cuda_ctx, CU_CTX_SCHED_BLOCKING_SYNC, cu_device); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error creating a CUDA context\n"); + ret = CHECK_CU(cu->cuCtxCreate(&hwctx->cuda_ctx, CU_CTX_SCHED_BLOCKING_SYNC, cu_device)); + if (ret < 0) goto error; - } // Setting stream to NULL will make functions automatically use the default CUstream hwctx->stream = NULL; - cu->cuCtxPopCurrent(&dummy); + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); hwctx->internal->is_allocated = 1; return 0; error: - cuda_device_uninit(ctx); + cuda_device_uninit(device_ctx); return AVERROR_UNKNOWN; } -- cgit v1.2.3