Skip to content

Commit

Permalink
Switch to single pass rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
PolyMeilex committed Sep 28, 2023
1 parent 8da05c9 commit 7357109
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 175 deletions.
20 changes: 9 additions & 11 deletions neothesia-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ impl Recorder {
.update(&self.gpu.queue, time_without_lead_in(&self.playback));

self.keyboard.update(&self.gpu.queue, &mut self.text);

self.text.update((self.width, self.height), &self.gpu);
}

fn render(
Expand All @@ -123,10 +125,11 @@ impl Recorder {
texture_desc: &wgpu::TextureDescriptor<'_>,
output_buffer: &wgpu::Buffer,
) {
self.gpu.clear(view, self.config.background_color.into());
let bg_color = self.config.background_color;
let bg_color = wgpu_jumpstart::Color::from(bg_color).into_linear_wgpu_color();

{
let mut render_pass = self
let mut rpass = self
.gpu
.encoder
.begin_render_pass(&wgpu::RenderPassDescriptor {
Expand All @@ -135,23 +138,18 @@ impl Recorder {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
load: wgpu::LoadOp::Clear(bg_color),
store: true,
},
})],
depth_stencil_attachment: None,
});

self.waterfall
.render(&self.transform_uniform, &mut render_pass);

self.keyboard
.render(&self.transform_uniform, &mut render_pass);
self.waterfall.render(&self.transform_uniform, &mut rpass);
self.keyboard.render(&self.transform_uniform, &mut rpass);
self.text.render(&mut rpass);
}

self.text
.render((self.width, self.height), &mut self.gpu, view);

{
let u32_size = std::mem::size_of::<u32>() as u32;

Expand Down
4 changes: 2 additions & 2 deletions neothesia-core/src/render/background_animation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct BgPipeline {
time_uniform: Uniform<TimeUniform>,
}

impl<'a> BgPipeline {
impl BgPipeline {
pub fn new(gpu: &Gpu) -> Self {
let shader = gpu
.device
Expand Down Expand Up @@ -56,7 +56,7 @@ impl<'a> BgPipeline {
}
}

pub fn render(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
pub fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_bind_group(0, &self.time_uniform.bind_group, &[]);

Expand Down
22 changes: 5 additions & 17 deletions neothesia-core/src/render/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl TextRenderer {
});
}

pub fn render(&mut self, logical_size: (u32, u32), gpu: &mut Gpu, view: &wgpu::TextureView) {
pub fn update(&mut self, logical_size: (u32, u32), gpu: &Gpu) {
let elements = self.queue.iter().map(|area| glyphon::TextArea {
buffer: &area.buffer,
left: area.left,
Expand All @@ -142,22 +142,10 @@ impl TextRenderer {
)
.unwrap();

// TODO: Use single pass, now that this is posible thanks to glyphon
let mut pass = gpu.encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("glyphon text"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
},
})],
depth_stencil_attachment: None,
});

self.text_renderer.render(&self.atlas, &mut pass).unwrap();

self.queue.clear();
}

pub fn render<'rpass>(&'rpass mut self, render_pass: &mut wgpu::RenderPass<'rpass>) {
self.text_renderer.render(&self.atlas, render_pass).unwrap();
}
}
94 changes: 65 additions & 29 deletions neothesia/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ mod scene;
mod target;
mod utils;

use std::time::Duration;

use iced_core::Renderer;
use scene::{menu_scene, playing_scene, Scene};
use target::Target;
use utils::window::WindowState;
Expand Down Expand Up @@ -39,7 +42,6 @@ struct Neothesia {
target: Target,
surface: Surface,

last_time: std::time::Instant,
fps_timer: fps_ticker::Fps,

Check warning on line 45 in neothesia/src/main.rs

View workflow job for this annotation

GitHub Actions / build_macos

field `fps_timer` is never read

Check warning on line 45 in neothesia/src/main.rs

View workflow job for this annotation

GitHub Actions / build_ubuntu

field `fps_timer` is never read

Check warning on line 45 in neothesia/src/main.rs

View workflow job for this annotation

GitHub Actions / build_ubuntu

field `fps_timer` is never read

Check warning on line 45 in neothesia/src/main.rs

View workflow job for this annotation

GitHub Actions / build_macos

field `fps_timer` is never read

Check warning on line 45 in neothesia/src/main.rs

View workflow job for this annotation

GitHub Actions / build_windows

field `fps_timer` is never read

Check warning on line 45 in neothesia/src/main.rs

View workflow job for this annotation

GitHub Actions / build_windows

field `fps_timer` is never read
game_scene: Box<dyn Scene>,
}
Expand All @@ -55,7 +57,6 @@ impl Neothesia {
Self {
target,
surface,
last_time: std::time::Instant::now(),
fps_timer: Default::default(),
game_scene: Box::new(game_scene),
}
Expand Down Expand Up @@ -114,6 +115,8 @@ impl Neothesia {
fn neothesia_event(&mut self, event: NeothesiaEvent, control_flow: &mut ControlFlow) {
match event {
NeothesiaEvent::Play(midi_file) => {
self.target.iced_manager.renderer.clear();

let to = playing_scene::PlayingScene::new(&self.target, midi_file);
self.game_scene = Box::new(to);
}
Expand All @@ -131,16 +134,18 @@ impl Neothesia {
}
}

fn update(&mut self) {
self.fps_timer.tick();

let delta = self.last_time.elapsed();
self.last_time = std::time::Instant::now();
fn update(&mut self, delta: Duration) {
#[cfg(debug_assertions)]
{
self.fps_timer.tick();
self.target.text_renderer.queue_fps(self.fps_timer.avg());
}

self.game_scene.update(&mut self.target, delta);

#[cfg(debug_assertions)]
self.target.text_renderer.queue_fps(self.fps_timer.avg());
self.target.text_renderer.update(
self.target.window_state.physical_size.into(),
&self.target.gpu,
);
}

fn render(&mut self) {
Expand All @@ -156,20 +161,48 @@ impl Neothesia {
.texture
.create_view(&wgpu::TextureViewDescriptor::default());

{
let bg_color = self.target.config.background_color;
let bg_color = wgpu_jumpstart::Color::from(bg_color).into_linear_wgpu_color();
let mut rpass =
self.target
.gpu
.encoder
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Main Neothesia Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(bg_color),
store: true,
},
})],

depth_stencil_attachment: None,
});

self.game_scene.render(&self.target.transform, &mut rpass);
self.target.text_renderer.render(&mut rpass);
}

