feat(runtime): bound static preview asset loading
This commit is contained in:
@@ -27,7 +27,7 @@ Open source проект с реализацией компонентов игр
|
|||||||
- [apps/fparkan-cli](apps/fparkan-cli) — CLI для архивов, графов и acceptance-отчетов.
|
- [apps/fparkan-cli](apps/fparkan-cli) — CLI для архивов, графов и acceptance-отчетов.
|
||||||
- [apps/fparkan-viewer](apps/fparkan-viewer) — inspection-only CLI для archive/model/texture/map без live Vulkan draw path.
|
- [apps/fparkan-viewer](apps/fparkan-viewer) — inspection-only CLI для archive/model/texture/map без live Vulkan draw path.
|
||||||
- [apps/fparkan-headless](apps/fparkan-headless) — headless runtime composition root.
|
- [apps/fparkan-headless](apps/fparkan-headless) — headless runtime composition root.
|
||||||
- [apps/fparkan-game](apps/fparkan-game) — mission composition root: по умолчанию выдаёт planning report; opt-in `--backend static-vulkan` открывает native Vulkan окно для первой подготовленной MSH-модели миссии.
|
- [apps/fparkan-game](apps/fparkan-game) — mission composition root: по умолчанию выдаёт planning report; opt-in `--backend static-vulkan` использует bounded preview loader и открывает native Vulkan окно для первой mesh-backed MSH-модели.
|
||||||
|
|
||||||
## Текущий статус рендера
|
## Текущий статус рендера
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ use fparkan_render_vulkan::{
|
|||||||
VulkanSmokeRenderer, VulkanSmokeRendererCreateInfo, VulkanStaticMesh,
|
VulkanSmokeRenderer, VulkanSmokeRendererCreateInfo, VulkanStaticMesh,
|
||||||
};
|
};
|
||||||
use fparkan_runtime::{
|
use fparkan_runtime::{
|
||||||
create, frame, load_mission, loaded_mission_assets, EngineConfig, EngineMode, EngineServices,
|
create, frame, load_mission, load_mission_static_preview, loaded_mission_assets, EngineConfig,
|
||||||
MissionAssets, MissionObjectDraft, MissionRequest,
|
EngineMode, EngineServices, MissionAssets, MissionObjectDraft, MissionRequest,
|
||||||
};
|
};
|
||||||
use fparkan_vfs::DirectoryVfs;
|
use fparkan_vfs::DirectoryVfs;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -74,12 +74,14 @@ fn run(args: &[String]) -> Result<String, String> {
|
|||||||
services,
|
services,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.to_string())?;
|
.map_err(|err| err.to_string())?;
|
||||||
let loaded = load_mission(
|
let request = MissionRequest {
|
||||||
&mut engine,
|
key: args.mission.clone(),
|
||||||
MissionRequest {
|
};
|
||||||
key: args.mission.clone(),
|
let loaded = if args.backend == RenderBackendMode::StaticVulkan {
|
||||||
},
|
load_mission_static_preview(&mut engine, request)
|
||||||
)
|
} else {
|
||||||
|
load_mission(&mut engine, request)
|
||||||
|
}
|
||||||
.map_err(|err| err.to_string())?;
|
.map_err(|err| err.to_string())?;
|
||||||
|
|
||||||
if args.backend == RenderBackendMode::StaticVulkan {
|
if args.backend == RenderBackendMode::StaticVulkan {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ use fparkan_path::{normalize_relative, NormalizedPath, PathError, PathPolicy};
|
|||||||
use fparkan_prototype::{
|
use fparkan_prototype::{
|
||||||
build_prototype_graph_report, PrototypeGraph, PrototypeGraphFailure, PrototypeGraphReport,
|
build_prototype_graph_report, PrototypeGraph, PrototypeGraphFailure, PrototypeGraphReport,
|
||||||
};
|
};
|
||||||
use fparkan_resource::{resource_name, CachedResourceRepository};
|
use fparkan_resource::{resource_name, CachedResourceRepository, ResourceRepository};
|
||||||
use fparkan_vfs::{Vfs, VfsError};
|
use fparkan_vfs::{Vfs, VfsError};
|
||||||
use fparkan_world::{
|
use fparkan_world::{
|
||||||
construct_object, new as new_world, register_object, step, InputSnapshot, ObjectDraft,
|
construct_object, new as new_world, register_object, step, InputSnapshot, ObjectDraft,
|
||||||
@@ -182,6 +182,17 @@ pub struct MissionObjectDraft {
|
|||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||||
struct MissionLoadOptions {
|
struct MissionLoadOptions {
|
||||||
fail_after_registered_objects: Option<usize>,
|
fail_after_registered_objects: Option<usize>,
|
||||||
|
asset_scope: MissionAssetScope,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Selects how much of the resolved mission asset graph to prepare.
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||||
|
enum MissionAssetScope {
|
||||||
|
/// Prepare every reachable asset; required by normal runtime loading.
|
||||||
|
#[default]
|
||||||
|
Full,
|
||||||
|
/// Prepare one root at a time until a mesh-backed preview model is found.
|
||||||
|
FirstMeshPreview,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loaded mission.
|
/// Loaded mission.
|
||||||
@@ -462,6 +473,33 @@ pub fn load_mission(
|
|||||||
load_mission_with_trace(engine, request).map(|(loaded, _trace)| loaded)
|
load_mission_with_trace(engine, request).map(|(loaded, _trace)| loaded)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Loads a mission using the bounded static-preview asset scope.
|
||||||
|
///
|
||||||
|
/// This mode preserves map, TMA, graph, construction and registration work,
|
||||||
|
/// but prepares only the first root that supplies a mesh-backed model. It is
|
||||||
|
/// intended solely for the opt-in static Vulkan preview and must not be used
|
||||||
|
/// for normal gameplay, where all reachable assets remain required.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns [`EngineError`] under the same decoding, graph, terrain and world
|
||||||
|
/// conditions as [`load_mission`], plus asset errors for the roots examined by
|
||||||
|
/// the preview scope.
|
||||||
|
pub fn load_mission_static_preview(
|
||||||
|
engine: &mut Engine,
|
||||||
|
request: MissionRequest,
|
||||||
|
) -> Result<LoadedMission, EngineError> {
|
||||||
|
load_mission_with_options(
|
||||||
|
engine,
|
||||||
|
request,
|
||||||
|
MissionLoadOptions {
|
||||||
|
asset_scope: MissionAssetScope::FirstMeshPreview,
|
||||||
|
..MissionLoadOptions::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map(|(loaded, _trace)| loaded)
|
||||||
|
}
|
||||||
|
|
||||||
/// Loads mission transactionally and returns a diagnostic trace.
|
/// Loads mission transactionally and returns a diagnostic trace.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
@@ -564,15 +602,22 @@ fn load_mission_with_options(
|
|||||||
failures: prototype_report.failures.clone(),
|
failures: prototype_report.failures.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let mission_assets = AssetManager::new(repository)
|
let asset_manager = AssetManager::new(repository);
|
||||||
.prepare_mission_assets(
|
let mission_assets = match options.asset_scope {
|
||||||
|
MissionAssetScope::Full => asset_manager.prepare_mission_assets(
|
||||||
&prototype_graph.root_prototype_request_spans,
|
&prototype_graph.root_prototype_request_spans,
|
||||||
&resolved_prototypes,
|
&resolved_prototypes,
|
||||||
)
|
),
|
||||||
.map_err(|source| EngineError::AssetPreparation {
|
MissionAssetScope::FirstMeshPreview => prepare_first_mesh_preview_assets(
|
||||||
mission: request.key.clone(),
|
&asset_manager,
|
||||||
source,
|
&prototype_graph.root_prototype_request_spans,
|
||||||
})?;
|
&resolved_prototypes,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.map_err(|source| EngineError::AssetPreparation {
|
||||||
|
mission: request.key.clone(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
let mission_asset_plan = mission_assets.to_plan();
|
let mission_asset_plan = mission_assets.to_plan();
|
||||||
let object_drafts: Vec<_> = mission
|
let object_drafts: Vec<_> = mission
|
||||||
.objects
|
.objects
|
||||||
@@ -672,6 +717,21 @@ fn load_mission_with_options(
|
|||||||
Ok((summary, trace))
|
Ok((summary, trace))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prepare_first_mesh_preview_assets<R: ResourceRepository>(
|
||||||
|
asset_manager: &AssetManager<R>,
|
||||||
|
root_spans: &[std::ops::Range<usize>],
|
||||||
|
prototypes: &[fparkan_prototype::EffectivePrototype],
|
||||||
|
) -> Result<MissionAssets, AssetPreparationError> {
|
||||||
|
for span in root_spans {
|
||||||
|
let assets =
|
||||||
|
asset_manager.prepare_mission_assets(std::slice::from_ref(span), prototypes)?;
|
||||||
|
if !assets.models.is_empty() {
|
||||||
|
return Ok(assets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(MissionAssets::default())
|
||||||
|
}
|
||||||
|
|
||||||
/// Steps headless mode.
|
/// Steps headless mode.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
@@ -1063,6 +1123,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
MissionLoadOptions {
|
MissionLoadOptions {
|
||||||
fail_after_registered_objects: Some(1),
|
fail_after_registered_objects: Some(1),
|
||||||
|
..MissionLoadOptions::default()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.expect_err("forced registration failure");
|
.expect_err("forced registration failure");
|
||||||
|
|||||||
@@ -35,10 +35,12 @@
|
|||||||
- `apps/fparkan-game` по умолчанию выдает `render-planning` JSON report поверх
|
- `apps/fparkan-game` по умолчанию выдает `render-planning` JSON report поверх
|
||||||
synthetic window descriptor и `VulkanPlanningBackend`. Opt-in `--backend static-vulkan`
|
synthetic window descriptor и `VulkanPlanningBackend`. Opt-in `--backend static-vulkan`
|
||||||
уже создаёт native `winit` window и передаёт первую подготовленную MSH модели миссии в
|
уже создаёт native `winit` window и передаёт первую подготовленную MSH модели миссии в
|
||||||
`VulkanSmokeRenderer` с пустым списком materials (явный white-fallback). Это не является
|
`VulkanSmokeRenderer` с пустым списком materials (явный white-fallback). Режим использует
|
||||||
rendered acceptance: fresh GOG `MISSIONS/Autodemo.00/data.tma` test не дошёл до окна за
|
отдельный bounded preview loader: normal `load_mission` по-прежнему готовит все reachable
|
||||||
локальный 120-second runner limit, поэтому нет live report, pixel artifact или validation
|
assets, тогда как preview останавливает asset preparation после первого root с mesh-backed
|
||||||
evidence именно для game path.
|
model. Это не является rendered acceptance: fresh GOG `MISSIONS/Autodemo.00/data.tma` test
|
||||||
|
с этим scope всё равно не дошёл до окна за локальный 120-second runner limit, поэтому нет
|
||||||
|
live report, pixel artifact или validation evidence именно для game path.
|
||||||
- `apps/fparkan-viewer` сейчас inspection-only CLI и не открывает live Vulkan
|
- `apps/fparkan-viewer` сейчас inspection-only CLI и не открывает live Vulkan
|
||||||
asset viewer.
|
asset viewer.
|
||||||
- Следующий реальный milestone для rendered acceptance: `VulkanAssetRenderer`
|
- Следующий реальный milestone для rendered acceptance: `VulkanAssetRenderer`
|
||||||
|
|||||||
@@ -951,6 +951,14 @@ WEAR/MAT0/TEXM material data, or establish a game camera. A GOG
|
|||||||
limit before the window/report, so this mode has implementation and unit/lint
|
limit before the window/report, so this mode has implementation and unit/lint
|
||||||
evidence only, not a corpus GPU acceptance claim.
|
evidence only, not a corpus GPU acceptance claim.
|
||||||
|
|
||||||
|
The preview now asks `load_mission_static_preview` for assets. Normal mission
|
||||||
|
loading remains full and transactional; the preview scope walks root spans in
|
||||||
|
TMA order and stops asset preparation after the first mesh-backed model. It is
|
||||||
|
therefore not a hidden relaxation of gameplay validation. A second GOG
|
||||||
|
`Autodemo.00` attempt with this narrower asset scope still exceeded 120 seconds
|
||||||
|
before opening a window, which locates the remaining startup cost before the
|
||||||
|
Vulkan draw loop but does not identify it as terrain versus graph work.
|
||||||
|
|
||||||
`Land.msh` использует отдельный geometry-only bridge: validated `TerrainFace28`
|
`Land.msh` использует отдельный geometry-only bridge: validated `TerrainFace28`
|
||||||
сохраняет source triangle order, а его positions и packed UV0 попадают в тот же
|
сохраняет source triangle order, а его positions и packed UV0 попадают в тот же
|
||||||
static vertex/index upload path. Для текущего диагностического viewer XZ bounds
|
static vertex/index upload path. Для текущего диагностического viewer XZ bounds
|
||||||
|
|||||||
Reference in New Issue
Block a user