From 6e56f56fdc2040b5ab63863e64bae03dda3a456b Mon Sep 17 00:00:00 2001 From: nanoqsh Date: Sun, 21 Jan 2024 23:23:50 +0600 Subject: [PATCH] Update --- dunge/src/bind.rs | 11 ++- dunge/src/context.rs | 23 +++-- dunge/src/draw.rs | 12 +-- dunge/src/el.rs | 24 +++-- dunge/src/state.rs | 81 ++++------------- dunge/src/update.rs | 44 ++++----- dunge/tests/triangle_group.rs | 5 +- dunge/tests/triangle_index.rs | 3 +- dunge/tests/triangle_instance.rs | 5 +- dunge/tests/triangle_vertex.rs | 5 +- dunge_shader/src/vector.rs | 2 +- examples/cube/src/main.rs | 149 ++++++++++++++++++++++++++++--- examples/triangle/src/main.rs | 2 +- 13 files changed, 230 insertions(+), 136 deletions(-) diff --git a/dunge/src/bind.rs b/dunge/src/bind.rs index b08297f..a3020a1 100644 --- a/dunge/src/bind.rs +++ b/dunge/src/bind.rs @@ -3,7 +3,7 @@ use { group::BoundTexture, shader::Shader, state::State, texture::Sampler, uniform::Uniform, Group, }, - std::{any::TypeId, fmt, marker::PhantomData, sync::Arc}, + std::{any::TypeId, error, fmt, marker::PhantomData, sync::Arc}, wgpu::{ BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindingResource, Device, }, @@ -58,9 +58,10 @@ pub struct GroupHandler { shader_id: usize, id: usize, layout: Arc, - ty: PhantomData, + ty: PhantomData, } +#[derive(Debug)] pub struct ForeignShader; impl fmt::Display for ForeignShader { @@ -69,6 +70,8 @@ impl fmt::Display for ForeignShader { } } +impl error::Error for ForeignShader {} + pub trait Binding { fn binding(&self) -> Bind; } @@ -104,10 +107,10 @@ impl Binding for SharedBinding { pub type Update = Result<(), ForeignShader>; -pub(crate) fn update( +pub(crate) fn update( state: &State, uni: &mut UniqueBinding, - handler: &GroupHandler, + handler: &GroupHandler, group: &G, ) -> Update where diff --git a/dunge/src/context.rs b/dunge/src/context.rs index 0f93511..bf9747d 100644 --- a/dunge/src/context.rs +++ b/dunge/src/context.rs @@ -1,15 +1,18 @@ use { crate::{ bind::{self, Binder, GroupHandler, UniqueBinding, Update, Visit}, + draw::Draw, instance::Row, layer::{Layer, Options}, mesh::{self, Mesh}, shader::Shader, sl::IntoModule, state::State, - texture::{self, CopyBuffer, CopyBufferView, Filter, Make, MapResult, Mapped, Sampler}, + texture::{ + self, CopyBuffer, CopyBufferView, DrawTexture, Filter, Make, MapResult, Mapped, Sampler, + }, uniform::{IntoValue, Uniform, Value}, - Vertex, + Group, Vertex, }, std::{error, fmt, future::IntoFuture, sync::Arc}, }; @@ -91,17 +94,27 @@ impl Context { view.map(&self.0, tx, rx).await } - pub fn update_group( + pub fn update_group( &self, uni: &mut UniqueBinding, - handler: &GroupHandler, + handler: &GroupHandler, group: &G, ) -> Update where - G: Visit, + G: Visit, + H: Group, { bind::update(&self.0, uni, handler, group) } + + pub fn draw_to(&self, texture: &T, draw: D) + where + T: DrawTexture, + D: Draw, + { + let view = texture.draw_texture().render_view(); + self.0.draw(view, draw); + } } /// An error returned from the [`Context`] constructor. diff --git a/dunge/src/draw.rs b/dunge/src/draw.rs index 6eb5911..1c44fbb 100644 --- a/dunge/src/draw.rs +++ b/dunge/src/draw.rs @@ -1,29 +1,29 @@ use crate::state::Frame; pub trait Draw { - fn draw(&self, frame: Frame); + fn draw(&mut self, frame: Frame); } -impl Draw for &D +impl Draw for &mut D where D: Draw + ?Sized, { - fn draw(&self, frame: Frame) { + fn draw(&mut self, frame: Frame) { (**self).draw(frame); } } pub fn from_fn(draw: D) -> impl Draw where - D: Fn(Frame), + D: FnMut(Frame), { struct Func(D); impl Draw for Func where - D: Fn(Frame), + D: FnMut(Frame), { - fn draw(&self, frame: Frame) { + fn draw(&mut self, frame: Frame) { (self.0)(frame); } } diff --git a/dunge/src/el.rs b/dunge/src/el.rs index bf5c081..195e40f 100644 --- a/dunge/src/el.rs +++ b/dunge/src/el.rs @@ -1,9 +1,8 @@ use { crate::{ context::Context, - state::Render, time::{Fps, Time}, - update::{Close, Update}, + update::Update, window::View, }, std::{cell::Cell, error, fmt, ops, time::Duration}, @@ -92,7 +91,6 @@ where // Initial state let mut active = false; - let mut render = Render::default(); let mut time = Time::now(); let mut fps = Fps::default(); move |ev, target| match ev { @@ -185,7 +183,7 @@ where ctrl.fps = fps; } - if update.update(&ctrl).close() { + if let Then::Close = update.update(&ctrl).flow() { log::debug!("close"); target.exit(); return; @@ -195,7 +193,7 @@ where match ctrl.view.output() { Ok(output) => { let rv = output.render_view(); - cx.state().draw(&mut render, rv, &update); + cx.state().draw(rv, &mut update); output.present(); } Err(SurfaceError::Timeout) => log::info!("suface error: timeout"), @@ -278,14 +276,24 @@ pub struct Key { pub text: Option, } +pub trait Flow { + fn flow(self) -> Then; +} + +impl Flow for () { + fn flow(self) -> Then { + Then::Run + } +} + #[derive(Clone, Copy)] pub enum Then { Run, Close, } -impl Close for Then { - fn close(self) -> bool { - matches!(self, Self::Close) +impl Flow for Then { + fn flow(self) -> Self { + self } } diff --git a/dunge/src/state.rs b/dunge/src/state.rs index e2523bd..1be84d7 100644 --- a/dunge/src/state.rs +++ b/dunge/src/state.rs @@ -1,11 +1,11 @@ use { crate::{ color::Rgba, - context::{Context, Error}, + context::Error, draw::Draw, format::Format, layer::{Layer, SetLayer}, - texture::{CopyBuffer, CopyTexture, DrawTexture}, + texture::{CopyBuffer, CopyTexture}, }, std::sync::atomic::{self, AtomicUsize}, wgpu::{Color, CommandEncoder, Device, Instance, LoadOp, Queue, TextureView}, @@ -87,28 +87,24 @@ impl State { self.shader_ids.fetch_add(1, atomic::Ordering::Relaxed) } - pub fn draw(&self, render: &mut Render, view: RenderView, draw: D) + pub fn draw(&self, view: RenderView, mut draw: D) where D: Draw, { + use wgpu::CommandEncoderDescriptor; + self.queue.submit([]); - draw.draw(render.0.make(&self.device, view)); - let buffers = render.0.drain().map(CommandEncoder::finish); - self.queue.submit(buffers); - } -} + let mut encoder = { + let desc = CommandEncoderDescriptor::default(); + self.device.create_command_encoder(&desc) + }; -#[derive(Default)] -pub struct Render(Encoders); + draw.draw(Frame { + view, + encoder: &mut encoder, + }); -impl Render { - pub fn draw_to(&mut self, cx: &Context, texture: &T, draw: D) - where - T: DrawTexture, - D: Draw, - { - let view = texture.draw_texture().render_view(); - cx.state().draw(self, view, draw); + self.queue.submit([encoder.finish()]); } } @@ -139,20 +135,10 @@ impl From for Options { pub struct Frame<'v, 'e> { view: RenderView<'v>, - device: &'e Device, - encoders: &'e mut Encoders, - id: usize, + encoder: &'e mut CommandEncoder, } impl Frame<'_, '_> { - pub fn subframe<'e, 'v, T>(&'e mut self, texture: &'v T) -> Frame<'v, 'e> - where - T: DrawTexture, - { - let view = texture.draw_texture().render_view(); - self.encoders.make(self.device, view) - } - pub fn layer<'p, V, I, O>(&'p mut self, layer: &'p Layer, opts: O) -> SetLayer<'p, V, I> where O: Into, @@ -179,8 +165,7 @@ impl Frame<'_, '_> { ..Default::default() }; - let encoder = self.encoders.get_mut(self.id); - let pass = encoder.begin_render_pass(&desc); + let pass = self.encoder.begin_render_pass(&desc); layer.set(pass) } @@ -188,39 +173,7 @@ impl Frame<'_, '_> { where T: CopyTexture, { - let encoder = self.encoders.get_mut(self.id); - buffer.copy_texture(texture.copy_texture(), encoder); - } -} - -#[derive(Default)] -struct Encoders(Vec); - -impl Encoders { - fn make<'e, 'v>(&'e mut self, device: &'e Device, view: RenderView<'v>) -> Frame<'v, 'e> { - use wgpu::CommandEncoderDescriptor; - - let encoder = { - let desc = CommandEncoderDescriptor::default(); - device.create_command_encoder(&desc) - }; - - let id = self.0.len(); - self.0.push(encoder); - Frame { - view, - device, - encoders: self, - id, - } - } - - fn get_mut(&mut self, id: usize) -> &mut CommandEncoder { - &mut self.0[id] - } - - fn drain(&mut self) -> impl Iterator + '_ { - self.0.drain(..) + buffer.copy_texture(texture.copy_texture(), self.encoder); } } diff --git a/dunge/src/update.rs b/dunge/src/update.rs index 4a716d7..b7c6b56 100644 --- a/dunge/src/update.rs +++ b/dunge/src/update.rs @@ -1,46 +1,40 @@ -use crate::{draw::Draw, el::Control, state::Frame}; - -pub trait Close { - fn close(self) -> bool; -} - -impl Close for () { - fn close(self) -> bool { - false - } -} +use crate::{ + draw::Draw, + el::{Control, Flow}, + state::Frame, +}; pub trait Update: Draw { - type Close: Close; - fn update(&mut self, ctrl: &Control) -> Self::Close; + type Flow: Flow; + fn update(&mut self, ctrl: &Control) -> Self::Flow; } -pub fn from_fn(update: U, draw: D) -> impl Update +pub fn from_fn(update: U, draw: D) -> impl Update where - U: FnMut(&Control) -> C, - C: Close, - D: Fn(Frame), + U: FnMut(&Control) -> F, + F: Flow, + D: FnMut(Frame), { struct Func(U, D); impl Draw for Func where - D: Fn(Frame), + D: FnMut(Frame), { - fn draw(&self, frame: Frame) { + fn draw(&mut self, frame: Frame) { (self.1)(frame); } } - impl Update for Func + impl Update for Func where - U: FnMut(&Control) -> C, - C: Close, - D: Fn(Frame), + U: FnMut(&Control) -> F, + F: Flow, + D: FnMut(Frame), { - type Close = C; + type Flow = F; - fn update(&mut self, ctrl: &Control) -> Self::Close { + fn update(&mut self, ctrl: &Control) -> Self::Flow { (self.0)(ctrl) } } diff --git a/dunge/tests/triangle_group.rs b/dunge/tests/triangle_group.rs index 005afc6..965401f 100644 --- a/dunge/tests/triangle_group.rs +++ b/dunge/tests/triangle_group.rs @@ -8,7 +8,6 @@ use { group::BoundTexture, mesh, sl::{self, Groups, InVertex, Out}, - state::Render, texture::{self, Filter, Sampler}, Group, Vertex, }, @@ -37,7 +36,7 @@ fn render() -> Result<(), Error> { } let triangle = |vert: InVertex, Groups(map): Groups| Out { - place: sl::concat(vert.pos, Vec2::new(0., 1.)), + place: sl::vec4_concat(vert.pos, Vec2::new(0., 1.)), color: sl::texture_sample(map.tex, map.sam, sl::fragment(vert.tex)), }; @@ -100,7 +99,7 @@ fn render() -> Result<(), Error> { frame.copy_texture(&buffer, &view); }); - Render::default().draw_to(&cx, &view, draw); + cx.draw_to(&view, draw); let mapped = helpers::block_on({ let (tx, rx) = helpers::oneshot(); cx.map_view(buffer.view(), tx, rx) diff --git a/dunge/tests/triangle_index.rs b/dunge/tests/triangle_index.rs index 6132b80..7a14404 100644 --- a/dunge/tests/triangle_index.rs +++ b/dunge/tests/triangle_index.rs @@ -6,7 +6,6 @@ use { draw, format::Format, sl::{self, Index, Out}, - state::Render, texture, }, glam::Vec4, @@ -49,7 +48,7 @@ fn render() -> Result<(), Error> { frame.copy_texture(&buffer, &view); }); - Render::default().draw_to(&cx, &view, draw); + cx.draw_to(&view, draw); let mapped = helpers::block_on({ let (tx, rx) = helpers::oneshot(); cx.map_view(buffer.view(), tx, rx) diff --git a/dunge/tests/triangle_instance.rs b/dunge/tests/triangle_instance.rs index 983e57a..414930a 100644 --- a/dunge/tests/triangle_instance.rs +++ b/dunge/tests/triangle_instance.rs @@ -7,7 +7,6 @@ use { format::Format, instance::Row, sl::{self, InInstance, Index, Out}, - state::Render, texture, Instance, }, glam::Vec2, @@ -31,7 +30,7 @@ fn render() -> Result<(), Error> { let [x, y] = sl::thunk(sl::f32(index) * THIRD + R_OFFSET); let p = sl::vec2(sl::cos(x), sl::sin(y)) * TRIANGLE_SIZE + t.0; Out { - place: sl::concat(p, Vec2::new(0., 1.)), + place: sl::vec4_concat(p, Vec2::new(0., 1.)), color: sl::vec4_with(sl::fragment(t.1), 1.), } }; @@ -65,7 +64,7 @@ fn render() -> Result<(), Error> { frame.copy_texture(&buffer, &view); }); - Render::default().draw_to(&cx, &view, draw); + cx.draw_to(&view, draw); let mapped = helpers::block_on({ let (tx, rx) = helpers::oneshot(); cx.map_view(buffer.view(), tx, rx) diff --git a/dunge/tests/triangle_vertex.rs b/dunge/tests/triangle_vertex.rs index c0db5d5..8cde279 100644 --- a/dunge/tests/triangle_vertex.rs +++ b/dunge/tests/triangle_vertex.rs @@ -7,7 +7,6 @@ use { format::Format, mesh, sl::{self, InVertex, Out}, - state::Render, texture, Vertex, }, glam::Vec2, @@ -26,7 +25,7 @@ fn render() -> Result<(), Error> { struct Vert([f32; 2], [f32; 3]); let triangle = |vert: InVertex| Out { - place: sl::concat(vert.0, Vec2::new(0., 1.)), + place: sl::vec4_concat(vert.0, Vec2::new(0., 1.)), color: sl::vec4_with(sl::fragment(vert.1), 1.), }; @@ -60,7 +59,7 @@ fn render() -> Result<(), Error> { frame.copy_texture(&buffer, &view); }); - Render::default().draw_to(&cx, &view, draw); + cx.draw_to(&view, draw); let mapped = helpers::block_on({ let (tx, rx) = helpers::oneshot(); cx.map_view(buffer.view(), tx, rx) diff --git a/dunge_shader/src/vector.rs b/dunge_shader/src/vector.rs index 884e112..2cc23e6 100644 --- a/dunge_shader/src/vector.rs +++ b/dunge_shader/src/vector.rs @@ -137,7 +137,7 @@ where } } -pub const fn concat(a: A, b: B) -> Ret, types::Vec4> +pub const fn vec4_concat(a: A, b: B) -> Ret, types::Vec4> where A: Eval>, B: Eval>, diff --git a/examples/cube/src/main.rs b/examples/cube/src/main.rs index 9baf159..6c638ad 100644 --- a/examples/cube/src/main.rs +++ b/examples/cube/src/main.rs @@ -9,14 +9,24 @@ fn main() { async fn run() -> Result<(), Error> { use dunge::{ + bind::UniqueBinding, color::Rgba, + context::Context, + draw::{self, Draw}, el::{KeyCode, Then}, - glam::{Mat4, Quat, Vec3}, + format::Format, + glam::{Mat4, Quat, Vec2, Vec3}, + group::BoundTexture, sl::{self, Groups, InVertex, Out}, + state::Options, + texture::{self, Filter, Sampler, Texture, ZeroSized}, uniform::Uniform, - update, Control, Frame, Group, Vertex, + update::Update, + Control, Frame, Group, Vertex, }; + type RenderTexture = texture::Draw>; + #[repr(C)] #[derive(Vertex)] struct Vert { @@ -34,6 +44,21 @@ async fn run() -> Result<(), Error> { color: sl::vec4_with(sl::fragment(vert.col), 1.), }; + #[repr(C)] + #[derive(Vertex)] + struct Screen([f32; 2], [f32; 2]); + + #[derive(Group)] + struct Map<'a> { + tex: BoundTexture<'a>, + sam: &'a Sampler, + } + + let screen = |vert: InVertex, Groups(map): Groups| Out { + place: sl::vec4_concat(vert.0, Vec2::new(0., 1.)), + color: sl::texture_sample(map.tex, map.sam, sl::fragment(vert.1)), + }; + let window = dunge::window().with_title("Cube").await?; let transform = |r, size| { let pos = Vec3::new(0., 0., -2.); @@ -49,21 +74,42 @@ async fn run() -> Result<(), Error> { }; let cx = window.context(); - let shader = cx.make_shader(cube); + let cube_shader = cx.make_shader(cube); + let screen_shader = cx.make_shader(screen); let mut r = 0.; let uniform = { let mat = transform(r, window.size()); cx.make_uniform(mat) }; - let bind = { - let mut binder = cx.make_binder(&shader); + let bind_transform = { let tr = Transform(&uniform); + let mut binder = cx.make_binder(&cube_shader); binder.bind(&tr); binder.into_binding() }; - let mech = { + let make_screen_tex = |cx: &Context, size| -> Result<_, ZeroSized> { + use dunge::texture::Data; + + let data = Data::empty(size, Format::RgbAlpha)?.with_bind().with_draw(); + Ok(cx.make_texture(data)) + }; + + let mut tex = make_screen_tex(&cx, window.size())?; + let sam = cx.make_sampler(Filter::Nearest); + let (bind_map, handler) = { + let map = Map { + tex: BoundTexture::new(&tex), + sam: &sam, + }; + + let mut binder = cx.make_binder(&screen_shader); + let handler = binder.bind(&map); + (binder.into_binding(), handler) + }; + + let mesh = { use dunge::mesh::Data; const P: f32 = 0.5; @@ -117,14 +163,42 @@ async fn run() -> Result<(), Error> { cx.make_mesh(&data) }; - let layer = cx.make_layer(&shader, window.format()); - let update = |ctrl: &Control| { + let screen_mesh = { + use dunge::mesh::Data; + + const VERTS: [Screen; 4] = [ + Screen([-1., -1.], [0., 1.]), + Screen([1., -1.], [1., 1.]), + Screen([1., 1.], [1., 0.]), + Screen([-1., 1.], [0., 0.]), + ]; + + let data = Data::from_quads(&[VERTS])?; + cx.make_mesh(&data) + }; + + let main_layer = cx.make_layer(&cube_shader, Format::RgbAlpha); + let screen_layer = cx.make_layer(&screen_shader, window.format()); + let mut size = window.size(); + let update = |state: &mut State, ctrl: &Control| { for key in ctrl.pressed_keys() { if key.code == KeyCode::Escape { return Then::Close; } } + if size != ctrl.size() { + size = ctrl.size(); + *state.tex = make_screen_tex(&cx, size).expect("TODO: error handling"); + let map = Map { + tex: BoundTexture::new(state.tex), + sam: &sam, + }; + + cx.update_group(&mut state.bind_map, &handler, &map) + .expect("TODO: error handling"); + } + r += ctrl.delta_time().as_secs_f32(); let mat = transform(r, ctrl.size()); uniform.update(&cx, mat); @@ -132,10 +206,63 @@ async fn run() -> Result<(), Error> { }; let clear = Rgba::from_standard([0., 0., 0., 1.]); - let draw = |mut frame: Frame| { - frame.layer(&layer, clear).bind(&bind).draw(&mech); + let draw = |state: &State, mut frame: Frame| { + let main = |mut frame: Frame| { + frame + .layer(&main_layer, clear) + .bind(&bind_transform) + .draw(&mesh); + }; + + cx.draw_to(state.tex, draw::from_fn(main)); + + frame + .layer(&screen_layer, Options::default()) + .bind(&state.bind_map) + .draw(&screen_mesh); }; - window.run(update::from_fn(update, draw))?; + struct App<'a, U, D> { + state: State<'a>, + update: U, + draw: D, + } + + struct State<'a> { + tex: &'a mut RenderTexture, + bind_map: UniqueBinding, + } + + let app = App { + state: State { + tex: &mut tex, + bind_map, + }, + update, + draw, + }; + + impl Draw for App<'_, U, D> + where + D: FnMut(&State, Frame), + { + fn draw(&mut self, frame: Frame) { + (self.draw)(&mut self.state, frame); + } + } + + impl Update for App<'_, U, D> + where + U: FnMut(&mut State, &Control) -> Then, + D: FnMut(&State, Frame), + { + type Flow = Then; + + fn update(&mut self, ctrl: &Control) -> Self::Flow { + (self.update)(&mut self.state, ctrl) + } + } + + window.run(app)?; Ok(()) } diff --git a/examples/triangle/src/main.rs b/examples/triangle/src/main.rs index 41ee789..b9d713c 100644 --- a/examples/triangle/src/main.rs +++ b/examples/triangle/src/main.rs @@ -40,8 +40,8 @@ async fn run() -> Result<(), Error> { let mut r = 0.; let uniform = cx.make_uniform(r); let bind = { - let mut binder = cx.make_binder(&shader); let offset = Offset(&uniform); + let mut binder = cx.make_binder(&shader); binder.bind(&offset); binder.into_binding() };