Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/gradient #425

Merged
merged 7 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,12 @@ tiny-skia-path = {version = "0.11.0"}
unicode-bidi = "0.3.7"
unicode-script = "0.5.4"
unicode-segmentation = "1.9.0"
usvg = {version = "0.33.0", default-features = false}
usvg = { version= "0.35.0", default-features = false }
webbrowser = "0.8.8"
wgpu = {version = "0.16.0"}
winit = {version = "0.28.5", default-features = false, features = ["x11", "wayland", "wayland-dlopen"]}
zerocopy = "0.7.3"
quick-xml = "0.30.0"

[workspace.metadata.release]
shared-version = true
Expand Down
2 changes: 1 addition & 1 deletion dev-helper/src/painter_backend_eq_image_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub fn assert_texture_eq_png(img: PixelImage, file_path: &std::path::Path) {
)
.unwrap();

const TOLERANCE: f64 = 0.0000025;
const TOLERANCE: f64 = 0.000008;
let (v, _) = dssim.compare(&expected, dissim_mig);
let v: f64 = v.into();

Expand Down
2 changes: 1 addition & 1 deletion gpu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ribir_geom = {path = "../geom", version = "0.0.1-alpha.4" }
ribir_painter = {path = "../painter", features = ["tessellation"], version = "0.0.1-alpha.4" }
slab = "0.4.8"
wgpu = {workspace = true, optional = true}
zerocopy.workspace = true
zerocopy = {workspace=true, features = ["derive"]}

