obs-ffmpeg, obs-qsv11: Ensure adapter order in encoder tests

On systems with multiple graphics adapters, one card can be configured
as power saving, and another card can be configured as performance.
Sometimes, OBS and the encoder test subprocesses will not be configured
the same way, so it's necessary to provide adapter order to the encoder
test subprocesses.

This change ensures the adapter order by passing the LUIDs to the test
subprocesses. The adapter indexes will then be updated accordingly.
This commit is contained in:
jp9000 2022-12-19 12:05:22 -08:00
parent 2396c4a01c
commit 122e864c38
6 changed files with 123 additions and 12 deletions

View file

@ -2,6 +2,7 @@
#include <util/platform.h>
#include <util/threading.h>
#include <util/config-file.h>
#include <util/windows/device-enum.h>
#include <util/dstr.h>
#include <util/pipe.h>
@ -222,14 +223,26 @@ extern struct obs_encoder_info hevc_nvenc_info;
#endif
extern struct obs_encoder_info av1_nvenc_info;
static bool enum_luids(void *param, uint32_t idx, uint64_t luid)
{
struct dstr *cmd = param;
dstr_catf(cmd, " %llX", luid);
UNUSED_PARAMETER(idx);
return true;
}
static bool av1_supported(void)
{
char *test_exe = os_get_executable_path_ptr("obs-nvenc-test.exe");
struct dstr cmd = {0};
struct dstr caps_str = {0};
bool av1_supported = false;
config_t *config = NULL;
os_process_pipe_t *pp = os_process_pipe_create(test_exe, "r");
dstr_copy(&cmd, test_exe);
enum_graphics_device_luids(enum_luids, &cmd);
os_process_pipe_t *pp = os_process_pipe_create(cmd.array, "r");
if (!pp) {
blog(LOG_WARNING, "[NVENC] Failed to launch the NVENC "
"test process I guess");
@ -278,6 +291,7 @@ fail:
if (config)
config_close(config);
dstr_free(&caps_str);
dstr_free(&cmd);
if (test_exe)
bfree(test_exe);

View file

@ -10,6 +10,7 @@
#include <d3d11.h>
#include <d3d11_1.h>
#include <vector>
#include <string>
#include <map>
@ -29,6 +30,7 @@ struct adapter_caps {
};
static AMFFactory *amf_factory = nullptr;
static std::vector<uint64_t> luid_order;
static std::map<uint32_t, adapter_caps> adapter_info;
static bool has_encoder(AMFContextPtr &amf_context, const wchar_t *encoder_name)
@ -39,6 +41,17 @@ static bool has_encoder(AMFContextPtr &amf_context, const wchar_t *encoder_name)
return res == AMF_OK;
}
static inline uint32_t get_adapter_idx(uint32_t adapter_idx, LUID luid)
{
for (size_t i = 0; i < luid_order.size(); i++) {
if (luid_order[i] == *(uint64_t *)&luid) {
return (uint32_t)i;
}
}
return adapter_idx;
}
static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx)
{
AMF_RESULT res;
@ -49,11 +62,12 @@ static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx)
if (FAILED(hr))
return false;
adapter_caps &caps = adapter_info[adapter_idx];
DXGI_ADAPTER_DESC desc;
adapter->GetDesc(&desc);
uint32_t luid_idx = get_adapter_idx(adapter_idx, desc.AdapterLuid);
adapter_caps &caps = adapter_info[luid_idx];
if (desc.VendorId != AMD_VENDOR_ID)
return true;
@ -96,7 +110,7 @@ DWORD WINAPI TimeoutThread(LPVOID param)
return 0;
}
int main(void)
int main(int argc, char *argv[])
try {
ComPtr<IDXGIFactory> factory;
AMF_RESULT res;
@ -128,6 +142,16 @@ try {
if (res != AMF_OK)
throw "AMFInit failed";
/* --------------------------------------------------------- */
/* parse expected LUID order */
for (int i = 1; i < argc; i++) {
luid_order.push_back(strtoull(argv[i], NULL, 16));
}
/* --------------------------------------------------------- */
/* obtain adapter compatibility information */
hr = CreateDXGIFactory1(__uuidof(IDXGIFactory), (void **)&factory);
if (FAILED(hr))
throw "CreateDXGIFactory1 failed";

View file

@ -1,4 +1,5 @@
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "../external/nvEncodeAPI.h"
@ -21,6 +22,8 @@ struct nvenc_info {
};
#define MAX_CAPS 10
static uint32_t luid_count = 0;
static uint64_t luid_order[MAX_CAPS] = {0};
static struct nvenc_info adapter_info[MAX_CAPS] = {0};
bool load_nvenc_lib(void)
@ -37,9 +40,20 @@ static inline void *load_nv_func(const char *func)
return func_ptr;
}
static inline uint32_t get_adapter_idx(uint32_t adapter_idx, LUID luid)
{
for (uint32_t i = 0; i < luid_count; i++) {
if (luid_order[i] == *(uint64_t *)&luid) {
return i;
}
}
return adapter_idx;
}
static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx)
{
struct nvenc_info *caps = &adapter_info[adapter_idx];
struct nvenc_info *caps;
IDXGIAdapter *adapter = NULL;
ID3D11Device *device = NULL;
ID3D11DeviceContext *context = NULL;
@ -57,6 +71,7 @@ static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx)
DXGI_ADAPTER_DESC desc;
adapter->lpVtbl->GetDesc(adapter, &desc);
caps = &adapter_info[get_adapter_idx(adapter_idx, desc.AdapterLuid)];
if (desc.VendorId != NVIDIA_VENDOR_ID)
return true;
@ -165,7 +180,7 @@ DWORD WINAPI TimeoutThread(LPVOID param)
return 0;
}
int main(void)
int main(int argc, char *argv[])
{
IDXGIFactory *factory = NULL;
HRESULT hr;
@ -186,6 +201,17 @@ int main(void)
if (!init_nvenc_internal())
return 0;
/* --------------------------------------------------------- */
/* parse expected LUID order */
luid_count = argc - 1;
for (int i = 1; i < argc; i++) {
luid_order[i - 1] = strtoull(argv[i], NULL, 16);
}
/* --------------------------------------------------------- */
/* obtain adapter compatibility information */
hr = CreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&factory);
if (FAILED(hr))
return 0;

