shader: bound scalar-read overlap checks by the bytes fixed-offset buffer writes reach

This commit is contained in:
nmzik
2026-10-21 03:48:25 +02:00
parent 70668fbd98
commit 68d0ba5a81
3 changed files with 20 additions and 7 deletions
@@ -941,8 +941,12 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
for (const auto& resource: program.info.buffers) {
if (!resource.written || resource.descriptor_index == UINT32_MAX) continue;
const auto& written = writer->buffer_sources[resource.descriptor_index];
if (written.size != 0 && ImageRangeOverlaps(address, size,
written.address, written.size)) {
// ADD_TID and swizzle move fixed-offset writes past write_extent.
const bool linear = (resource.packed_stride & ((1u << 14u) | (1u << 20u))) == 0u;
const auto written_size =
linear ? std::min<uint64_t>(written.size, resource.write_extent) : written.size;
if (written_size != 0 && ImageRangeOverlaps(address, size,
written.address, written_size)) {
EXIT("scalar resource reads overlap a shader buffer write\n");
}
}
@@ -125,6 +125,7 @@ struct BufferResource {
uint32_t descriptor_index = UINT32_MAX;
uint32_t first_use_pc = 0;
uint32_t max_byte_extent = 0;
uint32_t write_extent = 0; // UINT32_MAX once a write is runtime-addressed or formatted
uint32_t packed_stride = 0;
Prospero::BufferFormat descriptor_format = Prospero::BufferFormat::kInvalid;
uint32_t descriptor_swizzle = DstSel(4, 5, 6, 7);
@@ -3749,10 +3749,10 @@ private:
}
}
uint32_t AddBuffer(uint32_t source, const MemoryInfo& memory, ValueOpcode op, uint32_t pc) {
uint32_t AddBuffer(uint32_t source, const MemoryInfo& memory, const Inst& inst, uint32_t pc) {
for (uint32_t i = 0; i < m_info.buffers.size(); i++) {
if (m_info.buffers[i].source == source) {
Merge(m_info.buffers[i], memory, op, pc);
Merge(m_info.buffers[i], memory, inst, pc);
return i;
}
}
@@ -3762,13 +3762,14 @@ private:
BufferResource resource;
resource.source = source;
resource.first_use_pc = pc;
Merge(resource, memory, op, pc);
Merge(resource, memory, inst, pc);
m_info.buffers.push_back(resource);
return static_cast<uint32_t>(m_info.buffers.size() - 1);
}
static void Merge(BufferResource& resource, const MemoryInfo& memory, ValueOpcode op,
static void Merge(BufferResource& resource, const MemoryInfo& memory, const Inst& inst,
uint32_t pc) {
const auto op = inst.GetOpcode();
const auto access = BufferAccessOf(op);
const bool atomic = access == BufferAccess::Atomic;
const bool write = access == BufferAccess::Write || atomic;
@@ -3776,6 +3777,13 @@ private:
resource.max_byte_extent = std::max(resource.max_byte_extent, ByteExtent(memory));
resource.read = resource.read || !write || atomic;
resource.written = resource.written || write;
if (write) {
// Formatted stores write the whole format; otherwise zero index, VGPR and SGPR offsets
// leave only the immediate offset.
const bool fixed = !memory.formatted && inst.Arg(1).Resolve() == Value(0u) &&
inst.Arg(2).Resolve() == Value(0u) && inst.Arg(3).Resolve() == Value(0u);
resource.write_extent = std::max(resource.write_extent, fixed ? ByteExtent(memory) : UINT32_MAX);
}
resource.atomic = resource.atomic || atomic;
resource.formatted = resource.formatted || memory.formatted;
resource.scalar = resource.scalar || op == ValueOpcode::ReadConstBuffer ||
@@ -3945,7 +3953,7 @@ private:
m_info.uses_dma = true;
return;
}
resource = AddBuffer(source, memory, op, flags.pc);
resource = AddBuffer(source, memory, inst, flags.pc);
if (resource == UINT32_MAX) {
Fail(flags.pc, "buffer resource limit exceeded");
}