2 * Copyright 2018 Collabora Ltd.
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:
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
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.
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"
30 #include "pipe/p_state.h"
33 #include "compiler/nir/nir_builder.h"
35 #include "nir/tgsi_to_nir.h"
36 #include "tgsi/tgsi_dump.h"
37 #include "tgsi/tgsi_from_mesa.h"
39 #include "util/u_memory.h"
42 lower_discard_if_instr(nir_intrinsic_instr
*instr
, nir_builder
*b
)
44 if (instr
->intrinsic
== nir_intrinsic_discard_if
) {
45 b
->cursor
= nir_before_instr(&instr
->instr
);
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
);
55 /* a shader like this (shaders@glsl-fs-discard-04):
61 for (int i = 0; i < j; i++) {
66 gl_FragColor = vec4(0.0, 1.0, 0.0, 0.0);
71 will generate nir like:
78 vec1 32 ssa_17 = iadd ssa_50, ssa_31
83 intrinsic discard () () <-- not last instruction
84 vec1 32 ssa_23 = iadd ssa_50, ssa_31 <-- dead code loop itr increment
90 which means that we can't assert like this:
92 assert(instr->intrinsic != nir_intrinsic_discard ||
93 nir_block_last_instr(instr->instr.block) == &instr->instr);
96 and it's unnecessary anyway since post-vtn optimizing will dce the instructions following the discard
103 lower_discard_if(nir_shader
*shader
)
105 bool progress
= false;
107 nir_foreach_function(function
, shader
) {
108 if (function
->impl
) {
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
),
120 nir_metadata_preserve(function
->impl
, nir_metadata_dominance
);
127 static const struct nir_shader_compiler_options nir_options
= {
128 .lower_all_io_to_temps
= true,
131 .lower_flrp32
= 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,
142 zink_get_compiler_options(struct pipe_screen
*screen
,
143 enum pipe_shader_ir ir
,
144 enum pipe_shader_type shader
)
146 assert(ir
== PIPE_SHADER_IR_NIR
);
151 zink_tgsi_to_nir(struct pipe_screen
*screen
, const struct tgsi_token
*tokens
)
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");
159 return tgsi_to_nir(tokens
, screen
, false);
163 optimize_nir(struct nir_shader
*s
)
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
);
182 /* check for a genuine gl_PointSize output vs one from nir_lower_point_size_mov */
184 check_psiz(struct nir_shader
*s
)
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
;
195 /* semi-copied from iris */
197 update_so_info(struct pipe_stream_output_info
*so_info
,
198 uint64_t outputs_written
, bool have_psiz
)
200 uint8_t reverse_map
[64] = {};
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
)
207 reverse_map
[slot
++] = bit
;
210 for (unsigned i
= 0; i
< so_info
->num_outputs
; i
++) {
211 struct pipe_stream_output
*output
= &so_info
->output
[i
];
213 /* Map Gallium's condensed "slots" back to real VARYING_SLOT_* enums */
214 output
->register_index
= reverse_map
[output
->register_index
];
219 zink_compile_nir(struct zink_screen
*screen
, struct nir_shader
*nir
,
220 const struct pipe_stream_output_info
*so_info
)
222 struct zink_shader
*ret
= CALLOC_STRUCT(zink_shader
);
223 bool have_psiz
= false;
225 ret
->programs
= _mesa_pointer_set_create(NULL
);
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
);
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);
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");
244 ret
->num_bindings
= 0;
245 nir_foreach_variable_with_modes(var
, nir
, nir_var_uniform
|
247 if (var
->data
.mode
== nir_var_mem_ubo
) {
248 int binding
= zink_binding(nir
->info
.stage
,
249 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
,
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
;
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
;
268 } else if (glsl_type_is_sampler(var
->type
)) {
269 int binding
= zink_binding(nir
->info
.stage
,
270 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
,
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
;
280 ret
->info
= nir
->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
);
286 struct spirv_shader
*spirv
= nir_to_spirv(nir
, so_info
, so_info
? &ret
->stream_output
: NULL
);
289 if (zink_debug
& ZINK_DEBUG_SPIRV
) {
292 snprintf(buf
, sizeof(buf
), "dump%02d.spv", i
++);
293 FILE *fp
= fopen(buf
, "wb");
295 fwrite(spirv
->words
, sizeof(uint32_t), spirv
->num_words
, fp
);
297 fprintf(stderr
, "wrote '%s'...\n", buf
);
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
;
306 if (vkCreateShaderModule(screen
->dev
, &smci
, NULL
, &ret
->shader_module
) != VK_SUCCESS
)
316 zink_shader_free(struct zink_context
*ctx
, struct zink_shader
*shader
)
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
);
325 _mesa_set_destroy(shader
->programs
, NULL
);