1use crate::graph::graph_buffer::PhysicalBufferId;
2use crate::graph::graph_image::{PhysicalImageId, PhysicalImageViewId};
3use crate::graph::{
4 RenderGraphBufferSpecification, RenderGraphImageSpecification, RenderGraphPlan,
5 SwapchainSurfaceInfo,
6};
7use crate::{BufferResource, ImageResource, ImageViewResource, ResourceArc, ResourceLookupSet};
8use fnv::FnvHashMap;
9use rafx_api::{RafxBufferDef, RafxDeviceContext, RafxMemoryUsage, RafxResult, RafxTextureDef};
10use std::sync::{Arc, Mutex};
11
12#[derive(Clone, Hash, PartialEq, Eq, Debug)]
13struct RenderGraphCachedBufferKey {
14 specification: RenderGraphBufferSpecification,
15}
16
17struct RenderGraphCachedBuffer {
18 keep_until_frame: u64,
19 buffer: ResourceArc<BufferResource>,
20}
21
22#[derive(Clone, Hash, PartialEq, Eq, Debug)]
23struct RenderGraphCachedImageKey {
24 specification: RenderGraphImageSpecification,
25 swapchain_surface_info: SwapchainSurfaceInfo,
26}
27
28struct RenderGraphCachedImage {
29 keep_until_frame: u64,
30 image: ResourceArc<ImageResource>,
31}
32
33pub struct RenderGraphCacheInner {
34 buffers: FnvHashMap<RenderGraphCachedBufferKey, Vec<RenderGraphCachedBuffer>>,
35 images: FnvHashMap<RenderGraphCachedImageKey, Vec<RenderGraphCachedImage>>,
36 current_frame_index: u64,
37 frames_to_persist: u64,
38}
39
40impl RenderGraphCacheInner {
41 pub fn new(
42 max_frames_in_flight: u32,
43 reuse_resources: bool,
44 ) -> Self {
45 let frames_to_persist = if reuse_resources {
46 (max_frames_in_flight + 1) as u64
47 } else {
48 0
49 };
50
51 RenderGraphCacheInner {
52 buffers: Default::default(),
53 images: Default::default(),
54 current_frame_index: 0,
55 frames_to_persist,
56 }
57 }
58
59 pub fn on_frame_complete(&mut self) {
60 let current_frame_index = self.current_frame_index;
62
63 for value in self.buffers.values_mut() {
64 value.retain(|x| x.keep_until_frame > current_frame_index);
65 }
66
67 self.buffers.retain(|_k, v| !v.is_empty());
68
69 for value in self.images.values_mut() {
70 value.retain(|x| x.keep_until_frame > current_frame_index);
71 }
72
73 self.images.retain(|_k, v| !v.is_empty());
74
75 self.current_frame_index += 1;
76 }
77
78 pub fn clear(&mut self) {
79 self.buffers.clear();
80 self.images.clear();
81 }
82
83 pub(super) fn allocate_buffers(
84 &mut self,
85 device_context: &RafxDeviceContext,
86 graph: &RenderGraphPlan,
87 resources: &ResourceLookupSet,
88 ) -> RafxResult<FnvHashMap<PhysicalBufferId, ResourceArc<BufferResource>>> {
89 log::trace!("Allocate buffers for rendergraph");
90 let mut buffer_resources: FnvHashMap<PhysicalBufferId, ResourceArc<BufferResource>> =
91 Default::default();
92
93 let mut next_buffer_to_use = FnvHashMap::<RenderGraphCachedBufferKey, usize>::default();
97
98 let keep_until_frame = self.current_frame_index + self.frames_to_persist;
100
101 for (&physical_id, buffer) in &graph.external_buffers {
102 buffer_resources.insert(physical_id, buffer.resource.clone());
103 }
104
105 for (&id, specification) in &graph.intermediate_buffers {
108 let key = RenderGraphCachedBufferKey {
109 specification: specification.clone(),
110 };
111
112 let next_buffer_index = next_buffer_to_use.entry(key.clone()).or_insert(0);
113 let matching_cached_buffers = self
114 .buffers
115 .entry(key.clone())
116 .or_insert_with(Default::default);
117
118 if let Some(cached_buffer) = matching_cached_buffers.get_mut(*next_buffer_index) {
119 log::trace!(
120 " Buffer {:?} - REUSE {:?} (key: {:?}, index: {})",
121 id,
122 cached_buffer.buffer,
123 key,
124 next_buffer_index
125 );
126
127 cached_buffer.keep_until_frame = keep_until_frame;
129 *next_buffer_index += 1;
130
131 if device_context.device_info().debug_names_enabled {
132 cached_buffer
133 .buffer
134 .get_raw()
135 .buffer
136 .set_debug_name(&format!("RenderGraph Buffer {:?}", id));
137 }
138
139 buffer_resources.insert(id, cached_buffer.buffer.clone());
140 } else {
141 let buffer = device_context.create_buffer(&RafxBufferDef {
143 size: key.specification.size,
144 memory_usage: RafxMemoryUsage::GpuOnly,
146 resource_type: key.specification.resource_type,
147 ..Default::default()
149 })?;
150 if device_context.device_info().debug_names_enabled {
151 buffer.set_debug_name(&format!("RenderGraph Buffer {:?}", id));
152 }
153 let buffer = resources.insert_buffer(buffer);
154
155 log::trace!(
156 " Buffer {:?} - CREATE {:?} (key: {:?}, index: {})",
157 id,
158 buffer.get_raw().buffer,
159 key,
160 next_buffer_index
161 );
162
163 debug_assert_eq!(matching_cached_buffers.len(), *next_buffer_index);
165 matching_cached_buffers.push(RenderGraphCachedBuffer {
166 keep_until_frame,
167 buffer: buffer.clone(),
168 });
169 *next_buffer_index += 1;
170
171 buffer_resources.insert(id, buffer);
173 }
174 }
175
176 Ok(buffer_resources)
177 }
178
179 pub(super) fn allocate_images(
180 &mut self,
181 device_context: &RafxDeviceContext,
182 graph: &RenderGraphPlan,
183 resources: &ResourceLookupSet,
184 swapchain_surface_info: &SwapchainSurfaceInfo,
185 ) -> RafxResult<FnvHashMap<PhysicalImageId, ResourceArc<ImageResource>>> {
186 log::trace!("Allocate images for rendergraph");
187 let mut image_resources: FnvHashMap<PhysicalImageId, ResourceArc<ImageResource>> =
188 Default::default();
189
190 let mut next_image_to_use = FnvHashMap::<RenderGraphCachedImageKey, usize>::default();
194
195 let keep_until_frame = self.current_frame_index + self.frames_to_persist;
197
198 for (id, image) in &graph.external_images {
199 let physical_id = graph.image_views[id.0].physical_image;
200 image_resources.insert(physical_id, image.resource.get_raw().image);
201 }
202
203 for (&id, specification) in &graph.intermediate_images {
206 let key = RenderGraphCachedImageKey {
207 specification: specification.clone(),
208 swapchain_surface_info: swapchain_surface_info.clone(),
209 };
210
211 let next_image_index = next_image_to_use.entry(key.clone()).or_insert(0);
212 let matching_cached_images = self
213 .images
214 .entry(key.clone())
215 .or_insert_with(Default::default);
216
217 if let Some(cached_image) = matching_cached_images.get_mut(*next_image_index) {
218 log::trace!(
219 " Image {:?} - REUSE {:?} (key: {:?}, index: {})",
220 id,
221 cached_image.image.get_raw().image,
222 key,
223 next_image_index
224 );
225
226 cached_image.keep_until_frame = keep_until_frame;
228 *next_image_index += 1;
229
230 if device_context.device_info().debug_names_enabled {
231 cached_image
232 .image
233 .get_raw()
234 .image
235 .set_debug_name(&format!("RenderGraph Image {:?}", id));
236 }
237 image_resources.insert(id, cached_image.image.clone());
238 } else {
239 let extents = key.specification.extents;
241
242 let image = device_context.create_texture(&RafxTextureDef {
243 extents,
244 array_length: specification.layer_count,
245 mip_count: specification.mip_count,
246 format: specification.format,
247 sample_count: specification.samples,
248 resource_type: specification.resource_type,
249 dimensions: Default::default(),
250 })?;
251 if device_context.device_info().debug_names_enabled {
252 image.set_debug_name(&format!("RenderGraph Image {:?}", id));
253 }
254 let image = resources.insert_image(image);
255
256 log::trace!(
257 " Image {:?} - CREATE {:?} (key: {:?}, index: {})",
258 id,
259 image.get_raw().image,
260 key,
261 next_image_index
262 );
263
264 debug_assert_eq!(matching_cached_images.len(), *next_image_index);
266 matching_cached_images.push(RenderGraphCachedImage {
267 keep_until_frame,
268 image: image.clone(),
269 });
270 *next_image_index += 1;
271
272 image_resources.insert(id, image);
274 }
275 }
276
277 Ok(image_resources)
278 }
279
280 pub(super) fn allocate_image_views(
281 &mut self,
282 graph: &RenderGraphPlan,
283 resources: &ResourceLookupSet,
284 image_resources: &FnvHashMap<PhysicalImageId, ResourceArc<ImageResource>>,
285 ) -> RafxResult<FnvHashMap<PhysicalImageViewId, ResourceArc<ImageViewResource>>> {
286 let mut image_view_resources: FnvHashMap<
287 PhysicalImageViewId,
288 ResourceArc<ImageViewResource>,
289 > = Default::default();
290
291 for (id, image) in &graph.external_images {
294 image_view_resources.insert(*id, image.resource.clone());
295 }
296
297 for (id, view) in graph.image_views.iter().enumerate() {
298 let id = PhysicalImageViewId(id);
299
300 if image_view_resources.contains_key(&id) {
302 continue;
303 }
304
305 log::trace!("get_or_create_image_view for {:?}", view.physical_image);
306 let image_resource = &image_resources[&view.physical_image];
307
308 let old = image_view_resources.insert(
309 id,
310 resources.get_or_create_image_view(
311 image_resource,
312 view.view_options.texture_bind_type,
313 )?,
314 );
315 assert!(old.is_none());
316 }
317
318 Ok(image_view_resources)
319 }
320}
321
322#[derive(Clone)]
323pub struct RenderGraphCache {
324 pub(super) inner: Arc<Mutex<RenderGraphCacheInner>>,
325}
326
327impl RenderGraphCache {
328 pub fn new(
329 max_frames_in_flight: u32,
330 reuse_resources: bool,
331 ) -> Self {
332 let inner = RenderGraphCacheInner::new(max_frames_in_flight, reuse_resources);
333 RenderGraphCache {
334 inner: Arc::new(Mutex::new(inner)),
335 }
336 }
337
338 #[profiling::function]
339 pub fn on_frame_complete(&self) {
340 self.inner.lock().unwrap().on_frame_complete();
341 }
342
343 pub fn clear(&self) {
344 self.inner.lock().unwrap().clear();
345 }
346}