Skip to content

Commit d3c64d4

Browse files
committed
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 ruffle-rs#7027.
1 parent b39d54d commit d3c64d4

File tree

3 files changed

+63
-10
lines changed

3 files changed

+63
-10
lines changed

render/common_tess/src/lib.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub struct ShapeTessellator {
1313
stroke_tess: StrokeTessellator,
1414
mesh: Vec<Draw>,
1515
lyon_mesh: VertexBuffers<Vertex, u32>,
16+
mask_index_count: Option<u32>,
17+
is_stroke: bool,
1618
}
1719

1820
impl ShapeTessellator {
@@ -22,6 +24,8 @@ impl ShapeTessellator {
2224
stroke_tess: StrokeTessellator::new(),
2325
mesh: Vec::new(),
2426
lyon_mesh: VertexBuffers::new(),
27+
mask_index_count: None,
28+
is_stroke: false,
2529
}
2630
}
2731

@@ -33,9 +37,9 @@ impl ShapeTessellator {
3337
self.mesh = Vec::new();
3438
self.lyon_mesh = VertexBuffers::new();
3539
for path in shape.paths {
36-
let (fill_style, lyon_path) = match &path {
40+
let (fill_style, lyon_path, next_is_stroke) = match &path {
3741
DrawPath::Fill { style, commands } => {
38-
(*style, ruffle_path_to_lyon_path(commands, true))
42+
(*style, ruffle_path_to_lyon_path(commands, true), false)
3943
}
4044
DrawPath::Stroke {
4145
style,
@@ -44,6 +48,7 @@ impl ShapeTessellator {
4448
} => (
4549
style.fill_style(),
4650
ruffle_path_to_lyon_path(&commands, *is_closed),
51+
true,
4752
),
4853
};
4954

@@ -107,10 +112,19 @@ impl ShapeTessellator {
107112
}
108113
};
109114

110-
if needs_flush {
111-
// Non-solid color fills are isolated draw calls, so flush any pending color fill.
115+
if needs_flush || (self.is_stroke && !next_is_stroke) {
116+
// We flush separate draw calls in these cases:
117+
// * Non-solid color fills which require their own shader.
118+
// * Strokes followed by fills, because strokes need to be omitted
119+
// when using this shape as a mask.
112120
self.flush_draw(DrawType::Color);
121+
} else if !self.is_stroke && next_is_stroke {
122+
// Bake solid color fills followed by strokes into a single draw call, and adjust
123+
// the index count to omit the strokes when rendering this shape as a mask.
124+
debug_assert!(self.mask_index_count.is_none());
125+
self.mask_index_count = Some(self.lyon_mesh.indices.len() as u32);
113126
}
127+
self.is_stroke = next_is_stroke;
114128

115129
let mut buffers_builder =
116130
BuffersBuilder::new(&mut self.lyon_mesh, RuffleVertexCtor { color });
@@ -187,9 +201,13 @@ impl ShapeTessellator {
187201
let draw_mesh = std::mem::replace(&mut self.lyon_mesh, VertexBuffers::new());
188202
self.mesh.push(Draw {
189203
draw_type: draw,
204+
mask_index_count: self
205+
.mask_index_count
206+
.unwrap_or(draw_mesh.indices.len() as u32),
190207
vertices: draw_mesh.vertices,
191208
indices: draw_mesh.indices,
192209
});
210+
self.mask_index_count = None;
193211
}
194212
}
195213

@@ -205,6 +223,7 @@ pub struct Draw {
205223
pub draw_type: DrawType,
206224
pub vertices: Vec<Vertex>,
207225
pub indices: Vec<u32>,
226+
pub mask_index_count: u32,
208227
}
209228

210229
pub enum DrawType {

render/webgl/src/lib.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ impl WebGlRenderBackend {
348348
vertex_buffer,
349349
index_buffer,
350350
num_indices: 6,
351+
num_mask_indices: 6,
351352
}],
352353
};
353354
Ok(quad_mesh)
@@ -501,6 +502,7 @@ impl WebGlRenderBackend {
501502
let mut draws = Vec::with_capacity(lyon_mesh.len());
502503
for draw in lyon_mesh {
503504
let num_indices = draw.indices.len() as i32;
505+
let num_mask_indices = draw.mask_index_count as i32;
504506

505507
let vao = self.create_vertex_array().unwrap();
506508
let vertex_buffer = self.gl.create_buffer().unwrap();
@@ -565,13 +567,15 @@ impl WebGlRenderBackend {
565567
vertex_buffer,
566568
index_buffer,
567569
num_indices,
570+
num_mask_indices,
568571
},
569572
TessDrawType::Gradient(gradient) => Draw {
570573
draw_type: DrawType::Gradient(Box::new(Gradient::from(gradient))),
571574
vao,
572575
vertex_buffer,
573576
index_buffer,
574577
num_indices,
578+
num_mask_indices,
575579
},
576580
TessDrawType::Bitmap(bitmap) => Draw {
577581
draw_type: DrawType::Bitmap(BitmapDraw {
@@ -584,6 +588,7 @@ impl WebGlRenderBackend {
584588
vertex_buffer,
585589
index_buffer,
586590
num_indices,
591+
num_mask_indices,
587592
},
588593
});
589594

@@ -947,6 +952,18 @@ impl RenderBackend for WebGlRenderBackend {
947952

948953
let mesh = &self.meshes[shape.0];
949954
for draw in &mesh.draws {
955+
// Ignore strokes when drawing a mask stencil.
956+
let num_indices = if self.mask_state != MaskState::DrawMaskStencil
957+
&& self.mask_state != MaskState::ClearMaskStencil
958+
{
959+
draw.num_indices
960+
} else {
961+
draw.num_mask_indices
962+
};
963+
if num_indices == 0 {
964+
continue;
965+
}
966+
950967
self.bind_vertex_array(Some(&draw.vao));
951968

952969
let (program, src_blend, dst_blend) = match &draw.draw_type {
@@ -1068,7 +1085,7 @@ impl RenderBackend for WebGlRenderBackend {
10681085

10691086
// Draw the triangles.
10701087
self.gl
1071-
.draw_elements_with_i32(Gl::TRIANGLES, draw.num_indices, Gl::UNSIGNED_INT, 0);
1088+
.draw_elements_with_i32(Gl::TRIANGLES, num_indices, Gl::UNSIGNED_INT, 0);
10721089
}
10731090
}
10741091

@@ -1336,6 +1353,7 @@ struct Draw {
13361353
index_buffer: WebGlBuffer,
13371354
vao: WebGlVertexArrayObject,
13381355
num_indices: i32,
1356+
num_mask_indices: i32,
13391357
}
13401358

13411359
enum DrawType {

render/wgpu/src/lib.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ struct Draw {
283283
draw_type: DrawType,
284284
vertex_buffer: wgpu::Buffer,
285285
index_buffer: wgpu::Buffer,
286-
index_count: u32,
286+
num_indices: u32,
287+
num_mask_indices: u32,
287288
}
288289

289290
#[allow(dead_code)]
@@ -590,7 +591,8 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
590591
draw_type: DrawType::Color,
591592
vertex_buffer,
592593
index_buffer,
593-
index_count,
594+
num_indices: index_count,
595+
num_mask_indices: draw.mask_index_count,
594596
},
595597
TessDrawType::Gradient(gradient) => {
596598
// TODO: Extract to function?
@@ -672,7 +674,8 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
672674
},
673675
vertex_buffer,
674676
index_buffer,
675-
index_count,
677+
num_indices: index_count,
678+
num_mask_indices: draw.mask_index_count,
676679
}
677680
}
678681
TessDrawType::Bitmap(bitmap) => {
@@ -742,7 +745,8 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
742745
},
743746
vertex_buffer,
744747
index_buffer,
745-
index_count,
748+
num_indices: index_count,
749+
num_mask_indices: draw.mask_index_count,
746750
}
747751
}
748752
});
@@ -1086,6 +1090,18 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
10861090
);
10871091

10881092
for draw in &mesh.draws {
1093+
let num_indices = if self.mask_state != MaskState::DrawMaskStencil
1094+
&& self.mask_state != MaskState::ClearMaskStencil
1095+
{
1096+
draw.num_indices
1097+
} else {
1098+
// Omit strokes when drawing a mask stencil.
1099+
draw.num_mask_indices
1100+
};
1101+
if num_indices == 0 {
1102+
continue;
1103+
}
1104+
10891105
match &draw.draw_type {
10901106
DrawType::Color => {
10911107
frame.render_pass.set_pipeline(
@@ -1146,7 +1162,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
11461162
}
11471163
};
11481164

1149-
frame.render_pass.draw_indexed(0..draw.index_count, 0, 0..1);
1165+
frame.render_pass.draw_indexed(0..num_indices, 0, 0..1);
11501166
}
11511167
}
11521168

0 commit comments

Comments
 (0)