From 5de6c5973a68dd1ac9dbe40bc6e51f8313e5c768 Mon Sep 17 00:00:00 2001 From: Caio Marcelo de Oliveira Filho Date: Wed, 28 Oct 2020 14:55:05 -0700 Subject: [PATCH] spirv: Implement SPV_KHR_workgroup_memory_explicit_layout Reviewed-by: Jason Ekstrand Reviewed-by: Bas Nieuwenhuizen Part-of: --- src/compiler/nir/nir_lower_io.c | 6 +++- src/compiler/shader_info.h | 7 ++++ src/compiler/spirv/spirv_to_nir.c | 53 ++++++++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/compiler/nir/nir_lower_io.c b/src/compiler/nir/nir_lower_io.c index 07be1b2998a..4af3d7658c2 100644 --- a/src/compiler/nir/nir_lower_io.c +++ b/src/compiler/nir/nir_lower_io.c @@ -2303,8 +2303,12 @@ nir_lower_vars_to_explicit_types(nir_shader *shader, if (modes & nir_var_uniform) progress |= lower_vars_to_explicit(shader, &shader->variables, nir_var_uniform, type_info); - if (modes & nir_var_mem_shared) + + if (modes & nir_var_mem_shared) { + assert(!shader->info.cs.shared_memory_explicit_layout); progress |= lower_vars_to_explicit(shader, &shader->variables, nir_var_mem_shared, type_info); + } + if (modes & nir_var_shader_temp) progress |= lower_vars_to_explicit(shader, &shader->variables, nir_var_shader_temp, type_info); if (modes & nir_var_mem_constant) diff --git a/src/compiler/shader_info.h b/src/compiler/shader_info.h index 097284e9d26..6bec004c743 100644 --- a/src/compiler/shader_info.h +++ b/src/compiler/shader_info.h @@ -93,6 +93,7 @@ struct spirv_supported_capabilities { bool variable_pointers; bool vk_memory_model; bool vk_memory_model_device_scope; + bool workgroup_memory_explicit_layout; bool float16; bool amd_fragment_mask; bool amd_gcn_shader; @@ -384,6 +385,12 @@ typedef struct shader_info { * Uses subgroup intrinsics which can communicate across a quad. */ bool uses_wide_subgroup_intrinsics; + + /** + * Shared memory types have explicit layout set. Used for + * SPV_KHR_workgroup_storage_explicit_layout. + */ + bool shared_memory_explicit_layout; } cs; /* Applies to both TCS and TES. */ diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c index 5b1ae9490dc..006a43a4ee2 100644 --- a/src/compiler/spirv/spirv_to_nir.c +++ b/src/compiler/spirv/spirv_to_nir.c @@ -826,7 +826,8 @@ wrap_type_in_array(const struct glsl_type *type, } static bool -vtn_type_needs_explicit_layout(struct vtn_builder *b, enum vtn_variable_mode mode) +vtn_type_needs_explicit_layout(struct vtn_builder *b, struct vtn_type *type, + enum vtn_variable_mode mode) { /* For OpenCL we never want to strip the info from the types, and it makes * type comparisons easier in later stages. @@ -849,6 +850,9 @@ vtn_type_needs_explicit_layout(struct vtn_builder *b, enum vtn_variable_mode mod case vtn_variable_mode_shader_record: return true; + case vtn_variable_mode_workgroup: + return b->options->caps.workgroup_memory_explicit_layout; + default: return false; } @@ -922,7 +926,7 @@ vtn_type_get_nir_type(struct vtn_builder *b, struct vtn_type *type, * to allow SPIR-V generators perform type deduplication. Discard * unnecessary ones when passing to NIR. */ - if (!vtn_type_needs_explicit_layout(b, mode)) + if (!vtn_type_needs_explicit_layout(b, type, mode)) return glsl_get_bare_type(type->type); return type->type; @@ -1575,16 +1579,20 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, val->type->deref = deref_type; - /* Only certain storage classes use ArrayStride. The others (in - * particular Workgroup) are expected to be laid out by the driver. - */ + /* Only certain storage classes use ArrayStride. */ switch (storage_class) { + case SpvStorageClassWorkgroup: + if (!b->options->caps.workgroup_memory_explicit_layout) + break; + FALLTHROUGH; + case SpvStorageClassUniform: case SpvStorageClassPushConstant: case SpvStorageClassStorageBuffer: case SpvStorageClassPhysicalStorageBuffer: vtn_foreach_decoration(b, val, array_stride_decoration_cb, NULL); break; + default: /* Nothing to do. */ break; @@ -4539,6 +4547,20 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode, spv_check_supported(fragment_shading_rate, cap); break; + case SpvCapabilityWorkgroupMemoryExplicitLayoutKHR: + spv_check_supported(workgroup_memory_explicit_layout, cap); + break; + + case SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR: + spv_check_supported(workgroup_memory_explicit_layout, cap); + spv_check_supported(storage_8bit, cap); + break; + + case SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR: + spv_check_supported(workgroup_memory_explicit_layout, cap); + spv_check_supported(storage_16bit, cap); + break; + default: vtn_fail("Unhandled capability: %s (%u)", spirv_capability_to_string(cap), cap); @@ -5968,6 +5990,27 @@ spirv_to_nir(const uint32_t *words, size_t word_count, */ nir_opt_dce(b->shader); + /* Per SPV_KHR_workgroup_storage_explicit_layout, if one shared variable is + * a Block, all of them will be and Blocks are explicitly laid out. + */ + nir_foreach_variable_with_modes(var, b->shader, nir_var_mem_shared) { + if (glsl_type_is_interface(var->type)) { + assert(b->options->caps.workgroup_memory_explicit_layout); + b->shader->info.cs.shared_memory_explicit_layout = true; + break; + } + } + if (b->shader->info.cs.shared_memory_explicit_layout) { + unsigned size = 0; + nir_foreach_variable_with_modes(var, b->shader, nir_var_mem_shared) { + assert(glsl_type_is_interface(var->type)); + const bool align_to_stride = false; + size = MAX2(size, glsl_get_explicit_size(var->type, align_to_stride)); + } + b->shader->info.cs.shared_size = size; + b->shader->shared_size = size; + } + /* Unparent the shader from the vtn_builder before we delete the builder */ ralloc_steal(NULL, b->shader);