microsoft/spirv_to_dxil: Add DXIL validation to spirv2dxil
authorEnrico Galli <enrico.galli@intel.com>
Wed, 3 Nov 2021 18:18:30 +0000 (11:18 -0700)
committerMarge Bot <emma+marge@anholt.net>
Tue, 9 Nov 2021 01:32:47 +0000 (01:32 +0000)
Reviewed-by: Jesse Natalie <jenatali@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13655>

src/microsoft/spirv_to_dxil/dxil_validation.cpp [new file with mode: 0644]
src/microsoft/spirv_to_dxil/dxil_validation.h [new file with mode: 0644]
src/microsoft/spirv_to_dxil/meson.build
src/microsoft/spirv_to_dxil/spirv2dxil.c

diff --git a/src/microsoft/spirv_to_dxil/dxil_validation.cpp b/src/microsoft/spirv_to_dxil/dxil_validation.cpp
new file mode 100644 (file)
index 0000000..78a0e52
--- /dev/null
@@ -0,0 +1,133 @@
+/*\r
+ * Copyright © 2021 Intel Corporation\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a\r
+ * copy of this software and associated documentation files (the "Software"),\r
+ * to deal in the Software without restriction, including without limitation\r
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
+ * and/or sell copies of the Software, and to permit persons to whom the\r
+ * Software is furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice (including the next\r
+ * paragraph) shall be included in all copies or substantial portions of the\r
+ * Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
+ * DEALINGS IN THE SOFTWARE.\r
+ */\r
+\r
+#include "dxil_validation.h"\r
+\r
+#if DETECT_OS_WINDOWS\r
+\r
+#include <cstdio>\r
+#include <windows.h>\r
+#include <wrl/client.h>\r
+\r
+#include "dxcapi.h"\r
+\r
+using Microsoft::WRL::ComPtr;\r
+\r
+class DxilBlob : public IDxcBlob {\r
+ public:\r
+   DxilBlob(dxil_spirv_object *data) : m_data(data) {}\r
+\r
+   LPVOID STDMETHODCALLTYPE\r
+   GetBufferPointer() override\r
+   {\r
+      return m_data->binary.buffer;\r
+   }\r
+\r
+   SIZE_T STDMETHODCALLTYPE\r
+   GetBufferSize() override\r
+   {\r
+      return m_data->binary.size;\r
+   }\r
+\r
+   HRESULT STDMETHODCALLTYPE\r
+   QueryInterface(REFIID, void **) override\r
+   {\r
+      return E_NOINTERFACE;\r
+   }\r
+\r
+   ULONG STDMETHODCALLTYPE\r
+   AddRef() override\r
+   {\r
+      return 1;\r
+   }\r
+\r
+   ULONG STDMETHODCALLTYPE\r
+   Release() override\r
+   {\r
+      return 0;\r
+   }\r
+\r
+   dxil_spirv_object *m_data;\r
+};\r
+\r
+bool\r
+validate_dxil(dxil_spirv_object *dxil_obj)\r
+{\r
+   HMODULE dxil_dll = LoadLibraryA("dxil.dll");\r
+   if (!dxil_dll) {\r
+      fprintf(stderr, "Unable to load dxil.dll\n");\r
+      return false;\r
+   }\r
+   DxcCreateInstanceProc dxc_create_instance =\r
+      reinterpret_cast<DxcCreateInstanceProc>(\r
+         GetProcAddress(dxil_dll, "DxcCreateInstance"));\r
+\r
+   bool res = false;\r
+   DxilBlob blob(dxil_obj);\r
+   // Creating a block so that ComPtrs free before we call FreeLibrary\r
+   {\r
+      ComPtr<IDxcValidator> validator;\r
+      if (FAILED(dxc_create_instance(CLSID_DxcValidator,\r
+                                     IID_PPV_ARGS(&validator)))) {\r
+         fprintf(stderr, "Failed to create DxcValidator instance \n");\r
+         FreeLibrary(dxil_dll);\r
+         return false;\r
+      }\r
+\r
+      ComPtr<IDxcOperationResult> result;\r
+      validator->Validate(&blob, DxcValidatorFlags_InPlaceEdit, &result);\r
+      HRESULT status;\r
+      result->GetStatus(&status);\r
+      if (FAILED(status)) {\r
+         ComPtr<IDxcBlobEncoding> error;\r
+         result->GetErrorBuffer(&error);\r
+         BOOL known = false;\r
+         uint32_t cp = 0;\r
+         error->GetEncoding(&known, &cp);\r
+         fprintf(stderr, "DXIL: ");\r
+         if (cp == CP_UTF8 || cp == CP_ACP) {\r
+            fprintf(stderr, "%s\n",\r
+                    static_cast<char *>(error->GetBufferPointer()));\r
+         } else {\r
+            fwprintf(stderr, L"%ls\n",\r
+                     static_cast<wchar_t *>(error->GetBufferPointer()));\r
+         }\r
+      } else {\r
+         res = true;\r
+      }\r
+   }\r
+\r
+   FreeLibrary(dxil_dll);\r
+   return res;\r
+}\r
+\r
+#else\r
+\r
+bool\r
+validate_dxil(dxil_spirv_object *dxil_obj)\r
+{\r
+   fprintf(stderr, "DXIL validation only available in Windows.\n");\r
+   return false;\r
+}\r
+\r
+#endif\r
diff --git a/src/microsoft/spirv_to_dxil/dxil_validation.h b/src/microsoft/spirv_to_dxil/dxil_validation.h
new file mode 100644 (file)
index 0000000..fcb58f4
--- /dev/null
@@ -0,0 +1,41 @@
+/*\r
+ * Copyright © 2021 Intel Corporation\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a\r
+ * copy of this software and associated documentation files (the "Software"),\r
+ * to deal in the Software without restriction, including without limitation\r
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
+ * and/or sell copies of the Software, and to permit persons to whom the\r
+ * Software is furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice (including the next\r
+ * paragraph) shall be included in all copies or substantial portions of the\r
+ * Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
+ * DEALINGS IN THE SOFTWARE.\r
+ */\r
+\r
+#ifndef DXIL_VALIDATION_H\r
+#define DXIL_VALIDATION_H\r
+\r
+#include "spirv_to_dxil.h"\r
+#include "util/detect_os.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+bool\r
+validate_dxil(struct dxil_spirv_object *dxil_obj);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* DXIL_VALIDATION_H */\r
index d3e32b9..1033d28 100644 (file)
@@ -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],
index 858f58c..941d759 100644 (file)
@@ -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,