From c884afc6f71d5c0d30d1edc49026ed9d3c32542e Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Mon, 13 Jul 2020 19:27:53 +0200 Subject: [PATCH] tu: Add multiview lowering pass For now this only handles an a630 quirk where PC_MULTIVIEW_MASK doesn't exist. However in the future it will also handle multi-position output. Part-of: --- src/freedreno/vulkan/meson.build | 1 + src/freedreno/vulkan/tu_device.c | 3 + src/freedreno/vulkan/tu_nir_lower_multiview.c | 76 +++++++++++++++++++ src/freedreno/vulkan/tu_private.h | 4 + 4 files changed, 84 insertions(+) create mode 100644 src/freedreno/vulkan/tu_nir_lower_multiview.c diff --git a/src/freedreno/vulkan/meson.build b/src/freedreno/vulkan/meson.build index 8696f246da0..9c258170615 100644 --- a/src/freedreno/vulkan/meson.build +++ b/src/freedreno/vulkan/meson.build @@ -51,6 +51,7 @@ libtu_files = files( 'tu_fence.c', 'tu_formats.c', 'tu_image.c', + 'tu_nir_lower_multiview.c', 'tu_pass.c', 'tu_pipeline.c', 'tu_pipeline_cache.c', diff --git a/src/freedreno/vulkan/tu_device.c b/src/freedreno/vulkan/tu_device.c index 0ab94e2bf6e..9a6085f96d3 100644 --- a/src/freedreno/vulkan/tu_device.c +++ b/src/freedreno/vulkan/tu_device.c @@ -78,6 +78,7 @@ tu_physical_device_init(struct tu_physical_device *device, device->tile_align_w = 32; device->magic.PC_UNKNOWN_9805 = 0x0; device->magic.SP_UNKNOWN_A0F8 = 0x0; + device->supports_multiview_mask = false; /* TODO */ break; case 630: case 640: @@ -86,6 +87,7 @@ tu_physical_device_init(struct tu_physical_device *device, device->tile_align_w = 32; device->magic.PC_UNKNOWN_9805 = 0x1; device->magic.SP_UNKNOWN_A0F8 = 0x1; + device->supports_multiview_mask = device->gpu_id != 630; break; case 650: device->ccu_offset_gmem = 0x114000; @@ -93,6 +95,7 @@ tu_physical_device_init(struct tu_physical_device *device, device->tile_align_w = 96; device->magic.PC_UNKNOWN_9805 = 0x2; device->magic.SP_UNKNOWN_A0F8 = 0x2; + device->supports_multiview_mask = true; break; default: result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, diff --git a/src/freedreno/vulkan/tu_nir_lower_multiview.c b/src/freedreno/vulkan/tu_nir_lower_multiview.c new file mode 100644 index 00000000000..4402798d4d8 --- /dev/null +++ b/src/freedreno/vulkan/tu_nir_lower_multiview.c @@ -0,0 +1,76 @@ +/* + * Copyright © 2020 Valve Corporation + * SPDX-License-Identifier: MIT + */ + +#include "tu_private.h" +#include "nir_builder.h" + +/* Some a6xx variants cannot support a non-contiguous multiview mask. Instead, + * inside the shader something like this needs to be inserted: + * + * gl_Position = ((1ull << gl_ViewIndex) & view_mask) ? gl_Position : vec4(0.); + * + * Scan backwards until we find the gl_Position write (there should only be + * one). + */ +static bool +lower_multiview_mask(nir_function_impl *impl, uint32_t mask) +{ + nir_builder b; + nir_builder_init(&b, impl); + + nir_foreach_block_reverse(block, impl) { + nir_foreach_instr_reverse(instr, block) { + if (instr->type != nir_instr_type_intrinsic) + continue; + + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + if (intrin->intrinsic != nir_intrinsic_store_deref) + continue; + + nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); + if (deref->mode != nir_var_shader_out) + continue; + + nir_variable *var = nir_deref_instr_get_variable(deref); + if (var->data.location != VARYING_SLOT_POS) + continue; + + assert(intrin->src[1].is_ssa); + nir_ssa_def *orig_src = intrin->src[1].ssa; + b.cursor = nir_before_instr(instr); + + /* ((1ull << gl_ViewIndex) & mask) != 0 */ + nir_ssa_def *cmp = + nir_i2b(&b, nir_iand(&b, nir_imm_int(&b, mask), + nir_ishl(&b, nir_imm_int(&b, 1), + nir_load_view_index(&b)))); + + nir_ssa_def *src = nir_bcsel(&b, cmp, orig_src, nir_imm_float(&b, 0.)); + nir_instr_rewrite_src(instr, &intrin->src[1], nir_src_for_ssa(src)); + + nir_metadata_preserve(impl, nir_metadata_block_index | + nir_metadata_dominance); + return true; + } + } + + nir_metadata_preserve(impl, nir_metadata_all); + return false; +} + +bool +tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, struct tu_device *dev) +{ + nir_function_impl *entrypoint = nir_shader_get_entrypoint(nir); + + if (!dev->physical_device->supports_multiview_mask && + !util_is_power_of_two_or_zero(mask + 1)) { + return lower_multiview_mask(entrypoint, mask); + } + + nir_metadata_preserve(entrypoint, nir_metadata_all); + return false; +} + diff --git a/src/freedreno/vulkan/tu_private.h b/src/freedreno/vulkan/tu_private.h index 584931dc534..b466227e941 100644 --- a/src/freedreno/vulkan/tu_private.h +++ b/src/freedreno/vulkan/tu_private.h @@ -200,6 +200,7 @@ struct tu_physical_device /* gmem store/load granularity */ #define GMEM_ALIGN_W 16 #define GMEM_ALIGN_H 4 + bool supports_multiview_mask; struct { uint32_t PC_UNKNOWN_9805; @@ -1078,6 +1079,9 @@ struct tu_shader uint8_t active_desc_sets; }; +bool +tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, struct tu_device *dev); + struct tu_shader * tu_shader_create(struct tu_device *dev, gl_shader_stage stage, -- 2.30.2