Skip to content

Commit

Permalink
Layer options
Browse files Browse the repository at this point in the history
  • Loading branch information
nanoqsh committed Jan 16, 2024
1 parent bfac8c8 commit f42ca21
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 31 deletions.
11 changes: 7 additions & 4 deletions dunge/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use {
crate::{
bind::{self, Binder, GroupHandler, UniqueBinding, Update, Visit},
format::Format,
instance::Row,
layer::Layer,
layer::{Layer, Options},
mesh::{self, Mesh},
shader::Shader,
sl::IntoModule,
Expand Down Expand Up @@ -45,8 +44,12 @@ impl Context {
Uniform::new(&self.0, val.value().as_ref())
}

pub fn make_layer<V, I>(&self, format: Format, shader: &Shader<V, I>) -> Layer<V, I> {
Layer::new(&self.0, format, shader)
pub fn make_layer<V, I, O>(&self, shader: &Shader<V, I>, opts: O) -> Layer<V, I>
where
O: Into<Options>,
{
let opts = opts.into();
Layer::new(&self.0, shader, &opts)
}

pub fn make_mesh<V>(&self, data: &mesh::Data<V>) -> Mesh<V>
Expand Down
3 changes: 2 additions & 1 deletion dunge/src/format.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use wgpu::TextureFormat;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum Format {
#[default]
RgbAlpha,
BgrAlpha,
}
Expand Down
144 changes: 126 additions & 18 deletions dunge/src/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ use {
state::State,
},
std::{iter, marker::PhantomData},
wgpu::{RenderPass, RenderPipeline},
wgpu::{BlendState, PrimitiveTopology, RenderPass, RenderPipeline},
};

pub struct SetLayer<'p, V, I> {
shader_id: usize,
no_bindings: bool,
only_indexed_mesh: bool,
slots: Slots,
pass: RenderPass<'p>,
ty: PhantomData<(V, I)>,
Expand All @@ -34,24 +35,26 @@ impl<'p, V, I> SetLayer<'p, V, I> {
self.pass.set_bind_group(id, group, &[]);
}

SetBinding::new(self.slots, &mut self.pass)
SetBinding::new(self.only_indexed_mesh, self.slots, &mut self.pass)
}

pub fn bind_empty(&mut self) -> SetBinding<'_, 'p, V, I> {
assert!(self.no_bindings, "ths shader has any bindings");
SetBinding::new(self.slots, &mut self.pass)
SetBinding::new(self.only_indexed_mesh, self.slots, &mut self.pass)
}
}

pub struct SetBinding<'s, 'p, V, I> {
only_indexed_mesh: bool,
slots: Slots,
pass: &'s mut RenderPass<'p>,
ty: PhantomData<(V, I)>,
}

