Skip to content

Commit

Permalink
Add FramePacer utility helper
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Nov 3, 2023
1 parent 147db03 commit 36109ea
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 59 deletions.
2 changes: 1 addition & 1 deletion blade-egui/src/belt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl BufferBelt {
bp
}

pub fn flush(&mut self, sp: blade_graphics::SyncPoint) {
pub fn flush(&mut self, sp: &blade_graphics::SyncPoint) {
self.buffers
.extend(self.active.drain(..).map(|(rb, _)| (rb, sp.clone())));
}
Expand Down
2 changes: 1 addition & 1 deletion blade-egui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ impl GuiPainter {

/// Call this after submitting work at the given `sync_point`.
#[profiling::function]
pub fn after_submit(&mut self, sync_point: blade_graphics::SyncPoint) {
pub fn after_submit(&mut self, sync_point: &blade_graphics::SyncPoint) {
self.textures_to_delete.extend(
self.textures_dropped
.drain(..)
Expand Down
1 change: 1 addition & 0 deletions blade-render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod model;
mod render;
pub mod shader;
pub mod texture;
pub mod util;

pub use asset_hub::*;
pub use model::Model;
Expand Down
21 changes: 14 additions & 7 deletions blade-render/src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,13 @@ impl ShaderPipelines {
}
}

/// Temporary resources associated with a GPU frame.
#[derive(Default)]
pub struct FrameResources {
pub buffers: Vec<blade_graphics::Buffer>,
pub acceleration_structures: Vec<blade_graphics::AccelerationStructure>,
}

impl Renderer {
/// Create a new renderer with a given configuration.
///
Expand Down Expand Up @@ -1043,8 +1050,7 @@ impl Renderer {
env_map: Option<blade_asset::Handle<crate::Texture>>,
asset_hub: &crate::AssetHub,
gpu: &blade_graphics::Context,
temp_buffers: &mut Vec<blade_graphics::Buffer>,
temp_acceleration_structures: &mut Vec<blade_graphics::AccelerationStructure>,
temp: &mut FrameResources,
) {
let (env_view, env_extent) = match env_map {
Some(handle) => {
Expand All @@ -1057,7 +1063,8 @@ impl Renderer {
.assign(env_view, env_extent, command_encoder, gpu);

if self.acceleration_structure != blade_graphics::AccelerationStructure::default() {
temp_acceleration_structures.push(self.acceleration_structure);
temp.acceleration_structures
.push(self.acceleration_structure);
}

let geometry_count = objects
Expand All @@ -1070,7 +1077,7 @@ impl Renderer {
let hit_size = (geometry_count.max(1) * mem::size_of::<HitEntry>()) as u64;
//TODO: reuse the hit buffer
if self.hit_buffer != blade_graphics::Buffer::default() {
temp_buffers.push(self.hit_buffer);
temp.buffers.push(self.hit_buffer);
}
self.hit_buffer = gpu.create_buffer(blade_graphics::BufferDesc {
name: "hit entries",
Expand All @@ -1082,7 +1089,7 @@ impl Renderer {
size: hit_size,
memory: blade_graphics::Memory::Upload,
});
temp_buffers.push(hit_staging);
temp.buffers.push(hit_staging);
{
let mut transfers = command_encoder.transfer();
transfers.copy_buffer_to_buffer(hit_staging.at(0), self.hit_buffer.at(0), hit_size);
Expand Down Expand Up @@ -1222,8 +1229,8 @@ impl Renderer {
scratch_buf.at(0),
);

temp_buffers.push(instance_buf);
temp_buffers.push(scratch_buf);
temp.buffers.push(instance_buf);
temp.buffers.push(scratch_buf);
}

/// Prepare to render a frame.
Expand Down
68 changes: 68 additions & 0 deletions blade-render/src/util/frame_pacer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use crate::render::FrameResources;
use std::mem;

/// Utility object that encapsulates the logic
/// of always rendering 1 frame at a time, and
/// cleaning up the temporary resources.
pub struct FramePacer {
frame_index: usize,
prev_resources: FrameResources,
prev_sync_point: Option<blade_graphics::SyncPoint>,
command_encoder: Option<blade_graphics::CommandEncoder>,
next_resources: FrameResources,
}

impl FramePacer {
pub fn new(context: &blade_graphics::Context) -> Self {
let encoder = context.create_command_encoder(blade_graphics::CommandEncoderDesc {
name: "main",
buffer_count: 2,
});
Self {
frame_index: 0,
prev_resources: FrameResources::default(),
prev_sync_point: None,
command_encoder: Some(encoder),
next_resources: FrameResources::default(),
}
}

#[profiling::function]
pub fn wait_for_previous_frame(&mut self, context: &blade_graphics::Context) {
if let Some(sp) = self.prev_sync_point.take() {
context.wait_for(&sp, !0);
}
for buffer in self.prev_resources.buffers.drain(..) {
context.destroy_buffer(buffer);
}
for accel_structure in self.prev_resources.acceleration_structures.drain(..) {
context.destroy_acceleration_structure(accel_structure);
}
}

pub fn last_sync_point(&self) -> Option<&blade_graphics::SyncPoint> {
self.prev_sync_point.as_ref()
}

pub fn destroy(&mut self, context: &blade_graphics::Context) {
self.wait_for_previous_frame(context);
context.destroy_command_encoder(self.command_encoder.take().unwrap());
}

pub fn begin_frame(&mut self) -> (&mut blade_graphics::CommandEncoder, &mut FrameResources) {
let encoder = self.command_encoder.as_mut().unwrap();
encoder.start();
(encoder, &mut self.next_resources)
}

pub fn end_frame(&mut self, context: &blade_graphics::Context) -> &blade_graphics::SyncPoint {
let sync_point = context.submit(self.command_encoder.as_mut().unwrap());
self.frame_index += 1;
// Wait for the previous frame immediately - this ensures that we are
// only processing one frame at a time, and yet not stalling.
self.wait_for_previous_frame(context);
self.prev_sync_point = Some(sync_point);
mem::swap(&mut self.prev_resources, &mut self.next_resources);
self.prev_sync_point.as_ref().unwrap()
}
}
3 changes: 3 additions & 0 deletions blade-render/src/util/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod frame_pacer;

pub use self::frame_pacer::*;
2 changes: 1 addition & 1 deletion examples/particle/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl Example {
}
encoder.present(frame);
let sync_point = self.context.submit(encoder);
self.gui_painter.after_submit(sync_point.clone());
self.gui_painter.after_submit(&sync_point);

if let Some(sp) = self.prev_sync_point.take() {
self.context.wait_for(&sp, !0);
Expand Down
63 changes: 14 additions & 49 deletions examples/scene/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,10 @@ struct ConfigScene {
struct Example {
scene_path: PathBuf,
scene_environment_map: String,
prev_temp_buffers: Vec<gpu::Buffer>,
prev_acceleration_structures: Vec<gpu::AccelerationStructure>,
prev_sync_point: Option<gpu::SyncPoint>,
pacer: blade_render::util::FramePacer,
renderer: blade_render::Renderer,
scene_load_task: Option<choir::RunningTask>,
gui_painter: blade_egui::GuiPainter,
command_encoder: Option<gpu::CommandEncoder>,
asset_hub: blade_render::AssetHub,
context: Arc<gpu::Context>,
environment_map: Option<blade_asset::Handle<blade_render::Texture>>,
Expand Down Expand Up @@ -198,37 +195,30 @@ impl Example {

log::info!("Spinning up the renderer");
shader_task.join();
let mut command_encoder = context.create_command_encoder(gpu::CommandEncoderDesc {
name: "main",
buffer_count: 2,
});
command_encoder.start();
let mut pacer = blade_render::util::FramePacer::new(&context);
let (command_encoder, _) = pacer.begin_frame();
let render_config = blade_render::RenderConfig {
screen_size,
surface_format,
max_debug_lines: 1000,
};
let renderer = blade_render::Renderer::new(
&mut command_encoder,
command_encoder,
&context,
shaders,
&asset_hub.shaders,
&render_config,
);
let sync_point = context.submit(&mut command_encoder);

pacer.end_frame(&context);
let gui_painter = blade_egui::GuiPainter::new(surface_format, &context);

Self {
scene_path: PathBuf::new(),
scene_environment_map: String::new(),
prev_temp_buffers: Vec::new(),
prev_acceleration_structures: Vec::new(),
prev_sync_point: Some(sync_point),
pacer,
renderer,
scene_load_task: None,
gui_painter,
command_encoder: Some(command_encoder),
asset_hub,
context,
environment_map: None,
Expand Down Expand Up @@ -289,12 +279,10 @@ impl Example {

fn destroy(&mut self) {
self.workers.clear();
self.wait_for_previous_frame();
self.pacer.destroy(&self.context);
self.gui_painter.destroy(&self.context);
self.renderer.destroy(&self.context);
self.asset_hub.destroy();
self.context
.destroy_command_encoder(self.command_encoder.take().unwrap());
}

pub fn load_scene(&mut self, scene_path: &Path) {
Expand Down Expand Up @@ -391,19 +379,6 @@ impl Example {
log::info!("Saving scene to: {}", scene_path.display());
}

#[profiling::function]
fn wait_for_previous_frame(&mut self) {
if let Some(sp) = self.prev_sync_point.take() {
self.context.wait_for(&sp, !0);
}
for buffer in self.prev_temp_buffers.drain(..) {
self.context.destroy_buffer(buffer);
}
for accel_structure in self.prev_acceleration_structures.drain(..) {
self.context.destroy_acceleration_structure(accel_structure);
}
}

#[profiling::function]
fn render(
&mut self,
Expand All @@ -416,7 +391,7 @@ impl Example {
self.need_accumulation_reset |= self.renderer.hot_reload(
&self.asset_hub,
&self.context,
self.prev_sync_point.as_ref().unwrap(),
self.pacer.last_sync_point().unwrap(),
);
}

Expand All @@ -426,12 +401,11 @@ impl Example {
let new_render_size = surface_config.size;
if new_render_size != self.renderer.get_screen_size() {
log::info!("Resizing to {}", new_render_size);
self.wait_for_previous_frame();
self.pacer.wait_for_previous_frame(&self.context);
self.context.resize(surface_config);
}

let command_encoder = self.command_encoder.as_mut().unwrap();
command_encoder.start();
let (command_encoder, temp) = self.pacer.begin_frame();
if new_render_size != self.renderer.get_screen_size() {
self.renderer
.resize_screen(new_render_size, command_encoder, &self.context);
Expand All @@ -441,9 +415,7 @@ impl Example {
self.gui_painter
.update_textures(command_encoder, gui_textures, &self.context);

let mut temp_buffers = Vec::new();
let mut temp_acceleration_structures = Vec::new();
self.asset_hub.flush(command_encoder, &mut temp_buffers);
self.asset_hub.flush(command_encoder, &mut temp.buffers);

if let Some(ref task) = self.scene_load_task {
if task.is_done() {
Expand All @@ -464,8 +436,7 @@ impl Example {
self.environment_map,
&self.asset_hub,
&self.context,
&mut temp_buffers,
&mut temp_acceleration_structures,
temp,
);
self.have_objects_changed = false;
}
Expand Down Expand Up @@ -522,14 +493,8 @@ impl Example {
}

command_encoder.present(frame);
let sync_point = self.context.submit(command_encoder);
self.gui_painter.after_submit(sync_point.clone());

self.wait_for_previous_frame();
self.prev_sync_point = Some(sync_point);
self.prev_temp_buffers.extend(temp_buffers);
self.prev_acceleration_structures
.extend(temp_acceleration_structures);
let sync_point = self.pacer.end_frame(&self.context);
self.gui_painter.after_submit(sync_point);
}

fn add_manipulation_gizmo(&mut self, obj_index: usize, ui: &mut egui::Ui) {
Expand Down

0 comments on commit 36109ea

Please sign in to comment.