Mesa (main): microsoft/compiler: add common dxil-validator API
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Thu Apr 7 00:14:47 UTC 2022
Module: Mesa
Branch: main
Commit: 193cf76c095ccbaa7f5a0a08a8fa0e9abe080abc
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=193cf76c095ccbaa7f5a0a08a8fa0e9abe080abc
Author: Erik Faye-Lund <erik.faye-lund at collabora.com>
Date: Tue Apr 5 10:39:01 2022 +0200
microsoft/compiler: add common dxil-validator API
This API is only available on Windows, which is the only OS where DXIL
validation is a requirement, and where DXIL.dll (and dxcompiler.dll) are
available.
Reviewed-by: Boris Brezillon <boris.brezillon at collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15751>
---
src/microsoft/compiler/dxil_validator.cpp | 272 ++++++++++++++++++++++++++++++
src/microsoft/compiler/dxil_validator.h | 50 ++++++
src/microsoft/compiler/meson.build | 4 +
3 files changed, 326 insertions(+)
diff --git a/src/microsoft/compiler/dxil_validator.cpp b/src/microsoft/compiler/dxil_validator.cpp
new file mode 100644
index 00000000000..0e8d5da119c
--- /dev/null
+++ b/src/microsoft/compiler/dxil_validator.cpp
@@ -0,0 +1,272 @@
+#include "dxil_validator.h"
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+
+#include <windows.h>
+#include <unknwn.h>
+
+#include "util/ralloc.h"
+#include "util/u_debug.h"
+
+#include "dxcapi.h"
+
+#include <wrl/client.h>
+using Microsoft::WRL::ComPtr;
+
+struct dxil_validator {
+ HMODULE dxil_mod;
+ HMODULE dxcompiler_mod;
+
+ IDxcValidator *dxc_validator;
+ IDxcLibrary *dxc_library;
+ IDxcCompiler *dxc_compiler;
+};
+
+extern "C" extern IMAGE_DOS_HEADER __ImageBase;
+
+static HMODULE
+load_dxil_mod()
+{
+ /* First, try to load DXIL.dll from the default search-path */
+ HMODULE mod = LoadLibraryA("DXIL.dll");
+ if (mod)
+ return mod;
+
+ /* If that fails, try to load it next to the current module, so we can
+ * ship DXIL.dll next to the GLon12 DLL.
+ */
+
+ char self_path[MAX_PATH];
+ uint32_t path_size = GetModuleFileNameA((HINSTANCE)&__ImageBase,
+ self_path, sizeof(self_path));
+ if (!path_size || path_size == sizeof(self_path)) {
+ debug_printf("DXIL: Unable to get path to self");
+ return NULL;
+ }
+
+ auto last_slash = strrchr(self_path, '\\');
+ if (!last_slash) {
+ debug_printf("DXIL: Unable to get path to self");
+ return NULL;
+ }
+
+ *(last_slash + 1) = '\0';
+ if (strcat_s(self_path, "DXIL.dll") != 0) {
+ debug_printf("DXIL: Unable to get path to DXIL.dll next to self");
+ return NULL;
+ }
+
+ return LoadLibraryA(self_path);
+}
+
+static IDxcValidator *
+create_dxc_validator(HMODULE dxil_mod)
+{
+ DxcCreateInstanceProc dxil_create_func =
+ (DxcCreateInstanceProc)GetProcAddress(dxil_mod, "DxcCreateInstance");
+ if (!dxil_create_func) {
+ debug_printf("DXIL: Failed to load DxcCreateInstance from DXIL.dll\n");
+ return NULL;
+ }
+
+ IDxcValidator *dxc_validator;
+ HRESULT hr = dxil_create_func(CLSID_DxcValidator,
+ IID_PPV_ARGS(&dxc_validator));
+ if (FAILED(hr)) {
+ debug_printf("DXIL: Failed to create validator\n");
+ return NULL;
+ }
+
+ return dxc_validator;
+}
+
+struct dxil_validator *
+dxil_create_validator(const void *ctx)
+{
+ struct dxil_validator *val = rzalloc(ctx, struct dxil_validator);
+ if (!val)
+ return NULL;
+
+ /* Load DXIL.dll. This is a hard requirement on Windows, so we error
+ * out if this fails.
+ */
+ val->dxil_mod = load_dxil_mod();
+ if (!val->dxil_mod) {
+ debug_printf("DXIL: Failed to load DXIL.dll\n");
+ goto fail;
+ }
+
+ /* Create IDxcValidator. This is a hard requirement on Windows, so we
+ * error out if this fails.
+ */
+ val->dxc_validator = create_dxc_validator(val->dxil_mod);
+ if (!val->dxc_validator)
+ goto fail;
+
+ /* Try to load dxcompiler.dll. This is just used for diagnostics, and
+ * will fail on most end-users install. So we do not error out if this
+ * fails.
+ */
+ val->dxcompiler_mod = LoadLibraryA("dxcompiler.dll");
+ if (val->dxcompiler_mod) {
+ /* If we managed to load dxcompiler.dll, but either don't find
+ * DxcCreateInstance, or fail to create IDxcLibrary or
+ * IDxcCompiler, this is a good indication that the user wants
+ * diagnostics, but something went wrong. Print warnings to help
+ * figuring out what's wrong, but do not treat it as an error.
+ */
+ DxcCreateInstanceProc compiler_create_func =
+ (DxcCreateInstanceProc)GetProcAddress(val->dxcompiler_mod,
+ "DxcCreateInstance");
+ if (!compiler_create_func) {
+ debug_printf("DXIL: Failed to load DxcCreateInstance from "
+ "dxcompiler.dll\n");
+ } else {
+ if (FAILED(compiler_create_func(CLSID_DxcLibrary,
+ IID_PPV_ARGS(&val->dxc_library))))
+ debug_printf("DXIL: Unable to create IDxcLibrary instance\n");
+
+ if (FAILED(compiler_create_func(CLSID_DxcCompiler,
+ IID_PPV_ARGS(&val->dxc_compiler))))
+ debug_printf("DXIL: Unable to create IDxcCompiler instance\n");
+ }
+ }
+
+ return val;
+
+fail:
+ if (val->dxil_mod)
+ FreeLibrary(val->dxil_mod);
+
+ ralloc_free(val);
+ return NULL;
+}
+
+void
+dxil_destroy_validator(struct dxil_validator *val)
+{
+ /* if we have a validator, we have these */
+ FreeLibrary(val->dxil_mod);
+ val->dxc_validator->Release();
+
+ if (val->dxcompiler_mod) {
+ if (val->dxc_library)
+ val->dxc_library->Release();
+
+ if (val->dxc_compiler)
+ val->dxc_compiler->Release();
+
+ FreeLibrary(val->dxcompiler_mod);
+ }
+
+ ralloc_free(val);
+}
+
+class ShaderBlob : public IDxcBlob {
+public:
+ ShaderBlob(void *data, size_t size) :
+ m_data(data),
+ m_size(size)
+ {
+ }
+
+ LPVOID STDMETHODCALLTYPE
+ GetBufferPointer(void) override
+ {
+ return m_data;
+ }
+
+ SIZE_T STDMETHODCALLTYPE
+ GetBufferSize() override
+ {
+ return m_size;
+ }
+
+ HRESULT STDMETHODCALLTYPE
+ QueryInterface(REFIID, void **) override
+ {
+ return E_NOINTERFACE;
+ }
+
+ ULONG STDMETHODCALLTYPE
+ AddRef() override
+ {
+ return 1;
+ }
+
+ ULONG STDMETHODCALLTYPE
+ Release() override
+ {
+ return 0;
+ }
+
+ void *m_data;
+ size_t m_size;
+};
+
+bool
+dxil_validate_module(struct dxil_validator *val, void *data, size_t size, char **error)
+{
+ ShaderBlob source(data, size);
+
+ ComPtr<IDxcOperationResult> result;
+ val->dxc_validator->Validate(&source, DxcValidatorFlags_InPlaceEdit,
+ &result);
+
+ HRESULT hr;
+ result->GetStatus(&hr);
+
+ if (FAILED(hr) && error) {
+ /* try to resolve error message */
+ *error = NULL;
+ if (!val->dxc_library) {
+ debug_printf("DXIL: validation failed, but lacking IDxcLibrary"
+ "from dxcompiler.dll for proper diagnostics.\n");
+ return false;
+ }
+
+ ComPtr<IDxcBlobEncoding> blob, blob_utf8;
+
+ if (FAILED(result->GetErrorBuffer(&blob)))
+ fprintf(stderr, "DXIL: IDxcOperationResult::GetErrorBuffer() failed\n");
+ else if (FAILED(val->dxc_library->GetBlobAsUtf8(blob.Get(),
+ blob_utf8.GetAddressOf())))
+ fprintf(stderr, "DXIL: IDxcLibrary::GetBlobAsUtf8() failed\n");
+ else {
+ char *str = reinterpret_cast<char *>(blob_utf8->GetBufferPointer());
+ str[blob_utf8->GetBufferSize() - 1] = 0;
+ *error = ralloc_strdup(val, str);
+ }
+ }
+
+ return SUCCEEDED(hr);
+}
+
+char *
+dxil_disasm_module(struct dxil_validator *val, void *data, size_t size)
+{
+ if (!val->dxc_compiler || !val->dxc_library) {
+ fprintf(stderr, "DXIL: disassembly requires IDxcLibrary and "
+ "IDxcCompiler from dxcompiler.dll\n");
+ return NULL;
+ }
+
+ ShaderBlob source(data, size);
+ ComPtr<IDxcBlobEncoding> blob, blob_utf8;
+
+ if (FAILED(val->dxc_compiler->Disassemble(&source, &blob))) {
+ fprintf(stderr, "DXIL: IDxcCompiler::Disassemble() failed\n");
+ return NULL;
+ }
+
+ if (FAILED(val->dxc_library->GetBlobAsUtf8(blob.Get(), blob_utf8.GetAddressOf()))) {
+ fprintf(stderr, "DXIL: IDxcLibrary::GetBlobAsUtf8() failed\n");
+ return NULL;
+ }
+
+ char *str = reinterpret_cast<char*>(blob_utf8->GetBufferPointer());
+ str[blob_utf8->GetBufferSize() - 1] = 0;
+ return ralloc_strdup(val, str);
+}
diff --git a/src/microsoft/compiler/dxil_validator.h b/src/microsoft/compiler/dxil_validator.h
new file mode 100644
index 00000000000..0a880eb155d
--- /dev/null
+++ b/src/microsoft/compiler/dxil_validator.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright © Microsoft 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_VALIDATOR_H
+#define DXIL_VALIDATOR_H
+
+struct dxil_validator;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dxil_validator *
+dxil_create_validator(const void *ctx);
+
+void
+dxil_destroy_validator(struct dxil_validator *val);
+
+bool
+dxil_validate_module(struct dxil_validator *val, void *data,
+ size_t size, char **error);
+
+char *
+dxil_disasm_module(struct dxil_validator *val, void *data, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/microsoft/compiler/meson.build b/src/microsoft/compiler/meson.build
index a04fe87b636..e8953c7c693 100644
--- a/src/microsoft/compiler/meson.build
+++ b/src/microsoft/compiler/meson.build
@@ -33,6 +33,10 @@ files_libdxil_compiler = files(
'nir_to_dxil.c',
)
+if host_machine.system() == 'windows'
+ files_libdxil_compiler += files('dxil_validator.cpp')
+endif
+
dxil_nir_algebraic_c = custom_target(
'dxil_nir_algebraic.c',
input : 'dxil_nir_algebraic.py',
More information about the mesa-commit
mailing list