obs-StreamFX/source/nvidia/vfx/nvidia-vfx.cpp
Michael Fabian 'Xaymar' Dirks 5a3954ae0e project: Fix License, License headers and Copyright information
Fixes several files incorrectly stated a different license from the actual project, as well as the copyright headers included in all files. This change has no effect on the licensing terms, it should clear up a bit of confusion by contributors. Plus the files get a bit smaller, and we have less duplicated information across the entire project.

Overall the project is GPLv2 if not built with Qt, and GPLv3 if it is built with Qt. There are no parts licensed under a different license, all have been adapted from other compatible licenses into GPLv2 or GPLv3.
2023-04-05 18:59:08 +02:00

215 lines
6.8 KiB
C++

// AUTOGENERATED COPYRIGHT HEADER START
// Copyright (C) 2021-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
// AUTOGENERATED COPYRIGHT HEADER END
#include "nvidia-vfx.hpp"
#include "nvidia/cuda/nvidia-cuda-obs.hpp"
#include "obs/gs/gs-helper.hpp"
#include "util/util-logging.hpp"
#include "util/util-platform.hpp"
#include "warning-disable.hpp"
#include <filesystem>
#include <mutex>
#include "warning-enable.hpp"
#ifdef _DEBUG
#define ST_PREFIX "<%s> "
#define D_LOG_ERROR(x, ...) P_LOG_ERROR(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
#define D_LOG_WARNING(x, ...) P_LOG_WARN(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
#define D_LOG_INFO(x, ...) P_LOG_INFO(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
#define D_LOG_DEBUG(x, ...) P_LOG_DEBUG(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
#else
#define ST_PREFIX "<nvidia::vfx::vfx> "
#define D_LOG_ERROR(...) P_LOG_ERROR(ST_PREFIX __VA_ARGS__)
#define D_LOG_WARNING(...) P_LOG_WARN(ST_PREFIX __VA_ARGS__)
#define D_LOG_INFO(...) P_LOG_INFO(ST_PREFIX __VA_ARGS__)
#define D_LOG_DEBUG(...) P_LOG_DEBUG(ST_PREFIX __VA_ARGS__)
#endif
#if defined(WIN32)
#include "warning-disable.hpp"
#include <KnownFolders.h>
#include <ShlObj.h>
#include <Windows.h>
#include "warning-enable.hpp"
#define LIB_NAME "NVVideoEffects.dll"
#else
#define LIB_NAME "libNVVideoEffects.so"
#endif
#define ST_ENV_NVIDIA_VIDEO_EFFECTS_SDK_PATH L"NV_VIDEO_EFFECTS_PATH"
#define NVVFX_LOAD_SYMBOL(NAME) \
{ \
NAME = reinterpret_cast<decltype(NAME)>(_library->load_symbol(#NAME)); \
if (!NAME) \
throw std::runtime_error("Failed to load '" #NAME "' from '" LIB_NAME "'."); \
}
streamfx::nvidia::vfx::vfx::~vfx()
{
D_LOG_DEBUG("Finalizing... (Addr: 0x%" PRIuPTR ")", this);
#ifdef WIN32
// Remove the DLL directory from the library loader paths.
if (_extra != nullptr) {
RemoveDllDirectory(reinterpret_cast<DLL_DIRECTORY_COOKIE>(_extra));
}
#endif
{ // The library may need to release Graphics and CUDA resources.
auto gctx = ::streamfx::obs::gs::context();
auto cctx = ::streamfx::nvidia::cuda::obs::get()->get_context()->enter();
_library.reset();
}
}
streamfx::nvidia::vfx::vfx::vfx()
{
std::filesystem::path sdk_path;
auto gctx = ::streamfx::obs::gs::context();
auto cctx = ::streamfx::nvidia::cuda::obs::get()->get_context()->enter();
D_LOG_DEBUG("Initializing... (Addr: 0x%" PRIuPTR ")", this);
// Figure out the location of the Video Effects SDK, if it is installed.
#ifdef WIN32
{
DWORD env_size;
std::vector<wchar_t> buffer;
env_size = GetEnvironmentVariableW(ST_ENV_NVIDIA_VIDEO_EFFECTS_SDK_PATH, nullptr, 0);
if (env_size > 0) {
buffer.resize(static_cast<size_t>(env_size) + 1);
env_size = GetEnvironmentVariableW(ST_ENV_NVIDIA_VIDEO_EFFECTS_SDK_PATH, buffer.data(),
static_cast<DWORD>(buffer.size()));
sdk_path = std::wstring(buffer.data(), buffer.size());
} else {
PWSTR str = nullptr;
HRESULT res = SHGetKnownFolderPath(FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, nullptr, &str);
if (res == S_OK) {
sdk_path = std::wstring(str);
CoTaskMemFree(str);
sdk_path /= "NVIDIA Corporation";
sdk_path /= "NVIDIA Video Effects";
}
}
}
#else
throw std::runtime_error("Not yet implemented.");
#endif
// Check if any of the found paths are valid.
if (!std::filesystem::exists(sdk_path)) {
D_LOG_ERROR("No supported NVIDIA SDK is installed to provide '%s'.", LIB_NAME);
throw std::runtime_error("Failed to load '" LIB_NAME "'.");
}
// Try and load the library.
{
#ifdef WIN32
// On platforms where it is possible, modify the linker directories.
DLL_DIRECTORY_COOKIE ck = AddDllDirectory(sdk_path.wstring().c_str());
_extra = reinterpret_cast<void*>(ck);
if (ck == 0) {
DWORD ec = GetLastError();
std::string error;
{
LPWSTR str;
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, ec, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
reinterpret_cast<LPWSTR>(&str), 0, nullptr);
error = ::streamfx::util::platform::native_to_utf8(std::wstring(str));
LocalFree(str);
}
D_LOG_WARNING("Failed to add '%'s to the library loader paths with error: %s (Code %" PRIu32 ")",
sdk_path.string().c_str(), error.c_str(), ec);
}
#endif
std::filesystem::path paths[] = {
LIB_NAME,
util::platform::native_to_utf8(std::filesystem::path(sdk_path) / LIB_NAME),
};
for (auto path : paths) {
try {
_library = ::streamfx::util::library::load(path);
} catch (std::exception const& ex) {
D_LOG_ERROR("Failed to load '%s' with error: %s", path.string().c_str(), ex.what());
} catch (...) {
D_LOG_ERROR("Failed to load '%s'.", path.string().c_str());
}
if (_library) {
break;
}
}
if (!_library) {
#ifdef WIN32
// Remove the DLL directory from the library loader paths.
if (_extra != nullptr) {
RemoveDllDirectory(reinterpret_cast<DLL_DIRECTORY_COOKIE>(_extra));
}
#endif
throw std::runtime_error("Failed to load " LIB_NAME ".");
}
}
// Store the model path for later use.
_model_path = std::filesystem::path(sdk_path) / "models";
{ // Load Symbols
NVVFX_LOAD_SYMBOL(NvVFX_GetVersion);
NVVFX_LOAD_SYMBOL(NvVFX_CreateEffect);
NVVFX_LOAD_SYMBOL(NvVFX_DestroyEffect);
NVVFX_LOAD_SYMBOL(NvVFX_SetU32);
NVVFX_LOAD_SYMBOL(NvVFX_SetS32);
NVVFX_LOAD_SYMBOL(NvVFX_SetF32);
NVVFX_LOAD_SYMBOL(NvVFX_SetF64);
NVVFX_LOAD_SYMBOL(NvVFX_SetU64);
NVVFX_LOAD_SYMBOL(NvVFX_SetImage);
NVVFX_LOAD_SYMBOL(NvVFX_SetObject);
NVVFX_LOAD_SYMBOL(NvVFX_SetString);
NVVFX_LOAD_SYMBOL(NvVFX_SetCudaStream);
NVVFX_LOAD_SYMBOL(NvVFX_GetU32);
NVVFX_LOAD_SYMBOL(NvVFX_GetS32);
NVVFX_LOAD_SYMBOL(NvVFX_GetF32);
NVVFX_LOAD_SYMBOL(NvVFX_GetF64);
NVVFX_LOAD_SYMBOL(NvVFX_GetU64);
NVVFX_LOAD_SYMBOL(NvVFX_GetImage);
NVVFX_LOAD_SYMBOL(NvVFX_GetObject);
NVVFX_LOAD_SYMBOL(NvVFX_GetString);
NVVFX_LOAD_SYMBOL(NvVFX_GetCudaStream);
NVVFX_LOAD_SYMBOL(NvVFX_Run);
NVVFX_LOAD_SYMBOL(NvVFX_Load);
}
{ // Assign proper GPU.
auto cctx = ::streamfx::nvidia::cuda::obs::get()->get_context()->enter();
NvVFX_SetU32(nullptr, PARAMETER_GPU, 0);
}
}
std::shared_ptr<::streamfx::nvidia::vfx::vfx> streamfx::nvidia::vfx::vfx::get()
{
static std::weak_ptr<streamfx::nvidia::vfx::vfx> instance;
static std::mutex lock;
std::unique_lock<std::mutex> ul(lock);
if (instance.expired()) {
auto hard_instance = std::make_shared<streamfx::nvidia::vfx::vfx>();
instance = hard_instance;
return hard_instance;
}
return instance.lock();
}
std::filesystem::path const& streamfx::nvidia::vfx::vfx::model_path()
{
return _model_path;
}