diff options
| author | Valentin Popov <valentin@popov.link> | 2026-07-18 12:17:06 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-07-18 12:17:06 +0300 |
| commit | 2e14b1d5dd99ecd577c96ea4aaacdd584872a338 (patch) | |
| tree | 7ac3d27e04c1326d8a01f79039d727647588616f | |
| parent | 67308d4019891d607ca43807b6d0a3652923bb6d (diff) | |
| download | fparkan-2e14b1d5dd99ecd577c96ea4aaacdd584872a338.tar.xz fparkan-2e14b1d5dd99ecd577c96ea4aaacdd584872a338.zip | |
perf(assets): cache visual wear validation
| -rw-r--r-- | crates/fparkan-assets/src/lib.rs | 43 | ||||
| -rw-r--r-- | docs/tomes/05-render.md | 11 |
2 files changed, 52 insertions, 2 deletions
diff --git a/crates/fparkan-assets/src/lib.rs b/crates/fparkan-assets/src/lib.rs index d133574..11e324f 100644 --- a/crates/fparkan-assets/src/lib.rs +++ b/crates/fparkan-assets/src/lib.rs @@ -50,6 +50,9 @@ const TEXTURES_ARCHIVE: &str = "textures.lib"; const LIGHTMAP_ARCHIVE: &str = "lightmap.lib"; const VISUAL_DEPENDENCY_PROGRESS_INTERVAL: usize = 64; +type WearValidationCache = + HashMap<(NormalizedPath, Vec<u8>), Result<fparkan_material::WearTable, String>>; + /// Canonical terrain archive paths derived from a mission land reference. #[derive(Clone, Debug, Eq, PartialEq)] pub struct MissionTerrainPaths { @@ -1202,6 +1205,7 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep let mut diffuse_texture_validation = HashMap::new(); let mut lightmap_texture_validation = HashMap::new(); let mut material_validation = HashMap::new(); + let mut wear_validation = HashMap::new(); let mut wear_requests = 0usize; let mut material_requests = 0usize; let mut texture_requests = 0usize; @@ -1236,7 +1240,7 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep VisualDependencyPhase::Wear, wear_requests, ); - match resolve_wear_table(repository, mesh) { + match resolve_wear_table_cached(repository, mesh, &mut wear_validation) { Ok(table) => { report.wear_resolved_count += 1; let wear_key = match wear_resource_key(mesh) { @@ -1457,7 +1461,7 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep mesh.name.0.clone(), PrototypeGraphEdge::MeshToWear, PrototypeGraphRequiredness::Required, - &message.to_string(), + &message, ), } } @@ -1899,6 +1903,21 @@ fn resolve_wear_table<R: ResourceRepository>( decode_wear(&bytes).map_err(AssetError::Material) } +fn resolve_wear_table_cached<R: ResourceRepository>( + repository: &R, + mesh: &ResourceKey, + cache: &mut WearValidationCache, +) -> Result<fparkan_material::WearTable, String> { + let wear_key = wear_resource_key(mesh).map_err(|error| error.to_string())?; + let cache_key = (wear_key.archive.clone(), wear_key.name.0.clone()); + if let Some(result) = cache.get(&cache_key) { + return result.clone(); + } + let result = resolve_wear_table(repository, mesh).map_err(|error| error.to_string()); + cache.insert(cache_key, result.clone()); + result +} + fn push_visual_failure( report: &mut PrototypeGraphReport, graph: &PrototypeGraph, @@ -2324,6 +2343,26 @@ mod tests { } #[test] + fn wear_validation_cache_replays_archive_qualified_failure() { + let repository = repository_with_archives(&[]); + let mesh = ResourceKey { + archive: parse_path("static.rlb").expect("archive"), + name: resource_name(b"tree.msh"), + type_id: Some(0x4853_454D), + }; + let mut cache = WearValidationCache::new(); + cache.insert( + (mesh.archive.clone(), b"tree.wea".to_vec()), + Err("cached WEAR failure".to_string()), + ); + + assert_eq!( + resolve_wear_table_cached(&repository, &mesh, &mut cache), + Err("cached WEAR failure".to_string()) + ); + } + + #[test] fn count_only_plan_uses_graph_requests() { let graph = PrototypeGraph::default(); diff --git a/docs/tomes/05-render.md b/docs/tomes/05-render.md index d6c9953..b647f19 100644 --- a/docs/tomes/05-render.md +++ b/docs/tomes/05-render.md @@ -1151,6 +1151,17 @@ the measured unfinished interval for this run. It still does not allocate that time among MAT0 decode, graph allocation, archive I/O, OS cache state, or the interleaved TEXM requests. +Visual expansion now also caches WEAR validation by the complete derived WEAR +archive/name key and replays both successes and failures. It still creates each +per-prototype WEAR edge, increments the same request counters, and reports the +same failure provenance. A unit test verifies an archive-qualified cached +failure is replayed without consulting the repository. In a matched bounded +Part 2 probe the first TEXM-64 marker occurred at 135,520 ms, versus 134,793 +ms in the preceding sample, and neither run reached `Assets`; therefore this +corpus does not evidence a startup advance from WEAR caching. The path is kept +as a correctness-preserving duplicate-resolve optimization, not a causal +performance claim. + A rebuilt executable then ran a controlled 180-second Part 2 `Autodemo.00` probe with the append-only trace. Before exact-child termination it recorded `GraphVisualTextureRequests(64)`, `GraphVisualMaterialRequests(100)`, and every |
