#include <string>
#include "src/tint/lang/hlsl/validate/validate.h"
#include "src/tint/utils/command/command.h"
#include "src/tint/utils/file/tmpfile.h"
#include "src/tint/utils/macros/defer.h"
#include "src/tint/utils/text/string.h"
#ifdef _WIN32
#include <Windows.h>
#include <atlbase.h>
#include <d3dcommon.h>
#include <d3dcompiler.h>
#include <wrl.h>
#else
#include <dlfcn.h>
#endif
TINT_BEGIN_DISABLE_ALL_WARNINGS(…);
#ifdef __clang__
#define __EMULATE_UUID
#endif
#include "dxc/dxcapi.h"
TINT_END_DISABLE_ALL_WARNINGS(…);
TINT_DISABLE_WARNING_OLD_STYLE_CAST
namespace {
PFN_DXC_CREATE_INSTANCE;
DAWN_NO_SANITIZE("undefined")
HRESULT CallDxcCreateInstance(PFN_DXC_CREATE_INSTANCE dxc_create_instance,
CComPtr<IDxcCompiler3>& dxc_compiler) { … }
}
namespace tint::hlsl::validate {
Result ValidateUsingDXC(const std::string& dxc_path,
const std::string& source,
const EntryPointList& entry_points,
bool require_16bit_types,
uint32_t hlsl_shader_model) { … }
#ifdef _WIN32
Result ValidateUsingFXC(const std::string& fxc_path,
const std::string& source,
const EntryPointList& entry_points) {
Result result;
if (entry_points.empty()) {
result.output = "No entrypoint found";
result.failed = true;
return result;
}
HMODULE fxcLib = LoadLibraryA(fxc_path.c_str());
if (fxcLib == nullptr) {
result.output = "Couldn't load FXC";
result.failed = true;
return result;
}
auto* d3dCompile = reinterpret_cast<pD3DCompile>(
reinterpret_cast<void*>(GetProcAddress(fxcLib, "D3DCompile")));
auto* d3dDisassemble = reinterpret_cast<pD3DDisassemble>(
reinterpret_cast<void*>(GetProcAddress(fxcLib, "D3DDisassemble")));
if (d3dCompile == nullptr) {
result.output = "Couldn't load D3DCompile from FXC";
result.failed = true;
return result;
}
if (d3dDisassemble == nullptr) {
result.output = "Couldn't load D3DDisassemble from FXC";
result.failed = true;
return result;
}
for (auto ep : entry_points) {
const char* profile = "";
switch (ep.second) {
case ast::PipelineStage::kNone:
result.output = "Invalid PipelineStage";
result.failed = true;
return result;
case ast::PipelineStage::kVertex:
profile = "vs_5_1";
break;
case ast::PipelineStage::kFragment:
profile = "ps_5_1";
break;
case ast::PipelineStage::kCompute:
profile = "cs_5_1";
break;
}
UINT compileFlags = D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR |
D3DCOMPILE_IEEE_STRICTNESS;
CComPtr<ID3DBlob> compiledShader;
CComPtr<ID3DBlob> errors;
HRESULT res = d3dCompile(source.c_str(),
source.length(),
nullptr,
nullptr,
nullptr,
ep.first.c_str(),
profile,
compileFlags,
0,
&compiledShader,
&errors);
if (FAILED(res)) {
result.output = static_cast<char*>(errors->GetBufferPointer());
result.failed = true;
return result;
} else {
CComPtr<ID3DBlob> disassembly;
res = d3dDisassemble(compiledShader->GetBufferPointer(),
compiledShader->GetBufferSize(), 0, "", &disassembly);
if (FAILED(res)) {
result.output = "Failed to disassemble shader";
} else {
result.output = static_cast<char*>(disassembly->GetBufferPointer());
}
}
}
FreeLibrary(fxcLib);
return result;
}
#endif
}