From d3c64d4eb7dfe8faee7fc0ecbe8e009a17cefdc6 Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Tue, 24 May 2022 16:19:59 -0700 Subject: [PATCH] webgl/wgpu: Omit strokes when drawing a mask stencil Adjust `common_tess` to add an additional `mask_index_count` to draws. This is used to not render strokes when drawing a shape as a mask stencil. Fixes #7027. --- render/common_tess/src/lib.rs | 27 +++++++++++++++++++++++---- render/webgl/src/lib.rs | 20 +++++++++++++++++++- render/wgpu/src/lib.rs | 26 +++++++++++++++++++++----- 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/render/common_tess/src/lib.rs b/render/common_tess/src/lib.rs index 2d02cae25..8b64468df 100644 --- a/render/common_tess/src/lib.rs +++ b/render/common_tess/src/lib.rs @@ -13,6 +13,8 @@ pub struct ShapeTessellator { stroke_tess: StrokeTessellator, mesh: Vec, lyon_mesh: VertexBuffers, + mask_index_count: Option, + is_stroke: bool, } impl ShapeTessellator { @@ -22,6 +24,8 @@ impl ShapeTessellator { stroke_tess: StrokeTessellator::new(), mesh: Vec::new(), lyon_mesh: VertexBuffers::new(), + mask_index_count: None, + is_stroke: false, } } @@ -33,9 +37,9 @@ impl ShapeTessellator { self.mesh = Vec::new(); self.lyon_mesh = VertexBuffers::new(); for path in shape.paths { - let (fill_style, lyon_path) = match &path { + let (fill_style, lyon_path, next_is_stroke) = match &path { DrawPath::Fill { style, commands } => { - (*style, ruffle_path_to_lyon_path(commands, true)) + (*style, ruffle_path_to_lyon_path(commands, true), false) } DrawPath::Stroke { style, @@ -44,6 +48,7 @@ impl ShapeTessellator { } => ( style.fill_style(), ruffle_path_to_lyon_path(&commands, *is_closed), + true, ), }; @@ -107,10 +112,19 @@ impl ShapeTessellator { } }; - if needs_flush { - // Non-solid color fills are isolated draw calls, so flush any pending color fill. + if needs_flush || (self.is_stroke && !next_is_stroke) { + // We flush separate draw calls in these cases: + // * Non-solid color fills which require their own shader. + // * Strokes followed by fills, because strokes need to be omitted + // when using this shape as a mask. self.flush_draw(DrawType::Color); + } else if !self.is_stroke && next_is_stroke { + // Bake solid color fills followed by strokes into a single draw call, and adjust + // the index count to omit the strokes when rendering this shape as a mask. + debug_assert!(self.mask_index_count.is_none()); + self.mask_index_count = Some(self.lyon_mesh.indices.len() as u32); } + self.is_stroke = next_is_stroke; let mut buffers_builder = BuffersBuilder::new(&mut self.lyon_mesh, RuffleVertexCtor { color }); @@ -187,9 +201,13 @@ impl ShapeTessellator { let draw_mesh = std::mem::replace(&mut self.lyon_mesh, VertexBuffers::new()); self.mesh.push(Draw { draw_type: draw, + mask_index_count: self + .mask_index_count + .unwrap_or(draw_mesh.indices.len() as u32), vertices: draw_mesh.vertices, indices: draw_mesh.indices, }); + self.mask_index_count = None; } } @@ -205,6 +223,7 @@ pub struct Draw { pub draw_type: DrawType, pub vertices: Vec, pub indices: Vec, + pub mask_index_count: u32, } pub enum DrawType { diff --git a/render/webgl/src/lib.rs b/render/webgl/src/lib.rs index 8ed5cc726..37689f223 100644 --- a/render/webgl/src/lib.rs +++ b/render/webgl/src/lib.rs @@ -348,6 +348,7 @@ impl WebGlRenderBackend { vertex_buffer, index_buffer, num_indices: 6, + num_mask_indices: 6, }], }; Ok(quad_mesh) @@ -501,6 +502,7 @@ impl WebGlRenderBackend { let mut draws = Vec::with_capacity(lyon_mesh.len()); for draw in lyon_mesh { let num_indices = draw.indices.len() as i32; + let num_mask_indices = draw.mask_index_count as i32; let vao = self.create_vertex_array().unwrap(); let vertex_buffer = self.gl.create_buffer().unwrap(); @@ -565,6 +567,7 @@ impl WebGlRenderBackend { vertex_buffer, index_buffer, num_indices, + num_mask_indices, }, TessDrawType::Gradient(gradient) => Draw { draw_type: DrawType::Gradient(Box::new(Gradient::from(gradient))), @@ -572,6 +575,7 @@ impl WebGlRenderBackend { vertex_buffer, index_buffer, num_indices, + num_mask_indices, }, TessDrawType::Bitmap(bitmap) => Draw { draw_type: DrawType::Bitmap(BitmapDraw { @@ -584,6 +588,7 @@ impl WebGlRenderBackend { vertex_buffer, index_buffer, num_indices, + num_mask_indices, }, }); @@ -947,6 +952,18 @@ impl RenderBackend for WebGlRenderBackend { let mesh = &self.meshes[shape.0]; for draw in &mesh.draws { + // Ignore strokes when drawing a mask stencil. + let num_indices = if self.mask_state != MaskState::DrawMaskStencil + && self.mask_state != MaskState::ClearMaskStencil + { + draw.num_indices + } else { + draw.num_mask_indices + }; + if num_indices == 0 { + continue; + } + self.bind_vertex_array(Some(&draw.vao)); let (program, src_blend, dst_blend) = match &draw.draw_type { @@ -1068,7 +1085,7 @@ impl RenderBackend for WebGlRenderBackend { // Draw the triangles. self.gl - .draw_elements_with_i32(Gl::TRIANGLES, draw.num_indices, Gl::UNSIGNED_INT, 0); + .draw_elements_with_i32(Gl::TRIANGLES, num_indices, Gl::UNSIGNED_INT, 0); } } @@ -1336,6 +1353,7 @@ struct Draw { index_buffer: WebGlBuffer, vao: WebGlVertexArrayObject, num_indices: i32, + num_mask_indices: i32, } enum DrawType { diff --git a/render/wgpu/src/lib.rs b/render/wgpu/src/lib.rs index 62d558db6..a736642df 100644 --- a/render/wgpu/src/lib.rs +++ b/render/wgpu/src/lib.rs @@ -283,7 +283,8 @@ struct Draw { draw_type: DrawType, vertex_buffer: wgpu::Buffer, index_buffer: wgpu::Buffer, - index_count: u32, + num_indices: u32, + num_mask_indices: u32, } #[allow(dead_code)] @@ -590,7 +591,8 @@ impl WgpuRenderBackend { draw_type: DrawType::Color, vertex_buffer, index_buffer, - index_count, + num_indices: index_count, + num_mask_indices: draw.mask_index_count, }, TessDrawType::Gradient(gradient) => { // TODO: Extract to function? @@ -672,7 +674,8 @@ impl WgpuRenderBackend { }, vertex_buffer, index_buffer, - index_count, + num_indices: index_count, + num_mask_indices: draw.mask_index_count, } } TessDrawType::Bitmap(bitmap) => { @@ -742,7 +745,8 @@ impl WgpuRenderBackend { }, vertex_buffer, index_buffer, - index_count, + num_indices: index_count, + num_mask_indices: draw.mask_index_count, } } }); @@ -1086,6 +1090,18 @@ impl RenderBackend for WgpuRenderBackend { ); for draw in &mesh.draws { + let num_indices = if self.mask_state != MaskState::DrawMaskStencil + && self.mask_state != MaskState::ClearMaskStencil + { + draw.num_indices + } else { + // Omit strokes when drawing a mask stencil. + draw.num_mask_indices + }; + if num_indices == 0 { + continue; + } + match &draw.draw_type { DrawType::Color => { frame.render_pass.set_pipeline( @@ -1146,7 +1162,7 @@ impl RenderBackend for WgpuRenderBackend { } }; - frame.render_pass.draw_indexed(0..draw.index_count, 0, 0..1); + frame.render_pass.draw_indexed(0..num_indices, 0, 0..1); } }