self.target
.gpu
.clear(view, self.target.config.background_color.into());

self.game_scene.render(&mut self.target, view);

self.target.text_renderer.render(
(
self.target.window_state.physical_size.width,
self.target.window_state.physical_size.height,
),
&mut self.target.gpu,
view,
);
.iced_manager
.renderer
.with_primitives(|backend, primitive| {
if !primitive.is_empty() {
backend.present(
&self.target.gpu.device,
&self.target.gpu.queue,
&mut self.target.gpu.encoder,
None,
view,
primitive,
&self.target.iced_manager.viewport,
&self.target.iced_manager.debug.overlay(),
);
}
});

self.target.gpu.submit();
frame.present();
Expand All @@ -188,6 +221,8 @@ fn main() {

let mut app = Neothesia::new(target, surface);

let mut last_time = std::time::Instant::now();

// Investigate:
// https://github.com/gfx-rs/wgpu-rs/pull/306

Expand All @@ -197,18 +232,19 @@ fn main() {
Event::UserEvent(event) => {
app.neothesia_event(event, control_flow);
}
Event::MainEventsCleared => {
app.game_scene.main_events_cleared(&mut app.target);

app.update();
app.target.window.request_redraw();
}
Event::WindowEvent { event, .. } => {
app.window_event(&event, control_flow);
}
Event::RedrawRequested(_) => {
let delta = last_time.elapsed();
last_time = std::time::Instant::now();

app.update(delta);
app.render();
}
Event::RedrawEventsCleared => {
app.target.window.request_redraw();
}
_ => {}
}
});
Expand Down
110 changes: 29 additions & 81 deletions neothesia/src/scene/menu_scene/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use iced_menu::AppUi;
use iced_style::Theme;
use neothesia_core::render::BgPipeline;

use wgpu_jumpstart::{TransformUniform, Uniform};
use winit::event::WindowEvent;

use crate::{
Expand Down Expand Up @@ -55,43 +56,36 @@ impl Scene for MenuScene {
fn update(&mut self, target: &mut Target, delta: Duration) {
self.bg_pipeline.update_time(&mut target.gpu, delta);
self.iced_state.queue_message(iced_menu::Message::Tick);

self.futures
.retain_mut(|f| match f.as_mut().poll(&mut self.context) {
std::task::Poll::Ready(msg) => {
self.iced_state.queue_message(msg);
false
}
std::task::Poll::Pending => true,
});

if !self.iced_state.is_queue_empty() {
if let Some(command) = self.iced_state.update(target) {
for a in command.actions() {
match a {
iced_runtime::command::Action::Future(f) => {
self.futures.push(f);
}
_ => {}
}
}
}
}
}

fn render(&mut self, target: &mut Target, view: &wgpu::TextureView) {
self.bg_pipeline
.render(
&mut target
.gpu
.encoder
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
},
})],
depth_stencil_attachment: None,
}),
);

target
.iced_manager
.renderer
.with_primitives(|backend, primitive| {
backend.present(
&target.gpu.device,
&target.gpu.queue,
&mut target.gpu.encoder,
None,
view,
primitive,
&target.iced_manager.viewport,
&target.iced_manager.debug.overlay(),
)
})
fn render<'pass>(
&'pass mut self,
_transform: &'pass Uniform<TransformUniform>,
rpass: &mut wgpu::RenderPass<'pass>,
) {
self.bg_pipeline.render(rpass);
}

fn window_event(&mut self, target: &mut Target, event: &WindowEvent) {
Expand All @@ -112,51 +106,5 @@ impl Scene for MenuScene {
}
}
}

// Well this feature was fun, but there is no way to detect user interaction with a
// scrollbar so this has to go for now

// match &event {
// WindowEvent::MouseInput {
// state: ElementState::Pressed,
// button: MouseButton::Left,
// ..
// } => {
// if self.iced_state.mouse_interaction() == Interaction::Idle {
// target.window.drag_window().ok();
// }
// }
// _ => {}
// }
}

fn main_events_cleared(&mut self, target: &mut Target) {
if !self.iced_state.is_queue_empty() {
if let Some(command) = self.iced_state.update(target) {
for a in command.actions() {
match a {
iced_runtime::command::Action::Future(f) => {
self.futures.push(f);
}
_ => {}
}
}
}
}

let context = &mut self.context;
let mut messages = Vec::new();

self.futures.retain_mut(|f| match f.as_mut().poll(context) {
std::task::Poll::Ready(msg) => {
messages.push(msg);
false
}
std::task::Poll::Pending => true,
});

for msg in messages {
self.iced_state.queue_message(msg);
}
}
}
Loading

0 comments on commit 7357109

Please sign in to comment.