300 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
	
		
			7.4 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>
 | 
						|
extern "C" {
 | 
						|
#include <openssl/sha.h>
 | 
						|
} // extern "C"
 | 
						|
#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 _WIN64
 | 
						|
		const auto arch = L"x64";
 | 
						|
#elif defined _WIN32 // _WIN64
 | 
						|
		const auto arch = L"x86";
 | 
						|
#else // _WIN64 || _WIN32
 | 
						|
#error "Invalid configuration."
 | 
						|
#endif // _WIN64 || _WIN32
 | 
						|
 | 
						|
#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;
 | 
						|
		}
 | 
						|
#elif defined DESKTOP_APP_SPECIAL_TARGET // DESKTOP_APP_D3DCOMPILER_HASH
 | 
						|
#error "Special target build should have d3dcompiler hash."
 | 
						|
#endif // !DESKTOP_APP_D3DCOMPILER_HASH && DESKTOP_APP_SPECIAL_TARGET
 | 
						|
 | 
						|
		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
 | 
						|
 | 
						|
bool DirectXResolveCompiler() {
 | 
						|
	return DirectX::ResolveD3DCompiler();
 | 
						|
}
 | 
						|
 | 
						|
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"
 |