radeonsi: prepare for driver-specific driconf options
[mesa.git] / src / gallium / drivers / radeonsi / si_shader_nir.c
index eec5ac15d1b15d68f65c808dd3940b6ecd81545c..fce759b003d8492c2196fcdee8397359fd7d6a27 100644 (file)
 #include "compiler/nir_types.h"
 
 
+static int
+type_size(const struct glsl_type *type)
+{
+   return glsl_count_attribute_slots(type, false);
+}
+
 static void scan_instruction(struct tgsi_shader_info *info,
                             nir_instr *instr)
 {
@@ -313,6 +319,82 @@ void si_nir_scan_shader(const struct nir_shader *nir,
        }
 }
 
+/**
+ * Perform "lowering" operations on the NIR that are run once when the shader
+ * selector is created.
+ */
+void
+si_lower_nir(struct si_shader_selector* sel)
+{
+       /* Adjust the driver location of inputs and outputs. The state tracker
+        * interprets them as slots, while the ac/nir backend interprets them
+        * as individual components.
+        */
+       nir_foreach_variable(variable, &sel->nir->inputs)
+               variable->data.driver_location *= 4;
+
+       nir_foreach_variable(variable, &sel->nir->outputs) {
+               variable->data.driver_location *= 4;
+
+               if (sel->nir->stage == MESA_SHADER_FRAGMENT) {
+                       if (variable->data.location == FRAG_RESULT_DEPTH)
+                               variable->data.driver_location += 2;
+                       else if (variable->data.location == FRAG_RESULT_STENCIL)
+                               variable->data.driver_location += 1;
+               }
+       }
+
+       /* Perform lowerings (and optimizations) of code.
+        *
+        * Performance considerations aside, we must:
+        * - lower certain ALU operations
+        * - ensure constant offsets for texture instructions are folded
+        *   and copy-propagated
+        */
+       NIR_PASS_V(sel->nir, nir_lower_io, nir_var_uniform, type_size,
+                  (nir_lower_io_options)0);
+       NIR_PASS_V(sel->nir, nir_lower_uniforms_to_ubo);
+
+       NIR_PASS_V(sel->nir, nir_lower_returns);
+       NIR_PASS_V(sel->nir, nir_lower_vars_to_ssa);
+       NIR_PASS_V(sel->nir, nir_lower_alu_to_scalar);
+       NIR_PASS_V(sel->nir, nir_lower_phis_to_scalar);
+
+       static const struct nir_lower_tex_options lower_tex_options = {
+               .lower_txp = ~0u,
+       };
+       NIR_PASS_V(sel->nir, nir_lower_tex, &lower_tex_options);
+
+       bool progress;
+       do {
+               progress = false;
+
+               /* (Constant) copy propagation is needed for txf with offsets. */
+               NIR_PASS(progress, sel->nir, nir_copy_prop);
+               NIR_PASS(progress, sel->nir, nir_opt_remove_phis);
+               NIR_PASS(progress, sel->nir, nir_opt_dce);
+               if (nir_opt_trivial_continues(sel->nir)) {
+                       progress = true;
+                       NIR_PASS(progress, sel->nir, nir_copy_prop);
+                       NIR_PASS(progress, sel->nir, nir_opt_dce);
+               }
+               NIR_PASS(progress, sel->nir, nir_opt_if);
+               NIR_PASS(progress, sel->nir, nir_opt_dead_cf);
+               NIR_PASS(progress, sel->nir, nir_opt_cse);
+               NIR_PASS(progress, sel->nir, nir_opt_peephole_select, 8);
+
+               /* Needed for algebraic lowering */
+               NIR_PASS(progress, sel->nir, nir_opt_algebraic);
+               NIR_PASS(progress, sel->nir, nir_opt_constant_folding);
+
+               NIR_PASS(progress, sel->nir, nir_opt_undef);
+               NIR_PASS(progress, sel->nir, nir_opt_conditional_discard);
+               if (sel->nir->options->max_unroll_iterations) {
+                       NIR_PASS(progress, sel->nir, nir_opt_loop_unroll, 0);
+               }
+       } while (progress);
+}
+
 static void declare_nir_input_vs(struct si_shader_context *ctx,
                                 struct nir_variable *variable, unsigned rel,
                                 LLVMValueRef out[4])
@@ -342,8 +424,57 @@ static void declare_nir_input_fs(struct si_shader_context *ctx,
        (*fs_attr_idx)++;
 }
 
+static LLVMValueRef
+si_nir_load_sampler_desc(struct ac_shader_abi *abi,
+                        unsigned descriptor_set, unsigned base_index,
+                        unsigned constant_index, LLVMValueRef dynamic_index,
+                        enum ac_descriptor_type desc_type, bool image,
+                        bool write)
+{
+       struct si_shader_context *ctx = si_shader_context_from_abi(abi);
+       LLVMBuilderRef builder = ctx->ac.builder;
+       LLVMValueRef list = LLVMGetParam(ctx->main_fn, ctx->param_samplers_and_images);
+       LLVMValueRef index = dynamic_index;
+
+       assert(!descriptor_set);
+
+       if (!index)
+               index = ctx->ac.i32_0;
+
+       index = LLVMBuildAdd(builder, index,
+                            LLVMConstInt(ctx->ac.i32, base_index + constant_index, false),
+                            "");
+
+       if (image) {
+               assert(desc_type == AC_DESC_IMAGE || desc_type == AC_DESC_BUFFER);
+               assert(base_index + constant_index < ctx->num_images);
+
+               if (dynamic_index)
+                       index = si_llvm_bound_index(ctx, index, ctx->num_images);
+
+               index = LLVMBuildSub(ctx->gallivm.builder,
+                                    LLVMConstInt(ctx->i32, SI_NUM_IMAGES - 1, 0),
+                                    index, "");
+
+               /* TODO: be smarter about when we use dcc_off */
+               return si_load_image_desc(ctx, list, index, desc_type, write);
+       }
+
+       assert(base_index + constant_index < ctx->num_samplers);
+
+       if (dynamic_index)
+               index = si_llvm_bound_index(ctx, index, ctx->num_samplers);
+
+       index = LLVMBuildAdd(ctx->gallivm.builder, index,
+                            LLVMConstInt(ctx->i32, SI_NUM_IMAGES / 2, 0), "");
+
+       return si_load_sampler_desc(ctx, list, index, desc_type);
+}
+
 bool si_nir_build_llvm(struct si_shader_context *ctx, struct nir_shader *nir)
 {
+       struct tgsi_shader_info *info = &ctx->shader->selector->info;
+
        unsigned fs_attr_idx = 0;
        nir_foreach_variable(variable, &nir->inputs) {
                unsigned attrib_count = glsl_count_attribute_slots(variable->type,
@@ -366,6 +497,10 @@ bool si_nir_build_llvm(struct si_shader_context *ctx, struct nir_shader *nir)
        }
 
        ctx->abi.inputs = &ctx->inputs[0];
+       ctx->abi.load_sampler_desc = si_nir_load_sampler_desc;
+
+       ctx->num_samplers = util_last_bit(info->samplers_declared);
+       ctx->num_images = util_last_bit(info->images_declared);
 
        ac_nir_translate(&ctx->ac, &ctx->abi, nir, NULL);