Add Bind groups

This commit is contained in:
Marco Thomas
2021-08-25 12:29:50 +02:00
parent 68e111bd99
commit 2464e2118f
10 changed files with 214 additions and 149 deletions

7
Cargo.lock generated
View File

@@ -48,6 +48,12 @@ dependencies = [
"xml-rs", "xml-rs",
] ]
[[package]]
name = "anyhow"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
[[package]] [[package]]
name = "approx" name = "approx"
version = "0.4.0" version = "0.4.0"
@@ -1916,6 +1922,7 @@ dependencies = [
name = "wgpu-rs-learning" name = "wgpu-rs-learning"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow",
"bytemuck", "bytemuck",
"cgmath", "cgmath",
"env_logger", "env_logger",

View File

@@ -14,3 +14,4 @@ log = "0.4"
wgpu = "0.9" wgpu = "0.9"
pollster = "0.2" pollster = "0.2"
bytemuck = { version = "1.4", features = [ "derive" ] } bytemuck = { version = "1.4", features = [ "derive" ] }
anyhow = "1.0"

BIN
img/aqua.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 MiB

BIN
img/happy-tree.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -1,23 +0,0 @@
// Vertex shader
struct VertexOutput {
[[builtin(position)]] clip_coordinates: vec4<f32>;
[[location(0)]] position: vec2<f32>;
};
[[stage(vertex)]]
fn main([[builtin(vertex_index)]] in_vertex_index: u32) -> VertexOutput {
var out: VertexOutput;
let x = f32(1 - i32(in_vertex_index)) * 0.5;
let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
out.clip_coordinates = vec4<f32>(x, y, 0.0, 1.0);
out.position = vec2<f32>(x, y);
return out;
}
// Fragment shader
[[stage(fragment)]]
fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
let r = in.position.x;
let g = in.position.y;
return vec4<f32>(r, g, 0.1, 1.0);
}

View File

@@ -6,6 +6,7 @@ use winit::{
mod state; mod state;
mod vertex; mod vertex;
mod texture;
use crate::state::State; use crate::state::State;

View File

@@ -1,24 +1,30 @@
// Vertex shader // Vertex shader
struct VertexInput { struct VertexInput {
[[location(0)]] position: vec3<f32>; [[location(0)]] position: vec3<f32>;
[[location(1)]] color: vec3<f32>; [[location(1)]] texture_coords: vec2<f32>;
}; };
struct VertexOutput { struct VertexOutput {
[[builtin(position)]] clip_coordinate: vec4<f32>; [[builtin(position)]] clip_coordinate: vec4<f32>;
[[location(0)]] color: vec3<f32>; [[location(0)]] texture_coords: vec2<f32>;
}; };
[[stage(vertex)]] [[stage(vertex)]]
fn main(model: VertexInput) -> VertexOutput { fn main(model: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
out.clip_coordinate = vec4<f32>(model.position, 1.0); out.clip_coordinate = vec4<f32>(model.position, 1.0);
out.color = model.color; out.texture_coords = model.texture_coords;
return out; return out;
} }
// Fragment shader // Fragment shader
[[group(0), binding(0)]]
var t_aqua: texture_2d<f32>;
[[group(0), binding(1)]]
var s_aqua: sampler;
[[stage(fragment)]] [[stage(fragment)]]
fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> { fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
return vec4<f32>(in.color, 1.0); //return vec4<f32>(in.color, 1.0);
return textureSample(t_aqua, s_aqua, in.texture_coords);
} }

View File

@@ -7,22 +7,27 @@ use winit::{
window::Window, window::Window,
}; };
use crate::vertex::Vertex; use crate::{texture, vertex::Vertex};
/// Hold state with important information /// Hold state with important information
pub struct State { pub struct State {
surface: wgpu::Surface, surface: wgpu::Surface,
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
sc_desc: wgpu::SwapChainDescriptor, sc_desc: wgpu::SwapChainDescriptor,
swap_chain: wgpu::SwapChain, swap_chain: wgpu::SwapChain,
pub size: winit::dpi::PhysicalSize<u32>, pub size: winit::dpi::PhysicalSize<u32>,
clear_color: wgpu::Color,
render_pipeline: wgpu::RenderPipeline, render_pipeline: wgpu::RenderPipeline,
//challenge_render_pipeline: wgpu::RenderPipeline,
use_challenge_render_pipeline: bool,
vertex_buffer: wgpu::Buffer, vertex_buffer: wgpu::Buffer,
num_vertices: u32, index_buffer: wgpu::Buffer,
num_indices: u32,
aqua_bind_group: wgpu::BindGroup,
aqua_texture: texture::Texture,
} }
impl State { impl State {
@@ -73,6 +78,55 @@ impl State {
// actually create a swap_chain // actually create a swap_chain
let swap_chain = device.create_swap_chain(&surface, &sc_desc); let swap_chain = device.create_swap_chain(&surface, &sc_desc);
let aqua_bytes = include_bytes!("../img/aqua.png");
let aqua_texture = texture::Texture::from_bytes(&device, &queue, aqua_bytes, "aqua").unwrap();
let texture_bind_group_layout = device.create_bind_group_layout(
&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler {
comparison: false,
filtering: true,
},
count: None,
},
],
label: Some("texture_bind_group_layout"),
}
);
// bind groups can be changed on the fly, as long as they're in the same layout
// every texture and sampler needs to be added to a bindgroup
let aqua_bind_group = device.create_bind_group(
&wgpu::BindGroupDescriptor {
layout: &texture_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&aqua_texture.view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&aqua_texture.sampler),
}
],
label: Some("diffuse_bind_group"),
}
);
// load shader file // load shader file
let shader = device.create_shader_module( let shader = device.create_shader_module(
&wgpu::ShaderModuleDescriptor { &wgpu::ShaderModuleDescriptor {
@@ -82,11 +136,10 @@ impl State {
} }
); );
// TODO
let render_pipeline_layout = device.create_pipeline_layout( let render_pipeline_layout = device.create_pipeline_layout(
&wgpu::PipelineLayoutDescriptor { &wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layput"), label: Some("Render Pipeline Layput"),
bind_group_layouts: &[], bind_group_layouts: &[&texture_bind_group_layout],
push_constant_ranges: &[], push_constant_ranges: &[],
} }
); );
@@ -136,72 +189,6 @@ impl State {
} }
} }
); );
/*
// overwrite challenge shader file to shader
let shader = device.create_shader_module(
&wgpu::ShaderModuleDescriptor {
label: Some("Shader"),
flags: wgpu::ShaderFlags::all(),
source: wgpu::ShaderSource::Wgsl(
include_str!("challenge_shader.wgsl").into()),
}
);
// TODO
let render_pipeline_layout = device.create_pipeline_layout(
&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layput"),
bind_group_layouts: &[],
push_constant_ranges: &[],
}
);
// add everything to the challnge_render_pipeline
let challenge_render_pipeline = device.create_render_pipeline(
&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
// function name in shader.wgsl for [[stage(vertex)]]
entry_point: "main",
// already specified in the shader
buffers: &[],
},
// needed to sotre color data to swap_chain
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "main",
// setup of color outputs
targets: &[wgpu::ColorTargetState {
format: sc_desc.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrite::ALL,
}],
}),
primitive: wgpu::PrimitiveState {
topology: PrimitiveTopology::TriangleList,
strip_index_format: None,
// triangle facing forward when Counter Clock Wise
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
polygon_mode: wgpu::PolygonMode::Fill,
clamp_depth: false,
conservative: false,
},
depth_stencil: None,
multisample: wgpu::MultisampleState {
// only use 1 sample => no extra sampling
count: 1,
// use all
mask: !0,
// not using anti aliasing
alpha_to_coverage_enabled: false,
}
}
);
*/
let vertex_buffer = device.create_buffer_init( let vertex_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor { &wgpu::util::BufferInitDescriptor {
@@ -211,7 +198,15 @@ impl State {
} }
); );
let num_vertices = crate::vertex::VERTICES.len() as u32; let index_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Index Buffer"),
contents: bytemuck::cast_slice(crate::vertex::INDICES),
usage: wgpu::BufferUsage::INDEX,
}
);
let num_indices = crate::vertex::INDICES.len() as u32;
Self { Self {
surface, surface,
@@ -220,12 +215,12 @@ impl State {
sc_desc, // saved, so we can create a new swap_chain later sc_desc, // saved, so we can create a new swap_chain later
swap_chain, swap_chain,
size, size,
clear_color: wgpu::Color { r: 0.6, g: 0.6, b: 0.1, a: 1.0 },
render_pipeline, render_pipeline,
//challenge_render_pipeline,
use_challenge_render_pipeline: false,
vertex_buffer, vertex_buffer,
num_vertices, index_buffer,
num_indices,
aqua_bind_group,
aqua_texture,
} }
} }
@@ -242,23 +237,23 @@ impl State {
/// Idicate, whether an event has been fully processed /// Idicate, whether an event has been fully processed
pub fn input(&mut self, event: &WindowEvent) -> bool { pub fn input(&mut self, event: &WindowEvent) -> bool {
match event { match event {
WindowEvent::CursorMoved { position, .. } => { // WindowEvent::CursorMoved { position, .. } => {
let x = (position.x as f64) / self.size.width as f64; // let x = (position.x as f64) / self.size.width as f64;
let y = (position.y as f64) / self.size.height as f64; // let y = (position.y as f64) / self.size.height as f64;
self.clear_color = wgpu::Color { r: x, g: x, b: y, a: 1.0}; // self.clear_color = wgpu::Color { r: x, g: x, b: y, a: 1.0};
true // true
}, // },
WindowEvent::KeyboardInput { // WindowEvent::KeyboardInput {
input: KeyboardInput { // input: KeyboardInput {
state: ElementState::Pressed, // state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Space), // virtual_keycode: Some(VirtualKeyCode::Space),
.. // ..
}, // },
.. // ..
} => { // } => {
self.use_challenge_render_pipeline = !self.use_challenge_render_pipeline; // self.use_pentagon = !self.use_pentagon;
true // true
} // }
_ => false _ => false
} }
} }
@@ -288,7 +283,8 @@ impl State {
view: &frame.view, // draw to current screen view: &frame.view, // draw to current screen
resolve_target: None, // no multisampling yet resolve_target: None, // no multisampling yet
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(self.clear_color), load: wgpu::LoadOp::Clear(
wgpu::Color { r: 0.2, g: 0.5, b: 0.5, a: 1.0 }),
store: true, store: true,
} }
} }
@@ -296,18 +292,13 @@ impl State {
depth_stencil_attachment: None, depth_stencil_attachment: None,
}); });
// set pipeline
/*
if self.use_challenge_render_pipeline {
render_pass.set_pipeline(&self.challenge_render_pipeline);
} else {
render_pass.set_pipeline(&self.render_pipeline);
}
*/
render_pass.set_pipeline(&self.render_pipeline); render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
render_pass.set_bind_group(0, &self.aqua_bind_group, &[]);
// draw triangle // draw triangle
render_pass.draw(0..self.num_vertices, 0..1); render_pass.draw_indexed(0..self.num_indices, 0, 0..1);
//render_pass.draw(0..self.num_vertices, 0..1);
// drop so encoder isn't borrowed mutually anymore // drop so encoder isn't borrowed mutually anymore
drop(render_pass); drop(render_pass);

83
src/texture.rs Normal file
View File

@@ -0,0 +1,83 @@
use anyhow::*;
use image::GenericImageView;
pub struct Texture {
pub texture: wgpu::Texture,
pub view: wgpu::TextureView,
pub sampler: wgpu::Sampler,
}
impl Texture {
pub fn from_bytes(
device: &wgpu::Device,
queue: &wgpu::Queue,
bytes: &[u8],
label: &str,
) -> Result<Self> {
let img = image::load_from_memory(bytes)?;
Self::from_image(device, queue, &img, Some(label))
}
pub fn from_image(
device: &wgpu::Device,
queue: &wgpu::Queue,
img: &image::DynamicImage,
label: Option<&str>,
) -> Result<Self> {
let rgba = img.as_rgba8().unwrap();
let dimensions = rgba.dimensions();
let size = wgpu::Extent3d {
width: dimensions.0,
height: dimensions.1,
depth_or_array_layers: 1,
};
let texture = device.create_texture(&wgpu::TextureDescriptor {
label,
size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
// SAMPLED: use texture in shaders
// COPY_DST: copy data to this texture
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
});
// write texture into Texture
queue.write_texture(
wgpu::ImageCopyTexture {
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
},
// actual image data
rgba,
wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0),
rows_per_image: std::num::NonZeroU32::new(dimensions.1),
},
size,
);
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Nearest,
mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
});
Ok(Self {
texture,
view,
sampler,
})
}
}

View File

@@ -2,7 +2,7 @@
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Vertex { pub struct Vertex {
position: [f32; 3], position: [f32; 3],
color: [f32; 3], texture_coords: [f32; 2],
} }
impl Vertex { impl Vertex {
@@ -21,7 +21,7 @@ impl Vertex {
wgpu::VertexAttribute { wgpu::VertexAttribute {
offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
shader_location: 1, shader_location: 1,
format: wgpu::VertexFormat::Float32x3, format: wgpu::VertexFormat::Float32x2,
}, },
], ],
} }
@@ -29,19 +29,18 @@ impl Vertex {
} }
pub const VERTICES: &[Vertex] = &[ pub const VERTICES: &[Vertex] = &[
// Top Vertex { position: [-0.0868241, 0.49240386, 0.0], texture_coords: [0.4131759, 0.00759614], }, // A
Vertex { Vertex { position: [-0.49513406, 0.06958647, 0.0], texture_coords: [0.0048659444, 0.43041354], }, // B
position: [0.0, 0.5, 0.0], Vertex { position: [-0.21918549, -0.44939706, 0.0], texture_coords: [0.28081453, 0.949397], }, // C
color: [1.0, 0.0, 0.0], Vertex { position: [0.35966998, -0.3473291, 0.0], texture_coords: [0.85967, 0.84732914], }, // D
}, Vertex { position: [0.44147372, 0.2347359, 0.0], texture_coords: [0.9414737, 0.2652641], }, // E
// Left ];
Vertex {
position: [-0.5, -0.5, 0.0], pub const INDICES: &[u16] = &[
color: [0.0, 1.0, 0.0], // pentagon
}, 0, 1, 4,
// Right 1, 2, 4,
Vertex { 2, 3, 4,
position: [0.5, -0.5, 0.0], // padding
color: [0.0, 0.0, 1.0], 0,
},
]; ];