mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
graphics: fix vertex and instance IDs for unpatched indirect draws
This commit is contained in:
@@ -19739,9 +19739,9 @@ public:
|
||||
"the draw's cull mode or front face did not reach the host GPU");
|
||||
registers.SetModeControl({});
|
||||
|
||||
// Indirect records come from the GPU copy; the CPU backing holds zeros. In each pair the
|
||||
// first record draws nothing and the second covers the target, through vertex offset 7
|
||||
// for embedded fetches.
|
||||
// Indirect records come from the GPU copy; the CPU backing holds zeros. Embedded
|
||||
// fetches use vertex offset 7. Native shaders receive raw vertex/instance IDs when
|
||||
// the packet does not patch either offset SGPR, even with nonzero record offsets.
|
||||
{
|
||||
constexpr uint64_t vertices_address = depth_address + 0x38000;
|
||||
constexpr uint64_t args_address = vertices_address + 0x100;
|
||||
@@ -19752,19 +19752,23 @@ public:
|
||||
sizeof(positions));
|
||||
constexpr uint32_t stride = 32;
|
||||
const vk::DrawIndexedIndirectCommand indexed_records[]{
|
||||
{3, 1, 0, 0, 5}, {3, 1, 0, 7, 5}, {0, 1, 0, 0, 0}, {3, 1, 0, 0, 0}};
|
||||
{3, 1, 0, 0, 5}, {3, 1, 0, 7, 5}, {0, 1, 0, 0, 0}, {3, 1, 0, 0, 0},
|
||||
{0, 1, 0, 0, 0}, {3, 1, 0, -7, 0}, {0, 1, 0, 0, 0}, {3, 1, 0, 0, 11}};
|
||||
const vk::DrawIndirectCommand auto_records[]{{3, 1, 0, 5}, {3, 1, 7, 5}, {0, 1, 0, 0},
|
||||
{3, 1, 0, 0}};
|
||||
for (u32 i = 0; i < 4; i++) {
|
||||
{3, 1, 0, 0}, {0, 1, 0, 0}, {3, 1, 13, 0},
|
||||
{0, 1, 0, 0}, {3, 1, 0, 11}};
|
||||
constexpr u32 records_per_kind = std::size(indexed_records);
|
||||
static_assert(records_per_kind == std::size(auto_records));
|
||||
for (u32 i = 0; i < records_per_kind; i++) {
|
||||
std::memcpy(reinterpret_cast<void *>(args_address + i * stride), &indexed_records[i],
|
||||
sizeof(indexed_records[i]));
|
||||
std::memcpy(reinterpret_cast<void *>(args_address + (4 + i) * stride), &auto_records[i],
|
||||
sizeof(auto_records[i]));
|
||||
std::memcpy(reinterpret_cast<void *>(args_address + (records_per_kind + i) * stride),
|
||||
&auto_records[i], sizeof(auto_records[i]));
|
||||
}
|
||||
// Larger than a caching page, so the arguments are cached instead of streamed.
|
||||
(void)context.GetBufferCache().ObtainBuffer(
|
||||
vertices_address, BufferCache::CACHING_PAGESIZE * 2, false);
|
||||
const std::array<u32, 8 * stride / 4> zeros{};
|
||||
const std::array<u32, 2 * records_per_kind * stride / 4> zeros{};
|
||||
Require("GpuIndirectDraw", "CPU backing",
|
||||
LibKernel::Memory::TryWriteBacking(args_address, zeros.data(), sizeof(zeros)),
|
||||
"the CPU copy of the arguments could not be cleared");
|
||||
@@ -19825,26 +19829,35 @@ public:
|
||||
}
|
||||
};
|
||||
check("indexed embedded fetch", fetch_vs, true, 0);
|
||||
check("auto embedded fetch", fetch_vs, false, 4);
|
||||
check("auto embedded fetch", fetch_vs, false, records_per_kind);
|
||||
check("indexed native fetch", vertex_address, true, 2);
|
||||
check("auto native fetch", vertex_address, false, 6);
|
||||
check("auto native fetch", vertex_address, false, records_per_kind + 2);
|
||||
// Pipelines created from only their key and stage modules draw the same.
|
||||
scheduler.Finish();
|
||||
Require("PipelineFromKey", "vertex input pipelines",
|
||||
PipelineCacheTestAccess::RecreateGraphicsPipelines(context.GetPipelineCache()) > 0,
|
||||
"no cached graphics pipeline named only compiled modules");
|
||||
check("recreated indexed embedded fetch", fetch_vs, true, 0);
|
||||
check("recreated auto native fetch", vertex_address, false, 6);
|
||||
check("recreated auto native fetch", vertex_address, false, records_per_kind + 2);
|
||||
// Patched user SGPRs 0/1 read the records' base vertex 7 and first instance 5, not the
|
||||
// table pointers they hold, and the index VGPRs exclude both bases.
|
||||
check("indexed patched offsets", indirect_vs, true, 0, {0, 1});
|
||||
check("auto patched offsets", indirect_vs, false, 4, {0, 1});
|
||||
check("auto patched offsets", indirect_vs, false, records_per_kind, {0, 1});
|
||||
// Slots 4/5 lie past USER_SGPR, so the tables survive; rewritten fetches keep Vulkan's
|
||||
// vertex offset.
|
||||
check("indexed patched embedded fetch", fetch_vs, true, 0, {4, 5});
|
||||
// Patching one offset still leaves both bases out of the index VGPRs.
|
||||
check("auto instance-only patch", vertex_address, false, 5,
|
||||
check("auto instance-only patch", vertex_address, false, records_per_kind + 1,
|
||||
{ShaderIndirectOffsets::None, 1});
|
||||
// SH_NOP leaves the existing SGPR values intact; the native prolog adds these
|
||||
// values once while the record's unrelated offsets are ignored. Check each base
|
||||
// independently so a correct vertex offset cannot hide a broken instance offset.
|
||||
shaders.SetGsUserSgpr(0, 7);
|
||||
shaders.SetGsUserSgpr(1, 5);
|
||||
check("indexed unpatched vertex offset", indirect_vs, true, 4);
|
||||
check("auto unpatched vertex offset", indirect_vs, false, records_per_kind + 4);
|
||||
check("indexed unpatched instance offset", indirect_vs, true, 6);
|
||||
check("auto unpatched instance offset", indirect_vs, false, records_per_kind + 6);
|
||||
}
|
||||
|
||||
// A fourth VS invocation reads beyond the descriptor instead of reconstructing the corner.
|
||||
@@ -47399,7 +47412,7 @@ void CheckEmbeddedFetchVertexOffset() {
|
||||
vertex.tess = {.input_control_points = 3, .output_control_points = 3,
|
||||
.ls_stride = 124, .hs_stride = 128, .domain = 1,
|
||||
.partitioning = 2, .output_topology = 2};
|
||||
vertex.fetch_embedded = true;
|
||||
vertex.has_dynamic_vertex_fetch = true;
|
||||
vertex.fetch_buffer_reg = 0;
|
||||
vertex.fetch_attrib_reg = 2;
|
||||
vertex.resources_num = 1;
|
||||
@@ -47439,7 +47452,7 @@ void CheckEmbeddedFetchVertexOffset() {
|
||||
const auto Resolve = [](const CompiledShader &result,
|
||||
u32 index_offset) {
|
||||
ShaderVertexInputInfo vertex;
|
||||
vertex.fetch_embedded = true;
|
||||
vertex.has_dynamic_vertex_fetch = true;
|
||||
ShaderModule module;
|
||||
module.info.user_data_base = result.program.user_data_base;
|
||||
module.info.info.vertex_offset_sgpr = result.program.info.vertex_offset_sgpr;
|
||||
@@ -47450,7 +47463,7 @@ void CheckEmbeddedFetchVertexOffset() {
|
||||
|
||||
const auto ResolveInstance = [](const CompiledShader &result) {
|
||||
ShaderVertexInputInfo vertex;
|
||||
vertex.fetch_embedded = true;
|
||||
vertex.has_dynamic_vertex_fetch = true;
|
||||
ShaderModule module;
|
||||
module.info.user_data_base = result.program.user_data_base;
|
||||
module.info.info.instance_offset_sgpr =
|
||||
@@ -50344,7 +50357,7 @@ void CheckEmbeddedFetchLaneSpill() {
|
||||
|
||||
std::array<u32, 11> user_data{};
|
||||
ShaderVertexInputInfo vertex;
|
||||
vertex.fetch_embedded = true;
|
||||
vertex.has_dynamic_vertex_fetch = true;
|
||||
vertex.fetch_buffer_reg = 0;
|
||||
vertex.resources_num = 1;
|
||||
vertex.resources[0].fields[3] =
|
||||
|
||||
@@ -1938,7 +1938,7 @@ void TestVertexBufferGrouping() {
|
||||
Check(input.fetch_attrib_reg == 2, "a draw reread the vertex metadata of a mapped shader");
|
||||
ShaderMapUserData(regs.es_regs.data_addr, mapped);
|
||||
(void)PrepareProgram(regs, HW::Context{}, HW::UserConfig{}, input);
|
||||
Check(!input.fetch_embedded, "remapping a shader kept its previous vertex metadata");
|
||||
Check(!input.has_dynamic_vertex_fetch, "remapping a shader kept its previous vertex metadata");
|
||||
}
|
||||
|
||||
void TestNggVertexEntryState() {
|
||||
@@ -11575,7 +11575,7 @@ void TestEmbeddedFetchPreservesSharedScalarLoad() {
|
||||
reinterpret_cast<uint64_t>(attributes.data())};
|
||||
std::memcpy(user_data.data() + 12, tables, sizeof(tables));
|
||||
ShaderVertexInputInfo input{};
|
||||
input.fetch_embedded = true;
|
||||
input.has_dynamic_vertex_fetch = true;
|
||||
input.fetch_buffer_reg = 12;
|
||||
input.fetch_attrib_reg = 14;
|
||||
input.resources_num = 1;
|
||||
|
||||
Reference in New Issue
Block a user