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
lower_discard_if_instr(nir_intrinsic_instr * instr,nir_builder * b)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    /* a shader like this (shaders@glsl-fs-discard-04):
56 
57       uniform int j, k;
58 
59       void main()
60       {
61        for (int i = 0; i < j; i++) {
62         if (i > k)
63          continue;
64         discard;
65        }
66        gl_FragColor = vec4(0.0, 1.0, 0.0, 0.0);
67       }
68 
69 
70 
71       will generate nir like:
72 
73       loop   {
74          //snip
75          if   ssa_11   {
76             block   block_5:
77             /   preds:   block_4   /
78             vec1   32   ssa_17   =   iadd   ssa_50,   ssa_31
79             /   succs:   block_7   /
80          }   else   {
81             block   block_6:
82             /   preds:   block_4   /
83             intrinsic   discard   ()   () <-- not last instruction
84             vec1   32   ssa_23   =   iadd   ssa_50,   ssa_31 <-- dead code loop itr increment
85             /   succs:   block_7   /
86          }
87          //snip
88       }
89 
90       which means that we can't assert like this:
91 
92       assert(instr->intrinsic != nir_intrinsic_discard ||
93              nir_block_last_instr(instr->instr.block) == &instr->instr);
94 
95 
96       and it's unnecessary anyway since post-vtn optimizing will dce the instructions following the discard
97     */
98 
99    return false;
100 }
101 
102 static bool
lower_discard_if(nir_shader * shader)103 lower_discard_if(nir_shader *shader)
104 {
105    bool progress = false;
106 
107    nir_foreach_function(function, shader) {
108       if (function->impl) {
109          nir_builder builder;
110          nir_builder_init(&builder, function->impl);
111          nir_foreach_block(block, function->impl) {
112             nir_foreach_instr_safe(instr, block) {
113                if (instr->type == nir_instr_type_intrinsic)
114                   progress |= lower_discard_if_instr(
115                                                   nir_instr_as_intrinsic(instr),
116                                                   &builder);
117             }
118          }
119 
120          nir_metadata_preserve(function->impl, nir_metadata_dominance);
121       }
122    }
123 
124    return progress;
125 }
126 
127 static const struct nir_shader_compiler_options nir_options = {
128    .lower_all_io_to_temps = true,
129    .lower_ffma = true,
130    .lower_fdph = true,
131    .lower_flrp32 = true,
132    .lower_fpow = true,
133    .lower_fsat = true,
134    .lower_extract_byte = true,
135    .lower_extract_word = true,
136    .lower_mul_high = true,
137    .lower_rotate = true,
138    .lower_uadd_carry = true,
139 };
140 
141 const void *
zink_get_compiler_options(struct pipe_screen * screen,enum pipe_shader_ir ir,enum pipe_shader_type shader)142 zink_get_compiler_options(struct pipe_screen *screen,
143                           enum pipe_shader_ir ir,
144                           enum pipe_shader_type shader)
145 {
146    assert(ir == PIPE_SHADER_IR_NIR);
147    return &nir_options;
148 }
149 
150 struct nir_shader *
zink_tgsi_to_nir(struct pipe_screen * screen,const struct tgsi_token * tokens)151 zink_tgsi_to_nir(struct pipe_screen *screen, const struct tgsi_token *tokens)
152 {
153    if (zink_debug & ZINK_DEBUG_TGSI) {
154       fprintf(stderr, "TGSI shader:\n---8<---\n");
155       tgsi_dump_to_file(tokens, 0, stderr);
156       fprintf(stderr, "---8<---\n\n");
157    }
158 
159    return tgsi_to_nir(tokens, screen, false);
160 }
161 
162 static void
optimize_nir(struct nir_shader * s)163 optimize_nir(struct nir_shader *s)
164 {
165    bool progress;
166    do {
167       progress = false;
168       NIR_PASS_V(s, nir_lower_vars_to_ssa);
169       NIR_PASS(progress, s, nir_copy_prop);
170       NIR_PASS(progress, s, nir_opt_remove_phis);
171       NIR_PASS(progress, s, nir_opt_dce);
172       NIR_PASS(progress, s, nir_opt_dead_cf);
173       NIR_PASS(progress, s, nir_opt_cse);
174       NIR_PASS(progress, s, nir_opt_peephole_select, 8, true, true);
175       NIR_PASS(progress, s, nir_opt_algebraic);
176       NIR_PASS(progress, s, nir_opt_constant_folding);
177       NIR_PASS(progress, s, nir_opt_undef);
178       NIR_PASS(progress, s, zink_nir_lower_b2b);
179    } while (progress);
180 }
181 
182 /* check for a genuine gl_PointSize output vs one from nir_lower_point_size_mov */
183 static bool
check_psiz(struct nir_shader * s)184 check_psiz(struct nir_shader *s)
185 {
186    nir_foreach_shader_out_variable(var, s) {
187       if (var->data.location == VARYING_SLOT_PSIZ) {
188          /* genuine PSIZ outputs will have this set */
189          return !!var->data.explicit_location;
190       }
191    }
192    return false;
193 }
194 
195 /* semi-copied from iris */
196 static void
update_so_info(struct pipe_stream_output_info * so_info,uint64_t outputs_written,bool have_psiz)197 update_so_info(struct pipe_stream_output_info *so_info,
198                uint64_t outputs_written, bool have_psiz)
199 {
200    uint8_t reverse_map[64] = {};
201    unsigned slot = 0;
202    while (outputs_written) {
203       int bit = u_bit_scan64(&outputs_written);
204       /* PSIZ from nir_lower_point_size_mov breaks stream output, so always skip it */
205       if (bit == VARYING_SLOT_PSIZ && !have_psiz)
206          continue;
207       reverse_map[slot++] = bit;
208    }
209 
210    for (unsigned i = 0; i < so_info->num_outputs; i++) {
211       struct pipe_stream_output *output = &so_info->output[i];
212 
213       /* Map Gallium's condensed "slots" back to real VARYING_SLOT_* enums */
214       output->register_index = reverse_map[output->register_index];
215    }
216 }
217 
218 struct zink_shader *
zink_compile_nir(struct zink_screen * screen,struct nir_shader * nir,const struct pipe_stream_output_info * so_info)219 zink_compile_nir(struct zink_screen *screen, struct nir_shader *nir,
220                  const struct pipe_stream_output_info *so_info)
221 {
222    struct zink_shader *ret = CALLOC_STRUCT(zink_shader);
223    bool have_psiz = false;
224 
225    ret->programs = _mesa_pointer_set_create(NULL);
226 
227    NIR_PASS_V(nir, nir_lower_uniforms_to_ubo, 1);
228    NIR_PASS_V(nir, nir_lower_clip_halfz);
229    if (nir->info.stage == MESA_SHADER_VERTEX)
230       have_psiz = check_psiz(nir);
231    NIR_PASS_V(nir, nir_lower_regs_to_ssa);
232    optimize_nir(nir);
233    NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_function_temp, NULL);
234    NIR_PASS_V(nir, lower_discard_if);
235    NIR_PASS_V(nir, nir_lower_fragcolor);
236    NIR_PASS_V(nir, nir_convert_from_ssa, true);
237 
238    if (zink_debug & ZINK_DEBUG_NIR) {
239       fprintf(stderr, "NIR shader:\n---8<---\n");
240       nir_print_shader(nir, stderr);
241       fprintf(stderr, "---8<---\n");
242    }
243 
244    ret->num_bindings = 0;
245    nir_foreach_variable_with_modes(var, nir, nir_var_uniform |
246                                              nir_var_mem_ubo) {
247       if (var->data.mode == nir_var_mem_ubo) {
248          int binding = zink_binding(nir->info.stage,
249                                     VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
250                                     var->data.binding);
251          ret->bindings[ret->num_bindings].index = var->data.binding;
252          ret->bindings[ret->num_bindings].binding = binding;
253          ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
254          ret->num_bindings++;
255       } else {
256          assert(var->data.mode == nir_var_uniform);
257          if (glsl_type_is_array(var->type) &&
258              glsl_type_is_sampler(glsl_get_array_element(var->type))) {
259             for (int i = 0; i < glsl_get_length(var->type); ++i) {
260                int binding = zink_binding(nir->info.stage,
261                                           VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
262                                           var->data.binding + i);
263                ret->bindings[ret->num_bindings].index = var->data.binding + i;
264                ret->bindings[ret->num_bindings].binding = binding;
265                ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
266                ret->num_bindings++;
267             }
268          } else if (glsl_type_is_sampler(var->type)) {
269             int binding = zink_binding(nir->info.stage,
270                                        VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
271                                        var->data.binding);
272             ret->bindings[ret->num_bindings].index = var->data.binding;
273             ret->bindings[ret->num_bindings].binding = binding;
274             ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
275             ret->num_bindings++;
276          }
277       }
278    }
279 
280    ret->info = nir->info;
281    if (so_info) {
282       memcpy(&ret->stream_output, so_info, sizeof(ret->stream_output));
283       update_so_info(&ret->stream_output, nir->info.outputs_written, have_psiz);
284    }
285 
286    struct spirv_shader *spirv = nir_to_spirv(nir, so_info, so_info ? &ret->stream_output : NULL);
287    assert(spirv);
288 
289    if (zink_debug & ZINK_DEBUG_SPIRV) {
290       char buf[256];
291       static int i;
292       snprintf(buf, sizeof(buf), "dump%02d.spv", i++);
293       FILE *fp = fopen(buf, "wb");
294       if (fp) {
295          fwrite(spirv->words, sizeof(uint32_t), spirv->num_words, fp);
296          fclose(fp);
297          fprintf(stderr, "wrote '%s'...\n", buf);
298       }
299    }
300 
301    VkShaderModuleCreateInfo smci = {};
302    smci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
303    smci.codeSize = spirv->num_words * sizeof(uint32_t);
304    smci.pCode = spirv->words;
305 
306    if (vkCreateShaderModule(screen->dev, &smci, NULL, &ret->shader_module) != VK_SUCCESS)
307       return NULL;
308 
309    free(spirv->words);
310    free(spirv);
311 
312    return ret;
313 }
314 
315 void
zink_shader_free(struct zink_context * ctx,struct zink_shader * shader)316 zink_shader_free(struct zink_context *ctx, struct zink_shader *shader)
317 {
318    struct zink_screen *screen = zink_screen(ctx->base.screen);
319    vkDestroyShaderModule(screen->dev, shader->shader_module, NULL);
320    set_foreach(shader->programs, entry) {
321       struct zink_gfx_program *prog = (void*)entry->key;
322       _mesa_hash_table_remove_key(ctx->program_cache, prog->stages);
323       zink_destroy_gfx_program(screen, prog);
324    }
325    _mesa_set_destroy(shader->programs, NULL);
326    FREE(shader);
327 }
328