1use crate::assets::storage::GpuAssetServer;
2use crate::render::frame_pipeline::render_pipeline::{PipelineHandles, RenderPipeline};
3use crate::render::graph::RenderGraph;
4use crate::render::resource::ResourcePool;
5use crate::render::world::RWorld;
6use crate::vulkan::core::commands::Commands;
7use crate::vulkan::core::sync::FrameSync;
8use crate::vulkan::core::DeviceContext;
9use crate::vulkan::timestamps::GpuFrameTimes;
10use crate::vulkan::{Device, VulkanContext};
11use ash::vk;
12use std::sync::Arc;
13
14const FRAMES_IN_FLIGHT: u32 = 3;
15
16pub trait DynRenderer: Send {
17 fn draw_frame(
18 &mut self,
19 ctx: &VulkanContext,
20 render_world: &RWorld,
21 gpu_assets: &mut GpuAssetServer,
22 ) -> anyhow::Result<bool>;
23
24 fn resize_output(&mut self, w: u32, h: u32, gpu: &GpuAssetServer) -> anyhow::Result<()>;
25 fn resize_internal(&mut self, w: u32, h: u32, gpu: &GpuAssetServer) -> anyhow::Result<()>;
26
27 fn last_frame_times(&self) -> Option<&GpuFrameTimes>;
28
29 fn exposure(&self) -> f32;
30 fn set_exposure(&mut self, v: f32);
31
32 fn fsr_sharpness(&self) -> f32;
33 fn set_fsr_sharpness(&mut self, v: f32);
34}
35
36pub struct Renderer<P: RenderPipeline> {
37 pub graph: RenderGraph,
38 pub pipeline: P,
39
40 pub commands: Commands,
41 pub(crate) frames: Vec<FrameSync>,
42 pub(crate) acquire_semaphores: Vec<vk::Semaphore>,
43 pub(crate) present_semaphores: Vec<vk::Semaphore>,
44 pub(crate) current_frame: usize,
45 pub(crate) swapchain_loader: ash::khr::swapchain::Device,
46 pub(crate) device: Arc<Device>,
47 pub(crate) handles: PipelineHandles,
48
49 pub exposure: f32,
50 pub fsr_sharpness: f32,
51}
52
53impl<P: RenderPipeline> Renderer<P> {
54 pub fn draw_frame(
55 &mut self,
56 ctx: &VulkanContext,
57 render_world: &RWorld,
58 gpu_assets: &mut GpuAssetServer,
59 ) -> anyhow::Result<bool> {
60 puffin::profile_function!();
61
62 let frame = &self.frames[self.current_frame];
63 let cmd = self.commands.buffers[self.current_frame];
64 let device = &ctx.device.handle;
65 let swapchain = ctx.swapchain.as_ref().unwrap();
66
67 unsafe {
68 puffin::profile_scope!("wait_for_fences");
69 device.wait_for_fences(&[frame.render_fence], true, u64::MAX)?;
70 }
71
72 let acquire_sem = self.acquire_semaphores[self.current_frame];
73 let (image_index, suboptimal) = match unsafe {
74 self.swapchain_loader.acquire_next_image(swapchain.handle, u64::MAX, acquire_sem, vk::Fence::null())
75 } {
76 Ok(r) => r,
77 Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => return Ok(true),
78 Err(e) => return Err(e.into()),
79 };
80
81 self.graph.pool.update_external(
82 self.handles.swapchain,
83 swapchain.images[image_index as usize],
84 swapchain.image_views[image_index as usize],
85 swapchain.extent,
86 );
87 self.graph.reset_external_layouts();
88
89 unsafe { device.reset_fences(&[frame.render_fence])? };
90 unsafe {
91 device.reset_command_buffer(cmd, vk::CommandBufferResetFlags::empty())?;
92 device.begin_command_buffer(
93 cmd,
94 &vk::CommandBufferBeginInfo::default().flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT),
95 )?;
96 }
97
98 {
99 puffin::profile_scope!("graph_execute");
100 self.graph.execute(device, cmd, render_world, gpu_assets)?;
101 }
102
103 unsafe { device.end_command_buffer(cmd)? };
104
105 let present_sem = self.present_semaphores[image_index as usize];
106
107 unsafe {
108 puffin::profile_scope!("queue_submit");
109 let wait_info = vk::SemaphoreSubmitInfo::default()
110 .semaphore(acquire_sem)
111 .stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT);
112
113 let signal_info = vk::SemaphoreSubmitInfo::default()
114 .semaphore(present_sem)
115 .stage_mask(vk::PipelineStageFlags2::ALL_GRAPHICS);
116
117 let cmd_info = vk::CommandBufferSubmitInfo::default().command_buffer(cmd);
118
119 device.queue_submit2(
120 ctx.device.graphics_queue,
121 &[vk::SubmitInfo2::default()
122 .wait_semaphore_infos(std::slice::from_ref(&wait_info))
123 .command_buffer_infos(std::slice::from_ref(&cmd_info))
124 .signal_semaphore_infos(std::slice::from_ref(&signal_info))],
125 frame.render_fence,
126 )?;
127 self.graph.mark_submitted();
128 }
129
130 let needs_recreate = match unsafe {
131 puffin::profile_scope!("queue_present");
132 let signal_semaphores = [present_sem];
133 self.swapchain_loader.queue_present(
134 ctx.device.present_queue,
135 &vk::PresentInfoKHR::default()
136 .wait_semaphores(&signal_semaphores)
137 .swapchains(&[swapchain.handle])
138 .image_indices(&[image_index]),
139 )
140 } {
141 Ok(false) => false,
142 Ok(true) => true,
143 Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => true,
144 Err(e) => return Err(e.into()),
145 };
146
147 self.current_frame = (self.current_frame + 1) % FRAMES_IN_FLIGHT as usize;
148 Ok(needs_recreate || suboptimal)
149 }
150
151 pub fn resize_output(&mut self, new_w: u32, new_h: u32, gpu: &GpuAssetServer) -> anyhow::Result<()> {
152 unsafe { self.device.handle.device_wait_idle()? };
153 self.graph.resize_output((new_w, new_h), gpu)?;
154 self.pipeline.on_resize(&mut self.graph, new_w, new_h)
155 }
156
157 pub fn resize_internal(&mut self, new_w: u32, new_h: u32, gpu: &GpuAssetServer) -> anyhow::Result<()> {
158 unsafe { self.device.handle.device_wait_idle()? };
159 self.graph.resize_internal((new_w, new_h), gpu)?;
160 self.pipeline.on_resize_internal(&mut self.graph, new_w, new_h)
161 }
162}
163
164impl<P: RenderPipeline> DynRenderer for Renderer<P> {
165 fn draw_frame(
166 &mut self,
167 ctx: &VulkanContext,
168 render_world: &RWorld,
169 gpu_assets: &mut GpuAssetServer,
170 ) -> anyhow::Result<bool> {
171 self.draw_frame(ctx, render_world, gpu_assets)
172 }
173
174 fn resize_output(&mut self, w: u32, h: u32, gpu: &GpuAssetServer) -> anyhow::Result<()> {
175 self.resize_output(w, h, gpu)
176 }
177
178 fn resize_internal(&mut self, w: u32, h: u32, gpu: &GpuAssetServer) -> anyhow::Result<()> {
179 self.resize_internal(w, h, gpu)
180 }
181
182 fn last_frame_times(&self) -> Option<&GpuFrameTimes> {
183 self.graph.last_frame_times.as_ref()
184 }
185
186 fn exposure(&self) -> f32 {
187 self.exposure
188 }
189 fn set_exposure(&mut self, v: f32) {
190 self.exposure = v;
191 }
192
193 fn fsr_sharpness(&self) -> f32 {
194 self.fsr_sharpness
195 }
196 fn set_fsr_sharpness(&mut self, v: f32) {
197 self.fsr_sharpness = v;
198 }
199}
200
201pub fn build_dyn_renderer<P: RenderPipeline + Default + 'static>(
202 ctx: &VulkanContext,
203 gpu_assets: &mut GpuAssetServer,
204 prev_exposure: f32,
205 prev_fsr_sharpness: f32,
206) -> anyhow::Result<Box<dyn DynRenderer>> {
207 let swapchain = ctx.swapchain.as_ref().unwrap();
208 let image_count = swapchain.images.len();
209
210 let acquire_semaphores: Vec<vk::Semaphore> = (0..image_count)
211 .map(|_| {
212 let info = vk::SemaphoreCreateInfo::default();
213 unsafe { ctx.device.handle.create_semaphore(&info, None) }
214 })
215 .collect::<Result<_, _>>()?;
216
217 let present_semaphores: Vec<vk::Semaphore> = (0..image_count)
218 .map(|_| unsafe { ctx.device.handle.create_semaphore(&vk::SemaphoreCreateInfo::default(), None) })
219 .collect::<Result<_, _>>()?;
220
221 let pool = ResourcePool::new(
222 ctx.device.handle.clone(),
223 ctx.device.physical,
224 ctx.instance.handle.clone(),
225 ctx.debug_utils.clone(),
226 );
227
228 let mut graph = RenderGraph::new(
229 pool,
230 ctx.device.handle.clone(),
231 (1280, 720),
232 (swapchain.extent.width, swapchain.extent.height),
233 ctx.debug_utils.clone(),
234 );
235
236 let handles = P::build(ctx, gpu_assets, &mut graph)?;
237 graph.allocate(gpu_assets)?;
238 graph.compile()?;
239
240 let frames: Vec<_> =
241 (0..FRAMES_IN_FLIGHT).map(|_| FrameSync::new(&ctx.device.handle)).collect::<anyhow::Result<_>>()?;
242
243 let commands = Commands::new(&ctx.device.handle, ctx.device.graphics_family, FRAMES_IN_FLIGHT)?;
244
245 graph.enable_timestamps(
246 DeviceContext {
247 device: &ctx.device.handle,
248 physical_device: ctx.device.physical,
249 instance: &ctx.instance.handle,
250 },
251 FRAMES_IN_FLIGHT,
252 commands.pool,
253 ctx.device.graphics_queue,
254 )?;
255
256 let swapchain_loader = ash::khr::swapchain::Device::new(&ctx.instance.handle, &ctx.device.handle);
257
258 Ok(Box::new(Renderer::<P> {
259 graph,
260 pipeline: Default::default(),
261 commands,
262 frames,
263 acquire_semaphores,
264 present_semaphores,
265 current_frame: 0,
266 swapchain_loader,
267 device: ctx.device.clone(),
268 handles,
269 exposure: prev_exposure,
270 fsr_sharpness: prev_fsr_sharpness,
271 }))
272}
273
274impl<P: RenderPipeline> Drop for Renderer<P> {
275 fn drop(&mut self) {
276 unsafe {
277 self.device.handle.device_wait_idle().ok();
278 for &sem in &self.acquire_semaphores {
279 self.device.handle.destroy_semaphore(sem, None);
280 }
281 for &sem in &self.present_semaphores {
282 self.device.handle.destroy_semaphore(sem, None);
283 }
284 }
285 }
286}