d3d12: use dxil_validator

Now that we have a shiny, new dxil validator interface, let's start
using it in the D3D12 gallium driver.

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15751>
This commit is contained in:
Erik Faye-Lund 2022-04-05 11:11:54 +02:00 committed by Marge Bot
parent 193cf76c09
commit 1e570962ef
5 changed files with 49 additions and 246 deletions

View file

@ -46,57 +46,14 @@
#include <directx/d3d12.h>
#include <dxguids/dxguids.h>
#include <dxcapi.h>
#include <wrl/client.h>
extern "C" {
#include "tgsi/tgsi_parse.h"
#include "tgsi/tgsi_point_sprite.h"
}
using Microsoft::WRL::ComPtr;
struct d3d12_validation_tools
{
d3d12_validation_tools();
bool validate_and_sign(struct blob *dxil);
void disassemble(struct blob *dxil);
void load_dxil_dll();
struct HModule {
HModule();
~HModule();
bool load(LPCSTR file_name);
operator util_dl_library *() const;
private:
util_dl_library *module;
};
HModule dxil_module;
HModule dxc_compiler_module;
ComPtr<IDxcCompiler> compiler;
ComPtr<IDxcValidator> validator;
ComPtr<IDxcLibrary> library;
};
struct d3d12_validation_tools *d3d12_validator_create()
{
d3d12_validation_tools *tools = new d3d12_validation_tools();
if (tools->validator)
return tools;
delete tools;
return nullptr;
}
void d3d12_validator_destroy(struct d3d12_validation_tools *validator)
{
delete validator;
}
#ifdef _WIN32
#include "dxil_validator.h"
#endif
const void *
d3d12_get_compiler_options(struct pipe_screen *screen,
@ -227,13 +184,34 @@ compile_nir(struct d3d12_context *ctx, struct d3d12_shader_selector *sel,
shader->cb_bindings[shader->num_cb_bindings++].binding = i;
}
}
if (ctx->validation_tools) {
ctx->validation_tools->validate_and_sign(&tmp);
#ifdef _WIN32
if (ctx->dxil_validator) {
if (!(d3d12_debug & D3D12_DEBUG_EXPERIMENTAL)) {
char *err;
if (!dxil_validate_module(ctx->dxil_validator, tmp.data,
tmp.size, &err) && err) {
debug_printf(
"== VALIDATION ERROR =============================================\n"
"%s\n"
"== END ==========================================================\n",
err);
ralloc_free(err);
}
}
if (d3d12_debug & D3D12_DEBUG_DISASS) {
ctx->validation_tools->disassemble(&tmp);
char *str = dxil_disasm_module(ctx->dxil_validator, tmp.data,
tmp.size);
fprintf(stderr,
"== BEGIN SHADER ============================================\n"
"%s\n"
"== END SHADER ==============================================\n",
str);
ralloc_free(str);
}
}
#endif
blob_finish_get_buffer(&tmp, &shader->bytecode, &shader->bytecode_length);
@ -1467,183 +1445,3 @@ d3d12_shader_free(struct d3d12_shader_selector *sel)
ralloc_free(sel->initial);
ralloc_free(sel);
}
#ifdef _WIN32
// Used to get path to self
extern "C" extern IMAGE_DOS_HEADER __ImageBase;
#endif
void d3d12_validation_tools::load_dxil_dll()
{
if (!dxil_module.load(UTIL_DL_PREFIX "dxil" UTIL_DL_EXT)) {
#ifdef _WIN32
char selfPath[MAX_PATH] = "";
uint32_t pathSize = GetModuleFileNameA((HINSTANCE)&__ImageBase, selfPath, sizeof(selfPath));
if (pathSize == 0 || pathSize == sizeof(selfPath)) {
debug_printf("D3D12: Unable to get path to self");
return;
}
auto lastSlash = strrchr(selfPath, '\\');
if (!lastSlash) {
debug_printf("D3D12: Unable to get path to self");
return;
}
*(lastSlash + 1) = '\0';
if (strcat_s(selfPath, "dxil.dll") != 0) {
debug_printf("D3D12: Unable to get path to dxil.dll next to self");
return;
}
dxil_module.load(selfPath);
#endif
}
}
d3d12_validation_tools::d3d12_validation_tools()
{
load_dxil_dll();
DxcCreateInstanceProc dxil_create_func = (DxcCreateInstanceProc)util_dl_get_proc_address(dxil_module, "DxcCreateInstance");
if (dxil_create_func) {
HRESULT hr = dxil_create_func(CLSID_DxcValidator, IID_PPV_ARGS(&validator));
if (FAILED(hr)) {
debug_printf("D3D12: Unable to create validator\n");
}
}
#ifdef _WIN32
else if (!(d3d12_debug & D3D12_DEBUG_EXPERIMENTAL)) {
debug_printf("D3D12: Unable to load DXIL.dll\n");
}
#endif
DxcCreateInstanceProc compiler_create_func = nullptr;
if(dxc_compiler_module.load("dxcompiler.dll"))
compiler_create_func = (DxcCreateInstanceProc)util_dl_get_proc_address(dxc_compiler_module, "DxcCreateInstance");
if (compiler_create_func) {
HRESULT hr = compiler_create_func(CLSID_DxcLibrary, IID_PPV_ARGS(&library));
if (FAILED(hr)) {
debug_printf("D3D12: Unable to create library instance: %x\n", hr);
}
if (d3d12_debug & D3D12_DEBUG_DISASS) {
hr = compiler_create_func(CLSID_DxcCompiler, IID_PPV_ARGS(&compiler));
if (FAILED(hr)) {
debug_printf("D3D12: Unable to create compiler instance\n");
}
}
} else if (d3d12_debug & D3D12_DEBUG_DISASS) {
debug_printf("D3D12: Disassembly requested but compiler couldn't be loaded\n");
}
}
d3d12_validation_tools::HModule::HModule():
module(0)
{
}
d3d12_validation_tools::HModule::~HModule()
{
if (module)
util_dl_close(module);
}
inline
d3d12_validation_tools::HModule::operator util_dl_library * () const
{
return module;
}
bool
d3d12_validation_tools::HModule::load(LPCSTR file_name)
{
module = util_dl_open(file_name);
return module != nullptr;
}
class ShaderBlob : public IDxcBlob {
public:
ShaderBlob(blob* data) : m_data(data) {}
LPVOID STDMETHODCALLTYPE GetBufferPointer(void) override { return m_data->data; }
SIZE_T STDMETHODCALLTYPE GetBufferSize() override { return m_data->size; }
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**) override { return E_NOINTERFACE; }
ULONG STDMETHODCALLTYPE AddRef() override { return 1; }
ULONG STDMETHODCALLTYPE Release() override { return 0; }
blob* m_data;
};
bool d3d12_validation_tools::validate_and_sign(struct blob *dxil)
{
ShaderBlob source(dxil);
ComPtr<IDxcOperationResult> result;
validator->Validate(&source, DxcValidatorFlags_InPlaceEdit, &result);
HRESULT validationStatus;
result->GetStatus(&validationStatus);
if (FAILED(validationStatus)) {
if (!library) {
debug_printf("D3D12: validation failed, but lacking "
"IDxcLibrary for proper diagnostics.\n");
return false;
}
ComPtr<IDxcBlobEncoding> printBlob, printBlobUtf8;
result->GetErrorBuffer(&printBlob);
library->GetBlobAsUtf8(printBlob.Get(), printBlobUtf8.GetAddressOf());
char *errorString;
if (printBlobUtf8) {
errorString = reinterpret_cast<char*>(printBlobUtf8->GetBufferPointer());
errorString[printBlobUtf8->GetBufferSize() - 1] = 0;
debug_printf("== VALIDATION ERROR =============================================\n%s\n"
"== END ==========================================================\n",
errorString);
}
return false;
}
return true;
}
void d3d12_validation_tools::disassemble(struct blob *dxil)
{
if (!compiler) {
fprintf(stderr, "D3D12: No Disassembler\n");
return;
}
ShaderBlob source(dxil);
IDxcBlobEncoding* pDisassembly = nullptr;
if (FAILED(compiler->Disassemble(&source, &pDisassembly))) {
fprintf(stderr, "D3D12: Disassembler failed\n");
return;
}
ComPtr<IDxcBlobEncoding> dissassably(pDisassembly);
ComPtr<IDxcBlobEncoding> blobUtf8;
library->GetBlobAsUtf8(pDisassembly, blobUtf8.GetAddressOf());
if (!blobUtf8) {
fprintf(stderr, "D3D12: Unable to get utf8 encoding\n");
return;
}
char *disassembly = reinterpret_cast<char*>(blobUtf8->GetBufferPointer());
disassembly[blobUtf8->GetBufferSize() - 1] = 0;
fprintf(stderr, "== BEGIN SHADER ============================================\n"
"%s\n"
"== END SHADER ==============================================\n",
disassembly);
}

