[PERF] Async Background Work Lanes for Assets and FS
This commit is contained in:
parent
0adec90f23
commit
b84946a3a0
@ -359,6 +359,16 @@ struct AssetLoadJob {
|
||||
entry: AssetEntry,
|
||||
}
|
||||
|
||||
struct AssetLoadJobResources<'a> {
|
||||
handles: &'a Arc<RwLock<HandleTable>>,
|
||||
target_generations: &'a Arc<RwLock<TargetGenerationTable>>,
|
||||
assets_data: &'a Arc<RwLock<AssetsPayloadSource>>,
|
||||
pipeline_telemetry: &'a Arc<Mutex<AssetPipelineTelemetryState>>,
|
||||
gfx_policy: &'a BankPolicy<GlyphBank>,
|
||||
sound_policy: &'a BankPolicy<SoundBank>,
|
||||
scene_policy: &'a BankPolicy<SceneBank>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct AssetLoadQueueState {
|
||||
pending: VecDeque<AssetLoadJob>,
|
||||
@ -475,17 +485,17 @@ impl AssetLoadWorker {
|
||||
let queue = Arc::new(AssetLoadQueue::default());
|
||||
let worker_queue = Arc::clone(&queue);
|
||||
let join_handle = thread::spawn(move || {
|
||||
let resources = AssetLoadJobResources {
|
||||
handles: &handles,
|
||||
target_generations: &target_generations,
|
||||
assets_data: &assets_data,
|
||||
pipeline_telemetry: &pipeline_telemetry,
|
||||
gfx_policy: &gfx_policy,
|
||||
sound_policy: &sound_policy,
|
||||
scene_policy: &scene_policy,
|
||||
};
|
||||
while let Some(job) = worker_queue.next_job() {
|
||||
AssetManager::process_load_job(
|
||||
job.clone(),
|
||||
&handles,
|
||||
&target_generations,
|
||||
&assets_data,
|
||||
&pipeline_telemetry,
|
||||
&gfx_policy,
|
||||
&sound_policy,
|
||||
&scene_policy,
|
||||
);
|
||||
AssetManager::process_load_job(job.clone(), &resources);
|
||||
worker_queue.complete_active(job.handle_id, job.request_generation);
|
||||
}
|
||||
});
|
||||
@ -942,24 +952,18 @@ impl AssetManager {
|
||||
Ok(handle_id)
|
||||
}
|
||||
|
||||
fn process_load_job(
|
||||
job: AssetLoadJob,
|
||||
handles: &Arc<RwLock<HandleTable>>,
|
||||
target_generations: &Arc<RwLock<TargetGenerationTable>>,
|
||||
assets_data: &Arc<RwLock<AssetsPayloadSource>>,
|
||||
pipeline_telemetry: &Arc<Mutex<AssetPipelineTelemetryState>>,
|
||||
gfx_policy: &BankPolicy<GlyphBank>,
|
||||
sound_policy: &BankPolicy<SoundBank>,
|
||||
scene_policy: &BankPolicy<SceneBank>,
|
||||
) {
|
||||
if !Self::is_current_target_generation(target_generations, job.slot, job.request_generation)
|
||||
{
|
||||
pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
fn process_load_job(job: AssetLoadJob, resources: &AssetLoadJobResources<'_>) {
|
||||
if !Self::is_current_target_generation(
|
||||
resources.target_generations,
|
||||
job.slot,
|
||||
job.request_generation,
|
||||
) {
|
||||
resources.pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
let mut handles_map = handles.write().unwrap();
|
||||
let mut handles_map = resources.handles.write().unwrap();
|
||||
let Some(handle) = handles_map.get_mut(&job.handle_id) else {
|
||||
return;
|
||||
};
|
||||
@ -972,52 +976,53 @@ impl AssetManager {
|
||||
handle.progress = ASSET_PROGRESS_LOADING;
|
||||
}
|
||||
let started_at = Instant::now();
|
||||
pipeline_telemetry.lock().unwrap().record_started(0);
|
||||
resources.pipeline_telemetry.lock().unwrap().record_started(0);
|
||||
|
||||
match job.entry.bank_type {
|
||||
BankType::GLYPH => {
|
||||
let result = Self::perform_load_glyph_bank(&job.entry, Arc::clone(assets_data));
|
||||
let result =
|
||||
Self::perform_load_glyph_bank(&job.entry, Arc::clone(resources.assets_data));
|
||||
match result {
|
||||
Ok(tilebank) => {
|
||||
if !Self::is_current_target_generation(
|
||||
target_generations,
|
||||
resources.target_generations,
|
||||
job.slot,
|
||||
job.request_generation,
|
||||
) {
|
||||
pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
resources.pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
return;
|
||||
}
|
||||
let bank_arc = Arc::new(tilebank);
|
||||
let resident_arc = gfx_policy.put_resident(
|
||||
let resident_arc = resources.gfx_policy.put_resident(
|
||||
job.asset_id,
|
||||
bank_arc,
|
||||
job.entry.decoded_size as usize,
|
||||
);
|
||||
if !Self::is_current_target_generation(
|
||||
target_generations,
|
||||
resources.target_generations,
|
||||
job.slot,
|
||||
job.request_generation,
|
||||
) {
|
||||
pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
resources.pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
return;
|
||||
}
|
||||
gfx_policy.stage(
|
||||
resources.gfx_policy.stage(
|
||||
job.handle_id,
|
||||
resident_arc,
|
||||
job.entry.decoded_size as usize,
|
||||
);
|
||||
Self::complete_load_job(handles, &job, LoadStatus::READY);
|
||||
Self::complete_load_job(resources.handles, &job, LoadStatus::READY);
|
||||
Self::record_load_job_finished(
|
||||
pipeline_telemetry,
|
||||
resources.pipeline_telemetry,
|
||||
&job,
|
||||
started_at,
|
||||
LoadStatus::READY,
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
Self::complete_load_job(handles, &job, LoadStatus::ERROR);
|
||||
Self::complete_load_job(resources.handles, &job, LoadStatus::ERROR);
|
||||
Self::record_load_job_finished(
|
||||
pipeline_telemetry,
|
||||
resources.pipeline_telemetry,
|
||||
&job,
|
||||
started_at,
|
||||
LoadStatus::ERROR,
|
||||
@ -1026,48 +1031,49 @@ impl AssetManager {
|
||||
}
|
||||
}
|
||||
BankType::SOUNDS => {
|
||||
let result = Self::perform_load_sound_bank(&job.entry, Arc::clone(assets_data));
|
||||
let result =
|
||||
Self::perform_load_sound_bank(&job.entry, Arc::clone(resources.assets_data));
|
||||
match result {
|
||||
Ok(soundbank) => {
|
||||
if !Self::is_current_target_generation(
|
||||
target_generations,
|
||||
resources.target_generations,
|
||||
job.slot,
|
||||
job.request_generation,
|
||||
) {
|
||||
pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
resources.pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
return;
|
||||
}
|
||||
let bank_arc = Arc::new(soundbank);
|
||||
let resident_arc = sound_policy.put_resident(
|
||||
let resident_arc = resources.sound_policy.put_resident(
|
||||
job.asset_id,
|
||||
bank_arc,
|
||||
job.entry.decoded_size as usize,
|
||||
);
|
||||
if !Self::is_current_target_generation(
|
||||
target_generations,
|
||||
resources.target_generations,
|
||||
job.slot,
|
||||
job.request_generation,
|
||||
) {
|
||||
pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
resources.pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
return;
|
||||
}
|
||||
sound_policy.stage(
|
||||
resources.sound_policy.stage(
|
||||
job.handle_id,
|
||||
resident_arc,
|
||||
job.entry.decoded_size as usize,
|
||||
);
|
||||
Self::complete_load_job(handles, &job, LoadStatus::READY);
|
||||
Self::complete_load_job(resources.handles, &job, LoadStatus::READY);
|
||||
Self::record_load_job_finished(
|
||||
pipeline_telemetry,
|
||||
resources.pipeline_telemetry,
|
||||
&job,
|
||||
started_at,
|
||||
LoadStatus::READY,
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
Self::complete_load_job(handles, &job, LoadStatus::ERROR);
|
||||
Self::complete_load_job(resources.handles, &job, LoadStatus::ERROR);
|
||||
Self::record_load_job_finished(
|
||||
pipeline_telemetry,
|
||||
resources.pipeline_telemetry,
|
||||
&job,
|
||||
started_at,
|
||||
LoadStatus::ERROR,
|
||||
@ -1076,48 +1082,49 @@ impl AssetManager {
|
||||
}
|
||||
}
|
||||
BankType::SCENE => {
|
||||
let result = Self::perform_load_scene_bank(&job.entry, Arc::clone(assets_data));
|
||||
let result =
|
||||
Self::perform_load_scene_bank(&job.entry, Arc::clone(resources.assets_data));
|
||||
match result {
|
||||
Ok(scenebank) => {
|
||||
if !Self::is_current_target_generation(
|
||||
target_generations,
|
||||
resources.target_generations,
|
||||
job.slot,
|
||||
job.request_generation,
|
||||
) {
|
||||
pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
resources.pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
return;
|
||||
}
|
||||
let bank_arc = Arc::new(scenebank);
|
||||
let resident_arc = scene_policy.put_resident(
|
||||
let resident_arc = resources.scene_policy.put_resident(
|
||||
job.asset_id,
|
||||
bank_arc,
|
||||
job.entry.decoded_size as usize,
|
||||
);
|
||||
if !Self::is_current_target_generation(
|
||||
target_generations,
|
||||
resources.target_generations,
|
||||
job.slot,
|
||||
job.request_generation,
|
||||
) {
|
||||
pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
resources.pipeline_telemetry.lock().unwrap().record_stale_discard();
|
||||
return;
|
||||
}
|
||||
scene_policy.stage(
|
||||
resources.scene_policy.stage(
|
||||
job.handle_id,
|
||||
resident_arc,
|
||||
job.entry.decoded_size as usize,
|
||||
);
|
||||
Self::complete_load_job(handles, &job, LoadStatus::READY);
|
||||
Self::complete_load_job(resources.handles, &job, LoadStatus::READY);
|
||||
Self::record_load_job_finished(
|
||||
pipeline_telemetry,
|
||||
resources.pipeline_telemetry,
|
||||
&job,
|
||||
started_at,
|
||||
LoadStatus::READY,
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
Self::complete_load_job(handles, &job, LoadStatus::ERROR);
|
||||
Self::complete_load_job(resources.handles, &job, LoadStatus::ERROR);
|
||||
Self::record_load_job_finished(
|
||||
pipeline_telemetry,
|
||||
resources.pipeline_telemetry,
|
||||
&job,
|
||||
started_at,
|
||||
LoadStatus::ERROR,
|
||||
|
||||
@ -150,11 +150,11 @@ impl AsyncWorkCancelToken {
|
||||
}
|
||||
|
||||
pub fn cancel(&self) {
|
||||
self.canceled.store(true, Ordering::Release);
|
||||
self.canceled.store(true, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn is_canceled(&self) -> bool {
|
||||
self.canceled.load(Ordering::Acquire)
|
||||
self.canceled.load(Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,11 +277,13 @@ impl AsyncWorkLane {
|
||||
|
||||
pub fn request_cancel(&self, job_id: AsyncWorkJobId) -> bool {
|
||||
let state = self.state.lock().unwrap();
|
||||
if state.active.is_some_and(|active| active.id == job_id) {
|
||||
if let Some(token) = &state.active_cancel_token {
|
||||
token.cancel();
|
||||
return true;
|
||||
}
|
||||
if let Some(token) = state
|
||||
.active
|
||||
.filter(|active| active.id == job_id)
|
||||
.and(state.active_cancel_token.as_ref())
|
||||
{
|
||||
token.cancel();
|
||||
return true;
|
||||
}
|
||||
|
||||
for pending in &state.pending {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user