rafx_framework/resources/
resource_lookup.rs

1use crate::resources::pipeline_cache::GraphicsPipelineRenderTargetMeta;
2use crate::resources::resource_arc::{ResourceId, ResourceWithHash, WeakResourceArc};
3use crate::resources::ResourceArc;
4use crate::ResourceDropSink;
5use crossbeam_channel::{Receiver, Sender};
6use fnv::{FnvHashMap, FnvHasher};
7use rafx_api::RafxTexture;
8use rafx_api::*;
9use serde::{Deserialize, Serialize};
10use std::hash::{Hash, Hasher};
11use std::marker::PhantomData;
12use std::sync::atomic::AtomicU64;
13use std::sync::atomic::Ordering;
14use std::sync::{Arc, Mutex};
15
16// Hash of a GPU resource
17#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
18pub struct ResourceHash(u64);
19
20impl ResourceHash {
21    pub fn from_key<KeyT: Hash>(key: &KeyT) -> ResourceHash {
22        let mut hasher = FnvHasher::default();
23        key.hash(&mut hasher);
24        ResourceHash(hasher.finish())
25    }
26}
27
28impl From<ResourceId> for ResourceHash {
29    fn from(resource_id: ResourceId) -> Self {
30        ResourceHash(resource_id.0)
31    }
32}
33
34impl Into<ResourceId> for ResourceHash {
35    fn into(self) -> ResourceId {
36        ResourceId(self.0)
37    }
38}
39
40//
41// A lookup of resources. They reference count using Arcs internally and send a signal when they
42// drop. This allows the resources to be collected and disposed of
43//
44pub struct ResourceLookupInner<KeyT, ResourceT>
45where
46    KeyT: Eq + Hash + Clone,
47    ResourceT: Clone,
48{
49    resources: FnvHashMap<ResourceHash, WeakResourceArc<ResourceT>>,
50    //TODO: Add support for "cancelling" dropping stuff. This would likely be a ring of hashmaps.
51    // that gets cycled.
52    drop_sink: ResourceDropSink<ResourceT>,
53    drop_tx: Sender<ResourceWithHash<ResourceT>>,
54    drop_rx: Receiver<ResourceWithHash<ResourceT>>,
55    phantom_data: PhantomData<KeyT>,
56    #[cfg(debug_assertions)]
57    keys: FnvHashMap<ResourceHash, KeyT>,
58    #[cfg(debug_assertions)]
59    lock_call_count_previous_frame: u64,
60    #[cfg(debug_assertions)]
61    lock_call_count: u64,
62    create_count_previous_frame: u64,
63    create_count: u64,
64}
65
66//TODO: Don't love using a mutex here. If this becomes a performance bottleneck:
67// - Try making locks more granular (something like dashmap)
68// - Have a read-only hashmap that's checked first and then a read/write map that's checked if the
69//   read-only fails. At a later sync point, copy new data from the read-write into the read. This
70//   could occur during the extract phase. Or could potentially double-buffer the read-only map
71//   and swap them.
72pub struct ResourceLookup<KeyT, ResourceT>
73where
74    KeyT: Eq + Hash + Clone,
75    ResourceT: Clone,
76{
77    inner: Mutex<ResourceLookupInner<KeyT, ResourceT>>,
78}
79
80impl<KeyT, ResourceT> ResourceLookup<KeyT, ResourceT>
81where
82    KeyT: Eq + Hash + Clone,
83    ResourceT: Clone + std::fmt::Debug,
84{
85    pub fn new(max_frames_in_flight: u32) -> Self {
86        let (drop_tx, drop_rx) = crossbeam_channel::unbounded();
87
88        let inner = ResourceLookupInner {
89            resources: Default::default(),
90            drop_sink: ResourceDropSink::new(max_frames_in_flight),
91            drop_tx,
92            drop_rx,
93            phantom_data: Default::default(),
94            #[cfg(debug_assertions)]
95            keys: Default::default(),
96            #[cfg(debug_assertions)]
97            lock_call_count_previous_frame: 0,
98            #[cfg(debug_assertions)]
99            lock_call_count: 0,
100            create_count_previous_frame: 0,
101            create_count: 0,
102        };
103
104        ResourceLookup {
105            inner: Mutex::new(inner),
106        }
107    }
108
109    fn do_get(
110        inner: &mut ResourceLookupInner<KeyT, ResourceT>,
111        hash: ResourceHash,
112        _key: &KeyT,
113    ) -> Option<ResourceArc<ResourceT>> {
114        let resource = inner.resources.get(&hash);
115
116        if let Some(resource) = resource {
117            let upgrade = resource.upgrade();
118            #[cfg(debug_assertions)]
119            if upgrade.is_some() {
120                debug_assert!(inner.keys.get(&hash).unwrap() == _key);
121            }
122
123            upgrade
124        } else {
125            None
126        }
127    }
128
129    fn do_create<F>(
130        inner: &mut ResourceLookupInner<KeyT, ResourceT>,
131        hash: ResourceHash,
132        _key: &KeyT,
133        create_resource_fn: F,
134    ) -> RafxResult<ResourceArc<ResourceT>>
135    where
136        F: FnOnce() -> RafxResult<ResourceT>,
137    {
138        // Process any pending drops. If we don't do this, it's possible that the pending drop could
139        // wipe out the state we're about to set
140        Self::handle_dropped_resources(inner);
141
142        inner.create_count += 1;
143
144        let resource = (create_resource_fn)()?;
145        log::trace!(
146            "insert resource {} {:?}",
147            core::any::type_name::<ResourceT>(),
148            resource
149        );
150
151        let arc = ResourceArc::new(resource, hash.into(), inner.drop_tx.clone());
152        let downgraded = arc.downgrade();
153        let old = inner.resources.insert(hash, downgraded);
154        assert!(old.is_none());
155
156        #[cfg(debug_assertions)]
157        {
158            inner.keys.insert(hash, _key.clone());
159            assert!(old.is_none());
160        }
161
162        Ok(arc)
163    }
164
165    #[allow(dead_code)]
166    pub fn get(
167        &self,
168        key: &KeyT,
169    ) -> Option<ResourceArc<ResourceT>> {
170        let hash = ResourceHash::from_key(key);
171        let mut guard = self.inner.lock().unwrap();
172        #[cfg(debug_assertions)]
173        {
174            guard.lock_call_count += 1;
175        }
176
177        Self::do_get(&mut *guard, hash, key)
178    }
179
180    pub fn create<F>(
181        &self,
182        key: &KeyT,
183        create_resource_fn: F,
184    ) -> RafxResult<ResourceArc<ResourceT>>
185    where
186        F: FnOnce() -> RafxResult<ResourceT>,
187    {
188        let hash = ResourceHash::from_key(key);
189        let mut guard = self.inner.lock().unwrap();
190        #[cfg(debug_assertions)]
191        {
192            guard.lock_call_count += 1;
193        }
194
195        Self::do_create(&mut *guard, hash, key, create_resource_fn)
196    }
197
198    pub fn get_or_create<F>(
199        &self,
200        key: &KeyT,
201        create_resource_fn: F,
202    ) -> RafxResult<ResourceArc<ResourceT>>
203    where
204        F: FnOnce() -> RafxResult<ResourceT>,
205    {
206        let hash = ResourceHash::from_key(key);
207
208        let mut guard = self.inner.lock().unwrap();
209        #[cfg(debug_assertions)]
210        {
211            guard.lock_call_count += 1;
212        }
213
214        if let Some(resource) = Self::do_get(&mut *guard, hash, key) {
215            //println!("get {} {:?}", core::any::type_name::<ResourceT>(), hash);
216            Ok(resource)
217        } else {
218            //println!("create {} {:?}", core::any::type_name::<ResourceT>(), hash);
219            Self::do_create(&mut *guard, hash, key, create_resource_fn)
220        }
221    }
222
223    fn handle_dropped_resources(inner: &mut ResourceLookupInner<KeyT, ResourceT>) {
224        for dropped in inner.drop_rx.try_iter() {
225            log::trace!(
226                "queue for delete {} {:?}",
227                core::any::type_name::<ResourceT>(),
228                dropped.resource_hash
229            );
230            inner.drop_sink.retire(dropped.resource);
231            inner.resources.remove(&dropped.resource_hash.into());
232
233            #[cfg(debug_assertions)]
234            {
235                inner.keys.remove(&dropped.resource_hash.into());
236            }
237        }
238    }
239
240    fn on_frame_complete(&self) -> RafxResult<()> {
241        let mut guard = self.inner.lock().unwrap();
242        #[cfg(debug_assertions)]
243        {
244            guard.lock_call_count_previous_frame = guard.lock_call_count + 1;
245            guard.lock_call_count = 0;
246        }
247
248        guard.create_count_previous_frame = guard.create_count;
249        guard.create_count = 0;
250
251        Self::handle_dropped_resources(&mut guard);
252        guard.drop_sink.on_frame_complete()?;
253        Ok(())
254    }
255
256    fn metrics(&self) -> ResourceLookupMetric {
257        let guard = self.inner.lock().unwrap();
258        ResourceLookupMetric {
259            count: guard.resources.len(),
260            previous_frame_create_count: guard.create_count_previous_frame,
261            #[cfg(debug_assertions)]
262            previous_frame_lock_call_count: guard.lock_call_count_previous_frame,
263        }
264    }
265
266    fn destroy(&self) -> RafxResult<()> {
267        let mut guard = self.inner.lock().unwrap();
268        #[cfg(debug_assertions)]
269        {
270            guard.lock_call_count += 1;
271        }
272
273        Self::handle_dropped_resources(&mut guard);
274
275        if !guard.resources.is_empty() {
276            log::warn!(
277                "{} resource count {} > 0, resources will leak",
278                core::any::type_name::<ResourceT>(),
279                guard.resources.len()
280            );
281        }
282
283        guard.drop_sink.destroy()?;
284        Ok(())
285    }
286}
287
288//
289// Keys for each resource type. (Some keys are simple and use types from crate::pipeline_description
290// and some are a combination of the definitions and runtime state. (For example, combining a
291// renderpass with the swapchain surface it would be applied to)
292//
293
294#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
295pub struct FixedFunctionState {
296    pub blend_state: RafxBlendState,
297    pub depth_state: RafxDepthState,
298    pub rasterizer_state: RafxRasterizerState,
299}
300
301#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
302pub struct ShaderHash(u64);
303impl ShaderHash {
304    pub fn new(
305        entry_points: &[&RafxReflectedEntryPoint],
306        shader_module_hashes: &[RafxShaderPackageHash],
307    ) -> Self {
308        let reflection_data: Vec<_> = entry_points
309            .iter()
310            .map(|x| &x.rafx_api_reflection)
311            .collect();
312        let mut hasher = FnvHasher::default();
313        RafxShaderStageDef::hash_definition(&mut hasher, &reflection_data, shader_module_hashes);
314        let hash = hasher.finish();
315        ShaderHash(hash)
316    }
317}
318
319#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
320pub struct SamplerHash(u64);
321impl SamplerHash {
322    pub fn new(sampler_def: &RafxSamplerDef) -> Self {
323        let mut hasher = FnvHasher::default();
324        sampler_def.hash(&mut hasher);
325        let hash = hasher.finish();
326        SamplerHash(hash)
327    }
328}
329
330#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
331pub struct RootSignatureHash(u64);
332impl RootSignatureHash {
333    pub fn new(
334        shader_hashes: &[ShaderHash],
335        immutable_sampler_keys: &[RafxImmutableSamplerKey],
336        immutable_sampler_hashes: &[Vec<SamplerHash>],
337    ) -> Self {
338        let mut hasher = FnvHasher::default();
339        RafxRootSignatureDef::hash_definition(
340            &mut hasher,
341            shader_hashes,
342            immutable_sampler_keys,
343            immutable_sampler_hashes,
344        );
345        let hash = hasher.finish();
346        RootSignatureHash(hash)
347    }
348}
349
350#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
351pub struct DescriptorSetLayoutHash(u64);
352impl DescriptorSetLayoutHash {
353    pub fn new(
354        root_signature_hash: RootSignatureHash,
355        set_index: u32,
356        bindings: &RafxReflectedDescriptorSetLayout,
357    ) -> Self {
358        let mut hasher = FnvHasher::default();
359        root_signature_hash.hash(&mut hasher);
360        set_index.hash(&mut hasher);
361        bindings.hash(&mut hasher);
362        let hash = hasher.finish();
363        DescriptorSetLayoutHash(hash)
364    }
365}
366
367#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
368pub struct MaterialPassHash(u64);
369impl MaterialPassHash {
370    pub fn new(
371        shader_hash: ShaderHash,
372        root_signature_hash: RootSignatureHash,
373        descriptor_set_layout_hashes: &[DescriptorSetLayoutHash],
374        fixed_function_state: &FixedFunctionState,
375        vertex_inputs: &[MaterialPassVertexInput],
376    ) -> Self {
377        let mut hasher = FnvHasher::default();
378        shader_hash.hash(&mut hasher);
379        root_signature_hash.hash(&mut hasher);
380        descriptor_set_layout_hashes.hash(&mut hasher);
381        fixed_function_state.hash(&mut hasher);
382        for vertex_input in vertex_inputs {
383            vertex_input.hash(&mut hasher);
384        }
385        let hash = hasher.finish();
386        MaterialPassHash(hash)
387    }
388}
389
390#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
391pub struct GraphicsPipelineHash(u64);
392impl GraphicsPipelineHash {
393    pub fn new(
394        material_pass_key: MaterialPassHash,
395        render_target_meta: &GraphicsPipelineRenderTargetMeta,
396        primitive_topology: RafxPrimitiveTopology,
397        vertex_layout: &RafxVertexLayout,
398    ) -> Self {
399        let mut hasher = FnvHasher::default();
400        material_pass_key.hash(&mut hasher);
401        render_target_meta
402            .render_target_meta_hash()
403            .hash(&mut hasher);
404        primitive_topology.hash(&mut hasher);
405        vertex_layout.hash(&mut hasher);
406        let hash = hasher.finish();
407        GraphicsPipelineHash(hash)
408    }
409}
410
411#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
412pub struct ComputePipelineHash(u64);
413impl ComputePipelineHash {
414    pub fn new(
415        shader_hash: ShaderHash,
416        root_signature_hash: RootSignatureHash,
417        descriptor_set_layout_hashes: &[DescriptorSetLayoutHash],
418    ) -> Self {
419        let mut hasher = FnvHasher::default();
420        shader_hash.hash(&mut hasher);
421        root_signature_hash.hash(&mut hasher);
422        descriptor_set_layout_hashes.hash(&mut hasher);
423        let hash = hasher.finish();
424        ComputePipelineHash(hash)
425    }
426}
427
428#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
429pub struct ShaderModuleKey {
430    hash: RafxShaderPackageHash,
431}
432
433#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
434pub struct ShaderKey {
435    hash: ShaderHash,
436}
437
438#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
439pub struct RootSignatureKey {
440    // hash is based on shader code hash, stage, and entry point
441    hash: RootSignatureHash,
442}
443
444#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
445pub struct DescriptorSetLayoutKey {
446    hash: DescriptorSetLayoutHash,
447}
448
449#[derive(Debug, Clone, PartialEq, Eq, Hash)]
450pub struct MaterialPassVertexInput {
451    pub semantic: String,
452    pub location: u32,
453    pub gl_attribute_name: String,
454}
455
456#[derive(Debug, Clone, PartialEq, Eq, Hash)]
457pub struct MaterialPassKey {
458    hash: MaterialPassHash,
459}
460
461#[derive(Debug, Clone, PartialEq, Eq, Hash)]
462pub struct GraphicsPipelineKey {
463    hash: GraphicsPipelineHash,
464}
465
466#[derive(Debug, Clone, PartialEq, Eq, Hash)]
467pub struct ComputePipelineKey {
468    hash: ComputePipelineHash,
469}
470
471#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
472pub struct ImageKey {
473    id: u64,
474}
475
476#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
477pub struct BufferKey {
478    id: u64,
479}
480
481#[derive(Debug, Clone, PartialEq, Eq, Hash)]
482pub struct SamplerKey {
483    hash: SamplerHash,
484}
485
486#[derive(Debug, Clone, PartialEq, Eq, Hash)]
487pub struct ImageViewKey {
488    image_key: ImageKey,
489    texture_bind_type: Option<RafxTextureBindType>,
490}
491
492#[derive(Debug)]
493pub struct ResourceLookupMetric {
494    pub count: usize,
495    pub previous_frame_create_count: u64,
496    #[cfg(debug_assertions)]
497    pub previous_frame_lock_call_count: u64,
498}
499
500#[derive(Debug)]
501pub struct ResourceMetrics {
502    pub shader_module_metrics: ResourceLookupMetric,
503    pub shader_metrics: ResourceLookupMetric,
504    pub root_signature_metrics: ResourceLookupMetric,
505    pub descriptor_set_layout_metrics: ResourceLookupMetric,
506    pub material_pass_metrics: ResourceLookupMetric,
507    pub graphics_pipeline_metrics: ResourceLookupMetric,
508    pub compute_pipeline_metrics: ResourceLookupMetric,
509    pub image_metrics: ResourceLookupMetric,
510    pub image_view_metrics: ResourceLookupMetric,
511    pub sampler_metrics: ResourceLookupMetric,
512    pub buffer_metrics: ResourceLookupMetric,
513}
514
515#[derive(Debug, Clone)]
516pub struct ShaderModuleResource {
517    pub shader_module_key: ShaderModuleKey,
518    pub shader_package: Arc<RafxShaderPackage>,
519    pub shader_module: RafxShaderModule,
520}
521
522#[derive(Debug, Clone)]
523pub struct ShaderResource {
524    pub key: ShaderKey,
525    pub shader_modules: Vec<ResourceArc<ShaderModuleResource>>,
526    pub shader: RafxShader,
527}
528
529#[derive(Debug, Clone)]
530pub struct RootSignatureResource {
531    pub key: RootSignatureKey,
532    pub shaders: Vec<ResourceArc<ShaderResource>>,
533    pub immutable_samplers: Vec<ResourceArc<SamplerResource>>,
534    pub root_signature: RafxRootSignature,
535}
536
537#[derive(Debug, Clone)]
538pub struct DescriptorSetLayoutResource {
539    // Just keep it in scope
540    pub root_signature_arc: ResourceArc<RootSignatureResource>,
541    pub root_signature: RafxRootSignature,
542    pub set_index: u32,
543
544    pub descriptor_set_layout_def: Arc<RafxReflectedDescriptorSetLayout>,
545    pub key: DescriptorSetLayoutKey,
546}
547
548#[derive(Debug, Clone)]
549pub struct MaterialPassResource {
550    pub material_pass_key: MaterialPassKey,
551    pub shader: ResourceArc<ShaderResource>,
552    pub root_signature: ResourceArc<RootSignatureResource>,
553    pub descriptor_set_layouts: Arc<Vec<ResourceArc<DescriptorSetLayoutResource>>>,
554    pub fixed_function_state: Arc<FixedFunctionState>,
555    pub vertex_inputs: Arc<Vec<MaterialPassVertexInput>>,
556    pub debug_name: Option<String>,
557}
558
559#[derive(Debug, Clone)]
560pub struct GraphicsPipelineResource {
561    pub render_target_meta: GraphicsPipelineRenderTargetMeta,
562    pub pipeline: Arc<RafxPipeline>,
563    pub descriptor_set_layouts: Arc<Vec<ResourceArc<DescriptorSetLayoutResource>>>,
564}
565
566#[derive(Debug, Clone)]
567pub struct ComputePipelineResource {
568    pub root_signature: ResourceArc<RootSignatureResource>,
569    pub pipeline: Arc<RafxPipeline>,
570    pub descriptor_set_layouts: Arc<Vec<ResourceArc<DescriptorSetLayoutResource>>>,
571}
572
573#[derive(Debug, Clone)]
574pub struct ImageResource {
575    pub image: RafxTexture,
576    // Dynamic resources have no key
577    pub image_key: Option<ImageKey>,
578}
579
580#[derive(Debug, Clone)]
581pub struct ImageViewResource {
582    pub image: ResourceArc<ImageResource>,
583    // Dynamic resources have no key
584    pub image_view_key: Option<ImageViewKey>,
585    pub texture_bind_type: Option<RafxTextureBindType>,
586}
587
588#[derive(Debug, Clone)]
589pub struct SamplerResource {
590    pub sampler: RafxSampler,
591    pub sampler_key: SamplerKey,
592}
593
594#[derive(Debug, Clone)]
595pub struct BufferResource {
596    pub buffer: Arc<RafxBuffer>,
597    // Dynamic resources have no key
598    pub buffer_key: Option<BufferKey>,
599}
600
601//
602// Handles raw lookup and destruction of GPU resources. Everything is reference counted. No safety
603// is provided for dependencies/order of destruction. The general expectation is that anything
604// dropped can safely be destroyed after a few frames have passed (based on max number of frames
605// that can be submitted to the GPU)
606//
607//TODO: Some of the resources like buffers and images don't need to be "keyed" and could probably
608// be kept in a slab. We *do* need a way to access and quickly remove elements though, and whatever
609// key we use is sent through a Sender/Receiver pair to be dropped later.
610pub struct ResourceLookupSetInner {
611    device_context: RafxDeviceContext,
612
613    shader_modules: ResourceLookup<ShaderModuleKey, ShaderModuleResource>,
614    shaders: ResourceLookup<ShaderKey, ShaderResource>,
615    root_signatures: ResourceLookup<RootSignatureKey, RootSignatureResource>,
616    descriptor_set_layouts: ResourceLookup<DescriptorSetLayoutKey, DescriptorSetLayoutResource>,
617    material_passes: ResourceLookup<MaterialPassKey, MaterialPassResource>,
618    graphics_pipelines: ResourceLookup<GraphicsPipelineKey, GraphicsPipelineResource>,
619    compute_pipelines: ResourceLookup<ComputePipelineKey, ComputePipelineResource>,
620    images: ResourceLookup<ImageKey, ImageResource>,
621    image_views: ResourceLookup<ImageViewKey, ImageViewResource>,
622    samplers: ResourceLookup<SamplerKey, SamplerResource>,
623    buffers: ResourceLookup<BufferKey, BufferResource>,
624
625    // Used to generate keys for images/buffers
626    next_image_id: AtomicU64,
627    next_buffer_id: AtomicU64,
628}
629
630#[derive(Clone)]
631pub struct ResourceLookupSet {
632    inner: Arc<ResourceLookupSetInner>,
633}
634
635impl ResourceLookupSet {
636    pub fn new(
637        device_context: &RafxDeviceContext,
638        max_frames_in_flight: u32,
639    ) -> Self {
640        let set = ResourceLookupSetInner {
641            device_context: device_context.clone(),
642            shader_modules: ResourceLookup::new(max_frames_in_flight),
643            shaders: ResourceLookup::new(max_frames_in_flight),
644            root_signatures: ResourceLookup::new(max_frames_in_flight),
645            descriptor_set_layouts: ResourceLookup::new(max_frames_in_flight),
646            material_passes: ResourceLookup::new(max_frames_in_flight),
647            graphics_pipelines: ResourceLookup::new(max_frames_in_flight),
648            compute_pipelines: ResourceLookup::new(max_frames_in_flight),
649            images: ResourceLookup::new(max_frames_in_flight),
650            image_views: ResourceLookup::new(max_frames_in_flight),
651            samplers: ResourceLookup::new(max_frames_in_flight),
652            buffers: ResourceLookup::new(max_frames_in_flight),
653            next_image_id: AtomicU64::new(0),
654            next_buffer_id: AtomicU64::new(0),
655        };
656
657        ResourceLookupSet {
658            inner: Arc::new(set),
659        }
660    }
661
662    pub fn device_context(&self) -> &RafxDeviceContext {
663        &self.inner.device_context
664    }
665
666    #[profiling::function]
667    pub fn on_frame_complete(&self) -> RafxResult<()> {
668        self.inner.images.on_frame_complete()?;
669        self.inner.image_views.on_frame_complete()?;
670        self.inner.buffers.on_frame_complete()?;
671        self.inner.shader_modules.on_frame_complete()?;
672        self.inner.shaders.on_frame_complete()?;
673        self.inner.samplers.on_frame_complete()?;
674        self.inner.root_signatures.on_frame_complete()?;
675        self.inner.descriptor_set_layouts.on_frame_complete()?;
676        self.inner.material_passes.on_frame_complete()?;
677        self.inner.graphics_pipelines.on_frame_complete()?;
678        self.inner.compute_pipelines.on_frame_complete()?;
679        Ok(())
680    }
681
682    // This assumes that no GPU work remains that relies on these resources. Use
683    // RafxQueue::wait_for_queue_idle
684    pub fn destroy(&self) -> RafxResult<()> {
685        //WARNING: These need to be in order of dependencies to avoid frame-delays on destroying
686        // resources.
687        self.inner.compute_pipelines.destroy()?;
688        self.inner.graphics_pipelines.destroy()?;
689        self.inner.material_passes.destroy()?;
690        self.inner.descriptor_set_layouts.destroy()?;
691        self.inner.root_signatures.destroy()?;
692        self.inner.samplers.destroy()?;
693        self.inner.shaders.destroy()?;
694        self.inner.shader_modules.destroy()?;
695        self.inner.buffers.destroy()?;
696        self.inner.image_views.destroy()?;
697        self.inner.images.destroy()?;
698        Ok(())
699    }
700
701    pub fn metrics(&self) -> ResourceMetrics {
702        ResourceMetrics {
703            shader_module_metrics: self.inner.shader_modules.metrics(),
704            shader_metrics: self.inner.shaders.metrics(),
705            root_signature_metrics: self.inner.root_signatures.metrics(),
706            descriptor_set_layout_metrics: self.inner.descriptor_set_layouts.metrics(),
707            material_pass_metrics: self.inner.material_passes.metrics(),
708            graphics_pipeline_metrics: self.inner.graphics_pipelines.metrics(),
709            compute_pipeline_metrics: self.inner.compute_pipelines.metrics(),
710            image_metrics: self.inner.images.metrics(),
711            image_view_metrics: self.inner.image_views.metrics(),
712            sampler_metrics: self.inner.samplers.metrics(),
713            buffer_metrics: self.inner.buffers.metrics(),
714        }
715    }
716
717    pub fn get_or_create_shader_module_from_hashed_package(
718        &self,
719        package: &RafxHashedShaderPackage,
720    ) -> RafxResult<ResourceArc<ShaderModuleResource>> {
721        self.get_or_create_shader_module(
722            package.shader_package(),
723            Some(package.shader_package_hash()),
724        )
725    }
726
727    pub fn get_or_create_shader_module(
728        &self,
729        shader_package: &RafxShaderPackage,
730        shader_package_hash: Option<RafxShaderPackageHash>,
731    ) -> RafxResult<ResourceArc<ShaderModuleResource>> {
732        let shader_package_hash =
733            shader_package_hash.unwrap_or_else(|| RafxShaderPackageHash::new(shader_package));
734
735        let shader_module_key = ShaderModuleKey {
736            hash: shader_package_hash,
737        };
738
739        self.inner
740            .shader_modules
741            .get_or_create(&shader_module_key, || {
742                log::trace!(
743                    "Creating shader module\n[hash: {:?}]",
744                    shader_module_key.hash,
745                );
746
747                let shader_module = self
748                    .inner
749                    .device_context
750                    .create_shader_module(shader_package.module_def())?;
751
752                let resource = ShaderModuleResource {
753                    shader_module,
754                    shader_package: Arc::new(shader_package.clone()),
755                    shader_module_key: shader_module_key.clone(),
756                };
757                log::trace!("Created shader module {:?}", resource);
758                Ok(resource)
759            })
760    }
761
762    pub fn get_or_create_sampler(
763        &self,
764        sampler_def: &RafxSamplerDef,
765    ) -> RafxResult<ResourceArc<SamplerResource>> {
766        let hash = SamplerHash::new(sampler_def);
767        let sampler_key = SamplerKey { hash };
768
769        self.inner.samplers.get_or_create(&sampler_key, || {
770            log::trace!("Creating sampler\n{:#?}", sampler_def);
771
772            let sampler = self.inner.device_context.create_sampler(sampler_def)?;
773
774            let resource = SamplerResource {
775                sampler,
776                sampler_key: sampler_key.clone(),
777            };
778
779            log::trace!("Created sampler {:?}", resource);
780            Ok(resource)
781        })
782    }
783
784    pub fn get_or_create_shader(
785        &self,
786        shader_modules: &[ResourceArc<ShaderModuleResource>],
787        entry_points: &[&RafxReflectedEntryPoint],
788    ) -> RafxResult<ResourceArc<ShaderResource>> {
789        let shader_module_hashes: Vec<_> = shader_modules
790            .iter()
791            .map(|x| x.get_raw().shader_module_key.hash)
792            .collect();
793
794        let hash = ShaderHash::new(entry_points, &shader_module_hashes);
795        let key = ShaderKey { hash };
796
797        self.inner.shaders.get_or_create(&key, || {
798            log::trace!("Creating shader\n");
799
800            let mut shader_defs = Vec::with_capacity(entry_points.len());
801            for (entry_point, module) in entry_points.iter().zip(shader_modules) {
802                shader_defs.push(RafxShaderStageDef {
803                    shader_module: module.get_raw().shader_module.clone(),
804                    reflection: entry_point.rafx_api_reflection.clone(),
805                });
806            }
807
808            let shader = self.inner.device_context.create_shader(shader_defs)?;
809
810            let resource = ShaderResource {
811                key,
812                shader,
813                shader_modules: shader_modules.iter().cloned().collect(),
814            };
815
816            log::trace!("Created shader {:?}", resource);
817            Ok(resource)
818        })
819    }
820
821    pub fn get_or_create_root_signature(
822        &self,
823        shader_resources: &[ResourceArc<ShaderResource>],
824        immutable_sampler_keys: &[RafxImmutableSamplerKey],
825        immutable_sampler_resources: &[Vec<ResourceArc<SamplerResource>>],
826    ) -> RafxResult<ResourceArc<RootSignatureResource>> {
827        let shader_hashes: Vec<_> = shader_resources
828            .iter()
829            .map(|x| x.get_raw().key.hash)
830            .collect();
831
832        let mut sampler_hashes = Vec::with_capacity(immutable_sampler_resources.len());
833        for sampler_list in immutable_sampler_resources {
834            let hashes: Vec<_> = sampler_list
835                .iter()
836                .map(|x| x.get_raw().sampler_key.hash)
837                .collect();
838            sampler_hashes.push(hashes);
839        }
840
841        let hash = RootSignatureHash::new(&shader_hashes, immutable_sampler_keys, &sampler_hashes);
842        let key = RootSignatureKey { hash };
843
844        self.inner.root_signatures.get_or_create(&key, || {
845            let mut samplers = Vec::with_capacity(immutable_sampler_resources.len());
846            for sampler_list in immutable_sampler_resources {
847                let cloned_sampler_list: Vec<_> = sampler_list
848                    .iter()
849                    .map(|x| x.get_raw().sampler.clone())
850                    .collect();
851                samplers.push(cloned_sampler_list);
852            }
853
854            let mut immutable_samplers = Vec::with_capacity(samplers.len());
855            for i in 0..samplers.len() {
856                immutable_samplers.push(RafxImmutableSamplers {
857                    key: immutable_sampler_keys[i].clone(),
858                    samplers: &samplers[i],
859                });
860            }
861
862            log::trace!("Creating root signature\n{:#?}", key);
863            let shaders: Vec<_> = shader_resources
864                .iter()
865                .map(|x| x.get_raw().shader.clone())
866                .collect();
867            let root_signature =
868                self.inner
869                    .device_context
870                    .create_root_signature(&RafxRootSignatureDef {
871                        shaders: &shaders,
872                        immutable_samplers: &immutable_samplers,
873                    })?;
874
875            let shaders = shader_resources.iter().cloned().collect();
876
877            let mut immutable_samplers = vec![];
878            for resource_list in immutable_sampler_resources {
879                for resource in resource_list {
880                    immutable_samplers.push(resource.clone());
881                }
882            }
883
884            let resource = RootSignatureResource {
885                key,
886                root_signature,
887                shaders,
888                immutable_samplers,
889            };
890
891            log::trace!("Created root signature");
892            Ok(resource)
893        })
894    }
895
896    pub fn get_or_create_descriptor_set_layout(
897        &self,
898        root_signature: &ResourceArc<RootSignatureResource>,
899        set_index: u32,
900        descriptor_set_layout_def: &RafxReflectedDescriptorSetLayout,
901    ) -> RafxResult<ResourceArc<DescriptorSetLayoutResource>> {
902        let hash = DescriptorSetLayoutHash::new(
903            root_signature.get_raw().key.hash,
904            set_index,
905            descriptor_set_layout_def,
906        );
907        let key = DescriptorSetLayoutKey { hash };
908
909        self.inner.descriptor_set_layouts.get_or_create(&key, || {
910            log::trace!(
911                "Creating descriptor set layout set_index={}, root_signature:\n{:#?}",
912                set_index,
913                root_signature
914            );
915
916            // Create the resource object, which contains the descriptor set layout we created plus
917            // ResourceArcs to the samplers, which must remain alive for the lifetime of the descriptor set
918            let resource = DescriptorSetLayoutResource {
919                root_signature_arc: root_signature.clone(),
920                root_signature: root_signature.get_raw().root_signature.clone(),
921                set_index,
922                descriptor_set_layout_def: Arc::new(descriptor_set_layout_def.clone()),
923                key: key.clone(),
924            };
925
926            log::trace!("Created descriptor set layout {:?}", resource);
927            Ok(resource)
928        })
929    }
930
931    pub fn get_or_create_material_pass(
932        &self,
933        shader: ResourceArc<ShaderResource>,
934        root_signature: ResourceArc<RootSignatureResource>,
935        descriptor_sets: Vec<ResourceArc<DescriptorSetLayoutResource>>,
936        fixed_function_state: Arc<FixedFunctionState>,
937        vertex_inputs: Arc<Vec<MaterialPassVertexInput>>,
938        debug_name: Option<&str>,
939    ) -> RafxResult<ResourceArc<MaterialPassResource>> {
940        let descriptor_set_hashes: Vec<_> = descriptor_sets
941            .iter()
942            .map(|x| x.get_raw().key.hash)
943            .collect();
944        let hash = MaterialPassHash::new(
945            shader.get_raw().key.hash,
946            root_signature.get_raw().key.hash,
947            &descriptor_set_hashes,
948            &*fixed_function_state,
949            &*vertex_inputs,
950        );
951        let material_pass_key = MaterialPassKey { hash };
952
953        self.inner
954            .material_passes
955            .get_or_create(&material_pass_key, || {
956                log::trace!("Creating material pass\n{:#?}", material_pass_key);
957                let debug_name = debug_name.map(|x| format!("MaterialPass {}", x));
958                let resource = MaterialPassResource {
959                    material_pass_key: material_pass_key.clone(),
960                    root_signature,
961                    descriptor_set_layouts: Arc::new(descriptor_sets),
962                    shader,
963                    fixed_function_state,
964                    vertex_inputs,
965                    debug_name,
966                };
967                Ok(resource)
968            })
969    }
970
971    pub fn get_or_create_graphics_pipeline(
972        &self,
973        material_pass: &ResourceArc<MaterialPassResource>,
974        render_target_meta: &GraphicsPipelineRenderTargetMeta,
975        primitive_topology: RafxPrimitiveTopology,
976        vertex_layout: &RafxVertexLayout,
977    ) -> RafxResult<ResourceArc<GraphicsPipelineResource>> {
978        let hash = GraphicsPipelineHash::new(
979            material_pass.get_raw().material_pass_key.hash,
980            render_target_meta,
981            primitive_topology,
982            vertex_layout,
983        );
984
985        let pipeline_key = GraphicsPipelineKey { hash };
986
987        self.inner
988            .graphics_pipelines
989            .get_or_create(&pipeline_key, || {
990                log::trace!("Creating graphics pipeline\n{:#?}", pipeline_key);
991                let debug_name = material_pass
992                    .get_raw()
993                    .debug_name
994                    .as_ref()
995                    .map(|x| format!("RafxGraphicsPipeline {}", x));
996
997                let fixed_function_state = &material_pass.get_raw().fixed_function_state;
998                let pipeline = self.inner.device_context.create_graphics_pipeline(
999                    &RafxGraphicsPipelineDef {
1000                        root_signature: &material_pass
1001                            .get_raw()
1002                            .root_signature
1003                            .get_raw()
1004                            .root_signature,
1005
1006                        shader: &material_pass.get_raw().shader.get_raw().shader,
1007
1008                        blend_state: &fixed_function_state.blend_state,
1009                        depth_state: &fixed_function_state.depth_state,
1010                        rasterizer_state: &fixed_function_state.rasterizer_state,
1011
1012                        primitive_topology,
1013                        vertex_layout: &vertex_layout,
1014
1015                        color_formats: &render_target_meta.color_formats(),
1016                        depth_stencil_format: render_target_meta.depth_stencil_format(),
1017                        sample_count: render_target_meta.sample_count(),
1018                        debug_name: debug_name.as_deref(),
1019                    },
1020                )?;
1021
1022                let resource = GraphicsPipelineResource {
1023                    render_target_meta: render_target_meta.clone(),
1024                    pipeline: Arc::new(pipeline),
1025                    descriptor_set_layouts: material_pass.get_raw().descriptor_set_layouts.clone(),
1026                };
1027                Ok(resource)
1028            })
1029    }
1030
1031    pub fn get_or_create_compute_pipeline(
1032        &self,
1033        shader: &ResourceArc<ShaderResource>,
1034        root_signature: &ResourceArc<RootSignatureResource>,
1035        descriptor_set_layouts: Vec<ResourceArc<DescriptorSetLayoutResource>>,
1036        debug_name: Option<&str>,
1037    ) -> RafxResult<ResourceArc<ComputePipelineResource>> {
1038        let descriptor_set_hashes: Vec<_> = descriptor_set_layouts
1039            .iter()
1040            .map(|x| x.get_raw().key.hash)
1041            .collect();
1042        let hash = ComputePipelineHash::new(
1043            shader.get_raw().key.hash,
1044            root_signature.get_raw().key.hash,
1045            &descriptor_set_hashes,
1046        );
1047        let pipeline_key = ComputePipelineKey { hash };
1048
1049        self.inner
1050            .compute_pipelines
1051            .get_or_create(&pipeline_key, || {
1052                log::trace!("Creating compute pipeline\n{:#?}", pipeline_key);
1053                let debug_name = debug_name.map(|x| format!("RafxComputePipeline {}", x));
1054                let rafx_pipeline =
1055                    self.inner
1056                        .device_context
1057                        .create_compute_pipeline(&RafxComputePipelineDef {
1058                            root_signature: &root_signature.get_raw().root_signature,
1059                            shader: &shader.get_raw().shader,
1060                            debug_name: debug_name.as_deref(),
1061                        })?;
1062                log::trace!("Created compute pipeline {:?}", rafx_pipeline);
1063
1064                let resource = ComputePipelineResource {
1065                    root_signature: root_signature.clone(),
1066                    pipeline: Arc::new(rafx_pipeline),
1067                    descriptor_set_layouts: Arc::new(descriptor_set_layouts),
1068                };
1069                Ok(resource)
1070            })
1071    }
1072
1073    pub fn insert_image(
1074        &self,
1075        image: RafxTexture,
1076    ) -> ResourceArc<ImageResource> {
1077        let image_id = self.inner.next_image_id.fetch_add(1, Ordering::Relaxed);
1078
1079        let image_key = ImageKey { id: image_id };
1080
1081        let resource = ImageResource {
1082            image,
1083            image_key: Some(image_key),
1084        };
1085
1086        self.inner
1087            .images
1088            .create(&image_key, || Ok(resource))
1089            .unwrap()
1090    }
1091
1092    //TODO: Support direct removal of raw images with verification that no references remain
1093
1094    // A key difference between this insert_buffer and the insert_buffer in a DynResourceAllocator
1095    // is that these can be retrieved. This one is more appropriate to use with loaded assets, and
1096    // DynResourceAllocator with runtime assets
1097    pub fn insert_buffer(
1098        &self,
1099        buffer: RafxBuffer,
1100    ) -> ResourceArc<BufferResource> {
1101        let buffer_id = self.inner.next_buffer_id.fetch_add(1, Ordering::Relaxed);
1102        let buffer_key = BufferKey { id: buffer_id };
1103
1104        let resource = BufferResource {
1105            buffer: Arc::new(buffer),
1106            buffer_key: Some(buffer_key),
1107        };
1108
1109        self.inner
1110            .buffers
1111            .create(&buffer_key, || Ok(resource))
1112            .unwrap()
1113    }
1114
1115    pub fn get_or_create_image_view(
1116        &self,
1117        image: &ResourceArc<ImageResource>,
1118        texture_bind_type: Option<RafxTextureBindType>,
1119    ) -> RafxResult<ResourceArc<ImageViewResource>> {
1120        if image.get_raw().image_key.is_none() {
1121            log::error!("Tried to create an image view resource with a dynamic image");
1122            return Err("Tried to create an image view resource with a dynamic image")?;
1123        }
1124
1125        let image_view_key = ImageViewKey {
1126            image_key: image.get_raw().image_key.unwrap(),
1127            texture_bind_type,
1128        };
1129
1130        self.inner.image_views.get_or_create(&image_view_key, || {
1131            log::trace!("Creating image view\n{:#?}", image_view_key);
1132            let resource = ImageViewResource {
1133                image: image.clone(),
1134                texture_bind_type,
1135                image_view_key: Some(image_view_key.clone()),
1136            };
1137            log::trace!("Created image view\n{:#?}", resource);
1138
1139            Ok(resource)
1140        })
1141    }
1142}