View file

@ -59,10 +59,6 @@ enum d3d12_state_var {
#define D3D12_MAX_POINT_SIZE 255.0f
struct d3d12_validation_tools *d3d12_validator_create();
void d3d12_validator_destroy(struct d3d12_validation_tools *validator);
const void *
d3d12_get_compiler_options(struct pipe_screen *screen,
enum pipe_shader_ir ir,

View file

@ -57,12 +57,19 @@ extern "C" {
#include <string.h>
#ifdef _WIN32
#include "dxil_validator.h"
#endif
static void
d3d12_context_destroy(struct pipe_context *pctx)
{
struct d3d12_context *ctx = d3d12_context(pctx);
if (ctx->validation_tools)
d3d12_validator_destroy(ctx->validation_tools);
#ifdef _WIN32
if (ctx->dxil_validator)
dxil_destroy_validator(ctx->dxil_validator);
#endif
if (ctx->timestamp_query)
pctx->destroy_query(pctx, ctx->timestamp_query);
@ -2511,7 +2518,11 @@ d3d12_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
}
d3d12_init_null_sampler(ctx);
ctx->validation_tools = d3d12_validator_create();
#ifdef _WIN32
if (!(d3d12_debug & D3D12_DEBUG_EXPERIMENTAL) ||
(d3d12_debug & D3D12_DEBUG_DISASS))
ctx->dxil_validator = dxil_create_validator(NULL);
#endif
ctx->blitter = util_blitter_create(&ctx->base);
if (!ctx->blitter)

View file

@ -151,7 +151,10 @@ struct d3d12_shader_state {
struct blitter_context;
struct primconvert_context;
struct d3d12_validation_tools;
#ifdef _WIN32
struct dxil_validator;
#endif
#ifdef __cplusplus
class ResourceStateManager;
@ -246,7 +249,9 @@ struct d3d12_context {
struct d3d12_descriptor_handle null_sampler;
PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE D3D12SerializeVersionedRootSignature;
struct d3d12_validation_tools *validation_tools;
#ifdef _WIN32
struct dxil_validator *dxil_validator;
#endif
struct d3d12_resource *current_predication;
bool predication_condition;

View file

@ -813,14 +813,7 @@ create_device(IUnknown *adapter)
}
#ifdef _WIN32
if (!(d3d12_debug & D3D12_DEBUG_EXPERIMENTAL)) {
struct d3d12_validation_tools *validation_tools = d3d12_validator_create();
if (!validation_tools) {
debug_printf("D3D12: failed to initialize validator with experimental shader models disabled\n");
return nullptr;
}
d3d12_validator_destroy(validation_tools);
} else
if (d3d12_debug & D3D12_DEBUG_EXPERIMENTAL)
#endif
{
D3D12EnableExperimentalFeatures = (PFN_D3D12ENABLEEXPERIMENTALFEATURES)util_dl_get_proc_address(d3d12_mod, "D3D12EnableExperimentalFeatures");