radeonsi: move MRT color exporting into a separate function
[mesa.git] / src / gallium / drivers / radeonsi / si_shader.c
index 4b49f9d6be33971506f6d3da37adf84cc1091562..69c5d62f73d0571927dc363c57c325509c575ca3 100644 (file)
@@ -1302,18 +1302,8 @@ static void si_llvm_init_export_args(struct lp_build_tgsi_context *bld_base,
        if (si_shader_ctx->type == TGSI_PROCESSOR_FRAGMENT) {
                int cbuf = target - V_008DFC_SQ_EXP_MRT;
 
-               if (cbuf >= 0 && cbuf < 8) {
+               if (cbuf >= 0 && cbuf < 8)
                        compressed = (si_shader_ctx->shader->key.ps.export_16bpc >> cbuf) & 0x1;
-
-                       if (compressed)
-                               si_shader_ctx->shader->spi_shader_col_format |=
-                                       V_028714_SPI_SHADER_FP16_ABGR << (4 * cbuf);
-                       else
-                               si_shader_ctx->shader->spi_shader_col_format |=
-                                       V_028714_SPI_SHADER_32_ABGR << (4 * cbuf);
-
-                       si_shader_ctx->shader->cb_shader_mask |= 0xf << (4 * cbuf);
-               }
        }
 
        /* Set COMPR flag */
@@ -1333,34 +1323,19 @@ static void si_llvm_init_export_args(struct lp_build_tgsi_context *bld_base,
                                                    LLVMInt32TypeInContext(base->gallivm->context),
                                                    pack_args, 2,
                                                    LLVMReadNoneAttribute | LLVMNoUnwindAttribute);
-                       args[chan + 7] = args[chan + 5] =
+                       args[chan + 5] =
                                LLVMBuildBitCast(base->gallivm->builder,
                                                 packed,
                                                 LLVMFloatTypeInContext(base->gallivm->context),
                                                 "");
+                       args[chan + 7] = base->undef;
                }
        } else
                memcpy(&args[5], values, sizeof(values[0]) * 4);
 }
 
