diff --git a/CHANGELOG.md b/CHANGELOG.md index ba0e7d3cf5..f80cfc5db4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -143,6 +143,7 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non - Native adapters can now use MSAA x2 and x8 if it's supported , previously only x1 and x4 were supported . By @39ali in [3140](https://github.com/gfx-rs/wgpu/pull/3140) - Implemented correleation between user timestamps and platform specific presentation timestamps via [`Adapter::get_presentation_timestamp`]. By @cwfitzgerald in [#3240](https://github.com/gfx-rs/wgpu/pull/3240) - Added support for `Features::SHADER_PRIMITIVE_INDEX` on all backends. By @cwfitzgerald in [#3272](https://github.com/gfx-rs/wgpu/pull/3272) +- Implemented `TextureFormat::Stencil8`, allowing for stencil testing without depth components. By @Dinnerbone in [#3343](https://github.com/gfx-rs/wgpu/pull/3343) #### GLES @@ -205,6 +206,7 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non ### Examples - Log adapter info in hello example on wasm target by @JolifantoBambla in [#2858](https://github.com/gfx-rs/wgpu/pull/2858) +- Added new example `stencil-triangles` to show basic use of stencil testing. By @Dinnerbone in [#3343](https://github.com/gfx-rs/wgpu/pull/3343) ### Testing/Internal diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index b8c8cde0bf..70c01a9c46 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -331,8 +331,8 @@ pub(crate) fn validate_texture_copy_range( let extent = extent_virtual.physical_size(desc.format); match desc.format { - //wgt::TextureFormat::Stencil8 | - wgt::TextureFormat::Depth16Unorm + wgt::TextureFormat::Stencil8 + | wgt::TextureFormat::Depth16Unorm | wgt::TextureFormat::Depth32Float | wgt::TextureFormat::Depth32FloatStencil8 | wgt::TextureFormat::Depth24Plus diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 3fa41032d1..d190cbbfd9 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -705,8 +705,8 @@ impl NumericType { (NumericDimension::Vector(Vs::Quad), Sk::Sint) } Tf::Rg11b10Float => (NumericDimension::Vector(Vs::Tri), Sk::Float), - //Tf::Stencil8 | - Tf::Depth16Unorm + Tf::Stencil8 + | Tf::Depth16Unorm | Tf::Depth32Float | Tf::Depth32FloatStencil8 | Tf::Depth24Plus diff --git a/wgpu-hal/src/auxil/dxgi/conv.rs b/wgpu-hal/src/auxil/dxgi/conv.rs index 887a9670a4..ed82faaa71 100644 --- a/wgpu-hal/src/auxil/dxgi/conv.rs +++ b/wgpu-hal/src/auxil/dxgi/conv.rs @@ -47,7 +47,7 @@ pub fn map_texture_format_failable(format: wgt::TextureFormat) -> Option DXGI_FORMAT_R32G32B32A32_UINT, Tf::Rgba32Sint => DXGI_FORMAT_R32G32B32A32_SINT, Tf::Rgba32Float => DXGI_FORMAT_R32G32B32A32_FLOAT, - // Tf::Stencil8 => DXGI_FORMAT_D24_UNORM_S8_UINT, + Tf::Stencil8 => DXGI_FORMAT_D24_UNORM_S8_UINT, Tf::Depth16Unorm => DXGI_FORMAT_D16_UNORM, Tf::Depth24Plus => DXGI_FORMAT_D24_UNORM_S8_UINT, Tf::Depth24PlusStencil8 => DXGI_FORMAT_D24_UNORM_S8_UINT, @@ -109,9 +109,9 @@ pub fn map_texture_format_nodepth(format: wgt::TextureFormat) -> dxgiformat::DXG wgt::TextureFormat::Depth32FloatStencil8 => { dxgiformat::DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS } - wgt::TextureFormat::Depth24Plus | wgt::TextureFormat::Depth24PlusStencil8 => { - dxgiformat::DXGI_FORMAT_R24_UNORM_X8_TYPELESS - } + wgt::TextureFormat::Stencil8 + | wgt::TextureFormat::Depth24Plus + | wgt::TextureFormat::Depth24PlusStencil8 => dxgiformat::DXGI_FORMAT_R24_UNORM_X8_TYPELESS, _ => { assert_eq!( crate::FormatAspects::from(format), @@ -127,6 +127,7 @@ pub fn map_texture_format_depth_typeless(format: wgt::TextureFormat) -> dxgiform wgt::TextureFormat::Depth16Unorm => dxgiformat::DXGI_FORMAT_R16_TYPELESS, wgt::TextureFormat::Depth32Float => dxgiformat::DXGI_FORMAT_R32_TYPELESS, wgt::TextureFormat::Depth32FloatStencil8 => dxgiformat::DXGI_FORMAT_R32G8X24_TYPELESS, + wgt::TextureFormat::Stencil8 => dxgiformat::DXGI_FORMAT_R24G8_TYPELESS, wgt::TextureFormat::Depth24Plus | wgt::TextureFormat::Depth24PlusStencil8 => { dxgiformat::DXGI_FORMAT_R24G8_TYPELESS } diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 9d4231da86..833ae36d2d 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -786,8 +786,8 @@ impl crate::Adapter for super::Adapter { Tf::Rgba32Uint => renderable | storage, Tf::Rgba32Sint => renderable | storage, Tf::Rgba32Float => unfilterable | storage | float_renderable | texture_float_linear, - //Tf::Stencil8 | - Tf::Depth16Unorm + Tf::Stencil8 + | Tf::Depth16Unorm | Tf::Depth32Float | Tf::Depth32FloatStencil8 | Tf::Depth24Plus diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index d0d065f10e..93f015363f 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -56,7 +56,11 @@ impl super::AdapterShared { Tf::Rgba32Uint => (glow::RGBA32UI, glow::RGBA_INTEGER, glow::UNSIGNED_INT), Tf::Rgba32Sint => (glow::RGBA32I, glow::RGBA_INTEGER, glow::INT), Tf::Rgba32Float => (glow::RGBA32F, glow::RGBA, glow::FLOAT), - //Tf::Stencil8 => (glow::R8UI, glow::STENCIL_COMPONENTS, glow::UNSIGNED_BYTE), + Tf::Stencil8 => ( + glow::STENCIL_INDEX8, + glow::STENCIL_COMPONENTS, + glow::UNSIGNED_BYTE, + ), Tf::Depth16Unorm => ( glow::DEPTH_COMPONENT16, glow::DEPTH_COMPONENT, diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index db15ecf24e..f20aa89a1f 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -636,7 +636,7 @@ impl From for FormatAspects { impl From for FormatAspects { fn from(format: wgt::TextureFormat) -> Self { match format { - //wgt::TextureFormat::Stencil8 => Self::STENCIL, + wgt::TextureFormat::Stencil8 => Self::STENCIL, wgt::TextureFormat::Depth16Unorm => Self::DEPTH, wgt::TextureFormat::Depth32Float | wgt::TextureFormat::Depth24Plus => Self::DEPTH, wgt::TextureFormat::Depth32FloatStencil8 | wgt::TextureFormat::Depth24PlusStencil8 => { diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 5ade092c24..26bb167c33 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -166,13 +166,9 @@ impl crate::Adapter for super::Adapter { }; flags } - /*Tf::Stencil8 => { - let mut flags = all_caps - | Tfc::DEPTH_STENCIL_ATTACHMENT - | Tfc::MULTISAMPLE - | msaa_resolve_apple3x_if; - flags - }*/ + Tf::Stencil8 => { + all_caps | Tfc::DEPTH_STENCIL_ATTACHMENT | msaa_count | msaa_resolve_apple3x_if + } Tf::Depth16Unorm => { let mut flags = Tfc::DEPTH_STENCIL_ATTACHMENT | msaa_count | msaa_resolve_apple3x_if; @@ -909,7 +905,7 @@ impl super::PrivateCapabilities { Tf::Rgba32Uint => RGBA32Uint, Tf::Rgba32Sint => RGBA32Sint, Tf::Rgba32Float => RGBA32Float, - //Tf::Stencil8 => R8Unorm, + Tf::Stencil8 => Stencil8, Tf::Depth16Unorm => Depth16Unorm, Tf::Depth32Float => Depth32Float, Tf::Depth32FloatStencil8 => Depth32Float_Stencil8, diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index cf5c8eeae7..796379575d 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -1016,6 +1016,13 @@ impl super::Instance { .optimal_tiling_features .contains(vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT) }, + texture_s8: unsafe { + self.shared + .raw + .get_physical_device_format_properties(phd, vk::Format::S8_UINT) + .optimal_tiling_features + .contains(vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT) + }, non_coherent_map_mask: phd_capabilities.properties.limits.non_coherent_atom_size - 1, can_present: true, //TODO: make configurable diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index e52409043a..d9c6912500 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -64,7 +64,15 @@ impl super::PrivateCapabilities { F::D32_SFLOAT_S8_UINT } } - //Tf::Stencil8 => F::R8_UNORM, + Tf::Stencil8 => { + if self.texture_s8 { + F::S8_UINT + } else if self.texture_d24_s8 { + F::D24_UNORM_S8_UINT + } else { + F::D32_SFLOAT_S8_UINT + } + } Tf::Depth16Unorm => F::D16_UNORM, Tf::Rgb9e5Ufloat => F::E5B9G9R9_UFLOAT_PACK32, Tf::Bc1RgbaUnorm => F::BC1_RGBA_UNORM_BLOCK, diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index f8ffbc718e..a30dbec224 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -160,6 +160,7 @@ struct PrivateCapabilities { timeline_semaphores: bool, texture_d24: bool, texture_d24_s8: bool, + texture_s8: bool, /// Ability to present contents to any screen. Only needed to work around broken platform configurations. can_present: bool, non_coherent_map_mask: wgt::BufferAddress, diff --git a/wgpu-info/src/main.rs b/wgpu-info/src/main.rs index 9d477e7cd5..cb1cbb3f96 100644 --- a/wgpu-info/src/main.rs +++ b/wgpu-info/src/main.rs @@ -8,7 +8,7 @@ mod inner { // Lets keep these on one line #[rustfmt::skip] - const TEXTURE_FORMAT_LIST: [wgpu::TextureFormat; 113] = [ + const TEXTURE_FORMAT_LIST: [wgpu::TextureFormat; 114] = [ wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::R8Snorm, wgpu::TextureFormat::R8Uint, @@ -50,7 +50,7 @@ mod inner { wgpu::TextureFormat::Rgba32Uint, wgpu::TextureFormat::Rgba32Sint, wgpu::TextureFormat::Rgba32Float, - //wgpu::TextureFormat::Stencil8, + wgpu::TextureFormat::Stencil8, wgpu::TextureFormat::Depth16Unorm, wgpu::TextureFormat::Depth32Float, wgpu::TextureFormat::Depth32FloatStencil8, diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 6a12bad9c1..373be2d75e 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -1929,7 +1929,7 @@ pub enum TextureFormat { // Depth and stencil formats /// Stencil format with 8 bit integer stencil. - //Stencil8, + Stencil8, /// Special depth format with 16 bit integer depth. Depth16Unorm, /// Special depth format with at least 24 bit integer depth. @@ -2163,6 +2163,7 @@ impl<'de> Deserialize<'de> for TextureFormat { "rgba32uint" => TextureFormat::Rgba32Uint, "rgba32sint" => TextureFormat::Rgba32Sint, "rgba32float" => TextureFormat::Rgba32Float, + "stencil8" => TextureFormat::Stencil8, "depth32float" => TextureFormat::Depth32Float, "depth32float-stencil8" => TextureFormat::Depth32FloatStencil8, "depth16unorm" => TextureFormat::Depth16Unorm, @@ -2288,6 +2289,7 @@ impl Serialize for TextureFormat { TextureFormat::Rgba32Uint => "rgba32uint", TextureFormat::Rgba32Sint => "rgba32sint", TextureFormat::Rgba32Float => "rgba32float", + TextureFormat::Stencil8 => "stencil8", TextureFormat::Depth32Float => "depth32float", TextureFormat::Depth16Unorm => "depth16unorm", TextureFormat::Depth32FloatStencil8 => "depth32float-stencil8", @@ -2443,6 +2445,7 @@ impl TextureFormat { Self::Rgba32Sint => ( native, sint, linear, noaa, (1, 1), 16, all_flags, 4), Self::Rgba32Float => ( native, nearest, linear, noaa, (1, 1), 16, all_flags, 4), // Depth-stencil textures + Self::Stencil8 => ( native, depth, linear, msaa, (1, 1), 2, attachment, 1), Self::Depth16Unorm => ( native, depth, linear, msaa, (1, 1), 2, attachment, 1), Self::Depth24Plus => ( native, depth, linear, msaa, (1, 1), 4, attachment, 1), Self::Depth24PlusStencil8 => ( native, depth, linear, msaa, (1, 1), 4, attachment, 2), @@ -2702,6 +2705,10 @@ fn texture_format_serialize() { serde_json::to_string(&TextureFormat::Rgba32Float).unwrap(), "\"rgba32float\"".to_string() ); + assert_eq!( + serde_json::to_string(&TextureFormat::Stencil8).unwrap(), + "\"stencil8\"".to_string() + ); assert_eq!( serde_json::to_string(&TextureFormat::Depth32Float).unwrap(), "\"depth32float\"".to_string() @@ -2990,6 +2997,10 @@ fn texture_format_deserialize() { serde_json::from_str::("\"rgba32float\"").unwrap(), TextureFormat::Rgba32Float ); + assert_eq!( + serde_json::from_str::("\"stencil8\"").unwrap(), + TextureFormat::Stencil8 + ); assert_eq!( serde_json::from_str::("\"depth32float\"").unwrap(), TextureFormat::Depth32Float diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index b2e90793fd..97ab4980ae 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -75,6 +75,10 @@ test = true name = "water" test = true +[[example]] +name = "stencil-triangles" +test = true + [features] default = ["wgsl", "expose-ids"] # Apply run-time checks, even in release builds. These are in addition diff --git a/wgpu/examples/README.md b/wgpu/examples/README.md index acf0da0c70..ef427e7351 100644 --- a/wgpu/examples/README.md +++ b/wgpu/examples/README.md @@ -12,41 +12,41 @@ All the examples use [WGSL](https://gpuweb.github.io/gpuweb/wgsl.html) shaders u All framework-based examples render to the window and are reftested against the screenshot in the directory. ## Feature matrix -| Feature | boids | bunnymark | cube | mipmap | msaa-line | shadow | skybox | texture-arrays | water | conservative-raster | -| ---------------------------- | ------ | --------- | ------ | ------ | --------- | ------ | ------ | -------------- | ------ | ------------------- | -| vertex attributes | :star: | | :star: | | :star: | :star: | :star: | :star: | :star: | | -| instancing | :star: | | | | | | | | | | -| lines and points | | | | | :star: | | | | | :star: | -| dynamic buffer offsets | | :star: | | | | :star: | | | | | -| implicit layout | | | | :star: | | | | | | | -| sampled color textures | :star: | :star: | :star: | :star: | | | :star: | :star: | :star: | :star: | -| storage textures | :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: | | | | | | :star: | | -| render bundles | | | | | :star: | | | | :star: | | -| compute passes | :star: | | | | | | | | | | -| error scopes | | | :star: | | | | | | | | -| *optional extensions* | | | | | | | | :star: | | | -| - SPIR-V shaders | | | | | | | | | | | -| - binding array | | | | | | | | :star: | | | -| - push constants | | | | | | | | | | | -| - depth clamping | | | | | | :star: | | | | | -| - compressed textures | | | | | | | :star: | | | | -| - polygon mode | | | :star: | | | | | | | | -| - queries | | | | :star: | | | | | | | -| - conservative rasterization | | | | | | | | | | :star: | -| *integrations* | | | | | | | | | | | -| - staging belt | | | | | | | :star: | | | | -| - typed arena | | | | | | | | | | | -| - obj loading | | | | | | | :star: | | | | +| Feature | boids | bunnymark | cube | mipmap | msaa-line | shadow | skybox | texture-arrays | water | conservative-raster | stencil-triangles | +|------------------------------| ------ | --------- | ------ | ------ | --------- | ------ | ------ | -------------- | ------ | ------------------- |-------------------| +| vertex attributes | :star: | | :star: | | :star: | :star: | :star: | :star: | :star: | | | +| instancing | :star: | | | | | | | | | | | +| lines and points | | | | | :star: | | | | | :star: | | +| dynamic buffer offsets | | :star: | | | | :star: | | | | | | +| implicit layout | | | | :star: | | | | | | | | +| sampled color textures | :star: | :star: | :star: | :star: | | | :star: | :star: | :star: | :star: | | +| storage textures | :star: | | | | | | | | | | | +| comparison samplers | | | | | | :star: | | | | | | +| subresource views | | | | :star: | | :star: | | | | | | +| cubemaps | | | | | | | :star: | | | | | +| multisampling | | | | | :star: | | | | | | | +| off-screen rendering | | | | | | :star: | | | :star: | :star: | | +| stencil testing | | | | | | | | | | | :star: | +| depth testing | | | | | | :star: | :star: | | :star: | | | +| depth biasing | | | | | | :star: | | | | | | +| read-only depth | | | | | | | | | :star: | | | +| blending | | :star: | :star: | | | | | | :star: | | | +| render bundles | | | | | :star: | | | | :star: | | | +| compute passes | :star: | | | | | | | | | | | +| error scopes | | | :star: | | | | | | | | | +| *optional extensions* | | | | | | | | :star: | | | | +| - SPIR-V shaders | | | | | | | | | | | | +| - binding array | | | | | | | | :star: | | | | +| - push constants | | | | | | | | | | | | +| - depth clamping | | | | | | :star: | | | | | | +| - compressed textures | | | | | | | :star: | | | | | +| - polygon mode | | | :star: | | | | | | | | | +| - queries | | | | :star: | | | | | | | | +| - conservative rasterization | | | | | | | | | | :star: | | +| *integrations* | | | | | | | | | | | | +| - staging belt | | | | | | | :star: | | | | | +| - typed arena | | | | | | | | | | | | +| - obj loading | | | | | | | :star: | | | | | ## Hacking diff --git a/wgpu/examples/stencil-triangles/README.md b/wgpu/examples/stencil-triangles/README.md new file mode 100644 index 0000000000..f55c27b779 --- /dev/null +++ b/wgpu/examples/stencil-triangles/README.md @@ -0,0 +1,19 @@ +# hello-triangle + +This example renders two different sized triangles to display three same sized triangles, +by demonstrating the use of stencil buffers. + +First it draws a small "mask" triangle, which sets the stencil buffer at every pixel to 1. + +Then, it draws a larger "outer" triangle which only touches pixels where the stencil buffer is less than 1. + + +## To Run + +``` +cargo run --example stencil-triangles +``` + +## Screenshots + +![Stencil Triangles window](./screenshot.png) diff --git a/wgpu/examples/stencil-triangles/main.rs b/wgpu/examples/stencil-triangles/main.rs new file mode 100644 index 0000000000..1de2ae8eb9 --- /dev/null +++ b/wgpu/examples/stencil-triangles/main.rs @@ -0,0 +1,251 @@ +use bytemuck::{Pod, Zeroable}; +use std::borrow::Cow; +use std::mem; +use wgpu::util::DeviceExt; + +#[path = "../framework.rs"] +mod framework; + +#[repr(C)] +#[derive(Clone, Copy, Pod, Zeroable)] +struct Vertex { + _pos: [f32; 4], +} + +fn vertex(x: f32, y: f32) -> Vertex { + Vertex { + _pos: [x, y, 0.0, 1.0], + } +} + +struct Triangles { + outer_vertex_buffer: wgpu::Buffer, + mask_vertex_buffer: wgpu::Buffer, + outer_pipeline: wgpu::RenderPipeline, + mask_pipeline: wgpu::RenderPipeline, + stencil_buffer: wgpu::Texture, +} + +impl framework::Example for Triangles { + fn init( + config: &wgpu::SurfaceConfiguration, + _adapter: &wgpu::Adapter, + device: &wgpu::Device, + _queue: &wgpu::Queue, + ) -> Self { + // Create the vertex and index buffers + let vertex_size = mem::size_of::(); + let outer_vertices = [vertex(-1.0, -1.0), vertex(1.0, -1.0), vertex(0.0, 1.0)]; + let mask_vertices = [vertex(-0.5, 0.0), vertex(0.0, -1.0), vertex(0.5, 0.0)]; + + let outer_vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Outer Vertex Buffer"), + contents: bytemuck::cast_slice(&outer_vertices), + usage: wgpu::BufferUsages::VERTEX, + }); + + let mask_vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Mask Vertex Buffer"), + contents: bytemuck::cast_slice(&mask_vertices), + usage: wgpu::BufferUsages::VERTEX, + }); + + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[], + push_constant_ranges: &[], + }); + + let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: None, + source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))), + }); + + let vertex_buffers = [wgpu::VertexBufferLayout { + array_stride: vertex_size as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &[wgpu::VertexAttribute { + format: wgpu::VertexFormat::Float32x4, + offset: 0, + shader_location: 0, + }], + }]; + + let mask_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: None, + layout: Some(&pipeline_layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + buffers: &vertex_buffers, + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: config.format, + blend: None, + write_mask: wgpu::ColorWrites::empty(), + })], + }), + primitive: Default::default(), + depth_stencil: Some(wgpu::DepthStencilState { + format: wgpu::TextureFormat::Stencil8, + depth_write_enabled: false, + depth_compare: wgpu::CompareFunction::Always, + stencil: wgpu::StencilState { + front: wgpu::StencilFaceState { + compare: wgpu::CompareFunction::Always, + pass_op: wgpu::StencilOperation::Replace, + ..Default::default() + }, + back: wgpu::StencilFaceState::IGNORE, + read_mask: !0, + write_mask: !0, + }, + bias: Default::default(), + }), + multisample: wgpu::MultisampleState::default(), + multiview: None, + }); + + let outer_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: None, + layout: Some(&pipeline_layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + buffers: &vertex_buffers, + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + targets: &[Some(config.format.into())], + }), + primitive: Default::default(), + depth_stencil: Some(wgpu::DepthStencilState { + format: wgpu::TextureFormat::Stencil8, + depth_write_enabled: false, + depth_compare: wgpu::CompareFunction::Always, + stencil: wgpu::StencilState { + front: wgpu::StencilFaceState { + compare: wgpu::CompareFunction::Greater, + ..Default::default() + }, + back: wgpu::StencilFaceState::IGNORE, + read_mask: !0, + write_mask: !0, + }, + bias: Default::default(), + }), + multisample: wgpu::MultisampleState::default(), + multiview: None, + }); + + let stencil_buffer = device.create_texture(&wgpu::TextureDescriptor { + label: Some("Stencil buffer"), + size: wgpu::Extent3d { + width: config.width, + height: config.height, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Stencil8, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + }); + + // Done + Triangles { + outer_vertex_buffer, + mask_vertex_buffer, + outer_pipeline, + mask_pipeline, + stencil_buffer, + } + } + + fn update(&mut self, _event: winit::event::WindowEvent) { + // empty + } + + fn resize( + &mut self, + _config: &wgpu::SurfaceConfiguration, + _device: &wgpu::Device, + _queue: &wgpu::Queue, + ) { + // empty + } + + fn render( + &mut self, + view: &wgpu::TextureView, + device: &wgpu::Device, + queue: &wgpu::Queue, + _spawner: &framework::Spawner, + ) { + let mut encoder = + device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + { + let depth_view = self.stencil_buffer.create_view(&Default::default()); + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.1, + g: 0.2, + b: 0.3, + a: 1.0, + }), + store: true, + }, + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &depth_view, + depth_ops: None, + stencil_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(0), + store: true, + }), + }), + }); + + rpass.set_stencil_reference(1); + + rpass.set_pipeline(&self.mask_pipeline); + rpass.set_vertex_buffer(0, self.mask_vertex_buffer.slice(..)); + rpass.draw(0..3, 0..1); + + rpass.set_pipeline(&self.outer_pipeline); + rpass.set_vertex_buffer(0, self.outer_vertex_buffer.slice(..)); + rpass.draw(0..3, 0..1); + } + + queue.submit(Some(encoder.finish())); + } +} + +fn main() { + framework::run::("stencil-triangles"); +} + +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + +#[test] +#[wasm_bindgen_test::wasm_bindgen_test] +fn stencil_triangles() { + framework::test::(framework::FrameworkRefTest { + image_path: "/examples/stencil-triangles/screenshot.png", + width: 1024, + height: 768, + optional_features: wgpu::Features::default(), + base_test_parameters: framework::test_common::TestParameters::default(), + tolerance: 1, + max_outliers: 0, + }); +} diff --git a/wgpu/examples/stencil-triangles/screenshot.png b/wgpu/examples/stencil-triangles/screenshot.png new file mode 100644 index 0000000000..305a4a3260 Binary files /dev/null and b/wgpu/examples/stencil-triangles/screenshot.png differ diff --git a/wgpu/examples/stencil-triangles/shader.wgsl b/wgpu/examples/stencil-triangles/shader.wgsl new file mode 100644 index 0000000000..302051a186 --- /dev/null +++ b/wgpu/examples/stencil-triangles/shader.wgsl @@ -0,0 +1,15 @@ +struct VertexOutput { + @builtin(position) position: vec4, +}; + +@vertex +fn vs_main(@location(0) position: vec4) -> VertexOutput { + var result: VertexOutput; + result.position = position; + return result; +} + +@fragment +fn fs_main(vertex: VertexOutput) -> @location(0) vec4 { + return vec4(0.97, 0.88, 0.21, 1.0); +} diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 8b55f4fc6b..7a35437be9 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -183,7 +183,7 @@ fn map_texture_format(texture_format: wgt::TextureFormat) -> web_sys::GpuTexture TextureFormat::Rgba32Sint => tf::Rgba32sint, TextureFormat::Rgba32Float => tf::Rgba32float, // Depth/stencil formats - //TextureFormat::Stencil8 => tf::Stencil8, + TextureFormat::Stencil8 => tf::Stencil8, TextureFormat::Depth16Unorm => tf::Depth16unorm, TextureFormat::Depth24Plus => tf::Depth24plus, TextureFormat::Depth24PlusStencil8 => tf::Depth24plusStencil8, diff --git a/wgpu/tests/clear_texture.rs b/wgpu/tests/clear_texture.rs index 70c42ba433..3afdd98009 100644 --- a/wgpu/tests/clear_texture.rs +++ b/wgpu/tests/clear_texture.rs @@ -42,7 +42,7 @@ static TEXTURE_FORMATS_UNCOMPRESSED: &[wgpu::TextureFormat] = &[ ]; static TEXTURE_FORMATS_DEPTH: &[wgpu::TextureFormat] = &[ - //wgpu::TextureFormat::Stencil8, + wgpu::TextureFormat::Stencil8, wgpu::TextureFormat::Depth16Unorm, wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Depth24PlusStencil8,