From e878947f3765f85b4619318eca1cf25bfca47b65 Mon Sep 17 00:00:00 2001 From: WolframRhodium Date: Wed, 21 Aug 2024 13:25:43 +0800 Subject: [PATCH] vsmigx/{CMakeLists.txt,win32.cpp},.github/workflows/windows-migx.yml: delay load migx --- vsmigx/CMakeLists.txt | 10 ++++- vsmigx/win32.cpp | 95 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 vsmigx/win32.cpp diff --git a/vsmigx/CMakeLists.txt b/vsmigx/CMakeLists.txt index 945f113..78e03fd 100644 --- a/vsmigx/CMakeLists.txt +++ b/vsmigx/CMakeLists.txt @@ -9,7 +9,7 @@ set(VAPOURSYNTH_INCLUDE_DIRECTORY "" CACHE PATH "Path to VapourSynth headers") find_package(migraphx REQUIRED CONFIG) find_package(hip REQUIRED CONFIG) -add_library(vsmigx SHARED vs_migraphx.cpp) +add_library(vsmigx SHARED vs_migraphx.cpp win32.cpp) target_include_directories(vsmigx PRIVATE ${VAPOURSYNTH_INCLUDE_DIRECTORY}) @@ -22,6 +22,14 @@ set_target_properties(vsmigx PROPERTIES CXX_STANDARD_REQUIRED ON ) +if (WIN32) + target_link_options(vsmigx PRIVATE + "/DELAYLOAD:migraphx_c.dll" + "/DELAYLOAD:amdhip64_6.dll" + "delayimp.lib" + ) +endif() + find_package(Git REQUIRED) execute_process( COMMAND ${GIT_EXECUTABLE} describe --tags --long --always diff --git a/vsmigx/win32.cpp b/vsmigx/win32.cpp new file mode 100644 index 0000000..8e009a3 --- /dev/null +++ b/vsmigx/win32.cpp @@ -0,0 +1,95 @@ +#ifdef _MSC_VER +#include +#include +#include +#include +#include +#include + +#define DLL_DIR L"vsmlrt-hip" + +#include + +namespace { +std::vector dlls = { + // This list must be sorted by dependency. + L"amdhip64_6.dll", + L"migraphx.dll", + L"migraphx_tf.dll", + L"migraphx_onnx.dll", + L"migraphx_c.dll", // must be the last +}; + +namespace fs = std::filesystem; +static fs::path dllDir() { + static const std::wstring res = []() -> std::wstring { + HMODULE mod = 0; + if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (char *)dllDir, &mod)) { + std::vector buf; + size_t n = 0; + do { + buf.resize(buf.size() + MAX_PATH); + n = GetModuleFileNameW(mod, buf.data(), buf.size()); + } while (n >= buf.size()); + buf.resize(n); + std::wstring path(buf.begin(), buf.end()); + return path; + } + throw std::runtime_error("unable to locate myself"); + }(); + return fs::path(res).parent_path(); +} + +FARPROC loadDLLs() { + fs::path dir = dllDir() / DLL_DIR; + HMODULE h = nullptr; + for (const auto dll: dlls) { + fs::path p = dir / dll; + std::wstring s = p; + h = LoadLibraryW(s.c_str()); + if (getenv("VSMIGX_VERBOSE")) + std::wcerr << L"vsmigx: preloading " << p << L": " << h << std::endl; + if (!h) + std::wcerr << L"vsmigx: failed to preload " << s << std::endl; + } + return (FARPROC)h; +} + +extern "C" FARPROC WINAPI delayload_hook(unsigned reason, DelayLoadInfo* info) { + switch (reason) { + case dliNoteStartProcessing: + case dliNoteEndProcessing: + // Nothing to do here. + break; + case dliNotePreLoadLibrary: + //std::cerr << "loading " << info->szDll << std::endl; + if (std::string(info->szDll).find("migraphx_c.dll") != std::string::npos || + std::string(info->szDll).find("amdhip64_6.dll") != std::string::npos + ) + return loadDLLs(); + break; + case dliNotePreGetProcAddress: + // Nothing to do here. + break; + case dliFailLoadLib: + case dliFailGetProc: + // Returning NULL from error notifications will cause the delay load + // runtime to raise a VcppException structured exception, that some code + // might want to handle. + return NULL; + break; + default: + abort(); // unreachable. + break; + } + // Returning NULL causes the delay load machinery to perform default + // processing for this notification. + return NULL; +} +} // namespace + +extern "C" { + const PfnDliHook __pfnDliNotifyHook2 = delayload_hook; + const PfnDliHook __pfnDliFailureHook2 = delayload_hook; +}; +#endif