Skip to content

Commit

Permalink
Uniforms
Browse files Browse the repository at this point in the history
  • Loading branch information
nanoqsh committed Jan 11, 2024
1 parent 364ad31 commit 430ceb3
Show file tree
Hide file tree
Showing 15 changed files with 305 additions and 168 deletions.
12 changes: 11 additions & 1 deletion dunge/src/bind.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use {
crate::{group::BoundTexture, shader::Shader, state::State, texture::Sampler, Group},
crate::{
group::BoundTexture, shader::Shader, state::State, texture::Sampler, uniform::Uniform,
Group,
},
std::{any::TypeId, fmt, marker::PhantomData, sync::Arc},
wgpu::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindingResource, Device,
Expand All @@ -23,6 +26,13 @@ pub trait VisitMember<'a> {
fn visit_member(self, visitor: &mut Visitor<'a>);
}

impl<'a, V> VisitMember<'a> for &'a Uniform<V> {
fn visit_member(self, visitor: &mut Visitor<'a>) {
let binding = self.buffer().as_entire_buffer_binding();
visitor.push(BindingResource::Buffer(binding));
}
}

impl<'a> VisitMember<'a> for BoundTexture<'a> {
fn visit_member(self, visitor: &mut Visitor<'a>) {
visitor.push(BindingResource::TextureView(self.get().view()));
Expand Down
9 changes: 8 additions & 1 deletion dunge/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use {
texture::{
self, CopyBuffer, CopyBufferView, DrawTexture, Filter, Make, MapResult, Mapped, Sampler,
},
uniform::{Uniform, Value},
Vertex,
},
std::{error, fmt, future::IntoFuture, sync::Arc},
Expand All @@ -24,7 +25,6 @@ impl Context {
Self(Arc::new(state))
}

#[cfg(feature = "winit")]
pub(crate) fn state(&self) -> &State {
&self.0
}
Expand All @@ -40,6 +40,13 @@ impl Context {
Binder::new(&self.0, shader)
}

pub fn make_uniform<V>(&self, val: V) -> Uniform<V>
where
V: Value,
{
Uniform::new(&self.0, &val.value())
}

pub fn make_layer<V>(&self, format: Format, shader: &Shader<V>) -> Layer<V> {
Layer::new(&self.0, format, shader)
}
Expand Down
7 changes: 7 additions & 0 deletions dunge/src/el.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ where
let mut ctrl = Control {
close: Cell::default(),
min_delta_time: Cell::new(Duration::from_secs_f32(1. / 60.)),
delta_time: Duration::ZERO,
fps: 0,
pressed_keys: vec![],
released_keys: vec![],
Expand Down Expand Up @@ -179,6 +180,7 @@ where
}

time.reset();
ctrl.delta_time = delta_time;
if let Some(fps) = fps.count(delta_time) {
ctrl.fps = fps;
}
Expand Down Expand Up @@ -231,6 +233,7 @@ where
pub struct Control {
close: Cell<bool>,
min_delta_time: Cell<Duration>,
delta_time: Duration,
fps: u32,
pressed_keys: Vec<Key>,
released_keys: Vec<Key>,
Expand All @@ -245,6 +248,10 @@ impl Control {
self.min_delta_time.set(min_delta_time);
}

pub fn delta_time(&self) -> Duration {
self.delta_time
}

pub fn fps(&self) -> u32 {
self.fps
}
Expand Down
27 changes: 21 additions & 6 deletions dunge/src/group.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::{
sl::{GlobalOut, ReadGlobal, Ret},
texture::{BindTexture, Sampler, Texture},
types::{self, GroupMemberType},
types::{self, MemberType},
uniform::{Uniform, Value},
};

pub use dunge_shader::group::{DeclareGroup, Projection};
Expand All @@ -26,30 +27,44 @@ impl<'a> BoundTexture<'a> {
///
/// The trait is sealed because the derive macro relies on no new types being used.
pub trait MemberProjection: private::Sealed {
const TYPE: GroupMemberType;
const TYPE: MemberType;
type Field;
fn member_projection(id: u32, binding: u32, out: GlobalOut) -> Self::Field;
}

impl<V> private::Sealed for &Uniform<V> where V: Value {}

impl<V> MemberProjection for &Uniform<V>
where
V: Value,
{
const TYPE: MemberType = V::TYPE;
type Field = Ret<ReadGlobal, V::Type>;

fn member_projection(id: u32, binding: u32, out: GlobalOut) -> Self::Field {
ReadGlobal::new(id, binding, Self::TYPE.is_value(), out)
}
}

impl private::Sealed for BoundTexture<'_> {}

impl MemberProjection for BoundTexture<'_> {
const TYPE: GroupMemberType = GroupMemberType::Tx2df;
const TYPE: MemberType = MemberType::Tx2df;
type Field = Ret<ReadGlobal, types::Texture2d<f32>>;

fn member_projection(id: u32, binding: u32, out: GlobalOut) -> Self::Field {
ReadGlobal::new(id, binding, out)
ReadGlobal::new(id, binding, Self::TYPE.is_value(), out)
}
}

impl private::Sealed for &Sampler {}

impl MemberProjection for &Sampler {
const TYPE: GroupMemberType = GroupMemberType::Sampl;
const TYPE: MemberType = MemberType::Sampl;
type Field = Ret<ReadGlobal, types::Sampler>;

fn member_projection(id: u32, binding: u32, out: GlobalOut) -> Self::Field {
ReadGlobal::new(id, binding, out)
ReadGlobal::new(id, binding, Self::TYPE.is_value(), out)
}
}

Expand Down
1 change: 1 addition & 0 deletions dunge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod mesh;
pub mod shader;
pub mod state;
pub mod texture;
pub mod uniform;
pub mod vertex;

#[cfg(feature = "winit")]
Expand Down
16 changes: 13 additions & 3 deletions dunge/src/shader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use {
bind::TypedGroup,
sl::{InputInfo, IntoModule, Module, Stages},
state::State,
types::{GroupMemberType, VectorType},
types::{MemberType, VectorType},
},
std::marker::PhantomData,
wgpu::{PipelineLayout, ShaderModule, VertexAttribute, VertexBufferLayout},
Expand Down Expand Up @@ -98,7 +98,17 @@ impl Inner {
entries.clear();
for (binding, member) in iter::zip(0.., info.decl) {
let entry = match member {
GroupMemberType::Tx2df => BindGroupLayoutEntry {
MemberType::Scalar(_) | MemberType::Vector(_) => BindGroupLayoutEntry {
binding,
visibility: visibility(info.stages),
ty: BindingType::Buffer {
ty: BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
MemberType::Tx2df => BindGroupLayoutEntry {
binding,
visibility: visibility(info.stages),
ty: BindingType::Texture {
Expand All @@ -108,7 +118,7 @@ impl Inner {
},
count: None,
},
GroupMemberType::Sampl => BindGroupLayoutEntry {
MemberType::Sampl => BindGroupLayoutEntry {
binding,
visibility: visibility(info.stages),
ty: BindingType::Sampler(SamplerBindingType::Filtering),
Expand Down
1 change: 1 addition & 0 deletions dunge/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ impl State {
where
D: Draw,
{
self.queue.submit([]);
draw.draw(render.0.make(&self.device, view));
let buffers = render.0.drain().map(CommandEncoder::finish);
self.queue.submit(buffers);
Expand Down
150 changes: 150 additions & 0 deletions dunge/src/uniform.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
use {
crate::{
context::Context,
state::State,
types::{self, MemberType, ScalarType, VectorType},
},
std::{marker::PhantomData, sync::Arc},
wgpu::Buffer,
};

#[derive(Clone)]
pub struct Uniform<V> {
buf: Arc<Buffer>,
ty: PhantomData<V>,
}

impl<V> Uniform<V> {
pub(crate) fn new(state: &State, data: &Data) -> Self {
use wgpu::{
util::{BufferInitDescriptor, DeviceExt},
BufferUsages,
};

let buf = {
let desc = BufferInitDescriptor {
label: None,
contents: data.as_slice(),
usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
};

state.device().create_buffer_init(&desc)
};

Self {
buf: Arc::new(buf),
ty: PhantomData,
}
}

pub fn update(&self, cx: &Context, val: V)
where
V: Value,
{
let queue = cx.state().queue();
let data = val.value();
queue.write_buffer(&self.buf, 0, data.as_slice());
}

pub(crate) fn buffer(&self) -> &Buffer {
&self.buf
}
}

pub trait Value: private::Sealed {
const TYPE: MemberType;
type Type;
fn value(self) -> Data;
}

impl private::Sealed for f32 {}

impl Value for f32 {
const TYPE: MemberType = MemberType::Scalar(ScalarType::Float);
type Type = Self;

fn value(self) -> Data {
Data([self, 0., 0., 0.])
}
}

impl private::Sealed for [f32; 2] {}

impl Value for [f32; 2] {
const TYPE: MemberType = MemberType::Vector(VectorType::Vec2f);
type Type = types::Vec2<f32>;

fn value(self) -> Data {
let [x, y] = self;
Data([x, y, 0., 0.])
}
}

impl private::Sealed for [f32; 3] {}

impl Value for [f32; 3] {
const TYPE: MemberType = MemberType::Vector(VectorType::Vec3f);
type Type = types::Vec3<f32>;

fn value(self) -> Data {
let [x, y, z] = self;
Data([x, y, z, 0.])
}
}

impl private::Sealed for [f32; 4] {}

impl Value for [f32; 4] {
const TYPE: MemberType = MemberType::Vector(VectorType::Vec4f);
type Type = types::Vec4<f32>;

fn value(self) -> Data {
let [x, y, z, w] = self;
Data([x, y, z, w])
}
}

impl private::Sealed for glam::Vec2 {}

impl Value for glam::Vec2 {
const TYPE: MemberType = MemberType::Vector(VectorType::Vec2f);
type Type = types::Vec2<f32>;

fn value(self) -> Data {
self.to_array().value()
}
}

impl private::Sealed for glam::Vec3 {}

impl Value for glam::Vec3 {
const TYPE: MemberType = MemberType::Vector(VectorType::Vec3f);
type Type = types::Vec3<f32>;

fn value(self) -> Data {
self.to_array().value()
}
}

impl private::Sealed for glam::Vec4 {}

impl Value for glam::Vec4 {
const TYPE: MemberType = MemberType::Vector(VectorType::Vec4f);
type Type = types::Vec4<f32>;

fn value(self) -> Data {
self.to_array().value()
}
}

pub struct Data([f32; 4]);

impl Data {
fn as_slice(&self) -> &[u8] {
bytemuck::cast_slice(&self.0)
}
}

mod private {
pub trait Sealed {}
}
2 changes: 1 addition & 1 deletion dunge_macros/src/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub(crate) fn derive(input: DeriveInput) -> TokenStream {
]);
}

impl ::dunge::bind::Visit for Map<#(#anon_lts),*> {
impl ::dunge::bind::Visit for #name<#(#anon_lts),*> {
fn visit<'a>(&'a self, visitor: &mut ::dunge::bind::Visitor<'a>) {
#(#group_visit_members);*;
}
Expand Down
Loading

0 comments on commit 430ceb3

Please sign in to comment.