dad861b036
For game capture, hook DXGI release function to release D3D objects if the related swap chain is also being destroyed. An added bonus is that the game capture hook will handle swap chain recreation for applications that don't use ResizeBuffers.
243 lines
5.9 KiB
C
243 lines
5.9 KiB
C
#include <obs-module.h>
|
|
#include <util/windows/win-version.h>
|
|
#include <util/platform.h>
|
|
#include <util/dstr.h>
|
|
#include <util/config-file.h>
|
|
#include <util/pipe.h>
|
|
|
|
#include <windows.h>
|
|
#include "graphics-hook-info.h"
|
|
|
|
extern struct graphics_offsets offsets32;
|
|
extern struct graphics_offsets offsets64;
|
|
|
|
static inline bool load_offsets_from_string(struct graphics_offsets *offsets,
|
|
const char *str)
|
|
{
|
|
config_t *config;
|
|
|
|
if (config_open_string(&config, str) != CONFIG_SUCCESS) {
|
|
return false;
|
|
}
|
|
|
|
offsets->d3d8.present =
|
|
(uint32_t)config_get_uint(config, "d3d8", "present");
|
|
|
|
offsets->d3d9.present =
|
|
(uint32_t)config_get_uint(config, "d3d9", "present");
|
|
offsets->d3d9.present_ex =
|
|
(uint32_t)config_get_uint(config, "d3d9", "present_ex");
|
|
offsets->d3d9.present_swap =
|
|
(uint32_t)config_get_uint(config, "d3d9", "present_swap");
|
|
offsets->d3d9.d3d9_clsoff =
|
|
(uint32_t)config_get_uint(config, "d3d9", "d3d9_clsoff");
|
|
offsets->d3d9.is_d3d9ex_clsoff =
|
|
(uint32_t)config_get_uint(config, "d3d9", "is_d3d9ex_clsoff");
|
|
|
|
offsets->dxgi.present =
|
|
(uint32_t)config_get_uint(config, "dxgi", "present");
|
|
offsets->dxgi.present1 =
|
|
(uint32_t)config_get_uint(config, "dxgi", "present1");
|
|
offsets->dxgi.resize =
|
|
(uint32_t)config_get_uint(config, "dxgi", "resize");
|
|
offsets->dxgi2.release =
|
|
(uint32_t)config_get_uint(config, "dxgi", "release");
|
|
|
|
config_close(config);
|
|
return true;
|
|
}
|
|
|
|
static inline bool load_offsets_from_file(struct graphics_offsets *offsets,
|
|
const char *file)
|
|
{
|
|
char *str = os_quick_read_utf8_file(file);
|
|
bool success = false;
|
|
if (str && *str)
|
|
success = load_offsets_from_string(offsets, str);
|
|
bfree(str);
|
|
return success;
|
|
}
|
|
|
|
static inline bool config_ver_mismatch(config_t *ver_config,
|
|
const char *section,
|
|
struct win_version_info *ver)
|
|
{
|
|
struct win_version_info config_ver;
|
|
bool mismatch = false;
|
|
|
|
#define get_sub_ver(subver) \
|
|
config_ver.subver = (int)config_get_int(ver_config, section, #subver); \
|
|
mismatch |= config_ver.subver != ver->subver;
|
|
|
|
get_sub_ver(major);
|
|
get_sub_ver(minor);
|
|
get_sub_ver(build);
|
|
get_sub_ver(revis);
|
|
|
|
#undef get_sub_ver
|
|
|
|
return mismatch;
|
|
}
|
|
|
|
static inline void write_config_ver(config_t *ver_config, const char *section,
|
|
struct win_version_info *ver)
|
|
{
|
|
#define set_sub_ver(subver) \
|
|
config_set_int(ver_config, section, #subver, ver->subver);
|
|
|
|
set_sub_ver(major);
|
|
set_sub_ver(minor);
|
|
set_sub_ver(build);
|
|
set_sub_ver(revis);
|
|
|
|
#undef set_sub_ver
|
|
}
|
|
|
|
static bool get_32bit_system_dll_ver(const wchar_t *system_lib,
|
|
struct win_version_info *ver)
|
|
{
|
|
wchar_t path[MAX_PATH];
|
|
UINT ret;
|
|
|
|
#ifdef _WIN64
|
|
ret = GetSystemWow64DirectoryW(path, MAX_PATH);
|
|
#else
|
|
ret = GetSystemDirectoryW(path, MAX_PATH);
|
|
#endif
|
|
if (!ret) {
|
|
blog(LOG_ERROR,
|
|
"Failed to get windows 32bit system path: "
|
|
"%lu",
|
|
GetLastError());
|
|
return false;
|
|
}
|
|
|
|
wcscat(path, L"\\");
|
|
wcscat(path, system_lib);
|
|
return get_dll_ver(path, ver);
|
|
}
|
|
|
|
bool cached_versions_match(void)
|
|
{
|
|
struct win_version_info d3d8_ver = {0};
|
|
struct win_version_info d3d9_ver = {0};
|
|
struct win_version_info dxgi_ver = {0};
|
|
bool ver_mismatch = false;
|
|
config_t *config;
|
|
char *ver_file;
|
|
int ret;
|
|
|
|
ver_mismatch |= !get_32bit_system_dll_ver(L"d3d8.dll", &d3d8_ver);
|
|
ver_mismatch |= !get_32bit_system_dll_ver(L"d3d9.dll", &d3d9_ver);
|
|
ver_mismatch |= !get_32bit_system_dll_ver(L"dxgi.dll", &dxgi_ver);
|
|
|
|
ver_file = obs_module_config_path("version.ini");
|
|
if (!ver_file)
|
|
return false;
|
|
|
|
ret = config_open(&config, ver_file, CONFIG_OPEN_ALWAYS);
|
|
if (ret != CONFIG_SUCCESS)
|
|
goto failed;
|
|
|
|
ver_mismatch |= config_ver_mismatch(config, "d3d8", &d3d8_ver);
|
|
ver_mismatch |= config_ver_mismatch(config, "d3d9", &d3d9_ver);
|
|
ver_mismatch |= config_ver_mismatch(config, "dxgi", &dxgi_ver);
|
|
|
|
if (ver_mismatch) {
|
|
write_config_ver(config, "d3d8", &d3d8_ver);
|
|
write_config_ver(config, "d3d9", &d3d9_ver);
|
|
write_config_ver(config, "dxgi", &dxgi_ver);
|
|
config_save_safe(config, "tmp", NULL);
|
|
}
|
|
|
|
failed:
|
|
bfree(ver_file);
|
|
config_close(config);
|
|
return !ver_mismatch;
|
|
}
|
|
|
|
bool load_graphics_offsets(bool is32bit, const char *config_path)
|
|
{
|
|
char *offset_exe_path = NULL;
|
|
struct dstr offset_exe = {0};
|
|
struct dstr config_ini = {0};
|
|
struct dstr str = {0};
|
|
os_process_pipe_t *pp;
|
|
bool success = false;
|
|
char data[2048];
|
|
|
|
#ifndef _WIN64
|
|
if (!is32bit && !is_64_bit_windows()) {
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
dstr_copy(&offset_exe, "get-graphics-offsets");
|
|
dstr_cat(&offset_exe, is32bit ? "32.exe" : "64.exe");
|
|
offset_exe_path = obs_module_file(offset_exe.array);
|
|
|
|
pp = os_process_pipe_create(offset_exe_path, "r");
|
|
if (!pp) {
|
|
blog(LOG_INFO, "load_graphics_offsets: Failed to start '%s'",
|
|
offset_exe.array);
|
|
goto error;
|
|
}
|
|
|
|
for (;;) {
|
|
size_t len =
|
|
os_process_pipe_read(pp, (uint8_t *)data, sizeof(data));
|
|
if (!len)
|
|
break;
|
|
|
|
dstr_ncat(&str, data, len);
|
|
}
|
|
|
|
if (dstr_is_empty(&str)) {
|
|
blog(LOG_INFO,
|
|
"load_graphics_offsets: Failed to read "
|
|
"from '%s'",
|
|
offset_exe.array);
|
|
goto error;
|
|
}
|
|
|
|
// uncomment this if you enable USE_HOOK_ADDRESS_CACHE
|
|
/*
|
|
dstr_copy(&config_ini, config_path);
|
|
dstr_cat(&config_ini, is32bit ? "32.ini" : "64.ini");
|
|
|
|
os_quick_write_utf8_file_safe(config_ini.array, str.array, str.len, false,
|
|
"tmp", NULL);
|
|
dstr_free(&config_ini);
|
|
*/
|
|
|
|
success = load_offsets_from_string(is32bit ? &offsets32 : &offsets64,
|
|
str.array);
|
|
if (!success) {
|
|
blog(LOG_INFO, "load_graphics_offsets: Failed to load string");
|
|
}
|
|
|
|
os_process_pipe_destroy(pp);
|
|
|
|
error:
|
|
bfree(offset_exe_path);
|
|
dstr_free(&offset_exe);
|
|
dstr_free(&str);
|
|
return success;
|
|
}
|
|
|
|
bool load_cached_graphics_offsets(bool is32bit, const char *config_path)
|
|
{
|
|
struct dstr config_ini = {0};
|
|
bool success;
|
|
|
|
dstr_copy(&config_ini, config_path);
|
|
dstr_cat(&config_ini, is32bit ? "32.ini" : "64.ini");
|
|
success = load_offsets_from_file(is32bit ? &offsets32 : &offsets64,
|
|
config_ini.array);
|
|
if (!success)
|
|
success = load_graphics_offsets(is32bit, config_path);
|
|
|
|
dstr_free(&config_ini);
|
|
return success;
|
|
}
|