app: gate diagnostic captures and logging behind debug cvars, native renderer on by default

This commit is contained in:
mchughalex 2026-07-19 22:45:33 +01:00
parent 275fa431c3
commit 404cec3378
10 changed files with 89 additions and 75 deletions

View file

@ -82,6 +82,13 @@ REXCVAR_DEFINE_BOOL(
REXCVAR_DEFINE_STRING(skate3_native_render_snapshot_dir, "native_render_snapshots", "Skate 3", REXCVAR_DEFINE_STRING(skate3_native_render_snapshot_dir, "native_render_snapshots", "Skate 3",
"Directory for native-render guest memory snapshots and metadata") "Directory for native-render guest memory snapshots and metadata")
.lifecycle(rex::cvar::Lifecycle::kHotReload); .lifecycle(rex::cvar::Lifecycle::kHotReload);
REXCVAR_DEFINE_BOOL(skate3_native_render_capture_hotkeys, false, "Skate 3",
"Enable the diagnostic capture triggers: F7 scene-ring dump, F8 "
"cache flush, F9/F10 snapshot recording, F11 A/B parity capture, "
"controller RB+X / RB+A combos, and the snapshot-dir trigger "
"file. Off = no key/pad polling and no capture output.")
.debug_only()
.lifecycle(rex::cvar::Lifecycle::kHotReload);
namespace skate3::native_scene { namespace skate3::native_scene {
@ -624,9 +631,11 @@ void OnCaptureFrameEnd(uint8_t* base, uint64_t frame_index,
// Manual triggers (work repeatedly): press F9 (window recording per the // Manual triggers (work repeatedly): press F9 (window recording per the
// snapshot cvars), F10 (IMMEDIATE single-frame capture: full memory // snapshot cvars), F10 (IMMEDIATE single-frame capture: full memory
// snapshot + this frame's records/draws, for catching a broken object the // snapshot + this frame's records/draws, for catching a broken object the
// moment it is on screen), or create <snapshot_dir>\trigger. // moment it is on screen), or create <snapshot_dir>\trigger. All of them
// (and their key/pad polling) sit behind skate3_native_render_capture_hotkeys.
const bool capture_hotkeys = REXCVAR_GET(skate3_native_render_capture_hotkeys);
#if defined(_WIN32) #if defined(_WIN32)
if (!g_collecting) { if (capture_hotkeys && !g_collecting) {
static bool f9_was_down = false; static bool f9_was_down = false;
const bool f9_down = (GetAsyncKeyState(VK_F9) & 0x8000) != 0; const bool f9_down = (GetAsyncKeyState(VK_F9) & 0x8000) != 0;
if (f9_down && !f9_was_down) { if (f9_down && !f9_was_down) {
@ -733,7 +742,10 @@ void OnCaptureFrameEnd(uint8_t* base, uint64_t frame_index,
static uint64_t ab_resume_frame = 0; static uint64_t ab_resume_frame = 0;
static char ab_tag[24] = {}; static char ab_tag[24] = {};
static bool f11_was_down = false; static bool f11_was_down = false;
const bool f11_down = (GetAsyncKeyState(VK_F11) & 0x8000) != 0; // Gate the poll itself; a sequence already in flight still runs to
// completion so the renderer is never left toggled to emulated.
const bool f11_down =
capture_hotkeys && (GetAsyncKeyState(VK_F11) & 0x8000) != 0;
constexpr uint64_t kSettleFrames = 60; constexpr uint64_t kSettleFrames = 60;
switch (ab_state) { switch (ab_state) {
case AbState::kIdle: case AbState::kIdle:
@ -919,7 +931,7 @@ void OnCaptureFrameEnd(uint8_t* base, uint64_t frame_index,
} }
} }
#endif #endif
if (!g_collecting && frame_index % 32 == 0) { if (capture_hotkeys && !g_collecting && frame_index % 32 == 0) {
const std::filesystem::path trigger = SnapshotDir() / "trigger"; const std::filesystem::path trigger = SnapshotDir() / "trigger";
std::error_code ec; std::error_code ec;
if (std::filesystem::exists(trigger, ec)) { if (std::filesystem::exists(trigger, ec)) {

View file

@ -23,10 +23,16 @@
REXCVAR_DEFINE_BOOL( REXCVAR_DEFINE_BOOL(
skate3_native_render_scene_entity_ident, true, "Skate 3", skate3_native_render_scene_entity_ident, true, "Skate 3",
"Build the presentation-entity identity store (MeshContext -> owning " "Build the presentation-entity identity store (MeshContext -> owning "
"entity, from the game's BindConstants walks) and compare the entity's " "entity, from the game's BindConstants walks). The store feeds the "
"direct fields (world transform, opacity) against the renderer's " "entity serve paths (fade serve, ROPA world serve, palette identity); "
"captured values. Observer only: emits the ident[] stats line, serves " "off disables those consumers as well.")
"nothing.") .lifecycle(rex::cvar::Lifecycle::kHotReload);
REXCVAR_DEFINE_BOOL(
skate3_native_render_scene_entity_ident_log, false, "Skate 3",
"Log identity-store diagnostics: the periodic ident[] stats line and "
"rate-limited serve-path lines.")
.debug_only()
.lifecycle(rex::cvar::Lifecycle::kHotReload); .lifecycle(rex::cvar::Lifecycle::kHotReload);
REXCVAR_DEFINE_BOOL( REXCVAR_DEFINE_BOOL(
@ -279,7 +285,8 @@ void OnBindClass(uint32_t entity, EntClass cls) {
// table, for promoting vtable-based classification later. // table, for promoting vtable-based classification later.
static std::unordered_map<uint64_t, bool> s_seen; static std::unordered_map<uint64_t, bool> s_seen;
const uint64_t key = (uint64_t(it->second.vtable) << 8) | uint8_t(cls); const uint64_t key = (uint64_t(it->second.vtable) << 8) | uint8_t(cls);
if (s_seen.size() < 64 && s_seen.emplace(key, true).second) { if (REXCVAR_GET(skate3_native_render_scene_entity_ident_log) &&
s_seen.size() < 64 && s_seen.emplace(key, true).second) {
REXLOG_INFO("native-entity: class {} vtbl={:08X} entity={:08X}", REXLOG_INFO("native-entity: class {} vtbl={:08X} entity={:08X}",
ClassName(cls), it->second.vtable, entity); ClassName(cls), it->second.vtable, entity);
} }
@ -377,7 +384,8 @@ void ObserveRopaWorld(uint8_t* base, uint32_t ctx, const float rows[12]) {
if (c416 == 2 && c352 == 2) { if (c416 == 2 && c352 == 2) {
static std::atomic<uint32_t> s_logged{0}; static std::atomic<uint32_t> s_logged{0};
const uint32_t ln = s_logged.fetch_add(1, std::memory_order_relaxed); const uint32_t ln = s_logged.fetch_add(1, std::memory_order_relaxed);
if (ln < 8 || (ln & 1023u) == 0) { if (REXCVAR_GET(skate3_native_render_scene_entity_ident_log) &&
(ln < 8 || (ln & 1023u) == 0)) {
REXLOG_INFO( REXLOG_INFO(
"native-entity: ropa world DIVERGES both fields ctx={:08X} " "native-entity: ropa world DIVERGES both fields ctx={:08X} "
"cls={} entity={:08X} bank=({:.3f},{:.3f},{:.3f},{:.2f}) " "cls={} entity={:08X} bank=({:.3f},{:.3f},{:.3f},{:.2f}) "
@ -424,7 +432,8 @@ void ObserveCharItem(uint8_t* base, uint32_t ctx, uint32_t family,
g_fade_div.fetch_add(1, std::memory_order_relaxed); g_fade_div.fetch_add(1, std::memory_order_relaxed);
static std::atomic<uint32_t> s_logged{0}; static std::atomic<uint32_t> s_logged{0};
const uint32_t ln = s_logged.fetch_add(1, std::memory_order_relaxed); const uint32_t ln = s_logged.fetch_add(1, std::memory_order_relaxed);
if (ln < 8 || (ln & 2047u) == 0) { if (REXCVAR_GET(skate3_native_render_scene_entity_ident_log) &&
(ln < 8 || (ln & 2047u) == 0)) {
REXLOG_INFO( REXLOG_INFO(
"native-entity: fade divergence ctx={:08X} cls={} fam={} " "native-entity: fade divergence ctx={:08X} cls={} fam={} "
"e496={:.3f} used={:.3f} (n={})", "e496={:.3f} used={:.3f} (n={})",
@ -441,7 +450,8 @@ void NoteAcceptedWorldCompare(const float bank_rows[12],
g_wprim_div.fetch_add(1, std::memory_order_relaxed); g_wprim_div.fetch_add(1, std::memory_order_relaxed);
static std::atomic<uint32_t> s_logged{0}; static std::atomic<uint32_t> s_logged{0};
const uint32_t ln = s_logged.fetch_add(1, std::memory_order_relaxed); const uint32_t ln = s_logged.fetch_add(1, std::memory_order_relaxed);
if (ln < 8 || (ln & 1023u) == 0) { if (REXCVAR_GET(skate3_native_render_scene_entity_ident_log) &&
(ln < 8 || (ln & 1023u) == 0)) {
REXLOG_INFO( REXLOG_INFO(
"native-entity: PRIMARY world diverges from accepted bank " "native-entity: PRIMARY world diverges from accepted bank "
"i={} bank={:.4f} ent={:.4f} (n={})", "i={} bank={:.4f} ent={:.4f} (n={})",
@ -633,7 +643,8 @@ bool ServeRopaWorld(uint8_t* base, uint32_t ctx, uint32_t vb_obj,
g_wserve.fetch_add(1, std::memory_order_relaxed); g_wserve.fetch_add(1, std::memory_order_relaxed);
static std::atomic<uint32_t> s_logged{0}; static std::atomic<uint32_t> s_logged{0};
const uint32_t ln = s_logged.fetch_add(1, std::memory_order_relaxed); const uint32_t ln = s_logged.fetch_add(1, std::memory_order_relaxed);
if (ln < 8 || (ln & 2047u) == 0) { if (REXCVAR_GET(skate3_native_render_scene_entity_ident_log) &&
(ln < 8 || (ln & 2047u) == 0)) {
REXLOG_INFO( REXLOG_INFO(
"native-entity: ropa world SERVED ctx={:08X} cls={} entity={:08X} " "native-entity: ropa world SERVED ctx={:08X} cls={} entity={:08X} "
"t=({:.2f},{:.2f},{:.2f}) (n={})", "t=({:.2f},{:.2f},{:.2f}) (n={})",
@ -644,7 +655,8 @@ bool ServeRopaWorld(uint8_t* base, uint32_t ctx, uint32_t vb_obj,
} }
void EmitStats() { void EmitStats() {
if (!REXCVAR_GET(skate3_native_render_scene_entity_ident)) { if (!REXCVAR_GET(skate3_native_render_scene_entity_ident) ||
!REXCVAR_GET(skate3_native_render_scene_entity_ident_log)) {
return; return;
} }
const uint32_t frame = const uint32_t frame =

View file

@ -714,8 +714,8 @@ std::optional<rex::PathConfig> Skate3BaseApp::OnFinalizePaths(
} }
void Skate3BaseApp::OnCreateDialogs(rex::ui::ImGuiDrawer* drawer) { void Skate3BaseApp::OnCreateDialogs(rex::ui::ImGuiDrawer* drawer) {
// Always-on native/emulated corner readout (top right; cvar // Native/emulated corner readout (top right; off by default, cvar
// skate3_native_render_mode_indicator hides it live). Input-transparent, // skate3_native_render_mode_indicator shows it live). Input-transparent,
// so it never affects cursor or focus handling. // so it never affects cursor or focus handling.
render_mode_indicator_ = std::make_unique<skate3::RenderModeIndicator>(drawer); render_mode_indicator_ = std::make_unique<skate3::RenderModeIndicator>(drawer);
rex::ui::RegisterBind("bind_skate3_menu", "Escape", "Skate 3 settings", [this] { rex::ui::RegisterBind("bind_skate3_menu", "Escape", "Skate 3 settings", [this] {
@ -746,7 +746,12 @@ void Skate3BaseApp::OnCreateDialogs(rex::ui::ImGuiDrawer* drawer) {
}); });
rex::ui::RegisterBind("bind_skate3_ultrawide_targets", "F7", rex::ui::RegisterBind("bind_skate3_ultrawide_targets", "F7",
"Skate 3 ultrawide targets", [this] { "Skate 3 ultrawide targets", [this] {
// Developer tuning dialog; rides the same opt-in as
// the F4 cvar browser.
if (rex::cvar::Query<bool>(
"advanced_settings_overlay_enabled")) {
ToggleUltrawideTargets(); ToggleUltrawideTargets();
}
}); });
rex::ui::RegisterBind("bind_skate3_save_draw_fingerprints", "F8", rex::ui::RegisterBind("bind_skate3_save_draw_fingerprints", "F8",
"Save draw fingerprint log", [this] { "Save draw fingerprint log", [this] {

View file

@ -13,7 +13,7 @@
#include "skate3_native_scene.h" #include "skate3_native_scene.h"
REXCVAR_DEFINE_BOOL(skate3_native_render_mode_indicator, true, "Skate 3", REXCVAR_DEFINE_BOOL(skate3_native_render_mode_indicator, false, "Skate 3",
"Small top-right corner readout of which renderer produced the " "Small top-right corner readout of which renderer produced the "
"last presented frame: NATIVE (native scene renderer) or " "last presented frame: NATIVE (native scene renderer) or "
"EMULATED (Xenos GPU emulation: menus/loading yields, F5 off).") "EMULATED (Xenos GPU emulation: menus/loading yields, F5 off).")

View file

@ -24,11 +24,11 @@ class NativeDebugDialog final : public rex::ui::ImGuiDialog {
bool visible_ = false; bool visible_ = false;
}; };
// Tiny always-on top-right corner readout of which renderer produced the // Tiny top-right corner readout of which renderer produced the last
// last presented frame: NATIVE (native scene renderer) or EMULATED (Xenos // presented frame: NATIVE (native scene renderer) or EMULATED (Xenos
// GPU emulation; menus/loading yields, F5 off). Input-transparent, no // GPU emulation; menus/loading yields, F5 off). Input-transparent, no
// continuous repaint (updates ride the guest frame paints); hidden via // continuous repaint (updates ride the guest frame paints); off by
// skate3_native_render_mode_indicator (hot). // default, shown via skate3_native_render_mode_indicator (hot).
class RenderModeIndicator final : public rex::ui::ImGuiDialog { class RenderModeIndicator final : public rex::ui::ImGuiDialog {
public: public:
explicit RenderModeIndicator(rex::ui::ImGuiDrawer* drawer) : ImGuiDialog(drawer) {} explicit RenderModeIndicator(rex::ui::ImGuiDrawer* drawer) : ImGuiDialog(drawer) {}

View file

@ -23,7 +23,7 @@
#include <rex/logging.h> #include <rex/logging.h>
#include <rex/ui/window.h> #include <rex/ui/window.h>
REXCVAR_DEFINE_BOOL(skate3_native_render, false, "Skate 3", REXCVAR_DEFINE_BOOL(skate3_native_render, true, "Skate 3",
"Enable the Skate 3 data-driven native renderer hook layer") "Enable the Skate 3 data-driven native renderer hook layer")
.lifecycle(rex::cvar::Lifecycle::kRequiresRestart); .lifecycle(rex::cvar::Lifecycle::kRequiresRestart);
REXCVAR_DEFINE_INT32(skate3_native_render_log_interval, 0, "Skate 3", REXCVAR_DEFINE_INT32(skate3_native_render_log_interval, 0, "Skate 3",

View file

@ -59,7 +59,7 @@
REXCVAR_DECLARE(std::string, skate3_native_render_snapshot_dir); REXCVAR_DECLARE(std::string, skate3_native_render_snapshot_dir);
REXCVAR_DEFINE_BOOL(skate3_native_render_scene, false, "Skate 3", REXCVAR_DEFINE_BOOL(skate3_native_render_scene, true, "Skate 3",
"Render the game scene natively from the hooked MeshContext stream, " "Render the game scene natively from the hooked MeshContext stream, "
"replacing the emulated GPU output (requires skate3_native_render). " "replacing the emulated GPU output (requires skate3_native_render). "
"Hot-toggles live between the native and emulated renderers (F5).") "Hot-toggles live between the native and emulated renderers (F5).")
@ -967,8 +967,13 @@ REXCVAR_DEFINE_BOOL(skate3_native_render_scene_stretch_guard, true, "Skate 3",
"Draw-time stretch veto: skin cached sample verts of each " "Draw-time stretch veto: skin cached sample verts of each "
"skinned mesh's GPU-resident decode with the final palette " "skinned mesh's GPU-resident decode with the final palette "
"every frame; wider than bind size = the 1-frame mangled-" "every frame; wider than bind size = the 1-frame mangled-"
"ribbon flash: skip the item's draws (blink) and dump the " "ribbon flash; skip the item's draws (blink)")
"palette to logs/stretch_*.txt for diagnosis") .lifecycle(rex::cvar::Lifecycle::kHotReload);
REXCVAR_DEFINE_BOOL(skate3_native_render_scene_stretch_guard_dump, false, "Skate 3",
"On a stretch veto, dump the full bone palette and probe "
"verts to logs/stretch_*.txt (first 6 trips) for offline "
"diagnosis of which rows are junk")
.debug_only()
.lifecycle(rex::cvar::Lifecycle::kHotReload); .lifecycle(rex::cvar::Lifecycle::kHotReload);
REXCVAR_DEFINE_BOOL(skate3_native_render_scene_lm_dump, false, "Skate 3", REXCVAR_DEFINE_BOOL(skate3_native_render_scene_lm_dump, false, "Skate 3",
"Diagnostic: dump the decoded mip 0 of every generated-mip " "Diagnostic: dump the decoded mip 0 of every generated-mip "
@ -1036,8 +1041,8 @@ REXCVAR_DEFINE_DOUBLE(
REXCVAR_DEFINE_INT32(skate3_native_render_scene_synthetic_pan, 0, "Skate 3", REXCVAR_DEFINE_INT32(skate3_native_render_scene_synthetic_pan, 0, "Skate 3",
"Synthetic constant-rate camera pan (judder isolation): 0 = off, " "Synthetic constant-rate camera pan (judder isolation): 0 = off, "
"1 = time-based at scene build, 2 = fixed angle step per frame, " "1 = time-based at scene build, 2 = fixed angle step per frame, "
"3 = synthetic samples through the camera smoother. Hotkey P " "3 = synthetic samples through the camera smoother.")
"cycles the modes.") .debug_only()
.lifecycle(rex::cvar::Lifecycle::kHotReload); .lifecycle(rex::cvar::Lifecycle::kHotReload);
REXCVAR_DEFINE_DOUBLE(skate3_native_render_scene_synthetic_pan_rate, 90.0, "Skate 3", REXCVAR_DEFINE_DOUBLE(skate3_native_render_scene_synthetic_pan_rate, 90.0, "Skate 3",
"Synthetic pan rate in degrees/second") "Synthetic pan rate in degrees/second")
@ -2524,19 +2529,6 @@ void RequestSceneRingDump() {
} }
void FlushMeshCache() { g_flush_meshes.store(true, std::memory_order_relaxed); } void FlushMeshCache() { g_flush_meshes.store(true, std::memory_order_relaxed); }
int CycleSyntheticPan() {
const int mode =
(std::clamp(int(REXCVAR_GET(skate3_native_render_scene_synthetic_pan)), 0, 3) + 1) %
4;
REXCVAR_SET(skate3_native_render_scene_synthetic_pan, mode);
static const char* kModeNames[] = {"off", "time-based (host clock at scene build)",
"fixed angle step per frame",
"synthetic samples through the smoother"};
REXLOG_INFO("native-scene synthetic-pan: hotkey -> mode {} ({})", mode,
kModeNames[mode]);
return mode;
}
// RecordBoneSignal / RecordCameraSignal: native/skate3_native_diagnostics.cpp. // RecordBoneSignal / RecordCameraSignal: native/skate3_native_diagnostics.cpp.
bool ToggleSceneEnabled() { bool ToggleSceneEnabled() {
@ -7580,7 +7572,7 @@ void Publish2dDraws(uint8_t* base) {
s_seen.clear(); s_seen.clear();
} }
if (s_seen.size() < 24 && s_seen.insert(d.fetch[1]).second) { if (s_seen.size() < 24 && s_seen.insert(d.fetch[1]).second) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: BIG 2D quad tex=({:08x},{:08x},{:08x}) flags={:02x} " "native-scene: BIG 2D quad tex=({:08x},{:08x},{:08x}) flags={:02x} "
"src_stride={} count={} bbox=({:.0f},{:.0f})-({:.0f},{:.0f}) " "src_stride={} count={} bbox=({:.0f},{:.0f})-({:.0f},{:.0f}) "
"c8=({:.2f},{:.2f},{:.2f},{:.2f}) (n={})", "c8=({:.2f},{:.2f},{:.2f},{:.2f}) (n={})",
@ -7618,7 +7610,7 @@ void Publish2dDraws(uint8_t* base) {
s_fade_logs.store(0, std::memory_order_relaxed); s_fade_logs.store(0, std::memory_order_relaxed);
} }
if (s_fade_logs.fetch_add(1, std::memory_order_relaxed) < 6) { if (s_fade_logs.fetch_add(1, std::memory_order_relaxed) < 6) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: transition fade fill alpha={:.2f} " "native-scene: transition fade fill alpha={:.2f} "
"rgb=({:.2f},{:.2f},{:.2f}) flags={:02x}", "rgb=({:.2f},{:.2f},{:.2f}) flags={:02x}",
alpha, d.consts[32], d.consts[33], d.consts[34], d.flags); alpha, d.consts[32], d.consts[33], d.consts[34], d.flags);
@ -7921,7 +7913,7 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
g_slow_frame_log_budget.fetch_sub(1, std::memory_order_relaxed) > 0) { g_slow_frame_log_budget.fetch_sub(1, std::memory_order_relaxed) > 0) {
const double ours_ms = const double ours_ms =
double(s_prev_build_ns + s_prev_cap_ns) * 1e-6; double(s_prev_build_ns + s_prev_cap_ns) * 1e-6;
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: slow guest frame dt={:.2f}ms prev[cap={:.2f} build={:.2f} " "native-scene: slow guest frame dt={:.2f}ms prev[cap={:.2f} build={:.2f} "
"(2d={:.2f} spl={:.2f} pal={:.2f} ptail={:.2f} walk={:.2f}) rest={:.2f}]ms", "(2d={:.2f} spl={:.2f} pal={:.2f} ptail={:.2f} walk={:.2f}) rest={:.2f}]ms",
dt_ms, double(s_prev_cap_ns) * 1e-6, double(s_prev_build_ns) * 1e-6, dt_ms, double(s_prev_cap_ns) * 1e-6, double(s_prev_build_ns) * 1e-6,
@ -8053,7 +8045,7 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
static std::atomic<uint64_t> s_aux_views{0}; static std::atomic<uint64_t> s_aux_views{0};
const uint64_t n = s_aux_views.fetch_add(1, std::memory_order_relaxed); const uint64_t n = s_aux_views.fetch_add(1, std::memory_order_relaxed);
if (n < 4 || (n & 255u) == 0) { if (n < 4 || (n & 255u) == 0) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: aux perspective view skipped (portrait RTT " "native-scene: aux perspective view skipped (portrait RTT "
"pass, proj aspect {:.2f}) (n={})", "pass, proj aspect {:.2f}) (n={})",
m00 > 1e-6f ? m11 / m00 : 0.0f, n); m00 > 1e-6f ? m11 / m00 : 0.0f, n);
@ -8274,7 +8266,7 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
static std::atomic<uint32_t> incoh_logged{0}; static std::atomic<uint32_t> incoh_logged{0};
const uint32_t ln = incoh_logged.fetch_add(1, std::memory_order_relaxed); const uint32_t ln = incoh_logged.fetch_add(1, std::memory_order_relaxed);
if (ln < 32 || (ln & 255u) == 0) { if (ln < 32 || (ln & 255u) == 0) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: publish INCOHERENT palette mesh={:08X} fam={} " "native-scene: publish INCOHERENT palette mesh={:08X} fam={} "
"ropa={} src={} spread={:.2f} bind=({:.2f},{:.2f},{:.2f}) " "ropa={} src={} spread={:.2f} bind=({:.2f},{:.2f},{:.2f}) "
"bone0_t=({:.1f},{:.1f},{:.1f})", "bone0_t=({:.1f},{:.1f},{:.1f})",
@ -8570,7 +8562,7 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
const uint32_t ln = const uint32_t ln =
s_fam_logged.fetch_add(1, std::memory_order_relaxed); s_fam_logged.fetch_add(1, std::memory_order_relaxed);
if (ln < 8 || (ln & 1023u) == 0) { if (ln < 8 || (ln & 1023u) == 0) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: rows bridge cross-family serve " "native-scene: rows bridge cross-family serve "
"mesh={:08X} fam {}->{} (n={})", "mesh={:08X} fam {}->{} (n={})",
item.mesh, item.char_family, eit->second.fam, ln); item.mesh, item.char_family, eit->second.fam, ln);
@ -9072,7 +9064,7 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
const uint32_t ln = const uint32_t ln =
s_sub_logged.fetch_add(1, std::memory_order_relaxed); s_sub_logged.fetch_add(1, std::memory_order_relaxed);
if (ln < 16 || (ln & 511u) == 0) { if (ln < 16 || (ln & 511u) == 0) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: LW palette substituted ctx={:08X} mesh={:08X} " "native-scene: LW palette substituted ctx={:08X} mesh={:08X} "
"fam={} rows={} (n={})", "fam={} rows={} (n={})",
item.ctx, item.mesh, item.char_family, n, ln); item.ctx, item.mesh, item.char_family, n, ln);
@ -9723,7 +9715,7 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
probe.fp == item.fingerprint ? 1 : 0, item.bones[3], probe.fp == item.fingerprint ? 1 : 0, item.bones[3],
item.bones[7], item.bones[11]); item.bones[7], item.bones[11]);
} }
if (ln < 6) { if (ln < 6 && REXCVAR_GET(skate3_native_render_scene_stretch_guard_dump)) {
// Full palette + probe dump for offline diagnosis (which rows are // Full palette + probe dump for offline diagnosis (which rows are
// junk, which bones the stretched samples weight to). // junk, which bones the stretched samples weight to).
char path[128]; char path[128];

View file

@ -638,13 +638,6 @@ bool ToggleSceneEnabled();
void FlushTextureCache(); void FlushTextureCache();
void FlushMeshCache(); void FlushMeshCache();
// Synthetic camera pan probe (judder isolation, hotkey P): cycles
// skate3_native_render_scene_synthetic_pan 0 -> 1 -> 2 -> 3 -> 0 and returns
// the new mode. 1 = time-based constant-rate pan injected at scene build,
// 2 = fixed angle step per published frame, 3 = synthetic pose samples fed
// through the camera smoother (reconstruction error logged numerically).
int CycleSyntheticPan();
// Camera-signal recorder (judder diagnosis): for `seconds`, records every // Camera-signal recorder (judder diagnosis): for `seconds`, records every
// distinct guest camera pose (1 kHz sampler timestamps) plus the per-frame // distinct guest camera pose (1 kHz sampler timestamps) plus the per-frame
// raw and smoothed headings, then writes logs/cam_signal_<ts>.csv. Pan the // raw and smoothed headings, then writes logs/cam_signal_<ts>.csv. Pan the

View file

@ -2135,7 +2135,7 @@ bool EnsureGuestCubeTexture(const NativeGuestOutputRenderContext& context, uint8
} }
} }
device->Unmap(out.upload); device->Unmap(out.upload);
REXLOG_INFO("native-scene: cube {:08X} {}x{} fmt={} -> RGBA full chain ({} levels)", REXLOG_DEBUG("native-scene: cube {:08X} {}x{} fmt={} -> RGBA full chain ({} levels)",
tex_ptr, width, height, uint32_t(info.format), levels); tex_ptr, width, height, uint32_t(info.format), levels);
nrhi::Swizzle swizzle_mapping[4]; nrhi::Swizzle swizzle_mapping[4];
ComposeSrvSwizzle(fetch.swizzle, xenos::XE_GPU_TEXTURE_SWIZZLE_RGBA, ComposeSrvSwizzle(fetch.swizzle, xenos::XE_GPU_TEXTURE_SWIZZLE_RGBA,
@ -2256,7 +2256,7 @@ bool EnsureGuestCubeTexture(const NativeGuestOutputRenderContext& context, uint8
} }
device->Unmap(out.upload); device->Unmap(out.upload);
REXLOG_INFO("native-scene: cube {:08X} {}x{} fmt={} mips={} (of {} avail)", tex_ptr, REXLOG_DEBUG("native-scene: cube {:08X} {}x{} fmt={} mips={} (of {} avail)", tex_ptr,
width, height, uint32_t(info.format), mip_levels, info.mip_levels()); width, height, uint32_t(info.format), mip_levels, info.mip_levels());
if (g_tex_stage_out != nullptr) { if (g_tex_stage_out != nullptr) {
// Decode worker: export the commit recipe, face-major (face * levels + // Decode worker: export the commit recipe, face-major (face * levels +
@ -3765,7 +3765,7 @@ void WarmItemResources(const NativeGuestOutputRenderContext& context, uint8_t* b
if (within()) { if (within()) {
if (g_warm_mesh_log_budget.load(std::memory_order_relaxed) > 0 && if (g_warm_mesh_log_budget.load(std::memory_order_relaxed) > 0 &&
g_warm_mesh_log_budget.fetch_sub(1, std::memory_order_relaxed) > 0) { g_warm_mesh_log_budget.fetch_sub(1, std::memory_order_relaxed) > 0) {
REXLOG_INFO("native-scene: settle mesh REVALIDATE mesh={:08X} fp {:016X}->{:016X}", REXLOG_DEBUG("native-scene: settle mesh REVALIDATE mesh={:08X} fp {:016X}->{:016X}",
item.mesh, mit->second.fingerprint, item.fingerprint); item.mesh, mit->second.fingerprint, item.fingerprint);
} }
g_r.device->DestroyDeferred(mit->second.vb); g_r.device->DestroyDeferred(mit->second.vb);
@ -3816,7 +3816,7 @@ void WarmItemResources(const NativeGuestOutputRenderContext& context, uint8_t* b
} }
if (g_warm_tex_log_budget.load(std::memory_order_relaxed) > 0 && if (g_warm_tex_log_budget.load(std::memory_order_relaxed) > 0 &&
g_warm_tex_log_budget.fetch_sub(1, std::memory_order_relaxed) > 0) { g_warm_tex_log_budget.fetch_sub(1, std::memory_order_relaxed) > 0) {
REXLOG_INFO("native-scene: settle tex RETIRE ptr={:08X} key={:016X} incomplete={} " REXLOG_DEBUG("native-scene: settle tex RETIRE ptr={:08X} key={:016X} incomplete={} "
"fp {:016X}->{:016X}", "fp {:016X}->{:016X}",
tex_ptr, key, it->second.incomplete, it->second.payload_fp, fp); tex_ptr, key, it->second.incomplete, it->second.payload_fp, fp);
} }
@ -4450,7 +4450,7 @@ void PrewarmCommit(const NativeGuestOutputRenderContext& context,
s_swap_logs.store(0, std::memory_order_relaxed); s_swap_logs.store(0, std::memory_order_relaxed);
} }
if (s_swap_logs.fetch_add(1) < 8) { if (s_swap_logs.fetch_add(1) < 8) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: texture heal commit key={:016X} fp {:016X} " "native-scene: texture heal commit key={:016X} fp {:016X} "
"-> {:016X}", "-> {:016X}",
t.words_key, wit->second.payload_fp, t.gt.payload_fp); t.words_key, wit->second.payload_fp, t.gt.payload_fp);
@ -6475,7 +6475,7 @@ void LogFrameStats(const FrameScene& scene, uint64_t frames, uint32_t drawn,
g_warm_tex_log_budget.store(4, std::memory_order_relaxed); g_warm_tex_log_budget.store(4, std::memory_order_relaxed);
g_slow_frame_log_budget.store(3, std::memory_order_relaxed); g_slow_frame_log_budget.store(3, std::memory_order_relaxed);
} }
if (frames % 600 == 0) { if (frames % 600 == 0 && REXCVAR_GET(skate3_native_render_scene_perf_log)) {
uint32_t lw_ctxs = 0, lw_ents = 0; uint32_t lw_ctxs = 0, lw_ents = 0;
skate3::native_lw::QueryLwStats(&lw_ctxs, &lw_ents); skate3::native_lw::QueryLwStats(&lw_ctxs, &lw_ents);
REXLOG_INFO( REXLOG_INFO(
@ -7018,7 +7018,7 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
static std::atomic<uint32_t> s_sh_logged{0}; static std::atomic<uint32_t> s_sh_logged{0};
const uint32_t sl = s_sh_logged.fetch_add(1, std::memory_order_relaxed); const uint32_t sl = s_sh_logged.fetch_add(1, std::memory_order_relaxed);
if (sl < 24 || (sl & 1023u) == 0) { if (sl < 24 || (sl & 1023u) == 0) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: SHADOW ALTERNATION valid={} ready={} draws={} " "native-scene: SHADOW ALTERNATION valid={} ready={} draws={} "
"row0=({:.3f},{:.3f},{:.3f},{:.3f}) (n={})", "row0=({:.3f},{:.3f},{:.3f},{:.3f}) (n={})",
scene.shadow_valid ? 1 : 0, shadow_ready ? 1 : 0, shadow_draws, scene.shadow_valid ? 1 : 0, shadow_ready ? 1 : 0, shadow_draws,
@ -8645,7 +8645,7 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
const uint32_t ln = const uint32_t ln =
s_stale.fetch_add(1, std::memory_order_relaxed); s_stale.fetch_add(1, std::memory_order_relaxed);
if (ln < 16 || (ln & 1023u) == 0) { if (ln < 16 || (ln & 1023u) == 0) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: ropa shape STALE gen dropped mesh={:08X} " "native-scene: ropa shape STALE gen dropped mesh={:08X} "
"age={:.2f}s seq_gap={} (n={})", "age={:.2f}s seq_gap={} (n={})",
item.mesh, ring_newest_t - g.t, item.mesh, ring_newest_t - g.t,
@ -8703,7 +8703,7 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
const uint32_t ln = const uint32_t ln =
s_blend_miss_log.fetch_add(1, std::memory_order_relaxed); s_blend_miss_log.fetch_add(1, std::memory_order_relaxed);
if (ln < 64 || (ln & 63u) == 0) { if (ln < 64 || (ln & 63u) == 0) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: ropa blend MISS mesh={:08X} sc={} ng={} " "native-scene: ropa blend MISS mesh={:08X} sc={} ng={} "
"total={:.2f} stride={} ring={} ring_off={} (n={})", "total={:.2f} stride={} ring={} ring_off={} (n={})",
item.mesh, item.shape_count, ng, total, buffers.vb_view.stride, item.mesh, item.shape_count, ng, total, buffers.vb_view.stride,
@ -8855,7 +8855,7 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
static std::atomic<uint32_t> s_flip_logged{0}; static std::atomic<uint32_t> s_flip_logged{0};
const uint32_t fl = s_flip_logged.fetch_add(1, std::memory_order_relaxed); const uint32_t fl = s_flip_logged.fetch_add(1, std::memory_order_relaxed);
if (fl < 24 || (fl & 511u) == 0) { if (fl < 24 || (fl & 511u) == 0) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: hair ROUTE FLIP mesh={:08X} ctx={:08X} fam={} " "native-scene: hair ROUTE FLIP mesh={:08X} ctx={:08X} fam={} "
"alpha={} -> route {} rows14=({:.3f},{:.3f},{:.3f}) (n={})", "alpha={} -> route {} rows14=({:.3f},{:.3f},{:.3f}) (n={})",
item.mesh, item.ctx, item.char_family, item.char_alpha ? 1 : 0, item.mesh, item.ctx, item.char_family, item.char_alpha ? 1 : 0,
@ -8869,7 +8869,7 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
static std::atomic<uint32_t> s_bone_alt_logged{0}; static std::atomic<uint32_t> s_bone_alt_logged{0};
const uint32_t bl = s_bone_alt_logged.fetch_add(1, std::memory_order_relaxed); const uint32_t bl = s_bone_alt_logged.fetch_add(1, std::memory_order_relaxed);
if (bl < 24 || (bl & 1023u) == 0) { if (bl < 24 || (bl & 1023u) == 0) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: hair BONES ALTERNATION mesh={:08X} ctx={:08X} " "native-scene: hair BONES ALTERNATION mesh={:08X} ctx={:08X} "
"fam={} bones={} src={} caster_bank={} (n={})", "fam={} bones={} src={} caster_bank={} (n={})",
item.mesh, item.ctx, item.char_family, item.bones.size() / 12, item.mesh, item.ctx, item.char_family, item.bones.size() / 12,
@ -8918,7 +8918,7 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
static std::atomic<uint64_t> s_blinks{0}; static std::atomic<uint64_t> s_blinks{0};
const uint64_t n = s_blinks.fetch_add(1, std::memory_order_relaxed); const uint64_t n = s_blinks.fetch_add(1, std::memory_order_relaxed);
if (n < 16 || (n & 255u) == 0) { if (n < 16 || (n & 255u) == 0) {
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: fade BLINK repaired mesh={:08X} fam={} ropa={} " "native-scene: fade BLINK repaired mesh={:08X} fam={} ropa={} "
"src={} rows13=({:.3f},{:.3f},{:.3f},{:.3f}) " "src={} rows13=({:.3f},{:.3f},{:.3f},{:.3f}) "
"rows14=({:.3f},{:.3f}) (n={})", "rows14=({:.3f},{:.3f}) (n={})",
@ -9705,7 +9705,7 @@ bool RenderScene(const NativeGuestOutputRenderContext& context, void* /*user_dat
if (frame_number - s_pfx_log_frame > 120) { if (frame_number - s_pfx_log_frame > 120) {
s_pfx_log_frame = frame_number; s_pfx_log_frame = frame_number;
const auto& fx = scene.photo_fx; const auto& fx = scene.photo_fx;
REXLOG_INFO( REXLOG_DEBUG(
"native-scene: pfx live rows: visualfx c2=({:.3f},{:.3f}) " "native-scene: pfx live rows: visualfx c2=({:.3f},{:.3f}) "
"c4.x={:.5f} c7=({:.4f},{:.4f},{:.4f},{:.4f}) | dofmb " "c4.x={:.5f} c7=({:.4f},{:.4f},{:.4f},{:.4f}) | dofmb "
"c2.x={:.3f} | dof c0.x={:.3f} | uber c0.x={:.3f} " "c2.x={:.3f} | dof c0.x={:.3f} | uber c0.x={:.3f} "

@ -1 +1 @@
Subproject commit b6c738c8e136957a28c604c86c0907ff57758a1e Subproject commit 2365c9784eb7a529ec7f44f74f51836519c6ab4b