From 8d2757789a72714489fc1fd5dfee04e48c52fee8 Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Fri, 21 Aug 2020 13:46:09 +0200 Subject: [PATCH] tu: Enable multi-position output Part-of: --- src/freedreno/vulkan/tu_device.c | 1 + src/freedreno/vulkan/tu_nir_lower_multiview.c | 52 +++++++++++++++---- src/freedreno/vulkan/tu_private.h | 4 +- src/freedreno/vulkan/tu_shader.c | 3 +- 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/freedreno/vulkan/tu_device.c b/src/freedreno/vulkan/tu_device.c index 572b8aa030f..1f58026ce0e 100644 --- a/src/freedreno/vulkan/tu_device.c +++ b/src/freedreno/vulkan/tu_device.c @@ -197,6 +197,7 @@ static const struct debug_control tu_debug_options[] = { { "sysmem", TU_DEBUG_SYSMEM }, { "forcebin", TU_DEBUG_FORCEBIN }, { "noubwc", TU_DEBUG_NOUBWC }, + { "nomultipos", TU_DEBUG_NOMULTIPOS }, { NULL, 0 } }; diff --git a/src/freedreno/vulkan/tu_nir_lower_multiview.c b/src/freedreno/vulkan/tu_nir_lower_multiview.c index 4402798d4d8..80ec26e9bc4 100644 --- a/src/freedreno/vulkan/tu_nir_lower_multiview.c +++ b/src/freedreno/vulkan/tu_nir_lower_multiview.c @@ -15,11 +15,21 @@ * one). */ static bool -lower_multiview_mask(nir_function_impl *impl, uint32_t mask) +lower_multiview_mask(nir_shader *nir, uint32_t *mask) { + nir_function_impl *impl = nir_shader_get_entrypoint(nir); + + if (util_is_power_of_two_or_zero(*mask + 1)) { + nir_metadata_preserve(impl, nir_metadata_all); + return false; + } + nir_builder b; nir_builder_init(&b, impl); + uint32_t old_mask = *mask; + *mask = BIT(util_logbase2(old_mask) + 1) - 1; + nir_foreach_block_reverse(block, impl) { nir_foreach_instr_reverse(instr, block) { if (instr->type != nir_instr_type_intrinsic) @@ -43,7 +53,7 @@ lower_multiview_mask(nir_function_impl *impl, uint32_t mask) /* ((1ull << gl_ViewIndex) & mask) != 0 */ nir_ssa_def *cmp = - nir_i2b(&b, nir_iand(&b, nir_imm_int(&b, mask), + nir_i2b(&b, nir_iand(&b, nir_imm_int(&b, old_mask), nir_ishl(&b, nir_imm_int(&b, 1), nir_load_view_index(&b)))); @@ -61,16 +71,40 @@ lower_multiview_mask(nir_function_impl *impl, uint32_t mask) } bool -tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, struct tu_device *dev) +tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, bool *multi_pos_output, + struct tu_device *dev) { - nir_function_impl *entrypoint = nir_shader_get_entrypoint(nir); + *multi_pos_output = false; - if (!dev->physical_device->supports_multiview_mask && - !util_is_power_of_two_or_zero(mask + 1)) { - return lower_multiview_mask(entrypoint, mask); + bool progress = false; + + if (!dev->physical_device->supports_multiview_mask) + NIR_PASS(progress, nir, lower_multiview_mask, &mask); + + unsigned num_views = util_logbase2(mask) + 1; + + /* Speculatively assign output locations so that we know num_outputs. We + * will assign output locations for real after this pass. + */ + unsigned num_outputs; + nir_assign_io_var_locations(nir, nir_var_shader_out, &num_outputs, MESA_SHADER_VERTEX); + + /* In addition to the generic checks done by NIR, check that we don't + * overflow VPC with the extra copies of gl_Position. + */ + if (likely(!(dev->physical_device->instance->debug_flags & TU_DEBUG_NOMULTIPOS)) && + num_outputs + (num_views - 1) <= 32 && nir_can_lower_multiview(nir)) { + *multi_pos_output = true; + + /* It appears that the multiview mask is ignored when multi-position + * output is enabled, so we have to write 0 to inactive views ourselves. + */ + NIR_PASS(progress, nir, lower_multiview_mask, &mask); + + NIR_PASS_V(nir, nir_lower_multiview, mask); + progress = true; } - nir_metadata_preserve(entrypoint, nir_metadata_all); - return false; + return progress; } diff --git a/src/freedreno/vulkan/tu_private.h b/src/freedreno/vulkan/tu_private.h index 37e75fc1eeb..388f5b3835e 100644 --- a/src/freedreno/vulkan/tu_private.h +++ b/src/freedreno/vulkan/tu_private.h @@ -227,6 +227,7 @@ enum tu_debug_flags TU_DEBUG_SYSMEM = 1 << 4, TU_DEBUG_FORCEBIN = 1 << 5, TU_DEBUG_NOUBWC = 1 << 6, + TU_DEBUG_NOMULTIPOS = 1 << 7, }; struct tu_instance @@ -1031,7 +1032,8 @@ struct tu_shader }; bool -tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, struct tu_device *dev); +tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, bool *multi_pos_output, + struct tu_device *dev); nir_shader * tu_spirv_to_nir(struct tu_device *dev, diff --git a/src/freedreno/vulkan/tu_shader.c b/src/freedreno/vulkan/tu_shader.c index f0d2e50d8a6..9d4fe21470d 100644 --- a/src/freedreno/vulkan/tu_shader.c +++ b/src/freedreno/vulkan/tu_shader.c @@ -761,7 +761,8 @@ tu_shader_create(struct tu_device *dev, } if (nir->info.stage == MESA_SHADER_VERTEX && multiview_mask) { - NIR_PASS_V(nir, tu_nir_lower_multiview, multiview_mask, dev); + tu_nir_lower_multiview(nir, multiview_mask, + &shader->multi_pos_output, dev); } NIR_PASS_V(nir, nir_lower_explicit_io,