From 37c366e2830245511d6364b818adc838fc879401 Mon Sep 17 00:00:00 2001 From: Enrico Galli Date: Wed, 3 Nov 2021 11:18:30 -0700 Subject: [PATCH] microsoft/spirv_to_dxil: Add DXIL validation to spirv2dxil Reviewed-by: Jesse Natalie Part-of: --- src/microsoft/spirv_to_dxil/dxil_validation.cpp | 133 ++++++++++++++++++++++++ src/microsoft/spirv_to_dxil/dxil_validation.h | 41 ++++++++ src/microsoft/spirv_to_dxil/meson.build | 2 + src/microsoft/spirv_to_dxil/spirv2dxil.c | 22 +++- 4 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 src/microsoft/spirv_to_dxil/dxil_validation.cpp create mode 100644 src/microsoft/spirv_to_dxil/dxil_validation.h diff --git a/src/microsoft/spirv_to_dxil/dxil_validation.cpp b/src/microsoft/spirv_to_dxil/dxil_validation.cpp new file mode 100644 index 0000000..78a0e52 --- /dev/null +++ b/src/microsoft/spirv_to_dxil/dxil_validation.cpp @@ -0,0 +1,133 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "dxil_validation.h" + +#if DETECT_OS_WINDOWS + +#include +#include +#include + +#include "dxcapi.h" + +using Microsoft::WRL::ComPtr; + +class DxilBlob : public IDxcBlob { + public: + DxilBlob(dxil_spirv_object *data) : m_data(data) {} + + LPVOID STDMETHODCALLTYPE + GetBufferPointer() override + { + return m_data->binary.buffer; + } + + SIZE_T STDMETHODCALLTYPE + GetBufferSize() override + { + return m_data->binary.size; + } + + HRESULT STDMETHODCALLTYPE + QueryInterface(REFIID, void **) override + { + return E_NOINTERFACE; + } + + ULONG STDMETHODCALLTYPE + AddRef() override + { + return 1; + } + + ULONG STDMETHODCALLTYPE + Release() override + { + return 0; + } + + dxil_spirv_object *m_data; +}; + +bool +validate_dxil(dxil_spirv_object *dxil_obj) +{ + HMODULE dxil_dll = LoadLibraryA("dxil.dll"); + if (!dxil_dll) { + fprintf(stderr, "Unable to load dxil.dll\n"); + return false; + } + DxcCreateInstanceProc dxc_create_instance = + reinterpret_cast( + GetProcAddress(dxil_dll, "DxcCreateInstance")); + + bool res = false; + DxilBlob blob(dxil_obj); + // Creating a block so that ComPtrs free before we call FreeLibrary + { + ComPtr validator; + if (FAILED(dxc_create_instance(CLSID_DxcValidator, + IID_PPV_ARGS(&validator)))) { + fprintf(stderr, "Failed to create DxcValidator instance \n"); + FreeLibrary(dxil_dll); + return false; + } + + ComPtr result; + validator->Validate(&blob, DxcValidatorFlags_InPlaceEdit, &result); + HRESULT status; + result->GetStatus(&status); + if (FAILED(status)) { + ComPtr error; + result->GetErrorBuffer(&error); + BOOL known = false; + uint32_t cp = 0; + error->GetEncoding(&known, &cp); + fprintf(stderr, "DXIL: "); + if (cp == CP_UTF8 || cp == CP_ACP) { + fprintf(stderr, "%s\n", + static_cast(error->GetBufferPointer())); + } else { + fwprintf(stderr, L"%ls\n", + static_cast(error->GetBufferPointer())); + } + } else { + res = true; + } + } + + FreeLibrary(dxil_dll); + return res; +} + +#else + +bool +validate_dxil(dxil_spirv_object *dxil_obj) +{ + fprintf(stderr, "DXIL validation only available in Windows.\n"); + return false; +} + +#endif diff --git a/src/microsoft/spirv_to_dxil/dxil_validation.h b/src/microsoft/spirv_to_dxil/dxil_validation.h new file mode 100644 index 0000000..fcb58f4 --- /dev/null +++ b/src/microsoft/spirv_to_dxil/dxil_validation.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2021 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef DXIL_VALIDATION_H +#define DXIL_VALIDATION_H + +#include "spirv_to_dxil.h" +#include "util/detect_os.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +validate_dxil(struct dxil_spirv_object *dxil_obj); + +#ifdef __cplusplus +} +#endif + +#endif /* DXIL_VALIDATION_H */ diff --git a/src/microsoft/spirv_to_dxil/meson.build b/src/microsoft/spirv_to_dxil/meson.build index d3e32b9..1033d28 100644 --- a/src/microsoft/spirv_to_dxil/meson.build +++ b/src/microsoft/spirv_to_dxil/meson.build @@ -38,6 +38,8 @@ spirv_to_dxil = executable( 'spirv2dxil', files( 'spirv2dxil.c', + 'dxil_validation.h', + 'dxil_validation.cpp', ), dependencies : [idep_nir, idep_libdxil_compiler, idep_getopt], include_directories : [inc_include, inc_src, inc_compiler, inc_gallium], diff --git a/src/microsoft/spirv_to_dxil/spirv2dxil.c b/src/microsoft/spirv_to_dxil/spirv2dxil.c index 858f58c..941d759 100644 --- a/src/microsoft/spirv_to_dxil/spirv2dxil.c +++ b/src/microsoft/spirv_to_dxil/spirv2dxil.c @@ -29,6 +29,7 @@ */ #include "nir_to_dxil.h" +#include "dxil_validation.h" #include "spirv/nir_spirv.h" #include "spirv_to_dxil.h" @@ -68,16 +69,20 @@ main(int argc, char **argv) char *entry_point = "main"; char *output_file = ""; int ch; - + bool validate = false; + static struct option long_options[] = { {"stage", required_argument, 0, 's'}, {"entry", required_argument, 0, 'e'}, {"output", required_argument, 0, 'o'}, + {"validate", no_argument, 0, 'v'}, {0, 0, 0, 0}}; - while ((ch = getopt_long(argc, argv, "s:e:o:", long_options, NULL)) != + + while ((ch = getopt_long(argc, argv, "s:e:o:v", long_options, NULL)) != -1) { - switch (ch) { + switch(ch) + { case 's': shader_stage = stage_to_enum(optarg); if (shader_stage == MESA_SHADER_NONE) { @@ -91,6 +96,9 @@ main(int argc, char **argv) case 'o': output_file = optarg; break; + case 'v': + validate = true; + break; default: fprintf(stderr, "Unrecognized option.\n"); return 1; @@ -132,6 +140,14 @@ main(int argc, char **argv) if (spirv_to_dxil((uint32_t *)file_contents, word_count, NULL, 0, (dxil_spirv_shader_stage)shader_stage, entry_point, &conf, &obj)) { + + if (validate && !validate_dxil(&obj)) { + fprintf(stderr, "Failed to validate DXIL\n"); + spirv_to_dxil_free(&obj); + free(file_contents); + return 1; + } + FILE *file = fopen(output_file, "wb"); if (!file) { fprintf(stderr, "Failed to open %s, %s\n", output_file, -- 2.7.4