Optimize rollback sync-test performance #86

Merged
EIREXE merged 1 commits from perf/rollback-synctest into master 2026-10-07 15:50:46 +00:00
4 changed files with 127 additions and 27 deletions
Generated
+91
View File
@@ -516,6 +516,7 @@ checksum = "4bfadbebfc6599aa59289b754ac30023959854304f3d393da2cf62bb3cd5df8f"
dependencies = [
"bevy_dylib",
"bevy_internal",
"tracing",
]
[[package]]
@@ -694,6 +695,7 @@ dependencies = [
"downcast-rs 2.0.2",
"log",
"thiserror 2.0.19",
"tracing",
"variadics_please",
"wasm-bindgen",
"web-sys",
@@ -1001,6 +1003,7 @@ dependencies = [
"slotmap",
"smallvec",
"thiserror 2.0.19",
"tracing",
"variadics_please",
]
@@ -1421,9 +1424,11 @@ dependencies = [
"bevy_platform",
"bevy_utils",
"tracing",
"tracing-error",
"tracing-log",
"tracing-oslog",
"tracing-subscriber",
"tracing-tracy",
"tracing-wasm",
]
@@ -1733,9 +1738,11 @@ dependencies = [
"naga",
"nonmax",
"offset-allocator",
"profiling",
"send_wrapper",
"smallvec",
"thiserror 2.0.19",
"tracy-client",
"variadics_please",
"wasm-bindgen",
"weak-table",
@@ -3463,6 +3470,21 @@ dependencies = [
"rusb",
]
[[package]]
name = "generator"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54ade96dc9003043bce7c035c85a9df5a858bfb2039c5a2e6fdf00f324f6c551"
dependencies = [
"cc",
"cfg-if",
"libc",
"log",
"rustversion",
"windows-link",
"windows-result",
]
[[package]]
name = "gethostname"
version = "1.1.0"
@@ -4381,6 +4403,19 @@ version = "0.4.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
[[package]]
name = "loom"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
dependencies = [
"cfg-if",
"generator",
"scoped-tls",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "mach2"
version = "0.5.0"
@@ -5629,6 +5664,20 @@ name = "profiling"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5"
dependencies = [
"profiling-procmacros",
"tracing",
]
[[package]]
name = "profiling-procmacros"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb"
dependencies = [
"quote",
"syn 2.0.119",
]
[[package]]
name = "pxfm"
@@ -6829,6 +6878,16 @@ dependencies = [
"valuable",
]
[[package]]
name = "tracing-error"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db"
dependencies = [
"tracing",
"tracing-subscriber",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
@@ -6870,6 +6929,17 @@ dependencies = [
"tracing-log",
]
[[package]]
name = "tracing-tracy"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eaa1852afa96e0fe9e44caa53dc0bd2d9d05e0f2611ce09f97f8677af56e4ba"
dependencies = [
"tracing-core",
"tracing-subscriber",
"tracy-client",
]
[[package]]
name = "tracing-wasm"
version = "0.2.1"
@@ -6881,6 +6951,27 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "tracy-client"
version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6131992ff3e2cb96f407eb4eb005427ba15e2687260d99089b90e60e33169ce0"
dependencies = [
"loom",
"once_cell",
"tracy-client-sys",
]
[[package]]
name = "tracy-client-sys"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab27f167b093214c68413a2e0bcd318f0591af475597405ff68138ba0a433379"
dependencies = [
"cc",
"windows-targets 0.52.6",
]
[[package]]
name = "tree_magic_mini"
version = "3.2.2"
+6
View File
@@ -9,6 +9,7 @@ authors = [""]
[features]
default = ["development", "debug_features", "gamecube-adapter"]
development = ["bevy/dynamic_linking", "bevy/file_watcher", "bevy/embedded_watcher", "hitbox-viewer"]
tracy = ["bevy/trace_tracy"]
debug_features = ["bevy/free_camera"]
gamecube-adapter = ["dep:gc-adapter-neo"]
hitbox-viewer = ["bevy/bevy_dev_tools", "dep:egui_extras"]
@@ -44,6 +45,11 @@ fixed_math = "0.4.1"
[profile.dev.package."*"]
opt-level = 3
# The rollback simulation runs multiple times per rendered frame in sync-test
# mode, so optimizing the game crate is important even for development builds.
[profile.dev]
opt-level = 1
[profile.production]
inherits = "release"
lto = "thin"
+27 -20
View File
@@ -127,6 +127,8 @@ pub struct FighterBoneMatrices {
/// pose has the root translation removed.
previous_root_motion_translation: Option<FGVec3>,
root_motion_delta: crate::math::vec3::FGVec3,
cached_root_motion_kind: Option<AnimKind>,
cached_root_motion_cycle_delta: FGVec3,
}
#[derive(Component, Clone, Debug, Default)]
@@ -366,12 +368,6 @@ impl FighterBoneMatrices {
.expect("configured root motion bone should exist"),
)
};
self.model_matrices.resize(local.len(), None);
self.model_matrices.fill(None);
for index in 0..local.len() {
resolve_model_transform(index, parents, local, &mut self.model_matrices)
.expect("baked bone hierarchy should be valid");
}
let model_scale = FixedMat4 {
cols: [
[model_scale, FGi32::ZERO, FGi32::ZERO, FGi32::ZERO],
@@ -380,13 +376,16 @@ impl FighterBoneMatrices {
[FGi32::ZERO, FGi32::ZERO, FGi32::ZERO, FGi32::ONE],
],
};
// Root motion only needs the configured bone's model transform. Resolve
// that ancestry first, then do the normal full-pose pass once below.
// Previously the complete hierarchy was resolved once before removing
// root translation and once afterwards.
let raw_root_motion_translation = root_index.map(|root_index| {
model_scale
.mul(
self.model_matrices[root_index]
.expect("baked bone hierarchy should be valid"),
)
.get_translation()
self.model_matrices.resize(local.len(), None);
self.model_matrices.fill(None);
let root = resolve_model_transform(root_index, parents, local, &mut self.model_matrices)
.expect("baked bone hierarchy should be valid");
model_scale.mul(root).get_translation()
});
// Gameplay owns the root's displacement. Keep rotation and scale in
@@ -394,11 +393,12 @@ impl FighterBoneMatrices {
// used by visuals and gameplay volumes.
if let Some(root_index) = root_index {
self.local_matrices[root_index].translate(FGVec3::ZERO);
self.model_matrices.fill(None);
for index in 0..local.len() {
resolve_model_transform(index, parents, &self.local_matrices, &mut self.model_matrices)
.expect("baked bone hierarchy should be valid");
}
}
self.model_matrices.resize(local.len(), None);
self.model_matrices.fill(None);
for index in 0..local.len() {
resolve_model_transform(index, parents, &self.local_matrices, &mut self.model_matrices)
.expect("baked bone hierarchy should be valid");
}
self.matrices.clear();
self.matrices.extend(
@@ -517,9 +517,16 @@ fn sample_fighter_bone_matrices(
let manifest = manifests
.get(&fighter.manifest)
.expect("fighter manifest should be loaded before the match starts");
let root_motion_cycle_delta = baked
.root_motion_cycle_delta(frame.kind, &manifest.root_motion_bone, manifest.model_scale)
.unwrap_or(FGVec3::ZERO);
let root_motion_cycle_delta = if matrices.cached_root_motion_kind == Some(frame.kind) {
matrices.cached_root_motion_cycle_delta
} else {
let delta = baked
.root_motion_cycle_delta(frame.kind, &manifest.root_motion_bone, manifest.model_scale)
.unwrap_or(FGVec3::ZERO);
matrices.cached_root_motion_kind = Some(frame.kind);
matrices.cached_root_motion_cycle_delta = delta;
delta
};
let root_motion_loop_frame_count = baked
.frame_count(frame.kind)
.map(|count| count.saturating_sub(1).max(1));
+2 -6
View File
@@ -42,8 +42,8 @@ use crate::{
AttackKind, FighterAttackPlugin, FighterAttackScriptAssets, FighterDamage,
FighterKnockbackVelocity, FighterPendingHitReaction, FighterSolvedHurtboxes,
FighterStaleMoveQueue,
}, baked_animation::{FighterBoneIndexMap, FighterBoneMatrices}, ecb::FighterECBBoneIndices, manifest::FighterManifest, state::{FighterState, air::AirborneStateCommon, fall::FallState}, visual::{FighterAnimations, FighterInvulnerabilityVisualState},
}, game_settings::GameSettings, input::FighterInput, math::{int::FGi32, vec::FGVec2}, player::Player, schedule::GameplaySet, scripting::FighterAttackScript, stage::line::StageCollision,
}, baked_animation::FighterBoneIndexMap, ecb::FighterECBBoneIndices, manifest::FighterManifest, state::{FighterState, air::AirborneStateCommon, fall::FallState}, visual::{FighterAnimations, FighterInvulnerabilityVisualState},
}, game_settings::GameSettings, input::FighterInput, math::{int::FGi32, vec::FGVec2}, player::Player, schedule::GameplaySet, scripting::FighterAttackScript,
};
use state::state_interrupt_system;
@@ -250,7 +250,6 @@ impl Plugin for FighterPlugin {
.checksum_component_with_hash::<FighterInvulnerabilityState>()
.rollback_component_with_copy::<FighterKnockbackVelocity>()
.checksum_component_with_hash::<FighterKnockbackVelocity>()
.rollback_resource_with_reflect::<StageCollision>()
// Debug views.
.add_systems(
FixedPostUpdate,
@@ -284,11 +283,8 @@ impl Plugin for FighterPlugin {
)
.rollback_component_with_clone::<FighterState>()
.rollback_component_with_clone::<FighterHitboxes>()
.rollback_component_with_clone::<FighterBoneMatrices>()
.rollback_component_with_clone::<FighterHitstopShake>()
.checksum_component_with_hash::<FighterHitboxes>()
.rollback_component_with_clone::<FighterSolvedHurtboxes>()
.checksum_component_with_hash::<FighterSolvedHurtboxes>()
.checksum_component_with_hash::<FighterState>()
.checksum_component_with_hash::<FighterFacingDirection>()
.register_type::<FighterFacingDirection>();