turnip: parse VkPipeline{Multisample,ColorBlend}StateCreateInfo
authorChia-I Wu <olvaffe@gmail.com>
Thu, 21 Feb 2019 22:58:52 +0000 (14:58 -0800)
committerChia-I Wu <olvaffe@gmail.com>
Mon, 11 Mar 2019 17:02:13 +0000 (10:02 -0700)
src/freedreno/vulkan/tu_pipeline.c
src/freedreno/vulkan/tu_private.h
src/freedreno/vulkan/vk_format.h

index 9f91ffe32902045c05102c3688e5b783772cecfc..ebed283a8cc84f11492f01789ff57e4414691cb5 100644 (file)
@@ -50,6 +50,8 @@ struct tu_pipeline_builder
    /* these states are affectd by rasterizer_discard */
    VkSampleCountFlagBits samples;
    bool use_depth_stencil_attachment;
+   bool use_color_attachments;
+   VkFormat color_attachment_formats[MAX_RTS];
 };
 
 static enum tu_dynamic_state_bits
@@ -80,6 +82,34 @@ tu_dynamic_state_bit(VkDynamicState state)
    }
 }
 
+static bool
+tu_logic_op_reads_dst(VkLogicOp op)
+{
+   switch (op) {
+   case VK_LOGIC_OP_CLEAR:
+   case VK_LOGIC_OP_COPY:
+   case VK_LOGIC_OP_COPY_INVERTED:
+   case VK_LOGIC_OP_SET:
+      return false;
+   default:
+      return true;
+   }
+}
+
+static VkBlendFactor
+tu_blend_factor_no_dst_alpha(VkBlendFactor factor)
+{
+   /* treat dst alpha as 1.0 and avoid reading it */
+   switch (factor) {
+   case VK_BLEND_FACTOR_DST_ALPHA:
+      return VK_BLEND_FACTOR_ONE;
+   case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
+      return VK_BLEND_FACTOR_ZERO;
+   default:
+      return factor;
+   }
+}
+
 static enum pc_di_primtype
 tu6_primtype(VkPrimitiveTopology topology)
 {
@@ -163,6 +193,116 @@ tu6_stencil_op(VkStencilOp op)
    }
 }
 
