render: Fix masking issues on wgpu/webgl backends
Change the usage of the stencil buffer to avoid running out of stencil bits when too many nested masks are active. This also cleans things up on wgpu which requires us to make pipeline states in advice; now we only need a few stencil states for masking as opposed to hundreds.
This commit is contained in:
parent
8ba5dbfa49
commit
4558be948e
|
@ -81,6 +81,12 @@ dependencies = [
|
||||||
"num-traits 0.2.12",
|
"num-traits 0.2.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "array-macro"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06e97b4e522f9e55523001238ac59d13a8603af57f69980de5d8de4bbbe8ada6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
|
@ -909,6 +915,27 @@ version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enum-map"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f81f09b9cb18af2ea1da2688a1d6b1762b4f938d7495bb034bce48d4c608043"
|
||||||
|
dependencies = [
|
||||||
|
"array-macro",
|
||||||
|
"enum-map-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enum-map-derive"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e57001dfb2532f5a103ff869656887fae9a8defa7d236f3e39d2ee86ed629ad7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "enumset"
|
name = "enumset"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -2595,6 +2622,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"clap",
|
"clap",
|
||||||
|
"enum-map",
|
||||||
"futures",
|
"futures",
|
||||||
"image",
|
"image",
|
||||||
"jpeg-decoder",
|
"jpeg-decoder",
|
||||||
|
|
|
@ -40,6 +40,7 @@ pub trait RenderBackend: Downcast {
|
||||||
fn draw_letterbox(&mut self, letterbox: Letterbox);
|
fn draw_letterbox(&mut self, letterbox: Letterbox);
|
||||||
fn push_mask(&mut self);
|
fn push_mask(&mut self);
|
||||||
fn activate_mask(&mut self);
|
fn activate_mask(&mut self);
|
||||||
|
fn deactivate_mask(&mut self);
|
||||||
fn pop_mask(&mut self);
|
fn pop_mask(&mut self);
|
||||||
}
|
}
|
||||||
impl_downcast!(RenderBackend);
|
impl_downcast!(RenderBackend);
|
||||||
|
@ -143,6 +144,7 @@ impl RenderBackend for NullRenderer {
|
||||||
fn draw_letterbox(&mut self, _letterbox: Letterbox) {}
|
fn draw_letterbox(&mut self, _letterbox: Letterbox) {}
|
||||||
fn push_mask(&mut self) {}
|
fn push_mask(&mut self) {}
|
||||||
fn activate_mask(&mut self) {}
|
fn activate_mask(&mut self) {}
|
||||||
|
fn deactivate_mask(&mut self) {}
|
||||||
fn pop_mask(&mut self) {}
|
fn pop_mask(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1150,18 +1150,22 @@ pub fn render_children<'gc>(
|
||||||
children: &std::collections::BTreeMap<Depth, DisplayObject<'gc>>,
|
children: &std::collections::BTreeMap<Depth, DisplayObject<'gc>>,
|
||||||
) {
|
) {
|
||||||
let mut clip_depth = 0;
|
let mut clip_depth = 0;
|
||||||
let mut clip_depth_stack = vec![];
|
let mut clip_depth_stack: Vec<(Depth, DisplayObject<'_>)> = vec![];
|
||||||
for (&depth, &child) in children {
|
for (&depth, &child) in children {
|
||||||
// Check if we need to pop off a mask.
|
// Check if we need to pop off a mask.
|
||||||
// This must be a while loop because multiple masks can be popped
|
// This must be a while loop because multiple masks can be popped
|
||||||
// at the same dpeth.
|
// at the same dpeth.
|
||||||
while clip_depth > 0 && depth >= clip_depth {
|
while clip_depth > 0 && depth >= clip_depth {
|
||||||
|
// Clear the mask stencil and pop the mask.
|
||||||
|
let (prev_clip_depth, clip_child) = clip_depth_stack.pop().unwrap();
|
||||||
|
clip_depth = prev_clip_depth;
|
||||||
|
context.renderer.deactivate_mask();
|
||||||
|
clip_child.render(context);
|
||||||
context.renderer.pop_mask();
|
context.renderer.pop_mask();
|
||||||
clip_depth = clip_depth_stack.pop().unwrap();
|
|
||||||
}
|
}
|
||||||
if child.clip_depth() > 0 && child.allow_as_mask() {
|
if child.clip_depth() > 0 && child.allow_as_mask() {
|
||||||
// Push and render the mask.
|
// Push and render the mask.
|
||||||
clip_depth_stack.push(clip_depth);
|
clip_depth_stack.push((clip_depth, child));
|
||||||
clip_depth = child.clip_depth();
|
clip_depth = child.clip_depth();
|
||||||
context.renderer.push_mask();
|
context.renderer.push_mask();
|
||||||
child.render(context);
|
child.render(context);
|
||||||
|
@ -1172,9 +1176,11 @@ pub fn render_children<'gc>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while !clip_depth_stack.is_empty() {
|
// Pop any remaining masks.
|
||||||
|
for (_, clip_child) in clip_depth_stack.into_iter().rev() {
|
||||||
|
context.renderer.deactivate_mask();
|
||||||
|
clip_child.render(context);
|
||||||
context.renderer.pop_mask();
|
context.renderer.pop_mask();
|
||||||
clip_depth_stack.pop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1029,6 +1029,11 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
||||||
self.render_layout_box(context, layout_box);
|
self.render_layout_box(context, layout_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.renderer.deactivate_mask();
|
||||||
|
context.renderer.draw_rect(
|
||||||
|
Color::from_rgb(0, 0xff),
|
||||||
|
&(context.transform_stack.transform().matrix * mask),
|
||||||
|
);
|
||||||
context.renderer.pop_mask();
|
context.renderer.pop_mask();
|
||||||
|
|
||||||
context.transform_stack.pop();
|
context.transform_stack.pop();
|
||||||
|
|
|
@ -31,6 +31,7 @@ pub struct WebCanvasRenderBackend {
|
||||||
viewport_height: u32,
|
viewport_height: u32,
|
||||||
use_color_transform_hack: bool,
|
use_color_transform_hack: bool,
|
||||||
pixelated_property_value: &'static str,
|
pixelated_property_value: &'static str,
|
||||||
|
deactivating_mask: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Canvas-drawable shape data extracted from an SWF file.
|
/// Canvas-drawable shape data extracted from an SWF file.
|
||||||
|
@ -213,6 +214,7 @@ impl WebCanvasRenderBackend {
|
||||||
viewport_width: 0,
|
viewport_width: 0,
|
||||||
viewport_height: 0,
|
viewport_height: 0,
|
||||||
use_color_transform_hack: is_firefox,
|
use_color_transform_hack: is_firefox,
|
||||||
|
deactivating_mask: false,
|
||||||
|
|
||||||
// For rendering non-smoothed bitmaps.
|
// For rendering non-smoothed bitmaps.
|
||||||
// crisp-edges works in Firefox, pixelated works in Chrome (and others)?
|
// crisp-edges works in Firefox, pixelated works in Chrome (and others)?
|
||||||
|
@ -551,6 +553,8 @@ impl RenderBackend for WebCanvasRenderBackend {
|
||||||
self.context.set_fill_style(&color.into());
|
self.context.set_fill_style(&color.into());
|
||||||
self.context
|
self.context
|
||||||
.fill_rect(0.0, 0.0, width.into(), height.into());
|
.fill_rect(0.0, 0.0, width.into(), height.into());
|
||||||
|
|
||||||
|
self.deactivating_mask = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_frame(&mut self) {
|
fn end_frame(&mut self) {
|
||||||
|
@ -558,6 +562,10 @@ impl RenderBackend for WebCanvasRenderBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform) {
|
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform) {
|
||||||
|
if self.deactivating_mask {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.set_transform(&transform.matrix);
|
self.set_transform(&transform.matrix);
|
||||||
self.set_color_filter(transform);
|
self.set_color_filter(transform);
|
||||||
if let Some(bitmap) = self.bitmaps.get(bitmap.0) {
|
if let Some(bitmap) = self.bitmaps.get(bitmap.0) {
|
||||||
|
@ -569,6 +577,10 @@ impl RenderBackend for WebCanvasRenderBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) {
|
fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) {
|
||||||
|
if self.deactivating_mask {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.set_transform(&transform.matrix);
|
self.set_transform(&transform.matrix);
|
||||||
if let Some(shape) = self.shapes.get(shape.0) {
|
if let Some(shape) = self.shapes.get(shape.0) {
|
||||||
for command in shape.0.iter() {
|
for command in shape.0.iter() {
|
||||||
|
@ -629,6 +641,10 @@ impl RenderBackend for WebCanvasRenderBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_rect(&mut self, color: Color, matrix: &Matrix) {
|
fn draw_rect(&mut self, color: Color, matrix: &Matrix) {
|
||||||
|
if self.deactivating_mask {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.set_transform(matrix);
|
self.set_transform(matrix);
|
||||||
self.clear_color_filter();
|
self.clear_color_filter();
|
||||||
|
|
||||||
|
@ -685,7 +701,12 @@ impl RenderBackend for WebCanvasRenderBackend {
|
||||||
// We render the maskee clips to the second render target.
|
// We render the maskee clips to the second render target.
|
||||||
self.push_render_target();
|
self.push_render_target();
|
||||||
}
|
}
|
||||||
|
fn deactivate_mask(&mut self) {
|
||||||
|
self.deactivating_mask = true;
|
||||||
|
}
|
||||||
fn pop_mask(&mut self) {
|
fn pop_mask(&mut self) {
|
||||||
|
self.deactivating_mask = false;
|
||||||
|
|
||||||
let (maskee_canvas, maskee_context) = self.pop_render_target();
|
let (maskee_canvas, maskee_context) = self.pop_render_target();
|
||||||
let (masker_canvas, _masker_context) = self.pop_render_target();
|
let (masker_canvas, _masker_context) = self.pop_render_target();
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,14 @@ const GRADIENT_FRAGMENT_GLSL: &str = include_str!("../shaders/gradient.frag");
|
||||||
const BITMAP_FRAGMENT_GLSL: &str = include_str!("../shaders/bitmap.frag");
|
const BITMAP_FRAGMENT_GLSL: &str = include_str!("../shaders/bitmap.frag");
|
||||||
const NUM_VERTEX_ATTRIBUTES: u32 = 2;
|
const NUM_VERTEX_ATTRIBUTES: u32 = 2;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum MaskState {
|
||||||
|
NoMask,
|
||||||
|
DrawMaskStencil,
|
||||||
|
DrawMaskedContent,
|
||||||
|
ClearMaskStencil,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WebGlRenderBackend {
|
pub struct WebGlRenderBackend {
|
||||||
/// WebGL1 context
|
/// WebGL1 context
|
||||||
gl: Gl,
|
gl: Gl,
|
||||||
|
@ -48,15 +56,11 @@ pub struct WebGlRenderBackend {
|
||||||
|
|
||||||
quad_shape: ShapeHandle,
|
quad_shape: ShapeHandle,
|
||||||
|
|
||||||
|
mask_state: MaskState,
|
||||||
num_masks: u32,
|
num_masks: u32,
|
||||||
num_masks_active: u32,
|
mask_state_dirty: bool,
|
||||||
write_stencil_mask: u32,
|
|
||||||
test_stencil_mask: u32,
|
|
||||||
next_stencil_mask: u32,
|
|
||||||
mask_stack: Vec<(u32, u32)>,
|
|
||||||
|
|
||||||
active_program: *const ShaderProgram,
|
active_program: *const ShaderProgram,
|
||||||
mask_state_dirty: bool,
|
|
||||||
blend_func: (u32, u32),
|
blend_func: (u32, u32),
|
||||||
mult_color: Option<[f32; 4]>,
|
mult_color: Option<[f32; 4]>,
|
||||||
add_color: Option<[f32; 4]>,
|
add_color: Option<[f32; 4]>,
|
||||||
|
@ -191,15 +195,12 @@ impl WebGlRenderBackend {
|
||||||
viewport_width: 500.0,
|
viewport_width: 500.0,
|
||||||
viewport_height: 500.0,
|
viewport_height: 500.0,
|
||||||
view_matrix: [[0.0; 4]; 4],
|
view_matrix: [[0.0; 4]; 4],
|
||||||
|
|
||||||
|
mask_state: MaskState::NoMask,
|
||||||
num_masks: 0,
|
num_masks: 0,
|
||||||
num_masks_active: 0,
|
mask_state_dirty: true,
|
||||||
write_stencil_mask: 0,
|
|
||||||
test_stencil_mask: 0,
|
|
||||||
next_stencil_mask: 1,
|
|
||||||
mask_stack: vec![],
|
|
||||||
|
|
||||||
active_program: std::ptr::null(),
|
active_program: std::ptr::null(),
|
||||||
mask_state_dirty: true,
|
|
||||||
blend_func: (Gl::SRC_ALPHA, Gl::ONE_MINUS_SRC_ALPHA),
|
blend_func: (Gl::SRC_ALPHA, Gl::ONE_MINUS_SRC_ALPHA),
|
||||||
mult_color: None,
|
mult_color: None,
|
||||||
add_color: None,
|
add_color: None,
|
||||||
|
@ -636,29 +637,31 @@ impl WebGlRenderBackend {
|
||||||
fn set_stencil_state(&mut self) {
|
fn set_stencil_state(&mut self) {
|
||||||
// Set stencil state for masking, if necessary.
|
// Set stencil state for masking, if necessary.
|
||||||
if self.mask_state_dirty {
|
if self.mask_state_dirty {
|
||||||
if self.num_masks > 0 {
|
match self.mask_state {
|
||||||
self.gl.enable(Gl::STENCIL_TEST);
|
MaskState::NoMask => {
|
||||||
if self.num_masks_active < self.num_masks {
|
|
||||||
self.gl.stencil_mask(self.write_stencil_mask);
|
|
||||||
self.gl
|
|
||||||
.stencil_func(Gl::ALWAYS, self.write_stencil_mask as i32, 0xff);
|
|
||||||
self.gl.stencil_op(Gl::KEEP, Gl::KEEP, Gl::REPLACE);
|
|
||||||
self.gl.color_mask(false, false, false, false);
|
|
||||||
} else {
|
|
||||||
self.gl.stencil_mask(0xff);
|
|
||||||
self.gl.stencil_func(
|
|
||||||
Gl::EQUAL,
|
|
||||||
self.test_stencil_mask as i32,
|
|
||||||
self.test_stencil_mask,
|
|
||||||
);
|
|
||||||
self.gl.stencil_op(Gl::KEEP, Gl::KEEP, Gl::KEEP);
|
|
||||||
self.gl.color_mask(true, true, true, true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.gl.disable(Gl::STENCIL_TEST);
|
self.gl.disable(Gl::STENCIL_TEST);
|
||||||
self.gl.color_mask(true, true, true, true);
|
self.gl.color_mask(true, true, true, true);
|
||||||
}
|
}
|
||||||
self.mask_state_dirty = false;
|
MaskState::DrawMaskStencil => {
|
||||||
|
self.gl.enable(Gl::STENCIL_TEST);
|
||||||
|
self.gl
|
||||||
|
.stencil_func(Gl::EQUAL, (self.num_masks - 1) as i32, 0xff);
|
||||||
|
self.gl.stencil_op(Gl::KEEP, Gl::KEEP, Gl::INCR);
|
||||||
|
self.gl.color_mask(false, false, false, false);
|
||||||
|
}
|
||||||
|
MaskState::DrawMaskedContent => {
|
||||||
|
self.gl.enable(Gl::STENCIL_TEST);
|
||||||
|
self.gl.stencil_func(Gl::EQUAL, self.num_masks as i32, 0xff);
|
||||||
|
self.gl.stencil_op(Gl::KEEP, Gl::KEEP, Gl::KEEP);
|
||||||
|
self.gl.color_mask(true, true, true, true);
|
||||||
|
}
|
||||||
|
MaskState::ClearMaskStencil => {
|
||||||
|
self.gl.enable(Gl::STENCIL_TEST);
|
||||||
|
self.gl.stencil_func(Gl::EQUAL, self.num_masks as i32, 0xff);
|
||||||
|
self.gl.stencil_op(Gl::KEEP, Gl::KEEP, Gl::DECR);
|
||||||
|
self.gl.color_mask(false, false, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -796,13 +799,9 @@ impl RenderBackend for WebGlRenderBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin_frame(&mut self, clear: Color) {
|
fn begin_frame(&mut self, clear: Color) {
|
||||||
self.num_masks = 0;
|
|
||||||
self.num_masks_active = 0;
|
|
||||||
self.write_stencil_mask = 0;
|
|
||||||
self.test_stencil_mask = 0;
|
|
||||||
self.next_stencil_mask = 1;
|
|
||||||
|
|
||||||
self.active_program = std::ptr::null();
|
self.active_program = std::ptr::null();
|
||||||
|
self.mask_state = MaskState::NoMask;
|
||||||
|
self.num_masks = 0;
|
||||||
self.mask_state_dirty = true;
|
self.mask_state_dirty = true;
|
||||||
|
|
||||||
self.mult_color = None;
|
self.mult_color = None;
|
||||||
|
@ -1212,48 +1211,35 @@ impl RenderBackend for WebGlRenderBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_mask(&mut self) {
|
fn push_mask(&mut self) {
|
||||||
// Desktop draws the masker to the stencil buffer, one bit per mask.
|
assert!(
|
||||||
// Masks-within-masks are handled as a bitmask.
|
self.mask_state == MaskState::NoMask || self.mask_state == MaskState::DrawMaskedContent
|
||||||
// This does unfortunately mean we are limited in the number of masks at once (usually 8 bits).
|
|
||||||
if self.next_stencil_mask >= 0x100 {
|
|
||||||
// If we've reached the limit of masks, clear the stencil buffer and start over.
|
|
||||||
// But this may not be correct if there is still a mask active (mask-within-mask).
|
|
||||||
if self.test_stencil_mask != 0 {
|
|
||||||
log::warn!(
|
|
||||||
"Too many masks active for stencil buffer; possibly incorrect rendering"
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
self.next_stencil_mask = 1;
|
|
||||||
self.gl.stencil_mask(0xff);
|
|
||||||
self.gl.clear_stencil(self.test_stencil_mask as i32);
|
|
||||||
self.gl.clear(Gl::STENCIL_BUFFER_BIT);
|
|
||||||
self.gl.clear_stencil(0);
|
|
||||||
}
|
|
||||||
self.num_masks += 1;
|
self.num_masks += 1;
|
||||||
self.mask_stack
|
self.mask_state = MaskState::DrawMaskStencil;
|
||||||
.push((self.write_stencil_mask, self.test_stencil_mask));
|
|
||||||
self.write_stencil_mask = self.next_stencil_mask;
|
|
||||||
self.test_stencil_mask |= self.next_stencil_mask;
|
|
||||||
self.next_stencil_mask <<= 1;
|
|
||||||
self.mask_state_dirty = true;
|
self.mask_state_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate_mask(&mut self) {
|
fn activate_mask(&mut self) {
|
||||||
self.num_masks_active += 1;
|
assert!(self.num_masks > 0 && self.mask_state == MaskState::DrawMaskStencil);
|
||||||
|
self.mask_state = MaskState::DrawMaskedContent;
|
||||||
|
self.mask_state_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deactivate_mask(&mut self) {
|
||||||
|
assert!(self.num_masks > 0 && self.mask_state == MaskState::DrawMaskedContent);
|
||||||
|
self.mask_state = MaskState::ClearMaskStencil;
|
||||||
self.mask_state_dirty = true;
|
self.mask_state_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_mask(&mut self) {
|
fn pop_mask(&mut self) {
|
||||||
if !self.mask_stack.is_empty() {
|
assert!(self.num_masks > 0 && self.mask_state == MaskState::ClearMaskStencil);
|
||||||
self.num_masks -= 1;
|
self.num_masks -= 1;
|
||||||
self.num_masks_active -= 1;
|
self.mask_state = if self.num_masks == 0 {
|
||||||
let (write, test) = self.mask_stack.pop().unwrap();
|
MaskState::NoMask
|
||||||
self.write_stencil_mask = write;
|
|
||||||
self.test_stencil_mask = test;
|
|
||||||
self.mask_state_dirty = true;
|
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Mask stack underflow\n");
|
MaskState::DrawMaskedContent
|
||||||
}
|
};
|
||||||
|
self.mask_state_dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ futures = "0.3.6"
|
||||||
bytemuck = "1.4.1"
|
bytemuck = "1.4.1"
|
||||||
raw-window-handle = "0.3.3"
|
raw-window-handle = "0.3.3"
|
||||||
clap = { version = "3.0.0-beta.2", optional = true }
|
clap = { version = "3.0.0-beta.2", optional = true }
|
||||||
|
enum-map = "0.6.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
render_debug_labels = []
|
render_debug_labels = []
|
||||||
|
|
|
@ -24,6 +24,7 @@ use crate::utils::{
|
||||||
gradient_spread_mode_index, ruffle_path_to_lyon_path, swf_bitmap_to_gl_matrix,
|
gradient_spread_mode_index, ruffle_path_to_lyon_path, swf_bitmap_to_gl_matrix,
|
||||||
swf_to_gl_matrix,
|
swf_to_gl_matrix,
|
||||||
};
|
};
|
||||||
|
use enum_map::Enum;
|
||||||
use ruffle_core::color_transform::ColorTransform;
|
use ruffle_core::color_transform::ColorTransform;
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -59,17 +60,21 @@ pub struct WgpuRenderBackend<T: RenderTarget> {
|
||||||
viewport_height: f32,
|
viewport_height: f32,
|
||||||
view_matrix: [[f32; 4]; 4],
|
view_matrix: [[f32; 4]; 4],
|
||||||
textures: Vec<(swf::CharacterId, Texture)>,
|
textures: Vec<(swf::CharacterId, Texture)>,
|
||||||
|
mask_state: MaskState,
|
||||||
num_masks: u32,
|
num_masks: u32,
|
||||||
num_masks_active: u32,
|
|
||||||
write_stencil_mask: u32,
|
|
||||||
test_stencil_mask: u32,
|
|
||||||
next_stencil_mask: u32,
|
|
||||||
mask_stack: Vec<(u32, u32)>,
|
|
||||||
quad_vbo: wgpu::Buffer,
|
quad_vbo: wgpu::Buffer,
|
||||||
quad_ibo: wgpu::Buffer,
|
quad_ibo: wgpu::Buffer,
|
||||||
quad_tex_transforms: wgpu::Buffer,
|
quad_tex_transforms: wgpu::Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Enum)]
|
||||||
|
pub enum MaskState {
|
||||||
|
NoMask,
|
||||||
|
DrawMaskStencil,
|
||||||
|
DrawMaskedContent,
|
||||||
|
ClearMaskStencil,
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
struct Transforms {
|
struct Transforms {
|
||||||
|
@ -238,12 +243,10 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
|
||||||
viewport_height,
|
viewport_height,
|
||||||
view_matrix,
|
view_matrix,
|
||||||
textures: Vec::new(),
|
textures: Vec::new(),
|
||||||
|
|
||||||
num_masks: 0,
|
num_masks: 0,
|
||||||
num_masks_active: 0,
|
mask_state: MaskState::NoMask,
|
||||||
write_stencil_mask: 0,
|
|
||||||
test_stencil_mask: 0,
|
|
||||||
next_stencil_mask: 1,
|
|
||||||
mask_stack: Vec::new(),
|
|
||||||
quad_vbo,
|
quad_vbo,
|
||||||
quad_ibo,
|
quad_ibo,
|
||||||
quad_tex_transforms,
|
quad_tex_transforms,
|
||||||
|
@ -829,11 +832,9 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.mask_state = MaskState::NoMask;
|
||||||
self.num_masks = 0;
|
self.num_masks = 0;
|
||||||
self.num_masks_active = 0;
|
|
||||||
self.write_stencil_mask = 0;
|
|
||||||
self.test_stencil_mask = 0;
|
|
||||||
self.next_stencil_mask = 1;
|
|
||||||
|
|
||||||
if let Some((frame_output, encoder)) = &mut self.current_frame {
|
if let Some((frame_output, encoder)) = &mut self.current_frame {
|
||||||
let (color_attachment, resolve_target) = if self.msaa_sample_count >= 2 {
|
let (color_attachment, resolve_target) = if self.msaa_sample_count >= 2 {
|
||||||
|
@ -1006,21 +1007,22 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
render_pass.set_pipeline(&self.pipelines.bitmap.pipeline_for(
|
render_pass.set_pipeline(&self.pipelines.bitmap.pipeline_for(self.mask_state));
|
||||||
self.num_masks,
|
|
||||||
self.num_masks_active,
|
|
||||||
self.test_stencil_mask,
|
|
||||||
self.write_stencil_mask,
|
|
||||||
));
|
|
||||||
render_pass.set_bind_group(0, &bind_group, &[]);
|
render_pass.set_bind_group(0, &bind_group, &[]);
|
||||||
render_pass.set_vertex_buffer(0, self.quad_vbo.slice(..));
|
render_pass.set_vertex_buffer(0, self.quad_vbo.slice(..));
|
||||||
render_pass.set_index_buffer(self.quad_ibo.slice(..));
|
render_pass.set_index_buffer(self.quad_ibo.slice(..));
|
||||||
|
|
||||||
if self.num_masks_active < self.num_masks {
|
match self.mask_state {
|
||||||
render_pass.set_stencil_reference(self.write_stencil_mask);
|
MaskState::NoMask => (),
|
||||||
} else {
|
MaskState::DrawMaskStencil => {
|
||||||
render_pass.set_stencil_reference(self.test_stencil_mask);
|
debug_assert!(self.num_masks > 0);
|
||||||
|
render_pass.set_stencil_reference(self.num_masks - 1);
|
||||||
}
|
}
|
||||||
|
MaskState::DrawMaskedContent | MaskState::ClearMaskStencil => {
|
||||||
|
debug_assert!(self.num_masks > 0);
|
||||||
|
render_pass.set_stencil_reference(self.num_masks);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render_pass.draw_indexed(0..6, 0, 0..1);
|
render_pass.draw_indexed(0..6, 0, 0..1);
|
||||||
}
|
}
|
||||||
|
@ -1115,28 +1117,14 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
for draw in &mesh.draws {
|
for draw in &mesh.draws {
|
||||||
match &draw.draw_type {
|
match &draw.draw_type {
|
||||||
DrawType::Color => {
|
DrawType::Color => {
|
||||||
render_pass.set_pipeline(&self.pipelines.color.pipeline_for(
|
render_pass.set_pipeline(&self.pipelines.color.pipeline_for(self.mask_state));
|
||||||
self.num_masks,
|
|
||||||
self.num_masks_active,
|
|
||||||
self.test_stencil_mask,
|
|
||||||
self.write_stencil_mask,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
DrawType::Gradient { .. } => {
|
DrawType::Gradient { .. } => {
|
||||||
render_pass.set_pipeline(&self.pipelines.gradient.pipeline_for(
|
render_pass
|
||||||
self.num_masks,
|
.set_pipeline(&self.pipelines.gradient.pipeline_for(self.mask_state));
|
||||||
self.num_masks_active,
|
|
||||||
self.test_stencil_mask,
|
|
||||||
self.write_stencil_mask,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
DrawType::Bitmap { .. } => {
|
DrawType::Bitmap { .. } => {
|
||||||
render_pass.set_pipeline(&self.pipelines.bitmap.pipeline_for(
|
render_pass.set_pipeline(&self.pipelines.bitmap.pipeline_for(self.mask_state));
|
||||||
self.num_masks,
|
|
||||||
self.num_masks_active,
|
|
||||||
self.test_stencil_mask,
|
|
||||||
self.write_stencil_mask,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1144,11 +1132,17 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
render_pass.set_vertex_buffer(0, draw.vertex_buffer.slice(..));
|
render_pass.set_vertex_buffer(0, draw.vertex_buffer.slice(..));
|
||||||
render_pass.set_index_buffer(draw.index_buffer.slice(..));
|
render_pass.set_index_buffer(draw.index_buffer.slice(..));
|
||||||
|
|
||||||
if self.num_masks_active < self.num_masks {
|
match self.mask_state {
|
||||||
render_pass.set_stencil_reference(self.write_stencil_mask);
|
MaskState::NoMask => (),
|
||||||
} else {
|
MaskState::DrawMaskStencil => {
|
||||||
render_pass.set_stencil_reference(self.test_stencil_mask);
|
debug_assert!(self.num_masks > 0);
|
||||||
|
render_pass.set_stencil_reference(self.num_masks - 1);
|
||||||
}
|
}
|
||||||
|
MaskState::DrawMaskedContent | MaskState::ClearMaskStencil => {
|
||||||
|
debug_assert!(self.num_masks > 0);
|
||||||
|
render_pass.set_stencil_reference(self.num_masks);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render_pass.draw_indexed(0..draw.index_count, 0, 0..1);
|
render_pass.draw_indexed(0..draw.index_count, 0, 0..1);
|
||||||
}
|
}
|
||||||
|
@ -1254,21 +1248,22 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
render_pass.set_pipeline(&self.pipelines.color.pipeline_for(
|
render_pass.set_pipeline(&self.pipelines.color.pipeline_for(self.mask_state));
|
||||||
self.num_masks,
|
|
||||||
self.num_masks_active,
|
|
||||||
self.test_stencil_mask,
|
|
||||||
self.write_stencil_mask,
|
|
||||||
));
|
|
||||||
render_pass.set_bind_group(0, &bind_group, &[]);
|
render_pass.set_bind_group(0, &bind_group, &[]);
|
||||||
render_pass.set_vertex_buffer(0, self.quad_vbo.slice(..));
|
render_pass.set_vertex_buffer(0, self.quad_vbo.slice(..));
|
||||||
render_pass.set_index_buffer(self.quad_ibo.slice(..));
|
render_pass.set_index_buffer(self.quad_ibo.slice(..));
|
||||||
|
|
||||||
if self.num_masks_active < self.num_masks {
|
match self.mask_state {
|
||||||
render_pass.set_stencil_reference(self.write_stencil_mask);
|
MaskState::NoMask => (),
|
||||||
} else {
|
MaskState::DrawMaskStencil => {
|
||||||
render_pass.set_stencil_reference(self.test_stencil_mask);
|
debug_assert!(self.num_masks > 0);
|
||||||
|
render_pass.set_stencil_reference(self.num_masks - 1);
|
||||||
}
|
}
|
||||||
|
MaskState::DrawMaskedContent | MaskState::ClearMaskStencil => {
|
||||||
|
debug_assert!(self.num_masks > 0);
|
||||||
|
render_pass.set_stencil_reference(self.num_masks);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render_pass.draw_indexed(0..6, 0, 0..1);
|
render_pass.draw_indexed(0..6, 0, 0..1);
|
||||||
}
|
}
|
||||||
|
@ -1362,69 +1357,31 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_mask(&mut self) {
|
fn push_mask(&mut self) {
|
||||||
// Desktop draws the masker to the stencil buffer, one bit per mask.
|
assert!(
|
||||||
// Masks-within-masks are handled as a bitmask.
|
self.mask_state == MaskState::NoMask || self.mask_state == MaskState::DrawMaskedContent
|
||||||
// This does unfortunately mean we are limited in the number of masks at once (8 bits).
|
|
||||||
if self.next_stencil_mask >= 0x100 {
|
|
||||||
// If we've reached the limit of masks, clear the stencil buffer and start over.
|
|
||||||
// But this may not be correct if there is still a mask active (mask-within-mask).
|
|
||||||
if self.test_stencil_mask != 0 {
|
|
||||||
log::warn!(
|
|
||||||
"Too many masks active for stencil buffer; possibly incorrect rendering"
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
self.next_stencil_mask = 1;
|
|
||||||
if let Some((frame_output, encoder)) = &mut self.current_frame {
|
|
||||||
let (color_attachment, resolve_target) = if self.msaa_sample_count >= 2 {
|
|
||||||
(&self.frame_buffer_view, Some(frame_output.view()))
|
|
||||||
} else {
|
|
||||||
(frame_output.view(), None)
|
|
||||||
};
|
|
||||||
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
||||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
|
||||||
attachment: color_attachment,
|
|
||||||
resolve_target,
|
|
||||||
ops: wgpu::Operations {
|
|
||||||
load: wgpu::LoadOp::Load,
|
|
||||||
store: true,
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
depth_stencil_attachment: Some(
|
|
||||||
wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
|
||||||
attachment: &self.depth_texture_view,
|
|
||||||
depth_ops: Some(wgpu::Operations {
|
|
||||||
load: wgpu::LoadOp::Load,
|
|
||||||
store: true,
|
|
||||||
}),
|
|
||||||
stencil_ops: Some(wgpu::Operations {
|
|
||||||
load: wgpu::LoadOp::Clear(self.test_stencil_mask),
|
|
||||||
store: true,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.num_masks += 1;
|
self.num_masks += 1;
|
||||||
self.mask_stack
|
self.mask_state = MaskState::DrawMaskStencil;
|
||||||
.push((self.write_stencil_mask, self.test_stencil_mask));
|
|
||||||
self.write_stencil_mask = self.next_stencil_mask;
|
|
||||||
self.test_stencil_mask |= self.next_stencil_mask;
|
|
||||||
self.next_stencil_mask <<= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate_mask(&mut self) {
|
fn activate_mask(&mut self) {
|
||||||
self.num_masks_active += 1;
|
assert!(self.num_masks > 0 && self.mask_state == MaskState::DrawMaskStencil);
|
||||||
|
self.mask_state = MaskState::DrawMaskedContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deactivate_mask(&mut self) {
|
||||||
|
assert!(self.num_masks > 0 && self.mask_state == MaskState::DrawMaskedContent);
|
||||||
|
self.mask_state = MaskState::ClearMaskStencil;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_mask(&mut self) {
|
fn pop_mask(&mut self) {
|
||||||
if !self.mask_stack.is_empty() {
|
assert!(self.num_masks > 0 && self.mask_state == MaskState::ClearMaskStencil);
|
||||||
self.num_masks -= 1;
|
self.num_masks -= 1;
|
||||||
self.num_masks_active -= 1;
|
self.mask_state = if self.num_masks == 0 {
|
||||||
let (write, test) = self.mask_stack.pop().unwrap();
|
MaskState::NoMask
|
||||||
self.write_stencil_mask = write;
|
} else {
|
||||||
self.test_stencil_mask = test;
|
MaskState::DrawMaskedContent
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::{Error, GPUVertex};
|
use crate::{Error, GPUVertex, MaskState};
|
||||||
|
use enum_map::{enum_map, EnumMap};
|
||||||
use wgpu::vertex_attr_array;
|
use wgpu::vertex_attr_array;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ShapePipeline {
|
pub struct ShapePipeline {
|
||||||
pub write_mask_pipelines: Vec<wgpu::RenderPipeline>,
|
pub mask_pipelines: EnumMap<MaskState, wgpu::RenderPipeline>,
|
||||||
pub read_mask_pipelines: Vec<wgpu::RenderPipeline>,
|
|
||||||
pub bind_layout: wgpu::BindGroupLayout,
|
pub bind_layout: wgpu::BindGroupLayout,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,18 +16,8 @@ pub struct Pipelines {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShapePipeline {
|
impl ShapePipeline {
|
||||||
pub fn pipeline_for(
|
pub fn pipeline_for(&self, mask_state: MaskState) -> &wgpu::RenderPipeline {
|
||||||
&self,
|
&self.mask_pipelines[mask_state]
|
||||||
num_masks: u32,
|
|
||||||
num_masks_active: u32,
|
|
||||||
read_mask: u32,
|
|
||||||
write_mask: u32,
|
|
||||||
) -> &wgpu::RenderPipeline {
|
|
||||||
if num_masks_active < num_masks {
|
|
||||||
&self.write_mask_pipelines[write_mask.trailing_zeros() as usize]
|
|
||||||
} else {
|
|
||||||
&self.read_mask_pipelines[read_mask as usize]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,13 +152,11 @@ fn create_color_pipelines(
|
||||||
push_constant_ranges: &[],
|
push_constant_ranges: &[],
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut write_mask_pipelines = Vec::new();
|
let mask_pipelines = enum_map! {
|
||||||
let mut read_mask_pipelines = Vec::new();
|
MaskState::NoMask => {
|
||||||
|
let (stencil, write_mask) = mask_render_state(MaskState::NoMask);
|
||||||
for i in 0..8 {
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
let label = create_debug_label!("Color pipeline write mask {}", i);
|
create_debug_label!("Color pipeline no mask").as_deref(),
|
||||||
write_mask_pipelines.push(device.create_render_pipeline(&create_pipeline_descriptor(
|
|
||||||
label.as_deref(),
|
|
||||||
vertex_shader,
|
vertex_shader,
|
||||||
fragment_shader,
|
fragment_shader,
|
||||||
&pipeline_layout,
|
&pipeline_layout,
|
||||||
|
@ -176,22 +164,7 @@ fn create_color_pipelines(
|
||||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
depth_write_enabled: true,
|
depth_write_enabled: true,
|
||||||
depth_compare: wgpu::CompareFunction::Always,
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
stencil: wgpu::StencilStateDescriptor {
|
stencil,
|
||||||
front: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Always,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Replace,
|
|
||||||
},
|
|
||||||
back: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Always,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Replace,
|
|
||||||
},
|
|
||||||
read_mask: 0xff,
|
|
||||||
write_mask: 1 << i,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
&[wgpu::ColorStateDescriptor {
|
&[wgpu::ColorStateDescriptor {
|
||||||
format: wgpu::TextureFormat::Bgra8Unorm,
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
@ -205,17 +178,17 @@ fn create_color_pipelines(
|
||||||
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
operation: wgpu::BlendOperation::Add,
|
operation: wgpu::BlendOperation::Add,
|
||||||
},
|
},
|
||||||
write_mask: wgpu::ColorWrite::empty(),
|
write_mask,
|
||||||
}],
|
}],
|
||||||
vertex_buffers_description,
|
vertex_buffers_description,
|
||||||
msaa_sample_count,
|
msaa_sample_count,
|
||||||
)));
|
))
|
||||||
}
|
},
|
||||||
|
|
||||||
for i in 0..256 {
|
MaskState::DrawMaskStencil => {
|
||||||
let label = create_debug_label!("Color pipeline read mask {}", i);
|
let (stencil, write_mask) = mask_render_state(MaskState::DrawMaskStencil);
|
||||||
read_mask_pipelines.push(device.create_render_pipeline(&create_pipeline_descriptor(
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
label.as_deref(),
|
create_debug_label!("Color pipeline draw mask stencil").as_deref(),
|
||||||
vertex_shader,
|
vertex_shader,
|
||||||
fragment_shader,
|
fragment_shader,
|
||||||
&pipeline_layout,
|
&pipeline_layout,
|
||||||
|
@ -223,22 +196,7 @@ fn create_color_pipelines(
|
||||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
depth_write_enabled: true,
|
depth_write_enabled: true,
|
||||||
depth_compare: wgpu::CompareFunction::Always,
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
stencil: wgpu::StencilStateDescriptor {
|
stencil,
|
||||||
front: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Equal,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Keep,
|
|
||||||
},
|
|
||||||
back: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Equal,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Keep,
|
|
||||||
},
|
|
||||||
read_mask: i,
|
|
||||||
write_mask: 0,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
&[wgpu::ColorStateDescriptor {
|
&[wgpu::ColorStateDescriptor {
|
||||||
format: wgpu::TextureFormat::Bgra8Unorm,
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
@ -252,16 +210,80 @@ fn create_color_pipelines(
|
||||||
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
operation: wgpu::BlendOperation::Add,
|
operation: wgpu::BlendOperation::Add,
|
||||||
},
|
},
|
||||||
write_mask: wgpu::ColorWrite::ALL,
|
write_mask,
|
||||||
}],
|
}],
|
||||||
vertex_buffers_description,
|
vertex_buffers_description,
|
||||||
msaa_sample_count,
|
msaa_sample_count,
|
||||||
)));
|
))
|
||||||
}
|
},
|
||||||
|
|
||||||
|
MaskState::DrawMaskedContent => {
|
||||||
|
let (stencil, write_mask) = mask_render_state(MaskState::DrawMaskedContent);
|
||||||
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
|
create_debug_label!("Color pipeline draw masked content").as_deref(),
|
||||||
|
vertex_shader,
|
||||||
|
fragment_shader,
|
||||||
|
&pipeline_layout,
|
||||||
|
Some(wgpu::DepthStencilStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
|
depth_write_enabled: true,
|
||||||
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
|
stencil,
|
||||||
|
}),
|
||||||
|
&[wgpu::ColorStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
color_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
alpha_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
write_mask,
|
||||||
|
}],
|
||||||
|
vertex_buffers_description,
|
||||||
|
msaa_sample_count,
|
||||||
|
))
|
||||||
|
},
|
||||||
|
|
||||||
|
MaskState::ClearMaskStencil => {
|
||||||
|
let (stencil, write_mask) = mask_render_state(MaskState::ClearMaskStencil);
|
||||||
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
|
create_debug_label!("Color pipeline clear mask stencil").as_deref(),
|
||||||
|
vertex_shader,
|
||||||
|
fragment_shader,
|
||||||
|
&pipeline_layout,
|
||||||
|
Some(wgpu::DepthStencilStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
|
depth_write_enabled: true,
|
||||||
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
|
stencil,
|
||||||
|
}),
|
||||||
|
&[wgpu::ColorStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
color_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
alpha_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
write_mask,
|
||||||
|
}],
|
||||||
|
vertex_buffers_description,
|
||||||
|
msaa_sample_count,
|
||||||
|
))
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
ShapePipeline {
|
ShapePipeline {
|
||||||
write_mask_pipelines,
|
mask_pipelines,
|
||||||
read_mask_pipelines,
|
|
||||||
bind_layout,
|
bind_layout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,13 +352,11 @@ fn create_bitmap_pipeline(
|
||||||
push_constant_ranges: &[],
|
push_constant_ranges: &[],
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut write_mask_pipelines = Vec::new();
|
let mask_pipelines = enum_map! {
|
||||||
let mut read_mask_pipelines = Vec::new();
|
MaskState::NoMask => {
|
||||||
|
let (stencil, write_mask) = mask_render_state(MaskState::NoMask);
|
||||||
for i in 0..8 {
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
let label = create_debug_label!("Bitmap pipeline write mask {}", i);
|
create_debug_label!("Bitmap pipeline no mask").as_deref(),
|
||||||
write_mask_pipelines.push(device.create_render_pipeline(&create_pipeline_descriptor(
|
|
||||||
label.as_deref(),
|
|
||||||
vertex_shader,
|
vertex_shader,
|
||||||
fragment_shader,
|
fragment_shader,
|
||||||
&pipeline_layout,
|
&pipeline_layout,
|
||||||
|
@ -344,22 +364,7 @@ fn create_bitmap_pipeline(
|
||||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
depth_write_enabled: true,
|
depth_write_enabled: true,
|
||||||
depth_compare: wgpu::CompareFunction::Always,
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
stencil: wgpu::StencilStateDescriptor {
|
stencil,
|
||||||
front: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Always,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Replace,
|
|
||||||
},
|
|
||||||
back: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Always,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Replace,
|
|
||||||
},
|
|
||||||
read_mask: 0xff,
|
|
||||||
write_mask: 1 << i,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
&[wgpu::ColorStateDescriptor {
|
&[wgpu::ColorStateDescriptor {
|
||||||
format: wgpu::TextureFormat::Bgra8Unorm,
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
@ -373,17 +378,17 @@ fn create_bitmap_pipeline(
|
||||||
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
operation: wgpu::BlendOperation::Add,
|
operation: wgpu::BlendOperation::Add,
|
||||||
},
|
},
|
||||||
write_mask: wgpu::ColorWrite::empty(),
|
write_mask,
|
||||||
}],
|
}],
|
||||||
vertex_buffers_description,
|
vertex_buffers_description,
|
||||||
msaa_sample_count,
|
msaa_sample_count,
|
||||||
)));
|
))
|
||||||
}
|
},
|
||||||
|
|
||||||
for i in 0..256 {
|
MaskState::DrawMaskStencil => {
|
||||||
let label = create_debug_label!("Bitmap pipeline read mask {}", i);
|
let (stencil, write_mask) = mask_render_state(MaskState::DrawMaskStencil);
|
||||||
read_mask_pipelines.push(device.create_render_pipeline(&create_pipeline_descriptor(
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
label.as_deref(),
|
create_debug_label!("Bitmap pipeline draw mask stencil").as_deref(),
|
||||||
vertex_shader,
|
vertex_shader,
|
||||||
fragment_shader,
|
fragment_shader,
|
||||||
&pipeline_layout,
|
&pipeline_layout,
|
||||||
|
@ -391,27 +396,12 @@ fn create_bitmap_pipeline(
|
||||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
depth_write_enabled: true,
|
depth_write_enabled: true,
|
||||||
depth_compare: wgpu::CompareFunction::Always,
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
stencil: wgpu::StencilStateDescriptor {
|
stencil,
|
||||||
front: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Equal,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Keep,
|
|
||||||
},
|
|
||||||
back: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Equal,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Keep,
|
|
||||||
},
|
|
||||||
read_mask: i,
|
|
||||||
write_mask: 0,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
&[wgpu::ColorStateDescriptor {
|
&[wgpu::ColorStateDescriptor {
|
||||||
format: wgpu::TextureFormat::Bgra8Unorm,
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
color_blend: wgpu::BlendDescriptor {
|
color_blend: wgpu::BlendDescriptor {
|
||||||
src_factor: wgpu::BlendFactor::One,
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
operation: wgpu::BlendOperation::Add,
|
operation: wgpu::BlendOperation::Add,
|
||||||
},
|
},
|
||||||
|
@ -420,16 +410,80 @@ fn create_bitmap_pipeline(
|
||||||
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
operation: wgpu::BlendOperation::Add,
|
operation: wgpu::BlendOperation::Add,
|
||||||
},
|
},
|
||||||
write_mask: wgpu::ColorWrite::ALL,
|
write_mask,
|
||||||
}],
|
}],
|
||||||
vertex_buffers_description,
|
vertex_buffers_description,
|
||||||
msaa_sample_count,
|
msaa_sample_count,
|
||||||
)));
|
))
|
||||||
|
},
|
||||||
|
|
||||||
|
MaskState::DrawMaskedContent => {
|
||||||
|
let (stencil, write_mask) = mask_render_state(MaskState::DrawMaskedContent);
|
||||||
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
|
create_debug_label!("Bitmap pipeline draw masked content").as_deref(),
|
||||||
|
vertex_shader,
|
||||||
|
fragment_shader,
|
||||||
|
&pipeline_layout,
|
||||||
|
Some(wgpu::DepthStencilStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
|
depth_write_enabled: true,
|
||||||
|
depth_compare: wgpu::CompareFunction::Equal,
|
||||||
|
stencil,
|
||||||
|
}),
|
||||||
|
&[wgpu::ColorStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
color_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
alpha_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
write_mask,
|
||||||
|
}],
|
||||||
|
vertex_buffers_description,
|
||||||
|
msaa_sample_count,
|
||||||
|
))
|
||||||
|
},
|
||||||
|
|
||||||
|
MaskState::ClearMaskStencil => {
|
||||||
|
let (stencil, write_mask) = mask_render_state(MaskState::ClearMaskStencil);
|
||||||
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
|
create_debug_label!("Bitmap pipeline clear mask stencil").as_deref(),
|
||||||
|
vertex_shader,
|
||||||
|
fragment_shader,
|
||||||
|
&pipeline_layout,
|
||||||
|
Some(wgpu::DepthStencilStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
|
depth_write_enabled: true,
|
||||||
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
|
stencil,
|
||||||
|
}),
|
||||||
|
&[wgpu::ColorStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
color_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
alpha_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
write_mask,
|
||||||
|
}],
|
||||||
|
vertex_buffers_description,
|
||||||
|
msaa_sample_count,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ShapePipeline {
|
ShapePipeline {
|
||||||
write_mask_pipelines,
|
mask_pipelines,
|
||||||
read_mask_pipelines,
|
|
||||||
bind_layout,
|
bind_layout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -492,13 +546,11 @@ fn create_gradient_pipeline(
|
||||||
push_constant_ranges: &[],
|
push_constant_ranges: &[],
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut write_mask_pipelines = Vec::new();
|
let mask_pipelines = enum_map! {
|
||||||
let mut read_mask_pipelines = Vec::new();
|
MaskState::NoMask => {
|
||||||
|
let (stencil, write_mask) = mask_render_state(MaskState::NoMask);
|
||||||
for i in 0..8 {
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
let label = create_debug_label!("Gradient pipeline write mask {}", i);
|
create_debug_label!("Gradient pipeline no mask").as_deref(),
|
||||||
write_mask_pipelines.push(device.create_render_pipeline(&create_pipeline_descriptor(
|
|
||||||
label.as_deref(),
|
|
||||||
vertex_shader,
|
vertex_shader,
|
||||||
fragment_shader,
|
fragment_shader,
|
||||||
&pipeline_layout,
|
&pipeline_layout,
|
||||||
|
@ -506,22 +558,7 @@ fn create_gradient_pipeline(
|
||||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
depth_write_enabled: true,
|
depth_write_enabled: true,
|
||||||
depth_compare: wgpu::CompareFunction::Always,
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
stencil: wgpu::StencilStateDescriptor {
|
stencil,
|
||||||
front: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Always,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Replace,
|
|
||||||
},
|
|
||||||
back: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Always,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Replace,
|
|
||||||
},
|
|
||||||
read_mask: 0xff,
|
|
||||||
write_mask: 1 << i,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
&[wgpu::ColorStateDescriptor {
|
&[wgpu::ColorStateDescriptor {
|
||||||
format: wgpu::TextureFormat::Bgra8Unorm,
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
@ -535,17 +572,17 @@ fn create_gradient_pipeline(
|
||||||
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
operation: wgpu::BlendOperation::Add,
|
operation: wgpu::BlendOperation::Add,
|
||||||
},
|
},
|
||||||
write_mask: wgpu::ColorWrite::empty(),
|
write_mask,
|
||||||
}],
|
}],
|
||||||
vertex_buffers_description,
|
vertex_buffers_description,
|
||||||
msaa_sample_count,
|
msaa_sample_count,
|
||||||
)));
|
))
|
||||||
}
|
},
|
||||||
|
|
||||||
for i in 0..256 {
|
MaskState::DrawMaskStencil => {
|
||||||
let label = create_debug_label!("Gradient pipeline read mask {}", i);
|
let (stencil, write_mask) = mask_render_state(MaskState::DrawMaskStencil);
|
||||||
read_mask_pipelines.push(device.create_render_pipeline(&create_pipeline_descriptor(
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
label.as_deref(),
|
create_debug_label!("Gradient pipeline draw mask stencil").as_deref(),
|
||||||
vertex_shader,
|
vertex_shader,
|
||||||
fragment_shader,
|
fragment_shader,
|
||||||
&pipeline_layout,
|
&pipeline_layout,
|
||||||
|
@ -553,22 +590,7 @@ fn create_gradient_pipeline(
|
||||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
depth_write_enabled: true,
|
depth_write_enabled: true,
|
||||||
depth_compare: wgpu::CompareFunction::Always,
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
stencil: wgpu::StencilStateDescriptor {
|
stencil,
|
||||||
front: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Equal,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Keep,
|
|
||||||
},
|
|
||||||
back: wgpu::StencilStateFaceDescriptor {
|
|
||||||
compare: wgpu::CompareFunction::Equal,
|
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
|
||||||
pass_op: wgpu::StencilOperation::Keep,
|
|
||||||
},
|
|
||||||
read_mask: i,
|
|
||||||
write_mask: 0,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
&[wgpu::ColorStateDescriptor {
|
&[wgpu::ColorStateDescriptor {
|
||||||
format: wgpu::TextureFormat::Bgra8Unorm,
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
@ -582,16 +604,132 @@ fn create_gradient_pipeline(
|
||||||
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
operation: wgpu::BlendOperation::Add,
|
operation: wgpu::BlendOperation::Add,
|
||||||
},
|
},
|
||||||
write_mask: wgpu::ColorWrite::ALL,
|
write_mask,
|
||||||
}],
|
}],
|
||||||
vertex_buffers_description,
|
vertex_buffers_description,
|
||||||
msaa_sample_count,
|
msaa_sample_count,
|
||||||
)));
|
))
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
MaskState::DrawMaskedContent => {
|
||||||
|
let (stencil, write_mask) = mask_render_state(MaskState::DrawMaskedContent);
|
||||||
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
|
create_debug_label!("Gradient pipeline draw masked content").as_deref(),
|
||||||
|
vertex_shader,
|
||||||
|
fragment_shader,
|
||||||
|
&pipeline_layout,
|
||||||
|
Some(wgpu::DepthStencilStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
|
depth_write_enabled: true,
|
||||||
|
depth_compare: wgpu::CompareFunction::Equal,
|
||||||
|
stencil,
|
||||||
|
}),
|
||||||
|
&[wgpu::ColorStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
color_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
alpha_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
write_mask,
|
||||||
|
}],
|
||||||
|
vertex_buffers_description,
|
||||||
|
msaa_sample_count,
|
||||||
|
))
|
||||||
|
},
|
||||||
|
|
||||||
|
MaskState::ClearMaskStencil => {
|
||||||
|
let (stencil, write_mask) = mask_render_state(MaskState::ClearMaskStencil);
|
||||||
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
|
create_debug_label!("Gradient pipeline clear mask stencil").as_deref(),
|
||||||
|
vertex_shader,
|
||||||
|
fragment_shader,
|
||||||
|
&pipeline_layout,
|
||||||
|
Some(wgpu::DepthStencilStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
|
depth_write_enabled: true,
|
||||||
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
|
stencil,
|
||||||
|
}),
|
||||||
|
&[wgpu::ColorStateDescriptor {
|
||||||
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
color_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
alpha_blend: wgpu::BlendDescriptor {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
write_mask,
|
||||||
|
}],
|
||||||
|
vertex_buffers_description,
|
||||||
|
msaa_sample_count,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ShapePipeline {
|
ShapePipeline {
|
||||||
write_mask_pipelines,
|
mask_pipelines,
|
||||||
read_mask_pipelines,
|
|
||||||
bind_layout,
|
bind_layout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mask_render_state(state: MaskState) -> (wgpu::StencilStateDescriptor, wgpu::ColorWrite) {
|
||||||
|
let (stencil_state, color_write) = match state {
|
||||||
|
MaskState::NoMask => (
|
||||||
|
wgpu::StencilStateFaceDescriptor {
|
||||||
|
compare: wgpu::CompareFunction::Always,
|
||||||
|
fail_op: wgpu::StencilOperation::Keep,
|
||||||
|
depth_fail_op: wgpu::StencilOperation::Keep,
|
||||||
|
pass_op: wgpu::StencilOperation::Keep,
|
||||||
|
},
|
||||||
|
wgpu::ColorWrite::ALL,
|
||||||
|
),
|
||||||
|
MaskState::DrawMaskStencil => (
|
||||||
|
wgpu::StencilStateFaceDescriptor {
|
||||||
|
compare: wgpu::CompareFunction::Equal,
|
||||||
|
fail_op: wgpu::StencilOperation::Keep,
|
||||||
|
depth_fail_op: wgpu::StencilOperation::Keep,
|
||||||
|
pass_op: wgpu::StencilOperation::IncrementClamp,
|
||||||
|
},
|
||||||
|
wgpu::ColorWrite::empty(),
|
||||||
|
),
|
||||||
|
MaskState::DrawMaskedContent => (
|
||||||
|
wgpu::StencilStateFaceDescriptor {
|
||||||
|
compare: wgpu::CompareFunction::Equal,
|
||||||
|
fail_op: wgpu::StencilOperation::Keep,
|
||||||
|
depth_fail_op: wgpu::StencilOperation::Keep,
|
||||||
|
pass_op: wgpu::StencilOperation::Keep,
|
||||||
|
},
|
||||||
|
wgpu::ColorWrite::ALL,
|
||||||
|
),
|
||||||
|
MaskState::ClearMaskStencil => (
|
||||||
|
wgpu::StencilStateFaceDescriptor {
|
||||||
|
compare: wgpu::CompareFunction::Equal,
|
||||||
|
fail_op: wgpu::StencilOperation::Keep,
|
||||||
|
depth_fail_op: wgpu::StencilOperation::Keep,
|
||||||
|
pass_op: wgpu::StencilOperation::DecrementClamp,
|
||||||
|
},
|
||||||
|
wgpu::ColorWrite::empty(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
wgpu::StencilStateDescriptor {
|
||||||
|
front: stencil_state.clone(),
|
||||||
|
back: stencil_state,
|
||||||
|
read_mask: 0xff,
|
||||||
|
write_mask: 0xff,
|
||||||
|
},
|
||||||
|
color_write,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue