0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 04:42:18 +02:00
obs-studio/plugins/obs-nvenc/cuda-helpers.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

173 lines
4.3 KiB
C
Raw Permalink Normal View History

2024-03-11 10:00:17 +01:00
#include "obs-nvenc.h"
#include "nvenc-internal.h"
#include "cuda-helpers.h"
#include <util/platform.h>
#include <util/threading.h>
#include <util/config-file.h>
#include <util/dstr.h>
#include <util/pipe.h>
static void *cuda_lib = NULL;
static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
CudaFunctions *cu = NULL;
bool load_cuda_lib(void)
{
#ifdef _WIN32
cuda_lib = os_dlopen("nvcuda.dll");
#else
cuda_lib = os_dlopen("libcuda.so.1");
#endif
return cuda_lib != NULL;
}
static void *load_cuda_func(const char *func)
{
void *func_ptr = os_dlsym(cuda_lib, func);
if (!func_ptr) {
blog(LOG_ERROR, "[obs-nvenc] Could not load function: %s",
func);
}
return func_ptr;
}
typedef struct cuda_function {
ptrdiff_t offset;
const char *name;
} cuda_function;
static const cuda_function cuda_functions[] = {
{offsetof(CudaFunctions, cuInit), "cuInit"},
{offsetof(CudaFunctions, cuDeviceGetCount), "cuDeviceGetCount"},
{offsetof(CudaFunctions, cuDeviceGet), "cuDeviceGet"},
{offsetof(CudaFunctions, cuDeviceGetAttribute), "cuDeviceGetAttribute"},
{offsetof(CudaFunctions, cuCtxCreate), "cuCtxCreate_v2"},
{offsetof(CudaFunctions, cuCtxDestroy), "cuCtxDestroy_v2"},
{offsetof(CudaFunctions, cuCtxPushCurrent), "cuCtxPushCurrent_v2"},
{offsetof(CudaFunctions, cuCtxPopCurrent), "cuCtxPopCurrent_v2"},
{offsetof(CudaFunctions, cuArray3DCreate), "cuArray3DCreate_v2"},
{offsetof(CudaFunctions, cuArrayDestroy), "cuArrayDestroy"},
{offsetof(CudaFunctions, cuMemcpy2D), "cuMemcpy2D_v2"},
{offsetof(CudaFunctions, cuGetErrorName), "cuGetErrorName"},
{offsetof(CudaFunctions, cuGetErrorString), "cuGetErrorString"},
{offsetof(CudaFunctions, cuMemHostRegister), "cuMemHostRegister_v2"},
{offsetof(CudaFunctions, cuMemHostUnregister), "cuMemHostUnregister"},
#ifndef _WIN32
{offsetof(CudaFunctions, cuGLGetDevices), "cuGLGetDevices_v2"},
{offsetof(CudaFunctions, cuGraphicsGLRegisterImage),
"cuGraphicsGLRegisterImage"},
{offsetof(CudaFunctions, cuGraphicsUnregisterResource),
"cuGraphicsUnregisterResource"},
{offsetof(CudaFunctions, cuGraphicsMapResources),
"cuGraphicsMapResources"},
{offsetof(CudaFunctions, cuGraphicsUnmapResources),
"cuGraphicsUnmapResources"},
{offsetof(CudaFunctions, cuGraphicsSubResourceGetMappedArray),
"cuGraphicsSubResourceGetMappedArray"},
#endif
};
static const size_t num_cuda_funcs =
sizeof(cuda_functions) / sizeof(cuda_function);
static bool init_cuda_internal(obs_encoder_t *encoder)
{
static bool initialized = false;
static bool success = false;
if (initialized)
return success;
initialized = true;
if (!load_cuda_lib()) {
obs_encoder_set_last_error(encoder,
"Loading CUDA library failed.");
return false;
}
cu = bzalloc(sizeof(CudaFunctions));
for (size_t idx = 0; idx < num_cuda_funcs; idx++) {
const cuda_function func = cuda_functions[idx];
void *fptr = load_cuda_func(func.name);
if (!fptr) {
blog(LOG_ERROR,
"[obs-nvenc] Failed to find CUDA function: %s",
func.name);
obs_encoder_set_last_error(
encoder, "Loading CUDA functions failed.");
return false;
}
*(uintptr_t *)((uintptr_t)cu + func.offset) = (uintptr_t)fptr;
}
success = true;
return true;
}
bool cuda_get_error_desc(CUresult res, const char **name, const char **desc)
{
if (cu->cuGetErrorName(res, name) != CUDA_SUCCESS ||
cu->cuGetErrorString(res, desc) != CUDA_SUCCESS)
return false;
return true;
}
bool cuda_error_check(struct nvenc_data *enc, CUresult res, const char *func,
const char *call)
{
if (res == CUDA_SUCCESS)
return true;
struct dstr message = {0};
const char *name, *desc;
if (cuda_get_error_desc(res, &name, &desc)) {
dstr_printf(&message,
"%s: CUDA call \"%s\" failed with %s (%d): %s",
func, call, name, res, desc);
} else {
dstr_printf(&message, "%s: CUDA call \"%s\" failed with %d",
func, call, res);
}
error("%s", message.array);
obs_encoder_set_last_error(enc->encoder, message.array);
dstr_free(&message);
return false;
}
bool init_cuda(obs_encoder_t *encoder)
{
bool success;
pthread_mutex_lock(&init_mutex);
success = init_cuda_internal(encoder);
pthread_mutex_unlock(&init_mutex);
return success;
}
void obs_cuda_load(void)
{
pthread_mutex_init(&init_mutex, NULL);
}
void obs_cuda_unload(void)
{
bfree(cu);
pthread_mutex_destroy(&init_mutex);
}