diff --git a/Cargo.lock b/Cargo.lock index cc40ad25..b3e3b3c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -289,6 +289,7 @@ dependencies = [ "font-kit 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_canvas 0.1.0", "pathfinder_color 0.1.0", "pathfinder_content 0.1.0", @@ -1009,7 +1010,7 @@ dependencies = [ [[package]] name = "half" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1701,7 +1702,7 @@ name = "pathfinder_gl" version = "0.1.0" dependencies = [ "gl 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_geometry 0.4.0", "pathfinder_gpu 0.1.0", @@ -1714,7 +1715,7 @@ name = "pathfinder_gpu" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_color 0.1.0", "pathfinder_geometry 0.4.0", @@ -1764,7 +1765,7 @@ dependencies = [ "cocoa 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "metal 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_geometry 0.4.0", @@ -1779,6 +1780,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "instant 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2385,7 +2387,7 @@ name = "swf-parser" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "lzma-rs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2944,7 +2946,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum glutin_glx_sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "08c243de74d6cf5ea100c788826d2fb9319de315485dd4b310811a663b3809c3" "checksum glutin_wgl_sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a93dba7ee3a0feeac0f437141ff25e71ce2066bcf1a706acab1559ffff94eb6a" "checksum goblin 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3081214398d39e4bd7f2c1975f0488ed04614ffdd976c6fc7a0708278552c0da" -"checksum half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ff54597ea139063f4225f1ec47011b03c9de4a486957ff3fc506881dac951d0" +"checksum half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f36b5f248235f45773d4944f555f83ea61fe07b18b561ccf99d7483d7381e54d" "checksum harfbuzz 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46f7426266a5ece3e49eae6f48e602c0f8c39917354a847eac9c06437dcde8da" "checksum harfbuzz-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d74cab8498b2d15700b694fb38f77562869d05e1f8b602dd05221a1ca2d63" "checksum harfbuzz_rs 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cab35982090055087fad29795c465b33e8cf201bda50bfa008311ffe88630f16" diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index 26c8e1bc..b10ac35b 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -308,7 +308,6 @@ impl CanvasRenderingContext2D { let transform = self.current_state.transform; let clip_path = self.current_state.clip_path; let blend_mode = self.current_state.global_composite_operation.to_blend_mode(); - let opacity = (self.current_state.global_alpha * 255.0) as u8; outline.transform(&transform); @@ -334,7 +333,6 @@ impl CanvasRenderingContext2D { } path.set_fill_rule(fill_rule); path.set_blend_mode(blend_mode); - path.set_opacity(opacity); self.canvas.scene.push_path(path); self.composite_shadow_blur_render_targets_if_needed(shadow_blur_info, clip_path); @@ -344,7 +342,6 @@ impl CanvasRenderingContext2D { path.set_clip_path(clip_path); path.set_fill_rule(fill_rule); path.set_blend_mode(blend_mode); - path.set_opacity(opacity); self.canvas.scene.push_path(path); } @@ -587,7 +584,7 @@ impl State { } fn resolve_paint<'a>(&self, paint: &'a Paint) -> Cow<'a, Paint> { - let mut must_copy = !self.transform.is_identity(); + let mut must_copy = !self.transform.is_identity() || self.global_alpha < 1.0; if !must_copy { if let Paint::Pattern(ref pattern) = *paint { must_copy = self.image_smoothing_enabled != pattern.smoothing_enabled() @@ -600,6 +597,7 @@ impl State { let mut paint = (*paint).clone(); paint.apply_transform(&self.transform); + paint.apply_opacity(self.global_alpha); if let Paint::Pattern(ref mut pattern) = paint { pattern.set_smoothing_enabled(self.image_smoothing_enabled); } diff --git a/canvas/src/text.rs b/canvas/src/text.rs index f2f9588b..21710387 100644 --- a/canvas/src/text.rs +++ b/canvas/src/text.rs @@ -45,7 +45,6 @@ impl CanvasRenderingContext2D { let clip_path = self.current_state.clip_path; let blend_mode = self.current_state.global_composite_operation.to_blend_mode(); - let opacity = (self.current_state.global_alpha * 255.0) as u8; drop(self.canvas.scene.push_layout(&layout, &TextStyle { size: self.current_state.font_size }, @@ -54,7 +53,6 @@ impl CanvasRenderingContext2D { HintingOptions::None, clip_path, blend_mode, - opacity, paint_id)); } @@ -67,7 +65,6 @@ impl CanvasRenderingContext2D { let clip_path = self.current_state.clip_path; let blend_mode = self.current_state.global_composite_operation.to_blend_mode(); - let opacity = (self.current_state.global_alpha * 255.0) as u8; match self.current_state.text_align { TextAlign::Left => {}, @@ -96,7 +93,6 @@ impl CanvasRenderingContext2D { HintingOptions::None, clip_path, blend_mode, - opacity, paint_id)); } diff --git a/content/src/gradient.rs b/content/src/gradient.rs index 3b0635f7..c6460213 100644 --- a/content/src/gradient.rs +++ b/content/src/gradient.rs @@ -120,6 +120,11 @@ impl Gradient { &self.stops.array } + #[inline] + pub fn stops_mut(&mut self) -> &mut [ColorStop] { + &mut self.stops.array + } + pub fn sample(&self, mut t: f32) -> ColorU { if self.stops.is_empty() { return ColorU::transparent_black(); diff --git a/content/src/pattern.rs b/content/src/pattern.rs index cdd34205..4a1a190c 100644 --- a/content/src/pattern.rs +++ b/content/src/pattern.rs @@ -31,6 +31,7 @@ pub struct Pattern { transform: Transform2F, filter: Option, flags: PatternFlags, + opacity: u8, } #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -69,6 +70,7 @@ impl Pattern { transform: Transform2F::default(), filter: None, flags: PatternFlags::empty(), + opacity: !0, } } @@ -140,6 +142,16 @@ impl Pattern { self.flags.set(PatternFlags::NO_SMOOTHING, !enable); } + #[inline] + pub fn opacity(&self) -> u8 { + self.opacity + } + + #[inline] + pub fn set_opacity(&mut self, opacity: u8) { + self.opacity = opacity + } + #[inline] pub fn is_opaque(&self) -> bool { self.source.is_opaque() diff --git a/examples/canvas_nanovg/Cargo.toml b/examples/canvas_nanovg/Cargo.toml index e934d632..74fe8fd5 100644 --- a/examples/canvas_nanovg/Cargo.toml +++ b/examples/canvas_nanovg/Cargo.toml @@ -43,3 +43,6 @@ path = "../../resources" [dependencies.pathfinder_simd] path = "../../simd" + +[target.'cfg(not(windows))'.dependencies] +jemallocator = "0.3" diff --git a/examples/canvas_nanovg/src/main.rs b/examples/canvas_nanovg/src/main.rs index 49a43871..10cd4bf1 100644 --- a/examples/canvas_nanovg/src/main.rs +++ b/examples/canvas_nanovg/src/main.rs @@ -42,13 +42,20 @@ use std::f32::consts::PI; use std::sync::Arc; use std::time::Instant; +#[cfg(not(windows))] +use jemallocator; + +#[cfg(not(windows))] +#[global_allocator] +static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; + // TODO(pcwalton): See if we can reduce the amount of code by using the canvas shadow feature. const PI_2: f32 = PI * 2.0; const FRAC_PI_2_3: f32 = PI * 2.0 / 3.0; const WINDOW_WIDTH: i32 = 1024; -const WINDOW_HEIGHT: i32 = 768; +const WINDOW_HEIGHT: i32 = WINDOW_WIDTH * 3 / 4; static FONT_NAME_REGULAR: &'static str = "Roboto-Regular"; static FONT_NAME_BOLD: &'static str = "Roboto-Bold"; diff --git a/geometry/src/transform2d.rs b/geometry/src/transform2d.rs index c6e6acd9..acd462e4 100644 --- a/geometry/src/transform2d.rs +++ b/geometry/src/transform2d.rs @@ -228,6 +228,14 @@ impl Transform2F { pub fn m22(&self) -> f32 { self.matrix.m22() } + #[inline] + pub fn m31(&self) -> f32 { + self.vector.x() + } + #[inline] + pub fn m32(&self) -> f32 { + self.vector.y() + } #[inline] pub fn translate(&self, vector: Vector2F) -> Transform2F { diff --git a/gl/Cargo.toml b/gl/Cargo.toml index b9c787d2..7e1cc146 100644 --- a/gl/Cargo.toml +++ b/gl/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["rlib", "staticlib"] [dependencies] gl = "0.14" -half = "1.4" +half = "1.5" [dependencies.log] version = "0.4" diff --git a/gl/src/lib.rs b/gl/src/lib.rs index c20b0b79..4c6883ed 100644 --- a/gl/src/lib.rs +++ b/gl/src/lib.rs @@ -132,6 +132,9 @@ impl GLDevice { UniformData::Float(value) => { gl::Uniform1f(uniform.location, value); ck(); } + UniformData::IVec2(value) => { + gl::Uniform2i(uniform.location, value[0], value[1]); ck(); + } UniformData::IVec3(value) => { gl::Uniform3i(uniform.location, value[0], value[1], value[2]); ck(); } diff --git a/gpu/Cargo.toml b/gpu/Cargo.toml index 0c983347..2c01ec83 100644 --- a/gpu/Cargo.toml +++ b/gpu/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] bitflags = "1.0" -half = "1.4" +half = "1.5" [dependencies.image] version = "0.23" diff --git a/gpu/src/lib.rs b/gpu/src/lib.rs index fa2885a6..5961c6cf 100644 --- a/gpu/src/lib.rs +++ b/gpu/src/lib.rs @@ -20,7 +20,7 @@ use pathfinder_geometry::rect::RectI; use pathfinder_geometry::transform3d::Transform4F; use pathfinder_geometry::vector::{Vector2I, vec2i}; use pathfinder_resources::ResourceLoader; -use pathfinder_simd::default::{F32x2, F32x4}; +use pathfinder_simd::default::{F32x2, F32x4, I32x2}; use std::os::raw::c_void; use std::time::Duration; @@ -166,6 +166,7 @@ pub enum ShaderKind { #[derive(Clone, Copy)] pub enum UniformData { Float(f32), + IVec2(I32x2), IVec3([i32; 3]), Int(i32), Mat2(F32x4), diff --git a/metal/Cargo.toml b/metal/Cargo.toml index fb6fe7ac..4b040cad 100644 --- a/metal/Cargo.toml +++ b/metal/Cargo.toml @@ -11,7 +11,7 @@ block = "0.1" cocoa = "0.19" core-foundation = "0.7" foreign-types = "0.3" -half = "1.4" +half = "1.5" metal = "0.17" objc = "0.2" diff --git a/metal/src/lib.rs b/metal/src/lib.rs index afc9986e..2075ada8 100644 --- a/metal/src/lib.rs +++ b/metal/src/lib.rs @@ -48,7 +48,7 @@ use pathfinder_gpu::{Device, Primitive, RenderState, RenderTarget, ShaderKind, S use pathfinder_gpu::{TextureData, TextureDataRef, TextureFormat, TextureSamplingFlags}; use pathfinder_gpu::{UniformData, VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; use pathfinder_resources::ResourceLoader; -use pathfinder_simd::default::{F32x2, F32x4}; +use pathfinder_simd::default::{F32x2, F32x4, I32x2}; use std::cell::{Cell, RefCell}; use std::mem; use std::ptr; @@ -621,19 +621,23 @@ impl Device for MetalDevice { } fn begin_timer_query(&self, query: &MetalTimerQuery) { + /* self.command_buffers .borrow_mut() .last() .unwrap() .encode_signal_event(&self.shared_event, query.0.event_value); + */ } fn end_timer_query(&self, query: &MetalTimerQuery) { + /* self.command_buffers .borrow_mut() .last() .unwrap() .encode_signal_event(&self.shared_event, query.0.event_value + 1); + */ } fn try_recv_timer_query(&self, query: &MetalTimerQuery) -> Option { @@ -908,6 +912,10 @@ impl MetalDevice { UniformData::Float(value) => { uniform_buffer_data.write_f32::(value).unwrap() } + UniformData::IVec2(vector) => { + uniform_buffer_data.write_i32::(vector.x()).unwrap(); + uniform_buffer_data.write_i32::(vector.y()).unwrap(); + } UniformData::IVec3(values) => { uniform_buffer_data.write_i32::(values[0]).unwrap(); uniform_buffer_data.write_i32::(values[1]).unwrap(); @@ -1297,6 +1305,9 @@ impl UniformDataExt for UniformData { UniformData::Float(ref data) => { Some(slice::from_raw_parts(data as *const f32 as *const u8, 4 * 1)) } + UniformData::IVec2(ref data) => { + Some(slice::from_raw_parts(data as *const I32x2 as *const u8, 4 * 3)) + } UniformData::IVec3(ref data) => { Some(slice::from_raw_parts(data as *const i32 as *const u8, 4 * 3)) } @@ -1337,6 +1348,8 @@ impl TextureFormatExt for TextureFormat { // FIXME(pcwalton): This is wrong! But it prevents a crash for now. Some(TextureFormat::RGBA8) } + MTLPixelFormat::RGBA16Float => Some(TextureFormat::RGBA16F), + MTLPixelFormat::RGBA32Float => Some(TextureFormat::RGBA32F), _ => None, } } diff --git a/renderer/Cargo.toml b/renderer/Cargo.toml index 53315e1f..da22dcab 100644 --- a/renderer/Cargo.toml +++ b/renderer/Cargo.toml @@ -7,6 +7,7 @@ authors = ["Patrick Walton "] [dependencies] bitflags = "1.0" byteorder = "1.2" +half = "1.5" hashbrown = "0.7" rayon = "1.0" serde = "1.0" diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index e655f651..2884987b 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -13,7 +13,7 @@ use crate::concurrent::executor::Executor; use crate::gpu::renderer::{BlendModeExt, MASK_TILES_ACROSS, MASK_TILES_DOWN}; use crate::gpu_data::{FillBatchPrimitive, RenderCommand, TexturePageId, Tile, TileBatch}; -use crate::gpu_data::{TileBatchTexture, TileObjectPrimitive, TileVertex}; +use crate::gpu_data::{TileBatchTexture, TileObjectPrimitive}; use crate::options::{PreparedBuildOptions, PreparedRenderTransform, RenderCommandListener}; use crate::paint::{PaintInfo, PaintMetadata}; use crate::scene::{DisplayItem, Scene}; @@ -125,8 +125,8 @@ impl<'a> SceneBuilder<'a> { render_commands, paint_metadata, opacity_tile_page, - opacity_tile_transform, - render_target_metadata: _ + opacity_tile_transform: _, + render_target_metadata: _, } = self.scene.build_paint_info(render_transform); for render_command in render_commands { self.listener.send(render_command); @@ -153,7 +153,6 @@ impl<'a> SceneBuilder<'a> { }, paint_metadata: &paint_metadata, opacity_tile_page, - opacity_tile_transform, built_clip_paths: &built_clip_paths, }) }); @@ -186,7 +185,6 @@ impl<'a> SceneBuilder<'a> { path_build_params: PathBuildParams { path_index, view_box, built_options, scene }, paint_metadata, opacity_tile_page, - opacity_tile_transform, built_clip_paths, } = params; @@ -204,10 +202,9 @@ impl<'a> SceneBuilder<'a> { path_object.fill_rule(), view_box, TilingPathInfo::Draw(DrawTilingPathInfo { + paint_id, paint_metadata, - opacity_tile_transform, blend_mode: path_object.blend_mode(), - opacity: path_object.opacity(), built_clip_path, })); @@ -444,7 +441,7 @@ impl<'a> SceneBuilder<'a> { }; for alpha_tile in alpha_tiles { - let alpha_tile_coords = alpha_tile.upper_left.tile_position(); + let alpha_tile_coords = alpha_tile.tile_position(); if layer_z_buffer.test(alpha_tile_coords, current_depth) { culled_alpha_tiles.push(*alpha_tile); } @@ -452,6 +449,7 @@ impl<'a> SceneBuilder<'a> { } fn pack_tiles(&mut self, culled_tiles: CulledTiles) { + self.listener.send(RenderCommand::BeginTileDrawing); for display_item in culled_tiles.display_list { match display_item { CulledDisplayItem::DrawTiles(batch) => { @@ -509,7 +507,6 @@ struct DrawPathBuildParams<'a> { path_build_params: PathBuildParams<'a>, paint_metadata: &'a [PaintMetadata], opacity_tile_page: TexturePageId, - opacity_tile_transform: Transform2F, built_clip_paths: &'a [BuiltPath], } @@ -522,8 +519,7 @@ impl BuiltPath { let occludes = match *tiling_path_info { TilingPathInfo::Draw(ref draw_tiling_path_info) => { draw_tiling_path_info.paint_metadata.is_opaque && - draw_tiling_path_info.blend_mode.occludes_backdrop() && - draw_tiling_path_info.opacity == !0 + draw_tiling_path_info.blend_mode.occludes_backdrop() } TilingPathInfo::Clip => true, }; @@ -769,74 +765,42 @@ impl<'a> PackedTile<'a> { tiles: &mut Vec, draw_tiling_path_info: &DrawTilingPathInfo) { let fill_tile_index = self.draw_tile.alpha_tile_index as u16; - let fill_tile_backdrop = self.draw_tile.backdrop as i16; + let fill_tile_backdrop = self.draw_tile.backdrop as i8; let (clip_tile_index, clip_tile_backdrop) = match self.clip_tile { None => (0, 0), - Some(clip_tile) => (clip_tile.alpha_tile_index as u16, clip_tile.backdrop as i16), + Some(clip_tile) => (clip_tile.alpha_tile_index as u16, clip_tile.backdrop as i8), }; - tiles.push(Tile { - upper_left: TileVertex::new_alpha(self.tile_coords, - fill_tile_index, - fill_tile_backdrop, - clip_tile_index, - clip_tile_backdrop, - Vector2I::zero(), - draw_tiling_path_info), - upper_right: TileVertex::new_alpha(self.tile_coords, - fill_tile_index, - fill_tile_backdrop, - clip_tile_index, - clip_tile_backdrop, - vec2i(1, 0), - draw_tiling_path_info), - lower_left: TileVertex::new_alpha(self.tile_coords, - fill_tile_index, - fill_tile_backdrop, - clip_tile_index, - clip_tile_backdrop, - vec2i(0, 1), - draw_tiling_path_info), - lower_right: TileVertex::new_alpha(self.tile_coords, - fill_tile_index, - fill_tile_backdrop, - clip_tile_index, - clip_tile_backdrop, - vec2i(1, 1), - draw_tiling_path_info), - }); + tiles.push(Tile::new_alpha(self.tile_coords, + fill_tile_index, + fill_tile_backdrop, + clip_tile_index, + clip_tile_backdrop, + draw_tiling_path_info)); } } -impl TileVertex { +impl Tile { #[inline] fn new_alpha(tile_origin: Vector2I, draw_tile_index: u16, - draw_tile_backdrop: i16, + draw_tile_backdrop: i8, clip_tile_index: u16, - clip_tile_backdrop: i16, - tile_offset: Vector2I, + clip_tile_backdrop: i8, draw_tiling_path_info: &DrawTilingPathInfo) - -> TileVertex { - // TODO(pcwalton): Opacity. - let tile_position = tile_origin + tile_offset; - let color_0_uv = draw_tiling_path_info.paint_metadata.calculate_tex_coords(tile_position); - let color_1_uv = calculate_opacity_uv(draw_tiling_path_info); - let mask_0_uv = calculate_mask_uv(draw_tile_index, tile_offset); - let mask_1_uv = calculate_mask_uv(clip_tile_index, tile_offset); - TileVertex { - tile_x: tile_position.x() as i16, - tile_y: tile_position.y() as i16, - color_0_u: color_0_uv.x(), - color_0_v: color_0_uv.y(), - color_1_u: color_1_uv.x(), - color_1_v: color_1_uv.y(), - mask_0_u: mask_0_uv.x(), - mask_0_v: mask_0_uv.y(), - mask_1_u: mask_1_uv.x(), - mask_1_v: mask_1_uv.y(), + -> Tile { + let mask_0_uv = calculate_mask_uv(draw_tile_index); + let mask_1_uv = calculate_mask_uv(clip_tile_index); + Tile { + tile_x: tile_origin.x() as i16, + tile_y: tile_origin.y() as i16, + mask_0_u: mask_0_uv.x() as u8, + mask_0_v: mask_0_uv.y() as u8, + mask_1_u: mask_1_uv.x() as u8, + mask_1_v: mask_1_uv.y() as u8, mask_0_backdrop: draw_tile_backdrop, mask_1_backdrop: clip_tile_backdrop, + color: draw_tiling_path_info.paint_id.0, } } @@ -846,16 +810,9 @@ impl TileVertex { } } -fn calculate_mask_uv(tile_index: u16, tile_offset: Vector2I) -> Vector2F { +fn calculate_mask_uv(tile_index: u16) -> Vector2I { + debug_assert_eq!(MASK_TILES_ACROSS, MASK_TILES_DOWN); let mask_u = tile_index as i32 % MASK_TILES_ACROSS as i32; let mask_v = tile_index as i32 / MASK_TILES_ACROSS as i32; - let scale = vec2f(1.0 / MASK_TILES_ACROSS as f32, 1.0 / MASK_TILES_DOWN as f32); - (vec2i(mask_u, mask_v) + tile_offset).to_f32() * scale -} - -fn calculate_opacity_uv(draw_tiling_path_info: &DrawTilingPathInfo) -> Vector2F { - let DrawTilingPathInfo { opacity_tile_transform, opacity, .. } = *draw_tiling_path_info; - let texel_coord = (vec2i((opacity % 16) as i32, (opacity / 16) as i32).to_f32() + - vec2f(0.5, 0.5)) * (1.0 / 16.0); - opacity_tile_transform * texel_coord + vec2i(mask_u, mask_v) } diff --git a/renderer/src/gpu/debug.rs b/renderer/src/gpu/debug.rs index 1c0b7f4d..e6b42467 100644 --- a/renderer/src/gpu/debug.rs +++ b/renderer/src/gpu/debug.rs @@ -144,26 +144,13 @@ where let mean_gpu_sample = self.gpu_samples.mean(); self.ui_presenter.draw_text( device, - &format!( - "Stage 0 GPU: {:.3} ms", - duration_to_ms(mean_gpu_sample.time.stage_0) - ), + &format!("GPU: {:.3} ms", duration_to_ms(mean_gpu_sample.time.time)), origin + vec2i(0, LINE_HEIGHT * 1), false, ); - self.ui_presenter.draw_text( - device, - &format!( - "Stage 1 GPU: {:.3} ms", - duration_to_ms(mean_gpu_sample.time.stage_1) - ), - origin + vec2i(0, LINE_HEIGHT * 2), - false, - ); - let wallclock_time = f64::max(duration_to_ms(mean_gpu_sample.time.stage_0), - duration_to_ms(mean_cpu_sample.elapsed)) + - duration_to_ms(mean_gpu_sample.time.stage_1); + let wallclock_time = f64::max(duration_to_ms(mean_gpu_sample.time.time), + duration_to_ms(mean_cpu_sample.elapsed)); self.ui_presenter.draw_text( device, &format!("Wallclock: {:.3} ms", wallclock_time), @@ -255,12 +242,7 @@ impl Add for GPUSample { impl Div for GPUSample { type Output = GPUSample; fn div(self, divisor: usize) -> GPUSample { - GPUSample { - time: RenderTime { - stage_0: self.time.stage_0 / (divisor as u32), - stage_1: self.time.stage_1 / (divisor as u32), - } - } + GPUSample { time: RenderTime { time: self.time.time / divisor as u32 } } } } diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index faf82c63..017afea2 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -14,10 +14,11 @@ use crate::gpu::shaders::{BlitProgram, BlitVertexArray, CopyTileProgram, CopyTil use crate::gpu::shaders::{FillProgram, FillVertexArray, MAX_FILLS_PER_BATCH, ReprojectionProgram}; use crate::gpu::shaders::{ReprojectionVertexArray, StencilProgram, StencilVertexArray}; use crate::gpu::shaders::{TileProgram, TileVertexArray}; -use crate::gpu_data::{FillBatchPrimitive, RenderCommand, TextureLocation, TexturePageDescriptor}; -use crate::gpu_data::{TexturePageId, Tile, TileBatchTexture}; +use crate::gpu_data::{FillBatchPrimitive, RenderCommand, TextureLocation, TextureMetadataEntry}; +use crate::gpu_data::{TexturePageDescriptor, TexturePageId, Tile, TileBatchTexture}; use crate::options::BoundingQuad; use crate::tiles::{TILE_HEIGHT, TILE_WIDTH}; +use half::f16; use pathfinder_color::{self as color, ColorF, ColorU}; use pathfinder_content::effects::{BlendMode, BlurDirection, DefringingKernel}; use pathfinder_content::effects::{Filter, PatternFilter}; @@ -26,13 +27,14 @@ use pathfinder_content::render_target::RenderTargetId; use pathfinder_geometry::line_segment::LineSegment2F; use pathfinder_geometry::rect::RectI; use pathfinder_geometry::transform3d::Transform4F; +use pathfinder_geometry::util; use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F, vec2f, vec2i}; use pathfinder_gpu::{BlendFactor, BlendState, BufferData, BufferTarget, BufferUploadMode}; use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions}; use pathfinder_gpu::{RenderState, RenderTarget, StencilFunc, StencilState, TextureDataRef}; use pathfinder_gpu::{TextureFormat, UniformData}; use pathfinder_resources::ResourceLoader; -use pathfinder_simd::default::{F32x2, F32x4}; +use pathfinder_simd::default::{F32x2, F32x4, I32x2}; use std::cmp; use std::collections::VecDeque; use std::f32; @@ -51,6 +53,11 @@ pub(crate) const MASK_TILES_DOWN: u32 = 256; const SQRT_2_PI_INV: f32 = 0.3989422804014327; const TEXTURE_CACHE_SIZE: usize = 8; +const TIMER_QUERY_CACHE_SIZE: usize = 8; + +const TEXTURE_METADATA_ENTRIES_PER_ROW: i32 = 256; +const TEXTURE_METADATA_TEXTURE_WIDTH: i32 = TEXTURE_METADATA_ENTRIES_PER_ROW * 2; +const TEXTURE_METADATA_TEXTURE_HEIGHT: i32 = 65536 / TEXTURE_METADATA_ENTRIES_PER_ROW; // FIXME(pcwalton): Shrink this again! const MASK_FRAMEBUFFER_WIDTH: i32 = TILE_WIDTH as i32 * MASK_TILES_ACROSS as i32; @@ -106,7 +113,6 @@ where blit_vertex_array: BlitVertexArray, tile_vertex_array: TileVertexArray, tile_copy_vertex_array: CopyTileVertexArray, - area_lut_texture: D::Texture, tile_vertex_buffer: D::Buffer, quad_vertex_positions_buffer: D::Buffer, quad_vertex_indices_buffer: D::Buffer, @@ -119,7 +125,8 @@ where texture_pages: Vec>, render_targets: Vec, render_target_stack: Vec, - + texture_metadata_texture: D::Texture, + area_lut_texture: D::Texture, gamma_lut_texture: D::Texture, // Stencil shader @@ -137,8 +144,8 @@ where // Debug pub stats: RenderStats, - current_timers: RenderTimers, - pending_timers: VecDeque>, + current_timer: Option, + pending_timers: VecDeque, free_timer_queries: Vec, pub debug_ui_presenter: DebugUIPresenter, @@ -165,6 +172,10 @@ where let area_lut_texture = device.create_texture_from_png(resources, "area-lut"); let gamma_lut_texture = device.create_texture_from_png(resources, "gamma-lut"); + let texture_metadata_texture = device.create_texture( + TextureFormat::RGBA16F, + Vector2I::new(TEXTURE_METADATA_TEXTURE_WIDTH, TEXTURE_METADATA_TEXTURE_HEIGHT)); + let quad_vertex_positions_buffer = device.create_buffer(); device.allocate_buffer( &quad_vertex_positions_buffer, @@ -198,7 +209,8 @@ where &device, &tile_program, &tile_vertex_buffer, - &quads_vertex_indices_buffer, + &quad_vertex_positions_buffer, + &quad_vertex_indices_buffer, ); let tile_copy_vertex_array = CopyTileVertexArray::new( &device, @@ -225,6 +237,11 @@ where let intermediate_dest_texture = device.create_texture(TextureFormat::RGBA8, window_size); let intermediate_dest_framebuffer = device.create_framebuffer(intermediate_dest_texture); + let mut timer_queries = vec![]; + for _ in 0..TIMER_QUERY_CACHE_SIZE { + timer_queries.push(device.create_timer_query()); + } + let debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size); Renderer { @@ -239,7 +256,6 @@ where blit_vertex_array, tile_vertex_array, tile_copy_vertex_array, - area_lut_texture, tile_vertex_buffer, quad_vertex_positions_buffer, quad_vertex_indices_buffer, @@ -253,7 +269,9 @@ where render_targets: vec![], render_target_stack: vec![], + area_lut_texture, gamma_lut_texture, + texture_metadata_texture, stencil_program, stencil_vertex_array, @@ -262,9 +280,9 @@ where reprojection_vertex_array, stats: RenderStats::default(), - current_timers: RenderTimers::new(), + current_timer: None, pending_timers: VecDeque::new(), - free_timer_queries: vec![], + free_timer_queries: timer_queries, debug_ui_presenter, framebuffer_flags: FramebufferFlags::empty(), @@ -295,11 +313,12 @@ where RenderCommand::DeclareRenderTarget { id, location } => { self.declare_render_target(id, location) } - RenderCommand::AddFills(ref fills) => self.add_fills(fills), - RenderCommand::FlushFills => { - self.draw_buffered_fills(); - self.begin_composite_timer_query(); + RenderCommand::UploadTextureMetadata(ref metadata) => { + self.upload_texture_metadata(metadata) } + RenderCommand::AddFills(ref fills) => self.add_fills(fills), + RenderCommand::FlushFills => self.draw_buffered_fills(), + RenderCommand::BeginTileDrawing => self.begin_tile_drawing(), RenderCommand::PushRenderTarget(render_target_id) => { self.push_render_target(render_target_id) } @@ -320,13 +339,22 @@ where } } + fn begin_tile_drawing(&mut self) { + if let Some(timer_query) = self.allocate_timer_query() { + self.device.begin_timer_query(&timer_query); + self.current_timer = Some(timer_query); + } + } + pub fn end_scene(&mut self) { self.blit_intermediate_dest_framebuffer_if_necessary(); - self.end_composite_timer_query(); - self.pending_timers.push_back(mem::replace(&mut self.current_timers, RenderTimers::new())); - self.device.end_commands(); + + if let Some(timer_query) = self.current_timer.take() { + self.device.end_timer_query(&timer_query); + self.pending_timers.push_back(timer_query); + } } fn start_rendering(&mut self, @@ -351,32 +379,14 @@ where } pub fn shift_rendering_time(&mut self) -> Option { - let timers = self.pending_timers.front()?; - - // Accumulate stage-0 time. - let mut total_stage_0_time = Duration::new(0, 0); - for timer_query in &timers.stage_0 { - match self.device.try_recv_timer_query(timer_query) { - None => return None, - Some(stage_0_time) => total_stage_0_time += stage_0_time, + if let Some(query) = self.pending_timers.pop_front() { + if let Some(time) = self.device.try_recv_timer_query(&query) { + self.free_timer_queries.push(query); + return Some(RenderTime { time }); } + self.pending_timers.push_front(query); } - - // Get stage-1 time. - let stage_1_time = { - let stage_1_timer_query = timers.stage_1.as_ref().unwrap(); - match self.device.try_recv_timer_query(stage_1_timer_query) { - None => return None, - Some(query) => query, - } - }; - - // Recycle all timer queries. - let timers = self.pending_timers.pop_front().unwrap(); - self.free_timer_queries.extend(timers.stage_0.into_iter()); - self.free_timer_queries.push(timers.stage_1.unwrap()); - - Some(RenderTime { stage_0: total_stage_0_time, stage_1: stage_1_time }) + None } #[inline] @@ -464,6 +474,34 @@ where render_target.location = location; } + fn upload_texture_metadata(&mut self, metadata: &[TextureMetadataEntry]) { + let padded_texel_size = + (util::alignup_i32(metadata.len() as i32, TEXTURE_METADATA_ENTRIES_PER_ROW) * + TEXTURE_METADATA_TEXTURE_WIDTH * 4) as usize; + let mut texels = Vec::with_capacity(padded_texel_size); + for entry in metadata { + texels.extend_from_slice(&[ + f16::from_f32(entry.color_0_transform.m11()), + f16::from_f32(entry.color_0_transform.m21()), + f16::from_f32(entry.color_0_transform.m12()), + f16::from_f32(entry.color_0_transform.m22()), + f16::from_f32(entry.color_0_transform.m31()), + f16::from_f32(entry.color_0_transform.m32()), + f16::from_f32(entry.opacity), + f16::default(), + ]); + } + while texels.len() < padded_texel_size { + texels.push(f16::default()) + } + + let texture = &mut self.texture_metadata_texture; + let width = TEXTURE_METADATA_TEXTURE_WIDTH; + let height = texels.len() as i32 / (4 * TEXTURE_METADATA_TEXTURE_WIDTH); + let rect = RectI::new(Vector2I::zero(), Vector2I::new(width, height)); + self.device.upload_to_texture(texture, rect, TextureDataRef::F16(&texels)); + } + fn upload_tiles(&mut self, tiles: &[Tile]) { self.device.allocate_buffer(&self.tile_vertex_buffer, BufferData::Memory(&tiles), @@ -532,9 +570,6 @@ where clear_color = Some(ColorF::default()); }; - let timer_query = self.allocate_timer_query(); - self.device.begin_timer_query(&timer_query); - debug_assert!(self.buffered_fills.len() <= u32::MAX as usize); self.device.draw_elements_instanced(6, self.buffered_fills.len() as u32, &RenderState { target: &RenderTarget::Framebuffer(&self.fill_framebuffer), @@ -564,9 +599,6 @@ where }, }); - self.device.end_timer_query(&timer_query); - self.current_timers.stage_0.push(timer_query); - self.framebuffer_flags.insert(FramebufferFlags::MUST_PRESERVE_FILL_FRAMEBUFFER_CONTENTS); self.buffered_fills.clear(); } @@ -607,7 +639,7 @@ where } } - let mut textures = vec![]; + let mut textures = vec![&self.texture_metadata_texture]; let mut uniforms = vec![ (&self.tile_program.transform_uniform, UniformData::Mat4(self.tile_transform().to_columns())), @@ -615,6 +647,10 @@ where UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))), (&self.tile_program.framebuffer_size_uniform, UniformData::Vec2(draw_viewport.size().to_f32().0)), + (&self.tile_program.texture_metadata_uniform, UniformData::TextureUnit(0)), + (&self.tile_program.texture_metadata_size_uniform, + UniformData::IVec2(I32x2::new(TEXTURE_METADATA_TEXTURE_WIDTH, + TEXTURE_METADATA_TEXTURE_HEIGHT))), ]; if needs_readable_framebuffer { @@ -687,7 +723,7 @@ where uniforms.push((&self.tile_program.ctrl_uniform, UniformData::Int(ctrl))); - self.device.draw_elements(tile_count * 6, &RenderState { + self.device.draw_elements_instanced(6, tile_count, &RenderState { target: &self.draw_render_target(), program: &self.tile_program.program, vertex_array: &self.tile_vertex_array.vertex_array, @@ -1036,23 +1072,8 @@ where self.device.framebuffer_texture(&self.texture_page_framebuffer(id)) } - fn allocate_timer_query(&mut self) -> D::TimerQuery { - match self.free_timer_queries.pop() { - Some(query) => query, - None => self.device.create_timer_query(), - } - } - - fn begin_composite_timer_query(&mut self) { - let timer_query = self.allocate_timer_query(); - self.device.begin_timer_query(&timer_query); - self.current_timers.stage_1 = Some(timer_query); - } - - fn end_composite_timer_query(&mut self) { - if let Some(ref query) = self.current_timers.stage_1 { - self.device.end_timer_query(query); - } + fn allocate_timer_query(&mut self) -> Option { + self.free_timer_queries.pop() } } @@ -1090,27 +1111,15 @@ impl Div for RenderStats { } } -struct RenderTimers where D: Device { - stage_0: Vec, - stage_1: Option, -} - -impl RenderTimers where D: Device { - fn new() -> RenderTimers { - RenderTimers { stage_0: vec![], stage_1: None } - } -} - #[derive(Clone, Copy, Debug)] pub struct RenderTime { - pub stage_0: Duration, - pub stage_1: Duration, + pub time: Duration, } impl Default for RenderTime { #[inline] fn default() -> RenderTime { - RenderTime { stage_0: Duration::new(0, 0), stage_1: Duration::new(0, 0) } + RenderTime { time: Duration::new(0, 0) } } } @@ -1119,10 +1128,7 @@ impl Add for RenderTime { #[inline] fn add(self, other: RenderTime) -> RenderTime { - RenderTime { - stage_0: self.stage_0 + other.stage_0, - stage_1: self.stage_1 + other.stage_1, - } + RenderTime { time: self.time + other.time } } } diff --git a/renderer/src/gpu/shaders.rs b/renderer/src/gpu/shaders.rs index d073c416..ad41bd51 100644 --- a/renderer/src/gpu/shaders.rs +++ b/renderer/src/gpu/shaders.rs @@ -15,7 +15,7 @@ use pathfinder_resources::ResourceLoader; // TODO(pcwalton): Replace with `mem::size_of` calls? const FILL_INSTANCE_SIZE: usize = 8; -const TILE_VERTEX_SIZE: usize = 40; +const TILE_INSTANCE_SIZE: usize = 12; pub const MAX_FILLS_PER_BATCH: usize = 0x4000; @@ -155,83 +155,80 @@ impl TileVertexArray where D: Device { pub fn new(device: &D, tile_program: &TileProgram, tile_vertex_buffer: &D::Buffer, - quads_vertex_indices_buffer: &D::Buffer) + quad_vertex_positions_buffer: &D::Buffer, + quad_vertex_indices_buffer: &D::Buffer) -> TileVertexArray { let vertex_array = device.create_vertex_array(); - let tile_position_attr = - device.get_vertex_attr(&tile_program.program, "TilePosition").unwrap(); - let color_0_tex_coord_attr = - device.get_vertex_attr(&tile_program.program, "ColorTexCoord0").unwrap(); - let color_1_tex_coord_attr = - device.get_vertex_attr(&tile_program.program, "ColorTexCoord1").unwrap(); + let tile_offset_attr = + device.get_vertex_attr(&tile_program.program, "TileOffset").unwrap(); + let tile_origin_attr = + device.get_vertex_attr(&tile_program.program, "TileOrigin").unwrap(); let mask_0_tex_coord_attr = device.get_vertex_attr(&tile_program.program, "MaskTexCoord0").unwrap(); let mask_1_tex_coord_attr = device.get_vertex_attr(&tile_program.program, "MaskTexCoord1").unwrap(); let mask_backdrop_attr = device.get_vertex_attr(&tile_program.program, "MaskBackdrop").unwrap(); + let color_attr = device.get_vertex_attr(&tile_program.program, "Color").unwrap(); - device.bind_buffer(&vertex_array, tile_vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tile_offset_attr, &VertexAttrDescriptor { size: 2, class: VertexAttrClass::Int, attr_type: VertexAttrType::I16, - stride: TILE_VERTEX_SIZE, + stride: 4, offset: 0, divisor: 0, buffer_index: 0, }); - device.configure_vertex_attr(&vertex_array, - &color_0_tex_coord_attr, - &VertexAttrDescriptor { + device.bind_buffer(&vertex_array, tile_vertex_buffer, BufferTarget::Vertex); + device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::F32, - stride: TILE_VERTEX_SIZE, - offset: 4, - divisor: 0, - buffer_index: 0, - }); - device.configure_vertex_attr(&vertex_array, - &color_1_tex_coord_attr, - &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::F32, - stride: TILE_VERTEX_SIZE, - offset: 12, - divisor: 0, - buffer_index: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: TILE_INSTANCE_SIZE, + offset: 0, + divisor: 1, + buffer_index: 1, }); device.configure_vertex_attr(&vertex_array, &mask_0_tex_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::F32, - stride: TILE_VERTEX_SIZE, - offset: 20, - divisor: 0, - buffer_index: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U8, + stride: TILE_INSTANCE_SIZE, + offset: 4, + divisor: 1, + buffer_index: 1, }); device.configure_vertex_attr(&vertex_array, &mask_1_tex_coord_attr, &VertexAttrDescriptor { size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::F32, - stride: TILE_VERTEX_SIZE, - offset: 28, - divisor: 0, - buffer_index: 0, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::U8, + stride: TILE_INSTANCE_SIZE, + offset: 6, + divisor: 1, + buffer_index: 1, }); device.configure_vertex_attr(&vertex_array, &mask_backdrop_attr, &VertexAttrDescriptor { size: 2, class: VertexAttrClass::Int, - attr_type: VertexAttrType::I16, - stride: TILE_VERTEX_SIZE, - offset: 36, - divisor: 0, - buffer_index: 0, + attr_type: VertexAttrType::I8, + stride: TILE_INSTANCE_SIZE, + offset: 8, + divisor: 1, + buffer_index: 1, }); - device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index); + device.configure_vertex_attr(&vertex_array, &color_attr, &VertexAttrDescriptor { + size: 1, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + stride: TILE_INSTANCE_SIZE, + offset: 10, + divisor: 1, + buffer_index: 1, + }); + device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); TileVertexArray { vertex_array } } @@ -258,7 +255,7 @@ impl CopyTileVertexArray where D: Device { size: 2, class: VertexAttrClass::Int, attr_type: VertexAttrType::I16, - stride: TILE_VERTEX_SIZE, + stride: TILE_INSTANCE_SIZE, offset: 0, divisor: 0, buffer_index: 0, @@ -314,6 +311,8 @@ pub struct TileProgram where D: Device { pub program: D::Program, pub transform_uniform: D::Uniform, pub tile_size_uniform: D::Uniform, + pub texture_metadata_uniform: D::Uniform, + pub texture_metadata_size_uniform: D::Uniform, pub dest_texture_uniform: D::Uniform, pub color_texture_0_uniform: D::Uniform, pub color_texture_1_uniform: D::Uniform, @@ -333,6 +332,8 @@ impl TileProgram where D: Device { let program = device.create_program(resources, "tile"); let transform_uniform = device.get_uniform(&program, "Transform"); let tile_size_uniform = device.get_uniform(&program, "TileSize"); + let texture_metadata_uniform = device.get_uniform(&program, "TextureMetadata"); + let texture_metadata_size_uniform = device.get_uniform(&program, "TextureMetadataSize"); let dest_texture_uniform = device.get_uniform(&program, "DestTexture"); let color_texture_0_uniform = device.get_uniform(&program, "ColorTexture0"); let color_texture_1_uniform = device.get_uniform(&program, "ColorTexture1"); @@ -349,6 +350,8 @@ impl TileProgram where D: Device { program, transform_uniform, tile_size_uniform, + texture_metadata_uniform, + texture_metadata_size_uniform, dest_texture_uniform, color_texture_0_uniform, color_texture_1_uniform, diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index 6e195d9c..f00b8b9f 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -17,6 +17,7 @@ use pathfinder_content::fill::FillRule; use pathfinder_content::render_target::RenderTargetId; use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8}; use pathfinder_geometry::rect::RectI; +use pathfinder_geometry::transform2d::Transform2F; use pathfinder_geometry::vector::Vector2I; use pathfinder_gpu::TextureSamplingFlags; use std::fmt::{Debug, Formatter, Result as DebugResult}; @@ -50,6 +51,9 @@ pub enum RenderCommand { // TODO(pcwalton): Add a rect to this so we can render to subrects of a page. DeclareRenderTarget { id: RenderTargetId, location: TextureLocation }, + // Upload texture metadata. + UploadTextureMetadata(Vec), + // Adds fills to the queue. AddFills(Vec), @@ -63,6 +67,9 @@ pub enum RenderCommand { // Pops a render target from the stack. PopRenderTarget, + // Marks that tile compositing is about to begin. + BeginTileDrawing, + // Draws a batch of tiles to the render target on top of the stack. DrawTiles(TileBatch), @@ -117,6 +124,13 @@ pub struct TileObjectPrimitive { pub backdrop: i8, } +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct TextureMetadataEntry { + pub color_0_transform: Transform2F, + pub opacity: f32, +} + // FIXME(pcwalton): Move `subpx` before `px` and remove `repr(packed)`. #[derive(Clone, Copy, Debug, Default)] #[repr(packed)] @@ -129,27 +143,15 @@ pub struct FillBatchPrimitive { #[derive(Clone, Copy, Debug, Default)] #[repr(C)] pub struct Tile { - pub upper_left: TileVertex, - pub upper_right: TileVertex, - pub lower_left: TileVertex, - pub lower_right: TileVertex, -} - -#[derive(Clone, Copy, Debug, Default)] -#[repr(C)] -pub struct TileVertex { pub tile_x: i16, pub tile_y: i16, - pub color_0_u: f32, - pub color_0_v: f32, - pub color_1_u: f32, - pub color_1_v: f32, - pub mask_0_u: f32, - pub mask_0_v: f32, - pub mask_1_u: f32, - pub mask_1_v: f32, - pub mask_0_backdrop: i16, - pub mask_1_backdrop: i16, + pub mask_0_u: u8, + pub mask_0_v: u8, + pub mask_1_u: u8, + pub mask_1_v: u8, + pub mask_0_backdrop: i8, + pub mask_1_backdrop: i8, + pub color: u16, } impl Debug for RenderCommand { @@ -165,12 +167,16 @@ impl Debug for RenderCommand { RenderCommand::DeclareRenderTarget { id, location } => { write!(formatter, "DeclareRenderTarget({:?}, {:?})", id, location) } + RenderCommand::UploadTextureMetadata(ref metadata) => { + write!(formatter, "UploadTextureMetadata(x{})", metadata.len()) + } RenderCommand::AddFills(ref fills) => write!(formatter, "AddFills(x{})", fills.len()), RenderCommand::FlushFills => write!(formatter, "FlushFills"), RenderCommand::PushRenderTarget(render_target_id) => { write!(formatter, "PushRenderTarget({:?})", render_target_id) } RenderCommand::PopRenderTarget => write!(formatter, "PopRenderTarget"), + RenderCommand::BeginTileDrawing => write!(formatter, "BeginTileDrawing"), RenderCommand::DrawTiles(ref batch) => { write!(formatter, "DrawTiles(x{}, C0 {:?}, C1 {:?}, M0 {:?}, {:?})", diff --git a/renderer/src/paint.rs b/renderer/src/paint.rs index de146621..9bfbc965 100644 --- a/renderer/src/paint.rs +++ b/renderer/src/paint.rs @@ -9,9 +9,9 @@ // except according to those terms. use crate::allocator::{AllocationMode, TextureAllocator}; -use crate::gpu_data::{RenderCommand, TextureLocation, TexturePageDescriptor, TexturePageId}; +use crate::gpu_data::{RenderCommand, TextureLocation, TextureMetadataEntry}; +use crate::gpu_data::{TexturePageDescriptor, TexturePageId}; use crate::scene::RenderTarget; -use crate::tiles::{TILE_HEIGHT, TILE_WIDTH}; use hashbrown::HashMap; use pathfinder_color::ColorU; use pathfinder_content::effects::{Filter, PatternFilter}; @@ -136,6 +136,27 @@ impl Paint { Paint::Pattern(ref mut pattern) => pattern.apply_transform(*transform), } } + + fn opacity(&self) -> u8 { + match *self { + Paint::Color(_) | Paint::Gradient(_) => !0, + Paint::Pattern(ref pattern) => pattern.opacity(), + } + } + + pub fn apply_opacity(&mut self, new_opacity: f32) { + match *self { + Paint::Color(ref mut color) => color.a = (color.a as f32 * new_opacity) as u8, + Paint::Gradient(ref mut gradient) => { + for stop in gradient.stops_mut() { + stop.color.a = (stop.color.a as f32 * new_opacity) as u8 + } + } + Paint::Pattern(ref mut pattern) => { + pattern.set_opacity((pattern.opacity() as f32 * new_opacity) as u8) + } + } + } } pub struct PaintInfo { @@ -167,6 +188,8 @@ pub struct PaintMetadata { pub is_opaque: bool, /// The filter to be applied to this paint. pub filter: PaintFilter, + /// The paint opacity (global alpha, in canvas terminology). + pub opacity: u8, } #[derive(Clone, Copy, Debug)] @@ -292,6 +315,7 @@ impl Palette { sampling_flags, is_opaque: paint.is_opaque(), filter, + opacity: paint.opacity(), }); } @@ -300,8 +324,9 @@ impl Palette { let texture_scale = allocator.page_scale(metadata.location.page); metadata.texture_transform = match paint { Paint::Color(_) => { + let matrix = Matrix2x2F(F32x4::default()); let vector = rect_to_inset_uv(metadata.location.rect, texture_scale).origin(); - Transform2F { matrix: Matrix2x2F(F32x4::default()), vector } * render_transform.inverse() + Transform2F { matrix, vector } * render_transform.inverse() } Paint::Gradient(Gradient { line: gradient_line, radii: None, .. }) => { let v0 = metadata.location.rect.to_f32().center().y() * texture_scale.y(); @@ -333,7 +358,7 @@ impl Palette { PatternSource::RenderTarget { .. } => { // FIXME(pcwalton): Only do this in GL, not Metal! let texture_origin_uv = rect_to_uv(metadata.location.rect, - texture_scale).lower_left(); + texture_scale).lower_left(); Transform2F::from_translation(texture_origin_uv) * Transform2F::from_scale(texture_scale * vec2f(1.0, -1.0)) * pattern.transform().inverse() * render_transform @@ -354,9 +379,18 @@ impl Palette { let opacity_tile_page = opacity_tile_builder.tile_location.page; let opacity_tile_transform = opacity_tile_builder.tile_transform(&allocator); + // Create texture metadata. + let texture_metadata = paint_metadata.iter().map(|paint_metadata| { + TextureMetadataEntry { + color_0_transform: paint_metadata.texture_transform, + opacity: paint_metadata.opacity as f32 / 255.0, + } + }).collect(); + // Create render commands. let mut render_commands = vec![ - RenderCommand::AllocateTexturePages(texture_page_descriptors) + RenderCommand::UploadTextureMetadata(texture_metadata), + RenderCommand::AllocateTexturePages(texture_page_descriptors), ]; for (index, metadata) in render_target_metadata.iter().enumerate() { let id = RenderTargetId(index as u32); @@ -386,14 +420,6 @@ impl Palette { } impl PaintMetadata { - // TODO(pcwalton): Apply clamp/repeat to tile rect. - pub(crate) fn calculate_tex_coords(&self, tile_position: Vector2I) -> Vector2F { - let tile_size = vec2i(TILE_WIDTH as i32, TILE_HEIGHT as i32); - let position = (tile_position * tile_size).to_f32(); - let tex_coords = self.texture_transform * position; - tex_coords - } - pub(crate) fn filter(&self) -> Filter { match self.filter { PaintFilter::None => Filter::None, diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index 0d50dcd0..028173df 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -143,7 +143,6 @@ impl Scene { }), fill_rule: draw_path.fill_rule, blend_mode: draw_path.blend_mode, - opacity: draw_path.opacity, name: draw_path.name, }); } @@ -313,7 +312,6 @@ pub struct DrawPath { clip_path: Option, fill_rule: FillRule, blend_mode: BlendMode, - opacity: u8, name: String, } @@ -355,7 +353,6 @@ impl DrawPath { clip_path: None, fill_rule: FillRule::Winding, blend_mode: BlendMode::SrcOver, - opacity: !0, name: String::new(), } } @@ -400,16 +397,6 @@ impl DrawPath { self.blend_mode = new_blend_mode } - #[inline] - pub(crate) fn opacity(&self) -> u8 { - self.opacity - } - - #[inline] - pub fn set_opacity(&mut self, new_opacity: u8) { - self.opacity = new_opacity - } - #[inline] pub fn set_name(&mut self, new_name: String) { self.name = new_name diff --git a/renderer/src/tiles.rs b/renderer/src/tiles.rs index 222734cd..61e9e884 100644 --- a/renderer/src/tiles.rs +++ b/renderer/src/tiles.rs @@ -10,7 +10,7 @@ use crate::builder::{BuiltPath, ObjectBuilder, Occluder, SceneBuilder, SolidTiles}; use crate::gpu_data::TileObjectPrimitive; -use crate::paint::PaintMetadata; +use crate::paint::{PaintId, PaintMetadata}; use pathfinder_content::effects::BlendMode; use pathfinder_content::fill::FillRule; use pathfinder_content::outline::{Contour, Outline, PointIndex}; @@ -18,7 +18,6 @@ use pathfinder_content::segment::Segment; use pathfinder_content::sorted_vector::SortedVector; use pathfinder_geometry::line_segment::LineSegment2F; use pathfinder_geometry::rect::{RectF, RectI}; -use pathfinder_geometry::transform2d::Transform2F; use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i}; use std::cmp::Ordering; use std::mem; @@ -48,10 +47,9 @@ pub(crate) enum TilingPathInfo<'a> { #[derive(Clone, Copy)] pub(crate) struct DrawTilingPathInfo<'a> { + pub(crate) paint_id: PaintId, pub(crate) paint_metadata: &'a PaintMetadata, - pub(crate) opacity_tile_transform: Transform2F, pub(crate) blend_mode: BlendMode, - pub(crate) opacity: u8, pub(crate) built_clip_path: Option<&'a BuiltPath>, } diff --git a/renderer/src/z_buffer.rs b/renderer/src/z_buffer.rs index 4a22cffd..4df9991a 100644 --- a/renderer/src/z_buffer.rs +++ b/renderer/src/z_buffer.rs @@ -11,13 +11,13 @@ //! Software occlusion culling. use crate::builder::Occluder; -use crate::gpu_data::{Tile, TileBatch, TileBatchTexture, TileVertex}; +use crate::gpu_data::{Tile, TileBatch, TileBatchTexture}; use crate::paint::{PaintId, PaintMetadata}; use crate::tile_map::DenseTileMap; use crate::tiles; use pathfinder_content::effects::{BlendMode, Filter}; use pathfinder_geometry::rect::RectF; -use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2i}; +use pathfinder_geometry::vector::Vector2I; use vec_map::VecMap; pub(crate) struct ZBuffer { @@ -71,7 +71,8 @@ impl ZBuffer { let tile_coords = self.buffer.index_to_coords(tile_index); let depth_metadata = self.depth_metadata[depth as usize]; - let paint_metadata = &paint_metadata[depth_metadata.paint_id.0 as usize]; + let paint_id = depth_metadata.paint_id; + let paint_metadata = &paint_metadata[paint_id.0 as usize]; let tile_position = tile_coords + self.buffer.rect.origin(); @@ -103,7 +104,7 @@ impl ZBuffer { } let batch = solid_tiles.batches.last_mut().unwrap(); - batch.tiles.push(Tile::new_solid_with_paint_metadata(tile_position, paint_metadata)); + batch.tiles.push(Tile::new_solid_from_paint_id(tile_position, paint_id)); } solid_tiles @@ -111,42 +112,17 @@ impl ZBuffer { } impl Tile { - pub(crate) fn new_solid_with_paint_metadata(tile_position: Vector2I, - paint_metadata: &PaintMetadata) - -> Tile { + pub(crate) fn new_solid_from_paint_id(tile_origin: Vector2I, paint_id: PaintId) -> Tile { Tile { - upper_left: TileVertex::new_solid_from_paint_metadata(tile_position, paint_metadata), - upper_right: TileVertex::new_solid_from_paint_metadata(tile_position + vec2i(1, 0), - paint_metadata), - lower_left: TileVertex::new_solid_from_paint_metadata(tile_position + vec2i(0, 1), - paint_metadata), - lower_right: TileVertex::new_solid_from_paint_metadata(tile_position + vec2i(1, 1), - paint_metadata), - } - } -} - -impl TileVertex { - fn new_solid_from_uv(tile_position: Vector2I, color_0_uv: Vector2F) -> TileVertex { - TileVertex { - tile_x: tile_position.x() as i16, - tile_y: tile_position.y() as i16, - color_0_u: color_0_uv.x(), - color_0_v: color_0_uv.y(), - color_1_u: 0.0, - color_1_v: 0.0, - mask_0_u: 0.0, - mask_0_v: 0.0, - mask_1_u: 0.0, - mask_1_v: 0.0, + tile_x: tile_origin.x() as i16, + tile_y: tile_origin.y() as i16, mask_0_backdrop: 0, mask_1_backdrop: 0, + mask_0_u: 0, + mask_0_v: 0, + mask_1_u: 0, + mask_1_v: 0, + color: paint_id.0, } } - - fn new_solid_from_paint_metadata(tile_position: Vector2I, paint_metadata: &PaintMetadata) - -> TileVertex { - let color_uv = paint_metadata.calculate_tex_coords(tile_position); - TileVertex::new_solid_from_uv(tile_position, color_uv) - } } diff --git a/resources/shaders/gl3/tile.fs.glsl b/resources/shaders/gl3/tile.fs.glsl index 534a27dd..93d36805 100644 --- a/resources/shaders/gl3/tile.fs.glsl +++ b/resources/shaders/gl3/tile.fs.glsl @@ -76,11 +76,9 @@ precision highp sampler2D; - uniform sampler2D uColorTexture0; -uniform sampler2D uColorTexture1; uniform sampler2D uMaskTexture0; uniform sampler2D uMaskTexture1; uniform sampler2D uDestTexture; @@ -95,7 +93,7 @@ uniform int uCtrl; in vec3 vMaskTexCoord0; in vec3 vMaskTexCoord1; in vec2 vColorTexCoord0; -in vec2 vColorTexCoord1; +in float vOpacity; out vec4 oFragColor; @@ -575,11 +573,9 @@ void calculateColor(int ctrl){ uFilterParams2, color0Filter); } - if(((ctrl >> 7)& 0x1)!= 0) - color *= sampleColor(uColorTexture1, vColorTexCoord1); - color . a *= maskAlpha; + color . a *= maskAlpha * vOpacity; int compositeOp =(ctrl >> 8)& 0xf; diff --git a/resources/shaders/gl3/tile.vs.glsl b/resources/shaders/gl3/tile.vs.glsl index 4f39bcaa..3ed8f3e5 100644 --- a/resources/shaders/gl3/tile.vs.glsl +++ b/resources/shaders/gl3/tile.vs.glsl @@ -17,25 +17,39 @@ precision highp sampler2D; uniform mat4 uTransform; uniform vec2 uTileSize; +uniform sampler2D uTextureMetadata; +uniform ivec2 uTextureMetadataSize; -in ivec2 aTilePosition; -in vec2 aColorTexCoord0; -in vec2 aColorTexCoord1; -in vec2 aMaskTexCoord0; -in vec2 aMaskTexCoord1; +in ivec2 aTileOffset; +in ivec2 aTileOrigin; +in uvec2 aMaskTexCoord0; +in uvec2 aMaskTexCoord1; in ivec2 aMaskBackdrop; +in int aColor; out vec3 vMaskTexCoord0; out vec3 vMaskTexCoord1; out vec2 vColorTexCoord0; -out vec2 vColorTexCoord1; +out float vOpacity; void main(){ - vec2 position = vec2(aTilePosition)* uTileSize; - vColorTexCoord0 = aColorTexCoord0; - vColorTexCoord1 = aColorTexCoord1; - vMaskTexCoord0 = vec3(aMaskTexCoord0, float(aMaskBackdrop . x)); - vMaskTexCoord1 = vec3(aMaskTexCoord1, float(aMaskBackdrop . y)); + vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset); + vec2 position =(tileOrigin + tileOffset)* uTileSize; + + vec2 maskTexCoord0 =(vec2(aMaskTexCoord0)+ tileOffset)/ 256.0; + vec2 maskTexCoord1 =(vec2(aMaskTexCoord1)+ tileOffset)/ 256.0; + + vec2 textureMetadataScale = vec2(1.0)/ vec2(uTextureMetadataSize); + vec2 metadataEntryCoord = ivec2(aColor % 256 * 2, aColor / 256); + vec2 colorTexMatrix0Coord =(metadataEntryCoord + vec2(0.5, 0.5))* textureMetadataScale; + vec2 colorTexOffsetsCoord =(metadataEntryCoord + vec2(1.5, 0.5))* textureMetadataScale; + vec4 colorTexMatrix0 = texture(uTextureMetadata, colorTexMatrix0Coord); + vec4 colorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord); + + vColorTexCoord0 = mat2(colorTexMatrix0)* position + colorTexOffsets . xy; + vOpacity = colorTexOffsets . z; + vMaskTexCoord0 = vec3(maskTexCoord0, float(aMaskBackdrop . x)); + vMaskTexCoord1 = vec3(maskTexCoord1, float(aMaskBackdrop . y)); gl_Position = uTransform * vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/metal/tile.fs.metal b/resources/shaders/metal/tile.fs.metal index 18c5ec5c..79e5ea71 100644 --- a/resources/shaders/metal/tile.fs.metal +++ b/resources/shaders/metal/tile.fs.metal @@ -21,11 +21,9 @@ struct spvDescriptorSetBuffer0 constant float4* uFilterParams0 [[id(10)]]; constant float4* uFilterParams1 [[id(11)]]; constant float4* uFilterParams2 [[id(12)]]; - texture2d uColorTexture1 [[id(13)]]; - sampler uColorTexture1Smplr [[id(14)]]; - texture2d uDestTexture [[id(15)]]; - sampler uDestTextureSmplr [[id(16)]]; - constant int* uCtrl [[id(17)]]; + texture2d uDestTexture [[id(13)]]; + sampler uDestTextureSmplr [[id(14)]]; + constant int* uCtrl [[id(15)]]; }; constant float3 _1003 = {}; @@ -40,7 +38,7 @@ struct main0_in float3 vMaskTexCoord0 [[user(locn0)]]; float3 vMaskTexCoord1 [[user(locn1)]]; float2 vColorTexCoord0 [[user(locn2)]]; - float2 vColorTexCoord1 [[user(locn3)]]; + float vOpacity [[user(locn3)]]; }; // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() @@ -534,7 +532,7 @@ float4 composite(thread const float4& srcColor, thread const texture2d de return float4(((srcColor.xyz * (srcColor.w * (1.0 - destColor.w))) + (blendedRGB * (srcColor.w * destColor.w))) + (destColor.xyz * (1.0 - srcColor.w)), 1.0); } -void calculateColor(thread const int& ctrl, thread texture2d uMaskTexture0, thread const sampler uMaskTexture0Smplr, thread float3& vMaskTexCoord0, thread texture2d uMaskTexture1, thread const sampler uMaskTexture1Smplr, thread float3& vMaskTexCoord1, thread float2& vColorTexCoord0, thread texture2d uColorTexture0, thread const sampler uColorTexture0Smplr, thread texture2d uGammaLUT, thread const sampler uGammaLUTSmplr, thread float2 uColorTexture0Size, thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread float4 uFilterParams0, thread float4 uFilterParams1, thread float4 uFilterParams2, thread texture2d uColorTexture1, thread const sampler uColorTexture1Smplr, thread float2& vColorTexCoord1, thread texture2d uDestTexture, thread const sampler uDestTextureSmplr, thread float4& oFragColor) +void calculateColor(thread const int& ctrl, thread texture2d uMaskTexture0, thread const sampler uMaskTexture0Smplr, thread float3& vMaskTexCoord0, thread texture2d uMaskTexture1, thread const sampler uMaskTexture1Smplr, thread float3& vMaskTexCoord1, thread float2& vColorTexCoord0, thread texture2d uColorTexture0, thread const sampler uColorTexture0Smplr, thread texture2d uGammaLUT, thread const sampler uGammaLUTSmplr, thread float2 uColorTexture0Size, thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread float4 uFilterParams0, thread float4 uFilterParams1, thread float4 uFilterParams2, thread float& vOpacity, thread texture2d uDestTexture, thread const sampler uDestTextureSmplr, thread float4& oFragColor) { int maskCtrl0 = (ctrl >> 0) & 3; int maskCtrl1 = (ctrl >> 2) & 3; @@ -561,20 +559,15 @@ void calculateColor(thread const int& ctrl, thread texture2d uMaskTexture int param_13 = color0Filter; color += filterColor(param_6, uColorTexture0, uColorTexture0Smplr, uGammaLUT, uGammaLUTSmplr, param_7, param_8, param_9, param_10, param_11, param_12, param_13); } - if (((ctrl >> 7) & 1) != 0) - { - float2 param_14 = vColorTexCoord1; - color *= sampleColor(uColorTexture1, uColorTexture1Smplr, param_14); - } - color.w *= maskAlpha; + color.w *= (maskAlpha * vOpacity); int compositeOp = (ctrl >> 8) & 15; - float4 param_15 = color; - float2 param_16 = uFramebufferSize; - float2 param_17 = gl_FragCoord.xy; - int param_18 = compositeOp; - color = composite(param_15, uDestTexture, uDestTextureSmplr, param_16, param_17, param_18); - float3 _1304 = color.xyz * color.w; - color = float4(_1304.x, _1304.y, _1304.z, color.w); + float4 param_14 = color; + float2 param_15 = uFramebufferSize; + float2 param_16 = gl_FragCoord.xy; + int param_17 = compositeOp; + color = composite(param_14, uDestTexture, uDestTextureSmplr, param_15, param_16, param_17); + float3 _1294 = color.xyz * color.w; + color = float4(_1294.x, _1294.y, _1294.z, color.w); oFragColor = color; } @@ -582,7 +575,7 @@ fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuff { main0_out out = {}; int param = (*spvDescriptorSet0.uCtrl); - calculateColor(param, spvDescriptorSet0.uMaskTexture0, spvDescriptorSet0.uMaskTexture0Smplr, in.vMaskTexCoord0, spvDescriptorSet0.uMaskTexture1, spvDescriptorSet0.uMaskTexture1Smplr, in.vMaskTexCoord1, in.vColorTexCoord0, spvDescriptorSet0.uColorTexture0, spvDescriptorSet0.uColorTexture0Smplr, spvDescriptorSet0.uGammaLUT, spvDescriptorSet0.uGammaLUTSmplr, (*spvDescriptorSet0.uColorTexture0Size), gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), (*spvDescriptorSet0.uFilterParams0), (*spvDescriptorSet0.uFilterParams1), (*spvDescriptorSet0.uFilterParams2), spvDescriptorSet0.uColorTexture1, spvDescriptorSet0.uColorTexture1Smplr, in.vColorTexCoord1, spvDescriptorSet0.uDestTexture, spvDescriptorSet0.uDestTextureSmplr, out.oFragColor); + calculateColor(param, spvDescriptorSet0.uMaskTexture0, spvDescriptorSet0.uMaskTexture0Smplr, in.vMaskTexCoord0, spvDescriptorSet0.uMaskTexture1, spvDescriptorSet0.uMaskTexture1Smplr, in.vMaskTexCoord1, in.vColorTexCoord0, spvDescriptorSet0.uColorTexture0, spvDescriptorSet0.uColorTexture0Smplr, spvDescriptorSet0.uGammaLUT, spvDescriptorSet0.uGammaLUTSmplr, (*spvDescriptorSet0.uColorTexture0Size), gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), (*spvDescriptorSet0.uFilterParams0), (*spvDescriptorSet0.uFilterParams1), (*spvDescriptorSet0.uFilterParams2), in.vOpacity, spvDescriptorSet0.uDestTexture, spvDescriptorSet0.uDestTextureSmplr, out.oFragColor); return out; } diff --git a/resources/shaders/metal/tile.vs.metal b/resources/shaders/metal/tile.vs.metal index d0b8400d..d1c868af 100644 --- a/resources/shaders/metal/tile.vs.metal +++ b/resources/shaders/metal/tile.vs.metal @@ -7,7 +7,10 @@ using namespace metal; struct spvDescriptorSetBuffer0 { constant float2* uTileSize [[id(0)]]; - constant float4x4* uTransform [[id(1)]]; + constant int2* uTextureMetadataSize [[id(1)]]; + texture2d uTextureMetadata [[id(2)]]; + sampler uTextureMetadataSmplr [[id(3)]]; + constant float4x4* uTransform [[id(4)]]; }; struct main0_out @@ -15,28 +18,38 @@ struct main0_out float3 vMaskTexCoord0 [[user(locn0)]]; float3 vMaskTexCoord1 [[user(locn1)]]; float2 vColorTexCoord0 [[user(locn2)]]; - float2 vColorTexCoord1 [[user(locn3)]]; + float vOpacity [[user(locn3)]]; float4 gl_Position [[position]]; }; struct main0_in { - int2 aTilePosition [[attribute(0)]]; - float2 aColorTexCoord0 [[attribute(1)]]; - float2 aColorTexCoord1 [[attribute(2)]]; - float2 aMaskTexCoord0 [[attribute(3)]]; - float2 aMaskTexCoord1 [[attribute(4)]]; - int2 aMaskBackdrop [[attribute(5)]]; + int2 aTileOffset [[attribute(0)]]; + int2 aTileOrigin [[attribute(1)]]; + uint2 aMaskTexCoord0 [[attribute(2)]]; + uint2 aMaskTexCoord1 [[attribute(3)]]; + int2 aMaskBackdrop [[attribute(4)]]; + int aColor [[attribute(5)]]; }; vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) { main0_out out = {}; - float2 position = float2(in.aTilePosition) * (*spvDescriptorSet0.uTileSize); - out.vColorTexCoord0 = in.aColorTexCoord0; - out.vColorTexCoord1 = in.aColorTexCoord1; - out.vMaskTexCoord0 = float3(in.aMaskTexCoord0, float(in.aMaskBackdrop.x)); - out.vMaskTexCoord1 = float3(in.aMaskTexCoord1, float(in.aMaskBackdrop.y)); + float2 tileOrigin = float2(in.aTileOrigin); + float2 tileOffset = float2(in.aTileOffset); + float2 position = (tileOrigin + tileOffset) * (*spvDescriptorSet0.uTileSize); + float2 maskTexCoord0 = (float2(in.aMaskTexCoord0) + tileOffset) / float2(256.0); + float2 maskTexCoord1 = (float2(in.aMaskTexCoord1) + tileOffset) / float2(256.0); + float2 textureMetadataScale = float2(1.0) / float2((*spvDescriptorSet0.uTextureMetadataSize)); + float2 metadataEntryCoord = float2(int2((in.aColor % 256) * 2, in.aColor / 256)); + float2 colorTexMatrix0Coord = (metadataEntryCoord + float2(0.5)) * textureMetadataScale; + float2 colorTexOffsetsCoord = (metadataEntryCoord + float2(1.5, 0.5)) * textureMetadataScale; + float4 colorTexMatrix0 = spvDescriptorSet0.uTextureMetadata.sample(spvDescriptorSet0.uTextureMetadataSmplr, colorTexMatrix0Coord, level(0.0)); + float4 colorTexOffsets = spvDescriptorSet0.uTextureMetadata.sample(spvDescriptorSet0.uTextureMetadataSmplr, colorTexOffsetsCoord, level(0.0)); + out.vColorTexCoord0 = (float2x2(float2(colorTexMatrix0.xy), float2(colorTexMatrix0.zw)) * position) + colorTexOffsets.xy; + out.vOpacity = colorTexOffsets.z; + out.vMaskTexCoord0 = float3(maskTexCoord0, float(in.aMaskBackdrop.x)); + out.vMaskTexCoord1 = float3(maskTexCoord1, float(in.aMaskBackdrop.y)); out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0); return out; } diff --git a/shaders/tile.fs.glsl b/shaders/tile.fs.glsl index f40a4838..c09e3d31 100644 --- a/shaders/tile.fs.glsl +++ b/shaders/tile.fs.glsl @@ -74,11 +74,9 @@ precision highp sampler2D; #define COMBINER_CTRL_MASK_1_SHIFT 2 #define COMBINER_CTRL_COLOR_0_FILTER_SHIFT 4 #define COMBINER_CTRL_COLOR_0_ENABLE_SHIFT 6 -#define COMBINER_CTRL_COLOR_1_ENABLE_SHIFT 7 #define COMBINER_CTRL_COMPOSITE_SHIFT 8 uniform sampler2D uColorTexture0; -uniform sampler2D uColorTexture1; uniform sampler2D uMaskTexture0; uniform sampler2D uMaskTexture1; uniform sampler2D uDestTexture; @@ -93,7 +91,7 @@ uniform int uCtrl; in vec3 vMaskTexCoord0; in vec3 vMaskTexCoord1; in vec2 vColorTexCoord0; -in vec2 vColorTexCoord1; +in float vOpacity; out vec4 oFragColor; @@ -573,11 +571,9 @@ void calculateColor(int ctrl) { uFilterParams2, color0Filter); } - if (((ctrl >> COMBINER_CTRL_COLOR_1_ENABLE_SHIFT) & COMBINER_CTRL_COLOR_ENABLE_MASK) != 0) - color *= sampleColor(uColorTexture1, vColorTexCoord1); - // Apply mask. - color.a *= maskAlpha; + // Apply mask and opacity. + color.a *= maskAlpha * vOpacity; // Apply composite. int compositeOp = (ctrl >> COMBINER_CTRL_COMPOSITE_SHIFT) & COMBINER_CTRL_COMPOSITE_MASK; diff --git a/shaders/tile.vs.glsl b/shaders/tile.vs.glsl index 44fc464c..2c7bc8c4 100644 --- a/shaders/tile.vs.glsl +++ b/shaders/tile.vs.glsl @@ -15,24 +15,38 @@ precision highp sampler2D; uniform mat4 uTransform; uniform vec2 uTileSize; +uniform sampler2D uTextureMetadata; +uniform ivec2 uTextureMetadataSize; -in ivec2 aTilePosition; -in vec2 aColorTexCoord0; -in vec2 aColorTexCoord1; -in vec2 aMaskTexCoord0; -in vec2 aMaskTexCoord1; +in ivec2 aTileOffset; +in ivec2 aTileOrigin; +in uvec2 aMaskTexCoord0; +in uvec2 aMaskTexCoord1; in ivec2 aMaskBackdrop; +in int aColor; out vec3 vMaskTexCoord0; out vec3 vMaskTexCoord1; out vec2 vColorTexCoord0; -out vec2 vColorTexCoord1; +out float vOpacity; void main() { - vec2 position = vec2(aTilePosition) * uTileSize; - vColorTexCoord0 = aColorTexCoord0; - vColorTexCoord1 = aColorTexCoord1; - vMaskTexCoord0 = vec3(aMaskTexCoord0, float(aMaskBackdrop.x)); - vMaskTexCoord1 = vec3(aMaskTexCoord1, float(aMaskBackdrop.y)); + vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset); + vec2 position = (tileOrigin + tileOffset) * uTileSize; + + vec2 maskTexCoord0 = (vec2(aMaskTexCoord0) + tileOffset) / 256.0; + vec2 maskTexCoord1 = (vec2(aMaskTexCoord1) + tileOffset) / 256.0; + + vec2 textureMetadataScale = vec2(1.0) / vec2(uTextureMetadataSize); + vec2 metadataEntryCoord = ivec2(aColor % 256 * 2, aColor / 256); + vec2 colorTexMatrix0Coord = (metadataEntryCoord + vec2(0.5, 0.5)) * textureMetadataScale; + vec2 colorTexOffsetsCoord = (metadataEntryCoord + vec2(1.5, 0.5)) * textureMetadataScale; + vec4 colorTexMatrix0 = texture(uTextureMetadata, colorTexMatrix0Coord); + vec4 colorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord); + + vColorTexCoord0 = mat2(colorTexMatrix0) * position + colorTexOffsets.xy; + vOpacity = colorTexOffsets.z; + vMaskTexCoord0 = vec3(maskTexCoord0, float(aMaskBackdrop.x)); + vMaskTexCoord1 = vec3(maskTexCoord1, float(aMaskBackdrop.y)); gl_Position = uTransform * vec4(position, 0.0, 1.0); } diff --git a/svg/src/lib.rs b/svg/src/lib.rs index 4060ef6c..24840488 100644 --- a/svg/src/lib.rs +++ b/svg/src/lib.rs @@ -230,14 +230,16 @@ impl BuiltSVG { opacity: Opacity, fill_rule: UsvgFillRule) { outline.transform(&state.transform); - let paint = Paint::from_svg_paint(paint, &state.transform, &mut self.result_flags); + let paint = Paint::from_svg_paint(paint, + &state.transform, + opacity, + &mut self.result_flags); let style = self.scene.push_paint(&paint); let fill_rule = FillRule::from_usvg_fill_rule(fill_rule); let mut path = DrawPath::new(outline, style); path.set_clip_path(state.clip_path); path.set_fill_rule(fill_rule); path.set_name(name); - path.set_opacity((opacity.value() * 255.0) as u8); self.scene.push_path(path); } } @@ -287,6 +289,7 @@ impl Display for BuildResultFlags { trait PaintExt { fn from_svg_paint(svg_paint: &UsvgPaint, transform: &Transform2F, + opacity: Opacity, result_flags: &mut BuildResultFlags) -> Self; } @@ -295,6 +298,7 @@ impl PaintExt for Paint { #[inline] fn from_svg_paint(svg_paint: &UsvgPaint, transform: &Transform2F, + opacity: Opacity, result_flags: &mut BuildResultFlags) -> Paint { // TODO(pcwalton): Support gradients. @@ -307,6 +311,7 @@ impl PaintExt for Paint { } }); paint.apply_transform(transform); + paint.apply_opacity(opacity.value() as f32); paint } } diff --git a/text/src/lib.rs b/text/src/lib.rs index 55c729de..09368ca2 100644 --- a/text/src/lib.rs +++ b/text/src/lib.rs @@ -35,7 +35,6 @@ pub trait SceneExt { hinting_options: HintingOptions, clip_path: Option, blend_mode: BlendMode, - opacity: u8, paint_id: PaintId) -> Result<(), GlyphLoadingError> where F: Loader; @@ -48,7 +47,6 @@ pub trait SceneExt { hinting_options: HintingOptions, clip_path: Option, blend_mode: BlendMode, - opacity: u8, paint_id: PaintId) -> Result<(), GlyphLoadingError>; @@ -61,7 +59,6 @@ pub trait SceneExt { hinting_options: HintingOptions, clip_path: Option, blend_mode: BlendMode, - opacity: u8, paint_id: PaintId) -> Result<(), GlyphLoadingError>; } @@ -76,7 +73,6 @@ impl SceneExt for Scene { hinting_options: HintingOptions, clip_path: Option, blend_mode: BlendMode, - opacity: u8, paint_id: PaintId) -> Result<(), GlyphLoadingError> where F: Loader { @@ -93,7 +89,6 @@ impl SceneExt for Scene { let mut path = DrawPath::new(outline, paint_id); path.set_clip_path(clip_path); path.set_blend_mode(blend_mode); - path.set_opacity(opacity); self.push_path(path); Ok(()) @@ -107,7 +102,6 @@ impl SceneExt for Scene { hinting_options: HintingOptions, clip_path: Option, blend_mode: BlendMode, - opacity: u8, paint_id: PaintId) -> Result<(), GlyphLoadingError> { for glyph in &layout.glyphs { @@ -124,7 +118,6 @@ impl SceneExt for Scene { hinting_options, clip_path, blend_mode, - opacity, paint_id)?; } Ok(()) @@ -140,7 +133,6 @@ impl SceneExt for Scene { hinting_options: HintingOptions, clip_path: Option, blend_mode: BlendMode, - opacity: u8, paint_id: PaintId) -> Result<(), GlyphLoadingError> { let layout = skribo::layout(style, collection, text); @@ -151,7 +143,6 @@ impl SceneExt for Scene { hinting_options, clip_path, blend_mode, - opacity, paint_id) } }