shader: add GLC/DLC buffer cache policy support

Co-authored-by: Mac <me@itsmemac.com>
This commit is contained in:
nmzik
2026-09-24 19:02:32 +04:00
parent 6a9ae4ae43
commit dc9280d75d
11 changed files with 124 additions and 18 deletions
@@ -227,6 +227,7 @@ Emitter::SpirvRequirements Emitter::AnalyzeProgramRequirements(const IR::Program
requirements.subgroup_local_invocation_id = true;
}
if (memory.kind == IR::ResourceKind::Buffer) {
requirements.coherent_buffers |= memory.coherent;
if (memory.resource >= program.info.buffers.size()) {
Fail(program, "buffer operation has invalid resource metadata");
}
@@ -67,6 +67,7 @@ struct SpirvRequirements {
bool function_scratch = false;
bool pixel_valid_mask = false;
bool buffer_int64_atomics = false;
bool coherent_buffers = false;
};
SpirvRequirements AnalyzeProgramRequirements(const IR::Program& program);
@@ -371,12 +372,13 @@ void EmitMemoryOffsets(EmitterState& state);
uint32_t LdsDwordCount(const EmitterState& state);
struct MemoryResourceAccess {
IR::ResourceKind kind = IR::ResourceKind::None;
uint32_t object_pointer = 0;
uint32_t length = 0;
uint32_t index_offset = 0;
uint32_t byte_offset = 0;
bool add_index_offset = false;
IR::ResourceKind kind = IR::ResourceKind::None;
uint32_t object_pointer = 0;
uint32_t length = 0;
uint32_t index_offset = 0;
uint32_t byte_offset = 0;
bool add_index_offset = false;
spv::MemoryAccessMask memory_access = spv::MemoryAccessMaskNone;
};
MemoryResourceAccess PrepareMemoryResourceAccess(EmitterState& state, const IR::MemoryInfo& mem);
@@ -313,7 +313,8 @@ uint32_t LoadWordInBounds(ValueEmitContext& ctx, const MemoryResourceAccess& res
uint32_t index) {
const auto value = ctx.state.builder.AllocateId();
const auto pointer = EmitMemoryElementPointer(ctx.state, resource, index);
ctx.state.builder.AddFunction(spv::OpLoad, TypeU32(ctx.state), value, pointer);
ctx.state.builder.AddFunction(spv::OpLoad, TypeU32(ctx.state), value, pointer,
resource.memory_access);
return value;
}
@@ -498,21 +499,21 @@ void StoreSubword(ValueEmitContext& ctx, const IR::Inst& inst, IR::MemoryInfo me
});
}
void StoreWordInBounds(ValueEmitContext& ctx, const MemoryResourceAccess& resource, uint32_t index,
uint32_t data) {
ctx.state.builder.AddFunction(spv::OpStore,
EmitMemoryElementPointer(ctx.state, resource, index), data,
resource.memory_access);
}
void StoreWordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem,
const MemoryResourceAccess& resource, uint32_t data) {
const auto index = EmitMemoryElementIndex(ctx.state, resource, DwordIndex(ctx, inst, mem));
EmitIfCondition(ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index), [&]() {
ctx.state.builder.AddFunction(spv::OpStore,
EmitMemoryElementPointer(ctx.state, resource, index), data);
StoreWordInBounds(ctx, resource, index, data);
});
}
void StoreWordInBounds(ValueEmitContext& ctx, const MemoryResourceAccess& resource, uint32_t index,
uint32_t data) {
ctx.state.builder.AddFunction(spv::OpStore,
EmitMemoryElementPointer(ctx.state, resource, index), data);
}
void StoreWord(ValueEmitContext& ctx, const IR::Inst& inst, IR::MemoryInfo mem) {
EmitIfCondition(ctx.state, ctx.Arg(inst, inst.NumArgs() - 1), [&]() {
const auto resource = PrepareMemoryResourceAccess(ctx.state, mem);
@@ -86,7 +86,9 @@ MemoryResourceAccess PrepareStorageBufferResourceAccess(EmitterState& state,
}
const auto array_index =
ResourceForDescriptor(state, IR::DescriptorBindingKind::Buffers, mem.resource);
MemoryResourceAccess access {.kind = mem.kind};
MemoryResourceAccess access {
.kind = mem.kind,
.memory_access = mem.coherent ? spv::MemoryAccessVolatileMask : spv::MemoryAccessMaskNone};
access.object_pointer = state.builder.AllocateId();
state.builder.AddFunction(spv::OpAccessChain, pointer_type, access.object_pointer, variable,
ConstantU32(state, array_index));
@@ -201,6 +201,16 @@ void DefineDescriptors(EmitterState& state) {
state.builder.AddAnnotation(spv::OpDecorate, state.storage_buffer_u64_variable,
spv::DecorationAliased);
}
if (state.requirements.coherent_buffers) {
// RDNA2 stores publish to L2 even without GLC; every alias of the buffer
// must participate in visibility for cache-bypassing polling loads.
state.builder.AddAnnotation(spv::OpDecorate, state.storage_buffer_variable,
spv::DecorationCoherent);
if (state.storage_buffer_u64_variable != 0) {
state.builder.AddAnnotation(spv::OpDecorate, state.storage_buffer_u64_variable,
spv::DecorationCoherent);
}
}
break;
case IR::DescriptorBindingKind::BdaPagetable:
state.bda_pagetable_variable = Define(StorageBufferU64Type(state), "bda_pagetable");