@@ -2595,14 +2595,44 @@ void CompilerGLSL::emit_buffer_reference_block(uint32_t type_id, bool forward_de
25952595 }
25962596}
25972597
2598- void CompilerGLSL::emit_buffer_block_native(const SPIRVariable *var, SPIRType *type, StorageClass storage)
2598+ std::string CompilerGLSL::to_buffer_pointer_name_prefix(uint32_t ptr_id) const
25992599{
2600- if (!type)
2600+ auto itr = std::find_if(descriptor_heap_types.begin(), descriptor_heap_types.end(),
2601+ [&](const DescriptorHeapMeta &meta) { return meta.buffer_pointer_id == ptr_id; });
2602+
2603+ assert(itr != descriptor_heap_types.end());
2604+
2605+ auto name = to_name(itr->type);
2606+
2607+ // The same block type can be instantiated with different read-write decorations.
2608+ if (itr->nonreadable)
2609+ name += "NoRead";
2610+ if (itr->nonwritable)
2611+ name += "NoWrite";
2612+
2613+ return join("spv", name);
2614+ }
2615+
2616+ void CompilerGLSL::emit_buffer_block_native(const SPIRVariable *var, const DescriptorHeapMeta *heap_meta)
2617+ {
2618+ assert(var || heap_meta);
2619+
2620+ SPIRType *type;
2621+ if (var)
26012622 type = &get<SPIRType>(var->basetype);
2623+ else
2624+ type = &get<SPIRType>(heap_meta->type);
26022625
26032626 Bitset flags = var ? ir.get_buffer_block_flags(*var) : ir.get_buffer_block_type_flags(*type);
2604- if (var)
2605- storage = var->storage;
2627+ auto storage = var ? var->storage : heap_meta->storage;
2628+
2629+ if (heap_meta)
2630+ {
2631+ if (heap_meta->nonreadable)
2632+ flags.set(DecorationNonReadable);
2633+ if (heap_meta->nonwritable)
2634+ flags.set(DecorationNonWritable);
2635+ }
26062636
26072637 bool ssbo = storage == StorageClassStorageBuffer || storage == StorageClassShaderRecordBufferKHR ||
26082638 has_decoration(type->self, DecorationBufferBlock);
@@ -2615,6 +2645,15 @@ void CompilerGLSL::emit_buffer_block_native(const SPIRVariable *var, SPIRType *t
26152645 // Block names should never alias, but from HLSL input they kind of can because block types are reused for UAVs ...
26162646 auto buffer_name = to_name(type->self, false);
26172647
2648+ if (heap_meta)
2649+ {
2650+ // The same block type can be instantiated with different read-write decorations.
2651+ if (heap_meta->nonreadable)
2652+ buffer_name += "NoRead";
2653+ if (heap_meta->nonwritable)
2654+ buffer_name += "NoWrite";
2655+ }
2656+
26182657 auto &block_namespace = ssbo ? block_ssbo_names : block_ubo_names;
26192658
26202659 // Shaders never use the block by interface name, so we don't
@@ -2694,7 +2733,15 @@ void CompilerGLSL::emit_buffer_block_native(const SPIRVariable *var, SPIRType *t
26942733 }
26952734 else
26962735 {
2697- end_scope_decl(join("spv", to_name(type->self), "ResourceHeap[]"));
2736+ auto name = to_name(type->self);
2737+
2738+ // The same block type can be instantiated with different read-write decorations.
2739+ if (heap_meta->nonreadable)
2740+ name += "NoRead";
2741+ if (heap_meta->nonwritable)
2742+ name += "NoWrite";
2743+
2744+ end_scope_decl(join("spv", name, "ResourceHeap[]"));
26982745 }
26992746
27002747 statement("");
@@ -4147,7 +4194,7 @@ void CompilerGLSL::emit_resources()
41474194
41484195 for (const auto &heap_type : descriptor_heap_types)
41494196 {
4150- auto &type = get<SPIRType>(heap_type.first );
4197+ auto &type = get<SPIRType>(heap_type.type );
41514198
41524199 if (type.basetype == SPIRType::Image || type.basetype == SPIRType::AccelerationStructure)
41534200 {
@@ -4167,7 +4214,7 @@ void CompilerGLSL::emit_resources()
41674214 }
41684215 else
41694216 {
4170- emit_buffer_block_native(nullptr, &type, heap_type.second );
4217+ emit_buffer_block_native(nullptr, &heap_type);
41714218 }
41724219 }
41734220
@@ -12946,11 +12993,23 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
1294612993 if (untyped)
1294712994 {
1294812995 auto *var = maybe_get_backing_variable(ptr_id);
12949- if (!var || !has_decoration(var->self, DecorationBuiltIn) ||
12950- (BuiltIn(get_decoration(var->self, DecorationBuiltIn)) != BuiltInResourceHeapEXT &&
12951- BuiltIn(get_decoration(var->self, DecorationBuiltIn)) != BuiltInSamplerHeapEXT))
12996+
12997+ // Chase back to base SPIRExpression.
12998+ auto *expr = maybe_get<SPIRExpression>(ptr_id);
12999+ while (expr && !expr->buffer_pointer && expr->loaded_from)
13000+ expr = maybe_get<SPIRExpression>(expr->loaded_from);
13001+
13002+ // Buffer pointers stop the loaded from chain to deal with aliasing better, so carve that out specifically.
13003+ bool is_buffer_pointer = expr && expr->buffer_pointer;
13004+
13005+ if (!is_buffer_pointer)
1295213006 {
12953- SPIRV_CROSS_THROW("Untyped pointer access chains are currently only supported for descriptor heap access.");
13007+ if (!var || !has_decoration(var->self, DecorationBuiltIn) ||
13008+ (BuiltIn(get_decoration(var->self, DecorationBuiltIn)) != BuiltInResourceHeapEXT &&
13009+ BuiltIn(get_decoration(var->self, DecorationBuiltIn)) != BuiltInSamplerHeapEXT))
13010+ {
13011+ SPIRV_CROSS_THROW("Untyped pointer access chains are currently only supported for descriptor heap access.");
13012+ }
1295413013 }
1295513014 }
1295613015
@@ -12978,7 +13037,10 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
1297813037 // For further buffer access chains, we don't do any fixups since we have resolved to proper types.
1297913038 // For buffer types we only prepend when the access chain starts from a BufferPointerEXT base.
1298013039 // Multi-stage access chains are not possible for image types.
12981- e = join("spv", to_name(data_type.self), e);
13040+ if (ptr_expr && ptr_expr->buffer_pointer)
13041+ e = join(to_buffer_pointer_name_prefix(ptr_expr->self), e);
13042+ else
13043+ e = join("spv", to_name(data_type.self), e);
1298213044 }
1298313045 }
1298413046
@@ -13081,10 +13143,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
1308113143
1308213144 if (untyped)
1308313145 {
13084- auto &data_type = get<SPIRType>(ops[2]);
1308513146 auto *ptr_expr = maybe_get<SPIRExpression>(ptr_id);
1308613147 if (ptr_expr && ptr_expr->buffer_pointer)
13087- e = join("spv", to_name(data_type. self), e);
13148+ e = join(to_buffer_pointer_name_prefix(ptr_expr-> self), e);
1308813149 }
1308913150
1309013151 if (has_decoration(ptr_id, DecorationNonUniform))
@@ -13112,10 +13173,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
1311213173 // BufferPointerEXT can return a typed pointer, in which case we need to resolve the heap alias now.
1311313174 auto &type = get<SPIRType>(type_id);
1311413175 if (type.basetype == SPIRType::Struct)
13115- e = join("spv", to_name(type.self ), e);
13176+ e = join(to_buffer_pointer_name_prefix(result_id ), e);
1311613177
1311713178 auto &expr = set<SPIRExpression>(result_id, std::move(e), type_id, true);
13118- expr.loaded_from = chain_expr->loaded_from;
13179+ // There isn't any backing variable here. OpBufferPointerEXT is meant to be a memory declaration instruction.
13180+ expr.loaded_from = 0;
1311913181 expr.access_chain = true;
1312013182 expr.buffer_pointer = true;
1312113183 expr.implied_read_expressions = chain_expr->implied_read_expressions;
0 commit comments