[dev-dependencies]
paste.workspace = true
Expand Down
174 changes: 167 additions & 7 deletions gpu/src/gpu_backend.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use self::textures_mgr::{TextureID, TexturesMgr};
use crate::{ColorAttr, GPUBackendImpl, ImgPrimitive, MaskLayer};
use crate::{
ColorAttr, GPUBackendImpl, GradientStopPrimitive, ImagePrimIndex, ImgPrimitive,
LinearGradientPrimIndex, LinearGradientPrimitive, MaskLayer, RadialGradientPrimIndex,
RadialGradientPrimitive,
};
use ribir_geom::{rect_corners, DeviceRect, DeviceSize, Point};
use ribir_painter::{
image::ColorFormat, AntiAliasing, Color, PaintCommand, PaintPath, PainterBackend, PixelImage,
Expand All @@ -8,15 +12,22 @@ use ribir_painter::{
use std::{error::Error, future::Future, ops::Range, pin::Pin};

mod atlas;

mod textures_mgr;
use textures_mgr::*;

pub struct GPUBackend<Impl: GPUBackendImpl> {
gpu_impl: Impl,
tex_mgr: TexturesMgr<Impl::Texture>,
color_vertices_buffer: VertexBuffers<ColorAttr>,
img_vertices_buffer: VertexBuffers<u32>,
img_vertices_buffer: VertexBuffers<ImagePrimIndex>,
img_prims: Vec<ImgPrimitive>,
radial_gradient_vertices_buffer: VertexBuffers<RadialGradientPrimIndex>,
radial_gradient_stops: Vec<GradientStopPrimitive>,
radial_gradient_prims: Vec<RadialGradientPrimitive>,
linear_gradient_prims: Vec<LinearGradientPrimitive>,
linear_gradient_stops: Vec<GradientStopPrimitive>,
linear_gradient_vertices_buffer: VertexBuffers<LinearGradientPrimIndex>,
draw_indices: Vec<DrawIndices>,
tex_ids_map: TextureIdxMap,
viewport: DeviceRect,
Expand All @@ -29,7 +40,8 @@ pub struct GPUBackend<Impl: GPUBackendImpl> {
enum DrawIndices {
Color(Range<u32>),
Img(Range<u32>),
_Gradient(Range<u32>),
RadialGradient(Range<u32>),
LinearGradient(Range<u32>),
}

struct ClipLayer {
Expand Down Expand Up @@ -124,6 +136,28 @@ where
self.gpu_impl.load_img_primitives(&self.img_prims);
self.gpu_impl.load_img_vertices(&self.img_vertices_buffer);
}
if !self.radial_gradient_vertices_buffer.indices.is_empty() {
self
.gpu_impl
.load_radial_gradient_primitives(&self.radial_gradient_prims);
self
.gpu_impl
.load_radial_gradient_stops(&self.radial_gradient_stops);
self
.gpu_impl
.load_radial_gradient_vertices(&self.radial_gradient_vertices_buffer);
}
if !self.linear_gradient_vertices_buffer.indices.is_empty() {
self
.gpu_impl
.load_linear_gradient_primitives(&self.linear_gradient_prims);
self
.gpu_impl
.load_linear_gradient_stops(&self.linear_gradient_stops);
self
.gpu_impl
.load_linear_gradient_vertices(&self.linear_gradient_vertices_buffer);
}

self.tex_mgr.submit(&mut self.gpu_impl);
self.layers_submit(output, surface);
Expand All @@ -149,6 +183,12 @@ where
skip_clip_cnt: 0,
color_vertices_buffer: VertexBuffers::with_capacity(256, 512),
img_vertices_buffer: VertexBuffers::with_capacity(256, 512),
radial_gradient_vertices_buffer: VertexBuffers::with_capacity(256, 512),
radial_gradient_prims: vec![],
radial_gradient_stops: vec![],
linear_gradient_vertices_buffer: VertexBuffers::with_capacity(256, 512),
linear_gradient_stops: vec![],
linear_gradient_prims: vec![],
img_prims: vec![],
draw_indices: vec![],
viewport: DeviceRect::zero(),
Expand Down Expand Up @@ -193,7 +233,70 @@ where
};
self.img_prims.push(prim);
let buffer = &mut self.img_vertices_buffer;
add_draw_rect_vertices(rect, output_tex_size, prim_idx, buffer);
add_draw_rect_vertices(rect, output_tex_size, ImagePrimIndex(prim_idx), buffer);
}
}
PaintCommand::RadialGradient { path, radial_gradient } => {
let ts = path.transform;
if let Some((rect, mask_head)) = self.new_mask_layer(path) {
self.update_to_radial_gradient_indices();
let prim: RadialGradientPrimitive = RadialGradientPrimitive {
transform: ts.inverse().unwrap().to_array(),
stop_start: self.radial_gradient_stops.len() as u32,
stop_cnt: radial_gradient.stops.len() as u32,
start_center: radial_gradient.start_center.to_array(),
start_radius: radial_gradient.start_radius,
end_center: radial_gradient.end_center.to_array(),
end_radius: radial_gradient.end_radius,
mask_head,
spread: radial_gradient.spread_method as u32,
};
self.radial_gradient_stops.extend(
radial_gradient
.stops
.into_iter()
.map(Into::<GradientStopPrimitive>::into),
);
let prim_idx = self.radial_gradient_prims.len() as u32;
self.radial_gradient_prims.push(prim);
let buffer = &mut self.radial_gradient_vertices_buffer;

add_draw_rect_vertices(
rect,
output_tex_size,
RadialGradientPrimIndex(prim_idx),
buffer,
);
}
}
PaintCommand::LinearGradient { path, linear_gradient } => {
let ts = path.transform;
if let Some((rect, mask_head)) = self.new_mask_layer(path) {
self.update_to_linear_gradient_indices();
let prim: LinearGradientPrimitive = LinearGradientPrimitive {
transform: ts.inverse().unwrap().to_array(),
stop_start: self.linear_gradient_stops.len() as u32,
stop_cnt: linear_gradient.stops.len() as u32,
start_position: linear_gradient.start.to_array(),
end_position: linear_gradient.end.to_array(),
mask_head,
spread: linear_gradient.spread_method as u32,
};
self.linear_gradient_stops.extend(
linear_gradient
.stops
.into_iter()
.map(Into::<GradientStopPrimitive>::into),
);
let prim_idx = self.linear_gradient_prims.len() as u32;
self.linear_gradient_prims.push(prim);
let buffer = &mut self.linear_gradient_vertices_buffer;
add_draw_rect_vertices(
rect,
output_tex_size,
LinearGradientPrimIndex(prim_idx),
buffer,
);
}
}
PaintCommand::Clip(path) => {
Expand Down Expand Up @@ -235,6 +338,13 @@ where
self.img_vertices_buffer.indices.clear();
self.img_prims.clear();
self.mask_layers.clear();
self.radial_gradient_vertices_buffer.indices.clear();
self.radial_gradient_vertices_buffer.vertices.clear();
self.radial_gradient_prims.clear();
self.radial_gradient_stops.clear();
self.linear_gradient_prims.clear();
self.linear_gradient_vertices_buffer.indices.clear();
self.linear_gradient_stops.clear();
}

fn update_to_color_indices(&mut self) {
Expand All @@ -253,12 +363,43 @@ where
}
}