impl<'s, 'p, V, I> SetBinding<'s, 'p, V, I> {
fn new(slots: Slots, pass: &'s mut RenderPass<'p>) -> Self {
fn new(only_indexed_mesh: bool, slots: Slots, pass: &'s mut RenderPass<'p>) -> Self {
Self {
only_indexed_mesh,
slots,
pass,
ty: PhantomData,
Expand All @@ -65,6 +68,7 @@ impl<'s, 'p, V, I> SetBinding<'s, 'p, V, I> {
let mut setter = Setter::new(self.slots.instance, self.pass);
instance.set(&mut setter);
SetInstance {
only_indexed_mesh: self.only_indexed_mesh,
len: setter.len(),
slots: self.slots,
pass: self.pass,
Expand All @@ -74,57 +78,156 @@ impl<'s, 'p, V, I> SetBinding<'s, 'p, V, I> {
}

impl<'p, V> SetBinding<'_, 'p, V, ()> {
#[inline]
pub fn draw(&mut self, mesh: &'p Mesh<V>) {
assert!(
!self.only_indexed_mesh || mesh.is_indexed(),
"only an indexed mesh can be drawn on this layer",
);

mesh.draw(self.pass, self.slots.vertex, 1);
}
}

impl SetBinding<'_, '_, (), ()> {
pub fn draw_triangles(&mut self, count: u32) {
self.pass.draw(0..count * 3, 0..1);
#[inline]
pub fn draw_points(&mut self, n: u32) {
assert!(
!self.only_indexed_mesh,
"only an indexed mesh can be drawn on this layer",
);

self.pass.draw(0..n, 0..1);
}
}

pub struct SetInstance<'s, 'p, V> {
only_indexed_mesh: bool,
len: u32,
slots: Slots,
pass: &'s mut RenderPass<'p>,
ty: PhantomData<V>,
}

impl<'p, V> SetInstance<'_, 'p, V> {
#[inline]
pub fn draw(&mut self, mesh: &'p Mesh<V>) {
assert!(
!self.only_indexed_mesh || mesh.is_indexed(),
"only an indexed mesh can be drawn on this layer",
);

mesh.draw(self.pass, self.slots.vertex, self.len);
}
}

impl SetInstance<'_, '_, ()> {
pub fn draw_triangles(&mut self, count: u32) {
self.pass.draw(0..count * 3, 0..self.len);
#[inline]
pub fn draw_points(&mut self, n: u32) {
assert!(
!self.only_indexed_mesh,
"only an indexed mesh can be drawn on this layer",
);

self.pass.draw(0..n, 0..self.len);
}
}

#[derive(Clone, Copy, Default)]
pub enum Blend {
#[default]
None,
Replace,
Alpha,
}

impl Blend {
fn wgpu(self) -> Option<BlendState> {
match self {
Self::None => None,
Self::Replace => Some(BlendState::REPLACE),
Self::Alpha => Some(BlendState::ALPHA_BLENDING),
}
}
}

#[derive(Clone, Copy, Default)]
pub enum Topology {
PointList,
LineList,
LineStrip,
#[default]
TriangleList,
TriangleStrip,
}

impl Topology {
fn wgpu(self) -> PrimitiveTopology {
match self {
Self::PointList => PrimitiveTopology::PointList,
Self::LineList => PrimitiveTopology::LineList,
Self::LineStrip => PrimitiveTopology::LineStrip,
Self::TriangleList => PrimitiveTopology::TriangleList,
Self::TriangleStrip => PrimitiveTopology::TriangleStrip,
}
}
}

#[derive(Default)]
pub struct Options {
pub format: Format,
pub blend: Blend,
pub topology: Topology,
pub indexed_mesh: bool,
pub depth: bool,
}

impl From<Format> for Options {
fn from(format: Format) -> Self {
Self {
format,
..Default::default()
}
}
}

pub struct Layer<V, I> {
shader_id: usize,
no_bindings: bool,

// Is indexed mesh used.
// This is necessary to draw a mesh with any strip mode.
only_indexed_mesh: bool,
slots: Slots,
format: Format,
render: RenderPipeline,
ty: PhantomData<(V, I)>,
}

impl<V, I> Layer<V, I> {
pub(crate) fn new(state: &State, format: Format, shader: &Shader<V, I>) -> Self {
pub(crate) fn new(state: &State, shader: &Shader<V, I>, opts: &Options) -> Self {
use wgpu::*;

const DEPTH_FORMAT: TextureFormat = TextureFormat::Depth24Plus;

let Options {
format,
blend,
topology,
indexed_mesh,
depth,
} = opts;

let targets = [Some(ColorTargetState {
format: format.wgpu(),
blend: Some(BlendState::REPLACE),
blend: blend.wgpu(),
write_mask: ColorWrites::ALL,
})];

let module = shader.module();
let buffers = shader.buffers();
let topology = topology.wgpu();
let only_indexed_mesh = *indexed_mesh && topology.is_strip();
let desc = RenderPipelineDescriptor {
label: None,
layout: Some(shader.layout()),
Expand All @@ -134,15 +237,18 @@ impl<V, I> Layer<V, I> {
buffers: &buffers,
},
primitive: PrimitiveState {
topology: PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: FrontFace::Ccw,
topology,
strip_index_format: only_indexed_mesh.then_some(IndexFormat::Uint16),
cull_mode: Some(Face::Back),
polygon_mode: PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
..Default::default()
},
depth_stencil: None,
depth_stencil: depth.then_some(DepthStencilState {
format: DEPTH_FORMAT,
depth_write_enabled: true,
depth_compare: CompareFunction::Less,
stencil: StencilState::default(),
bias: DepthBiasState::default(),
}),
multisample: MultisampleState::default(),
fragment: Some(FragmentState {
module,
Expand All @@ -156,8 +262,9 @@ impl<V, I> Layer<V, I> {
Self {
shader_id: shader.id(),
no_bindings: shader.groups().is_empty(),
only_indexed_mesh,
slots: shader.slots(),
format,
format: *format,
render,
ty: PhantomData,
}
Expand All @@ -172,6 +279,7 @@ impl<V, I> Layer<V, I> {
SetLayer {
shader_id: self.shader_id,
no_bindings: self.no_bindings,
only_indexed_mesh: self.only_indexed_mesh,
slots: self.slots,
pass,
ty: PhantomData,
Expand Down
4 changes: 4 additions & 0 deletions dunge/src/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ impl<V> Mesh<V> {
}
}

pub(crate) fn is_indexed(&self) -> bool {
self.indxs.is_some()
}

pub(crate) fn draw<'a>(&'a self, pass: &mut RenderPass<'a>, slot: u32, count: u32) {
use wgpu::IndexFormat;

Expand Down
2 changes: 1 addition & 1 deletion dunge/tests/triangle_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fn render() -> Result<(), Error> {
binder.into_binding()
};

let layer = cx.make_layer(Format::RgbAlpha, &shader);
let layer = cx.make_layer(&shader, Format::RgbAlpha);
let view = {
use texture::Data;

Expand Down
4 changes: 2 additions & 2 deletions dunge/tests/triangle_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn render() -> Result<(), Error> {

let cx = helpers::block_on(dunge::context())?;
let shader = cx.make_shader(triangle);
let layer = cx.make_layer(Format::RgbAlpha, &shader);
let layer = cx.make_layer(&shader, Format::RgbAlpha);
let view = {
use texture::Data;

Expand All @@ -45,7 +45,7 @@ fn render() -> Result<(), Error> {
let buffer = cx.make_copy_buffer(SIZE);
let opts = Rgba::from_standard([0., 0., 0., 1.]);
let draw = draw::from_fn(|mut frame| {
frame.layer(&layer, opts).bind_empty().draw_triangles(1);
frame.layer(&layer, opts).bind_empty().draw_points(3);
frame.copy_texture(&buffer, &view);
});

Expand Down
4 changes: 2 additions & 2 deletions dunge/tests/triangle_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn render() -> Result<(), Error> {

let cx = helpers::block_on(dunge::context())?;
let shader = cx.make_shader(triangle);
let layer = cx.make_layer(Format::RgbAlpha, &shader);
let layer = cx.make_layer(&shader, Format::RgbAlpha);
let view = {
use texture::Data;

Expand All @@ -60,7 +60,7 @@ fn render() -> Result<(), Error> {
.layer(&layer, opts)
.bind_empty()
.instance(&transform)
.draw_triangles(1);
.draw_points(3);

frame.copy_texture(&buffer, &view);
});
Expand Down
2 changes: 1 addition & 1 deletion dunge/tests/triangle_vertex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn render() -> Result<(), Error> {

let cx = helpers::block_on(dunge::context())?;
let shader = cx.make_shader(triangle);
let layer = cx.make_layer(Format::RgbAlpha, &shader);
let layer = cx.make_layer(&shader, Format::RgbAlpha);
let view = {
use texture::Data;

Expand Down
4 changes: 2 additions & 2 deletions examples/triangle/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ async fn run() -> Result<(), Error> {
binder.into_binding()
};

let layer = cx.make_layer(window.format(), &shader);
let layer = cx.make_layer(&shader, window.format());
let update = |ctrl: &Control| {
for key in ctrl.pressed_keys() {
if key.code == KeyCode::Escape {
Expand All @@ -60,7 +60,7 @@ async fn run() -> Result<(), Error> {

let draw = |mut frame: Frame| {
let clear = Rgba::from_standard([0., 0., 0., 1.]);
frame.layer(&layer, clear).bind(&bind).draw_triangles(1);
frame.layer(&layer, clear).bind(&bind).draw_points(3);
};

window.run(update::from_fn(update, draw))?;
Expand Down

0 comments on commit f42ca21

Please sign in to comment.