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 }
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 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 #[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 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 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 #[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 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 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 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 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 self.transfer_queue.wait_for_queue_idle().unwrap();
437 self.graphics_queue.wait_for_queue_idle().unwrap();
438
439 for asset_type in self.asset_registration_order.iter().rev() {
442 self.asset_types.remove(asset_type).unwrap();
443 }
444
445 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}