mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
shader: track buffer liveness and offsets by resource count
Co-authored-by: fxpw <fxpw@outlook.com>
This commit is contained in:
@@ -18,7 +18,7 @@ namespace {
|
||||
}
|
||||
|
||||
void ValidateNativeProgram(const IR::Program& program, bool lds_storage) {
|
||||
uint64_t live_buffers = 0;
|
||||
std::vector<bool> live_buffers(program.info.buffers.size());
|
||||
bool uses_lds = false;
|
||||
bool uses_gds = false;
|
||||
const auto uses_mapping = [](const auto& resource) {
|
||||
@@ -85,12 +85,12 @@ void ValidateNativeProgram(const IR::Program& program, bool lds_storage) {
|
||||
if (memory.resource >= program.info.buffers.size()) {
|
||||
Fail(program, "typed shader contains an invalid buffer resource");
|
||||
}
|
||||
live_buffers |= uint64_t{1} << memory.resource;
|
||||
live_buffers[memory.resource] = true;
|
||||
for (const auto child: program.info.buffers[memory.resource].indirect_resources) {
|
||||
if (child >= program.info.buffers.size()) {
|
||||
Fail(program, "typed shader contains an invalid indirect buffer resource");
|
||||
}
|
||||
live_buffers |= uint64_t{1} << child;
|
||||
live_buffers[child] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,8 +149,9 @@ void ValidateNativeProgram(const IR::Program& program, bool lds_storage) {
|
||||
std::array<uint32_t, static_cast<size_t>(Kind::Count)> expected {};
|
||||
auto& buffer_count = expected[static_cast<size_t>(Kind::Buffers)];
|
||||
for (uint32_t index = 0; index < program.info.buffers.size(); ++index) {
|
||||
const auto slot = (live_buffers & (uint64_t{1} << index)) != 0 ? buffer_count++ : UINT32_MAX;
|
||||
if (program.info.buffers[index].descriptor_index != slot) {
|
||||
const auto slot = live_buffers[index] ? buffer_count++ : UINT32_MAX;
|
||||
if (program.info.buffers[index].live != live_buffers[index] ||
|
||||
program.info.buffers[index].descriptor_index != slot) {
|
||||
Fail(program, "native buffer descriptor index does not match shader topology");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ struct EmitterState {
|
||||
uint32_t lane_count = 1;
|
||||
uint32_t lane_half = 0;
|
||||
std::array<BufferDefinition, 4> storage_buffers {};
|
||||
std::array<uint32_t, IR::ShaderInfo::MaxBuffers> memory_byte_offsets {};
|
||||
std::vector<uint32_t> memory_byte_offsets;
|
||||
uint32_t bda_pagetable_variable = 0;
|
||||
uint32_t fault_buffer_variable = 0;
|
||||
uint32_t bda_pointer_function = 0;
|
||||
|
||||
@@ -129,14 +129,15 @@ bool UsesSharedIndirectBufferAccess(const EmitterState& state, uint32_t resource
|
||||
}
|
||||
|
||||
void EmitMemoryOffsets(EmitterState& state) {
|
||||
std::array<bool, IR::ShaderInfo::MaxBuffers> dynamic_offsets {};
|
||||
const auto count = state.program.bindings.descriptor_counts[static_cast<size_t>(IR::DescriptorBindingKind::Buffers)];
|
||||
state.memory_byte_offsets.resize(count);
|
||||
std::vector<bool> dynamic_offsets(count);
|
||||
for (uint32_t resource = 0; resource < state.program.info.buffers.size(); ++resource) {
|
||||
if (!UsesSharedIndirectBufferAccess(state, resource)) continue;
|
||||
for (const auto candidate: state.program.info.buffers[resource].indirect_resources) {
|
||||
dynamic_offsets[state.program.info.buffers[candidate].descriptor_index] = true;
|
||||
}
|
||||
}
|
||||
const auto count = state.program.bindings.descriptor_counts[static_cast<size_t>(IR::DescriptorBindingKind::Buffers)];
|
||||
for (uint32_t i = 0; i < count; i += 4u) {
|
||||
const auto lanes = std::min(4u, count - i);
|
||||
if (std::all_of(dynamic_offsets.begin() + i, dynamic_offsets.begin() + i + lanes,
|
||||
|
||||
@@ -212,9 +212,8 @@ void DefineDescriptors(EmitterState& state) {
|
||||
auto& bindings = state.program.bindings;
|
||||
auto& counts = bindings.descriptor_counts;
|
||||
auto& buffer_count = counts[static_cast<size_t>(Kind::Buffers)];
|
||||
for (uint32_t index = 0; index < info.buffers.size(); ++index) {
|
||||
info.buffers[index].descriptor_index = (info.live_buffers & (uint64_t{1} << index)) != 0
|
||||
? buffer_count++ : UINT32_MAX;
|
||||
for (auto& buffer: info.buffers) {
|
||||
buffer.descriptor_index = buffer.live ? buffer_count++ : UINT32_MAX;
|
||||
}
|
||||
std::array<const IR::ImageResource*, IR::ImageBindingCount> image_types {};
|
||||
for (auto& image: info.images) {
|
||||
|
||||
@@ -129,6 +129,7 @@ struct BufferResource {
|
||||
bool atomic = false;
|
||||
bool formatted = false;
|
||||
bool scalar = false;
|
||||
bool live = false;
|
||||
uint32_t indirect_root = NoIndirectBuffer;
|
||||
uint32_t indirect_mapping_offset = 0;
|
||||
uint32_t indirect_search_iterations = 0;
|
||||
@@ -493,7 +494,6 @@ struct ShaderInfo {
|
||||
std::vector<StageInput> inputs;
|
||||
std::vector<StageOutput> outputs;
|
||||
std::vector<uint32_t> user_data_registers;
|
||||
uint64_t live_buffers = 0;
|
||||
std::array<uint8_t, 32> vertex_fetch_components {};
|
||||
int32_t vertex_offset_sgpr = -1;
|
||||
int32_t instance_offset_sgpr = -1;
|
||||
|
||||
@@ -311,12 +311,12 @@ void Visit(Program& program, ShaderStageInputInfo input_info, InputUsage& inputs
|
||||
if (memory.resource >= info.buffers.size() || memory.resource >= ShaderInfo::MaxBuffers) {
|
||||
return Fail("buffer operation has invalid resource metadata");
|
||||
}
|
||||
info.live_buffers |= uint64_t{1} << memory.resource;
|
||||
info.buffers[memory.resource].live = true;
|
||||
for (const auto child: info.buffers[memory.resource].indirect_resources) {
|
||||
if (child >= info.buffers.size()) {
|
||||
return Fail("indirect buffer operation has invalid resource metadata");
|
||||
}
|
||||
info.live_buffers |= uint64_t{1} << child;
|
||||
info.buffers[child].live = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -572,7 +572,7 @@ void CollectShaderInfo(Program& program, ShaderStageInputInfo input_info) {
|
||||
info.inputs.clear();
|
||||
info.outputs.clear();
|
||||
info.user_data_registers.clear();
|
||||
info.live_buffers = 0;
|
||||
for (auto& buffer: info.buffers) buffer.live = false;
|
||||
info.has_bitwise_xor = info.uses_lds = info.uses_gds = info.uses_flattened_srt =
|
||||
info.uses_dispatch_threads = info.uses_swizzle = false;
|
||||
info.bvh = info.subgroup_ballot = info.subgroup_barrier = info.subgroup_shuffle = info.subgroup_arithmetic =
|
||||
|
||||
@@ -4602,7 +4602,7 @@ void TestDynamicSrtReadRemainsExplicit() {
|
||||
ShaderComputeInputInfo compute{};
|
||||
CollectShaderInfo(fixture.program, {.compute = &compute});
|
||||
Check(!fixture.program.info.uses_flattened_srt && fixture.program.info.uses_dma &&
|
||||
fixture.program.info.live_buffers == 1u,
|
||||
fixture.program.info.buffers.size() == 1u && fixture.program.info.buffers[0].live,
|
||||
"dynamic scalar read received the wrong resource usage");
|
||||
}
|
||||
|
||||
@@ -6969,9 +6969,9 @@ void TestShaderInfoCollection() {
|
||||
{fixture.UserData(3), fixture.UserData(4), Value(64u), Value(0u)}, 4);
|
||||
MemoryInfo buffer;
|
||||
buffer.kind = ResourceKind::Buffer;
|
||||
fixture.Emit(ValueOpcode::LoadBufferU32,
|
||||
{handle, Value(0u), Value(0u), Value(0u), Value(true)},
|
||||
fixture.AddMemory(buffer, 4));
|
||||
const auto load = fixture.Emit(ValueOpcode::LoadBufferU32,
|
||||
{handle, Value(0u), Value(0u), Value(0u), Value(true)},
|
||||
fixture.AddMemory(buffer, 4));
|
||||
const auto invocation = fixture.Emit(
|
||||
ValueOpcode::GetBuiltin,
|
||||
{Value(static_cast<uint32_t>(StageInputKind::GlobalInvocationId)),
|
||||
@@ -6993,7 +6993,7 @@ void TestShaderInfoCollection() {
|
||||
StageInputKind::GlobalInvocationId,
|
||||
"typed shader values were not reflected in shader info");
|
||||
|
||||
Check(fixture.program.info.live_buffers == 1u &&
|
||||
Check(fixture.program.info.buffers.size() == 1u && fixture.program.info.buffers[0].live &&
|
||||
fixture.program.info.uses_gds && !fixture.program.info.uses_lds,
|
||||
"typed resources were not collected in shader info");
|
||||
Check(NativeBinding(ShaderType::Compute, DescriptorBindingKind::Buffers) ==
|
||||
@@ -7006,6 +7006,11 @@ void TestShaderInfoCollection() {
|
||||
"fixed stage binding ranges are inconsistent");
|
||||
Check(fixture.program.info.user_data_registers == std::vector<uint32_t>({3u, 4u}),
|
||||
"shader info did not collect live typed user-data values");
|
||||
load.ResolveInstruction()->Invalidate();
|
||||
fixture.program.shader_info_complete = false;
|
||||
CollectShaderInfo(fixture.program, {.compute = &compute});
|
||||
Check(!fixture.program.info.buffers[0].live,
|
||||
"shader info recollection retained a removed buffer use");
|
||||
}
|
||||
|
||||
void TestImageBindingAbi() {
|
||||
@@ -7172,7 +7177,8 @@ void TestResourceLimitIsTransactional() {
|
||||
"compute shader did not retain all 64 distinct buffers");
|
||||
ShaderComputeInputInfo compute{};
|
||||
CollectShaderInfo(accepted.program, {.compute = &compute});
|
||||
Check(accepted.program.info.live_buffers == UINT64_MAX,
|
||||
Check(std::ranges::all_of(accepted.program.info.buffers,
|
||||
[](const auto &buffer) { return buffer.live; }),
|
||||
"shader info truncated the 64 live buffers");
|
||||
|
||||
Fixture fixture;
|
||||
|
||||
Reference in New Issue
Block a user