rafx_framework/resources/
resource_manager.rs

1use super::dyn_resources;
2use super::pipeline_cache;
3use super::resource_lookup;
4use crate::{
5    DescriptorSetAllocatorProvider, DescriptorSetAllocatorRef, DynResourceAllocatorSet,
6    GraphicsPipelineCache, MAX_FRAMES_IN_FLIGHT,
7};
8
9use crate::graph::RenderGraphCache;
10use crate::render_features::RenderRegistry;
11use crate::resources::builtin_pipelines::BuiltinPipelines;
12use crate::resources::descriptor_sets::DescriptorSetAllocatorManager;
13use crate::resources::dyn_commands::DynCommandPoolAllocator;
14use crate::resources::dyn_resources::{
15    DynResourceAllocatorSetManager, DynResourceAllocatorSetProvider,
16};
17use crate::resources::resource_lookup::ResourceLookupSet;
18use rafx_api::{RafxDeviceContext, RafxResult};
19use std::sync::Arc;
20
21//TODO: Support descriptors that can be different per-view
22//TODO: Support dynamic descriptors tied to command buffers?
23//TODO: Support data inheritance for descriptors
24
25#[derive(Debug)]
26pub struct ResourceManagerMetrics {
27    pub dyn_resource_metrics: dyn_resources::ResourceMetrics,
28    pub resource_metrics: resource_lookup::ResourceMetrics,
29    pub graphics_pipeline_cache_metrics: pipeline_cache::GraphicsPipelineCacheMetrics,
30}
31
32struct ResourceContextInner {
33    descriptor_set_allocator_provider: DescriptorSetAllocatorProvider,
34    dyn_resources_allocator_provider: DynResourceAllocatorSetProvider,
35    dyn_command_pool_allocator: DynCommandPoolAllocator,
36    resources: ResourceLookupSet,
37    graphics_pipeline_cache: GraphicsPipelineCache,
38    render_graph_cache: RenderGraphCache,
39    builtin_pipelines: BuiltinPipelines,
40}
41
42#[derive(Clone)]
43pub struct ResourceContext {
44    inner: Arc<ResourceContextInner>,
45}
46
47impl ResourceContext {
48    pub fn device_context(&self) -> &RafxDeviceContext {
49        self.inner.resources.device_context()
50    }
51
52    pub fn resources(&self) -> &ResourceLookupSet {
53        &self.inner.resources
54    }
55
56    pub fn graphics_pipeline_cache(&self) -> &GraphicsPipelineCache {
57        &self.inner.graphics_pipeline_cache
58    }
59
60    pub fn render_graph_cache(&self) -> &RenderGraphCache {
61        &self.inner.render_graph_cache
62    }
63
64    pub fn create_dyn_command_pool_allocator(&self) -> DynCommandPoolAllocator {
65        self.inner.dyn_command_pool_allocator.clone()
66    }
67
68    pub fn create_dyn_resource_allocator_set(&self) -> DynResourceAllocatorSet {
69        self.inner.dyn_resources_allocator_provider.get_allocator()
70    }
71
72    pub fn create_descriptor_set_allocator(&self) -> DescriptorSetAllocatorRef {
73        self.inner.descriptor_set_allocator_provider.get_allocator()
74    }
75
76    pub fn builtin_pipelines(&self) -> &BuiltinPipelines {
77        &self.inner.builtin_pipelines
78    }
79}
80
81pub struct ResourceManager {
82    render_registry: RenderRegistry,
83    dyn_resource_allocators: DynResourceAllocatorSetManager,
84    dyn_command_pool_allocator: DynCommandPoolAllocator,
85    resources: ResourceLookupSet,
86    render_graph_cache: RenderGraphCache,
87    descriptor_set_allocator: DescriptorSetAllocatorManager,
88    graphics_pipeline_cache: GraphicsPipelineCache,
89
90    // This is Some() until ResourceManager is dropped
91    builtin_pipelines: Option<BuiltinPipelines>,
92}
93
94impl ResourceManager {
95    pub fn new(
96        device_context: &RafxDeviceContext,
97        render_registry: &RenderRegistry,
98    ) -> Self {
99        let resources = ResourceLookupSet::new(device_context, MAX_FRAMES_IN_FLIGHT as u32);
100        let builtin_pipelines =
101            BuiltinPipelines::new(&resources).expect("Failed to load a built-in resource");
102
103        //DX12TODO: Disable resource reuse for DX12 for now
104        // vulkan lets us transition from COMMON but dx12 doesn't. The graph
105        // is trying to reuse an image from previous frame transitioning it from COMMON
106        let reuse_resources = !device_context.is_dx12();
107
108        ResourceManager {
109            render_registry: render_registry.clone(),
110            dyn_command_pool_allocator: DynCommandPoolAllocator::new(MAX_FRAMES_IN_FLIGHT as u32),
111            dyn_resource_allocators: DynResourceAllocatorSetManager::new(
112                device_context,
113                MAX_FRAMES_IN_FLIGHT as u32,
114            ),
115            resources: resources.clone(),
116            render_graph_cache: RenderGraphCache::new(MAX_FRAMES_IN_FLIGHT as u32, reuse_resources),
117            descriptor_set_allocator: DescriptorSetAllocatorManager::new(device_context),
118            graphics_pipeline_cache: GraphicsPipelineCache::new(render_registry, resources),
119            builtin_pipelines: Some(builtin_pipelines),
120        }
121    }
122
123    pub fn device_context(&self) -> &RafxDeviceContext {
124        self.resources.device_context()
125    }
126
127    pub fn resource_context(&self) -> ResourceContext {
128        let inner = ResourceContextInner {
129            descriptor_set_allocator_provider: self
130                .descriptor_set_allocator
131                .create_allocator_provider(),
132            dyn_resources_allocator_provider: self
133                .dyn_resource_allocators
134                .create_allocator_provider(),
135            dyn_command_pool_allocator: self.dyn_command_pool_allocator.clone(),
136            resources: self.resources.clone(),
137            graphics_pipeline_cache: self.graphics_pipeline_cache.clone(),
138            render_graph_cache: self.render_graph_cache.clone(),
139            builtin_pipelines: self.builtin_pipelines.as_ref().unwrap().clone(),
140        };
141
142        ResourceContext {
143            inner: Arc::new(inner),
144        }
145    }
146
147    pub fn resources(&self) -> &ResourceLookupSet {
148        &self.resources
149    }
150
151    pub fn graphics_pipeline_cache(&self) -> &GraphicsPipelineCache {
152        &self.graphics_pipeline_cache
153    }
154
155    pub fn dyn_command_pool_allocator(&self) -> &DynCommandPoolAllocator {
156        &self.dyn_command_pool_allocator
157    }
158
159    pub fn create_dyn_resource_allocator_set(&self) -> DynResourceAllocatorSet {
160        self.dyn_resource_allocators.get_allocator()
161    }
162
163    pub fn create_dyn_resource_allocator_provider(&self) -> DynResourceAllocatorSetProvider {
164        self.dyn_resource_allocators.create_allocator_provider()
165    }
166
167    pub fn create_descriptor_set_allocator(&self) -> DescriptorSetAllocatorRef {
168        self.descriptor_set_allocator.get_allocator()
169    }
170
171    pub fn create_descriptor_set_allocator_provider(&self) -> DescriptorSetAllocatorProvider {
172        self.descriptor_set_allocator.create_allocator_provider()
173    }
174
175    pub fn render_registry(&self) -> &RenderRegistry {
176        &self.render_registry
177    }
178
179    pub fn metrics(&self) -> ResourceManagerMetrics {
180        let dyn_resource_metrics = self.dyn_resource_allocators.metrics();
181        let resource_metrics = self.resources.metrics();
182        let graphics_pipeline_cache_metrics = self.graphics_pipeline_cache.metrics();
183
184        ResourceManagerMetrics {
185            dyn_resource_metrics,
186            resource_metrics,
187            graphics_pipeline_cache_metrics,
188        }
189    }
190
191    #[profiling::function]
192    pub fn on_frame_complete(&mut self) -> RafxResult<()> {
193        self.render_graph_cache.on_frame_complete();
194        self.graphics_pipeline_cache.on_frame_complete();
195        self.resources.on_frame_complete()?;
196        self.dyn_command_pool_allocator.on_frame_complete()?;
197        self.dyn_resource_allocators.on_frame_complete()?;
198        self.descriptor_set_allocator.on_frame_complete();
199        Ok(())
200    }
201}
202
203impl Drop for ResourceManager {
204    fn drop(&mut self) {
205        log::info!("Cleaning up resource manager");
206        log::trace!("Resource Manager Metrics:\n{:#?}", self.metrics());
207
208        self.builtin_pipelines = None;
209
210        // Wipe caches to ensure we don't keep anything alive
211        self.render_graph_cache.clear();
212        self.graphics_pipeline_cache.clear_all_pipelines();
213
214        // Drop all descriptors. These bind to raw resources, so we need to drop them before
215        // dropping resources
216        self.descriptor_set_allocator.destroy().unwrap();
217
218        // Now drop all resources with a zero ref count and warn for any resources that remain
219        self.resources.destroy().unwrap();
220        self.dyn_resource_allocators.destroy().unwrap();
221
222        log::info!("Dropping resource manager");
223        log::trace!("Resource Manager Metrics:\n{:#?}", self.metrics());
224    }
225}