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
|
||||
// skinned palettes.
|
||||
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:
|
||||
// own_draw_last only proves SOME clone of this mesh drew last (clones
|
||||
// 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
|
||||
// this frame; rescued with their cached world (see g_rigid_world_cache).
|
||||
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) {
|
||||
uint64_t n = 0;
|
||||
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);
|
||||
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));
|
||||
} else {
|
||||
// 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);
|
||||
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,
|
||||
// world AND palette together (mixing frames' interpretations is the
|
||||
// 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)
|
||||
// instead of a constant bank.
|
||||
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.
|
||||
// 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
|
||||
|
|
@ -839,6 +842,17 @@ struct RigidWorldCache {
|
|||
uint64_t frame = 0;
|
||||
};
|
||||
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
|
||||
// world path (their placed copies come from the kind-2 capture).
|
||||
inline std::atomic<uint64_t> g_world_props{0};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue