zink: handle ixor in ntv
[mesa.git] / src / gallium / drivers / zink / zink_compiler.c
1 /*
2 * Copyright 2018 Collabora Ltd.
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "zink_context.h"
25 #include "zink_compiler.h"
26 #include "zink_program.h"
27 #include "zink_screen.h"
28 #include "nir_to_spirv/nir_to_spirv.h"
29
30 #include "pipe/p_state.h"
31
32 #include "nir.h"
33 #include "compiler/nir/nir_builder.h"
34
35 #include "nir/tgsi_to_nir.h"
36 #include "tgsi/tgsi_dump.h"
37 #include "tgsi/tgsi_from_mesa.h"
38
39 #include "util/u_memory.h"
40
41 static bool
42 lower_discard_if_instr(nir_intrinsic_instr *instr, nir_builder *b)
43 {
44 if (instr->intrinsic == nir_intrinsic_discard_if) {
45 b->cursor = nir_before_instr(&instr->instr);
46
47 nir_if *if_stmt = nir_push_if(b, nir_ssa_for_src(b, instr->src[0], 1));
48 nir_intrinsic_instr *discard =
49 nir_intrinsic_instr_create(b->shader, nir_intrinsic_discard);
50 nir_builder_instr_insert(b, &discard->instr);
51 nir_pop_if(b, if_stmt);
52 nir_instr_remove(&instr->instr);
53 return true;
54 }
55 assert(instr->intrinsic != nir_intrinsic_discard ||
56 nir_block_last_instr(instr->instr.block) == &instr->instr);
57
58 return false;
59 }
60
61 static bool
62 lower_discard_if(nir_shader *shader)
63 {
64 bool progress = false;
65
66 nir_foreach_function(function, shader) {
67 if (function->impl) {
68 nir_builder builder;
69 nir_builder_init(&builder, function->impl);
70 nir_foreach_block(block, function->impl) {
71 nir_foreach_instr_safe(instr, block) {
72 if (instr->type == nir_instr_type_intrinsic)
73 progress |= lower_discard_if_instr(
74 nir_instr_as_intrinsic(instr),
75 &builder);
76 }
77 }
78
79 nir_metadata_preserve(function->impl, nir_metadata_dominance);
80 }
81 }
82
83 return progress;
84 }
85
86 static const struct nir_shader_compiler_options nir_options = {
87 .lower_all_io_to_temps = true,
88 .lower_ffma = true,
89 .lower_fdph = true,
90 .lower_flrp32 = true,
91 .lower_fpow = true,
92 .lower_fsat = true,
93 .lower_extract_byte = true,
94 .lower_extract_word = true,
95 };
96
97 const void *
98 zink_get_compiler_options(struct pipe_screen *screen,
99 enum pipe_shader_ir ir,
100 enum pipe_shader_type shader)
101 {
102 assert(ir == PIPE_SHADER_IR_NIR);
103 return &nir_options;
104 }
105
106 struct nir_shader *
107 zink_tgsi_to_nir(struct pipe_screen *screen, const struct tgsi_token *tokens)
108 {
109 if (zink_debug & ZINK_DEBUG_TGSI) {
110 fprintf(stderr, "TGSI shader:\n---8<---\n");
111 tgsi_dump_to_file(tokens, 0, stderr);
112 fprintf(stderr, "---8<---\n\n");
113 }
114
115 return tgsi_to_nir(tokens, screen, false);
116 }
117
118 static void
119 optimize_nir(struct nir_shader *s)
120 {
121 bool progress;
122 do {
123 progress = false;
124 NIR_PASS_V(s, nir_lower_vars_to_ssa);
125 NIR_PASS(progress, s, nir_copy_prop);
126 NIR_PASS(progress, s, nir_opt_remove_phis);
127 NIR_PASS(progress, s, nir_opt_dce);
128 NIR_PASS(progress, s, nir_opt_dead_cf);
129 NIR_PASS(progress, s, nir_opt_cse);
130 NIR_PASS(progress, s, nir_opt_peephole_select, 8, true, true);
131 NIR_PASS(progress, s, nir_opt_algebraic);
132 NIR_PASS(progress, s, nir_opt_constant_folding);
133 NIR_PASS(progress, s, nir_opt_undef);
134 NIR_PASS(progress, s, zink_nir_lower_b2b);
135 } while (progress);
136 }
137
138 /* check for a genuine gl_PointSize output vs one from nir_lower_point_size_mov */
139 static bool
140 check_psiz(struct nir_shader *s)
141 {
142 nir_foreach_variable(var, &s->outputs) {
143 if (var->data.location == VARYING_SLOT_PSIZ) {
144 /* genuine PSIZ outputs will have this set */
145 return !!var->data.explicit_location;
146 }
147 }
148 return false;
149 }
150
151 /* semi-copied from iris */
152 static void
153 update_so_info(struct pipe_stream_output_info *so_info,
154 uint64_t outputs_written, bool have_psiz)
155 {
156 uint8_t reverse_map[64] = {};
157 unsigned slot = 0;
158 while (outputs_written) {
159 int bit = u_bit_scan64(&outputs_written);
160 /* PSIZ from nir_lower_point_size_mov breaks stream output, so always skip it */
161 if (bit == VARYING_SLOT_PSIZ && !have_psiz)
162 continue;
163 reverse_map[slot++] = bit;
164 }
165
166 for (unsigned i = 0; i < so_info->num_outputs; i++) {
167 struct pipe_stream_output *output = &so_info->output[i];
168
169 /* Map Gallium's condensed "slots" back to real VARYING_SLOT_* enums */
170 output->register_index = reverse_map[output->register_index];
171 }
172 }
173
174 struct zink_shader *
175 zink_compile_nir(struct zink_screen *screen, struct nir_shader *nir,
176 const struct pipe_stream_output_info *so_info)
177 {
178 struct zink_shader *ret = CALLOC_STRUCT(zink_shader);
179 bool have_psiz = false;
180
181 ret->programs = _mesa_pointer_set_create(NULL);
182
183 NIR_PASS_V(nir, nir_lower_uniforms_to_ubo, 1);
184 NIR_PASS_V(nir, nir_lower_clip_halfz);
185 if (nir->info.stage == MESA_SHADER_VERTEX)
186 have_psiz = check_psiz(nir);
187 NIR_PASS_V(nir, nir_lower_regs_to_ssa);
188 optimize_nir(nir);
189 NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_function_temp, NULL);
190 NIR_PASS_V(nir, lower_discard_if);
191 NIR_PASS_V(nir, nir_convert_from_ssa, true);
192
193 if (zink_debug & ZINK_DEBUG_NIR) {
194 fprintf(stderr, "NIR shader:\n---8<---\n");
195 nir_print_shader(nir, stderr);
196 fprintf(stderr, "---8<---\n");
197 }
198
199 ret->num_bindings = 0;
200 nir_foreach_variable(var, &nir->uniforms) {
201 if (var->data.mode == nir_var_mem_ubo) {
202 int binding = zink_binding(nir->info.stage,
203 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
204 var->data.binding);
205 ret->bindings[ret->num_bindings].index = var->data.binding;
206 ret->bindings[ret->num_bindings].binding = binding;
207 ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
208 ret->num_bindings++;
209 } else {
210 assert(var->data.mode == nir_var_uniform);
211 if (glsl_type_is_array(var->type) &&
212 glsl_type_is_sampler(glsl_get_array_element(var->type))) {
213 for (int i = 0; i < glsl_get_length(var->type); ++i) {
214 int binding = zink_binding(nir->info.stage,
215 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
216 var->data.binding + i);
217 ret->bindings[ret->num_bindings].index = var->data.binding + i;
218 ret->bindings[ret->num_bindings].binding = binding;
219 ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
220 ret->num_bindings++;
221 }
222 } else if (glsl_type_is_sampler(var->type)) {
223 int binding = zink_binding(nir->info.stage,
224 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
225 var->data.binding);
226 ret->bindings[ret->num_bindings].index = var->data.binding;
227 ret->bindings[ret->num_bindings].binding = binding;
228 ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
229 ret->num_bindings++;
230 }
231 }
232 }
233
234 ret->info = nir->info;
235 if (so_info) {
236 memcpy(&ret->stream_output, so_info, sizeof(ret->stream_output));
237 update_so_info(&ret->stream_output, nir->info.outputs_written, have_psiz);
238 }
239
240 struct spirv_shader *spirv = nir_to_spirv(nir, so_info, so_info ? &ret->stream_output : NULL);
241 assert(spirv);
242
243 if (zink_debug & ZINK_DEBUG_SPIRV) {
244 char buf[256];
245 static int i;
246 snprintf(buf, sizeof(buf), "dump%02d.spv", i++);
247 FILE *fp = fopen(buf, "wb");
248 if (fp) {
249 fwrite(spirv->words, sizeof(uint32_t), spirv->num_words, fp);
250 fclose(fp);
251 fprintf(stderr, "wrote '%s'...\n", buf);
252 }
253 }
254
255 VkShaderModuleCreateInfo smci = {};
256 smci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
257 smci.codeSize = spirv->num_words * sizeof(uint32_t);
258 smci.pCode = spirv->words;
259
260 if (vkCreateShaderModule(screen->dev, &smci, NULL, &ret->shader_module) != VK_SUCCESS)
261 return NULL;
262
263 return ret;
264 }
265
266 void
267 zink_shader_free(struct zink_screen *screen, struct zink_shader *shader)
268 {
269 vkDestroyShaderModule(screen->dev, shader->shader_module, NULL);
270 set_foreach(shader->programs, entry) {
271 zink_gfx_program_remove_shader((void*)entry->key, shader);
272 }
273 _mesa_set_destroy(shader->programs, NULL);
274 FREE(shader);
275 }