diff --git a/src/xenia/gpu/command_processor.cc b/src/xenia/gpu/command_processor.cc index c8584405e..c7b01575c 100644 --- a/src/xenia/gpu/command_processor.cc +++ b/src/xenia/gpu/command_processor.cc @@ -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(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"; }