tu: Implement multiview pipeline state
[mesa.git] / src / freedreno / vulkan / tu_pipeline.c
index 3049fdc7a43ff413fe78967c7dd153b04f27f8ba..58e2db66bcd7efa3dbb0ae40b708f449b7689551 100644 (file)
@@ -264,6 +264,7 @@ struct tu_pipeline_builder
    VkFormat color_attachment_formats[MAX_RTS];
    VkFormat depth_attachment_format;
    uint32_t render_components;
+   uint32_t multiview_mask;
 };
 
 static bool
@@ -529,11 +530,18 @@ tu6_emit_vs_system_values(struct tu_cs *cs,
          ir3_find_sysval_regid(gs, SYSTEM_VALUE_GS_HEADER_IR3) :
          regid(63, 0);
 
+   /* Note: we currently don't support multiview with tess or GS. If we did,
+    * and the HW actually works, then we'd have to somehow share this across
+    * stages. Note that the blob doesn't support this either.
+    */
+   const uint32_t viewid_regid =
+      ir3_find_sysval_regid(vs, SYSTEM_VALUE_VIEW_INDEX);
+
    tu_cs_emit_pkt4(cs, REG_A6XX_VFD_CONTROL_1, 6);
    tu_cs_emit(cs, A6XX_VFD_CONTROL_1_REGID4VTX(vertexid_regid) |
                   A6XX_VFD_CONTROL_1_REGID4INST(instanceid_regid) |
                   A6XX_VFD_CONTROL_1_REGID4PRIMID(primitiveid_regid) |
-                  0xfc000000);
+                  A6XX_VFD_CONTROL_1_REGID4VIEWID(viewid_regid));
    tu_cs_emit(cs, A6XX_VFD_CONTROL_2_REGID_HSPATCHID(hs_patch_regid) |
                   A6XX_VFD_CONTROL_2_REGID_INVOCATIONID(hs_invocation_regid));
    tu_cs_emit(cs, A6XX_VFD_CONTROL_3_REGID_DSPATCHID(ds_patch_regid) |
@@ -905,7 +913,7 @@ tu6_emit_vpc(struct tu_cs *cs,
    tu_cs_emit(cs, A6XX_VPC_CNTL_0_NUMNONPOSVAR(fs ? fs->total_in : 0) |
                   COND(fs && fs->total_in, A6XX_VPC_CNTL_0_VARYING) |
                   A6XX_VPC_CNTL_0_PRIMIDLOC(linkage.primid_loc) |
-                  A6XX_VPC_CNTL_0_VIEWIDLOC(0xff));
+                  A6XX_VPC_CNTL_0_VIEWIDLOC(linkage.viewid_loc));
 
    if (hs) {
       shader_info *hs_info = &hs->shader->nir->info;
@@ -1010,9 +1018,6 @@ tu6_emit_vpc(struct tu_cs *cs,
       tu_cs_emit_pkt4(cs, REG_A6XX_PC_PRIMITIVE_CNTL_6, 1);
       tu_cs_emit(cs, A6XX_PC_PRIMITIVE_CNTL_6_STRIDE_IN_VPC(vec4_size));
 
-      tu_cs_emit_pkt4(cs, REG_A6XX_PC_MULTIVIEW_CNTL, 1);
-      tu_cs_emit(cs, 0);
-
       tu_cs_emit_pkt4(cs, REG_A6XX_SP_GS_PRIM_SIZE, 1);
       tu_cs_emit(cs, vs->output_size);
    }
@@ -1413,6 +1418,33 @@ tu6_emit_program(struct tu_cs *cs,
       tu6_emit_xs_config(cs, stage, xs, builder->shader_iova[stage]);
    }
 
+   if (!binning_pass) {
+      uint32_t multiview_views = util_logbase2(builder->multiview_mask) + 1;
+      uint32_t multiview_cntl = builder->multiview_mask ?
+         A6XX_PC_MULTIVIEW_CNTL_ENABLE |
+         A6XX_PC_MULTIVIEW_CNTL_VIEWS(multiview_views) |
+         A6XX_PC_MULTIVIEW_CNTL_DISABLEMULTIPOS /* TODO multi-pos output */
+         : 0;
+
+      /* Copy what the blob does here. This will emit an extra 0x3f
+       * CP_EVENT_WRITE when multiview is disabled. I'm not exactly sure what
+       * this is working around yet.
+       */
+      tu_cs_emit_pkt7(cs, CP_REG_WRITE, 3);
+      tu_cs_emit(cs, CP_REG_WRITE_0_TRACKER(UNK_EVENT_WRITE));
+      tu_cs_emit(cs, REG_A6XX_PC_MULTIVIEW_CNTL);
+      tu_cs_emit(cs, multiview_cntl);
+
+      tu_cs_emit_pkt4(cs, REG_A6XX_VFD_MULTIVIEW_CNTL, 1);
+      tu_cs_emit(cs, multiview_cntl);
+
+      if (multiview_cntl &&
+          builder->device->physical_device->supports_multiview_mask) {
+         tu_cs_emit_pkt4(cs, REG_A6XX_PC_MULTIVIEW_MASK, 1);
+         tu_cs_emit(cs, builder->multiview_mask);
+      }
+   }
+
    tu_cs_emit_pkt4(cs, REG_A6XX_SP_HS_UNKNOWN_A831, 1);
    tu_cs_emit(cs, 0);
 
@@ -1655,7 +1687,8 @@ tu6_emit_sample_locations(struct tu_cs *cs, const VkSampleLocationsInfoEXT *samp
 
 static uint32_t
 tu6_gras_su_cntl(const VkPipelineRasterizationStateCreateInfo *rast_info,
-                 VkSampleCountFlagBits samples)
+                 VkSampleCountFlagBits samples,
+                 bool multiview)
 {
    uint32_t gras_su_cntl = 0;
 
@@ -1675,6 +1708,12 @@ tu6_gras_su_cntl(const VkPipelineRasterizationStateCreateInfo *rast_info,
    if (samples > VK_SAMPLE_COUNT_1_BIT)
       gras_su_cntl |= A6XX_GRAS_SU_CNTL_MSAA_ENABLE;
 
+   if (multiview) {
+      gras_su_cntl |=
+         A6XX_GRAS_SU_CNTL_UNK17 |
+         A6XX_GRAS_SU_CNTL_MULTIVIEW_ENABLE;
+   }
+
    return gras_su_cntl;
 }
 
@@ -1984,8 +2023,8 @@ tu_pipeline_builder_compile_shaders(struct tu_pipeline_builder *builder,
          continue;
 
       struct tu_shader *shader =
-         tu_shader_create(builder->device, stage, stage_info, builder->layout,
-                          builder->alloc);
+         tu_shader_create(builder->device, stage, stage_info, builder->multiview_mask,
+                          builder->layout, builder->alloc);
       if (!shader)
          return VK_ERROR_OUT_OF_HOST_MEMORY;
 
@@ -2267,7 +2306,7 @@ tu_pipeline_builder_parse_rasterization(struct tu_pipeline_builder *builder,
                    A6XX_GRAS_SU_POINT_SIZE(1.0f));
 
    pipeline->gras_su_cntl =
-      tu6_gras_su_cntl(rast_info, builder->samples);
+      tu6_gras_su_cntl(rast_info, builder->samples, builder->multiview_mask != 0);
 
    if (tu_pipeline_static_state(pipeline, &cs, VK_DYNAMIC_STATE_LINE_WIDTH, 2)) {
       pipeline->gras_su_cntl |=
@@ -2488,6 +2527,13 @@ tu_pipeline_builder_init_graphics(
       .layout = layout,
    };
 
+   const struct tu_render_pass *pass =
+      tu_render_pass_from_handle(create_info->renderPass);
+   const struct tu_subpass *subpass =
+      &pass->subpasses[create_info->subpass];
+
+   builder->multiview_mask = subpass->multiview_mask;
+
    builder->rasterizer_discard =
       create_info->pRasterizationState->rasterizerDiscardEnable;
 
@@ -2496,11 +2542,6 @@ tu_pipeline_builder_init_graphics(
    } else {
       builder->samples = create_info->pMultisampleState->rasterizationSamples;
 
-      const struct tu_render_pass *pass =
-         tu_render_pass_from_handle(create_info->renderPass);
-      const struct tu_subpass *subpass =
-         &pass->subpasses[create_info->subpass];
-
       const uint32_t a = subpass->depth_stencil_attachment.attachment;
       builder->depth_attachment_format = (a != VK_ATTACHMENT_UNUSED) ?
          pass->attachments[a].format : VK_FORMAT_UNDEFINED;
@@ -2603,7 +2644,7 @@ tu_compute_pipeline_create(VkDevice device,
    struct ir3_shader_key key = {};
 
    struct tu_shader *shader =
-      tu_shader_create(dev, MESA_SHADER_COMPUTE, stage_info, layout, pAllocator);
+      tu_shader_create(dev, MESA_SHADER_COMPUTE, stage_info, 0, layout, pAllocator);
    if (!shader) {
       result = VK_ERROR_OUT_OF_HOST_MEMORY;
       goto fail;