+static enum a3xx_rop_code
+tu6_rop(VkLogicOp op)
+{
+   switch (op) {
+   case VK_LOGIC_OP_CLEAR:
+      return ROP_CLEAR;
+   case VK_LOGIC_OP_AND:
+      return ROP_AND;
+   case VK_LOGIC_OP_AND_REVERSE:
+      return ROP_AND_REVERSE;
+   case VK_LOGIC_OP_COPY:
+      return ROP_COPY;
+   case VK_LOGIC_OP_AND_INVERTED:
+      return ROP_AND_INVERTED;
+   case VK_LOGIC_OP_NO_OP:
+      return ROP_NOOP;
+   case VK_LOGIC_OP_XOR:
+      return ROP_XOR;
+   case VK_LOGIC_OP_OR:
+      return ROP_OR;
+   case VK_LOGIC_OP_NOR:
+      return ROP_NOR;
+   case VK_LOGIC_OP_EQUIVALENT:
+      return ROP_EQUIV;
+   case VK_LOGIC_OP_INVERT:
+      return ROP_INVERT;
+   case VK_LOGIC_OP_OR_REVERSE:
+      return ROP_OR_REVERSE;
+   case VK_LOGIC_OP_COPY_INVERTED:
+      return ROP_COPY_INVERTED;
+   case VK_LOGIC_OP_OR_INVERTED:
+      return ROP_OR_INVERTED;
+   case VK_LOGIC_OP_NAND:
+      return ROP_NAND;
+   case VK_LOGIC_OP_SET:
+      return ROP_SET;
+   default:
+      unreachable("invalid VkLogicOp");
+      return ROP_NOOP;
+   }
+}
+
+static enum adreno_rb_blend_factor
+tu6_blend_factor(VkBlendFactor factor)
+{
+   switch (factor) {
+   case VK_BLEND_FACTOR_ZERO:
+      return FACTOR_ZERO;
+   case VK_BLEND_FACTOR_ONE:
+      return FACTOR_ONE;
+   case VK_BLEND_FACTOR_SRC_COLOR:
+      return FACTOR_SRC_COLOR;
+   case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
+      return FACTOR_ONE_MINUS_SRC_COLOR;
+   case VK_BLEND_FACTOR_DST_COLOR:
+      return FACTOR_DST_COLOR;
+   case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
+      return FACTOR_ONE_MINUS_DST_COLOR;
+   case VK_BLEND_FACTOR_SRC_ALPHA:
+      return FACTOR_SRC_ALPHA;
+   case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
+      return FACTOR_ONE_MINUS_SRC_ALPHA;
+   case VK_BLEND_FACTOR_DST_ALPHA:
+      return FACTOR_DST_ALPHA;
+   case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
+      return FACTOR_ONE_MINUS_DST_ALPHA;
+   case VK_BLEND_FACTOR_CONSTANT_COLOR:
+      return FACTOR_CONSTANT_COLOR;
+   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
+      return FACTOR_ONE_MINUS_CONSTANT_COLOR;
+   case VK_BLEND_FACTOR_CONSTANT_ALPHA:
+      return FACTOR_CONSTANT_ALPHA;
+   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
+      return FACTOR_ONE_MINUS_CONSTANT_ALPHA;
+   case VK_BLEND_FACTOR_SRC_ALPHA_SATURATE:
+      return FACTOR_SRC_ALPHA_SATURATE;
+   case VK_BLEND_FACTOR_SRC1_COLOR:
+      return FACTOR_SRC1_COLOR;
+   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:
+      return FACTOR_ONE_MINUS_SRC1_COLOR;
+   case VK_BLEND_FACTOR_SRC1_ALPHA:
+      return FACTOR_SRC1_ALPHA;
+   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:
+      return FACTOR_ONE_MINUS_SRC1_ALPHA;
+   default:
+      unreachable("invalid VkBlendFactor");
+      return FACTOR_ZERO;
+   }
+}
+
+static enum a3xx_rb_blend_opcode
+tu6_blend_op(VkBlendOp op)
+{
+   switch (op) {
+   case VK_BLEND_OP_ADD:
+      return BLEND_DST_PLUS_SRC;
+   case VK_BLEND_OP_SUBTRACT:
+      return BLEND_SRC_MINUS_DST;
+   case VK_BLEND_OP_REVERSE_SUBTRACT:
+      return BLEND_DST_MINUS_SRC;
+   case VK_BLEND_OP_MIN:
+      return BLEND_MIN_DST_SRC;
+   case VK_BLEND_OP_MAX:
+      return BLEND_MAX_DST_SRC;
+   default:
+      unreachable("invalid VkBlendOp");
+      return BLEND_DST_PLUS_SRC;
+   }
+}
+
 static uint32_t
 tu6_guardband_adj(uint32_t v)
 {
@@ -388,6 +528,146 @@ tu6_emit_stencil_reference(struct tu_cs *cs, uint32_t front, uint32_t back)
               A6XX_RB_STENCILREF_REF(front) | A6XX_RB_STENCILREF_BFREF(back));
 }
 
