X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcompiler%2Fspirv%2Fvtn_variables.c;h=6de4ceffb82ae2e63053f77490e3a02ec4dbe8b7;hb=23bfba8663cadeb5167c0b30d9b64cf01a913911;hp=a16765eaa86458d4a16d3c6a117635568e67179a;hpb=9e3213ad30fdf121f98dc3e250486c1533047c10;p=mesa.git diff --git a/src/compiler/spirv/vtn_variables.c b/src/compiler/spirv/vtn_variables.c index a16765eaa86..6de4ceffb82 100644 --- a/src/compiler/spirv/vtn_variables.c +++ b/src/compiler/spirv/vtn_variables.c @@ -124,6 +124,18 @@ vtn_mode_uses_ssa_offset(struct vtn_builder *b, mode == vtn_variable_mode_push_constant; } +static bool +vtn_mode_is_cross_invocation(struct vtn_builder *b, + enum vtn_variable_mode mode) +{ + return mode == vtn_variable_mode_ssbo || + mode == vtn_variable_mode_ubo || + mode == vtn_variable_mode_phys_ssbo || + mode == vtn_variable_mode_push_constant || + mode == vtn_variable_mode_workgroup || + mode == vtn_variable_mode_cross_workgroup; +} + static bool vtn_pointer_is_external_block(struct vtn_builder *b, struct vtn_pointer *ptr) @@ -606,12 +618,6 @@ vtn_pointer_dereference(struct vtn_builder *b, nir_deref_instr * vtn_pointer_to_deref(struct vtn_builder *b, struct vtn_pointer *ptr) { - if (b->wa_glslang_179) { - /* Do on-the-fly copy propagation for samplers. */ - if (ptr->var && ptr->var->copy_prop_sampler) - return vtn_pointer_to_deref(b, ptr->var->copy_prop_sampler); - } - vtn_assert(!vtn_pointer_uses_ssa_offset(b, ptr)); if (!ptr->deref) { struct vtn_access_chain chain = { @@ -1044,6 +1050,25 @@ _vtn_variable_load_store(struct vtn_builder *b, bool load, enum gl_access_qualifier access, struct vtn_ssa_value **inout) { + if (ptr->mode == vtn_variable_mode_uniform) { + if (ptr->type->base_type == vtn_base_type_image || + ptr->type->base_type == vtn_base_type_sampler) { + /* See also our handling of OpTypeSampler and OpTypeImage */ + vtn_assert(load); + (*inout)->def = vtn_pointer_to_ssa(b, ptr); + return; + } else if (ptr->type->base_type == vtn_base_type_sampled_image) { + /* See also our handling of OpTypeSampledImage */ + vtn_assert(load); + struct vtn_sampled_image si = { + .image = vtn_pointer_to_deref(b, ptr), + .sampler = vtn_pointer_to_deref(b, ptr), + }; + (*inout)->def = vtn_sampled_image_to_nir_ssa(b, si); + return; + } + } + enum glsl_base_type base_type = glsl_get_base_type(ptr->type->type); switch (base_type) { case GLSL_TYPE_UINT: @@ -1061,11 +1086,11 @@ _vtn_variable_load_store(struct vtn_builder *b, bool load, if (glsl_type_is_vector_or_scalar(ptr->type->type)) { /* We hit a vector or scalar; go ahead and emit the load[s] */ nir_deref_instr *deref = vtn_pointer_to_deref(b, ptr); - if (vtn_pointer_is_external_block(b, ptr)) { - /* If it's external, we call nir_load/store_deref directly. The - * vtn_local_load/store helpers are too clever and do magic to - * avoid array derefs of vectors. That magic is both less - * efficient than the direct load/store and, in the case of + if (vtn_mode_is_cross_invocation(b, ptr->mode)) { + /* If it's cross-invocation, we call nir_load/store_deref + * directly. The vtn_local_load/store helpers are too clever and + * do magic to avoid array derefs of vectors. That magic is both + * less efficient than the direct load/store and, in the case of * stores, is broken because it creates a race condition if two * threads are writing to different components of the same vector * due to the load+insert+store it uses to emulate the array @@ -1142,7 +1167,8 @@ static void _vtn_variable_copy(struct vtn_builder *b, struct vtn_pointer *dest, struct vtn_pointer *src) { - vtn_assert(src->type->type == dest->type->type); + vtn_assert(glsl_get_bare_type(src->type->type) == + glsl_get_bare_type(dest->type->type)); enum glsl_base_type base_type = glsl_get_base_type(src->type->type); switch (base_type) { case GLSL_TYPE_UINT: @@ -1371,6 +1397,10 @@ vtn_get_builtin_location(struct vtn_builder *b, *location = SYSTEM_VALUE_GLOBAL_INVOCATION_INDEX; set_mode_system_value(b, mode); break; + case SpvBuiltInGlobalOffset: + *location = SYSTEM_VALUE_BASE_GLOBAL_INVOCATION_ID; + set_mode_system_value(b, mode); + break; case SpvBuiltInBaseVertex: /* OpenGL gl_BaseVertex (SYSTEM_VALUE_BASE_VERTEX) is not the same * semantic as Vulkan BaseVertex (SYSTEM_VALUE_FIRST_VERTEX). @@ -1410,8 +1440,13 @@ vtn_get_builtin_location(struct vtn_builder *b, set_mode_system_value(b, mode); break; case SpvBuiltInViewIndex: - *location = SYSTEM_VALUE_VIEW_INDEX; - set_mode_system_value(b, mode); + if (b->options && b->options->view_index_is_input) { + *location = VARYING_SLOT_VIEW_INDEX; + vtn_assert(*mode == nir_var_shader_in); + } else { + *location = SYSTEM_VALUE_VIEW_INDEX; + set_mode_system_value(b, mode); + } break; case SpvBuiltInSubgroupEqMask: *location = SYSTEM_VALUE_SUBGROUP_EQ_MASK, @@ -1965,20 +2000,6 @@ vtn_pointer_from_ssa(struct vtn_builder *b, nir_ssa_def *ssa, ptr->type = ptr_type->deref; ptr->ptr_type = ptr_type; - if (b->wa_glslang_179) { - /* To work around https://github.com/KhronosGroup/glslang/issues/179 we - * need to whack the mode because it creates a function parameter with - * the Function storage class even though it's a pointer to a sampler. - * If we don't do this, then NIR won't get rid of the deref_cast for us. - */ - if (ptr->mode == vtn_variable_mode_function && - (ptr->type->base_type == vtn_base_type_sampler || - ptr->type->base_type == vtn_base_type_sampled_image)) { - ptr->mode = vtn_variable_mode_uniform; - nir_mode = nir_var_uniform; - } - } - if (vtn_pointer_uses_ssa_offset(b, ptr)) { /* This pointer type needs to have actual storage */ vtn_assert(ptr_type->type); @@ -2130,10 +2151,12 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, b->shader->info.num_ssbos++; break; case vtn_variable_mode_uniform: - if (glsl_type_is_image(without_array->type)) - b->shader->info.num_images++; - else if (glsl_type_is_sampler(without_array->type)) - b->shader->info.num_textures++; + if (without_array->base_type == vtn_base_type_image) { + if (glsl_type_is_image(without_array->glsl_image)) + b->shader->info.num_images++; + else if (glsl_type_is_sampler(without_array->glsl_image)) + b->shader->info.num_textures++; + } break; case vtn_variable_mode_push_constant: b->shader->num_uniforms = vtn_type_block_size(b, type); @@ -2196,10 +2219,6 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, /* Create the variable normally */ var->var = rzalloc(b->shader, nir_variable); var->var->name = ralloc_strdup(var->var, val->name); - /* Workgroup variables don't have any explicit layout but some - * layouts may have leaked through due to type deduplication in the - * SPIR-V. - */ var->var->type = vtn_type_get_nir_type(b, var->type, var->mode); var->var->data.mode = nir_var_mem_shared; break; @@ -2252,11 +2271,6 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, var->var = rzalloc(b->shader, nir_variable); var->var->name = ralloc_strdup(var->var, val->name); - /* In Vulkan, shader I/O variables don't have any explicit layout but - * some layouts may have leaked through due to type deduplication in - * the SPIR-V. We do, however, keep the layouts in the variable's - * interface_type because we need offsets for XFB arrays of blocks. - */ var->var->type = vtn_type_get_nir_type(b, var->type, var->mode); var->var->data.mode = nir_mode; var->var->data.patch = var->patch; @@ -2340,7 +2354,8 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, if (var->mode == vtn_variable_mode_uniform || var->mode == vtn_variable_mode_ubo || - var->mode == vtn_variable_mode_ssbo) { + var->mode == vtn_variable_mode_ssbo || + var->mode == vtn_variable_mode_atomic_counter) { /* XXX: We still need the binding information in the nir_variable * for these. We should fix that. */ @@ -2350,7 +2365,7 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, var->var->data.index = var->input_attachment_index; var->var->data.offset = var->offset; - if (glsl_type_is_image(without_array->type)) + if (glsl_type_is_image(glsl_without_array(var->var->type))) var->var->data.image.format = without_array->image_format; } @@ -2432,6 +2447,83 @@ nir_sloppy_bitcast(nir_builder *b, nir_ssa_def *val, return nir_shrink_zero_pad_vec(b, val, num_components); } +static bool +vtn_get_mem_operands(struct vtn_builder *b, const uint32_t *w, unsigned count, + unsigned *idx, SpvMemoryAccessMask *access, unsigned *alignment, + SpvScope *dest_scope, SpvScope *src_scope) +{ + *access = 0; + *alignment = 0; + if (*idx >= count) + return false; + + *access = w[(*idx)++]; + if (*access & SpvMemoryAccessAlignedMask) { + vtn_assert(*idx < count); + *alignment = w[(*idx)++]; + } + + if (*access & SpvMemoryAccessMakePointerAvailableMask) { + vtn_assert(*idx < count); + vtn_assert(dest_scope); + *dest_scope = vtn_constant_uint(b, w[(*idx)++]); + } + + if (*access & SpvMemoryAccessMakePointerVisibleMask) { + vtn_assert(*idx < count); + vtn_assert(src_scope); + *src_scope = vtn_constant_uint(b, w[(*idx)++]); + } + + return true; +} + +SpvMemorySemanticsMask +vtn_mode_to_memory_semantics(enum vtn_variable_mode mode) +{ + switch (mode) { + case vtn_variable_mode_ssbo: + case vtn_variable_mode_phys_ssbo: + return SpvMemorySemanticsUniformMemoryMask; + case vtn_variable_mode_workgroup: + return SpvMemorySemanticsWorkgroupMemoryMask; + case vtn_variable_mode_cross_workgroup: + return SpvMemorySemanticsCrossWorkgroupMemoryMask; + case vtn_variable_mode_atomic_counter: + return SpvMemorySemanticsAtomicCounterMemoryMask; + case vtn_variable_mode_image: + return SpvMemorySemanticsImageMemoryMask; + case vtn_variable_mode_output: + return SpvMemorySemanticsOutputMemoryMask; + default: + return SpvMemorySemanticsMaskNone; + } +} + +static void +vtn_emit_make_visible_barrier(struct vtn_builder *b, SpvMemoryAccessMask access, + SpvScope scope, enum vtn_variable_mode mode) +{ + if (!(access & SpvMemoryAccessMakePointerVisibleMask)) + return; + + vtn_emit_memory_barrier(b, scope, SpvMemorySemanticsMakeVisibleMask | + SpvMemorySemanticsAcquireMask | + vtn_mode_to_memory_semantics(mode)); +} + +static void +vtn_emit_make_available_barrier(struct vtn_builder *b, SpvMemoryAccessMask access, + SpvScope scope, enum vtn_variable_mode mode) +{ + if (!(access & SpvMemoryAccessMakePointerAvailableMask)) + return; + + vtn_emit_memory_barrier(b, scope, SpvMemorySemanticsMakeAvailableMask | + SpvMemorySemanticsReleaseMask | + vtn_mode_to_memory_semantics(mode)); +} + void vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) @@ -2471,6 +2563,32 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, break; } + case SpvOpConstantSampler: { + /* Synthesize a pointer-to-sampler type, create a variable of that type, + * and give the variable a constant initializer with the sampler params */ + struct vtn_type *sampler_type = vtn_value(b, w[1], vtn_value_type_type)->type; + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_pointer); + + struct vtn_type *ptr_type = rzalloc(b, struct vtn_type); + ptr_type = rzalloc(b, struct vtn_type); + ptr_type->base_type = vtn_base_type_pointer; + ptr_type->deref = sampler_type; + ptr_type->storage_class = SpvStorageClassUniform; + + ptr_type->type = nir_address_format_to_glsl_type( + vtn_mode_to_address_format(b, vtn_variable_mode_function)); + + vtn_create_variable(b, val, ptr_type, ptr_type->storage_class, NULL, NULL); + + nir_variable *nir_var = val->pointer->var->var; + nir_var->data.sampler.is_inline_sampler = true; + nir_var->data.sampler.addressing_mode = w[3]; + nir_var->data.sampler.normalized_coordinates = w[4]; + nir_var->data.sampler.filter_mode = w[5]; + + break; + } + case SpvOpAccessChain: case SpvOpPtrAccessChain: case SpvOpInBoundsAccessChain: @@ -2493,33 +2611,12 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, } struct vtn_type *ptr_type = vtn_get_type(b, w[1]); - struct vtn_value *base_val = vtn_untyped_value(b, w[3]); - if (base_val->value_type == vtn_value_type_sampled_image) { - /* This is rather insane. SPIR-V allows you to use OpSampledImage - * to combine an array of images with a single sampler to get an - * array of sampled images that all share the same sampler. - * Fortunately, this means that we can more-or-less ignore the - * sampler when crawling the access chain, but it does leave us - * with this rather awkward little special-case. - */ - struct vtn_value *val = - vtn_push_value(b, w[2], vtn_value_type_sampled_image); - val->sampled_image = ralloc(b, struct vtn_sampled_image); - val->sampled_image->image = - vtn_pointer_dereference(b, base_val->sampled_image->image, chain); - val->sampled_image->sampler = base_val->sampled_image->sampler; - val->sampled_image->image = - vtn_decorate_pointer(b, val, val->sampled_image->image); - val->sampled_image->sampler = - vtn_decorate_pointer(b, val, val->sampled_image->sampler); - } else { - vtn_assert(base_val->value_type == vtn_value_type_pointer); - struct vtn_pointer *ptr = - vtn_pointer_dereference(b, base_val->pointer, chain); - ptr->ptr_type = ptr_type; - ptr->access |= access; - vtn_push_pointer(b, w[2], ptr); - } + struct vtn_pointer *base = + vtn_value(b, w[3], vtn_value_type_pointer)->pointer; + struct vtn_pointer *ptr = vtn_pointer_dereference(b, base, chain); + ptr->ptr_type = ptr_type; + ptr->access |= access; + vtn_push_pointer(b, w[2], ptr); break; } @@ -2529,7 +2626,22 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, vtn_assert_types_equal(b, opcode, dest->type->deref, src->type->deref); + unsigned idx = 3, dest_alignment, src_alignment; + SpvMemoryAccessMask dest_access, src_access; + SpvScope dest_scope, src_scope; + vtn_get_mem_operands(b, w, count, &idx, &dest_access, &dest_alignment, + &dest_scope, &src_scope); + if (!vtn_get_mem_operands(b, w, count, &idx, &src_access, &src_alignment, + NULL, &src_scope)) { + src_alignment = dest_alignment; + src_access = dest_access; + } + + vtn_emit_make_visible_barrier(b, src_access, src_scope, src->pointer->mode); + vtn_variable_copy(b, dest->pointer, src->pointer); + + vtn_emit_make_available_barrier(b, dest_access, dest_scope, dest->pointer->mode); break; } @@ -2540,34 +2652,12 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, vtn_assert_types_equal(b, opcode, res_type, src_val->type->deref); - if (res_type->base_type == vtn_base_type_image || - res_type->base_type == vtn_base_type_sampler) { - vtn_push_pointer(b, w[2], src); - return; - } else if (res_type->base_type == vtn_base_type_sampled_image) { - struct vtn_value *val = - vtn_push_value(b, w[2], vtn_value_type_sampled_image); - val->sampled_image = ralloc(b, struct vtn_sampled_image); - val->sampled_image->image = val->sampled_image->sampler = - vtn_decorate_pointer(b, val, src); - return; - } - - if (count > 4) { - unsigned idx = 5; - SpvMemoryAccessMask access = w[4]; - if (access & SpvMemoryAccessAlignedMask) - idx++; + unsigned idx = 4, alignment; + SpvMemoryAccessMask access; + SpvScope scope; + vtn_get_mem_operands(b, w, count, &idx, &access, &alignment, NULL, &scope); - if (access & SpvMemoryAccessMakePointerVisibleMask) { - SpvMemorySemanticsMask semantics = - SpvMemorySemanticsMakeVisibleMask | - vtn_storage_class_to_memory_semantics(src->ptr_type->storage_class); - - SpvScope scope = vtn_constant_uint(b, w[idx]); - vtn_emit_memory_barrier(b, scope, semantics); - } - } + vtn_emit_make_visible_barrier(b, access, scope, src->mode); vtn_push_ssa_value(b, w[2], vtn_variable_load(b, src)); break; @@ -2603,42 +2693,15 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, vtn_assert_types_equal(b, opcode, dest_val->type->deref, src_val->type); - if (glsl_type_is_sampler(dest->type->type)) { - if (b->wa_glslang_179) { - vtn_warn("OpStore of a sampler detected. Doing on-the-fly copy " - "propagation to workaround the problem."); - vtn_assert(dest->var->copy_prop_sampler == NULL); - struct vtn_value *v = vtn_untyped_value(b, w[2]); - if (v->value_type == vtn_value_type_sampled_image) { - dest->var->copy_prop_sampler = v->sampled_image->sampler; - } else { - vtn_assert(v->value_type == vtn_value_type_pointer); - dest->var->copy_prop_sampler = v->pointer; - } - } else { - vtn_fail("Vulkan does not allow OpStore of a sampler or image."); - } - break; - } + unsigned idx = 3, alignment; + SpvMemoryAccessMask access; + SpvScope scope; + vtn_get_mem_operands(b, w, count, &idx, &access, &alignment, &scope, NULL); struct vtn_ssa_value *src = vtn_ssa_value(b, w[2]); vtn_variable_store(b, src, dest); - if (count > 3) { - unsigned idx = 4; - SpvMemoryAccessMask access = w[3]; - - if (access & SpvMemoryAccessAlignedMask) - idx++; - - if (access & SpvMemoryAccessMakePointerAvailableMask) { - SpvMemorySemanticsMask semantics = - SpvMemorySemanticsMakeAvailableMask | - vtn_storage_class_to_memory_semantics(dest->ptr_type->storage_class); - SpvScope scope = vtn_constant_uint(b, w[idx]); - vtn_emit_memory_barrier(b, scope, semantics); - } - } + vtn_emit_make_available_barrier(b, access, scope, dest->mode); break; }