mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
shader: bound scalar-read overlap checks by the bytes fixed-offset buffer writes reach
This commit is contained in:
@@ -941,8 +941,12 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
|||||||
for (const auto& resource: program.info.buffers) {
|
for (const auto& resource: program.info.buffers) {
|
||||||
if (!resource.written || resource.descriptor_index == UINT32_MAX) continue;
|
if (!resource.written || resource.descriptor_index == UINT32_MAX) continue;
|
||||||
const auto& written = writer->buffer_sources[resource.descriptor_index];
|
const auto& written = writer->buffer_sources[resource.descriptor_index];
|
||||||
if (written.size != 0 && ImageRangeOverlaps(address, size,
|
// ADD_TID and swizzle move fixed-offset writes past write_extent.
|
||||||
written.address, written.size)) {
|
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");
|
EXIT("scalar resource reads overlap a shader buffer write\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ struct BufferResource {
|
|||||||
uint32_t descriptor_index = UINT32_MAX;
|
uint32_t descriptor_index = UINT32_MAX;
|
||||||
uint32_t first_use_pc = 0;
|
uint32_t first_use_pc = 0;
|
||||||
uint32_t max_byte_extent = 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;
|
uint32_t packed_stride = 0;
|
||||||
Prospero::BufferFormat descriptor_format = Prospero::BufferFormat::kInvalid;
|
Prospero::BufferFormat descriptor_format = Prospero::BufferFormat::kInvalid;
|
||||||
uint32_t descriptor_swizzle = DstSel(4, 5, 6, 7);
|
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++) {
|
for (uint32_t i = 0; i < m_info.buffers.size(); i++) {
|
||||||
if (m_info.buffers[i].source == source) {
|
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;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3762,13 +3762,14 @@ private:
|
|||||||
BufferResource resource;
|
BufferResource resource;
|
||||||
resource.source = source;
|
resource.source = source;
|
||||||
resource.first_use_pc = pc;
|
resource.first_use_pc = pc;
|
||||||
Merge(resource, memory, op, pc);
|
Merge(resource, memory, inst, pc);
|
||||||
m_info.buffers.push_back(resource);
|
m_info.buffers.push_back(resource);
|
||||||
return static_cast<uint32_t>(m_info.buffers.size() - 1);
|
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) {
|
uint32_t pc) {
|
||||||
|
const auto op = inst.GetOpcode();
|
||||||
const auto access = BufferAccessOf(op);
|
const auto access = BufferAccessOf(op);
|
||||||
const bool atomic = access == BufferAccess::Atomic;
|
const bool atomic = access == BufferAccess::Atomic;
|
||||||
const bool write = access == BufferAccess::Write || 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.max_byte_extent = std::max(resource.max_byte_extent, ByteExtent(memory));
|
||||||
resource.read = resource.read || !write || atomic;
|
resource.read = resource.read || !write || atomic;
|
||||||
resource.written = resource.written || write;
|
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.atomic = resource.atomic || atomic;
|
||||||
resource.formatted = resource.formatted || memory.formatted;
|
resource.formatted = resource.formatted || memory.formatted;
|
||||||
resource.scalar = resource.scalar || op == ValueOpcode::ReadConstBuffer ||
|
resource.scalar = resource.scalar || op == ValueOpcode::ReadConstBuffer ||
|
||||||
@@ -3945,7 +3953,7 @@ private:
|
|||||||
m_info.uses_dma = true;
|
m_info.uses_dma = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
resource = AddBuffer(source, memory, op, flags.pc);
|
resource = AddBuffer(source, memory, inst, flags.pc);
|
||||||
if (resource == UINT32_MAX) {
|
if (resource == UINT32_MAX) {
|
||||||
Fail(flags.pc, "buffer resource limit exceeded");
|
Fail(flags.pc, "buffer resource limit exceeded");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user