Skip to content

Commit

Permalink
wgpu: Deduplicate common gradients from a single Mesh
Browse files Browse the repository at this point in the history
  • Loading branch information
Dinnerbone committed Jan 27, 2024
1 parent e479d12 commit fcb74d8
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 141 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions render/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ num-traits = "0.2"
num-derive = "0.4"
byteorder = "1.5"
wgpu = { workspace = true, optional = true }
indexmap = "2.1.0"

# This crate has a `compile_error!` on apple platforms
[target.'cfg(not(target_vendor = "apple"))'.dependencies.renderdoc]
Expand Down
2 changes: 1 addition & 1 deletion render/src/shape_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub enum FillRule {
NonZero,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Enum)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Enum, Hash)]
pub enum GradientType {
Linear,
Radial,
Expand Down
83 changes: 52 additions & 31 deletions render/src/tessellator.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::bitmap::BitmapSource;
use crate::shape_utils::{DistilledShape, DrawCommand, DrawPath, GradientType};
use indexmap::IndexSet;
use lyon::path::Path;
use lyon::tessellation::{
self,
Expand All @@ -14,6 +15,7 @@ pub struct ShapeTessellator {
fill_tess: FillTessellator,
stroke_tess: StrokeTessellator,
mesh: Vec<Draw>,
gradients: IndexSet<Gradient>,
lyon_mesh: VertexBuffers<Vertex, u32>,
mask_index_count: Option<u32>,
is_stroke: bool,
Expand All @@ -25,6 +27,7 @@ impl ShapeTessellator {
fill_tess: FillTessellator::new(),
stroke_tess: StrokeTessellator::new(),
mesh: Vec::new(),
gradients: IndexSet::new(),
lyon_mesh: VertexBuffers::new(),
mask_index_count: None,
is_stroke: false,
Expand All @@ -38,7 +41,9 @@ impl ShapeTessellator {
bitmap_source: &dyn BitmapSource,
) -> Mesh {
self.mesh = Vec::new();
self.gradients = IndexSet::new();
self.lyon_mesh = VertexBuffers::new();

for path in shape.paths {
let (fill_style, lyon_path, next_is_stroke) = match &path {
DrawPath::Fill {
Expand All @@ -59,36 +64,49 @@ impl ShapeTessellator {

let (draw, color, needs_flush) = match fill_style {
swf::FillStyle::Color(color) => (DrawType::Color, *color, false),
swf::FillStyle::LinearGradient(gradient) => (
DrawType::Gradient(swf_gradient_to_uniforms(
GradientType::Linear,
gradient,
swf::Fixed8::ZERO,
)),
swf::Color::WHITE,
true,
),
swf::FillStyle::RadialGradient(gradient) => (
DrawType::Gradient(swf_gradient_to_uniforms(
GradientType::Radial,
gradient,
swf::Fixed8::ZERO,
)),
swf::Color::WHITE,
true,
),
swf::FillStyle::LinearGradient(gradient) => {
let uniform =
swf_gradient_to_uniforms(GradientType::Linear, gradient, swf::Fixed8::ZERO);
let (gradient_index, _) = self.gradients.insert_full(uniform);

(
DrawType::Gradient {
matrix: swf_to_gl_matrix(gradient.matrix.into()),
gradient: gradient_index,
},
swf::Color::WHITE,
true,
)
}
swf::FillStyle::RadialGradient(gradient) => {
let uniform =
swf_gradient_to_uniforms(GradientType::Radial, gradient, swf::Fixed8::ZERO);
let (gradient_index, _) = self.gradients.insert_full(uniform);
(
DrawType::Gradient {
matrix: swf_to_gl_matrix(gradient.matrix.into()),
gradient: gradient_index,
},
swf::Color::WHITE,
true,
)
}
swf::FillStyle::FocalGradient {
gradient,
focal_point,
} => (
DrawType::Gradient(swf_gradient_to_uniforms(
GradientType::Focal,
gradient,
*focal_point,
)),
swf::Color::WHITE,
true,
),
} => {
let uniform =
swf_gradient_to_uniforms(GradientType::Focal, gradient, *focal_point);
let (gradient_index, _) = self.gradients.insert_full(uniform);
(
DrawType::Gradient {
matrix: swf_to_gl_matrix(gradient.matrix.into()),
gradient: gradient_index,
},
swf::Color::WHITE,
true,
)
}
swf::FillStyle::Bitmap {
id,
matrix,
Expand Down Expand Up @@ -197,6 +215,7 @@ impl ShapeTessellator {
self.lyon_mesh = VertexBuffers::new();
Mesh {
draws: std::mem::take(&mut self.mesh),
gradients: std::mem::take(&mut self.gradients).into_iter().collect(),
}
}

Expand Down Expand Up @@ -228,6 +247,7 @@ impl Default for ShapeTessellator {

pub struct Mesh {
pub draws: Vec<Draw>,
pub gradients: Vec<Gradient>,
}

pub struct Draw {
Expand All @@ -239,7 +259,10 @@ pub struct Draw {

pub enum DrawType {
Color,
Gradient(Gradient),
Gradient {
matrix: [[f32; 3]; 3],
gradient: usize,
},
Bitmap(Bitmap),
}

Expand All @@ -253,9 +276,8 @@ impl DrawType {
}
}

#[derive(Clone, Debug)]
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct Gradient {
pub matrix: [[f32; 3]; 3],
pub gradient_type: GradientType,
pub repeat_mode: swf::GradientSpread,
pub focal_point: swf::Fixed8,
Expand Down Expand Up @@ -390,7 +412,6 @@ fn swf_gradient_to_uniforms(
focal_point: swf::Fixed8,
) -> Gradient {
Gradient {
matrix: swf_to_gl_matrix(gradient.matrix.into()),
records: gradient.records.clone(),
gradient_type,
repeat_mode: gradient.spread,
Expand Down
15 changes: 9 additions & 6 deletions render/webgl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ impl WebGlRenderBackend {

let program = match draw.draw_type {
TessDrawType::Color => &self.color_program,
TessDrawType::Gradient(_) => &self.gradient_program,
TessDrawType::Gradient { .. } => &self.gradient_program,
TessDrawType::Bitmap(_) => &self.bitmap_program,
};

Expand Down Expand Up @@ -652,8 +652,11 @@ impl WebGlRenderBackend {
num_indices,
num_mask_indices,
},
TessDrawType::Gradient(gradient) => Draw {
draw_type: DrawType::Gradient(Box::new(Gradient::from(gradient))),
TessDrawType::Gradient { matrix, gradient } => Draw {
draw_type: DrawType::Gradient(Box::new(Gradient::new(
lyon_mesh.gradients[gradient].clone(), // TODO: Gradient deduplication
matrix,
))),
vao,
vertex_buffer: Buffer {
gl: self.gl.clone(),
Expand Down Expand Up @@ -1529,8 +1532,8 @@ struct Gradient {
interpolation: swf::GradientInterpolation,
}

impl From<TessGradient> for Gradient {
fn from(gradient: TessGradient) -> Self {
impl Gradient {
fn new(gradient: TessGradient, matrix: [[f32; 3]; 3]) -> Self {
// TODO: Support more than MAX_GRADIENT_COLORS.
let num_colors = gradient.records.len().min(MAX_GRADIENT_COLORS);
let mut ratios = [0.0; MAX_GRADIENT_COLORS];
Expand Down Expand Up @@ -1559,7 +1562,7 @@ impl From<TessGradient> for Gradient {
}

Self {
matrix: gradient.matrix,
matrix,
gradient_type: match gradient.gradient_type {
GradientType::Linear => 0,
GradientType::Radial => 1,
Expand Down
14 changes: 12 additions & 2 deletions render/wgpu/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::buffer_pool::{BufferPool, TexturePool};
use crate::context3d::WgpuContext3D;
use crate::dynamic_transforms::DynamicTransforms;
use crate::filters::FilterSource;
use crate::mesh::{Mesh, PendingDraw};
use crate::mesh::{CommonGradient, Mesh, PendingDraw};
use crate::pixel_bender::{run_pixelbender_shader_impl, ShaderMode};
use crate::surface::{LayerRef, Surface};
use crate::target::{MaybeOwnedBuffer, TextureTarget};
Expand Down Expand Up @@ -249,6 +249,16 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
let mut uniform_buffer = BufferBuilder::new_for_uniform(&self.descriptors.limits);
let mut vertex_buffer = BufferBuilder::new_for_vertices(&self.descriptors.limits);
let mut index_buffer = BufferBuilder::new_for_vertices(&self.descriptors.limits);
let mut gradients = Vec::with_capacity(lyon_mesh.gradients.len());

for gradient in lyon_mesh.gradients {
gradients.push(CommonGradient::new(
&self.descriptors,
gradient,
&mut uniform_buffer,
));
}

for draw in lyon_mesh.draws {
let draw_id = draws.len();
if let Some(draw) = PendingDraw::new(
Expand Down Expand Up @@ -283,7 +293,7 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {

let draws = draws
.into_iter()
.map(|d| d.finish(&self.descriptors, &uniform_buffer))
.map(|d| d.finish(&self.descriptors, &uniform_buffer, &gradients))
.collect();

Mesh {
Expand Down
Loading

0 comments on commit fcb74d8

Please sign in to comment.