aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-07-18 12:28:27 +0300
committerValentin Popov <valentin@popov.link>2026-07-18 12:28:27 +0300
commit564edf0bc1d5fed1cbfc00db2ba5c4cd9d1b94ea (patch)
tree5774de073f48c44195c149298bb67d4f2f12da95
parent2474e480200a8dfa260a069730c19c4bb2cbdf8e (diff)
downloadfparkan-564edf0bc1d5fed1cbfc00db2ba5c4cd9d1b94ea.tar.xz
fparkan-564edf0bc1d5fed1cbfc00db2ba5c4cd9d1b94ea.zip
feat(runtime): trace visual cache sizes
-rw-r--r--apps/fparkan-game/src/main.rs5
-rw-r--r--crates/fparkan-assets/src/lib.rs147
-rw-r--r--crates/fparkan-runtime/src/lib.rs18
-rw-r--r--docs/tomes/05-render.md8
4 files changed, 146 insertions, 32 deletions
diff --git a/apps/fparkan-game/src/main.rs b/apps/fparkan-game/src/main.rs
index 414ee71..d2561b6 100644
--- a/apps/fparkan-game/src/main.rs
+++ b/apps/fparkan-game/src/main.rs
@@ -1093,6 +1093,9 @@ mod tests {
request_count: 64,
graph_node_count: 128,
graph_edge_count: 192,
+ wear_cache_entries: 8,
+ material_cache_entries: 16,
+ texture_cache_entries: 32,
},
)?;
let progress = std::fs::read_to_string(&path).map_err(|err| err.to_string())?;
@@ -1100,7 +1103,7 @@ mod tests {
assert_eq!(
progress,
- "Starting\telapsed_ms=0\nGraphVisualMaterials\telapsed_ms=12\nGraphVisualMaterialRequests { request_count: 64, graph_node_count: 128, graph_edge_count: 192 }\telapsed_ms=34\n"
+ "Starting\telapsed_ms=0\nGraphVisualMaterials\telapsed_ms=12\nGraphVisualMaterialRequests { request_count: 64, graph_node_count: 128, graph_edge_count: 192, wear_cache_entries: 8, material_cache_entries: 16, texture_cache_entries: 32 }\telapsed_ms=34\n"
);
Ok(())
}
diff --git a/crates/fparkan-assets/src/lib.rs b/crates/fparkan-assets/src/lib.rs
index 6e3364d..58fa5ed 100644
--- a/crates/fparkan-assets/src/lib.rs
+++ b/crates/fparkan-assets/src/lib.rs
@@ -52,6 +52,7 @@ const VISUAL_DEPENDENCY_PROGRESS_INTERVAL: usize = 64;
type WearValidationCache =
HashMap<(NormalizedPath, Vec<u8>), Result<fparkan_material::WearTable, String>>;
+type TextureValidationCache = HashMap<Vec<u8>, Result<(), String>>;
/// Canonical terrain archive paths derived from a mission land reference.
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -483,6 +484,17 @@ pub enum VisualDependencyPhase {
Texture,
}
+/// Validation-cache entries retained while expanding visual dependencies.
+#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
+pub struct VisualDependencyCacheCounts {
+ /// Distinct WEAR archive/name keys resolved so far.
+ pub wear_entries: usize,
+ /// Distinct MAT0 raw names resolved so far.
+ pub material_entries: usize,
+ /// Distinct TEXM archive/name keys resolved so far.
+ pub texture_entries: usize,
+}
+
/// Throttled visual-dependency expansion progress.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct VisualDependencyProgress {
@@ -494,6 +506,8 @@ pub struct VisualDependencyProgress {
pub graph_node_count: usize,
/// Resource graph edges materialized before this request is resolved.
pub graph_edge_count: usize,
+ /// Validation-cache entries retained before this request is resolved.
+ pub cache_entries: VisualDependencyCacheCounts,
}
/// Errors raised while preparing CPU-side assets.
@@ -1241,10 +1255,18 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep
wear_requests = wear_requests.saturating_add(1);
report_visual_dependency_progress(
&mut on_progress,
- VisualDependencyPhase::Wear,
- wear_requests,
- graph.nodes.len(),
- graph.edges.len(),
+ VisualDependencyProgress {
+ phase: VisualDependencyPhase::Wear,
+ request_count: wear_requests,
+ graph_node_count: graph.nodes.len(),
+ graph_edge_count: graph.edges.len(),
+ cache_entries: visual_dependency_cache_counts(
+ &wear_validation,
+ &material_validation,
+ &diffuse_texture_validation,
+ &lightmap_texture_validation,
+ ),
+ },
);
match resolve_wear_table_cached(repository, mesh, &mut wear_validation) {
Ok(table) => {
@@ -1289,15 +1311,29 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep
request_count: material_requests,
graph_node_count: graph.nodes.len(),
graph_edge_count: graph.edges.len(),
+ cache_entries: visual_dependency_cache_counts(
+ &wear_validation,
+ &material_validation,
+ &diffuse_texture_validation,
+ &lightmap_texture_validation,
+ ),
});
for (material_index, _entry) in table.entries.iter().enumerate() {
material_requests = material_requests.saturating_add(1);
report_visual_dependency_progress(
&mut on_progress,
- VisualDependencyPhase::Material,
- material_requests,
- graph.nodes.len(),
- graph.edges.len(),
+ VisualDependencyProgress {
+ phase: VisualDependencyPhase::Material,
+ request_count: material_requests,
+ graph_node_count: graph.nodes.len(),
+ graph_edge_count: graph.edges.len(),
+ cache_entries: visual_dependency_cache_counts(
+ &wear_validation,
+ &material_validation,
+ &diffuse_texture_validation,
+ &lightmap_texture_validation,
+ ),
+ },
);
let Ok(material_index) = u16::try_from(material_index) else {
push_visual_failure(
@@ -1347,10 +1383,18 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep
texture_requests = texture_requests.saturating_add(1);
report_visual_dependency_progress(
&mut on_progress,
- VisualDependencyPhase::Texture,
- texture_requests,
- graph.nodes.len(),
- graph.edges.len(),
+ VisualDependencyProgress {
+ phase: VisualDependencyPhase::Texture,
+ request_count: texture_requests,
+ graph_node_count: graph.nodes.len(),
+ graph_edge_count: graph.edges.len(),
+ cache_entries: visual_dependency_cache_counts(
+ &wear_validation,
+ &material_validation,
+ &diffuse_texture_validation,
+ &lightmap_texture_validation,
+ ),
+ },
);
report.texture_request_count += 1;
match resolve_texm_validation_cached(
@@ -1415,10 +1459,18 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep
texture_requests = texture_requests.saturating_add(1);
report_visual_dependency_progress(
&mut on_progress,
- VisualDependencyPhase::Texture,
- texture_requests,
- graph.nodes.len(),
- graph.edges.len(),
+ VisualDependencyProgress {
+ phase: VisualDependencyPhase::Texture,
+ request_count: texture_requests,
+ graph_node_count: graph.nodes.len(),
+ graph_edge_count: graph.edges.len(),
+ cache_entries: visual_dependency_cache_counts(
+ &wear_validation,
+ &material_validation,
+ &diffuse_texture_validation,
+ &lightmap_texture_validation,
+ ),
+ },
);
report.lightmap_request_count += 1;
match resolve_texm_validation_cached(
@@ -1484,18 +1536,29 @@ pub fn extend_graph_report_with_visual_dependencies_with_progress<R: ResourceRep
fn report_visual_dependency_progress(
on_progress: &mut impl FnMut(VisualDependencyProgress),
- phase: VisualDependencyPhase,
- request_count: usize,
- graph_node_count: usize,
- graph_edge_count: usize,
+ progress: VisualDependencyProgress,
) {
- if request_count == 1 || request_count.is_multiple_of(VISUAL_DEPENDENCY_PROGRESS_INTERVAL) {
- on_progress(VisualDependencyProgress {
- phase,
- request_count,
- graph_node_count,
- graph_edge_count,
- });
+ if progress.request_count == 1
+ || progress
+ .request_count
+ .is_multiple_of(VISUAL_DEPENDENCY_PROGRESS_INTERVAL)
+ {
+ on_progress(progress);
+ }
+}
+
+fn visual_dependency_cache_counts(
+ wear_validation: &WearValidationCache,
+ material_validation: &HashMap<Vec<u8>, Result<ResolvedMaterial, String>>,
+ diffuse_texture_validation: &TextureValidationCache,
+ lightmap_texture_validation: &TextureValidationCache,
+) -> VisualDependencyCacheCounts {
+ VisualDependencyCacheCounts {
+ wear_entries: wear_validation.len(),
+ material_entries: material_validation.len(),
+ texture_entries: diffuse_texture_validation
+ .len()
+ .saturating_add(lightmap_texture_validation.len()),
}
}
@@ -2336,10 +2399,17 @@ mod tests {
for request_count in 1..=129 {
report_visual_dependency_progress(
&mut |event| progress.push(event),
- VisualDependencyPhase::Texture,
- request_count,
- 37,
- 41,
+ VisualDependencyProgress {
+ phase: VisualDependencyPhase::Texture,
+ request_count,
+ graph_node_count: 37,
+ graph_edge_count: 41,
+ cache_entries: VisualDependencyCacheCounts {
+ wear_entries: 3,
+ material_entries: 5,
+ texture_entries: 7,
+ },
+ },
);
}
@@ -2351,18 +2421,33 @@ mod tests {
request_count: 1,
graph_node_count: 37,
graph_edge_count: 41,
+ cache_entries: VisualDependencyCacheCounts {
+ wear_entries: 3,
+ material_entries: 5,
+ texture_entries: 7,
+ },
},
VisualDependencyProgress {
phase: VisualDependencyPhase::Texture,
request_count: 64,
graph_node_count: 37,
graph_edge_count: 41,
+ cache_entries: VisualDependencyCacheCounts {
+ wear_entries: 3,
+ material_entries: 5,
+ texture_entries: 7,
+ },
},
VisualDependencyProgress {
phase: VisualDependencyPhase::Texture,
request_count: 128,
graph_node_count: 37,
graph_edge_count: 41,
+ cache_entries: VisualDependencyCacheCounts {
+ wear_entries: 3,
+ material_entries: 5,
+ texture_entries: 7,
+ },
},
]
);
diff --git a/crates/fparkan-runtime/src/lib.rs b/crates/fparkan-runtime/src/lib.rs
index 1ab8e38..a80d58e 100644
--- a/crates/fparkan-runtime/src/lib.rs
+++ b/crates/fparkan-runtime/src/lib.rs
@@ -133,6 +133,12 @@ pub enum MissionLoadPhase {
graph_node_count: usize,
/// Graph edges materialized before the request.
graph_edge_count: usize,
+ /// Distinct WEAR validation keys retained before the request.
+ wear_cache_entries: usize,
+ /// Distinct MAT0 validation keys retained before the request.
+ material_cache_entries: usize,
+ /// Distinct TEXM validation keys retained before the request.
+ texture_cache_entries: usize,
},
/// Validate TEXM documents while expanding visual dependencies.
GraphVisualTextures,
@@ -144,6 +150,12 @@ pub enum MissionLoadPhase {
graph_node_count: usize,
/// Graph edges materialized before the request.
graph_edge_count: usize,
+ /// Distinct WEAR validation keys retained before the request.
+ wear_cache_entries: usize,
+ /// Distinct MAT0 validation keys retained before the request.
+ material_cache_entries: usize,
+ /// Distinct TEXM validation keys retained before the request.
+ texture_cache_entries: usize,
},
/// Prepare all reachable visual/resource dependencies.
Assets,
@@ -747,6 +759,9 @@ fn load_mission_with_options_and_progress(
request_count: progress.request_count,
graph_node_count: progress.graph_node_count,
graph_edge_count: progress.graph_edge_count,
+ wear_cache_entries: progress.cache_entries.wear_entries,
+ material_cache_entries: progress.cache_entries.material_entries,
+ texture_cache_entries: progress.cache_entries.texture_entries,
})
}
VisualDependencyPhase::Texture => {
@@ -754,6 +769,9 @@ fn load_mission_with_options_and_progress(
request_count: progress.request_count,
graph_node_count: progress.graph_node_count,
graph_edge_count: progress.graph_edge_count,
+ wear_cache_entries: progress.cache_entries.wear_entries,
+ material_cache_entries: progress.cache_entries.material_entries,
+ texture_cache_entries: progress.cache_entries.texture_entries,
})
}
};
diff --git a/docs/tomes/05-render.md b/docs/tomes/05-render.md
index d390a9a..cf51b41 100644
--- a/docs/tomes/05-render.md
+++ b/docs/tomes/05-render.md
@@ -1133,6 +1133,14 @@ probe recorded MAT0 request 3 at 52 nodes / 51 edges and request 4 at 55 nodes
they do not change traversal order, node or edge identities, provenance,
validation, cache semantics, or rendering.
+The same throttled snapshots now retain the number of distinct validation-cache
+keys for WEAR, MAT0, and TEXM before the request. In a fresh 50-second Part 2
+probe, MAT0 request 3 recorded cache counts 2 / 3 / 3 and request 4 recorded
+3 / 4 / 4, while the graph moved from 52 / 51 to 55 / 54 nodes / edges. The
+counts distinguish cache growth from graph growth without adding per-request
+file writes or asserting which parser, archive I/O operation, or allocation
+caused the elapsed interval.
+
`fparkan-game --load-progress` now initializes its file with `Starting` and
appends each later mission-load event instead of replacing the prior line. A
bounded probe can therefore retain both MAT0 and TEXM request milestones even