mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
shader: read image descriptors indexed by workgroup
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
This commit is contained in:
@@ -9921,6 +9921,101 @@ public:
|
||||
std::vector<u32>(8, image_value + count),
|
||||
"raw buffer descriptor materialization overwrote the newer native image");
|
||||
}
|
||||
|
||||
// PPSA24156 loads an image sharp from a 148-byte record selected by
|
||||
// WorkGroupID.z, then uses the same descriptor words for dimensions.
|
||||
constexpr auto parameters = base + 0x80000;
|
||||
constexpr auto table_address = parameters + 0x100;
|
||||
std::vector<u32> table_shader{
|
||||
EncodeSop2(0x26, 8, 4, 255), 148,
|
||||
EncodeSmem0(0x02, 16), EncodeSmem1(0, 125),
|
||||
EncodeSmem0(0x0b, 32, 8), EncodeSmem1(0, 8),
|
||||
EncodeSop2(0x1e, 8, 34, InlineU32(2)),
|
||||
EncodeSop2(0x20, 9, 33, InlineU32(30)),
|
||||
EncodeSop2(0x0e, 8, 8, 255), 0xfffcu,
|
||||
EncodeSop2(0x10, 8, 8, 9),
|
||||
EncodeSop2(0x27, 9, 34, 255), 0x000e000eu,
|
||||
EncodeSop2(0x02, 8, 8, 9),
|
||||
EncodeSop2(0x02, 8, 8, InlineU32(2)),
|
||||
EncodeVop1(0x01, 0, 4), EncodeVop1(0x01, 1, InlineU32(0)),
|
||||
EncodeVop1(0x01, 2, 8),
|
||||
EncodeMimg0(0x08, 1), EncodeMimg1(2, 0, 8)};
|
||||
AppendEnd(&table_shader);
|
||||
ShaderMapUserData(reinterpret_cast<uint64_t>(table_shader.data()),
|
||||
{.type = Prospero::ShaderBinaryType::kCs,
|
||||
.code_size_bytes = static_cast<u32>(table_shader.size() * sizeof(u32))});
|
||||
shaders.SetCsShader({.data_addr = reinterpret_cast<uint64_t>(table_shader.data()),
|
||||
.num_thread_x = 1, .num_thread_y = 1, .num_thread_z = 1,
|
||||
.wave_size = 64, .user_sgpr = 2, .tgid_x_en = true,
|
||||
.tgid_y_en = true, .tgid_z_en = true});
|
||||
shaders.SetCsUserSgpr(0, static_cast<u32>(parameters), HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(1, static_cast<u32>(parameters >> 32u), HW::UserSgprType::Unknown);
|
||||
const ShaderBufferResource table_buffer{{static_cast<u32>(table_address),
|
||||
static_cast<u32>(table_address >> 32u) | (148u << 16u), 2, 0x5204u}};
|
||||
LibKernel::Memory::WriteBacking(parameters, table_buffer.fields, sizeof(table_buffer.fields));
|
||||
struct TableCase { u32 groups, width, height, image; };
|
||||
uint64_t table_program_id = 0;
|
||||
for (const auto test : {TableCase{1, 4, 2, 0}, TableCase{2, 4, 2, 0},
|
||||
TableCase{2, 8, 3, 1}, TableCase{1, 4, 2, 0}}) {
|
||||
const auto address = base + 0x90000 + test.image * 0x10000;
|
||||
const ShaderTextureResource sharp{{static_cast<u32>(address >> 8u),
|
||||
(static_cast<u32>(Prospero::BufferFormat::k32UInt) << 20u) |
|
||||
(((test.width - 1u) & 3u) << 30u),
|
||||
((test.width - 1u) >> 2u) | ((test.height - 1u) << 14u),
|
||||
DstSel(4, 5, 6, 7) |
|
||||
(static_cast<u32>(Prospero::TileMode::kLinear) << 20u) |
|
||||
(static_cast<u32>(Prospero::ImageType::kColor2D) << 28u),
|
||||
0, 0x00700000u, 0, 0}};
|
||||
std::array<u32, 74> table{};
|
||||
for (u32 group = 0; group < test.groups; group++) {
|
||||
std::copy_n(sharp.fields, 8, table.begin() + group * 37);
|
||||
}
|
||||
Require(name, "descriptor table refresh", context.InvalidateMemory(table_address, sizeof(table)),
|
||||
"the descriptor table escaped its mapped allocation");
|
||||
LibKernel::Memory::WriteBacking(table_address, table.data(), sizeof(table));
|
||||
ShaderComputeInputInfo input{};
|
||||
input.workgroup_counts[0] = input.workgroup_counts[1] = 1;
|
||||
input.workgroup_counts[2] = test.groups;
|
||||
const auto program = context.GetPipelineCache().GetComputeProgram(
|
||||
shaders.GetCs(), processor.GetCtx().GetShaderRegisters(), input);
|
||||
Require(name, "workgroup table refresh and coalescing",
|
||||
input.workgroup_counts[2] == test.groups &&
|
||||
input.stage.program->info.images.size() == 1 &&
|
||||
input.stage.program->info.images[0].indirect_resources.empty() &&
|
||||
input.stage.resources->images.size() == 1 &&
|
||||
std::equal(std::begin(sharp.fields), std::end(sharp.fields),
|
||||
input.stage.resources->images[0].dwords.begin()) &&
|
||||
!input.stage.program->info.buffers.empty(),
|
||||
"workgroup bounds, refreshed sharp, or live descriptor dimension reads were lost");
|
||||
Require(name, "workgroup table program reuse",
|
||||
table_program_id == 0 || program.id == table_program_id,
|
||||
"changing the workgroup count or identical sharp values recompiled the shader");
|
||||
table_program_id = program.id;
|
||||
const auto *snapshot = input.stage.resources;
|
||||
const auto *image_storage = snapshot->images.data();
|
||||
const auto flattened_capacity = snapshot->flattened_srt.capacity();
|
||||
const auto repeated = context.GetPipelineCache().GetComputeProgram(
|
||||
shaders.GetCs(), processor.GetCtx().GetShaderRegisters(), input);
|
||||
Require(name, "workgroup table cache-hit storage reuse",
|
||||
repeated.id == program.id && input.stage.resources == snapshot &&
|
||||
snapshot->images.data() == image_storage &&
|
||||
snapshot->flattened_srt.capacity() == flattened_capacity,
|
||||
"a repeated descriptor table hit replaced its snapshot or storage");
|
||||
auto binding = RenderExecutorTestAccess::ResolveTexture(
|
||||
context.GetRenderExecutor(), input.stage.program->info.images[0],
|
||||
input.stage.resources->images[0]);
|
||||
const auto target = textures.FindImage(binding.desc);
|
||||
TextureCacheTestAccess::ClearImage(textures, scheduler.Current(), target,
|
||||
{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}, {});
|
||||
processor.DispatchDirect(1, 1, test.groups, 0x41u);
|
||||
const auto pixels = ReadCachedTexel(name, context, target, {},
|
||||
{test.width, test.height, 1});
|
||||
for (u32 pixel = 0; pixel < pixels.size(); pixel++) {
|
||||
const auto expected = pixel < test.groups ? test.width + test.height : 0u;
|
||||
Require(name, "workgroup table GPU dimension reads", pixels[pixel] == expected,
|
||||
"a retained descriptor load used stale dimensions or the wrong record stride");
|
||||
}
|
||||
}
|
||||
context.UnmapMemory(base, allocation_size);
|
||||
scheduler.Finish();
|
||||
});
|
||||
@@ -32161,7 +32256,7 @@ void CheckIndirectBufferStore(VulkanHarness &vulkan) {
|
||||
candidate.indirect_search_iterations = 0;
|
||||
candidate.indirect_resources.clear();
|
||||
program.descriptor_sources.resize(1);
|
||||
program.descriptor_sources[0].indirect_descriptor.emplace();
|
||||
program.descriptor_sources[0].indirect_descriptor.emplace().table_stride = 16;
|
||||
ShaderComputeInputInfo compute;
|
||||
compute.wave_size = 32;
|
||||
compute.host_subgroup_size = vulkan.SubgroupSize();
|
||||
@@ -32272,7 +32367,8 @@ void CheckIndirectImageKeySwitch() {
|
||||
program.descriptor_sources.resize(2);
|
||||
program.descriptor_sources[0].dword_count = 8;
|
||||
program.descriptor_sources[0].indirect_descriptor =
|
||||
DescriptorSource::IndirectDescriptor{0u, 0u, 224u, 12u, 0u};
|
||||
DescriptorSource::IndirectDescriptor{.material_source = 0, .table_source = 0,
|
||||
.selector_stride = 224, .selector_offset = 12, .table_stride = 32};
|
||||
program.descriptor_sources[1].dword_count = 4;
|
||||
|
||||
ImageResource root{};
|
||||
@@ -39609,6 +39705,11 @@ int main(int argc, char **argv) {
|
||||
vulkan.CheckRenderExecutorStencilBindingDiscovery();
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--native-indirect-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
vulkan.CheckNativeIndirectDispatch();
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--layered-image-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
vulkan.CheckUnifiedImageViewCache();
|
||||
|
||||
Reference in New Issue
Block a user