rafx_assets/assets/
asset_manager.rs

1use crate::assets::ImageAssetData;
2use crate::assets::{BufferAsset, ImageAsset, MaterialAsset};
3use crate::{
4    AssetLookup, AssetTypeHandler, BufferAssetData, MaterialInstanceSlotAssignment,
5    RafxGenericLoadEventHandler,
6};
7use hydrate_base::handle::{ArtifactHandle, Handle, LoadState};
8use rafx_framework::{
9    DescriptorSetAllocatorMetrics, DescriptorSetAllocatorProvider, DescriptorSetAllocatorRef,
10    DescriptorSetLayoutResource, DescriptorSetWriteSet, DynResourceAllocatorSet,
11    GraphicsPipelineCache, MaterialPass, RenderResources, ResourceArc, SlotNameLookup,
12};
13
14use crate::assets::buffer::BufferAssetTypeHandler;
15use crate::assets::compute_pipeline::ComputePipelineAssetTypeHandler;
16use crate::assets::graphics_pipeline::{
17    MaterialAssetTypeHandler, MaterialInstanceAssetTypeHandler, SamplerAssetTypeHandler,
18};
19use crate::assets::image::ImageAssetTypeHandler;
20use crate::assets::shader::ShaderAssetTypeHandler;
21use crate::hydrate_impl::AssetResource;
22use fnv::FnvHashMap;
23use rafx_api::{RafxDeviceContext, RafxQueue, RafxResult};
24use rafx_framework::descriptor_sets::{
25    DescriptorSetElementKey, DescriptorSetWriteElementBuffer, DescriptorSetWriteElementBufferData,
26    DescriptorSetWriteElementImage,
27};
28use rafx_framework::render_features::RenderRegistry;
29use rafx_framework::upload::{UploadQueue, UploadQueueConfig, UploadQueueContext};
30use rafx_framework::DescriptorSetAllocator;
31use rafx_framework::DynCommandPoolAllocator;
32use rafx_framework::DynResourceAllocatorSetProvider;
33use rafx_framework::ResourceLookupSet;
34use rafx_framework::{ResourceManager, ResourceManagerMetrics};
35use std::any::TypeId;
36use std::sync::Arc;
37
38#[derive(Debug)]
39pub struct AssetManagerMetrics {
40    pub resource_manager_metrics: ResourceManagerMetrics,
41    pub material_instance_descriptor_sets_metrics: DescriptorSetAllocatorMetrics,
42    //TODO: Metrics per asset type
43}
44
45pub struct AssetManagerLoaders {
46    pub image_loader: RafxGenericLoadEventHandler<ImageAssetData, ImageAsset>,
47    pub buffer_loader: RafxGenericLoadEventHandler<BufferAssetData, BufferAsset>,
48}
49
50pub struct AssetManager {
51    device_context: RafxDeviceContext,
52    resource_manager: ResourceManager,
53    upload_queue: UploadQueue,
54    material_instance_descriptor_sets: DescriptorSetAllocator,
55    graphics_queue: RafxQueue,
56    transfer_queue: RafxQueue,
57
58    asset_types: FnvHashMap<TypeId, Box<dyn AssetTypeHandler>>,
59    // Extremely rare that we modify asset_registration_order but we need to iterate it while
60    // having a mut reference to asset manager. Better to just reallocate the vec every time we
61    // register an asset type than clone every time we do a frame update.
62    asset_registration_order: Arc<Vec<TypeId>>,
63}
64
65impl AssetManager {
66    pub fn new(
67        device_context: &RafxDeviceContext,
68        render_registry: &RenderRegistry,
69        upload_queue_config: UploadQueueConfig,
70        graphics_queue: &RafxQueue,
71        transfer_queue: &RafxQueue,
72    ) -> RafxResult<Self> {
73        let resource_manager = ResourceManager::new(device_context, render_registry);
74        let upload_queue = UploadQueue::new(
75            device_context,
76            upload_queue_config,
77            graphics_queue.clone(),
78            transfer_queue.clone(),
79        )?;
80
81        Ok(AssetManager {
82            device_context: device_context.clone(),
83            resource_manager,
84            upload_queue,
85            material_instance_descriptor_sets: DescriptorSetAllocator::new(device_context),
86            graphics_queue: graphics_queue.clone(),
87            transfer_queue: transfer_queue.clone(),
88
89            asset_types: Default::default(),
90            asset_registration_order: Default::default(),
91        })
92    }
93
94    pub fn register_asset_type(
95        &mut self,
96        asset_type: Box<dyn AssetTypeHandler>,
97    ) -> RafxResult<()> {
98        let mut asset_registration_order = (*self.asset_registration_order).clone();
99        asset_registration_order.push(asset_type.asset_type_id());
100        self.asset_registration_order = Arc::new(asset_registration_order);
101        let old = self
102            .asset_types
103            .insert(asset_type.asset_type_id(), asset_type);
104        assert!(old.is_none());
105        Ok(())
106    }
107
108    pub fn register_default_asset_types(
109        &mut self,
110        asset_resource: &mut AssetResource,
111        _render_resources: &mut RenderResources,
112    ) -> RafxResult<()> {
113        let asset_type = ShaderAssetTypeHandler::create(self, asset_resource)?;
114        self.register_asset_type(asset_type)?;
115        let asset_type = ComputePipelineAssetTypeHandler::create(self, asset_resource)?;
116        self.register_asset_type(asset_type)?;
117        let asset_type = MaterialAssetTypeHandler::create(self, asset_resource)?;
118        self.register_asset_type(asset_type)?;
119        let asset_type = MaterialInstanceAssetTypeHandler::create(self, asset_resource)?;
120        self.register_asset_type(asset_type)?;
121        let asset_type = SamplerAssetTypeHandler::create(self, asset_resource)?;
122        self.register_asset_type(asset_type)?;
123        let asset_type = ImageAssetTypeHandler::create(self, asset_resource)?;
124        self.register_asset_type(asset_type)?;
125        let asset_type = BufferAssetTypeHandler::create(self, asset_resource)?;
126        self.register_asset_type(asset_type)?;
127        Ok(())
128    }
129
130    pub fn committed_asset<AssetT: 'static>(
131        &self,
132        handle: &Handle<AssetT>,
133    ) -> Option<&AssetT> {
134        let asset_type = self.asset_types.get(&TypeId::of::<AssetT>())?;
135        asset_type
136            .asset_lookup()
137            .downcast_ref::<AssetLookup<AssetT>>()
138            .unwrap()
139            .get_committed(handle.resolved_load_handle())
140    }
141
142    pub fn latest_asset<AssetT: 'static>(
143        &self,
144        handle: &Handle<AssetT>,
145    ) -> Option<&AssetT> {
146        let asset_type = self.asset_types.get(&TypeId::of::<AssetT>())?;
147        asset_type
148            .asset_lookup()
149            .downcast_ref::<AssetLookup<AssetT>>()
150            .unwrap()
151            .get_latest(handle.resolved_load_handle())
152    }
153
154    // The callback passed to this function will be ticked repeatedly while waiting for the load to complete. This
155    // can be used to update external systems that need to be updated in order for the load to complete
156    #[profiling::function]
157    pub fn wait_for_asset_to_load<
158        T,
159        TickFn: FnMut(&mut AssetManager, &mut AssetResource) -> RafxResult<()>,
160    >(
161        &mut self,
162        asset_handle: &Handle<T>,
163        asset_resource: &mut AssetResource,
164        asset_name: &str,
165        mut tick_fn: TickFn,
166    ) -> RafxResult<()> {
167        const PRINT_INTERVAL: std::time::Duration = std::time::Duration::from_millis(1000);
168        let mut last_print_time: Option<rafx_base::Instant> = None;
169
170        fn on_interval<F: Fn()>(
171            interval: std::time::Duration,
172            last_time: &mut Option<rafx_base::Instant>,
173            f: F,
174        ) {
175            let now = rafx_base::Instant::now();
176
177            if last_time.is_none() || now - last_time.unwrap() >= interval {
178                (f)();
179                *last_time = Some(now);
180            }
181        }
182
183        // log::info!(
184        //     "begin blocking wait for asset to resolve {} {:?}",
185        //     asset_name,
186        //     asset_handle
187        // );
188
189        loop {
190            asset_resource.update();
191            self.update_asset_loaders()?;
192            (tick_fn)(self, asset_resource)?;
193
194            match asset_handle.load_state(asset_resource.loader()) {
195                LoadState::Loaded => {
196                    break Ok(());
197                }
198                state @ _ => {
199                    on_interval(PRINT_INTERVAL, &mut last_print_time, || {
200                        let artifact_id = asset_handle.artifact_id(asset_resource.loader());
201                        log::info!(
202                            "blocked waiting for asset to resolve Name={} Handle={:?} ArtifactId={:?} State={:?}",
203                            asset_name,
204                            asset_handle.resolved_load_handle().id,
205                            artifact_id,
206                            state,
207                        );
208                    });
209                }
210            }
211        }
212    }
213
214    pub fn device_context(&self) -> &RafxDeviceContext {
215        &self.device_context
216    }
217
218    pub fn graphics_queue(&self) -> &RafxQueue {
219        &self.graphics_queue
220    }
221
222    pub fn transfer_queue(&self) -> &RafxQueue {
223        &self.transfer_queue
224    }
225
226    pub fn resource_manager(&self) -> &ResourceManager {
227        &self.resource_manager
228    }
229
230    pub fn resource_manager_mut(&mut self) -> &mut ResourceManager {
231        &mut self.resource_manager
232    }
233
234    pub fn resources(&self) -> &ResourceLookupSet {
235        self.resource_manager.resources()
236    }
237
238    pub fn graphics_pipeline_cache(&self) -> &GraphicsPipelineCache {
239        self.resource_manager.graphics_pipeline_cache()
240    }
241
242    pub fn dyn_command_pool_allocator(&self) -> &DynCommandPoolAllocator {
243        self.resource_manager.dyn_command_pool_allocator()
244    }
245
246    pub fn create_dyn_resource_allocator_set(&self) -> DynResourceAllocatorSet {
247        self.resource_manager.create_dyn_resource_allocator_set()
248    }
249
250    pub fn create_dyn_resource_allocator_provider(&self) -> DynResourceAllocatorSetProvider {
251        self.resource_manager
252            .create_dyn_resource_allocator_provider()
253    }
254
255    pub fn create_descriptor_set_allocator(&self) -> DescriptorSetAllocatorRef {
256        self.resource_manager.create_descriptor_set_allocator()
257    }
258
259    pub fn create_descriptor_set_allocator_provider(&self) -> DescriptorSetAllocatorProvider {
260        self.resource_manager
261            .create_descriptor_set_allocator_provider()
262    }
263
264    pub(crate) fn material_instance_descriptor_sets_mut(&mut self) -> &mut DescriptorSetAllocator {
265        &mut self.material_instance_descriptor_sets
266    }
267
268    pub fn upload_queue_context(&self) -> UploadQueueContext {
269        self.upload_queue.upload_queue_context()
270    }
271
272    //
273    // Loaders
274    //
275
276    pub fn get_descriptor_set_layout_for_pass(
277        &self,
278        handle: &Handle<MaterialAsset>,
279        pass_index: usize,
280        layout_index: usize,
281    ) -> Option<ResourceArc<DescriptorSetLayoutResource>> {
282        self.committed_asset(&handle)
283            .and_then(|x| x.passes.get(pass_index))
284            .map(|x| {
285                x.material_pass_resource.get_raw().descriptor_set_layouts[layout_index].clone()
286            })
287    }
288
289    // Call whenever you want to handle assets loading/unloading
290    #[profiling::function]
291    pub fn update_asset_loaders(&mut self) -> RafxResult<()> {
292        for asset_type in &*self.asset_registration_order.clone() {
293            let mut asset_type = self.asset_types.remove(asset_type).unwrap();
294            asset_type.process_load_requests(self)?;
295            self.asset_types
296                .insert(asset_type.asset_type_id(), asset_type);
297        }
298
299        self.upload_queue.update()?;
300
301        Ok(())
302    }
303
304    // Call just before rendering
305    pub fn on_begin_frame(&mut self) -> RafxResult<()> {
306        self.material_instance_descriptor_sets.flush_changes()
307    }
308
309    #[profiling::function]
310    pub fn on_frame_complete(&mut self) -> RafxResult<()> {
311        for (_, asset_type) in &mut self.asset_types {
312            asset_type.on_frame_complete()?;
313        }
314
315        self.resource_manager.on_frame_complete()?;
316        self.material_instance_descriptor_sets.on_frame_complete();
317        Ok(())
318    }
319
320    pub fn metrics(&self) -> AssetManagerMetrics {
321        //let loaded_asset_metrics = self.loaded_assets.metrics();
322        let resource_manager_metrics = self.resource_manager.metrics();
323        let material_instance_descriptor_sets_metrics =
324            self.material_instance_descriptor_sets.metrics();
325
326        AssetManagerMetrics {
327            resource_manager_metrics,
328            //loaded_asset_metrics,
329            material_instance_descriptor_sets_metrics,
330        }
331    }
332
333    #[profiling::function]
334    pub fn apply_material_instance_slot_assignment(
335        &self,
336        slot_assignment: &MaterialInstanceSlotAssignment,
337        pass_slot_name_lookup: &SlotNameLookup,
338        resources: &ResourceLookupSet,
339        material_pass_write_set: &mut Vec<DescriptorSetWriteSet>,
340    ) -> RafxResult<()> {
341        if let Some(slot_locations) = pass_slot_name_lookup.get(&slot_assignment.slot_name) {
342            for location in slot_locations {
343                log::trace!(
344                    "Apply write to location {:?} via slot {}",
345                    location,
346                    slot_assignment.slot_name
347                );
348
349                let layout_descriptor_set_writes =
350                    &mut material_pass_write_set[location.layout_index as usize];
351
352                let write = layout_descriptor_set_writes
353                    .elements
354                    .get_mut(&DescriptorSetElementKey {
355                        dst_binding: location.binding_index,
356                        array_index: slot_assignment.array_index,
357                    })
358                    .unwrap();
359
360                let what_to_bind = rafx_framework::descriptor_sets::what_to_bind(write);
361
362                if what_to_bind.bind_images || what_to_bind.bind_samplers {
363                    let mut write_image = DescriptorSetWriteElementImage {
364                        image_view: None,
365                        sampler: None,
366                    };
367
368                    if what_to_bind.bind_images {
369                        if let Some(image) = &slot_assignment.image {
370                            let loaded_image = self.latest_asset(&image).unwrap();
371                            write_image.image_view =
372                                Some(rafx_framework::descriptor_sets::DescriptorSetWriteElementImageValue::Resource(
373                                    loaded_image.image_view.clone(),
374                                ));
375                        }
376                    }
377
378                    if what_to_bind.bind_samplers {
379                        if let Some(sampler) = &slot_assignment.sampler {
380                            let sampler = resources.get_or_create_sampler(sampler)?;
381                            write_image.sampler = Some(sampler);
382                        }
383                    }
384
385                    write.image_info = write_image;
386                }
387
388                if what_to_bind.bind_buffers {
389                    let mut write_buffer = DescriptorSetWriteElementBuffer { buffer: None };
390
391                    if let Some(buffer_data) = &slot_assignment.buffer_data {
392                        write_buffer.buffer = Some(DescriptorSetWriteElementBufferData::Data(
393                            buffer_data.clone(),
394                        ));
395                    }
396
397                    write.buffer_info = write_buffer;
398                }
399            }
400        }
401
402        Ok(())
403    }
404
405    pub fn create_write_sets_for_material_instance_pass(
406        &self,
407        pass: &MaterialPass,
408        slots: &[MaterialInstanceSlotAssignment],
409        resources: &ResourceLookupSet,
410    ) -> RafxResult<Vec<DescriptorSetWriteSet>> {
411        let mut pass_descriptor_set_writes =
412            pass.create_uninitialized_write_sets_for_material_pass();
413
414        //
415        // Now modify the descriptor set writes to actually point at the things specified by the material
416        //
417        for slot in slots {
418            self.apply_material_instance_slot_assignment(
419                slot,
420                &pass.pass_slot_name_lookup,
421                resources,
422                &mut pass_descriptor_set_writes,
423            )?;
424        }
425
426        Ok(pass_descriptor_set_writes)
427    }
428}
429
430impl Drop for AssetManager {
431    fn drop(&mut self) {
432        log::info!("Cleaning up asset manager");
433        log::trace!("Asset Manager Metrics:\n{:#?}", self.metrics());
434
435        // Wait for queues to be idle before destroying resources
436        self.transfer_queue.wait_for_queue_idle().unwrap();
437        self.graphics_queue.wait_for_queue_idle().unwrap();
438
439        // Clear in reverse order of registration. This way if asset type A holds a reference to
440        // asset type B, A can be removed first, then B.
441        for asset_type in self.asset_registration_order.iter().rev() {
442            self.asset_types.remove(asset_type).unwrap();
443        }
444
445        // Drop all descriptors. These bind to raw resources, so we need to drop them before
446        // dropping resources
447        self.material_instance_descriptor_sets.destroy().unwrap();
448
449        log::info!("Dropping asset manager");
450        log::trace!("Asset Manager Metrics:\n{:#?}", self.metrics());
451    }
452}