-/* Load from output pointers and initialize arguments for the shader export intrinsic */
-static void si_llvm_init_export_args_load(struct lp_build_tgsi_context *bld_base,
-                                         LLVMValueRef *out_ptr,
-                                         unsigned target,
-                                         LLVMValueRef *args)
-{
-       struct gallivm_state *gallivm = bld_base->base.gallivm;
-       LLVMValueRef values[4];
-       int i;
-
-       for (i = 0; i < 4; i++)
-               values[i] = LLVMBuildLoad(gallivm->builder, out_ptr[i], "");
-
-       si_llvm_init_export_args(bld_base, values, target, args);
-}
-
 static void si_alpha_test(struct lp_build_tgsi_context *bld_base,
-                         LLVMValueRef alpha_ptr)
+                         LLVMValueRef alpha)
 {
        struct si_shader_context *si_shader_ctx = si_shader_context(bld_base);
        struct gallivm_state *gallivm = bld_base->base.gallivm;
@@ -1372,8 +1347,7 @@ static void si_alpha_test(struct lp_build_tgsi_context *bld_base,
                LLVMValueRef alpha_pass =
                        lp_build_cmp(&bld_base->base,
                                     si_shader_ctx->shader->key.ps.alpha_func,
-                                    LLVMBuildLoad(gallivm->builder, alpha_ptr, ""),
-                                    alpha_ref);
+                                    alpha, alpha_ref);
                LLVMValueRef arg =
                        lp_build_select(&bld_base->base,
                                        alpha_pass,
@@ -1392,12 +1366,12 @@ static void si_alpha_test(struct lp_build_tgsi_context *bld_base,
        }
 }
 
-static void si_scale_alpha_by_sample_mask(struct lp_build_tgsi_context *bld_base,
-                                         LLVMValueRef alpha_ptr)
+static LLVMValueRef si_scale_alpha_by_sample_mask(struct lp_build_tgsi_context *bld_base,
+                                                 LLVMValueRef alpha)
 {
        struct si_shader_context *si_shader_ctx = si_shader_context(bld_base);
        struct gallivm_state *gallivm = bld_base->base.gallivm;
-       LLVMValueRef coverage, alpha;
+       LLVMValueRef coverage;
 
        /* alpha = alpha * popcount(coverage) / SI_NUM_SMOOTH_AA_SAMPLES */
        coverage = LLVMGetParam(si_shader_ctx->radeon_bld.main_fn,
@@ -1415,9 +1389,7 @@ static void si_scale_alpha_by_sample_mask(struct lp_build_tgsi_context *bld_base
                                 lp_build_const_float(gallivm,
                                        1.0 / SI_NUM_SMOOTH_AA_SAMPLES), "");
 
-       alpha = LLVMBuildLoad(gallivm->builder, alpha_ptr, "");
-       alpha = LLVMBuildFMul(gallivm->builder, alpha, coverage, "");
-       LLVMBuildStore(gallivm->builder, alpha, alpha_ptr);
+       return LLVMBuildFMul(gallivm->builder, alpha, coverage, "");
 }
 
 static void si_llvm_emit_clipvertex(struct lp_build_tgsi_context * bld_base,
@@ -2110,6 +2082,110 @@ static void si_llvm_emit_vs_epilogue(struct lp_build_tgsi_context * bld_base)
        FREE(outputs);
 }
 
+static void si_export_mrt_z(struct lp_build_tgsi_context *bld_base,
+                          LLVMValueRef depth, LLVMValueRef stencil,
+                          LLVMValueRef samplemask)
+{
+       struct si_screen *sscreen = si_shader_context(bld_base)->screen;
+       struct lp_build_context *base = &bld_base->base;
+       struct lp_build_context *uint = &bld_base->uint_bld;
+       LLVMValueRef args[9];
+       unsigned mask = 0;
+
+       assert(depth || stencil || samplemask);
+
+       args[1] = uint->one; /* whether the EXEC mask is valid */
+       args[2] = uint->one; /* DONE bit */
+
+       /* Specify the target we are exporting */
+       args[3] = lp_build_const_int32(base->gallivm, V_008DFC_SQ_EXP_MRTZ);
+
+       args[4] = uint->zero; /* COMP flag */
+       args[5] = base->undef; /* R, depth */
+       args[6] = base->undef; /* G, stencil test value[0:7], stencil op value[8:15] */
+       args[7] = base->undef; /* B, sample mask */
+       args[8] = base->undef; /* A, alpha to mask */
+
+       if (depth) {
+               args[5] = depth;
+               mask |= 0x1;
+       }
+
+       if (stencil) {
+               args[6] = stencil;
+               mask |= 0x2;
+       }
+
+       if (samplemask) {
+               args[7] = samplemask;
+               mask |= 0x4;
+       }
+
+       /* SI (except OLAND) has a bug that it only looks
+        * at the X writemask component. */
+       if (sscreen->b.chip_class == SI &&
+           sscreen->b.family != CHIP_OLAND)
+               mask |= 0x1;
+
+       /* Specify which components to enable */
+       args[0] = lp_build_const_int32(base->gallivm, mask);
+
+       lp_build_intrinsic(base->gallivm->builder, "llvm.SI.export",
+                          LLVMVoidTypeInContext(base->gallivm->context),
+                          args, 9, 0);
+}
+
+static void si_export_mrt_color(struct lp_build_tgsi_context *bld_base,
+                               LLVMValueRef *color, unsigned index,
+                               bool is_last)
+{
+       struct si_shader_context *si_shader_ctx = si_shader_context(bld_base);
+       struct lp_build_context *base = &bld_base->base;
+       LLVMValueRef args[9];
+       int i;
+
+       /* Clamp color */
+       if (si_shader_ctx->shader->key.ps.clamp_color)
+               for (i = 0; i < 4; i++)
+                       color[i] = radeon_llvm_saturate(bld_base, color[i]);
+
+       /* Alpha to one */
+       if (si_shader_ctx->shader->key.ps.alpha_to_one)
+               color[3] = base->one;
+
+       /* Alpha test */
+       if (index == 0 &&
+           si_shader_ctx->shader->key.ps.alpha_func != PIPE_FUNC_ALWAYS)
+               si_alpha_test(bld_base, color[3]);
+
+       /* Line & polygon smoothing */
+       if (si_shader_ctx->shader->key.ps.poly_line_smoothing)
+               color[3] = si_scale_alpha_by_sample_mask(bld_base, color[3]);
+
+       /* If last_cbuf > 0, FS_COLOR0_WRITES_ALL_CBUFS is true. */
+       if (index == 0 &&
+           si_shader_ctx->shader->key.ps.last_cbuf > 0) {
+               for (int c = 1; c <= si_shader_ctx->shader->key.ps.last_cbuf; c++) {
+                       si_llvm_init_export_args(bld_base, color,
+                                                V_008DFC_SQ_EXP_MRT + c, args);
+                       lp_build_intrinsic(base->gallivm->builder, "llvm.SI.export",
+                                          LLVMVoidTypeInContext(base->gallivm->context),
+                                          args, 9, 0);
+               }
+       }
+
+       /* Export */
+       si_llvm_init_export_args(bld_base, color, V_008DFC_SQ_EXP_MRT + index,
+                                args);
+       if (is_last) {
+               args[1] = bld_base->uint_bld.one; /* whether the EXEC mask is valid */
+               args[2] = bld_base->uint_bld.one; /* DONE bit */
+       }
+       lp_build_intrinsic(base->gallivm->builder, "llvm.SI.export",
+                          LLVMVoidTypeInContext(base->gallivm->context),
+                          args, 9, 0);
+}
+
 static void si_llvm_emit_fs_epilogue(struct lp_build_tgsi_context * bld_base)
 {
        struct si_shader_context * si_shader_ctx = si_shader_context(bld_base);
@@ -2119,184 +2195,73 @@ static void si_llvm_emit_fs_epilogue(struct lp_build_tgsi_context * bld_base)
        struct tgsi_shader_info *info = &shader->selector->info;
        LLVMBuilderRef builder = base->gallivm->builder;
        LLVMValueRef args[9];
-       LLVMValueRef last_args[9] = { 0 };
-       int depth_index = -1, stencil_index = -1, samplemask_index = -1;
+       LLVMValueRef depth = NULL, stencil = NULL, samplemask = NULL;
+       int last_color_export = -1;
        int i;
 
+       /* If there are no outputs, add a dummy export. */
+       if (!info->num_outputs) {
+               args[0] = lp_build_const_int32(base->gallivm, 0x0); /* enabled channels */
+               args[1] = uint->one; /* whether the EXEC mask is valid */
+               args[2] = uint->one; /* DONE bit */
+               args[3] = lp_build_const_int32(base->gallivm, V_008DFC_SQ_EXP_NULL);
+               args[4] = uint->zero; /* COMPR flag (0 = 32-bit export) */
+               args[5] = uint->undef; /* R */
+               args[6] = uint->undef; /* G */
+               args[7] = uint->undef; /* B */
+               args[8] = uint->undef; /* A */
+
+               lp_build_intrinsic(base->gallivm->builder, "llvm.SI.export",
+                                  LLVMVoidTypeInContext(base->gallivm->context),
+                                  args, 9, 0);
+               return;
+       }
+
+       /* Determine the last export. If MRTZ is present, it's always last.
+        * Otherwise, find the last color export.
+        */
+       if (!info->writes_z && !info->writes_stencil && !info->writes_samplemask)
+               for (i = 0; i < info->num_outputs; i++)
+                       if (info->output_semantic_name[i] == TGSI_SEMANTIC_COLOR)
+                               last_color_export = i;
+
        for (i = 0; i < info->num_outputs; i++) {
                unsigned semantic_name = info->output_semantic_name[i];
                unsigned semantic_index = info->output_semantic_index[i];
-               unsigned target;
-               LLVMValueRef alpha_ptr;
+               unsigned j;
+               LLVMValueRef color[4] = {};
 
                /* Select the correct target */
                switch (semantic_name) {
                case TGSI_SEMANTIC_POSITION:
-                       depth_index = i;
-                       continue;
+                       depth = LLVMBuildLoad(builder,
+                                             si_shader_ctx->radeon_bld.soa.outputs[i][2], "");
+                       break;
                case TGSI_SEMANTIC_STENCIL:
-                       stencil_index = i;
-                       continue;
+                       stencil = LLVMBuildLoad(builder,
+                                               si_shader_ctx->radeon_bld.soa.outputs[i][1], "");
+                       break;
                case TGSI_SEMANTIC_SAMPLEMASK:
-                       samplemask_index = i;
-                       continue;
+                       samplemask = LLVMBuildLoad(builder,
+                                                  si_shader_ctx->radeon_bld.soa.outputs[i][0], "");
+                       break;
                case TGSI_SEMANTIC_COLOR:
-                       target = V_008DFC_SQ_EXP_MRT + semantic_index;
-                       alpha_ptr = si_shader_ctx->radeon_bld.soa.outputs[i][3];
-
-                       if (si_shader_ctx->shader->key.ps.clamp_color) {
-                               for (int j = 0; j < 4; j++) {
-                                       LLVMValueRef ptr = si_shader_ctx->radeon_bld.soa.outputs[i][j];
-                                       LLVMValueRef result = LLVMBuildLoad(builder, ptr, "");
-
-                                       result = radeon_llvm_saturate(bld_base, result);
-                                       LLVMBuildStore(builder, result, ptr);
-                               }
-                       }
-
-                       if (si_shader_ctx->shader->key.ps.alpha_to_one)
-                               LLVMBuildStore(base->gallivm->builder,
-                                              base->one, alpha_ptr);
-
-                       if (semantic_index == 0 &&
-                           si_shader_ctx->shader->key.ps.alpha_func != PIPE_FUNC_ALWAYS)
-                               si_alpha_test(bld_base, alpha_ptr);
-
-                       if (si_shader_ctx->shader->key.ps.poly_line_smoothing)
-                               si_scale_alpha_by_sample_mask(bld_base, alpha_ptr);
+                       for (j = 0; j < 4; j++)
+                               color[j] = LLVMBuildLoad(builder,
+                                                        si_shader_ctx->radeon_bld.soa.outputs[i][j], "");
 
+                       si_export_mrt_color(bld_base, color, semantic_index,
+                                           last_color_export == i);
                        break;
                default:
-                       target = 0;
                        fprintf(stderr,
                                "Warning: SI unhandled fs output type:%d\n",
                                semantic_name);
                }
-
-               si_llvm_init_export_args_load(bld_base,
-                                             si_shader_ctx->radeon_bld.soa.outputs[i],
-                                             target, args);
-
-               if (semantic_name == TGSI_SEMANTIC_COLOR) {
-                       /* If there is an export instruction waiting to be emitted, do so now. */
-                       if (last_args[0]) {
-                               lp_build_intrinsic(base->gallivm->builder,
-                                                  "llvm.SI.export",
-                                                  LLVMVoidTypeInContext(base->gallivm->context),
-                                                  last_args, 9, 0);
-                       }
-
-                       /* This instruction will be emitted at the end of the shader. */
-                       memcpy(last_args, args, sizeof(args));
-
-                       /* Handle FS_COLOR0_WRITES_ALL_CBUFS. */
-                       if (shader->selector->info.properties[TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS] &&
-                           semantic_index == 0 &&
-                           si_shader_ctx->shader->key.ps.last_cbuf > 0) {
-                               for (int c = 1; c <= si_shader_ctx->shader->key.ps.last_cbuf; c++) {
-                                       si_llvm_init_export_args_load(bld_base,
-                                                                     si_shader_ctx->radeon_bld.soa.outputs[i],
-                                                                     V_008DFC_SQ_EXP_MRT + c, args);
-                                       lp_build_intrinsic(base->gallivm->builder,
-                                                          "llvm.SI.export",
-                                                          LLVMVoidTypeInContext(base->gallivm->context),
-                                                          args, 9, 0);
-                               }
-                       }
-               } else {
-                       lp_build_intrinsic(base->gallivm->builder,
-                                          "llvm.SI.export",
-                                          LLVMVoidTypeInContext(base->gallivm->context),
-                                          args, 9, 0);
-               }
-       }
-
-       if (depth_index >= 0 || stencil_index >= 0 || samplemask_index >= 0) {
-               LLVMValueRef out_ptr;
-               unsigned mask = 0;
-
-               /* Specify the target we are exporting */
-               args[3] = lp_build_const_int32(base->gallivm, V_008DFC_SQ_EXP_MRTZ);
-
-               args[5] = base->zero; /* R, depth */
-               args[6] = base->zero; /* G, stencil test value[0:7], stencil op value[8:15] */
-               args[7] = base->zero; /* B, sample mask */
-               args[8] = base->zero; /* A, alpha to mask */
-
-               if (depth_index >= 0) {
-                       out_ptr = si_shader_ctx->radeon_bld.soa.outputs[depth_index][2];
-                       args[5] = LLVMBuildLoad(base->gallivm->builder, out_ptr, "");
-                       mask |= 0x1;
-               }
-
-               if (stencil_index >= 0) {
-                       out_ptr = si_shader_ctx->radeon_bld.soa.outputs[stencil_index][1];
-                       args[6] = LLVMBuildLoad(base->gallivm->builder, out_ptr, "");
-                       mask |= 0x2;
-               }
-
-               if (samplemask_index >= 0) {
-                       out_ptr = si_shader_ctx->radeon_bld.soa.outputs[samplemask_index][0];
-                       args[7] = LLVMBuildLoad(base->gallivm->builder, out_ptr, "");
-                       mask |= 0x4;
-               }
-
-               /* SI (except OLAND) has a bug that it only looks
-                * at the X writemask component. */
-               if (si_shader_ctx->screen->b.chip_class == SI &&
-                   si_shader_ctx->screen->b.family != CHIP_OLAND)
-                       mask |= 0x1;
-
-               if (samplemask_index >= 0)
-                       si_shader_ctx->shader->spi_shader_z_format = V_028710_SPI_SHADER_32_ABGR;
-               else if (stencil_index >= 0)
-                       si_shader_ctx->shader->spi_shader_z_format = V_028710_SPI_SHADER_32_GR;
-               else
-                       si_shader_ctx->shader->spi_shader_z_format = V_028710_SPI_SHADER_32_R;
-
-               /* Specify which components to enable */
-               args[0] = lp_build_const_int32(base->gallivm, mask);
-
-               args[1] =
-               args[2] =
-               args[4] = uint->zero;
-
-               if (last_args[0])
-                       lp_build_intrinsic(base->gallivm->builder,
-                                          "llvm.SI.export",
-                                          LLVMVoidTypeInContext(base->gallivm->context),
-                                          args, 9, 0);
-               else
-                       memcpy(last_args, args, sizeof(args));
-       }
-
-       if (!last_args[0]) {
-               /* Specify which components to enable */
-               last_args[0] = lp_build_const_int32(base->gallivm, 0x0);
-
-               /* Specify the target we are exporting */
-               last_args[3] = lp_build_const_int32(base->gallivm, V_008DFC_SQ_EXP_MRT);
-
-               /* Set COMPR flag to zero to export data as 32-bit */
-               last_args[4] = uint->zero;
-
-               /* dummy bits */
-               last_args[5]= uint->zero;
-               last_args[6]= uint->zero;
-               last_args[7]= uint->zero;
-               last_args[8]= uint->zero;
        }
 
-       /* Specify whether the EXEC mask represents the valid mask */
-       last_args[1] = uint->one;
-
-       /* Specify that this is the last export */
-       last_args[2] = lp_build_const_int32(base->gallivm, 1);
-
-       lp_build_intrinsic(base->gallivm->builder,
-                          "llvm.SI.export",
-                          LLVMVoidTypeInContext(base->gallivm->context),
-                          last_args, 9, 0);
+       if (depth || stencil || samplemask)
+               si_export_mrt_z(bld_base, depth, stencil, samplemask);
 }
 
 static void build_tex_intrinsic(const struct lp_build_tgsi_action * action,