fn update_to_radial_gradient_indices(&mut self) {
if !matches!(
self.draw_indices.last(),
Some(DrawIndices::RadialGradient(_))
) {
self.expand_indices_range();
let start = self.radial_gradient_vertices_buffer.indices.len() as u32;
self
.draw_indices
.push(DrawIndices::RadialGradient(start..start));
}
}

fn update_to_linear_gradient_indices(&mut self) {
if !matches!(
self.draw_indices.last(),
Some(DrawIndices::LinearGradient(_))
) {
self.expand_indices_range();
let start = self.linear_gradient_vertices_buffer.indices.len() as u32;
self
.draw_indices
.push(DrawIndices::LinearGradient(start..start));
}
}

fn expand_indices_range(&mut self) -> Option<&DrawIndices> {
let cmd = self.draw_indices.last_mut()?;
match cmd {
DrawIndices::Color(rg) => rg.end = self.color_vertices_buffer.indices.len() as u32,
DrawIndices::Img(rg) => rg.end = self.img_vertices_buffer.indices.len() as u32,
DrawIndices::_Gradient(_) => todo!(),
DrawIndices::RadialGradient(rg) => {
rg.end = self.radial_gradient_vertices_buffer.indices.len() as u32
}
DrawIndices::LinearGradient(rg) => {
rg.end = self.linear_gradient_vertices_buffer.indices.len() as u32
}
};

Some(&*cmd)
Expand Down Expand Up @@ -322,7 +463,16 @@ where
.for_each(|indices| match indices {
DrawIndices::Color(rg) => self.gpu_impl.draw_color_triangles(output, rg, color.take()),
DrawIndices::Img(rg) => self.gpu_impl.draw_img_triangles(output, rg, color.take()),
DrawIndices::_Gradient(_) => todo!(),
DrawIndices::RadialGradient(rg) => {
self
.gpu_impl
.draw_radial_gradient_triangles(output, rg, color.take())
}
DrawIndices::LinearGradient(rg) => {
self
.gpu_impl
.draw_linear_gradient_triangles(output, rg, color.take())
}
});
}
}
Expand Down Expand Up @@ -381,7 +531,7 @@ mod tests {
use ribir_algo::ShareResource;
use ribir_dev_helper::*;
use ribir_geom::*;
use ribir_painter::{Brush, Color, Painter, Path, PixelImage};
use ribir_painter::{Brush, Color, Painter, Path, PixelImage, Svg};

fn painter(bounds: Size) -> Painter { Painter::new(Rect::from_size(bounds)) }

Expand Down Expand Up @@ -518,4 +668,14 @@ mod tests {

painter
}

painter_backend_eq_image_test!(draw_svg_gradient);
fn draw_svg_gradient() -> Painter {
let mut painter = painter(Size::new(64., 64.));
let svg =
Svg::parse_from_bytes(include_bytes!("../../tests/assets/fill_with_gradient.svg")).unwrap();

painter.draw_svg(&svg);
painter
}
}
34 changes: 25 additions & 9 deletions gpu/src/gpu_backend/textures_mgr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
};
}

fn get_transform_pref_scale(transform: &Transform) -> f32 {
let Transform { m11, m12, m21, m22, .. } = *transform;
(m11.abs() + m12.abs()).max(m21.abs() + m22.abs())
}

impl<T: Texture> TexturesMgr<T>
where
T::Host: GPUBackendImpl<Texture = T>,
Expand Down Expand Up @@ -109,7 +114,7 @@
.then(path_ts)
}

let prefer_scale: f32 = transform.m11.abs().max(transform.m22.abs());
let prefer_scale: f32 = get_transform_pref_scale(transform);
let key = PathKey::from_path(path);

