1 /*
2 * Copyright © Microsoft Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "dxil_spirv_nir.h"
25 #include "spirv_to_dxil.h"
26 #include "dxil_nir.h"
27 #include "nir_to_dxil.h"
28 #include "shader_enums.h"
29 #include "spirv/nir_spirv.h"
30 #include "util/blob.h"
31
32 #include "git_sha1.h"
33 #include "vulkan/vulkan.h"
34
35 static_assert(DXIL_SPIRV_SHADER_NONE == (int)MESA_SHADER_NONE, "must match");
36 static_assert(DXIL_SPIRV_SHADER_VERTEX == (int)MESA_SHADER_VERTEX, "must match");
37 static_assert(DXIL_SPIRV_SHADER_TESS_CTRL == (int)MESA_SHADER_TESS_CTRL, "must match");
38 static_assert(DXIL_SPIRV_SHADER_TESS_EVAL == (int)MESA_SHADER_TESS_EVAL, "must match");
39 static_assert(DXIL_SPIRV_SHADER_GEOMETRY == (int)MESA_SHADER_GEOMETRY, "must match");
40 static_assert(DXIL_SPIRV_SHADER_FRAGMENT == (int)MESA_SHADER_FRAGMENT, "must match");
41 static_assert(DXIL_SPIRV_SHADER_COMPUTE == (int)MESA_SHADER_COMPUTE, "must match");
42 static_assert(DXIL_SPIRV_SHADER_KERNEL == (int)MESA_SHADER_KERNEL, "must match");
43
44 bool
spirv_to_dxil(const uint32_t * words,size_t word_count,struct dxil_spirv_specialization * specializations,unsigned int num_specializations,dxil_spirv_shader_stage stage,const char * entry_point_name,enum dxil_validator_version validator_version_max,const struct dxil_spirv_debug_options * dgb_opts,const struct dxil_spirv_runtime_conf * conf,const struct dxil_spirv_logger * logger,struct dxil_spirv_object * out_dxil)45 spirv_to_dxil(const uint32_t *words, size_t word_count,
46 struct dxil_spirv_specialization *specializations,
47 unsigned int num_specializations, dxil_spirv_shader_stage stage,
48 const char *entry_point_name,
49 enum dxil_validator_version validator_version_max,
50 const struct dxil_spirv_debug_options *dgb_opts,
51 const struct dxil_spirv_runtime_conf *conf,
52 const struct dxil_spirv_logger *logger,
53 struct dxil_spirv_object *out_dxil)
54 {
55 if (stage == DXIL_SPIRV_SHADER_NONE || stage == DXIL_SPIRV_SHADER_KERNEL)
56 return false;
57
58 glsl_type_singleton_init_or_ref();
59
60 struct nir_to_dxil_options opts = {
61 .environment = DXIL_ENVIRONMENT_VULKAN,
62 .shader_model_max = conf->shader_model_max,
63 .validator_version_max = validator_version_max,
64 };
65
66 const struct spirv_to_nir_options *spirv_opts = dxil_spirv_nir_get_spirv_options();
67 nir_shader_compiler_options nir_options;
68 const unsigned supported_bit_sizes = 16 | 32 | 64;
69 dxil_get_nir_compiler_options(&nir_options, conf->shader_model_max, supported_bit_sizes, supported_bit_sizes);
70 // We will manually handle base_vertex when vertex_id and instance_id have
71 // have been already converted to zero-base.
72 nir_options.lower_base_vertex = !conf->zero_based_vertex_instance_id;
73
74 nir_shader *nir = spirv_to_nir(
75 words, word_count, (struct nir_spirv_specialization *)specializations,
76 num_specializations, (gl_shader_stage)stage, entry_point_name,
77 spirv_opts, &nir_options);
78 if (!nir) {
79 glsl_type_singleton_decref();
80 return false;
81 }
82
83 nir_validate_shader(nir,
84 "Validate before feeding NIR to the DXIL compiler");
85
86 dxil_spirv_nir_prep(nir);
87
88 bool requires_runtime_data;
89 dxil_spirv_nir_passes(nir, conf, &requires_runtime_data);
90
91 if (dgb_opts->dump_nir)
92 nir_print_shader(nir, stderr);
93
94 struct dxil_logger logger_inner = {.priv = logger->priv,
95 .log = logger->log};
96
97 struct blob dxil_blob;
98 if (!nir_to_dxil(nir, &opts, &logger_inner, &dxil_blob)) {
99 if (dxil_blob.allocated)
100 blob_finish(&dxil_blob);
101 ralloc_free(nir);
102 glsl_type_singleton_decref();
103 return false;
104 }
105
106 ralloc_free(nir);
107 out_dxil->metadata.requires_runtime_data = requires_runtime_data;
108 blob_finish_get_buffer(&dxil_blob, &out_dxil->binary.buffer,
109 &out_dxil->binary.size);
110
111 glsl_type_singleton_decref();
112 return true;
113 }
114
115 void
spirv_to_dxil_free(struct dxil_spirv_object * dxil)116 spirv_to_dxil_free(struct dxil_spirv_object *dxil)
117 {
118 free(dxil->binary.buffer);
119 }
120
121 uint64_t
spirv_to_dxil_get_version()122 spirv_to_dxil_get_version()
123 {
124 const char sha1[] = MESA_GIT_SHA1;
125 const char* dash = strchr(sha1, '-');
126 if (dash) {
127 return strtoull(dash + 1, NULL, 16);
128 }
129 return 0;
130 }
131