Skip to content

Commit

Permalink
gpu: Expose FrameBudget for rendering.
Browse files Browse the repository at this point in the history
Also hook it up to monitor refresh rate.
  • Loading branch information
kpreid committed Jan 26, 2025
1 parent 4358373 commit a746ce9
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 10 deletions.
17 changes: 14 additions & 3 deletions all-is-cubes-desktop/src/winit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use std::mem;
use std::sync::Arc;
use std::time::Instant;
use std::time::{Duration, Instant};

use winit::event::{DeviceEvent, ElementState, WindowEvent};
use winit::event_loop::{ActiveEventLoop, ControlFlow};
Expand All @@ -11,6 +11,7 @@ use winit::window::{CursorGrabMode, Window};
use all_is_cubes::euclid::{Point2D, Size2D};
use all_is_cubes::listen;
use all_is_cubes_gpu::in_wgpu::SurfaceRenderer;
use all_is_cubes_gpu::FrameBudget;
use all_is_cubes_render::camera::{self, StandardCameras, Viewport};

use all_is_cubes_ui::apps::InputProcessor;
Expand Down Expand Up @@ -534,9 +535,19 @@ impl RendererToWinit for SurfaceRenderer<Instant> {
self.cameras()
}

fn redraw(&mut self, session: &Session, _window: &Window) {
fn redraw(&mut self, session: &Session, window: &Window) {
let frame_budget = FrameBudget::from_frame_period(
match window
.current_monitor()
.and_then(|m| m.refresh_rate_millihertz())
{
Some(mhz) => Duration::from_secs_f32(1000.0 / mhz as f32),
None => Duration::from_millis(16), // assume ~60 Hz
},
);

let _info = self
.render_frame(session.cursor_result(), |render_info| {
.render_frame(session.cursor_result(), &frame_budget, |render_info| {
format!("{}", session.info_text(render_info))
})
.unwrap();
Expand Down
15 changes: 15 additions & 0 deletions all-is-cubes-gpu/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ impl FrameBudget {
ui: VERY_LONG,
},
};

/// Create a [`FrameBudget`] presumed to be a good choice when the period between frames
/// (reciprocal of frame rate) is this long.
pub fn from_frame_period(frame_period: Duration) -> Self {
// The fraction of the frame period not accounted for here is time left for:
// * the simulation, and
// * everything in rendering that is not explicitly budgeted.
// TODO: In principle we should also be negotiating with the simulation.
Self {
update_meshes: Layers {
world: frame_period.mul_f32(0.3),
ui: frame_period.mul_f32(0.2),
},
}
}
}

/// A Duration long enough that it is not interesting in questions of rendering, but not
Expand Down
9 changes: 4 additions & 5 deletions all-is-cubes-gpu/src/in_wgpu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,12 @@ impl<I: time::Instant> SurfaceRenderer<I> {
pub fn render_frame(
&mut self,
cursor_result: Option<&Cursor>,
frame_budget: &FrameBudget,
info_text_fn: impl FnOnce(&RenderInfo) -> String,
) -> Result<RenderInfo, RenderError> {
let update_info = self.everything.update(
&self.queue,
cursor_result,
&FrameBudget::SIXTY_FPS, // TODO: figure out what we're vsyncing to, instead
)?;
let update_info = self
.everything
.update(&self.queue, cursor_result, frame_budget)?;

if self.viewport_dirty.get_and_clear() {
// Test because wgpu insists on nonzero values -- we'd rather be inconsistent
Expand Down
8 changes: 6 additions & 2 deletions all-is-cubes-wasm/src/web_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use web_sys::{
use all_is_cubes::euclid::{Point2D, Vector2D};
use all_is_cubes::listen;
use all_is_cubes::universe::{Universe, UniverseStepInfo};
use all_is_cubes_gpu::in_wgpu;
use all_is_cubes_gpu::{in_wgpu, FrameBudget};
use all_is_cubes_port::file::NonDiskFile;
use all_is_cubes_render::camera::{GraphicsOptions, StandardCameras, Viewport};
use all_is_cubes_ui::apps::{CursorIcon, Key};
Expand Down Expand Up @@ -419,7 +419,11 @@ impl WebSession {
WebRenderer::Wgpu(renderer) => {
// note: info text is HTML on web, so no string passed here
renderer
.render_frame(inner.session.cursor_result(), |_| String::new())
.render_frame(
inner.session.cursor_result(),
&FrameBudget::SIXTY_FPS, // TODO: try to estimate real refresh rate
|_| String::new(),
)
.expect("error in render_frame")
}
};
Expand Down

0 comments on commit a746ce9

Please sign in to comment.