mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-31 09:28:29 +00:00
shader: rely on robustBufferAccess2 for storage buffer bounds
This commit is contained in:
1 parent
ec746622c2
commit
ee034be4b2
10 files changed
+276
-19
No files matched your search
@@ -15,6 +15,8 @@ struct Profile {
|
||||
bool native_float_min_max = false; // NMin/NMax give the guest's NaN and signed-zero results.
|
||||
// OpReadClockKHR Device tick in picoseconds; 0 without shaderDeviceClock.
|
||||
uint32_t device_clock_period_ps = 0;
|
||||
// Storage buffer elements past the descriptor range, to the byte, read zero and drop writes.
|
||||
bool robust_buffer_access = false;
|
||||
};
|
||||
|
||||
inline constexpr Profile DefaultProfile {};
|
||||
|
||||
@@ -449,6 +449,10 @@ MemoryResourceAccess PrepareStorageBufferResourceAccess(EmitterState& st
|
||||
|
||||
uint32_t EmitMemoryElementInBounds(EmitterState& state, const MemoryResourceAccess& access,
|
||||
uint32_t index);
|
||||
// EmitMemoryElementInBounds, or true for storage buffers the device bounds-checks; only
|
||||
// loads and plain stores may use it.
|
||||
uint32_t EmitStorageElementInBounds(EmitterState& state, const MemoryResourceAccess& access,
|
||||
uint32_t index);
|
||||
|
||||
uint32_t EmitMemoryElementPointer(EmitterState& state, const MemoryResourceAccess& access,
|
||||
uint32_t index);
|
||||
|
||||
@@ -380,7 +380,7 @@ uint32_t LoadWordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const IR:
|
||||
const MemoryResourceAccess& resource) {
|
||||
const auto index = DwordIndex(ctx, inst, mem, resource.byte_offset);
|
||||
return EmitValueOrZeroIfCondition(
|
||||
ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index),
|
||||
ctx.state, EmitStorageElementInBounds(ctx.state, resource, index),
|
||||
[&]() { return LoadWordInBounds(ctx, resource, index); });
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ uint32_t LoadSubwordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const
|
||||
ctx.state, spv::OpShiftRightLogical, TypeU32(ctx.state), address,
|
||||
ConstantU32(ctx.state, std::countr_zero(resource.element_bits / 8u)));
|
||||
return EmitValueOrZeroIfCondition(
|
||||
ctx.state, EmitMemoryElementInBounds(ctx.state, resource, index), [&]() {
|
||||
ctx.state, EmitStorageElementInBounds(ctx.state, resource, index), [&]() {
|
||||
return LoadSubwordInBounds(ctx, resource, address, index, bits, sign_extend);
|
||||
});
|
||||
}
|
||||
@@ -561,11 +561,14 @@ void StoreSubwordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const IR:
|
||||
const auto index = Binary(
|
||||
ctx.state, spv::OpShiftRightLogical, TypeU32(ctx.state), address,
|
||||
ConstantU32(ctx.state, std::countr_zero(resource.element_bits / 8u)));
|
||||
EmitIfCondition(
|
||||
ctx.state, BufferIndexInBounds(ctx, inst, mem, resource,
|
||||
EmitMemoryElementInBounds(ctx.state, resource, index)), [&]() {
|
||||
StoreSubwordInBounds(ctx, mem, resource, address, index, bits, data);
|
||||
});
|
||||
// 32-bit views merge subwords in a compare-exchange loop, and out-of-range atomics return
|
||||
// undefined values.
|
||||
const auto in_bounds = resource.element_bits < 32u
|
||||
? EmitStorageElementInBounds(ctx.state, resource, index)
|
||||
: EmitMemoryElementInBounds(ctx.state, resource, index);
|
||||
EmitIfCondition(ctx.state, BufferIndexInBounds(ctx, inst, mem, resource, in_bounds), [&]() {
|
||||
StoreSubwordInBounds(ctx, mem, resource, address, index, bits, data);
|
||||
});
|
||||
}
|
||||
|
||||
void StoreSubword(ValueEmitContext& ctx, const IR::Inst& inst, IR::MemoryInfo mem, uint32_t bits) {
|
||||
@@ -632,7 +635,7 @@ void StoreWordPrepared(ValueEmitContext& ctx, const IR::Inst& inst, const IR::Me
|
||||
if (resource.object_pointer == 0u) return;
|
||||
const auto index = DwordIndex(ctx, inst, mem, resource.byte_offset);
|
||||
const auto in_bounds = BufferIndexInBounds(ctx, inst, mem, resource,
|
||||
EmitMemoryElementInBounds(ctx.state, resource, index));
|
||||
EmitStorageElementInBounds(ctx.state, resource, index));
|
||||
EmitIfCondition(ctx.state, in_bounds, [&]() {
|
||||
StoreWordInBounds(ctx, resource, index, data);
|
||||
});
|
||||
@@ -1604,10 +1607,18 @@ void EmitReadConstBuffer(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
}
|
||||
const auto access = PrepareMemoryResourceAccess(state, mem);
|
||||
// Scalar buffer addressing aligns the base and each offset independently.
|
||||
const auto element = Binary(
|
||||
auto element = Binary(
|
||||
state, spv::OpIAdd, TypeU32(state), index,
|
||||
Binary(state, spv::OpShiftRightLogical, TypeU32(state), access.byte_offset, ConstantU32(state, 2)));
|
||||
const auto condition = EmitMemoryElementInBounds(state, access, element);
|
||||
// The device computes byte offsets in 32 bits, so elements from 2^30 on would wrap back into
|
||||
// the range; the host prefix adds at most 63.
|
||||
constexpr uint32_t last_element = UINT32_MAX >> 2u;
|
||||
if (state.profile.robust_buffer_access &&
|
||||
(!offset.IsImmediate() || (offset.U32() >> 2u) + (mem.offset >> 2u) > last_element - 63u)) {
|
||||
element = EmitGlsl<GLSLstd450UMin, IR::Type::U32>(state, element,
|
||||
ConstantU32(state, last_element));
|
||||
}
|
||||
const auto condition = EmitStorageElementInBounds(state, access, element);
|
||||
ctx.Define(inst, EmitValueOrZeroIfCondition(state, condition, [&]() {
|
||||
return EmitNative<spv::OpLoad, IR::Type::U32>(
|
||||
state, EmitMemoryElementPointer(state, access, element));
|
||||
|
||||
@@ -341,6 +341,16 @@ uint32_t EmitMemoryElementInBounds(EmitterState& state, const MemoryResourceAcce
|
||||
return in_bounds;
|
||||
}
|
||||
|
||||
uint32_t EmitStorageElementInBounds(EmitterState& state, const MemoryResourceAccess& access,
|
||||
uint32_t index) {
|
||||
// The descriptor range ends where access.length does.
|
||||
if (state.profile.robust_buffer_access && (access.kind == IR::ResourceKind::Buffer ||
|
||||
access.kind == IR::ResourceKind::ScalarBuffer)) {
|
||||
return ConstantBool(state, true);
|
||||
}
|
||||
return EmitMemoryElementInBounds(state, access, index);
|
||||
}
|
||||
|
||||
uint32_t EmitMemoryElementPointer(EmitterState& state, const MemoryResourceAccess& access,
|
||||
uint32_t index) {
|
||||
if (access.kind == IR::ResourceKind::Lds || access.kind == IR::ResourceKind::Scratch) {
|
||||
|
||||
Reference in new issue
Block a user