mirror of
https://github.com/LizardByte/Sunshine.git
synced 2026-08-07 10:20:46 +00:00
213 lines
6.0 KiB
C++
213 lines
6.0 KiB
C++
/**
|
|
* @file tests/unit/test_nvenc_dynamic_factory.cpp
|
|
* @brief Tests for the Windows runtime NVENC SDK factory.
|
|
*/
|
|
#ifdef _WIN32
|
|
|
|
// standard includes
|
|
#include <array>
|
|
#include <bit>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <string_view>
|
|
#include <utility>
|
|
|
|
// lib includes
|
|
#include <gtest/gtest.h>
|
|
|
|
// local includes
|
|
#include "src/nvenc/nvenc_dynamic_factory.h"
|
|
|
|
namespace {
|
|
|
|
std::uint32_t reported_version; ///< Version returned by the fake NVENC driver.
|
|
std::uint32_t reported_status; ///< Status returned by the fake NVENC driver.
|
|
|
|
/**
|
|
* @brief Fake implementation of `NvEncodeAPIGetMaxSupportedVersion()`.
|
|
*
|
|
* @param version Receives the configured packed API version.
|
|
* @return Configured NVENC status code.
|
|
*/
|
|
std::uint32_t WINAPI get_fake_max_supported_version(std::uint32_t *version) {
|
|
*version = reported_version;
|
|
return reported_status;
|
|
}
|
|
|
|
/**
|
|
* @brief Minimal SDK-neutral encoder used to verify factory callbacks.
|
|
*/
|
|
class fake_nvenc_encoder final: public nvenc::nvenc_d3d11_interface {
|
|
public:
|
|
bool create_encoder(
|
|
const nvenc::nvenc_config &,
|
|
const video::config_t &,
|
|
const video::sunshine_colorspace_t &,
|
|
platf::pix_fmt_e
|
|
) override {
|
|
return true;
|
|
}
|
|
|
|
void destroy_encoder() override {
|
|
}
|
|
|
|
nvenc::nvenc_encoded_frame encode_frame(std::uint64_t frame_index, bool force_idr) override {
|
|
return {{}, frame_index, force_idr, false};
|
|
}
|
|
|
|
bool invalidate_ref_frames(std::uint64_t, std::uint64_t) override {
|
|
return true;
|
|
}
|
|
|
|
ID3D11Texture2D *get_input_texture() override {
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Make a non-owning fake Windows module handle for factory discovery tests.
|
|
*
|
|
* @return Shared fake module handle.
|
|
*/
|
|
nvenc::shared_dll make_fake_dll() {
|
|
constexpr std::uintptr_t fake_handle_value = 1U;
|
|
return {
|
|
reinterpret_cast<HMODULE>(fake_handle_value),
|
|
[](HMODULE) {
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @brief Make runtime operations that expose the fake version query function.
|
|
*
|
|
* @return Runtime operations for a successfully loaded fake NVENC driver.
|
|
*/
|
|
nvenc::nvenc_runtime_api make_fake_runtime_api() {
|
|
return {
|
|
[]() {
|
|
return make_fake_dll();
|
|
},
|
|
[](HMODULE dll, const char *symbol) {
|
|
EXPECT_EQ(dll, make_fake_dll().get());
|
|
EXPECT_EQ(std::string_view {symbol}, "NvEncodeAPIGetMaxSupportedVersion");
|
|
return std::bit_cast<FARPROC>(&get_fake_max_supported_version);
|
|
},
|
|
};
|
|
}
|
|
|
|
TEST(NvencDynamicFactoryTest, HandlesUnavailableDriver) {
|
|
bool resolved_symbol = false;
|
|
const nvenc::nvenc_runtime_api runtime_api {
|
|
[]() {
|
|
return nvenc::shared_dll {};
|
|
},
|
|
[&resolved_symbol](HMODULE, const char *) {
|
|
resolved_symbol = true;
|
|
return FARPROC {};
|
|
},
|
|
};
|
|
|
|
EXPECT_FALSE(nvenc::nvenc_dynamic_factory::get(runtime_api));
|
|
EXPECT_FALSE(resolved_symbol);
|
|
}
|
|
|
|
TEST(NvencDynamicFactoryTest, HandlesMissingVersionQuery) {
|
|
const nvenc::nvenc_runtime_api runtime_api {
|
|
[]() {
|
|
return make_fake_dll();
|
|
},
|
|
[](HMODULE, const char *) {
|
|
return FARPROC {};
|
|
},
|
|
};
|
|
|
|
EXPECT_FALSE(nvenc::nvenc_dynamic_factory::get(runtime_api));
|
|
}
|
|
|
|
TEST(NvencDynamicFactoryTest, HandlesFailedVersionQuery) {
|
|
reported_version = 1300U;
|
|
reported_status = 1U;
|
|
|
|
EXPECT_FALSE(nvenc::nvenc_dynamic_factory::get(make_fake_runtime_api()));
|
|
}
|
|
|
|
TEST(NvencDynamicFactoryTest, RejectsUnsupportedDriver) {
|
|
reported_version = 10U << 4U;
|
|
reported_status = 0U;
|
|
|
|
EXPECT_FALSE(nvenc::nvenc_dynamic_factory::get(make_fake_runtime_api()));
|
|
}
|
|
|
|
TEST(NvencDynamicFactoryTest, SelectsSupportedSdkImplementations) {
|
|
using enum nvenc::nvenc_sdk_version;
|
|
constexpr std::array test_cases {
|
|
std::pair {11U << 4U, sdk_11_0},
|
|
std::pair {12U << 4U, sdk_12_0},
|
|
std::pair {13U << 4U, sdk_13_0},
|
|
std::pair {14U << 4U, sdk_13_0},
|
|
};
|
|
reported_status = 0U;
|
|
|
|
for (const auto &[version, expected] : test_cases) {
|
|
reported_version = version;
|
|
const auto factory = nvenc::nvenc_dynamic_factory::get(make_fake_runtime_api());
|
|
ASSERT_TRUE(factory);
|
|
EXPECT_EQ(factory->sdk_version(), expected);
|
|
}
|
|
}
|
|
|
|
TEST(NvencDynamicFactoryTest, UsesConfiguredEncoderConstructors) {
|
|
bool created_native = false;
|
|
bool created_on_cuda = false;
|
|
const auto dll = make_fake_dll();
|
|
nvenc::nvenc_dynamic_factory factory {
|
|
dll,
|
|
nvenc::nvenc_sdk_version::sdk_13_0,
|
|
[&created_native, &dll](ID3D11Device *, nvenc::shared_dll callback_dll) {
|
|
created_native = true;
|
|
EXPECT_EQ(callback_dll, dll);
|
|
return std::make_unique<fake_nvenc_encoder>();
|
|
},
|
|
[&created_on_cuda, &dll](ID3D11Device *, nvenc::shared_dll callback_dll) {
|
|
created_on_cuda = true;
|
|
EXPECT_EQ(callback_dll, dll);
|
|
return std::make_unique<fake_nvenc_encoder>();
|
|
},
|
|
};
|
|
|
|
EXPECT_EQ(factory.sdk_version(), nvenc::nvenc_sdk_version::sdk_13_0);
|
|
EXPECT_TRUE(factory.create_nvenc_d3d11_native(nullptr));
|
|
EXPECT_TRUE(factory.create_nvenc_d3d11_on_cuda(nullptr));
|
|
EXPECT_TRUE(created_native);
|
|
EXPECT_TRUE(created_on_cuda);
|
|
}
|
|
|
|
TEST(NvencDynamicFactoryTest, UsesDefaultWindowsRuntime) {
|
|
const auto factory = nvenc::nvenc_dynamic_factory::get();
|
|
EXPECT_TRUE(!factory || factory->sdk_version() != nvenc::nvenc_sdk_version::unsupported);
|
|
}
|
|
|
|
TEST(NvencSharedDllTest, OwnsLoadedModuleUntilLastReference) {
|
|
const auto handle = LoadLibraryEx("version.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
|
ASSERT_NE(handle, nullptr);
|
|
|
|
auto dll = nvenc::make_shared_dll(handle);
|
|
EXPECT_EQ(dll.get(), handle);
|
|
auto copy = dll;
|
|
EXPECT_EQ(copy.use_count(), 2);
|
|
|
|
dll.reset();
|
|
EXPECT_EQ(copy.use_count(), 1);
|
|
copy.reset();
|
|
}
|
|
|
|
TEST(NvencSharedDllTest, AcceptsNullModule) {
|
|
auto dll = nvenc::make_shared_dll(nullptr);
|
|
EXPECT_FALSE(dll);
|
|
dll.reset();
|
|
}
|
|
|
|
} // namespace
|
|
#endif
|