render: time the submit-record loop and pre-size per-frame bookkeeping
This commit is contained in:
parent
2aef1222a0
commit
8f8642aec2
3 changed files with 26 additions and 4 deletions
|
|
@ -8236,6 +8236,9 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
|
||||||
FrameScene scene;
|
FrameScene scene;
|
||||||
scene.items.reserve(count);
|
scene.items.reserve(count);
|
||||||
std::unordered_set<uint32_t> seen;
|
std::unordered_set<uint32_t> seen;
|
||||||
|
// Pre-size the per-frame bookkeeping: these fill with thousands of
|
||||||
|
// entries every frame, and growing from empty rehashes repeatedly.
|
||||||
|
seen.reserve(count);
|
||||||
// Dynamic contexts are submitted several times per frame (once per pass);
|
// Dynamic contexts are submitted several times per frame (once per pass);
|
||||||
// each submission carries that pass's culled island list. Keep the fullest
|
// each submission carries that pass's culled island list. Keep the fullest
|
||||||
// one; a shadow-pass list can be missing body parts the main view needs.
|
// one; a shadow-pass list can be missing body parts the main view needs.
|
||||||
|
|
@ -8253,6 +8256,11 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
|
||||||
for (const DrawEntry& e : d.draws) n += e.index_count;
|
for (const DrawEntry& e : d.draws) n += e.index_count;
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
const bool wloop_prof = REXCVAR_GET(skate3_native_render_scene_perf_items);
|
||||||
|
const auto wloop_t0 = wloop_prof ? PerfClock::now() : PerfClock::time_point{};
|
||||||
|
if (wloop_prof) {
|
||||||
|
g_bi_records.fetch_add(count, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
for (size_t i = 0; i < count; ++i) {
|
for (size_t i = 0; i < count; ++i) {
|
||||||
const SubmitRecord& r = records[i];
|
const SubmitRecord& r = records[i];
|
||||||
// Primary opaque list of the chosen view only; other lists (shadow
|
// Primary opaque list of the chosen view only; other lists (shadow
|
||||||
|
|
@ -8400,6 +8408,9 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (wloop_prof) {
|
||||||
|
g_pw_bi_wloop.Add(PerfNsSince(wloop_t0));
|
||||||
|
}
|
||||||
// Cross-frame palette rescue + cache refresh (see g_bones_cache_ctx and
|
// Cross-frame palette rescue + cache refresh (see g_bones_cache_ctx and
|
||||||
// g_ropa_state_cache): published copies refresh their cache entries; a
|
// g_ropa_state_cache): published copies refresh their cache entries; a
|
||||||
// refused/pending capture re-publishes with the cached palette (one frame
|
// refused/pending capture re-publishes with the cached palette (one frame
|
||||||
|
|
|
||||||
|
|
@ -7081,7 +7081,8 @@ void LogFrameStats(const FrameScene& scene, uint64_t frames, uint32_t drawn,
|
||||||
"grid[valid={} age={}] "
|
"grid[valid={} age={}] "
|
||||||
"stages_us[mesh={:.2f} tex={:.2f} const={:.2f} submit={:.2f} n={}] "
|
"stages_us[mesh={:.2f} tex={:.2f} const={:.2f} submit={:.2f} n={}] "
|
||||||
"build_us[core n={} av={:.2f} fp n={} av={:.2f} walk n={} av={:.2f} "
|
"build_us[core n={} av={:.2f} fp n={} av={:.2f} walk n={} av={:.2f} "
|
||||||
"fetch av={:.2f}] retain[{:.2f}/{:.2f}ms app={} live={}]",
|
"fetch av={:.2f}] wloop[{:.2f}/{:.2f}ms recs={}] "
|
||||||
|
"retain[{:.2f}/{:.2f}ms app={} live={}]",
|
||||||
g_pw_di_in.count.load(std::memory_order_relaxed), avg_us(g_pw_di_in),
|
g_pw_di_in.count.load(std::memory_order_relaxed), avg_us(g_pw_di_in),
|
||||||
g_pw_di_in.MaxMs(),
|
g_pw_di_in.MaxMs(),
|
||||||
g_pw_di_occ.count.load(std::memory_order_relaxed),
|
g_pw_di_occ.count.load(std::memory_order_relaxed),
|
||||||
|
|
@ -7101,8 +7102,10 @@ void LogFrameStats(const FrameScene& scene, uint64_t frames, uint32_t drawn,
|
||||||
avg_us(g_pw_bi_core),
|
avg_us(g_pw_bi_core),
|
||||||
g_pw_bi_fp.count.load(std::memory_order_relaxed), avg_us(g_pw_bi_fp),
|
g_pw_bi_fp.count.load(std::memory_order_relaxed), avg_us(g_pw_bi_fp),
|
||||||
g_pw_bi_walk.count.load(std::memory_order_relaxed),
|
g_pw_bi_walk.count.load(std::memory_order_relaxed),
|
||||||
avg_us(g_pw_bi_walk), avg_us(g_pw_bi_fetch), g_pw_bi_retain.AvgMs(),
|
avg_us(g_pw_bi_walk), avg_us(g_pw_bi_fetch), g_pw_bi_wloop.AvgMs(),
|
||||||
g_pw_bi_retain.MaxMs(),
|
g_pw_bi_wloop.MaxMs(),
|
||||||
|
g_bi_records.exchange(0, std::memory_order_relaxed),
|
||||||
|
g_pw_bi_retain.AvgMs(), g_pw_bi_retain.MaxMs(),
|
||||||
g_retained_appended.exchange(0, std::memory_order_relaxed),
|
g_retained_appended.exchange(0, std::memory_order_relaxed),
|
||||||
g_retained_live.load(std::memory_order_relaxed));
|
g_retained_live.load(std::memory_order_relaxed));
|
||||||
}
|
}
|
||||||
|
|
@ -7114,7 +7117,8 @@ void LogFrameStats(const FrameScene& scene, uint64_t frames, uint32_t drawn,
|
||||||
&g_pw_di_in, &g_pw_di_occ, &g_pw_di_out,
|
&g_pw_di_in, &g_pw_di_occ, &g_pw_di_out,
|
||||||
&g_pw_di_mesh, &g_pw_di_tex, &g_pw_di_const,
|
&g_pw_di_mesh, &g_pw_di_tex, &g_pw_di_const,
|
||||||
&g_pw_di_submit, &g_pw_bi_core, &g_pw_bi_fp,
|
&g_pw_di_submit, &g_pw_bi_core, &g_pw_bi_fp,
|
||||||
&g_pw_bi_walk, &g_pw_bi_fetch, &g_pw_bi_retain}) {
|
&g_pw_bi_walk, &g_pw_bi_fetch, &g_pw_bi_wloop,
|
||||||
|
&g_pw_bi_retain}) {
|
||||||
w->Reset();
|
w->Reset();
|
||||||
}
|
}
|
||||||
// Refill the settle offender-log + slow-frame budgets for the next window.
|
// Refill the settle offender-log + slow-frame budgets for the next window.
|
||||||
|
|
|
||||||
|
|
@ -973,6 +973,13 @@ inline PerfWindow g_pw_bi_core; // BuildItemFromMeshCached total (hit validat
|
||||||
inline PerfWindow g_pw_bi_fp; // ComputeItemFingerprint on the cache-hit path
|
inline PerfWindow g_pw_bi_fp; // ComputeItemFingerprint on the cache-hit path
|
||||||
inline PerfWindow g_pw_bi_walk; // full BuildItemFromMesh rebuilds (cache miss)
|
inline PerfWindow g_pw_bi_walk; // full BuildItemFromMesh rebuilds (cache miss)
|
||||||
inline PerfWindow g_pw_bi_fetch; // AdoptDrawFetchOverrides per-frame guest reads
|
inline PerfWindow g_pw_bi_fetch; // AdoptDrawFetchOverrides per-frame guest reads
|
||||||
|
// Whole submit-record loop of BuildFrameScene (one Add per frame). Contains
|
||||||
|
// bi_core/bi_fetch plus everything they do not: per-record hash-set
|
||||||
|
// bookkeeping, the dynamic merge, draw-list copies and DrawItem churn.
|
||||||
|
// build - b2d - bspl - wloop - bpal - retain - remainder = the post-loop
|
||||||
|
// tail (camera smoothing, capture blocks, publish).
|
||||||
|
inline PerfWindow g_pw_bi_wloop;
|
||||||
|
inline std::atomic<uint64_t> g_bi_records{0}; // submit records per window
|
||||||
// Off-screen retention pass (always measured, one Add per frame: two clock
|
// Off-screen retention pass (always measured, one Add per frame: two clock
|
||||||
// reads): its cost and how many items it re-appends beyond the guest's own
|
// reads): its cost and how many items it re-appends beyond the guest's own
|
||||||
// submission are core visibility-culling telemetry, not deep profiling.
|
// submission are core visibility-culling telemetry, not deep profiling.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue