[GPU] log_draws: also dump vertex positions for file correlation
Some checks failed
Orchestrator / Commit Message Validation (push) Has been skipped
Orchestrator / Lint (push) Failing after 1m57s
Orchestrator / Windows (x86-64) (push) Has been skipped
Orchestrator / Linux (x86-64) (push) Has been skipped
Orchestrator / Create Release (push) Has been skipped
Some checks failed
Orchestrator / Commit Message Validation (push) Has been skipped
Orchestrator / Lint (push) Failing after 1m57s
Orchestrator / Windows (x86-64) (push) Has been skipped
Orchestrator / Linux (x86-64) (push) Has been skipped
Orchestrator / Create Release (push) Has been skipped
Extend the RE draw-logger to dump the first few vertex POSITIONS (read from guest memory) under each draw. The f32 position bytes are identical between the guest buffer and the on-disc .xpr (only f16 pairs are rearranged on load), so these values can be grep'd for in a resource file to locate a mesh whose in-file offset is otherwise unknown. Validated: world-space stage geometry byte-matches Stage_*.xpr at exact offsets. (Load-time-transformed meshes like the player ship don't match, which is itself a useful finding.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -215,6 +215,51 @@ void CommandProcessor::LogDrawForRE(uint32_t vgt_draw_initiator_value,
|
||||
a.stride, a.is_signed ? 1 : 0, a.is_integer ? 1 : 0, a.exp_adjust);
|
||||
}
|
||||
}
|
||||
|
||||
// Dump the first few vertex POSITIONS from guest memory. The f32 position
|
||||
// bytes are identical between the guest buffer and the on-disc .xpr (only
|
||||
// f16 pairs are rearranged on load), so these values can be searched for in
|
||||
// the file to locate a mesh whose in-file offset is otherwise unknown
|
||||
// (e.g. multi-XBG7 body meshes). See docs/re/structures/xbg7-mesh.md.
|
||||
if (!vs->vertex_bindings().empty()) {
|
||||
const auto& binding = vs->vertex_bindings()[0];
|
||||
xenos::xe_gpu_vertex_fetch_t fetch =
|
||||
register_file_->GetVertexFetch(binding.fetch_constant);
|
||||
// Position = the first f32×3 attribute (offset is in dwords).
|
||||
int32_t pos_off_bytes = -1;
|
||||
for (const auto& attr : binding.attributes) {
|
||||
if (attr.fetch_instr.attributes.data_format ==
|
||||
xenos::VertexFormat::k_32_32_32_FLOAT) {
|
||||
pos_off_bytes = attr.fetch_instr.attributes.offset * 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint32_t stride = binding.stride_words * 4;
|
||||
uint32_t vbase = uint32_t(fetch.address) << 2;
|
||||
uint32_t buf_bytes = uint32_t(fetch.size) * 4;
|
||||
if (pos_off_bytes >= 0 && stride > 0) {
|
||||
uint32_t max_v = buf_bytes / stride;
|
||||
uint32_t n = max_v < 8 ? max_v : 8;
|
||||
re_out << " positions:";
|
||||
for (uint32_t v = 0; v < n; ++v) {
|
||||
uint32_t a = vbase + v * stride + uint32_t(pos_off_bytes);
|
||||
const uint8_t* p = memory_->TranslatePhysical<const uint8_t*>(a);
|
||||
if (!p) {
|
||||
break;
|
||||
}
|
||||
auto be_f32 = [](const uint8_t* q) {
|
||||
uint32_t w = (uint32_t(q[0]) << 24) | (uint32_t(q[1]) << 16) |
|
||||
(uint32_t(q[2]) << 8) | uint32_t(q[3]);
|
||||
float f;
|
||||
std::memcpy(&f, &w, 4);
|
||||
return f;
|
||||
};
|
||||
re_out << fmt::format(" ({:.4f},{:.4f},{:.4f})", be_f32(p),
|
||||
be_f32(p + 4), be_f32(p + 8));
|
||||
}
|
||||
re_out << "\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
re_out << " (vertex shader not analyzed yet)\n";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user