mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
[rs] Added example for conservative rasterization (#791)
* Example for conservative rasterization * Update to wgpu-core/types 717c2d73e725c064a3c4696d6d7bdb428c9500b6 * conservative-raster example: fix wglsl const & readme * conservative raster example: optional lines, no more interaction
This commit is contained in:
parent
23c5e83167
commit
2bda1508f1
@ -26,20 +26,20 @@ webgl = ["wgc"]
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgc]
|
||||
package = "wgpu-core"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "5e15980bb53d2a5c24546dab640dcc72d211bd36"
|
||||
rev = "717c2d73e725c064a3c4696d6d7bdb428c9500b6"
|
||||
features = ["raw-window-handle", "cross"]
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.wgc]
|
||||
package = "wgpu-core"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "5e15980bb53d2a5c24546dab640dcc72d211bd36"
|
||||
rev = "717c2d73e725c064a3c4696d6d7bdb428c9500b6"
|
||||
features = ["raw-window-handle", "cross"]
|
||||
optional = true
|
||||
|
||||
[dependencies.wgt]
|
||||
package = "wgpu-types"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "5e15980bb53d2a5c24546dab640dcc72d211bd36"
|
||||
rev = "717c2d73e725c064a3c4696d6d7bdb428c9500b6"
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.5"
|
||||
|
||||
@ -10,40 +10,41 @@ Notably, `capture` example shows rendering without a surface/window. It reads ba
|
||||
All framework-based examples render to the window.
|
||||
|
||||
## Feature matrix
|
||||
| Feature | boids | cube | mipmap | msaa-line | shadow | skybox | texture-arrays | water |
|
||||
| ---------------------- | ------ | ------ | ------ | --------- | ------ | ------ | -------------- | ------ |
|
||||
| WGSL shaders | :star: | :star: | :star: | :star: | :star: | :star: | | |
|
||||
| vertex attributes | :star: | :star: | | :star: | :star: | :star: | :star: | :star: |
|
||||
| instancing | :star: | | | | | | | |
|
||||
| lines and points | | | | :star: | | | | |
|
||||
| dynamic buffer offsets | | | | | :star: | | | |
|
||||
| implicit layout | | | :star: | | | | | |
|
||||
| sampled color textures | :star: | :star: | :star: | | | :star: | :star: | :star: |
|
||||
| storage textures | :star: | | | | | | | |
|
||||
| binding array | | | | | | | :star: | |
|
||||
| comparison samplers | | | | | :star: | | | |
|
||||
| subresource views | | | :star: | | :star: | | | |
|
||||
| cubemaps | | | | | | :star: | | |
|
||||
| multisampling | | | | :star: | | | | |
|
||||
| off-screen rendering | | | | | :star: | | | :star: |
|
||||
| stencil testing | | | | | | | | |
|
||||
| depth testing | | | | | :star: | :star: | | :star: |
|
||||
| depth biasing | | | | | :star: | | | |
|
||||
| read-only depth | | | | | | | | :star: |
|
||||
| blending | | :star: | | | | | | :star: |
|
||||
| render bundles | | | | :star: | | | | :star: |
|
||||
| compute passes | :star: | | | | | | | |
|
||||
| *optional extensions* | | | | | | | :star: | |
|
||||
| - binding indexing | | | | | | | :star: | |
|
||||
| - push constants | | | | | | | :star: | |
|
||||
| - depth clamping | | | | | :star: | | | |
|
||||
| - compressed textures | | | | | | :star: | | |
|
||||
| - polygon mode | | :star: | | | | | | |
|
||||
| - queries | | | :star: | | | | | |
|
||||
| *integrations* | | | | | | | | |
|
||||
| - staging belt | | | | | | | | |
|
||||
| - typed arena | | | | | | | | |
|
||||
| - obj loading | | | | | | :star: | | |
|
||||
| Feature | boids | cube | mipmap | msaa-line | shadow | skybox | texture-arrays | water | conservative-raster |
|
||||
| ---------------------------- | ------ | ------ | ------ | --------- | ------ | ------ | -------------- | ------ | ------------------- |
|
||||
| WGSL shaders | :star: | :star: | :star: | :star: | :star: | :star: | | | :star: |
|
||||
| vertex attributes | :star: | :star: | | :star: | :star: | :star: | :star: | :star: | |
|
||||
| instancing | :star: | | | | | | | | |
|
||||
| lines and points | | | | :star: | | | | | :star: |
|
||||
| dynamic buffer offsets | | | | | :star: | | | | |
|
||||
| implicit layout | | | :star: | | | | | | |
|
||||
| sampled color textures | :star: | :star: | :star: | | | :star: | :star: | :star: | :star: |
|
||||
| storage textures | :star: | | | | | | | | |
|
||||
| binding array | | | | | | | :star: | | |
|
||||
| comparison samplers | | | | | :star: | | | | |
|
||||
| subresource views | | | :star: | | :star: | | | | |
|
||||
| cubemaps | | | | | | :star: | | | |
|
||||
| multisampling | | | | :star: | | | | | |
|
||||
| off-screen rendering | | | | | :star: | | | :star: | :star: |
|
||||
| stencil testing | | | | | | | | | |
|
||||
| depth testing | | | | | :star: | :star: | | :star: | |
|
||||
| depth biasing | | | | | :star: | | | | |
|
||||
| read-only depth | | | | | | | | :star: | |
|
||||
| blending | | :star: | | | | | | :star: | |
|
||||
| render bundles | | | | :star: | | | | :star: | |
|
||||
| compute passes | :star: | | | | | | | | |
|
||||
| *optional extensions* | | | | | | | :star: | | |
|
||||
| - binding indexing | | | | | | | :star: | | |
|
||||
| - push constants | | | | | | | :star: | | |
|
||||
| - depth clamping | | | | | :star: | | | | |
|
||||
| - compressed textures | | | | | | :star: | | | |
|
||||
| - polygon mode | | :star: | | | | | | | |
|
||||
| - queries | | | :star: | | | | | | |
|
||||
| - conservative rasterization | | | | | | | | | :star: |
|
||||
| *integrations* | | | | | | | | | |
|
||||
| - staging belt | | | | | | | | | |
|
||||
| - typed arena | | | | | | | | | |
|
||||
| - obj loading | | | | | | :star: | | | |
|
||||
|
||||
## Hacking
|
||||
|
||||
|
||||
20
wgpu/examples/conservative-raster/README.md
Normal file
20
wgpu/examples/conservative-raster/README.md
Normal file
@ -0,0 +1,20 @@
|
||||
# conservative-raster
|
||||
|
||||
This example shows how to render with conservative rasterization (native extension with limited support).
|
||||
|
||||
When enabled, any pixel touched by a triangle primitive is rasterized.
|
||||
This is useful for various advanced techniques, most prominently for implementing realtime voxelization.
|
||||
|
||||
The demonstration here is implemented by rendering a triangle to a low-resolution target and then upscaling it with nearest-neighbor filtering.
|
||||
The outlines of the triangle are then rendered in the original solution, using the same vertex shader as the triangle.
|
||||
Pixels only drawn with conservative rasterization enabled are depicted red.
|
||||
|
||||
## To Run
|
||||
|
||||
```
|
||||
cargo run --example conservative-raster
|
||||
```
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||
316
wgpu/examples/conservative-raster/main.rs
Normal file
316
wgpu/examples/conservative-raster/main.rs
Normal file
@ -0,0 +1,316 @@
|
||||
#[path = "../framework.rs"]
|
||||
mod framework;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
const RENDER_TARGET_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8UnormSrgb;
|
||||
|
||||
struct Example {
|
||||
low_res_target: wgpu::TextureView,
|
||||
bind_group_upscale: wgpu::BindGroup,
|
||||
|
||||
pipeline_triangle_conservative: wgpu::RenderPipeline,
|
||||
pipeline_triangle_regular: wgpu::RenderPipeline,
|
||||
pipeline_upscale: wgpu::RenderPipeline,
|
||||
pipeline_lines: Option<wgpu::RenderPipeline>,
|
||||
bind_group_layout_upscale: wgpu::BindGroupLayout,
|
||||
}
|
||||
|
||||
impl Example {
|
||||
fn create_low_res_target(
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
device: &wgpu::Device,
|
||||
bind_group_layout_upscale: &wgpu::BindGroupLayout,
|
||||
) -> (wgpu::TextureView, wgpu::BindGroup) {
|
||||
let texture_view = device
|
||||
.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("Low Resolution Target"),
|
||||
size: wgpu::Extent3d {
|
||||
width: sc_desc.width / 16,
|
||||
height: sc_desc.width / 16,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: RENDER_TARGET_FORMAT,
|
||||
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::RENDER_ATTACHMENT,
|
||||
})
|
||||
.create_view(&Default::default());
|
||||
|
||||
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
label: Some("Nearest Neighbor Sampler"),
|
||||
mag_filter: wgpu::FilterMode::Nearest,
|
||||
min_filter: wgpu::FilterMode::Nearest,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: Some("upscale bind group"),
|
||||
layout: &bind_group_layout_upscale,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(&texture_view),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Sampler(&sampler),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
(texture_view, bind_group)
|
||||
}
|
||||
}
|
||||
|
||||
impl framework::Example for Example {
|
||||
fn required_features() -> wgpu::Features {
|
||||
wgpu::Features::CONSERVATIVE_RASTERIZATION
|
||||
}
|
||||
fn optional_features() -> wgpu::Features {
|
||||
wgpu::Features::NON_FILL_POLYGON_MODE
|
||||
}
|
||||
fn init(
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
adapter: &wgpu::Adapter,
|
||||
device: &wgpu::Device,
|
||||
_queue: &wgpu::Queue,
|
||||
) -> Self {
|
||||
let pipeline_layout_empty =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: None,
|
||||
bind_group_layouts: &[],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
let shader_triangle_and_lines =
|
||||
device.create_shader_module(&wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!(
|
||||
"triangle_and_lines.wgsl"
|
||||
))),
|
||||
flags: wgpu::ShaderFlags::all(),
|
||||
});
|
||||
|
||||
let pipeline_triangle_conservative =
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Conservative Rasterization"),
|
||||
layout: Some(&pipeline_layout_empty),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader_triangle_and_lines,
|
||||
entry_point: "vs_main",
|
||||
buffers: &[],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader_triangle_and_lines,
|
||||
entry_point: "fs_main_red",
|
||||
targets: &[RENDER_TARGET_FORMAT.into()],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
conservative: true,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
});
|
||||
|
||||
let pipeline_triangle_regular =
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Regular Rasterization"),
|
||||
layout: Some(&pipeline_layout_empty),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader_triangle_and_lines,
|
||||
entry_point: "vs_main",
|
||||
buffers: &[],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader_triangle_and_lines,
|
||||
entry_point: "fs_main_blue",
|
||||
targets: &[RENDER_TARGET_FORMAT.into()],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
});
|
||||
|
||||
let pipeline_lines = if adapter
|
||||
.features()
|
||||
.contains(wgpu::Features::NON_FILL_POLYGON_MODE)
|
||||
{
|
||||
Some(
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Lines"),
|
||||
layout: Some(&pipeline_layout_empty),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader_triangle_and_lines,
|
||||
entry_point: "vs_main",
|
||||
buffers: &[],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader_triangle_and_lines,
|
||||
entry_point: "fs_main_white",
|
||||
targets: &[sc_desc.format.into()],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
polygon_mode: wgpu::PolygonMode::Line,
|
||||
topology: wgpu::PrimitiveTopology::LineStrip,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (pipeline_upscale, bind_group_layout_upscale) = {
|
||||
let bind_group_layout =
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: Some("upscale bindgroup"),
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: false },
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
multisampled: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler {
|
||||
filtering: false,
|
||||
comparison: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: None,
|
||||
bind_group_layouts: &[&bind_group_layout],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
let shader = device.create_shader_module(&wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("upscale.wgsl"))),
|
||||
flags: wgpu::ShaderFlags::all(),
|
||||
});
|
||||
(
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Upscale"),
|
||||
layout: Some(&pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader,
|
||||
entry_point: "vs_main",
|
||||
buffers: &[],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
entry_point: "fs_main",
|
||||
targets: &[sc_desc.format.into()],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
}),
|
||||
bind_group_layout,
|
||||
)
|
||||
};
|
||||
|
||||
let (low_res_target, bind_group_upscale) =
|
||||
Self::create_low_res_target(sc_desc, device, &bind_group_layout_upscale);
|
||||
|
||||
Self {
|
||||
low_res_target,
|
||||
bind_group_upscale,
|
||||
|
||||
pipeline_triangle_conservative,
|
||||
pipeline_triangle_regular,
|
||||
pipeline_upscale,
|
||||
pipeline_lines,
|
||||
bind_group_layout_upscale,
|
||||
}
|
||||
}
|
||||
|
||||
fn resize(
|
||||
&mut self,
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
device: &wgpu::Device,
|
||||
_queue: &wgpu::Queue,
|
||||
) {
|
||||
let (low_res_target, bind_group_upscale) =
|
||||
Self::create_low_res_target(sc_desc, device, &self.bind_group_layout_upscale);
|
||||
self.low_res_target = low_res_target;
|
||||
self.bind_group_upscale = bind_group_upscale;
|
||||
}
|
||||
|
||||
fn update(&mut self, _event: winit::event::WindowEvent) {}
|
||||
|
||||
fn render(
|
||||
&mut self,
|
||||
frame: &wgpu::SwapChainTexture,
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
_spawner: &framework::Spawner,
|
||||
) {
|
||||
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
label: Some("primary"),
|
||||
});
|
||||
|
||||
{
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("low resolution"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &self.low_res_target,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.pipeline_triangle_conservative);
|
||||
rpass.draw(0..3, 0..1);
|
||||
rpass.set_pipeline(&self.pipeline_triangle_regular);
|
||||
rpass.draw(0..3, 0..1);
|
||||
}
|
||||
{
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("full resolution"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &frame.view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.pipeline_upscale);
|
||||
rpass.set_bind_group(0, &self.bind_group_upscale, &[]);
|
||||
rpass.draw(0..3, 0..1);
|
||||
|
||||
if let Some(pipeline_lines) = &self.pipeline_lines {
|
||||
rpass.set_pipeline(pipeline_lines);
|
||||
rpass.draw(0..4, 0..1);
|
||||
}
|
||||
}
|
||||
|
||||
queue.submit(Some(encoder.finish()));
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
framework::run::<Example>("conservative-raster");
|
||||
}
|
||||
BIN
wgpu/examples/conservative-raster/screenshot.png
Normal file
BIN
wgpu/examples/conservative-raster/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
22
wgpu/examples/conservative-raster/triangle_and_lines.wgsl
Normal file
22
wgpu/examples/conservative-raster/triangle_and_lines.wgsl
Normal file
@ -0,0 +1,22 @@
|
||||
[[stage(vertex)]]
|
||||
fn vs_main([[builtin(vertex_index)]] vertex_index: u32) -> [[builtin(position)]] vec4<f32> {
|
||||
const i: i32 = i32(vertex_index % 3u);
|
||||
const x: f32 = f32(i - 1) * 0.75;
|
||||
const y: f32 = f32((i & 1) * 2 - 1) * 0.75 + x * 0.2 + 0.1;
|
||||
return vec4<f32>(x, y, 0.0, 1.0);
|
||||
}
|
||||
|
||||
[[stage(fragment)]]
|
||||
fn fs_main_red() -> [[location(0)]] vec4<f32> {
|
||||
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
[[stage(fragment)]]
|
||||
fn fs_main_blue() -> [[location(0)]] vec4<f32> {
|
||||
return vec4<f32>(0.13, 0.31, 0.85, 1.0); // cornflower blue in linear space
|
||||
}
|
||||
|
||||
[[stage(fragment)]]
|
||||
fn fs_main_white() -> [[location(0)]] vec4<f32> {
|
||||
return vec4<f32>(1.0, 1.0, 1.0, 1.0);
|
||||
}
|
||||
24
wgpu/examples/conservative-raster/upscale.wgsl
Normal file
24
wgpu/examples/conservative-raster/upscale.wgsl
Normal file
@ -0,0 +1,24 @@
|
||||
struct VertexOutput {
|
||||
[[builtin(position)]] position: vec4<f32>;
|
||||
[[location(0)]] tex_coords: vec2<f32>;
|
||||
};
|
||||
|
||||
[[stage(vertex)]]
|
||||
fn vs_main([[builtin(vertex_index)]] vertex_index: u32) -> VertexOutput {
|
||||
const x: f32 = f32(i32(vertex_index & 1) << 2) - 1.0;
|
||||
const y: f32 = f32(i32(vertex_index & 2) << 1) - 1.0;
|
||||
var output: VertexOutput;
|
||||
output.position = vec4<f32>(x, -y, 0.0, 1.0);
|
||||
output.tex_coords = vec2<f32>(x + 1.0, y + 1.0) * 0.5;
|
||||
return output;
|
||||
}
|
||||
|
||||
[[group(0), binding(0)]]
|
||||
var r_color: texture_2d<f32>;
|
||||
[[group(0), binding(1)]]
|
||||
var r_sampler: sampler;
|
||||
|
||||
[[stage(fragment)]]
|
||||
fn fs_main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
|
||||
return textureSample(r_color, r_sampler, in.tex_coords);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user