+static uint32_t
+tu6_rb_mrt_blend_control(const VkPipelineColorBlendAttachmentState *att,
+                         bool has_alpha)
+{
+   const enum a3xx_rb_blend_opcode color_op = tu6_blend_op(att->colorBlendOp);
+   const enum adreno_rb_blend_factor src_color_factor = tu6_blend_factor(
+      has_alpha ? att->srcColorBlendFactor
+                : tu_blend_factor_no_dst_alpha(att->srcColorBlendFactor));
+   const enum adreno_rb_blend_factor dst_color_factor = tu6_blend_factor(
+      has_alpha ? att->dstColorBlendFactor
+                : tu_blend_factor_no_dst_alpha(att->dstColorBlendFactor));
+   const enum a3xx_rb_blend_opcode alpha_op = tu6_blend_op(att->alphaBlendOp);
+   const enum adreno_rb_blend_factor src_alpha_factor =
+      tu6_blend_factor(att->srcAlphaBlendFactor);
+   const enum adreno_rb_blend_factor dst_alpha_factor =
+      tu6_blend_factor(att->dstAlphaBlendFactor);
+
+   return A6XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR(src_color_factor) |
+          A6XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE(color_op) |
+          A6XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR(dst_color_factor) |
+          A6XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR(src_alpha_factor) |
+          A6XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE(alpha_op) |
+          A6XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR(dst_alpha_factor);
+}
+
+static uint32_t
+tu6_rb_mrt_control(const VkPipelineColorBlendAttachmentState *att,
+                   uint32_t rb_mrt_control_rop,
+                   bool is_int,
+                   bool has_alpha)
+{
+   uint32_t rb_mrt_control =
+      A6XX_RB_MRT_CONTROL_COMPONENT_ENABLE(att->colorWriteMask);
+
+   /* ignore blending and logic op for integer attachments */
+   if (is_int) {
+      rb_mrt_control |= A6XX_RB_MRT_CONTROL_ROP_CODE(ROP_COPY);
+      return rb_mrt_control;
+   }
+
+   rb_mrt_control |= rb_mrt_control_rop;
+
+   if (att->blendEnable) {
+      rb_mrt_control |= A6XX_RB_MRT_CONTROL_BLEND;
+
+      if (has_alpha)
+         rb_mrt_control |= A6XX_RB_MRT_CONTROL_BLEND2;
+   }
+
+   return rb_mrt_control;
+}
+
+static void
+tu6_emit_rb_mrt_controls(struct tu_cs *cs,
+                         const VkPipelineColorBlendStateCreateInfo *blend_info,
+                         const VkFormat attachment_formats[MAX_RTS],
+                         uint32_t *blend_enable_mask)
+{
+   *blend_enable_mask = 0;
+
+   bool rop_reads_dst = false;
+   uint32_t rb_mrt_control_rop = 0;
+   if (blend_info->logicOpEnable) {
+      rop_reads_dst = tu_logic_op_reads_dst(blend_info->logicOp);
+      rb_mrt_control_rop =
+         A6XX_RB_MRT_CONTROL_ROP_ENABLE |
+         A6XX_RB_MRT_CONTROL_ROP_CODE(tu6_rop(blend_info->logicOp));
+   }
+
+   for (uint32_t i = 0; i < blend_info->attachmentCount; i++) {
+      const VkPipelineColorBlendAttachmentState *att =
+         &blend_info->pAttachments[i];
+      const VkFormat format = attachment_formats[i];
+
+      uint32_t rb_mrt_control = 0;
+      uint32_t rb_mrt_blend_control = 0;
+      if (format != VK_FORMAT_UNDEFINED) {
+         const bool is_int = vk_format_is_int(format);
+         const bool has_alpha = vk_format_has_alpha(format);
+
+         rb_mrt_control =
+            tu6_rb_mrt_control(att, rb_mrt_control_rop, is_int, has_alpha);
+         rb_mrt_blend_control = tu6_rb_mrt_blend_control(att, has_alpha);
+
+         if (att->blendEnable || rop_reads_dst)
+            *blend_enable_mask |= 1 << i;
+      }
+
+      tu_cs_emit_pkt4(cs, REG_A6XX_RB_MRT_CONTROL(i), 2);
+      tu_cs_emit(cs, rb_mrt_control);
+      tu_cs_emit(cs, rb_mrt_blend_control);
+   }
+
+   for (uint32_t i = blend_info->attachmentCount; i < MAX_RTS; i++) {
+      tu_cs_emit_pkt4(cs, REG_A6XX_RB_MRT_CONTROL(i), 2);
+      tu_cs_emit(cs, 0);
+      tu_cs_emit(cs, 0);
+   }
+}
+
+static void
+tu6_emit_blend_control(struct tu_cs *cs,
+                       uint32_t blend_enable_mask,
+                       const VkPipelineMultisampleStateCreateInfo *msaa_info)
+{
+   assert(!msaa_info->sampleShadingEnable);
+   assert(!msaa_info->alphaToOneEnable);
+
+   uint32_t sp_blend_cntl = A6XX_SP_BLEND_CNTL_UNK8;
+   if (blend_enable_mask)
+      sp_blend_cntl |= A6XX_SP_BLEND_CNTL_ENABLED;
+   if (msaa_info->alphaToCoverageEnable)
+      sp_blend_cntl |= A6XX_SP_BLEND_CNTL_ALPHA_TO_COVERAGE;
+
+   const uint32_t sample_mask =
+      msaa_info->pSampleMask ? *msaa_info->pSampleMask
+                             : ((1 << msaa_info->rasterizationSamples) - 1);
+
+   /* set A6XX_RB_BLEND_CNTL_INDEPENDENT_BLEND only when enabled? */
+   uint32_t rb_blend_cntl =
+      A6XX_RB_BLEND_CNTL_ENABLE_BLEND(blend_enable_mask) |
+      A6XX_RB_BLEND_CNTL_INDEPENDENT_BLEND |
+      A6XX_RB_BLEND_CNTL_SAMPLE_MASK(sample_mask);
+   if (msaa_info->alphaToCoverageEnable)
+      rb_blend_cntl |= A6XX_RB_BLEND_CNTL_ALPHA_TO_COVERAGE;
+
+   tu_cs_emit_pkt4(cs, REG_A6XX_SP_BLEND_CNTL, 1);
+   tu_cs_emit(cs, sp_blend_cntl);
+
+   tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLEND_CNTL, 1);
+   tu_cs_emit(cs, rb_blend_cntl);
+}
+
+void
+tu6_emit_blend_constants(struct tu_cs *cs, const float constants[4])
+{
+   tu_cs_emit_pkt4(cs, REG_A6XX_RB_BLEND_RED_F32, 4);
+   tu_cs_emit_array(cs, (const uint32_t *) constants, 4);
+}
+
 static VkResult
 tu_pipeline_builder_create_pipeline(struct tu_pipeline_builder *builder,
                                     struct tu_pipeline **out_pipeline)