View file

@ -8,7 +8,7 @@
#include <unordered_map>
#include <cstdlib>
#include <memory>
#include <string>
#include <sstream>
#include <vector>
#include <mutex>
#include <deque>
@ -24,6 +24,7 @@
#include <d3d11.h>
#include <d3d11_1.h>
#include <util/windows/device-enum.h>
#include <util/windows/HRError.hpp>
#include <util/windows/ComPtr.hpp>
#include <util/platform.h>
@ -2150,6 +2151,14 @@ static void register_av1()
/* ========================================================================= */
/* Global Stuff */
static bool enum_luids(void *param, uint32_t idx, uint64_t luid)
{
std::stringstream &cmd = *(std::stringstream *)param;
cmd << " " << std::hex << luid;
UNUSED_PARAMETER(idx);
return true;
}
extern "C" void amf_load(void)
try {
AMF_RESULT res;
@ -2167,9 +2176,13 @@ try {
/* Check for supported codecs */
BPtr<char> test_exe = os_get_executable_path_ptr("obs-amf-test.exe");
std::stringstream cmd;
std::string caps_str;
os_process_pipe_t *pp = os_process_pipe_create(test_exe, "r");
cmd << test_exe;
enum_graphics_device_luids(enum_luids, &cmd);
os_process_pipe_t *pp = os_process_pipe_create(cmd.str().c_str(), "r");
if (!pp)
throw "Failed to launch the AMF test process I guess";

View file

@ -9,6 +9,7 @@
#include <d3d11.h>
#include <d3d11_1.h>
#include <vector>
#include <string>
#include <map>
@ -26,6 +27,7 @@ struct adapter_caps {
bool supports_hevc = false;
};
static std::vector<uint64_t> luid_order;
static std::map<uint32_t, adapter_caps> adapter_info;
static bool has_encoder(mfxIMPL impl, mfxU32 codec_id)
@ -50,6 +52,17 @@ static bool has_encoder(mfxIMPL impl, mfxU32 codec_id)
return sts == MFX_ERR_NONE;
}
static inline uint32_t get_adapter_idx(uint32_t adapter_idx, LUID luid)
{
for (size_t i = 0; i < luid_order.size(); i++) {
if (luid_order[i] == *(uint64_t *)&luid) {
return (uint32_t)i;
}
}
return adapter_idx;
}
static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx)
{
mfxIMPL impls[4] = {MFX_IMPL_HARDWARE, MFX_IMPL_HARDWARE2,
@ -61,11 +74,11 @@ static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx)
if (FAILED(hr))
return false;
adapter_caps &caps = adapter_info[adapter_idx];
DXGI_ADAPTER_DESC desc;
adapter->GetDesc(&desc);
uint32_t luid_idx = get_adapter_idx(adapter_idx, desc.AdapterLuid);
adapter_caps &caps = adapter_info[luid_idx];
if (desc.VendorId != INTEL_VENDOR_ID)
return true;
@ -97,7 +110,7 @@ DWORD WINAPI TimeoutThread(LPVOID param)
return 0;
}
int main(void)
int main(int argc, char *argv[])
try {
ComPtr<IDXGIFactory> factory;
HRESULT hr;
@ -112,6 +125,13 @@ try {
CreateThread(NULL, 0, TimeoutThread, hMainThread, 0, &threadId);
CloseHandle(hThread);
/* --------------------------------------------------------- */
/* parse expected LUID order */
for (int i = 1; i < argc; i++) {
luid_order.push_back(strtoull(argv[i], NULL, 16));
}
/* --------------------------------------------------------- */
/* query qsv support */

View file

@ -54,6 +54,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <obs-module.h>
#include <util/windows/device-enum.h>
#include <util/config-file.h>
#include <util/platform.h>
#include <util/pipe.h>
@ -81,14 +82,26 @@ extern bool av1_supported(mfxIMPL impl);
struct adapter_info adapters[MAX_ADAPTERS] = {0};
size_t adapter_count = 0;
static bool enum_luids(void *param, uint32_t idx, uint64_t luid)
{
struct dstr *cmd = param;
dstr_catf(cmd, " %llX", luid);
UNUSED_PARAMETER(idx);
return true;
}
bool obs_module_load(void)
{
char *test_exe = os_get_executable_path_ptr("obs-qsv-test.exe");
struct dstr cmd = {0};
struct dstr caps_str = {0};
os_process_pipe_t *pp = NULL;
config_t *config = NULL;
pp = os_process_pipe_create(test_exe, "r");
dstr_copy(&cmd, test_exe);
enum_graphics_device_luids(enum_luids, &cmd);
pp = os_process_pipe_create(cmd.array, "r");
if (!pp) {
blog(LOG_INFO, "Failed to launch the QSV test process I guess");
goto fail;
@ -168,6 +181,7 @@ bool obs_module_load(void)
fail:
config_close(config);
dstr_free(&caps_str);
dstr_free(&cmd);
os_process_pipe_destroy(pp);
bfree(test_exe);