if let Some(h) = self
Expand All @@ -118,13 +123,14 @@
.filter(|h| h.attr >= prefer_scale)
.copied()
{
let slice = alpha_tex_slice(&self.alpha_atlas, &h).cut_blank_edge();
let matrix = cache_to_view_matrix(key.path(), transform, slice.rect.origin, h.attr);
(slice, matrix)
let mask_slice = alpha_tex_slice(&self.alpha_atlas, &h).cut_blank_edge();
let matrix = cache_to_view_matrix(key.path(), transform, mask_slice.rect.origin, h.attr);
(mask_slice.expand_for_paste(), matrix)
} else {
let path = key.path().clone();
let scale_bounds = path.bounds().scale(prefer_scale, prefer_scale);
let prefer_cache_size = path_add_edges(scale_bounds.round_out().size.to_i32().cast_unit());

let h = self
.alpha_atlas
.allocate(key, prefer_scale, prefer_cache_size, gpu_impl);
Expand All @@ -141,7 +147,7 @@
.fill_task
.push(FillTask { slice, path, ts, clip_rect: None });

(mask_slice, matrix)
(mask_slice.expand_for_paste(), matrix)
}
}

Expand Down Expand Up @@ -174,7 +180,10 @@
};

let offset = (clip_view.origin - slice.rect.origin).to_f32();
(slice, Transform::translation(offset.x, offset.y))
(
slice.expand_for_paste(),
Transform::translation(offset.x, offset.y),
)
}

pub(super) fn store_image(
Expand Down Expand Up @@ -217,7 +226,7 @@
let tex_width = tex_size.width as f32;
let tex_height = tex_size.height as f32;

let scale = ts.m11.max(ts.m22);
let scale = get_transform_pref_scale(ts);

path.tessellate(TOLERANCE / scale, buffer, |pos| {
let pos = ts.transform_point(pos);
Expand Down Expand Up @@ -310,7 +319,7 @@
break;
}
let (tex_id, rg, None) = &draw_indices[idx] else {
unreachable!();

Check warning on line 322 in gpu/src/gpu_backend/textures_mgr.rs

View check run for this annotation

Codecov / codecov/patch

gpu/src/gpu_backend/textures_mgr.rs#L322

Added line #L322 was not covered by tests
};
let next = draw_indices[idx..]
.iter()
Expand Down Expand Up @@ -365,14 +374,14 @@

fn extend_buffer<V>(dist: &mut VertexBuffers<V>, from: VertexBuffers<V>) {
if dist.vertices.is_empty() {
dist.vertices.extend(from.vertices);
dist.indices.extend(from.indices);

Check warning on line 378 in gpu/src/gpu_backend/textures_mgr.rs

View check run for this annotation

Codecov / codecov/patch

gpu/src/gpu_backend/textures_mgr.rs#L377-L378

Added lines #L377 - L378 were not covered by tests
} else {
let offset = dist.vertices.len() as u32;
dist
.indices
.extend(from.indices.into_iter().map(|i| offset + i));
dist.vertices.extend(from.vertices);

Check warning on line 384 in gpu/src/gpu_backend/textures_mgr.rs

View check run for this annotation

Codecov / codecov/patch

gpu/src/gpu_backend/textures_mgr.rs#L384

Added line #L384 was not covered by tests
}
}

Expand All @@ -390,6 +399,13 @@
self.rect = self.rect.inner_rect(blank_side);
self
}

pub fn expand_for_paste(mut self) -> TextureSlice {
const EXPANDED_EDGE: i32 = 1;
let blank_side = SideOffsets2D::new_all_same(EXPANDED_EDGE);
self.rect = self.rect.outer_rect(blank_side);
self
}
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -520,7 +536,7 @@
impl Eq for PathKey {}

pub fn prefer_cache_size(path: &Path, transform: &Transform) -> DeviceSize {
let prefer_scale: f32 = transform.m11.max(transform.m22);
let prefer_scale: f32 = get_transform_pref_scale(transform);
let prefer_cache_size = path
.bounds()
.scale(prefer_scale, prefer_scale)
Expand Down Expand Up @@ -633,7 +649,7 @@
let (slice2, ts2) = mgr.store_clipped_path(clip_view, path, &mut wgpu);
assert_eq!(slice1, slice2);
assert_eq!(ts1, ts2);
assert_eq!(slice1.rect, ribir_geom::rect(2, 2, 100, 100));
assert_eq!(slice1.rect, ribir_geom::rect(1, 1, 102, 102));
assert_eq!(ts1, Transform::new(1., 0., 0., 1., 8., 8.));
}

Expand Down
Loading
Loading