capture: place sort-list batched piece clones with their instance matrix
This commit is contained in:
parent
14acde031b
commit
a16314df0c
2 changed files with 59 additions and 0 deletions
|
|
@ -4209,6 +4209,15 @@ uint32_t CaptureDynamicState(uint8_t* base, uint32_t ctx, bool world_path,
|
||||||
// invisibly at the origin). Defer those to the post-draw fixup, like
|
// invisibly at the origin). Defer those to the post-draw fixup, like
|
||||||
// skinned palettes.
|
// skinned palettes.
|
||||||
if (!item.skinned) {
|
if (!item.skinned) {
|
||||||
|
if (!world_path && item.ctx != 0) {
|
||||||
|
// Mark the mesh as dynamically dispatched (see g_dyn_dispatch_meshes):
|
||||||
|
// far clones of it arriving through the static sort lists need their
|
||||||
|
// instance matrix, not the world-item identity.
|
||||||
|
if (g_dyn_dispatch_meshes.size() > 16384) {
|
||||||
|
g_dyn_dispatch_meshes.clear();
|
||||||
|
}
|
||||||
|
g_dyn_dispatch_meshes[item.mesh] = g_guest_frame;
|
||||||
|
}
|
||||||
// The instance's own matrix (ReadCtxInstanceWorld) outranks the bank:
|
// The instance's own matrix (ReadCtxInstanceWorld) outranks the bank:
|
||||||
// own_draw_last only proves SOME clone of this mesh drew last (clones
|
// own_draw_last only proves SOME clone of this mesh drew last (clones
|
||||||
// share (ib,vb)), so under batched dispatch the bank world routinely
|
// share (ib,vb)), so under batched dispatch the bank world routinely
|
||||||
|
|
@ -8474,6 +8483,11 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
|
||||||
// Per-instance rigid candidates whose post-draw world fixup never landed
|
// Per-instance rigid candidates whose post-draw world fixup never landed
|
||||||
// this frame; rescued with their cached world (see g_rigid_world_cache).
|
// this frame; rescued with their cached world (see g_rigid_world_cache).
|
||||||
std::unordered_map<uint32_t, const DrawItem*> pending_rigid_by_ctx;
|
std::unordered_map<uint32_t, const DrawItem*> pending_rigid_by_ctx;
|
||||||
|
// Sort-list records of dynamically-dispatched piece meshes (see
|
||||||
|
// g_dyn_dispatch_meshes): built here, published AFTER the record loop with
|
||||||
|
// the ctx owner's instance matrix, and only for ctxs no live dynamic
|
||||||
|
// capture already covered this frame.
|
||||||
|
std::unordered_map<uint32_t, DrawItem> sortlist_local_by_ctx;
|
||||||
const auto total_indices = [](const DrawItem& d) {
|
const auto total_indices = [](const DrawItem& d) {
|
||||||
uint64_t n = 0;
|
uint64_t n = 0;
|
||||||
for (const DrawEntry& e : d.draws) n += e.index_count;
|
for (const DrawEntry& e : d.draws) n += e.index_count;
|
||||||
|
|
@ -8635,6 +8649,18 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
|
||||||
g_world_props.fetch_add(1, std::memory_order_relaxed);
|
g_world_props.fetch_add(1, std::memory_order_relaxed);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const auto dit = g_dyn_dispatch_meshes.find(item.mesh);
|
||||||
|
if (dit != g_dyn_dispatch_meshes.end() &&
|
||||||
|
g_guest_frame - dit->second <= 1800) {
|
||||||
|
// Instance-transformed piece batched through the static sort lists
|
||||||
|
// (the game hands FAR clones of dynamically-dispatched pieces to
|
||||||
|
// the batcher): fmt-57 but MESH-LOCAL, so the identity world of
|
||||||
|
// this path collapses it at the origin. Defer; the post-loop
|
||||||
|
// publish serves the ctx owner's instance matrix, and only for
|
||||||
|
// ctxs no live dynamic capture covered this frame.
|
||||||
|
sortlist_local_by_ctx.try_emplace(r.a, std::move(item));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
scene.items.push_back(std::move(item));
|
scene.items.push_back(std::move(item));
|
||||||
} else {
|
} else {
|
||||||
// Silent world-item drop attribution (the F7 rings show world meshes
|
// Silent world-item drop attribution (the F7 rings show world meshes
|
||||||
|
|
@ -8842,6 +8868,25 @@ void BuildFrameScene(uint8_t* base, const SubmitRecord* records, size_t count) {
|
||||||
dyn_slot.try_emplace(ctxk, scene.items.size() - 1);
|
dyn_slot.try_emplace(ctxk, scene.items.size() - 1);
|
||||||
g_rigid_rescued.fetch_add(1, std::memory_order_relaxed);
|
g_rigid_rescued.fetch_add(1, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
// Sort-list copies of dynamically-dispatched piece meshes (see
|
||||||
|
// g_dyn_dispatch_meshes): the game batches FAR clones through the
|
||||||
|
// static lists, where no per-entity capture carries their placement.
|
||||||
|
// Publish with the ctx owner's instance matrix; a live dynamic capture
|
||||||
|
// for the same ctx always wins (near clones arrive through both paths
|
||||||
|
// in the same frame, and double-publishing would z-fight).
|
||||||
|
for (auto& [ctxk, item] : sortlist_local_by_ctx) {
|
||||||
|
if (dyn_slot.find(ctxk) != dyn_slot.end()) {
|
||||||
|
continue; // this instance published live
|
||||||
|
}
|
||||||
|
if (!ReadCtxInstanceWorld(base, ctxk, item.world)) {
|
||||||
|
g_world_props.fetch_add(1, std::memory_order_relaxed);
|
||||||
|
continue; // no placement: dropping beats an origin ghost
|
||||||
|
}
|
||||||
|
++pub_count[item.mesh];
|
||||||
|
scene.items.push_back(std::move(item));
|
||||||
|
dyn_slot.try_emplace(ctxk, scene.items.size() - 1);
|
||||||
|
g_sortlist_local_pub.fetch_add(1, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
// Refused ropa captures re-publish last frame's resolved state: mode,
|
// Refused ropa captures re-publish last frame's resolved state: mode,
|
||||||
// world AND palette together (mixing frames' interpretations is the
|
// world AND palette together (mixing frames' interpretations is the
|
||||||
// mangled-ribbon bug; see g_ropa_state_cache).
|
// mangled-ribbon bug; see g_ropa_state_cache).
|
||||||
|
|
|
||||||
|
|
@ -825,6 +825,9 @@ inline std::atomic<uint64_t> g_rigid_rescued{0};
|
||||||
// Rigid worlds served from the guest instance matrix (ReadCtxInstanceWorld)
|
// Rigid worlds served from the guest instance matrix (ReadCtxInstanceWorld)
|
||||||
// instead of a constant bank.
|
// instead of a constant bank.
|
||||||
inline std::atomic<uint64_t> g_rigid_ctx_world{0};
|
inline std::atomic<uint64_t> g_rigid_ctx_world{0};
|
||||||
|
// Sort-list piece copies published with the instance matrix (see
|
||||||
|
// g_dyn_dispatch_meshes).
|
||||||
|
inline std::atomic<uint64_t> g_sortlist_local_pub{0};
|
||||||
// Last published world per rigid dynamic context. Guest render thread only.
|
// Last published world per rigid dynamic context. Guest render thread only.
|
||||||
// Same-mesh piece clones (park-editor venues submit dozens) share (ib,vb),
|
// Same-mesh piece clones (park-editor venues submit dozens) share (ib,vb),
|
||||||
// and their hook-time captures defer to the post-draw fixup whenever the
|
// and their hook-time captures defer to the post-draw fixup whenever the
|
||||||
|
|
@ -839,6 +842,17 @@ struct RigidWorldCache {
|
||||||
uint64_t frame = 0;
|
uint64_t frame = 0;
|
||||||
};
|
};
|
||||||
inline std::unordered_map<uint32_t, RigidWorldCache> g_rigid_world_cache;
|
inline std::unordered_map<uint32_t, RigidWorldCache> g_rigid_world_cache;
|
||||||
|
// Meshes seen on the per-entity dynamic dispatch (kind-0 captures), stamped
|
||||||
|
// with the guest frame of the last sighting. The game batches FAR instances
|
||||||
|
// of such pieces through the static sort lists instead of dispatching them
|
||||||
|
// per entity; their fmt-57 vertices are MESH-LOCAL, so the world-item
|
||||||
|
// path's identity world collapses them at the origin (the far-corner
|
||||||
|
// "teardown": one sub-mesh of each distant piece went invisible). A
|
||||||
|
// sort-list record whose mesh is fresh here publishes with the ctx owner's
|
||||||
|
// instance matrix instead. The freshness window doubles as map-change
|
||||||
|
// hygiene: a mesh address reused by a later load expires out on its own.
|
||||||
|
// Guest render thread only.
|
||||||
|
inline std::unordered_map<uint32_t, uint64_t> g_dyn_dispatch_meshes;
|
||||||
// Model-space props in the world sort lists, excluded from the identity
|
// Model-space props in the world sort lists, excluded from the identity
|
||||||
// world path (their placed copies come from the kind-2 capture).
|
// world path (their placed copies come from the kind-2 capture).
|
||||||
inline std::atomic<uint64_t> g_world_props{0};
|
inline std::atomic<uint64_t> g_world_props{0};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue