mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-21 22:33:49 +00:00
[rs] Mipmapping example
This commit is contained in:
parent
154ed3a9a5
commit
2b047f996b
3
.gitignore
vendored
3
.gitignore
vendored
@ -8,3 +8,6 @@ Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# Other
|
||||
.DS_Store
|
||||
|
@ -24,7 +24,7 @@ gl = ["wgn/gfx-backend-gl"]
|
||||
|
||||
[dependencies]
|
||||
#TODO: only depend on the published version
|
||||
wgn = { package = "wgpu-native", features = ["local", "window-winit"], git = "https://github.com/gfx-rs/wgpu", rev = "8cc50253c428fb0a9aab3c74639a866465d65272" }
|
||||
wgn = { package = "wgpu-native", version = "0.2.6", features = ["local", "window-winit"], git = "https://github.com/gfx-rs/wgpu", rev = "a667d50d01c3df03b8540c523278e111da7fc82a" }
|
||||
arrayvec = "0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
|
10
wgpu/examples/mipmap/blit.frag
Normal file
10
wgpu/examples/mipmap/blit.frag
Normal file
@ -0,0 +1,10 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 v_TexCoord;
|
||||
layout(location = 0) out vec4 o_Target;
|
||||
layout(set = 0, binding = 0) uniform texture2D t_Color;
|
||||
layout(set = 0, binding = 1) uniform sampler s_Color;
|
||||
|
||||
void main() {
|
||||
o_Target = textureLod(sampler2D(t_Color, s_Color), v_TexCoord, 0.0);
|
||||
}
|
15
wgpu/examples/mipmap/blit.vert
Normal file
15
wgpu/examples/mipmap/blit.vert
Normal file
@ -0,0 +1,15 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec2 v_TexCoord;
|
||||
|
||||
void main() {
|
||||
vec2 tc = vec2(0.0);
|
||||
switch(gl_VertexIndex) {
|
||||
case 0: tc = vec2(1.0, 0.0); break;
|
||||
case 1: tc = vec2(1.0, 1.0); break;
|
||||
case 2: tc = vec2(0.0, 0.0); break;
|
||||
case 3: tc = vec2(0.0, 1.0); break;
|
||||
}
|
||||
v_TexCoord = tc;
|
||||
gl_Position = vec4(tc * 2.0 - 1.0, 0.5, 1.0);
|
||||
}
|
12
wgpu/examples/mipmap/draw.frag
Normal file
12
wgpu/examples/mipmap/draw.frag
Normal file
@ -0,0 +1,12 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 v_TexCoord;
|
||||
layout(location = 0) out vec4 o_Target;
|
||||
layout(set = 0, binding = 1) uniform texture2D t_Color;
|
||||
layout(set = 0, binding = 2) uniform sampler s_Color;
|
||||
|
||||
void main() {
|
||||
vec4 tex = texture(sampler2D(t_Color, s_Color), v_TexCoord);
|
||||
float mag = length(v_TexCoord-vec2(0.5));
|
||||
o_Target = mix(tex, vec4(0.0), mag*mag);
|
||||
}
|
15
wgpu/examples/mipmap/draw.vert
Normal file
15
wgpu/examples/mipmap/draw.vert
Normal file
@ -0,0 +1,15 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec4 a_Pos;
|
||||
layout(location = 0) out vec2 v_TexCoord;
|
||||
|
||||
layout(set = 0, binding = 0) uniform Locals {
|
||||
mat4 u_Transform;
|
||||
};
|
||||
|
||||
void main() {
|
||||
v_TexCoord = a_Pos.xy / 10.0;
|
||||
gl_Position = u_Transform * a_Pos;
|
||||
// convert from -1,1 Z to 0,1
|
||||
gl_Position.z = 0.5 * (gl_Position.z + gl_Position.w);
|
||||
}
|
419
wgpu/examples/mipmap/main.rs
Normal file
419
wgpu/examples/mipmap/main.rs
Normal file
@ -0,0 +1,419 @@
|
||||
#[path = "../framework.rs"]
|
||||
mod framework;
|
||||
|
||||
const TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::R8Unorm;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Vertex {
|
||||
#[allow(dead_code)]
|
||||
pos: [f32; 4],
|
||||
}
|
||||
|
||||
fn create_vertices() -> Vec<Vertex> {
|
||||
vec![
|
||||
Vertex {
|
||||
pos: [100.0, 0.0, 0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
pos: [100.0, 1000.0, 0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
pos: [-100.0, 0.0, 0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
pos: [-100.0, 1000.0, 0.0, 1.0],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn create_texels(size: usize) -> Vec<u8> {
|
||||
(0 .. size * size)
|
||||
.map(|id| {
|
||||
if (id + id / size) % 2 == 1 {
|
||||
0xFF
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
struct Example {
|
||||
vertex_buf: wgpu::Buffer,
|
||||
bind_group: wgpu::BindGroup,
|
||||
uniform_buf: wgpu::Buffer,
|
||||
draw_pipeline: wgpu::RenderPipeline,
|
||||
}
|
||||
|
||||
impl Example {
|
||||
fn generate_matrix(aspect_ratio: f32) -> cgmath::Matrix4<f32> {
|
||||
let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 1000.0);
|
||||
let mx_view = cgmath::Matrix4::look_at(
|
||||
cgmath::Point3::new(0f32, 0.0, 10.0),
|
||||
cgmath::Point3::new(0f32, 100.0, 0.0),
|
||||
-cgmath::Vector3::unit_z(),
|
||||
);
|
||||
mx_projection * mx_view
|
||||
}
|
||||
|
||||
fn generate_mipmaps(
|
||||
device: &wgpu::Device, texture: &wgpu::Texture, mip_count: u32
|
||||
) -> wgpu::CommandBuffer {
|
||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
bindings: &[
|
||||
wgpu::BindGroupLayoutBinding {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::SampledTexture,
|
||||
},
|
||||
wgpu::BindGroupLayoutBinding {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler,
|
||||
},
|
||||
],
|
||||
});
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: &[&bind_group_layout],
|
||||
});
|
||||
|
||||
let vs_bytes = framework::load_glsl(
|
||||
include_str!("blit.vert"),
|
||||
framework::ShaderStage::Vertex,
|
||||
);
|
||||
let fs_bytes = framework::load_glsl(
|
||||
include_str!("blit.frag"),
|
||||
framework::ShaderStage::Fragment,
|
||||
);
|
||||
let vs_module = device.create_shader_module(&vs_bytes);
|
||||
let fs_module = device.create_shader_module(&fs_bytes);
|
||||
|
||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
layout: &pipeline_layout,
|
||||
vertex_stage: wgpu::PipelineStageDescriptor {
|
||||
module: &vs_module,
|
||||
entry_point: "main",
|
||||
},
|
||||
fragment_stage: Some(wgpu::PipelineStageDescriptor {
|
||||
module: &fs_module,
|
||||
entry_point: "main",
|
||||
}),
|
||||
rasterization_state: wgpu::RasterizationStateDescriptor {
|
||||
front_face: wgpu::FrontFace::Cw,
|
||||
cull_mode: wgpu::CullMode::None,
|
||||
depth_bias: 0,
|
||||
depth_bias_slope_scale: 0.0,
|
||||
depth_bias_clamp: 0.0,
|
||||
},
|
||||
primitive_topology: wgpu::PrimitiveTopology::TriangleStrip,
|
||||
color_states: &[wgpu::ColorStateDescriptor {
|
||||
format: TEXTURE_FORMAT,
|
||||
color_blend: wgpu::BlendDescriptor::REPLACE,
|
||||
alpha_blend: wgpu::BlendDescriptor::REPLACE,
|
||||
write_mask: wgpu::ColorWrite::ALL,
|
||||
}],
|
||||
depth_stencil_state: None,
|
||||
index_format: wgpu::IndexFormat::Uint16,
|
||||
vertex_buffers: &[],
|
||||
sample_count: 1,
|
||||
});
|
||||
|
||||
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::Nearest,
|
||||
min_filter: wgpu::FilterMode::Nearest,
|
||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||
lod_min_clamp: -100.0,
|
||||
lod_max_clamp: 100.0,
|
||||
compare_function: wgpu::CompareFunction::Always,
|
||||
});
|
||||
|
||||
let views = (0 .. mip_count)
|
||||
.map(|mip| texture.create_view(&wgpu::TextureViewDescriptor {
|
||||
format: TEXTURE_FORMAT,
|
||||
dimension: wgpu::TextureViewDimension::D2,
|
||||
aspect: wgpu::TextureAspectFlags::COLOR,
|
||||
base_mip_level: mip,
|
||||
level_count: 1,
|
||||
base_array_layer: 0,
|
||||
array_count: 1,
|
||||
}))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut encoder = device.create_command_encoder(
|
||||
&wgpu::CommandEncoderDescriptor { todo: 0 }
|
||||
);
|
||||
|
||||
for target_mip in 1 .. mip_count as usize {
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &bind_group_layout,
|
||||
bindings: &[
|
||||
wgpu::Binding {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(&views[target_mip - 1]),
|
||||
},
|
||||
wgpu::Binding {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Sampler(&sampler),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &views[target_mip],
|
||||
resolve_target: None,
|
||||
load_op: wgpu::LoadOp::Clear,
|
||||
store_op: wgpu::StoreOp::Store,
|
||||
clear_color: wgpu::Color::WHITE,
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
rpass.set_pipeline(&pipeline);
|
||||
rpass.set_bind_group(0, &bind_group, &[]);
|
||||
rpass.draw(0 .. 4, 0 .. 1);
|
||||
}
|
||||
|
||||
encoder.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl framework::Example for Example {
|
||||
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) -> Self {
|
||||
use std::mem;
|
||||
|
||||
let mut init_encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
||||
|
||||
// Create the vertex and index buffers
|
||||
let vertex_size = mem::size_of::<Vertex>();
|
||||
let vertex_data = create_vertices();
|
||||
let vertex_buf = device
|
||||
.create_buffer_mapped(vertex_data.len(), wgpu::BufferUsage::VERTEX)
|
||||
.fill_from_slice(&vertex_data);
|
||||
|
||||
// Create pipeline layout
|
||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
bindings: &[
|
||||
wgpu::BindGroupLayoutBinding {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::VERTEX,
|
||||
ty: wgpu::BindingType::UniformBuffer,
|
||||
},
|
||||
wgpu::BindGroupLayoutBinding {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::SampledTexture,
|
||||
},
|
||||
wgpu::BindGroupLayoutBinding {
|
||||
binding: 2,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler,
|
||||
},
|
||||
],
|
||||
});
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: &[&bind_group_layout],
|
||||
});
|
||||
|
||||
// Create the texture
|
||||
let mip_level_count = 10;
|
||||
let size = 1 << mip_level_count;
|
||||
let texels = create_texels(size as usize);
|
||||
let texture_extent = wgpu::Extent3d {
|
||||
width: size,
|
||||
height: size,
|
||||
depth: 1,
|
||||
};
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
size: texture_extent,
|
||||
array_layer_count: 1,
|
||||
mip_level_count,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: TEXTURE_FORMAT,
|
||||
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::TRANSFER_DST,
|
||||
});
|
||||
let texture_view = texture.create_default_view();
|
||||
let temp_buf = device
|
||||
.create_buffer_mapped(texels.len(), wgpu::BufferUsage::TRANSFER_SRC)
|
||||
.fill_from_slice(&texels);
|
||||
init_encoder.copy_buffer_to_texture(
|
||||
wgpu::BufferCopyView {
|
||||
buffer: &temp_buf,
|
||||
offset: 0,
|
||||
row_pitch: 1 * size,
|
||||
image_height: size,
|
||||
},
|
||||
wgpu::TextureCopyView {
|
||||
texture: &texture,
|
||||
mip_level: 0,
|
||||
array_layer: 0,
|
||||
origin: wgpu::Origin3d {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
},
|
||||
},
|
||||
texture_extent,
|
||||
);
|
||||
|
||||
// Create other resources
|
||||
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
address_mode_u: wgpu::AddressMode::Repeat,
|
||||
address_mode_v: wgpu::AddressMode::Repeat,
|
||||
address_mode_w: wgpu::AddressMode::Repeat,
|
||||
mag_filter: wgpu::FilterMode::Linear,
|
||||
min_filter: wgpu::FilterMode::Linear,
|
||||
mipmap_filter: wgpu::FilterMode::Linear,
|
||||
lod_min_clamp: -100.0,
|
||||
lod_max_clamp: 100.0,
|
||||
compare_function: wgpu::CompareFunction::Always,
|
||||
});
|
||||
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
|
||||
let mx_ref: &[f32; 16] = mx_total.as_ref();
|
||||
let uniform_buf = device
|
||||
.create_buffer_mapped(
|
||||
16,
|
||||
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::TRANSFER_DST,
|
||||
)
|
||||
.fill_from_slice(mx_ref);
|
||||
|
||||
// Create bind group
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &bind_group_layout,
|
||||
bindings: &[
|
||||
wgpu::Binding {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer {
|
||||
buffer: &uniform_buf,
|
||||
range: 0 .. 64,
|
||||
},
|
||||
},
|
||||
wgpu::Binding {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::TextureView(&texture_view),
|
||||
},
|
||||
wgpu::Binding {
|
||||
binding: 2,
|
||||
resource: wgpu::BindingResource::Sampler(&sampler),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Create the render pipeline
|
||||
let vs_bytes = framework::load_glsl(
|
||||
include_str!("draw.vert"),
|
||||
framework::ShaderStage::Vertex,
|
||||
);
|
||||
let fs_bytes = framework::load_glsl(
|
||||
include_str!("draw.frag"),
|
||||
framework::ShaderStage::Fragment,
|
||||
);
|
||||
let vs_module = device.create_shader_module(&vs_bytes);
|
||||
let fs_module = device.create_shader_module(&fs_bytes);
|
||||
|
||||
let draw_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
layout: &pipeline_layout,
|
||||
vertex_stage: wgpu::PipelineStageDescriptor {
|
||||
module: &vs_module,
|
||||
entry_point: "main",
|
||||
},
|
||||
fragment_stage: Some(wgpu::PipelineStageDescriptor {
|
||||
module: &fs_module,
|
||||
entry_point: "main",
|
||||
}),
|
||||
rasterization_state: wgpu::RasterizationStateDescriptor {
|
||||
front_face: wgpu::FrontFace::Cw,
|
||||
cull_mode: wgpu::CullMode::Back,
|
||||
depth_bias: 0,
|
||||
depth_bias_slope_scale: 0.0,
|
||||
depth_bias_clamp: 0.0,
|
||||
},
|
||||
primitive_topology: wgpu::PrimitiveTopology::TriangleStrip,
|
||||
color_states: &[wgpu::ColorStateDescriptor {
|
||||
format: sc_desc.format,
|
||||
color_blend: wgpu::BlendDescriptor::REPLACE,
|
||||
alpha_blend: wgpu::BlendDescriptor::REPLACE,
|
||||
write_mask: wgpu::ColorWrite::ALL,
|
||||
}],
|
||||
depth_stencil_state: None,
|
||||
index_format: wgpu::IndexFormat::Uint16,
|
||||
vertex_buffers: &[wgpu::VertexBufferDescriptor {
|
||||
stride: vertex_size as wgpu::BufferAddress,
|
||||
step_mode: wgpu::InputStepMode::Vertex,
|
||||
attributes: &[
|
||||
wgpu::VertexAttributeDescriptor {
|
||||
format: wgpu::VertexFormat::Float4,
|
||||
offset: 0,
|
||||
shader_location: 0,
|
||||
},
|
||||
],
|
||||
}],
|
||||
sample_count: 1,
|
||||
});
|
||||
|
||||
// Done
|
||||
let init_command_buf = init_encoder.finish();
|
||||
let mipmap_command_buf = Self::generate_mipmaps(&device, &texture, mip_level_count);
|
||||
device.get_queue().submit(&[init_command_buf, mipmap_command_buf]);
|
||||
Example {
|
||||
vertex_buf,
|
||||
bind_group,
|
||||
uniform_buf,
|
||||
draw_pipeline,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _event: wgpu::winit::WindowEvent) {
|
||||
//empty
|
||||
}
|
||||
|
||||
fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) {
|
||||
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
|
||||
let mx_ref: &[f32; 16] = mx_total.as_ref();
|
||||
|
||||
let temp_buf = device
|
||||
.create_buffer_mapped(16, wgpu::BufferUsage::TRANSFER_SRC)
|
||||
.fill_from_slice(mx_ref);
|
||||
|
||||
let mut encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
||||
encoder.copy_buffer_to_buffer(&temp_buf, 0, &self.uniform_buf, 0, 64);
|
||||
device.get_queue().submit(&[encoder.finish()]);
|
||||
}
|
||||
|
||||
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
|
||||
let mut encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
||||
{
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &frame.view,
|
||||
resolve_target: None,
|
||||
load_op: wgpu::LoadOp::Clear,
|
||||
store_op: wgpu::StoreOp::Store,
|
||||
clear_color: wgpu::Color {
|
||||
r: 0.1,
|
||||
g: 0.2,
|
||||
b: 0.3,
|
||||
a: 1.0,
|
||||
},
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
rpass.set_pipeline(&self.draw_pipeline);
|
||||
rpass.set_bind_group(0, &self.bind_group, &[]);
|
||||
rpass.set_vertex_buffers(&[(&self.vertex_buf, 0)]);
|
||||
rpass.draw(0 .. 4, 0 .. 1);
|
||||
}
|
||||
|
||||
device.get_queue().submit(&[encoder.finish()]);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
framework::run::<Example>("cube");
|
||||
}
|
Loading…
Reference in New Issue
Block a user