graphics: report GET_LOD_STATS mip-statistics slots as unsampled

Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
This commit is contained in:
nmzikandTheCruZ committed 2026-10-31 00:44:27 +01:00
1 parent 4919fdb6e6
commit 14837b0479
2 files changed
+49 -7

No files matched your search

@@ -1285,16 +1285,19 @@ KYTY_CP_OP_PARSER(CpOpGetLodStats) {
EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0038e00); EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0038e00);
const auto buffer_size = buffer[0]; const auto buffer_size = buffer[0];
auto* dst = reinterpret_cast<void*>((buffer[1] & 0xffffffc0u) | auto* dst = reinterpret_cast<volatile uint32_t*>((buffer[1] & 0xffffffc0u) |
(static_cast<uint64_t>(buffer[2]) << 32u)); (static_cast<uint64_t>(buffer[2]) << 32u));
if (dst != nullptr && buffer_size != 0) { // Mip statistics are not collected: each of up to 256 2-dword slots after the 16-dword header
memset(dst, 0, buffer_size); // reports its id (dword 0 bits 24-31) and finest sampled mip 15 (dword 1 bits 24-27), i.e. no
// Hack? // samples. A non-zero dword 0 then marks the report complete.
if (buffer_size >= sizeof(uint32_t)) { if (dst != nullptr && buffer_size >= 64) {
auto* label = static_cast<uint32_t*>(dst); const auto slots = std::min((buffer_size - 64) / 8, 256u);
*label = 1; for (uint32_t slot = 0; slot < slots; slot++) {
dst[16 + slot * 2] = slot << 24u;
dst[16 + slot * 2 + 1] = 15u << 24u;
} }
dst[0] = 1;
} }
return 4; return 4;
+39
View File
@@ -52915,6 +52915,43 @@ void CheckPm4WaitResume(RenderContext &renderer) {
std::printf("[host] %-32s ok\n", "Pm4WaitResume"); std::printf("[host] %-32s ok\n", "Pm4WaitResume");
} }
void CheckPm4LodStats(RenderContext &renderer) {
constexpr const char *name = "Pm4LodStats";
GraphicsInitJmpTables();
CommandProcessor processor(renderer, 0);
// A 16-dword header, 256 two-dword slots and a guard the CP must leave unwritten.
constexpr uint32_t poison = 0xa5a5a5a5u;
alignas(64) std::array<uint32_t, 16 + 256 * 2 + 4> report{};
std::array<uint32_t, 5> packet{};
const auto run = [&](uint32_t size) {
report.fill(poison);
report[0] = 0;
CommandBufferLayout dcb{packet.data(), packet.data() + packet.size(), packet.data(),
packet.data() + packet.size(), nullptr, nullptr, 0};
Pm4Execution execution;
return Gen5::AgcDcbGetLodStats(reinterpret_cast<Gen5::CommandBuffer *>(&dcb), 0,
report.data(), size, 0, 0, 0, 0) == packet.data() &&
processor.Process(execution, packet) == Pm4ProcessResult::Complete && report[0] != 0;
};
// Slots below the count report no samples (finest mip 15); everything after them is untouched.
const auto empty_slots = [&](uint32_t slots) {
for (uint32_t slot = 0; slot < slots; slot++) {
if (report[16 + slot * 2] != slot << 24u || report[17 + slot * 2] != 15u << 24u) {
return false;
}
}
return std::all_of(report.begin() + 16 + slots * 2, report.end(),
[](uint32_t dw) { return dw == poison; });
};
Require(name, "full report", run(64 + 256 * 8 + 16) && empty_slots(256),
"report did not mark exactly 256 slots unsampled");
Require(name, "partial report", run(64 + 2 * 8 + 4) && empty_slots(2),
"report did not stop at the last whole slot in the buffer");
std::printf("[host] %-32s ok\n", name);
}
void CheckPm4MemSemaphore(RenderContext &renderer) { void CheckPm4MemSemaphore(RenderContext &renderer) {
constexpr const char *name = "Pm4MemSemaphore"; constexpr const char *name = "Pm4MemSemaphore";
Loader::SymbolDatabase symbols; Loader::SymbolDatabase symbols;
@@ -54030,6 +54067,7 @@ int main(int argc, char **argv) {
CheckPm4AcquireMemPackets(vulkan.RuntimeRenderer()); CheckPm4AcquireMemPackets(vulkan.RuntimeRenderer());
CheckPm4WaitPackets(vulkan.RuntimeRenderer()); CheckPm4WaitPackets(vulkan.RuntimeRenderer());
CheckPm4WaitResume(vulkan.RuntimeRenderer()); CheckPm4WaitResume(vulkan.RuntimeRenderer());
CheckPm4LodStats(vulkan.RuntimeRenderer());
CheckPm4MemSemaphore(vulkan.RuntimeRenderer()); CheckPm4MemSemaphore(vulkan.RuntimeRenderer());
return 0; return 0;
} }
@@ -54341,6 +54379,7 @@ int main(int argc, char **argv) {
CheckPm4ContextStateOperations(vulkan.RuntimeRenderer()); CheckPm4ContextStateOperations(vulkan.RuntimeRenderer());
CheckPm4IndirectControlFlow(vulkan.RuntimeRenderer()); CheckPm4IndirectControlFlow(vulkan.RuntimeRenderer());
CheckPm4WaitResume(vulkan.RuntimeRenderer()); CheckPm4WaitResume(vulkan.RuntimeRenderer());
CheckPm4LodStats(vulkan.RuntimeRenderer());
CheckPm4MemSemaphore(vulkan.RuntimeRenderer()); CheckPm4MemSemaphore(vulkan.RuntimeRenderer());
CheckPm4RewindResume(vulkan.RuntimeRenderer()); CheckPm4RewindResume(vulkan.RuntimeRenderer());
CheckEmbeddedFetchVertexOffset(); CheckEmbeddedFetchVertexOffset();