1
0
Fork 0
cmake_helpers/win_directx_helper/win_directx_helper.cpp
2021-07-20 15:38:58 +03:00

292 lines
7.1 KiB
C++

// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#include <d3d9.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <openssl/sha.h>
#include <string>
#include <vector>
#include <array>
#define LOAD_SYMBOL(handle, func) LoadSymbol(handle, #func, func)
namespace DirectX {
namespace {
constexpr auto kMaxPathLong = 32767;
using Handle = HINSTANCE;
// d3dcompiler_47.dll
HRESULT (__stdcall *D3DCompile)(
LPCVOID pSrcData,
SIZE_T SrcDataSize,
LPCSTR pFileName,
CONST D3D_SHADER_MACRO* pDefines,
ID3DInclude* pInclude,
LPCSTR pEntrypoint,
LPCSTR pTarget,
UINT Flags1,
UINT Flags2,
ID3DBlob** ppCode,
ID3DBlob** ppErrorMsgs);
HRESULT (__stdcall *D3DDisassemble)(
_In_reads_bytes_(SrcDataSize) LPCVOID pSrcData,
_In_ SIZE_T SrcDataSize,
_In_ UINT Flags,
_In_opt_ LPCSTR szComments,
_Out_ ID3DBlob** ppDisassembly);
// d3d9.dll
IDirect3D9 * (__stdcall *Direct3DCreate9)(UINT SDKVersion);
int (__stdcall *D3DPERF_BeginEvent)(D3DCOLOR col, LPCWSTR wszName);
int (__stdcall *D3DPERF_EndEvent)(void);
void (__stdcall *D3DPERF_SetMarker)(D3DCOLOR col, LPCWSTR wszName);
DWORD (__stdcall *D3DPERF_GetStatus)(void);
// d3d11.dll
HRESULT (__stdcall *D3D11CreateDevice)(
_In_opt_ IDXGIAdapter* pAdapter,
D3D_DRIVER_TYPE DriverType,
HMODULE Software,
UINT Flags,
_In_reads_opt_(FeatureLevels) CONST D3D_FEATURE_LEVEL* pFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
_COM_Outptr_opt_ ID3D11Device** ppDevice,
_Out_opt_ D3D_FEATURE_LEVEL* pFeatureLevel,
_COM_Outptr_opt_ ID3D11DeviceContext** ppImmediateContext);
// dxgi.dll
HRESULT (__stdcall *CreateDXGIFactory)(
REFIID riid,
_COM_Outptr_ void **ppFactory);
HRESULT (__stdcall *CreateDXGIFactory1)(
REFIID riid,
_COM_Outptr_ void **ppFactory);
template <typename Function>
inline bool LoadSymbol(Handle handle, const char *name, Function &func) {
func = handle
? reinterpret_cast<Function>(GetProcAddress(handle, name))
: nullptr;
return (func != nullptr);
}
// For win_directx_helper.
std::string FileSha256(const wchar_t *path) {
using uchar = unsigned char;
constexpr auto kLimit = 10 * 1024 * 1024;
auto buffer = std::vector<uchar>(kLimit);
auto size = DWORD();
const auto file = CreateFile(
path,
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr);
if (file == INVALID_HANDLE_VALUE) {
return {};
}
const auto read = ReadFile(file, buffer.data(), kLimit, &size, nullptr);
CloseHandle(file);
if (!read || !size || size >= kLimit) {
return {};
}
auto binary = std::array<uchar, SHA256_DIGEST_LENGTH>{};
SHA256(buffer.data(), size, binary.data());
const auto hex = [](uchar value) {
return (value >= 10) ? ('a' + (value - 10)) : ('0' + value);
};
auto result = std::string();
result.reserve(binary.size() * 2);
auto index = 0;
for (const auto byte : binary) {
result.push_back(hex(byte / 16));
result.push_back(hex(byte % 16));
}
return result;
}
bool ResolveD3DCompiler(const wchar_t *path) {
const auto d3dcompiler = LoadLibrary(path);
return true
&& LOAD_SYMBOL(d3dcompiler, D3DCompile)
&& LOAD_SYMBOL(d3dcompiler, D3DDisassemble);
}
bool ResolveD3DCompiler() {
static const auto loaded = [] {
#ifdef DESKTOP_APP_D3DCOMPILER_HASH
auto exePath = std::array<WCHAR, kMaxPathLong + 1>{ 0 };
const auto exeLength = GetModuleFileName(
nullptr,
exePath.data(),
kMaxPathLong + 1);
if (!exeLength || exeLength >= kMaxPathLong + 1) {
return false;
}
const auto exe = std::wstring(exePath.data());
const auto last1 = exe.find_last_of('\\');
const auto last2 = exe.find_last_of('/');
const auto last = std::max(
(last1 == std::wstring::npos) ? -1 : int(last1),
(last2 == std::wstring::npos) ? -1 : int(last2));
if (last < 0) {
return false;
}
#if defined _WIN32
const auto arch = L"x86";
#elif defined _WIN64 // _WIN32
const auto arch = L"x64";
#else // _WIN32 || _WIN64
#error "Invalid configuration."
#endif // _WIN32 || _WIN64
#define DESKTOP_APP_STRINGIFY2(x) #x
#define DESKTOP_APP_STRINGIFY(x) DESKTOP_APP_STRINGIFY2(x)
const auto hash = DESKTOP_APP_STRINGIFY(DESKTOP_APP_D3DCOMPILER_HASH);
#undef DESKTOP_APP_STRINGIFY
#undef DESKTOP_APP_STRINGIFY2
const auto compiler = exe.substr(0, last + 1)
+ L"modules\\" + arch + L"\\d3d\\d3dcompiler_47.dll";
const auto path = compiler.c_str();
if (FileSha256(path) == hash && ResolveD3DCompiler(path)) {
return true;
}
#endif // DESKTOP_APP_D3DCOMPILER_HASH
return ResolveD3DCompiler(L"d3dcompiler_47.dll");
}();
return loaded;
}
bool ResolveD3D9() {
static const auto loaded = [] {
const auto d3d9 = LoadLibrary(L"d3d9.dll");
LOAD_SYMBOL(d3d9, D3DPERF_BeginEvent);
LOAD_SYMBOL(d3d9, D3DPERF_EndEvent);
LOAD_SYMBOL(d3d9, D3DPERF_SetMarker);
LOAD_SYMBOL(d3d9, D3DPERF_GetStatus);
return ResolveD3DCompiler()
&& LOAD_SYMBOL(d3d9, Direct3DCreate9);
}();
return loaded;
}
bool ResolveD3D11() {
static const auto loaded = [] {
const auto d3d11 = LoadLibrary(L"d3d11.dll");
return ResolveD3DCompiler()
&& LOAD_SYMBOL(d3d11, D3D11CreateDevice);
}();
return loaded;
}
bool ResolveDXGI() {
static const auto loaded = [&] {
const auto dxgi = LoadLibrary(L"dxgi.dll");
LOAD_SYMBOL(dxgi, CreateDXGIFactory1);
return true
&& LOAD_SYMBOL(dxgi, CreateDXGIFactory);
}();
return loaded;
}
} // namespace
} // namespace DirectX
namespace D = DirectX;
extern "C" {
IDirect3D9 * WINAPI Direct3DCreate9(UINT SDKVersion) {
return D::ResolveD3D9()
? D::Direct3DCreate9(SDKVersion)
: nullptr;
}
int WINAPI D3DPERF_BeginEvent(D3DCOLOR col, LPCWSTR wszName) {
return (D::ResolveD3D9() && D::D3DPERF_BeginEvent)
? D::D3DPERF_BeginEvent(col, wszName)
: -1;
}
int WINAPI D3DPERF_EndEvent(void) {
return (D::ResolveD3D9() && D::D3DPERF_EndEvent)
? D::D3DPERF_EndEvent()
: -1;
}
void WINAPI D3DPERF_SetMarker(D3DCOLOR col, LPCWSTR wszName) {
if (D::ResolveD3D9() && D::D3DPERF_SetMarker) {
D::D3DPERF_SetMarker(col, wszName);
}
}
DWORD WINAPI D3DPERF_GetStatus(void) {
return (D::ResolveD3D9() && D::D3DPERF_GetStatus)
? D::D3DPERF_GetStatus()
: 0;
}
HRESULT WINAPI D3D11CreateDevice(
_In_opt_ IDXGIAdapter* pAdapter,
D3D_DRIVER_TYPE DriverType,
HMODULE Software,
UINT Flags,
_In_reads_opt_(FeatureLevels) CONST D3D_FEATURE_LEVEL* pFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
_COM_Outptr_opt_ ID3D11Device** ppDevice,
_Out_opt_ D3D_FEATURE_LEVEL* pFeatureLevel,
_COM_Outptr_opt_ ID3D11DeviceContext** ppImmediateContext) {
return D::ResolveD3D11()
? D::D3D11CreateDevice(
pAdapter,
DriverType,
Software,
Flags,
pFeatureLevels,
FeatureLevels,
SDKVersion,
ppDevice,
pFeatureLevel,
ppImmediateContext)
: CO_E_DLLNOTFOUND;
}
HRESULT WINAPI CreateDXGIFactory(
REFIID riid,
_COM_Outptr_ void **ppFactory) {
return D::ResolveDXGI()
? D::CreateDXGIFactory(riid, ppFactory)
: CO_E_DLLNOTFOUND;
}
HRESULT WINAPI CreateDXGIFactory1(
REFIID riid,
_COM_Outptr_ void **ppFactory) {
return (D::ResolveDXGI() && D::CreateDXGIFactory1)
? D::CreateDXGIFactory1(riid, ppFactory)
: CO_E_DLLNOTFOUND;
}
} // extern "C"