@@ -554,6 +834,53 @@ tu_pipeline_builder_parse_depth_stencil(struct tu_pipeline_builder *builder,
    pipeline->ds.state_ib = tu_cs_end_sub_stream(&pipeline->cs, &ds_cs);
 }
 
+static void
+tu_pipeline_builder_parse_multisample_and_color_blend(
+   struct tu_pipeline_builder *builder, struct tu_pipeline *pipeline)
+{
+   /* The spec says:
+    *
+    *    pMultisampleState is a pointer to an instance of the
+    *    VkPipelineMultisampleStateCreateInfo, and is ignored if the pipeline
+    *    has rasterization disabled.
+    *
+    * Also,
+    *
+    *    pColorBlendState is a pointer to an instance of the
+    *    VkPipelineColorBlendStateCreateInfo structure, and is ignored if the
+    *    pipeline has rasterization disabled or if the subpass of the render
+    *    pass the pipeline is created against does not use any color
+    *    attachments.
+    *
+    * We leave the relevant registers stale when rasterization is disabled.
+    */
+   if (builder->rasterizer_discard)
+      return;
+
+   static const VkPipelineColorBlendStateCreateInfo dummy_blend_info;
+   const VkPipelineMultisampleStateCreateInfo *msaa_info =
+      builder->create_info->pMultisampleState;
+   const VkPipelineColorBlendStateCreateInfo *blend_info =
+      builder->use_color_attachments ? builder->create_info->pColorBlendState
+                                     : &dummy_blend_info;
+
+   struct tu_cs blend_cs;
+   tu_cs_begin_sub_stream(builder->device, &pipeline->cs, MAX_RTS * 3 + 9,
+                          &blend_cs);
+
+   uint32_t blend_enable_mask;
+   tu6_emit_rb_mrt_controls(&blend_cs, blend_info,
+                            builder->color_attachment_formats,
+                            &blend_enable_mask);
+
+   if (!(pipeline->dynamic_state.mask & TU_DYNAMIC_BLEND_CONSTANTS))
+      tu6_emit_blend_constants(&blend_cs, blend_info->blendConstants);
+
+   tu6_emit_blend_control(&blend_cs, blend_enable_mask, msaa_info);
+
+   pipeline->blend.state_ib = tu_cs_end_sub_stream(&pipeline->cs, &blend_cs);
+}
+
 static void
 tu_pipeline_finish(struct tu_pipeline *pipeline,
                    struct tu_device *dev,
@@ -575,6 +902,7 @@ tu_pipeline_builder_build(struct tu_pipeline_builder *builder,
    tu_pipeline_builder_parse_viewport(builder, *pipeline);
    tu_pipeline_builder_parse_rasterization(builder, *pipeline);
    tu_pipeline_builder_parse_depth_stencil(builder, *pipeline);
+   tu_pipeline_builder_parse_multisample_and_color_blend(builder, *pipeline);
 
    /* we should have reserved enough space upfront such that the CS never
     * grows
@@ -614,6 +942,15 @@ tu_pipeline_builder_init_graphics(
 
       builder->use_depth_stencil_attachment =
          subpass->depth_stencil_attachment.attachment != VK_ATTACHMENT_UNUSED;
+
+      for (uint32_t i = 0; i < subpass->color_count; i++) {
+         const uint32_t a = subpass->color_attachments[i].attachment;
+         if (a == VK_ATTACHMENT_UNUSED)
+            continue;
+
+         builder->color_attachment_formats[i] = pass->attachments[a].format;
+         builder->use_color_attachments = true;
+      }
    }
 }
 
index e8c0e91a877781448a1176fd4d08c17a0d861e92..fa38a0f1e9a42793de595ba1e6a1f10c39228901 100644 (file)
@@ -1007,6 +1007,11 @@ struct tu_pipeline
    {
       struct tu_cs_entry state_ib;
    } ds;
+
+   struct
+   {
+      struct tu_cs_entry state_ib;
+   } blend;
 };
 
 void
@@ -1037,6 +1042,9 @@ tu6_emit_stencil_write_mask(struct tu_cs *cs, uint32_t front, uint32_t back);
 void
 tu6_emit_stencil_reference(struct tu_cs *cs, uint32_t front, uint32_t back);
 
+void
+tu6_emit_blend_constants(struct tu_cs *cs, const float constants[4]);
+
 struct tu_userdata_info *
 tu_lookup_user_sgpr(struct tu_pipeline *pipeline,
                     gl_shader_stage stage,
index 01e116575a39f9a59a07338e562d9812d5715751..4e13bc9c02d18798d599e40c3bc4a2d89cfd0f84 100644 (file)
@@ -414,6 +414,16 @@ vk_format_is_color(VkFormat format)
    return !vk_format_is_depth_or_stencil(format);
 }
 
+static inline bool
+vk_format_has_alpha(VkFormat format)
+{
+   const struct vk_format_description *desc = vk_format_description(format);
+
+   return (desc->colorspace == VK_FORMAT_COLORSPACE_RGB ||
+           desc->colorspace == VK_FORMAT_COLORSPACE_SRGB) &&
+          desc->swizzle[3] != VK_SWIZZLE_1;
+}
+
 static inline VkFormat
 vk_format_depth_only(VkFormat format)
 {