From c0c7dbd103481b9a07a0f5b56040b1cfadafd89f Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Thu, 2 Jul 2020 11:33:42 +0200 Subject: [PATCH] tu: Implement multiview pipeline state Part-of: --- src/freedreno/vulkan/tu_cmd_buffer.c | 3 -- src/freedreno/vulkan/tu_pipeline.c | 71 ++++++++++++++++++++++------ src/freedreno/vulkan/tu_private.h | 1 + src/freedreno/vulkan/tu_shader.c | 13 +++++ 4 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/freedreno/vulkan/tu_cmd_buffer.c b/src/freedreno/vulkan/tu_cmd_buffer.c index 0a17add004c..8f8066906e3 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.c +++ b/src/freedreno/vulkan/tu_cmd_buffer.c @@ -860,7 +860,6 @@ tu6_init_hw(struct tu_cmd_buffer *cmd, struct tu_cs *cs) tu_cs_emit_write_reg(cs, REG_A6XX_PC_UNKNOWN_9980, 0); tu_cs_emit_write_reg(cs, REG_A6XX_PC_PRIMITIVE_CNTL_6, 0); - tu_cs_emit_write_reg(cs, REG_A6XX_PC_MULTIVIEW_CNTL, 0); tu_cs_emit_write_reg(cs, REG_A6XX_SP_UNKNOWN_A81B, 0); @@ -878,8 +877,6 @@ tu6_init_hw(struct tu_cmd_buffer *cmd, struct tu_cs *cs) tu_cs_emit_write_reg(cs, REG_A6XX_VFD_MODE_CNTL, 0x00000000); - tu_cs_emit_write_reg(cs, REG_A6XX_VFD_MULTIVIEW_CNTL, 0); - tu_cs_emit_write_reg(cs, REG_A6XX_PC_MODE_CNTL, 0x0000001f); /* we don't use this yet.. probably best to disable.. */ diff --git a/src/freedreno/vulkan/tu_pipeline.c b/src/freedreno/vulkan/tu_pipeline.c index 3049fdc7a43..58e2db66bcd 100644 --- a/src/freedreno/vulkan/tu_pipeline.c +++ b/src/freedreno/vulkan/tu_pipeline.c @@ -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; diff --git a/src/freedreno/vulkan/tu_private.h b/src/freedreno/vulkan/tu_private.h index b466227e941..b62f5c6c88b 100644 --- a/src/freedreno/vulkan/tu_private.h +++ b/src/freedreno/vulkan/tu_private.h @@ -1086,6 +1086,7 @@ struct tu_shader * tu_shader_create(struct tu_device *dev, gl_shader_stage stage, const VkPipelineShaderStageCreateInfo *stage_info, + unsigned multiview_mask, struct tu_pipeline_layout *layout, const VkAllocationCallbacks *alloc); diff --git a/src/freedreno/vulkan/tu_shader.c b/src/freedreno/vulkan/tu_shader.c index 4461bae26d0..b85febe6410 100644 --- a/src/freedreno/vulkan/tu_shader.c +++ b/src/freedreno/vulkan/tu_shader.c @@ -59,6 +59,8 @@ tu_spirv_to_nir(struct ir3_compiler *compiler, /* Accessed via stg/ldg (not used with Vulkan?) */ .global_addr_format = nir_address_format_64bit_global, + /* ViewID is a sysval in geometry stages and an input in the FS */ + .view_index_is_input = stage == MESA_SHADER_FRAGMENT, .caps = { .transform_feedback = true, .tessellation = true, @@ -661,6 +663,7 @@ struct tu_shader * tu_shader_create(struct tu_device *dev, gl_shader_stage stage, const VkPipelineShaderStageCreateInfo *stage_info, + unsigned multiview_mask, struct tu_pipeline_layout *layout, const VkAllocationCallbacks *alloc) { @@ -768,9 +771,19 @@ tu_shader_create(struct tu_device *dev, &(nir_input_attachment_options) { .use_fragcoord_sysval = true, .use_layer_id_sysval = false, + /* When using multiview rendering, we must use + * gl_ViewIndex as the layer id to pass to the texture + * sampling function. gl_Layer doesn't work when + * multiview is enabled. + */ + .use_view_id_for_layer = multiview_mask != 0, }); } + if (stage == MESA_SHADER_VERTEX && multiview_mask) { + NIR_PASS_V(nir, tu_nir_lower_multiview, multiview_mask, dev); + } + NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_ubo | nir_var_mem_ssbo, nir_address_format_vec2_index_32bit_offset); -- 2.30.2