diff --git a/Cargo.lock b/Cargo.lock index 91a3daa8..a3ed56d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1131,6 +1131,9 @@ dependencies = [ name = "instant" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "iovec" @@ -1808,6 +1811,7 @@ 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)", "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)", "pathfinder_color 0.1.0", "pathfinder_content 0.1.0", diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index ec300657..825055fa 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -12,7 +12,7 @@ use pathfinder_color::ColorU; use pathfinder_content::dash::OutlineDash; -use pathfinder_content::effects::{BlendMode, BlurDirection, CompositeOp, Effects, Filter}; +use pathfinder_content::effects::{BlendMode, BlurDirection, Effects, Filter}; use pathfinder_content::fill::FillRule; use pathfinder_content::gradient::Gradient; use pathfinder_content::outline::{ArcDirection, Contour, Outline}; @@ -251,11 +251,9 @@ 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 composite_op = self.current_state.global_composite_operation.to_composite_op(); let opacity = (self.current_state.global_alpha * 255.0) as u8; if !self.current_state.shadow_paint.is_fully_transparent() { - let composite_render_target_id = self.push_render_target_if_needed(composite_op); let shadow_blur_render_target_ids = self.push_shadow_blur_render_targets_if_needed(); let paint = self.current_state.resolve_paint(&self.current_state.shadow_paint); @@ -273,10 +271,8 @@ impl CanvasRenderingContext2D { self.scene.push_path(path); self.composite_shadow_blur_render_targets_if_needed(shadow_blur_render_target_ids); - self.composite_render_target_if_needed(composite_op, composite_render_target_id); } - let render_target_id = self.push_render_target_if_needed(composite_op); outline.transform(&transform); let mut path = DrawPath::new(outline, paint_id); @@ -285,18 +281,6 @@ impl CanvasRenderingContext2D { path.set_blend_mode(blend_mode); path.set_opacity(opacity); self.scene.push_path(path); - - self.composite_render_target_if_needed(composite_op, render_target_id); - } - - fn push_render_target_if_needed(&mut self, composite_op: Option) - -> Option { - if composite_op.is_none() { - return None; - } - - let render_target_size = self.scene.view_box().size().ceil().to_i32(); - Some(self.scene.push_render_target(RenderTarget::new(render_target_size, String::new()))) } fn push_shadow_blur_render_targets_if_needed(&mut self) -> Option<[RenderTargetId; 2]> { @@ -312,19 +296,6 @@ impl CanvasRenderingContext2D { Some([render_target_id_a, render_target_id_b]) } - fn composite_render_target_if_needed(&mut self, - composite_op: Option, - render_target_id: Option) { - let composite_op = match composite_op { - None => return, - Some(composite_op) => composite_op, - }; - - self.scene.pop_render_target(); - self.scene.draw_render_target(render_target_id.unwrap(), - Effects::new(Filter::Composite(composite_op))); - } - fn composite_shadow_blur_render_targets_if_needed( &mut self, render_target_ids: Option<[RenderTargetId; 2]>) { @@ -679,6 +650,7 @@ pub enum CompositeOperation { impl CompositeOperation { fn to_blend_mode(self) -> BlendMode { match self { + CompositeOperation::Copy => BlendMode::Copy, CompositeOperation::SourceAtop => BlendMode::SrcAtop, CompositeOperation::DestinationOver => BlendMode::DestOver, CompositeOperation::DestinationOut => BlendMode::DestOut, @@ -699,43 +671,11 @@ impl CompositeOperation { CompositeOperation::Saturation => BlendMode::Saturation, CompositeOperation::Color => BlendMode::Color, CompositeOperation::Luminosity => BlendMode::Luminosity, - CompositeOperation::SourceOver | - CompositeOperation::SourceIn | - CompositeOperation::SourceOut | - CompositeOperation::DestinationIn | - CompositeOperation::DestinationAtop | - CompositeOperation::Copy => BlendMode::SrcOver, - } - } - - fn to_composite_op(self) -> Option { - match self { - CompositeOperation::SourceIn => Some(CompositeOp::SrcIn), - CompositeOperation::SourceOut => Some(CompositeOp::SrcOut), - CompositeOperation::DestinationIn => Some(CompositeOp::DestIn), - CompositeOperation::DestinationAtop => Some(CompositeOp::DestAtop), - CompositeOperation::Copy => Some(CompositeOp::Copy), - CompositeOperation::SourceOver | - CompositeOperation::SourceAtop | - CompositeOperation::DestinationOver | - CompositeOperation::DestinationOut | - CompositeOperation::Xor | - CompositeOperation::Lighter | - CompositeOperation::Multiply | - CompositeOperation::Screen | - CompositeOperation::Overlay | - CompositeOperation::Darken | - CompositeOperation::Lighten | - CompositeOperation::ColorDodge | - CompositeOperation::ColorBurn | - CompositeOperation::HardLight | - CompositeOperation::SoftLight | - CompositeOperation::Difference | - CompositeOperation::Exclusion | - CompositeOperation::Hue | - CompositeOperation::Saturation | - CompositeOperation::Color | - CompositeOperation::Luminosity => None, + CompositeOperation::SourceOver => BlendMode::SrcOver, + CompositeOperation::SourceIn => BlendMode::SrcIn, + CompositeOperation::SourceOut => BlendMode::SrcOut, + CompositeOperation::DestinationIn => BlendMode::DestIn, + CompositeOperation::DestinationAtop => BlendMode::DestAtop, } } } diff --git a/content/src/effects.rs b/content/src/effects.rs index 9141340c..b3166cc4 100644 --- a/content/src/effects.rs +++ b/content/src/effects.rs @@ -29,7 +29,7 @@ pub const MAX_STEM_DARKENING_AMOUNT: [f32; 2] = [0.3, 0.3]; pub const MAX_STEM_DARKENING_PIXELS_PER_EM: f32 = 72.0; /// Effects that can be applied to a layer. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Effects { /// The shader that should be used when compositing this layer onto its destination. pub filter: Filter, @@ -38,11 +38,8 @@ pub struct Effects { /// The shader that should be used when compositing this layer onto its destination. #[derive(Clone, Copy, Debug)] pub enum Filter { - /// A Porter-Duff compositing operation. - /// - /// The compositing operations here are the ones that can't be blend modes because they can - /// clear parts of the destination not overlapped by the source, plus the regular source-over. - Composite(CompositeOp), + /// No special filter. + None, /// Performs postprocessing operations useful for monochrome text. Text { @@ -68,61 +65,35 @@ pub enum Filter { }, } -#[derive(Clone, Copy, Debug)] -pub enum CompositeOp { - /// The default. - SrcOver, - /// No regions are enabled. - Clear, - /// Only the source will be present. - Copy, - /// The source that overlaps the destination replaces the destination. - SrcIn, - /// Destination which overlaps the source replaces the source. - DestIn, - /// Source is placed where it falls outside of the destination. - SrcOut, - /// Destination which overlaps the source replaces the source. Source is placed elsewhere. - DestAtop, -} - /// Blend modes that can be applied to individual paths. -/// -/// All blend modes preserve parts of the destination that are not overlapped by the source path. -/// Other Porter-Duff compositing operations are `CompositeOp`s. #[derive(Clone, Copy, PartialEq, Debug)] pub enum BlendMode { - // Supported by GPU blender + // Porter-Duff, supported by GPU blender Clear, + Copy, + SrcIn, + SrcOut, SrcOver, - DestOver, - DestOut, SrcAtop, + DestIn, + DestOut, + DestOver, + DestAtop, Xor, Lighter, - Lighten, - Darken, - // Overlay + // Others, unsupported by GPU blender + Darken, + Lighten, Multiply, Screen, HardLight, Overlay, - - // Dodge/burn ColorDodge, ColorBurn, - - // Soft light SoftLight, - - // Difference Difference, - - // Exclusion Exclusion, - - // HSL Hue, Saturation, Color, @@ -138,13 +109,6 @@ pub enum BlurDirection { Y, } -impl Default for CompositeOp { - #[inline] - fn default() -> CompositeOp { - CompositeOp::SrcOver - } -} - impl Default for BlendMode { #[inline] fn default() -> BlendMode { @@ -152,6 +116,13 @@ impl Default for BlendMode { } } +impl Default for Filter { + #[inline] + fn default() -> Filter { + Filter::None + } +} + impl Effects { #[inline] pub fn new(filter: Filter) -> Effects { @@ -173,6 +144,44 @@ impl BlendMode { BlendMode::Lighter | BlendMode::Lighten | BlendMode::Darken | + BlendMode::Copy | + BlendMode::SrcIn | + BlendMode::DestIn | + BlendMode::SrcOut | + BlendMode::DestAtop | + BlendMode::Multiply | + BlendMode::Screen | + BlendMode::HardLight | + BlendMode::Overlay | + BlendMode::ColorDodge | + BlendMode::ColorBurn | + BlendMode::SoftLight | + BlendMode::Difference | + BlendMode::Exclusion | + BlendMode::Hue | + BlendMode::Saturation | + BlendMode::Color | + BlendMode::Luminosity => false, + } + } + + /// True if this blend mode does not preserve destination areas outside the source. + pub fn is_destructive(self) -> bool { + match self { + BlendMode::Clear | + BlendMode::Copy | + BlendMode::SrcIn | + BlendMode::DestIn | + BlendMode::SrcOut | + BlendMode::DestAtop => true, + BlendMode::SrcOver | + BlendMode::DestOver | + BlendMode::DestOut | + BlendMode::SrcAtop | + BlendMode::Xor | + BlendMode::Lighter | + BlendMode::Lighten | + BlendMode::Darken | BlendMode::Multiply | BlendMode::Screen | BlendMode::HardLight | diff --git a/gl/src/lib.rs b/gl/src/lib.rs index 05f180d4..65171a44 100644 --- a/gl/src/lib.rs +++ b/gl/src/lib.rs @@ -169,11 +169,24 @@ impl GLDevice { } } + // Workaround for a macOS driver bug, it seems. + fn unset_uniform(&self, uniform: &GLUniform, data: &UniformData) { + unsafe { + match *data { + UniformData::TextureUnit(_) => { + gl::Uniform1i(uniform.location, 0); ck(); + } + _ => {} + } + } + } + fn reset_render_state(&self, render_state: &RenderState) { self.reset_render_options(&render_state.options); for texture_unit in 0..(render_state.textures.len() as u32) { self.unbind_texture(texture_unit); } + render_state.uniforms.iter().for_each(|(uniform, data)| self.unset_uniform(uniform, data)); self.unuse_program(); self.unbind_vertex_array(); } diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index 77df63ad..851c0256 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -11,21 +11,22 @@ //! Packs data onto the GPU. use crate::concurrent::executor::Executor; -use crate::gpu::renderer::{BlendModeProgram, MASK_TILES_ACROSS}; -use crate::gpu_data::{AlphaTile, AlphaTileBatch, AlphaTileVertex, FillBatchPrimitive, MaskTile}; -use crate::gpu_data::{MaskTileVertex, RenderCommand, SolidTile, SolidTileBatch}; -use crate::gpu_data::{TexturePageId, TileObjectPrimitive}; +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::options::{PreparedBuildOptions, RenderCommandListener}; use crate::paint::{PaintInfo, PaintMetadata, RenderTargetMetadata}; use crate::scene::{DisplayItem, Scene}; use crate::tile_map::DenseTileMap; -use crate::tiles::{self, DrawTilingPathInfo, TILE_HEIGHT, TILE_WIDTH, Tiler, TilingPathInfo}; +use crate::tiles::{self, DrawTilingPathInfo, PackedTile, TILE_HEIGHT, TILE_WIDTH}; +use crate::tiles::{Tiler, TilingPathInfo}; use crate::z_buffer::{DepthMetadata, ZBuffer}; -use pathfinder_content::effects::BlendMode; +use pathfinder_content::effects::{BlendMode, Effects, Filter}; use pathfinder_content::fill::FillRule; use pathfinder_content::render_target::RenderTargetId; use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8}; use pathfinder_geometry::rect::{RectF, RectI}; +use pathfinder_geometry::transform2d::Transform2F; use pathfinder_geometry::util; use pathfinder_geometry::vector::{Vector2F, Vector2I}; use pathfinder_gpu::TextureSamplingFlags; @@ -39,7 +40,6 @@ pub(crate) struct SceneBuilder<'a> { built_options: &'a PreparedBuildOptions, next_alpha_tile_index: AtomicUsize, - next_mask_tile_index: AtomicUsize, pub(crate) listener: Box, } @@ -55,21 +55,32 @@ pub(crate) struct ObjectBuilder { struct BuiltDrawPath { path: BuiltPath, blend_mode: BlendMode, - sampling_flags: TextureSamplingFlags, - color_texture_page: TexturePageId, + color_texture_page_0: TexturePageId, + color_texture_page_1: TexturePageId, + sampling_flags_0: TextureSamplingFlags, + sampling_flags_1: TextureSamplingFlags, + mask_0_fill_rule: FillRule, + mask_1_fill_rule: Option, } #[derive(Debug)] pub(crate) struct BuiltPath { - pub mask_tiles: Vec, - pub alpha_tiles: Vec, - pub solid_tiles: Vec, + pub solid_tiles: SolidTiles, + pub empty_tiles: Vec, + pub single_mask_tiles: Vec, + pub dual_mask_tiles: Vec, pub tiles: DenseTileMap, pub fill_rule: FillRule, } +#[derive(Clone, Debug)] +pub(crate) enum SolidTiles { + Occluders(Vec), + Regular(Vec), +} + #[derive(Clone, Copy, Debug)] -pub(crate) struct SolidTileInfo { +pub(crate) struct Occluder { pub(crate) coords: Vector2I, } @@ -82,10 +93,7 @@ impl<'a> SceneBuilder<'a> { SceneBuilder { scene, built_options, - next_alpha_tile_index: AtomicUsize::new(0), - next_mask_tile_index: AtomicUsize::new(0), - listener, } } @@ -113,6 +121,8 @@ impl<'a> SceneBuilder<'a> { render_commands, paint_metadata, render_target_metadata, + opacity_tile_page, + opacity_tile_transform, } = self.scene.build_paint_info(); for render_command in render_commands { self.listener.send(render_command); @@ -121,34 +131,37 @@ impl<'a> SceneBuilder<'a> { let effective_view_box = self.scene.effective_view_box(self.built_options); let built_clip_paths = executor.build_vector(clip_path_count, |path_index| { - self.build_clip_path(path_index, effective_view_box, &self.built_options, &self.scene) + self.build_clip_path(PathBuildParams { + path_index, + view_box: effective_view_box, + built_options: &self.built_options, + scene: &self.scene, + }) }); let built_draw_paths = executor.build_vector(draw_path_count, |path_index| { - self.build_draw_path(path_index, - effective_view_box, - &self.built_options, - &self.scene, - &paint_metadata, - &built_clip_paths) + self.build_draw_path(DrawPathBuildParams { + path_build_params: PathBuildParams { + path_index, + view_box: effective_view_box, + built_options: &self.built_options, + scene: &self.scene, + }, + paint_metadata: &paint_metadata, + opacity_tile_page, + opacity_tile_transform, + built_clip_paths: &built_clip_paths, + }) }); - self.finish_building(&paint_metadata, - &render_target_metadata, - built_clip_paths, - built_draw_paths); + self.finish_building(&paint_metadata, &render_target_metadata, built_draw_paths); let build_time = Instant::now() - start_time; self.listener.send(RenderCommand::Finish { build_time }); } - fn build_clip_path( - &self, - path_index: usize, - view_box: RectF, - built_options: &PreparedBuildOptions, - scene: &Scene, - ) -> BuiltPath { + fn build_clip_path(&self, params: PathBuildParams) -> BuiltPath { + let PathBuildParams { path_index, view_box, built_options, scene } = params; let path_object = &scene.clip_paths[path_index]; let outline = scene.apply_render_options(path_object.outline(), built_options); @@ -156,7 +169,6 @@ impl<'a> SceneBuilder<'a> { &outline, path_object.fill_rule(), view_box, - path_index as u16, TilingPathInfo::Clip); tiler.generate_tiles(); @@ -165,15 +177,15 @@ impl<'a> SceneBuilder<'a> { tiler.object_builder.built_path } - fn build_draw_path( - &self, - path_index: usize, - view_box: RectF, - built_options: &PreparedBuildOptions, - scene: &Scene, - paint_metadata: &[PaintMetadata], - built_clip_paths: &[BuiltPath], - ) -> BuiltDrawPath { + fn build_draw_path(&self, params: DrawPathBuildParams) -> BuiltDrawPath { + let DrawPathBuildParams { + path_build_params: PathBuildParams { path_index, view_box, built_options, scene }, + paint_metadata, + opacity_tile_page, + opacity_tile_transform, + built_clip_paths, + } = params; + let path_object = &scene.paths[path_index]; let outline = scene.apply_render_options(path_object.outline(), built_options); @@ -186,9 +198,9 @@ impl<'a> SceneBuilder<'a> { &outline, path_object.fill_rule(), view_box, - path_index as u16, TilingPathInfo::Draw(DrawTilingPathInfo { paint_metadata, + opacity_tile_transform, blend_mode: path_object.blend_mode(), opacity: path_object.opacity(), built_clip_path, @@ -201,26 +213,21 @@ impl<'a> SceneBuilder<'a> { BuiltDrawPath { path: tiler.object_builder.built_path, blend_mode: path_object.blend_mode(), - color_texture_page: paint_metadata.location.page, - sampling_flags: paint_metadata.sampling_flags, + color_texture_page_0: paint_metadata.location.page, + sampling_flags_0: paint_metadata.sampling_flags, + color_texture_page_1: opacity_tile_page, + sampling_flags_1: TextureSamplingFlags::empty(), + mask_0_fill_rule: path_object.fill_rule(), + mask_1_fill_rule: built_clip_path.map(|_| FillRule::Winding), } } fn cull_tiles(&self, paint_metadata: &[PaintMetadata], render_target_metadata: &[RenderTargetMetadata], - built_clip_paths: Vec, built_draw_paths: Vec) -> CulledTiles { - let mut culled_tiles = CulledTiles { - mask_winding_tiles: vec![], - mask_evenodd_tiles: vec![], - display_list: vec![], - }; - - for built_clip_path in built_clip_paths { - culled_tiles.push_mask_tiles(&built_clip_path); - } + let mut culled_tiles = CulledTiles { display_list: vec![] }; let mut remaining_layer_z_buffers = self.build_solid_tiles(&built_draw_paths); remaining_layer_z_buffers.reverse(); @@ -229,7 +236,7 @@ impl<'a> SceneBuilder<'a> { let first_z_buffer = remaining_layer_z_buffers.pop().unwrap(); let first_solid_tiles = first_z_buffer.build_solid_tiles(paint_metadata); for batch in first_solid_tiles.batches { - culled_tiles.display_list.push(CulledDisplayItem::DrawSolidTiles(batch)); + culled_tiles.display_list.push(CulledDisplayItem::DrawTiles(batch)); } let mut layer_z_buffers_stack = vec![first_z_buffer]; @@ -244,7 +251,7 @@ impl<'a> SceneBuilder<'a> { let z_buffer = remaining_layer_z_buffers.pop().unwrap(); let solid_tiles = z_buffer.build_solid_tiles(paint_metadata); for batch in solid_tiles.batches { - culled_tiles.display_list.push(CulledDisplayItem::DrawSolidTiles(batch)); + culled_tiles.display_list.push(CulledDisplayItem::DrawTiles(batch)); } layer_z_buffers_stack.push(z_buffer); } @@ -271,16 +278,22 @@ impl<'a> SceneBuilder<'a> { let uv_rect = RectI::new(tile_coords, Vector2I::splat(1)).to_f32() .scale_xy(uv_scale); - tiles.push(SolidTile::from_texture_rect(tile_coords, uv_rect)); + tiles.push(Tile::new_solid_from_texture_rect(tile_coords, uv_rect)); } } - let batch = SolidTileBatch { + let batch = TileBatch { tiles, - color_texture_page: metadata.location.page, - sampling_flags: TextureSamplingFlags::empty(), + color_texture_0: Some(TileBatchTexture { + page: metadata.location.page, + sampling_flags: TextureSamplingFlags::empty(), + }), + color_texture_1: None, effects, + blend_mode: BlendMode::SrcOver, + mask_0_fill_rule: None, + mask_1_fill_rule: None, }; - culled_tiles.display_list.push(CulledDisplayItem::DrawSolidTiles(batch)); + culled_tiles.display_list.push(CulledDisplayItem::DrawTiles(batch)); current_depth += 1; } @@ -290,55 +303,63 @@ impl<'a> SceneBuilder<'a> { } => { for draw_path_index in start_draw_path_index..end_draw_path_index { let built_draw_path = &built_draw_paths[draw_path_index as usize]; - culled_tiles.push_mask_tiles(&built_draw_path.path); + let layer_z_buffer = layer_z_buffers_stack.last().unwrap(); + let color_texture_0 = Some(TileBatchTexture { + page: built_draw_path.color_texture_page_0, + sampling_flags: built_draw_path.sampling_flags_0, + }); + let color_texture_1 = Some(TileBatchTexture { + page: built_draw_path.color_texture_page_1, + sampling_flags: built_draw_path.sampling_flags_1, + }); - // Create a new `DrawAlphaTiles` display item if we don't have one or if we - // have to break a batch due to blend mode or paint page. Note that every - // path with a blend mode that requires a readable framebuffer needs its - // own batch. - // - // TODO(pcwalton): If we really wanted to, we could use tile maps to avoid - // batch breaks in some cases… - match culled_tiles.display_list.last() { - Some(&CulledDisplayItem::DrawAlphaTiles(AlphaTileBatch { - tiles: _, - color_texture_page, - blend_mode, - sampling_flags - })) if color_texture_page == built_draw_path.color_texture_page && - blend_mode == built_draw_path.blend_mode && - sampling_flags == built_draw_path.sampling_flags && - !BlendModeProgram::from_blend_mode( - blend_mode).needs_readable_framebuffer() => {} - _ => { - let batch = AlphaTileBatch { - tiles: vec![], - color_texture_page: built_draw_path.color_texture_page, - blend_mode: built_draw_path.blend_mode, - sampling_flags: built_draw_path.sampling_flags, - }; - culled_tiles.display_list - .push(CulledDisplayItem::DrawAlphaTiles(batch)) - } + debug_assert!(built_draw_path.path.empty_tiles.is_empty() || + built_draw_path.blend_mode.is_destructive()); + self.add_alpha_tiles(&mut culled_tiles, + layer_z_buffer, + &built_draw_path.path.empty_tiles, + current_depth, + None, + None, + built_draw_path.blend_mode, + None, + None); + + self.add_alpha_tiles(&mut culled_tiles, + layer_z_buffer, + &built_draw_path.path.single_mask_tiles, + current_depth, + color_texture_0, + color_texture_1, + built_draw_path.blend_mode, + Some(built_draw_path.mask_0_fill_rule), + None); + + if let Some(mask_1_fill_rule) = built_draw_path.mask_1_fill_rule { + self.add_alpha_tiles(&mut culled_tiles, + layer_z_buffer, + &built_draw_path.path.dual_mask_tiles, + current_depth, + color_texture_0, + color_texture_1, + built_draw_path.blend_mode, + Some(built_draw_path.mask_0_fill_rule), + Some(mask_1_fill_rule)); } - // Fetch the destination alpha tiles buffer. - let culled_alpha_tiles = match *culled_tiles.display_list - .last_mut() - .unwrap() { - CulledDisplayItem::DrawAlphaTiles(AlphaTileBatch { - tiles: ref mut culled_alpha_tiles, - .. - }) => culled_alpha_tiles, - _ => unreachable!(), - }; - - let layer_z_buffer = layer_z_buffers_stack.last().unwrap(); - for alpha_tile in &built_draw_path.path.alpha_tiles { - let alpha_tile_coords = alpha_tile.upper_left.tile_position(); - if layer_z_buffer.test(alpha_tile_coords, current_depth) { - culled_alpha_tiles.push(*alpha_tile); + match built_draw_path.path.solid_tiles { + SolidTiles::Regular(ref tiles) => { + self.add_alpha_tiles(&mut culled_tiles, + layer_z_buffer, + tiles, + current_depth, + color_texture_0, + color_texture_1, + built_draw_path.blend_mode, + None, + built_draw_path.mask_1_fill_rule); } + SolidTiles::Occluders(_) => {} } current_depth += 1; @@ -354,7 +375,7 @@ impl<'a> SceneBuilder<'a> { let effective_view_box = self.scene.effective_view_box(self.built_options); let mut z_buffers = vec![ZBuffer::new(effective_view_box)]; let mut z_buffer_index_stack = vec![0]; - let mut current_depth = 0; + let mut current_depth = 1; // Create Z-buffers. for display_item in &self.scene.display_list { @@ -371,11 +392,17 @@ impl<'a> SceneBuilder<'a> { let z_buffer = &mut z_buffers[*z_buffer_index_stack.last().unwrap()]; for (path_subindex, built_draw_path) in built_draw_paths[start_index..end_index].iter().enumerate() { - let solid_tiles = &built_draw_path.path.solid_tiles; let path_index = (path_subindex + start_index) as u32; let path = &self.scene.paths[path_index as usize]; let metadata = DepthMetadata { paint_id: path.paint() }; - z_buffer.update(solid_tiles, current_depth, metadata); + match built_draw_path.path.solid_tiles { + SolidTiles::Regular(_) => { + z_buffer.update(&[], current_depth, metadata); + } + SolidTiles::Occluders(ref occluders) => { + z_buffer.update(occluders, current_depth, metadata); + } + } current_depth += 1; } } @@ -390,27 +417,76 @@ impl<'a> SceneBuilder<'a> { z_buffers } - fn pack_tiles(&mut self, culled_tiles: CulledTiles) { - if !culled_tiles.mask_winding_tiles.is_empty() { - self.listener.send(RenderCommand::RenderMaskTiles { - tiles: culled_tiles.mask_winding_tiles, - fill_rule: FillRule::Winding, - }); - } - if !culled_tiles.mask_evenodd_tiles.is_empty() { - self.listener.send(RenderCommand::RenderMaskTiles { - tiles: culled_tiles.mask_evenodd_tiles, - fill_rule: FillRule::EvenOdd, - }); + fn add_alpha_tiles(&self, + culled_tiles: &mut CulledTiles, + layer_z_buffer: &ZBuffer, + alpha_tiles: &[Tile], + current_depth: u32, + color_texture_0: Option, + color_texture_1: Option, + blend_mode: BlendMode, + mask_0_fill_rule: Option, + mask_1_fill_rule: Option) { + if alpha_tiles.is_empty() { + return; } + // Create a new `DrawTiles` display item if we don't have one or if we have to break a + // batch due to blend mode or paint page. Note that every path with a blend mode that + // requires a readable framebuffer needs its own batch. + // + // TODO(pcwalton): If we really wanted to, we could use tile maps to avoid + // batch breaks in some cases… + match culled_tiles.display_list.last() { + Some(&CulledDisplayItem::DrawTiles(TileBatch { + tiles: _, + color_texture_0: ref batch_color_texture_0, + color_texture_1: ref batch_color_texture_1, + blend_mode: batch_blend_mode, + effects: Effects { filter: Filter::None }, + mask_0_fill_rule: batch_mask_0_fill_rule, + mask_1_fill_rule: batch_mask_1_fill_rule, + })) if *batch_color_texture_0 == color_texture_0 && + *batch_color_texture_1 == color_texture_1 && + batch_blend_mode == blend_mode && + batch_mask_0_fill_rule == mask_0_fill_rule && + batch_mask_1_fill_rule == mask_1_fill_rule && + !batch_blend_mode.needs_readable_framebuffer() => {} + _ => { + let batch = TileBatch { + tiles: vec![], + color_texture_0, + color_texture_1, + blend_mode, + effects: Effects::default(), + mask_0_fill_rule, + mask_1_fill_rule, + }; + culled_tiles.display_list.push(CulledDisplayItem::DrawTiles(batch)) + } + } + + // Fetch the destination alpha tiles buffer. + let culled_alpha_tiles = match *culled_tiles.display_list.last_mut().unwrap() { + CulledDisplayItem::DrawTiles(TileBatch { tiles: ref mut culled_alpha_tiles, .. }) => { + culled_alpha_tiles + } + _ => unreachable!(), + }; + + for alpha_tile in alpha_tiles { + let alpha_tile_coords = alpha_tile.upper_left.tile_position(); + if layer_z_buffer.test(alpha_tile_coords, current_depth) { + culled_alpha_tiles.push(*alpha_tile); + } + } + } + + fn pack_tiles(&mut self, culled_tiles: CulledTiles) { for display_item in culled_tiles.display_list { match display_item { - CulledDisplayItem::DrawSolidTiles(batch) => { - self.listener.send(RenderCommand::DrawSolidTiles(batch)) - } - CulledDisplayItem::DrawAlphaTiles(batch) => { - self.listener.send(RenderCommand::DrawAlphaTiles(batch)) + CulledDisplayItem::DrawTiles(batch) => { + self.listener.send(RenderCommand::DrawTiles(batch)) } CulledDisplayItem::PushRenderTarget(render_target_id) => { self.listener.send(RenderCommand::PushRenderTarget(render_target_id)) @@ -425,21 +501,14 @@ impl<'a> SceneBuilder<'a> { fn finish_building(&mut self, paint_metadata: &[PaintMetadata], render_target_metadata: &[RenderTargetMetadata], - built_clip_paths: Vec, built_draw_paths: Vec) { self.listener.send(RenderCommand::FlushFills); let culled_tiles = self.cull_tiles(paint_metadata, render_target_metadata, - built_clip_paths, built_draw_paths); self.pack_tiles(culled_tiles); } - pub(crate) fn allocate_mask_tile_index(&self) -> u16 { - // FIXME(pcwalton): Check for overflow! - self.next_mask_tile_index.fetch_add(1, Ordering::Relaxed) as u16 - } - fn needs_readable_framebuffer(&self) -> bool { let mut framebuffer_nesting = 0; for display_item in &self.scene.display_list { @@ -453,8 +522,7 @@ impl<'a> SceneBuilder<'a> { } for path_index in start_index..end_index { let blend_mode = self.scene.paths[path_index as usize].blend_mode(); - let blend_mode_program = BlendModeProgram::from_blend_mode(blend_mode); - if blend_mode_program.needs_readable_framebuffer() { + if blend_mode.needs_readable_framebuffer() { return true; } } @@ -465,34 +533,70 @@ impl<'a> SceneBuilder<'a> { } } +struct PathBuildParams<'a> { + path_index: usize, + view_box: RectF, + built_options: &'a PreparedBuildOptions, + scene: &'a Scene, +} + +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], +} + impl BuiltPath { - fn new(bounds: RectF, fill_rule: FillRule) -> BuiltPath { + fn new(path_bounds: RectF, + view_box_bounds: RectF, + fill_rule: FillRule, + tiling_path_info: &TilingPathInfo) + -> 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 + } + TilingPathInfo::Clip => true, + }; + + let tile_map_bounds = if tiling_path_info.has_destructive_blend_mode() { + view_box_bounds + } else { + path_bounds + }; + BuiltPath { - mask_tiles: vec![], - alpha_tiles: vec![], - solid_tiles: vec![], - tiles: DenseTileMap::new(tiles::round_rect_out_to_tile_bounds(bounds)), + single_mask_tiles: vec![], + dual_mask_tiles: vec![], + empty_tiles: vec![], + solid_tiles: if occludes { + SolidTiles::Occluders(vec![]) + } else { + SolidTiles::Regular(vec![]) + }, + tiles: DenseTileMap::new(tiles::round_rect_out_to_tile_bounds(tile_map_bounds)), fill_rule, } } } -impl SolidTileInfo { +impl Occluder { #[inline] - pub(crate) fn new(coords: Vector2I) -> SolidTileInfo { - SolidTileInfo { coords } + pub(crate) fn new(coords: Vector2I) -> Occluder { + Occluder { coords } } } struct CulledTiles { - mask_winding_tiles: Vec, - mask_evenodd_tiles: Vec, display_list: Vec, } enum CulledDisplayItem { - DrawSolidTiles(SolidTileBatch), - DrawAlphaTiles(AlphaTileBatch), + DrawTiles(TileBatch), PushRenderTarget(RenderTargetId), PopRenderTarget, } @@ -506,8 +610,16 @@ pub struct TileStats { // Utilities for built objects impl ObjectBuilder { - pub(crate) fn new(bounds: RectF, fill_rule: FillRule) -> ObjectBuilder { - ObjectBuilder { built_path: BuiltPath::new(bounds, fill_rule), bounds, fills: vec![] } + pub(crate) fn new(path_bounds: RectF, + view_box_bounds: RectF, + fill_rule: FillRule, + tiling_path_info: &TilingPathInfo) + -> ObjectBuilder { + ObjectBuilder { + built_path: BuiltPath::new(path_bounds, view_box_bounds, fill_rule, tiling_path_info), + bounds: path_bounds, + fills: vec![], + } } #[inline] @@ -685,107 +797,81 @@ impl ObjectBuilder { pub(crate) fn local_tile_index_to_coords(&self, tile_index: u32) -> Vector2I { self.built_path.tiles.index_to_coords(tile_index as usize) } +} - pub(crate) fn push_mask_tile(mask_tiles: &mut Vec, - fill_tile: &TileObjectPrimitive, - mask_tile_index: u16, - object_index: u16) { - mask_tiles.push(MaskTile { - upper_left: MaskTileVertex::new(mask_tile_index, - fill_tile.alpha_tile_index as u16, - Vector2I::default(), - object_index, - fill_tile.backdrop as i16), - upper_right: MaskTileVertex::new(mask_tile_index, - fill_tile.alpha_tile_index as u16, - Vector2I::new(1, 0), - object_index, - fill_tile.backdrop as i16), - lower_left: MaskTileVertex::new(mask_tile_index, - fill_tile.alpha_tile_index as u16, - Vector2I::new(0, 1), - object_index, - fill_tile.backdrop as i16), - lower_right: MaskTileVertex::new(mask_tile_index, - fill_tile.alpha_tile_index as u16, - Vector2I::splat(1), - object_index, - fill_tile.backdrop as i16), - }); - } +impl<'a> PackedTile<'a> { + pub(crate) fn add_to(&self, + 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 (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), + }; - pub(crate) fn push_alpha_tile(alpha_tiles: &mut Vec, - mask_tile_index: u16, - tile_coords: Vector2I, - object_index: u16, - draw_tiling_path_info: &DrawTilingPathInfo) { - alpha_tiles.push(AlphaTile { - upper_left: AlphaTileVertex::new(tile_coords, - mask_tile_index, - Vector2I::default(), - object_index, - draw_tiling_path_info), - upper_right: AlphaTileVertex::new(tile_coords, - mask_tile_index, - Vector2I::new(1, 0), - object_index, + tiles.push(Tile { + upper_left: TileVertex::new_alpha(self.tile_coords, + fill_tile_index, + fill_tile_backdrop, + clip_tile_index, + clip_tile_backdrop, + Vector2I::default(), draw_tiling_path_info), - lower_left: AlphaTileVertex::new(tile_coords, - mask_tile_index, - Vector2I::new(0, 1), - object_index, - draw_tiling_path_info), - lower_right: AlphaTileVertex::new(tile_coords, - mask_tile_index, - Vector2I::splat(1), - object_index, + upper_right: TileVertex::new_alpha(self.tile_coords, + fill_tile_index, + fill_tile_backdrop, + clip_tile_index, + clip_tile_backdrop, + Vector2I::new(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, + Vector2I::new(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, + Vector2I::splat(1), + draw_tiling_path_info), }); } } -impl MaskTileVertex { +impl TileVertex { #[inline] - fn new(mask_index: u16, - fill_index: u16, - tile_offset: Vector2I, - object_index: u16, - backdrop: i16) - -> MaskTileVertex { - let mask_uv = calculate_mask_uv(mask_index, tile_offset); - let fill_uv = calculate_mask_uv(fill_index, tile_offset); - MaskTileVertex { - mask_u: mask_uv.x() as u16, - mask_v: mask_uv.y() as u16, - fill_u: fill_uv.x() as u16, - fill_v: fill_uv.y() as u16, - backdrop, - object_index, - } - } -} - -impl AlphaTileVertex { - #[inline] - fn new(tile_origin: Vector2I, - tile_index: u16, - tile_offset: Vector2I, - object_index: u16, - draw_tiling_path_info: &DrawTilingPathInfo) - -> AlphaTileVertex { + fn new_alpha(tile_origin: Vector2I, + draw_tile_index: u16, + draw_tile_backdrop: i16, + clip_tile_index: u16, + clip_tile_backdrop: i16, + tile_offset: Vector2I, + draw_tiling_path_info: &DrawTilingPathInfo) + -> TileVertex { + // TODO(pcwalton): Opacity. let tile_position = tile_origin + tile_offset; - let color_uv = draw_tiling_path_info.paint_metadata.calculate_tex_coords(tile_position); - let mask_uv = calculate_mask_uv(tile_index, tile_offset); - AlphaTileVertex { + 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_u: color_uv.x(), - color_v: color_uv.y(), - mask_u: mask_uv.x() as u16, - mask_v: mask_uv.y() as u16, - object_index, - opacity: draw_tiling_path_info.opacity, - pad: 0, + 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(), + mask_0_backdrop: draw_tile_backdrop, + mask_1_backdrop: clip_tile_backdrop, } } @@ -795,19 +881,16 @@ impl AlphaTileVertex { } } -fn calculate_mask_uv(tile_index: u16, tile_offset: Vector2I) -> Vector2I { +fn calculate_mask_uv(tile_index: u16, tile_offset: Vector2I) -> Vector2F { 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 mask_scale = 65535.0 / MASK_TILES_ACROSS as f32; - let mask_uv = Vector2I::new(mask_u, mask_v) + tile_offset; - mask_uv.to_f32().scale(mask_scale).to_i32() + let scale = Vector2F::new(1.0 / MASK_TILES_ACROSS as f32, 1.0 / MASK_TILES_DOWN as f32); + (Vector2I::new(mask_u, mask_v) + tile_offset).to_f32().scale_xy(scale) } -impl CulledTiles { - fn push_mask_tiles(&mut self, built_path: &BuiltPath) { - match built_path.fill_rule { - FillRule::Winding => self.mask_winding_tiles.extend_from_slice(&built_path.mask_tiles), - FillRule::EvenOdd => self.mask_evenodd_tiles.extend_from_slice(&built_path.mask_tiles), - } - } +fn calculate_opacity_uv(draw_tiling_path_info: &DrawTilingPathInfo) -> Vector2F { + let DrawTilingPathInfo { opacity_tile_transform, opacity, .. } = *draw_tiling_path_info; + let texel_coord = (Vector2I::new((opacity % 16) as i32, (opacity / 16) as i32).to_f32() + + Vector2F::splat(0.5)).scale(1.0 / 16.0); + opacity_tile_transform * texel_coord } diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index d4cded69..5d471179 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -10,29 +10,25 @@ use crate::gpu::debug::DebugUIPresenter; use crate::gpu::options::{DestFramebuffer, RendererOptions}; -use crate::gpu::shaders::{AlphaTileBlendModeProgram, AlphaTileDodgeBurnProgram}; -use crate::gpu::shaders::{AlphaTileHSLProgram, AlphaTileOverlayProgram}; -use crate::gpu::shaders::{AlphaTileProgram, AlphaTileVertexArray, BlitProgram, BlitVertexArray}; -use crate::gpu::shaders::{CopyTileProgram, CopyTileVertexArray, FillProgram, FillVertexArray}; -use crate::gpu::shaders::{MAX_FILLS_PER_BATCH, MaskTileProgram, MaskTileVertexArray}; -use crate::gpu::shaders::{ReprojectionProgram, ReprojectionVertexArray, SolidTileBlurFilterProgram, SolidTileProgram, SolidTileTextFilterProgram}; -use crate::gpu::shaders::{SolidTileVertexArray, StencilProgram, StencilVertexArray}; -use crate::gpu_data::{AlphaTile, FillBatchPrimitive, MaskTile, RenderCommand, SolidTile}; -use crate::gpu_data::{TextureLocation, TexturePageDescriptor, TexturePageId}; +use crate::gpu::shaders::{BlitProgram, BlitVertexArray, CopyTileProgram, CopyTileVertexArray}; +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::options::BoundingQuad; use crate::tiles::{TILE_HEIGHT, TILE_WIDTH}; use pathfinder_color::{self as color, ColorF, ColorU}; -use pathfinder_content::effects::{BlendMode, BlurDirection, CompositeOp, DefringingKernel}; -use pathfinder_content::effects::{Effects, Filter}; +use pathfinder_content::effects::{BlendMode, BlurDirection, DefringingKernel, Effects, Filter}; use pathfinder_content::fill::FillRule; use pathfinder_content::render_target::RenderTargetId; use pathfinder_geometry::rect::RectI; use pathfinder_geometry::transform3d::Transform4F; use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F}; -use pathfinder_gpu::{BlendFactor, BlendOp, BlendState, BufferData, BufferTarget, BufferUploadMode}; +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, TextureSamplingFlags, UniformData}; +use pathfinder_gpu::{TextureFormat, UniformData}; use pathfinder_resources::ResourceLoader; use pathfinder_simd::default::{F32x2, F32x4}; use std::cmp; @@ -58,13 +54,37 @@ const TEXTURE_CACHE_SIZE: usize = 8; const MASK_FRAMEBUFFER_WIDTH: i32 = TILE_WIDTH as i32 * MASK_TILES_ACROSS as i32; const MASK_FRAMEBUFFER_HEIGHT: i32 = TILE_HEIGHT as i32 * MASK_TILES_DOWN as i32; -const BLEND_TERM_DEST: i32 = 0; -const BLEND_TERM_SRC: i32 = 1; +const COMBINER_CTRL_MASK_WINDING: i32 = 0x1; +const COMBINER_CTRL_MASK_EVEN_ODD: i32 = 0x2; -const OVERLAY_BLEND_MODE_MULTIPLY: i32 = 0; -const OVERLAY_BLEND_MODE_SCREEN: i32 = 1; -const OVERLAY_BLEND_MODE_HARD_LIGHT: i32 = 2; -const OVERLAY_BLEND_MODE_OVERLAY: i32 = 3; +const COMBINER_CTRL_COLOR_ENABLE_MASK: i32 = 0x1; + +const COMBINER_CTRL_FILTER_TEXT: i32 = 0x2; +const COMBINER_CTRL_FILTER_BLUR: i32 = 0x3; + +const COMBINER_CTRL_COMPOSITE_NORMAL: i32 = 0x0; +const COMBINER_CTRL_COMPOSITE_MULTIPLY: i32 = 0x1; +const COMBINER_CTRL_COMPOSITE_SCREEN: i32 = 0x2; +const COMBINER_CTRL_COMPOSITE_OVERLAY: i32 = 0x3; +const COMBINER_CTRL_COMPOSITE_DARKEN: i32 = 0x4; +const COMBINER_CTRL_COMPOSITE_LIGHTEN: i32 = 0x5; +const COMBINER_CTRL_COMPOSITE_COLOR_DODGE: i32 = 0x6; +const COMBINER_CTRL_COMPOSITE_COLOR_BURN: i32 = 0x7; +const COMBINER_CTRL_COMPOSITE_HARD_LIGHT: i32 = 0x8; +const COMBINER_CTRL_COMPOSITE_SOFT_LIGHT: i32 = 0x9; +const COMBINER_CTRL_COMPOSITE_DIFFERENCE: i32 = 0xa; +const COMBINER_CTRL_COMPOSITE_EXCLUSION: i32 = 0xb; +const COMBINER_CTRL_COMPOSITE_HUE: i32 = 0xc; +const COMBINER_CTRL_COMPOSITE_SATURATION: i32 = 0xd; +const COMBINER_CTRL_COMPOSITE_COLOR: i32 = 0xe; +const COMBINER_CTRL_COMPOSITE_LUMINOSITY: i32 = 0xf; + +const COMBINER_CTRL_MASK_0_SHIFT: i32 = 0; +const COMBINER_CTRL_MASK_1_SHIFT: i32 = 2; +const COMBINER_CTRL_COLOR_0_FILTER_SHIFT: i32 = 4; +const COMBINER_CTRL_COLOR_0_ENABLE_SHIFT: i32 = 6; +const COMBINER_CTRL_COLOR_1_ENABLE_SHIFT: i32 = 7; +const COMBINER_CTRL_COMPOSITE_SHIFT: i32 = 8; pub struct Renderer where @@ -78,55 +98,25 @@ where options: RendererOptions, blit_program: BlitProgram, fill_program: FillProgram, - mask_winding_tile_program: MaskTileProgram, - mask_evenodd_tile_program: MaskTileProgram, - copy_tile_program: CopyTileProgram, - alpha_tile_program: AlphaTileProgram, - alpha_tile_overlay_program: AlphaTileOverlayProgram, - alpha_tile_dodgeburn_program: AlphaTileDodgeBurnProgram, - alpha_tile_softlight_program: AlphaTileBlendModeProgram, - alpha_tile_difference_program: AlphaTileBlendModeProgram, - alpha_tile_exclusion_program: AlphaTileBlendModeProgram, - alpha_tile_hsl_program: AlphaTileHSLProgram, + tile_program: TileProgram, + tile_copy_program: CopyTileProgram, blit_vertex_array: BlitVertexArray, - mask_winding_tile_vertex_array: MaskTileVertexArray, - mask_evenodd_tile_vertex_array: MaskTileVertexArray, - copy_tile_vertex_array: CopyTileVertexArray, - alpha_tile_vertex_array: AlphaTileVertexArray, - alpha_tile_overlay_vertex_array: AlphaTileVertexArray, - alpha_tile_dodgeburn_vertex_array: AlphaTileVertexArray, - alpha_tile_softlight_vertex_array: AlphaTileVertexArray, - alpha_tile_difference_vertex_array: AlphaTileVertexArray, - alpha_tile_exclusion_vertex_array: AlphaTileVertexArray, - alpha_tile_hsl_vertex_array: AlphaTileVertexArray, + tile_vertex_array: TileVertexArray, + tile_copy_vertex_array: CopyTileVertexArray, area_lut_texture: D::Texture, - alpha_tile_vertex_buffer: D::Buffer, + tile_vertex_buffer: D::Buffer, quad_vertex_positions_buffer: D::Buffer, quad_vertex_indices_buffer: D::Buffer, quads_vertex_indices_buffer: D::Buffer, quads_vertex_indices_length: usize, fill_vertex_array: FillVertexArray, fill_framebuffer: D::Framebuffer, - mask_framebuffer: D::Framebuffer, dest_blend_framebuffer: D::Framebuffer, intermediate_dest_framebuffer: D::Framebuffer, texture_pages: Vec>, render_targets: Vec, render_target_stack: Vec, - // This is a dummy texture consisting solely of a single `rgba(0, 0, 0, 255)` texel. It serves - // as the paint texture when drawing alpha tiles with the Clear blend mode. If this weren't - // used, then the transparent black paint would zero out the alpha mask. - clear_paint_texture: D::Texture, - - // Solid tiles - solid_tile_program: SolidTileProgram, - solid_tile_blur_filter_program: SolidTileBlurFilterProgram, - solid_tile_text_filter_program: SolidTileTextFilterProgram, - solid_tile_vertex_array: SolidTileVertexArray, - solid_tile_blur_filter_vertex_array: SolidTileVertexArray, - solid_tile_text_filter_vertex_array: SolidTileVertexArray, - solid_tile_vertex_buffer: D::Buffer, gamma_lut_texture: D::Texture, // Stencil shader @@ -164,36 +154,14 @@ where -> Renderer { let blit_program = BlitProgram::new(&device, resources); let fill_program = FillProgram::new(&device, resources); - let mask_winding_tile_program = MaskTileProgram::new(FillRule::Winding, - &device, - resources); - let mask_evenodd_tile_program = MaskTileProgram::new(FillRule::EvenOdd, - &device, - resources); - let copy_tile_program = CopyTileProgram::new(&device, resources); - let solid_tile_program = SolidTileProgram::new(&device, resources, "tile_solid"); - let alpha_tile_program = AlphaTileProgram::new(&device, resources); - let alpha_tile_overlay_program = AlphaTileOverlayProgram::new(&device, resources); - let alpha_tile_dodgeburn_program = AlphaTileDodgeBurnProgram::new(&device, resources); - let alpha_tile_softlight_program = AlphaTileBlendModeProgram::new(&device, - resources, - "tile_alpha_softlight"); - let alpha_tile_difference_program = - AlphaTileBlendModeProgram::new(&device, resources, "tile_alpha_difference"); - let alpha_tile_exclusion_program = AlphaTileBlendModeProgram::new(&device, - resources, - "tile_alpha_exclusion"); - let alpha_tile_hsl_program = AlphaTileHSLProgram::new(&device, resources); - let solid_tile_blur_filter_program = SolidTileBlurFilterProgram::new(&device, resources); - let solid_tile_text_filter_program = SolidTileTextFilterProgram::new(&device, resources); + let tile_program = TileProgram::new(&device, resources); + let tile_copy_program = CopyTileProgram::new(&device, resources); let stencil_program = StencilProgram::new(&device, resources); let reprojection_program = ReprojectionProgram::new(&device, resources); 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 alpha_tile_vertex_buffer = device.create_buffer(); - let solid_tile_vertex_buffer = device.create_buffer(); let quad_vertex_positions_buffer = device.create_buffer(); device.allocate_buffer( &quad_vertex_positions_buffer, @@ -209,6 +177,7 @@ where BufferUploadMode::Static, ); let quads_vertex_indices_buffer = device.create_buffer(); + let tile_vertex_buffer = device.create_buffer(); let blit_vertex_array = BlitVertexArray::new( &device, @@ -222,80 +191,16 @@ where &quad_vertex_positions_buffer, &quad_vertex_indices_buffer, ); - let mask_winding_tile_vertex_array = MaskTileVertexArray::new( + let tile_vertex_array = TileVertexArray::new( &device, - &mask_winding_tile_program, + &tile_program, + &tile_vertex_buffer, &quads_vertex_indices_buffer, ); - let mask_evenodd_tile_vertex_array = MaskTileVertexArray::new( + let tile_copy_vertex_array = CopyTileVertexArray::new( &device, - &mask_evenodd_tile_program, - &quads_vertex_indices_buffer, - ); - let copy_tile_vertex_array = CopyTileVertexArray::new( - &device, - ©_tile_program, - &alpha_tile_vertex_buffer, - &quads_vertex_indices_buffer, - ); - let alpha_tile_vertex_array = AlphaTileVertexArray::new( - &device, - &alpha_tile_program, - &alpha_tile_vertex_buffer, - &quads_vertex_indices_buffer, - ); - let alpha_tile_overlay_vertex_array = AlphaTileVertexArray::new( - &device, - &alpha_tile_overlay_program.alpha_tile_blend_mode_program.alpha_tile_program, - &alpha_tile_vertex_buffer, - &quads_vertex_indices_buffer, - ); - let alpha_tile_dodgeburn_vertex_array = AlphaTileVertexArray::new( - &device, - &alpha_tile_dodgeburn_program.alpha_tile_blend_mode_program.alpha_tile_program, - &alpha_tile_vertex_buffer, - &quads_vertex_indices_buffer, - ); - let alpha_tile_softlight_vertex_array = AlphaTileVertexArray::new( - &device, - &alpha_tile_softlight_program.alpha_tile_program, - &alpha_tile_vertex_buffer, - &quads_vertex_indices_buffer, - ); - let alpha_tile_difference_vertex_array = AlphaTileVertexArray::new( - &device, - &alpha_tile_difference_program.alpha_tile_program, - &alpha_tile_vertex_buffer, - &quads_vertex_indices_buffer, - ); - let alpha_tile_exclusion_vertex_array = AlphaTileVertexArray::new( - &device, - &alpha_tile_exclusion_program.alpha_tile_program, - &alpha_tile_vertex_buffer, - &quads_vertex_indices_buffer, - ); - let alpha_tile_hsl_vertex_array = AlphaTileVertexArray::new( - &device, - &alpha_tile_hsl_program.alpha_tile_blend_mode_program.alpha_tile_program, - &alpha_tile_vertex_buffer, - &quads_vertex_indices_buffer, - ); - let solid_tile_vertex_array = SolidTileVertexArray::new( - &device, - &solid_tile_program, - &solid_tile_vertex_buffer, - &quads_vertex_indices_buffer, - ); - let solid_tile_blur_filter_vertex_array = SolidTileVertexArray::new( - &device, - &solid_tile_blur_filter_program.solid_tile_program, - &solid_tile_vertex_buffer, - &quads_vertex_indices_buffer, - ); - let solid_tile_text_filter_vertex_array = SolidTileVertexArray::new( - &device, - &solid_tile_text_filter_program.solid_tile_program, - &solid_tile_vertex_buffer, + &tile_copy_program, + &tile_vertex_buffer, &quads_vertex_indices_buffer, ); let stencil_vertex_array = StencilVertexArray::new(&device, &stencil_program); @@ -312,23 +217,12 @@ where device.create_texture(TextureFormat::R16F, fill_framebuffer_size); let fill_framebuffer = device.create_framebuffer(fill_framebuffer_texture); - let mask_framebuffer_size = - Vector2I::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT); - let mask_framebuffer_texture = - device.create_texture(TextureFormat::R8, mask_framebuffer_size); - let mask_framebuffer = device.create_framebuffer(mask_framebuffer_texture); - let window_size = dest_framebuffer.window_size(&device); let dest_blend_texture = device.create_texture(TextureFormat::RGBA8, window_size); let dest_blend_framebuffer = device.create_framebuffer(dest_blend_texture); let intermediate_dest_texture = device.create_texture(TextureFormat::RGBA8, window_size); let intermediate_dest_framebuffer = device.create_framebuffer(intermediate_dest_texture); - let clear_paint_texture = - device.create_texture_from_data(TextureFormat::RGBA8, - Vector2I::splat(1), - TextureDataRef::U8(&[0, 0, 0, 255])); - let debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size); Renderer { @@ -338,50 +232,25 @@ where options, blit_program, fill_program, - mask_winding_tile_program, - mask_evenodd_tile_program, - copy_tile_program, - solid_tile_program, - alpha_tile_program, - alpha_tile_overlay_program, - alpha_tile_dodgeburn_program, - alpha_tile_softlight_program, - alpha_tile_difference_program, - alpha_tile_exclusion_program, - alpha_tile_hsl_program, + tile_program, + tile_copy_program, blit_vertex_array, - mask_winding_tile_vertex_array, - mask_evenodd_tile_vertex_array, - copy_tile_vertex_array, - alpha_tile_vertex_array, - alpha_tile_overlay_vertex_array, - alpha_tile_dodgeburn_vertex_array, - alpha_tile_softlight_vertex_array, - alpha_tile_difference_vertex_array, - alpha_tile_exclusion_vertex_array, - alpha_tile_hsl_vertex_array, + tile_vertex_array, + tile_copy_vertex_array, area_lut_texture, - alpha_tile_vertex_buffer, + tile_vertex_buffer, quad_vertex_positions_buffer, quad_vertex_indices_buffer, quads_vertex_indices_buffer, quads_vertex_indices_length: 0, fill_vertex_array, fill_framebuffer, - mask_framebuffer, dest_blend_framebuffer, intermediate_dest_framebuffer, texture_pages: vec![], render_targets: vec![], render_target_stack: vec![], - clear_paint_texture, - solid_tile_vertex_array, - solid_tile_blur_filter_program, - solid_tile_blur_filter_vertex_array, - solid_tile_text_filter_program, - solid_tile_text_filter_vertex_array, - solid_tile_vertex_buffer, gamma_lut_texture, stencil_program, @@ -429,32 +298,21 @@ where self.draw_buffered_fills(); self.begin_composite_timer_query(); } - RenderCommand::RenderMaskTiles { tiles: ref mask_tiles, fill_rule } => { - let count = mask_tiles.len(); - self.upload_mask_tiles(mask_tiles, fill_rule); - self.draw_mask_tiles(count as u32, fill_rule); - } RenderCommand::PushRenderTarget(render_target_id) => { self.push_render_target(render_target_id) } RenderCommand::PopRenderTarget => self.pop_render_target(), - RenderCommand::DrawSolidTiles(ref batch) => { - let count = batch.tiles.len(); - self.stats.solid_tile_count += count; - self.upload_solid_tiles(&batch.tiles); - self.draw_solid_tiles(count as u32, - batch.color_texture_page, - batch.sampling_flags, - batch.effects); - } - RenderCommand::DrawAlphaTiles(ref batch) => { + RenderCommand::DrawTiles(ref batch) => { let count = batch.tiles.len(); self.stats.alpha_tile_count += count; - self.upload_alpha_tiles(&batch.tiles); - self.draw_alpha_tiles(count as u32, - batch.color_texture_page, - batch.sampling_flags, - batch.blend_mode) + self.upload_tiles(&batch.tiles); + self.draw_tiles(count as u32, + batch.color_texture_0, + batch.color_texture_1, + batch.mask_0_fill_rule, + batch.mask_1_fill_rule, + batch.blend_mode, + batch.effects) } RenderCommand::Finish { .. } => {} } @@ -604,37 +462,12 @@ where render_target.location = location; } - fn upload_mask_tiles(&mut self, mask_tiles: &[MaskTile], fill_rule: FillRule) { - let vertex_array = match fill_rule { - FillRule::Winding => &self.mask_winding_tile_vertex_array, - FillRule::EvenOdd => &self.mask_evenodd_tile_vertex_array, - }; - - self.device.allocate_buffer( - &vertex_array.vertex_buffer, - BufferData::Memory(&mask_tiles), - BufferTarget::Vertex, - BufferUploadMode::Dynamic, - ); - self.ensure_index_buffer(mask_tiles.len()); - } - - fn upload_solid_tiles(&mut self, solid_tiles: &[SolidTile]) { - self.device.allocate_buffer( - &self.solid_tile_vertex_buffer, - BufferData::Memory(&solid_tiles), - BufferTarget::Vertex, - BufferUploadMode::Dynamic, - ); - self.ensure_index_buffer(solid_tiles.len()); - } - - fn upload_alpha_tiles(&mut self, alpha_tiles: &[AlphaTile]) { - self.device.allocate_buffer(&self.alpha_tile_vertex_buffer, - BufferData::Memory(&alpha_tiles), + fn upload_tiles(&mut self, tiles: &[Tile]) { + self.device.allocate_buffer(&self.tile_vertex_buffer, + BufferData::Memory(&tiles), BufferTarget::Vertex, BufferUploadMode::Dynamic); - self.ensure_index_buffer(alpha_tiles.len()); + self.ensure_index_buffer(tiles.len()); } fn ensure_index_buffer(&mut self, mut length: usize) { @@ -742,155 +575,111 @@ where Transform4F::from_scale(scale).translate(Vector4F::new(-1.0, 1.0, 0.0, 1.0)) } - fn draw_mask_tiles(&mut self, tile_count: u32, fill_rule: FillRule) { - let clear_color = - if self.framebuffer_flags - .contains(FramebufferFlags::MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS) { - None - } else { - Some(ColorF::new(1.0, 1.0, 1.0, 1.0)) - }; + fn draw_tiles(&mut self, + tile_count: u32, + color_texture_0: Option, + color_texture_1: Option, + mask_0_fill_rule: Option, + mask_1_fill_rule: Option, + blend_mode: BlendMode, + effects: Effects) { + // TODO(pcwalton): Disable blend for solid tiles. - let (mask_tile_program, mask_tile_vertex_array) = match fill_rule { - FillRule::Winding => { - (&self.mask_winding_tile_program, &self.mask_winding_tile_vertex_array) - } - FillRule::EvenOdd => { - (&self.mask_evenodd_tile_program, &self.mask_evenodd_tile_vertex_array) - } - }; - - self.device.draw_elements(tile_count * 6, &RenderState { - target: &RenderTarget::Framebuffer(&self.mask_framebuffer), - program: &mask_tile_program.program, - vertex_array: &mask_tile_vertex_array.vertex_array, - primitive: Primitive::Triangles, - textures: &[self.device.framebuffer_texture(&self.fill_framebuffer)], - uniforms: &[ - (&self.mask_winding_tile_program.fill_texture_uniform, - UniformData::TextureUnit(0)), - ], - viewport: self.mask_viewport(), - options: RenderOptions { - blend: Some(BlendState { - src_rgb_factor: BlendFactor::One, - src_alpha_factor: BlendFactor::One, - dest_rgb_factor: BlendFactor::One, - dest_alpha_factor: BlendFactor::One, - op: BlendOp::Min, - ..BlendState::default() - }), - clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, - ..RenderOptions::default() - }, - }); - - self.framebuffer_flags.insert(FramebufferFlags::MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS); - } - - fn draw_alpha_tiles(&mut self, - tile_count: u32, - color_texture_page: TexturePageId, - sampling_flags: TextureSamplingFlags, - blend_mode: BlendMode) { - let blend_mode_program = BlendModeProgram::from_blend_mode(blend_mode); - if blend_mode_program.needs_readable_framebuffer() { + let needs_readable_framebuffer = blend_mode.needs_readable_framebuffer(); + if needs_readable_framebuffer { self.copy_alpha_tiles_to_dest_blend_texture(tile_count); } let clear_color = self.clear_color_for_draw_operation(); - - let (alpha_tile_program, alpha_tile_vertex_array) = match blend_mode_program { - BlendModeProgram::Regular => (&self.alpha_tile_program, &self.alpha_tile_vertex_array), - BlendModeProgram::Overlay => { - (&self.alpha_tile_overlay_program.alpha_tile_blend_mode_program.alpha_tile_program, - &self.alpha_tile_overlay_vertex_array) - } - BlendModeProgram::DodgeBurn => { - (&self.alpha_tile_dodgeburn_program - .alpha_tile_blend_mode_program - .alpha_tile_program, - &self.alpha_tile_dodgeburn_vertex_array) - } - BlendModeProgram::SoftLight => { - (&self.alpha_tile_softlight_program.alpha_tile_program, - &self.alpha_tile_softlight_vertex_array) - } - BlendModeProgram::Difference => { - (&self.alpha_tile_difference_program.alpha_tile_program, - &self.alpha_tile_difference_vertex_array) - } - BlendModeProgram::Exclusion => { - (&self.alpha_tile_exclusion_program.alpha_tile_program, - &self.alpha_tile_exclusion_vertex_array) - } - BlendModeProgram::HSL => { - (&self.alpha_tile_hsl_program.alpha_tile_blend_mode_program.alpha_tile_program, - &self.alpha_tile_hsl_vertex_array) - } - }; - let draw_viewport = self.draw_viewport(); - let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)]; - let mut uniforms = vec![ - (&alpha_tile_program.transform_uniform, - UniformData::Mat4(self.tile_transform().to_columns())), - (&alpha_tile_program.tile_size_uniform, - UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))), - (&alpha_tile_program.stencil_texture_uniform, UniformData::TextureUnit(0)), - (&alpha_tile_program.framebuffer_size_uniform, - UniformData::Vec2(draw_viewport.size().to_f32().0)), - ]; - - let paint_texture = match blend_mode { - BlendMode::Clear => { - // Use a special dummy paint texture containing `rgba(0, 0, 0, 255)` so that the - // transparent black paint color doesn't zero out the mask. - &self.clear_paint_texture - } - _ => self.texture_page(color_texture_page), - }; - - self.device.set_texture_sampling_mode(paint_texture, sampling_flags); - - textures.push(paint_texture); - uniforms.push((&alpha_tile_program.paint_texture_uniform, UniformData::TextureUnit(1))); - - match blend_mode_program { - BlendModeProgram::Regular => {} - BlendModeProgram::Overlay => { - self.set_uniforms_for_overlay_blend_mode(&mut textures, &mut uniforms, blend_mode); - } - BlendModeProgram::DodgeBurn => { - self.set_uniforms_for_dodge_burn_blend_mode(&mut textures, - &mut uniforms, - blend_mode); - } - BlendModeProgram::SoftLight => { - self.set_uniforms_for_blend_mode(&mut textures, - &mut uniforms, - &self.alpha_tile_softlight_program); - } - BlendModeProgram::Difference => { - self.set_uniforms_for_blend_mode(&mut textures, - &mut uniforms, - &self.alpha_tile_difference_program); - } - BlendModeProgram::Exclusion => { - self.set_uniforms_for_blend_mode(&mut textures, - &mut uniforms, - &self.alpha_tile_exclusion_program); - } - BlendModeProgram::HSL => { - self.set_uniforms_for_hsl_blend_mode(&mut textures, &mut uniforms, blend_mode); + let mut ctrl = 0; + for &(fill_rule, shift) in &[ + (mask_0_fill_rule, COMBINER_CTRL_MASK_0_SHIFT), + (mask_1_fill_rule, COMBINER_CTRL_MASK_1_SHIFT), + ] { + match fill_rule { + None => {} + Some(FillRule::Winding) => ctrl |= COMBINER_CTRL_MASK_WINDING << shift, + Some(FillRule::EvenOdd) => ctrl |= COMBINER_CTRL_MASK_EVEN_ODD << shift, } } + let mut textures = vec![]; + let mut uniforms = vec![ + (&self.tile_program.transform_uniform, + UniformData::Mat4(self.tile_transform().to_columns())), + (&self.tile_program.tile_size_uniform, + UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))), + ]; + + if needs_readable_framebuffer { + uniforms.push((&self.tile_program.dest_texture_uniform, + UniformData::TextureUnit(textures.len() as u32))); + uniforms.push((&self.tile_program.dest_texture_size_uniform, + UniformData::Vec2(draw_viewport.size().to_f32().0))); + textures.push(self.device.framebuffer_texture(&self.dest_blend_framebuffer)); + } + + if mask_0_fill_rule.is_some() { + uniforms.push((&self.tile_program.mask_texture_0_uniform, + UniformData::TextureUnit(textures.len() as u32))); + textures.push(self.device.framebuffer_texture(&self.fill_framebuffer)); + } + if mask_1_fill_rule.is_some() { + uniforms.push((&self.tile_program.mask_texture_1_uniform, + UniformData::TextureUnit(textures.len() as u32))); + textures.push(self.device.framebuffer_texture(&self.fill_framebuffer)); + } + + // TODO(pcwalton): Refactor. + if let Some(color_texture) = color_texture_0 { + let color_texture_page = self.texture_page(color_texture.page); + let color_texture_size = self.device.texture_size(color_texture_page).to_f32(); + self.device.set_texture_sampling_mode(color_texture_page, + color_texture.sampling_flags); + uniforms.push((&self.tile_program.color_texture_0_uniform, + UniformData::TextureUnit(textures.len() as u32))); + uniforms.push((&self.tile_program.color_texture_0_size_uniform, + UniformData::Vec2(color_texture_size.0))); + textures.push(color_texture_page); + ctrl |= COMBINER_CTRL_COLOR_ENABLE_MASK << COMBINER_CTRL_COLOR_0_ENABLE_SHIFT; + } + if let Some(color_texture) = color_texture_1 { + let color_texture_page = self.texture_page(color_texture.page); + self.device.set_texture_sampling_mode(color_texture_page, + color_texture.sampling_flags); + uniforms.push((&self.tile_program.color_texture_1_uniform, + UniformData::TextureUnit(textures.len() as u32))); + textures.push(color_texture_page); + ctrl |= COMBINER_CTRL_COLOR_ENABLE_MASK << COMBINER_CTRL_COLOR_1_ENABLE_SHIFT; + } + + ctrl |= blend_mode.to_composite_ctrl() << COMBINER_CTRL_COMPOSITE_SHIFT; + + match effects.filter { + Filter::None => {} + Filter::Text { fg_color, bg_color, defringing_kernel, gamma_correction } => { + ctrl |= COMBINER_CTRL_FILTER_TEXT << COMBINER_CTRL_COLOR_0_FILTER_SHIFT; + self.set_uniforms_for_text_filter(&mut textures, + &mut uniforms, + fg_color, + bg_color, + defringing_kernel, + gamma_correction); + } + Filter::Blur { direction, sigma } => { + ctrl |= COMBINER_CTRL_FILTER_BLUR << COMBINER_CTRL_COLOR_0_FILTER_SHIFT; + self.set_uniforms_for_blur_filter(&mut uniforms, direction, sigma); + } + } + + uniforms.push((&self.tile_program.ctrl_uniform, UniformData::Int(ctrl))); + self.device.draw_elements(tile_count * 6, &RenderState { target: &self.draw_render_target(), - program: &alpha_tile_program.program, - vertex_array: &alpha_tile_vertex_array.vertex_array, + program: &self.tile_program.program, + vertex_array: &self.tile_vertex_array.vertex_array, primitive: Primitive::Triangles, textures: &textures, uniforms: &uniforms, @@ -906,83 +695,15 @@ where self.preserve_draw_framebuffer(); } - fn set_uniforms_for_blend_mode<'a>( - &'a self, - textures: &mut Vec<&'a D::Texture>, - uniforms: &mut Vec<(&'a D::Uniform, UniformData)>, - alpha_tile_blend_mode_program: &'a AlphaTileBlendModeProgram) { - textures.push(self.device.framebuffer_texture(&self.dest_blend_framebuffer)); - uniforms.push((&alpha_tile_blend_mode_program.dest_uniform, - UniformData::TextureUnit(textures.len() as u32 - 1))); - } - - fn set_uniforms_for_overlay_blend_mode<'a>(&'a self, - textures: &mut Vec<&'a D::Texture>, - uniforms: &mut Vec<(&'a D::Uniform, UniformData)>, - blend_mode: BlendMode) { - let overlay_blend_mode = match blend_mode { - BlendMode::Multiply => OVERLAY_BLEND_MODE_MULTIPLY, - BlendMode::Screen => OVERLAY_BLEND_MODE_SCREEN, - BlendMode::HardLight => OVERLAY_BLEND_MODE_HARD_LIGHT, - BlendMode::Overlay => OVERLAY_BLEND_MODE_OVERLAY, - _ => unreachable!(), - }; - - uniforms.push((&self.alpha_tile_overlay_program.blend_mode_uniform, - UniformData::Int(overlay_blend_mode))); - - self.set_uniforms_for_blend_mode(textures, - uniforms, - &self.alpha_tile_overlay_program - .alpha_tile_blend_mode_program); - } - - fn set_uniforms_for_dodge_burn_blend_mode<'a>( - &'a self, - textures: &mut Vec<&'a D::Texture>, - uniforms: &mut Vec<(&'a D::Uniform, UniformData)>, - blend_mode: BlendMode) { - uniforms.push((&self.alpha_tile_dodgeburn_program.burn_uniform, - UniformData::Int(if blend_mode == BlendMode::ColorBurn { 1 } else { 0 }))); - - self.set_uniforms_for_blend_mode(textures, - uniforms, - &self.alpha_tile_dodgeburn_program - .alpha_tile_blend_mode_program); - } - - fn set_uniforms_for_hsl_blend_mode<'a>(&'a self, - textures: &mut Vec<&'a D::Texture>, - uniforms: &mut Vec<(&'a D::Uniform, UniformData)>, - blend_mode: BlendMode) { - let hsl_terms = match blend_mode { - BlendMode::Hue => [BLEND_TERM_SRC, BLEND_TERM_DEST, BLEND_TERM_DEST], - BlendMode::Saturation => [BLEND_TERM_DEST, BLEND_TERM_SRC, BLEND_TERM_DEST], - BlendMode::Luminosity => [BLEND_TERM_DEST, BLEND_TERM_DEST, BLEND_TERM_SRC ], - BlendMode::Color => [BLEND_TERM_SRC, BLEND_TERM_SRC, BLEND_TERM_DEST], - _ => unreachable!(), - }; - - uniforms.push((&self.alpha_tile_hsl_program.blend_hsl_uniform, - UniformData::IVec3(hsl_terms))); - - self.set_uniforms_for_blend_mode(textures, - uniforms, - &self.alpha_tile_hsl_program - .alpha_tile_blend_mode_program); - } - fn copy_alpha_tiles_to_dest_blend_texture(&mut self, tile_count: u32) { let draw_viewport = self.draw_viewport(); let mut textures = vec![]; let mut uniforms = vec![ - (&self.copy_tile_program.transform_uniform, + (&self.tile_copy_program.transform_uniform, UniformData::Mat4(self.tile_transform().to_columns())), - (&self.copy_tile_program.tile_size_uniform, + (&self.tile_copy_program.tile_size_uniform, UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))), - (&self.copy_tile_program.framebuffer_size_uniform, - UniformData::Vec2(draw_viewport.size().to_f32().0)), ]; let draw_framebuffer = match self.draw_render_target() { @@ -991,20 +712,23 @@ where }; let draw_texture = self.device.framebuffer_texture(&draw_framebuffer); + uniforms.push((&self.tile_copy_program.src_uniform, + UniformData::TextureUnit(textures.len() as u32))); textures.push(draw_texture); - uniforms.push((&self.copy_tile_program.src_uniform, UniformData::TextureUnit(0))); + uniforms.push((&self.tile_copy_program.framebuffer_size_uniform, + UniformData::Vec2(draw_viewport.size().to_f32().0))); self.device.draw_elements(tile_count * 6, &RenderState { target: &RenderTarget::Framebuffer(&self.dest_blend_framebuffer), - program: &self.copy_tile_program.program, - vertex_array: &self.copy_tile_vertex_array.vertex_array, + program: &self.tile_copy_program.program, + vertex_array: &self.tile_copy_vertex_array.vertex_array, primitive: Primitive::Triangles, textures: &textures, uniforms: &uniforms, viewport: draw_viewport, options: RenderOptions { clear_ops: ClearOps { - color: Some(ColorF::transparent_black()), + color: Some(ColorF::new(1.0, 0.0, 0.0, 1.0)), ..ClearOps::default() }, ..RenderOptions::default() @@ -1012,80 +736,6 @@ where }); } - fn draw_solid_tiles(&mut self, - tile_count: u32, - color_texture_page: TexturePageId, - sampling_flags: TextureSamplingFlags, - effects: Effects) { - let clear_color = self.clear_color_for_draw_operation(); - - let (solid_tile_program, solid_tile_vertex_array) = match effects.filter { - Filter::Composite(_) => { - (&self.solid_tile_program, &self.solid_tile_vertex_array) - } - Filter::Text { .. } => { - (&self.solid_tile_text_filter_program.solid_tile_program, - &self.solid_tile_text_filter_vertex_array) - } - Filter::Blur { .. } => { - (&self.solid_tile_blur_filter_program.solid_tile_program, - &self.solid_tile_blur_filter_vertex_array) - } - }; - - let mut textures = vec![]; - let mut uniforms = vec![ - (&solid_tile_program.transform_uniform, - UniformData::Mat4(self.tile_transform().to_columns())), - (&solid_tile_program.tile_size_uniform, - UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))), - ]; - - let texture_page = self.texture_page(color_texture_page); - let texture_size = self.device.texture_size(texture_page); - self.device.set_texture_sampling_mode(texture_page, sampling_flags); - textures.push(texture_page); - uniforms.push((&solid_tile_program.color_texture_uniform, UniformData::TextureUnit(0))); - - let blend_state = match effects.filter { - Filter::Composite(composite_op) => composite_op.to_blend_state(), - Filter::Blur { .. } | Filter::Text { .. } => CompositeOp::SrcOver.to_blend_state(), - }; - - match effects.filter { - Filter::Composite(_) => {} - Filter::Text { fg_color, bg_color, defringing_kernel, gamma_correction } => { - self.set_uniforms_for_text_filter(&mut textures, - &mut uniforms, - fg_color, - bg_color, - defringing_kernel, - gamma_correction); - } - Filter::Blur { direction, sigma } => { - self.set_uniforms_for_blur_filter(&mut uniforms, texture_size, direction, sigma); - } - } - - self.device.draw_elements(6 * tile_count, &RenderState { - target: &self.draw_render_target(), - program: &solid_tile_program.program, - vertex_array: &solid_tile_vertex_array.vertex_array, - primitive: Primitive::Triangles, - textures: &textures, - uniforms: &uniforms, - viewport: self.draw_viewport(), - options: RenderOptions { - blend: blend_state, - stencil: self.stencil_state(), - clear_ops: ClearOps { color: clear_color, ..ClearOps::default() }, - ..RenderOptions::default() - }, - }); - - self.preserve_draw_framebuffer(); - } - fn draw_stencil(&mut self, quad_positions: &[Vector4F]) { self.device.allocate_buffer( &self.stencil_vertex_array.vertex_buffer, @@ -1204,30 +854,31 @@ where let gamma_lut_texture_unit = textures.len() as u32; textures.push(&self.gamma_lut_texture); - uniforms.extend_from_slice(&[ - (&self.solid_tile_text_filter_program.gamma_lut_uniform, - UniformData::TextureUnit(gamma_lut_texture_unit)), - (&self.solid_tile_text_filter_program.fg_color_uniform, UniformData::Vec4(fg_color.0)), - (&self.solid_tile_text_filter_program.bg_color_uniform, UniformData::Vec4(bg_color.0)), - (&self.solid_tile_text_filter_program.gamma_correction_enabled_uniform, - UniformData::Int(gamma_correction as i32)), - ]); - match defringing_kernel { Some(ref kernel) => { - uniforms.push((&self.solid_tile_text_filter_program.kernel_uniform, + uniforms.push((&self.tile_program.filter_params_0_uniform, UniformData::Vec4(F32x4::from_slice(&kernel.0)))); } None => { - uniforms.push((&self.solid_tile_text_filter_program.kernel_uniform, + uniforms.push((&self.tile_program.filter_params_0_uniform, UniformData::Vec4(F32x4::default()))); } } + + let mut params_2 = fg_color.0; + params_2.set_w(gamma_correction as i32 as f32); + + uniforms.extend_from_slice(&[ + (&self.tile_program.gamma_lut_uniform, + UniformData::TextureUnit(gamma_lut_texture_unit)), + (&self.tile_program.filter_params_1_uniform, UniformData::Vec4(bg_color.0)), + (&self.tile_program.filter_params_2_uniform, UniformData::Vec4(params_2)), + ]); + } fn set_uniforms_for_blur_filter<'a>(&'a self, uniforms: &mut Vec<(&'a D::Uniform, UniformData)>, - src_texture_size: Vector2I, direction: BlurDirection, sigma: f32) { let sigma_inv = 1.0 / sigma; @@ -1239,15 +890,14 @@ where BlurDirection::X => Vector2F::new(1.0, 0.0), BlurDirection::Y => Vector2F::new(0.0, 1.0), }; - let src_offset_scale = src_offset / src_texture_size.to_f32(); + + let support = f32::ceil(1.5 * sigma) * 2.0; uniforms.extend_from_slice(&[ - (&self.solid_tile_blur_filter_program.src_offset_scale_uniform, - UniformData::Vec2(src_offset_scale.0)), - (&self.solid_tile_blur_filter_program.initial_gauss_coeff_uniform, - UniformData::Vec3([gauss_coeff_x, gauss_coeff_y, gauss_coeff_z])), - (&self.solid_tile_blur_filter_program.support_uniform, - UniformData::Int(f32::ceil(1.5 * sigma) as i32 * 2)), + (&self.tile_program.filter_params_0_uniform, + UniformData::Vec4(src_offset.0.concat_xy_xy(F32x2::new(support, 0.0)))), + (&self.tile_program.filter_params_1_uniform, + UniformData::Vec4(F32x4::new(gauss_coeff_x, gauss_coeff_y, gauss_coeff_z, 0.0))), ]); } @@ -1269,7 +919,13 @@ where textures: &textures[..], uniforms: &uniforms[..], viewport: main_viewport, - options: RenderOptions::default(), + options: RenderOptions { + clear_ops: ClearOps { + color: Some(ColorF::new(0.0, 0.0, 0.0, 1.0)), + ..ClearOps::default() + }, + ..RenderOptions::default() + }, }); } @@ -1503,9 +1159,9 @@ impl ToBlendState for BlendMode { BlendMode::Clear => { Some(BlendState { src_rgb_factor: BlendFactor::Zero, - dest_rgb_factor: BlendFactor::OneMinusSrcAlpha, + dest_rgb_factor: BlendFactor::Zero, src_alpha_factor: BlendFactor::Zero, - dest_alpha_factor: BlendFactor::OneMinusSrcAlpha, + dest_alpha_factor: BlendFactor::Zero, ..BlendState::default() }) } @@ -1521,12 +1177,39 @@ impl ToBlendState for BlendMode { BlendMode::DestOver => { Some(BlendState { src_rgb_factor: BlendFactor::OneMinusDestAlpha, - dest_rgb_factor: BlendFactor::DestAlpha, + dest_rgb_factor: BlendFactor::One, src_alpha_factor: BlendFactor::OneMinusDestAlpha, dest_alpha_factor: BlendFactor::One, ..BlendState::default() }) } + BlendMode::SrcIn => { + Some(BlendState { + src_rgb_factor: BlendFactor::DestAlpha, + dest_rgb_factor: BlendFactor::Zero, + src_alpha_factor: BlendFactor::DestAlpha, + dest_alpha_factor: BlendFactor::Zero, + ..BlendState::default() + }) + } + BlendMode::DestIn => { + Some(BlendState { + src_rgb_factor: BlendFactor::Zero, + dest_rgb_factor: BlendFactor::SrcAlpha, + src_alpha_factor: BlendFactor::Zero, + dest_alpha_factor: BlendFactor::SrcAlpha, + ..BlendState::default() + }) + } + BlendMode::SrcOut => { + Some(BlendState { + src_rgb_factor: BlendFactor::OneMinusDestAlpha, + dest_rgb_factor: BlendFactor::Zero, + src_alpha_factor: BlendFactor::OneMinusDestAlpha, + dest_alpha_factor: BlendFactor::Zero, + ..BlendState::default() + }) + } BlendMode::DestOut => { Some(BlendState { src_rgb_factor: BlendFactor::Zero, @@ -1545,6 +1228,15 @@ impl ToBlendState for BlendMode { ..BlendState::default() }) } + BlendMode::DestAtop => { + Some(BlendState { + src_rgb_factor: BlendFactor::OneMinusDestAlpha, + dest_rgb_factor: BlendFactor::SrcAlpha, + src_alpha_factor: BlendFactor::OneMinusDestAlpha, + dest_alpha_factor: BlendFactor::SrcAlpha, + ..BlendState::default() + }) + } BlendMode::Xor => { Some(BlendState { src_rgb_factor: BlendFactor::OneMinusDestAlpha, @@ -1563,24 +1255,9 @@ impl ToBlendState for BlendMode { ..BlendState::default() }) } - BlendMode::Lighten => { - Some(BlendState { - src_rgb_factor: BlendFactor::One, - dest_rgb_factor: BlendFactor::OneMinusSrcAlpha, - src_alpha_factor: BlendFactor::One, - dest_alpha_factor: BlendFactor::One, - op: BlendOp::Max, - }) - } - BlendMode::Darken => { - Some(BlendState { - src_rgb_factor: BlendFactor::One, - dest_rgb_factor: BlendFactor::OneMinusSrcAlpha, - src_alpha_factor: BlendFactor::One, - dest_alpha_factor: BlendFactor::One, - op: BlendOp::Min, - }) - } + BlendMode::Copy | + BlendMode::Darken | + BlendMode::Lighten | BlendMode::Multiply | BlendMode::Screen | BlendMode::HardLight | @@ -1601,124 +1278,40 @@ impl ToBlendState for BlendMode { } } -impl ToBlendState for CompositeOp { - fn to_blend_state(self) -> Option { +pub trait BlendModeExt { + fn needs_readable_framebuffer(self) -> bool; +} + +impl BlendModeExt for BlendMode { + fn needs_readable_framebuffer(self) -> bool { match self { - CompositeOp::Clear => { - Some(BlendState { - src_rgb_factor: BlendFactor::Zero, - dest_rgb_factor: BlendFactor::OneMinusSrcAlpha, - src_alpha_factor: BlendFactor::Zero, - dest_alpha_factor: BlendFactor::OneMinusSrcAlpha, - ..BlendState::default() - }) - } - CompositeOp::Copy => { - Some(BlendState { - src_rgb_factor: BlendFactor::One, - dest_rgb_factor: BlendFactor::Zero, - src_alpha_factor: BlendFactor::One, - dest_alpha_factor: BlendFactor::Zero, - ..BlendState::default() - }) - } - CompositeOp::SrcOver => { - Some(BlendState { - src_rgb_factor: BlendFactor::One, - dest_rgb_factor: BlendFactor::OneMinusSrcAlpha, - src_alpha_factor: BlendFactor::One, - dest_alpha_factor: BlendFactor::OneMinusSrcAlpha, - ..BlendState::default() - }) - } - CompositeOp::SrcIn => { - Some(BlendState { - src_rgb_factor: BlendFactor::DestAlpha, - dest_rgb_factor: BlendFactor::Zero, - src_alpha_factor: BlendFactor::DestAlpha, - dest_alpha_factor: BlendFactor::Zero, - ..BlendState::default() - }) - } - CompositeOp::DestIn => { - Some(BlendState { - src_rgb_factor: BlendFactor::Zero, - dest_rgb_factor: BlendFactor::SrcAlpha, - src_alpha_factor: BlendFactor::Zero, - dest_alpha_factor: BlendFactor::SrcAlpha, - ..BlendState::default() - }) - } - CompositeOp::SrcOut => { - Some(BlendState { - src_rgb_factor: BlendFactor::OneMinusDestAlpha, - dest_rgb_factor: BlendFactor::Zero, - src_alpha_factor: BlendFactor::OneMinusDestAlpha, - dest_alpha_factor: BlendFactor::Zero, - ..BlendState::default() - }) - } - CompositeOp::DestAtop => { - Some(BlendState { - src_rgb_factor: BlendFactor::OneMinusDestAlpha, - dest_rgb_factor: BlendFactor::SrcAlpha, - src_alpha_factor: BlendFactor::OneMinusDestAlpha, - dest_alpha_factor: BlendFactor::SrcAlpha, - ..BlendState::default() - }) - } - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub(crate) enum BlendModeProgram { - Regular, - Overlay, - DodgeBurn, - SoftLight, - Difference, - Exclusion, - HSL, -} - -impl BlendModeProgram { - pub(crate) fn from_blend_mode(blend_mode: BlendMode) -> BlendModeProgram { - match blend_mode { BlendMode::Clear | BlendMode::SrcOver | BlendMode::DestOver | + BlendMode::SrcIn | + BlendMode::DestIn | + BlendMode::SrcOut | BlendMode::DestOut | BlendMode::SrcAtop | + BlendMode::DestAtop | BlendMode::Xor | BlendMode::Lighter | + BlendMode::Copy => false, BlendMode::Lighten | - BlendMode::Darken => BlendModeProgram::Regular, + BlendMode::Darken | BlendMode::Multiply | BlendMode::Screen | BlendMode::HardLight | - BlendMode::Overlay => BlendModeProgram::Overlay, + BlendMode::Overlay | BlendMode::ColorDodge | - BlendMode::ColorBurn => BlendModeProgram::DodgeBurn, - BlendMode::SoftLight => BlendModeProgram::SoftLight, - BlendMode::Difference => BlendModeProgram::Difference, - BlendMode::Exclusion => BlendModeProgram::Exclusion, + BlendMode::ColorBurn | + BlendMode::SoftLight | + BlendMode::Difference | + BlendMode::Exclusion | BlendMode::Hue | BlendMode::Saturation | BlendMode::Color | - BlendMode::Luminosity => BlendModeProgram::HSL, - } - } - - pub(crate) fn needs_readable_framebuffer(self) -> bool { - match self { - BlendModeProgram::Regular => false, - BlendModeProgram::Overlay | - BlendModeProgram::DodgeBurn | - BlendModeProgram::SoftLight | - BlendModeProgram::Difference | - BlendModeProgram::Exclusion | - BlendModeProgram::HSL => true, + BlendMode::Luminosity => true, } } } @@ -1734,3 +1327,41 @@ bitflags! { const INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED = 0x02; } } + +trait ToCompositeCtrl { + fn to_composite_ctrl(&self) -> i32; +} + +impl ToCompositeCtrl for BlendMode { + fn to_composite_ctrl(&self) -> i32 { + match *self { + BlendMode::SrcOver | + BlendMode::SrcAtop | + BlendMode::DestOver | + BlendMode::DestOut | + BlendMode::Xor | + BlendMode::Lighter | + BlendMode::Clear | + BlendMode::Copy | + BlendMode::SrcIn | + BlendMode::SrcOut | + BlendMode::DestIn | + BlendMode::DestAtop => COMBINER_CTRL_COMPOSITE_NORMAL, + BlendMode::Multiply => COMBINER_CTRL_COMPOSITE_MULTIPLY, + BlendMode::Darken => COMBINER_CTRL_COMPOSITE_DARKEN, + BlendMode::Lighten => COMBINER_CTRL_COMPOSITE_LIGHTEN, + BlendMode::Screen => COMBINER_CTRL_COMPOSITE_SCREEN, + BlendMode::Overlay => COMBINER_CTRL_COMPOSITE_OVERLAY, + BlendMode::ColorDodge => COMBINER_CTRL_COMPOSITE_COLOR_DODGE, + BlendMode::ColorBurn => COMBINER_CTRL_COMPOSITE_COLOR_BURN, + BlendMode::HardLight => COMBINER_CTRL_COMPOSITE_HARD_LIGHT, + BlendMode::SoftLight => COMBINER_CTRL_COMPOSITE_SOFT_LIGHT, + BlendMode::Difference => COMBINER_CTRL_COMPOSITE_DIFFERENCE, + BlendMode::Exclusion => COMBINER_CTRL_COMPOSITE_EXCLUSION, + BlendMode::Hue => COMBINER_CTRL_COMPOSITE_HUE, + BlendMode::Saturation => COMBINER_CTRL_COMPOSITE_SATURATION, + BlendMode::Color => COMBINER_CTRL_COMPOSITE_COLOR, + BlendMode::Luminosity => COMBINER_CTRL_COMPOSITE_LUMINOSITY, + } + } +} diff --git a/renderer/src/gpu/shaders.rs b/renderer/src/gpu/shaders.rs index 7f72a74a..78528d9a 100644 --- a/renderer/src/gpu/shaders.rs +++ b/renderer/src/gpu/shaders.rs @@ -9,16 +9,13 @@ // except according to those terms. use crate::gpu_data::FillBatchPrimitive; -use pathfinder_content::fill::FillRule; use pathfinder_gpu::{BufferData, BufferTarget, BufferUploadMode, Device, VertexAttrClass}; use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; use pathfinder_resources::ResourceLoader; // TODO(pcwalton): Replace with `mem::size_of` calls? const FILL_INSTANCE_SIZE: usize = 8; -const SOLID_TILE_VERTEX_SIZE: usize = 12; -const ALPHA_TILE_VERTEX_SIZE: usize = 20; -const MASK_TILE_VERTEX_SIZE: usize = 12; +const TILE_VERTEX_SIZE: usize = 40; pub const MAX_FILLS_PER_BATCH: usize = 0x4000; @@ -150,173 +147,93 @@ where } } -pub struct MaskTileVertexArray where D: Device { +pub struct TileVertexArray where D: Device { pub vertex_array: D::VertexArray, - pub vertex_buffer: D::Buffer, } -impl MaskTileVertexArray where D: Device { +impl TileVertexArray where D: Device { pub fn new(device: &D, - mask_tile_program: &MaskTileProgram, + tile_program: &TileProgram, + tile_vertex_buffer: &D::Buffer, quads_vertex_indices_buffer: &D::Buffer) - -> MaskTileVertexArray { - let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); - - let position_attr = device.get_vertex_attr(&mask_tile_program.program, "Position") - .unwrap(); - let fill_tex_coord_attr = device.get_vertex_attr(&mask_tile_program.program, - "FillTexCoord").unwrap(); - let backdrop_attr = device.get_vertex_attr(&mask_tile_program.program, "Backdrop") - .unwrap(); - - device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: MASK_TILE_VERTEX_SIZE, - offset: 0, - divisor: 0, - buffer_index: 0, - }); - device.configure_vertex_attr(&vertex_array, &fill_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: MASK_TILE_VERTEX_SIZE, - offset: 4, - divisor: 0, - buffer_index: 0, - }); - device.configure_vertex_attr(&vertex_array, &backdrop_attr, &VertexAttrDescriptor { - size: 1, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::I16, - stride: MASK_TILE_VERTEX_SIZE, - offset: 8, - divisor: 0, - buffer_index: 0, - }); - device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index); - - MaskTileVertexArray { vertex_array, vertex_buffer } - } -} - -pub struct AlphaTileVertexArray where D: Device { - pub vertex_array: D::VertexArray, -} - -impl AlphaTileVertexArray where D: Device { - pub fn new( - device: &D, - alpha_tile_program: &AlphaTileProgram, - alpha_tile_vertex_buffer: &D::Buffer, - quads_vertex_indices_buffer: &D::Buffer, - ) -> AlphaTileVertexArray { + -> TileVertexArray { let vertex_array = device.create_vertex_array(); let tile_position_attr = - device.get_vertex_attr(&alpha_tile_program.program, "TilePosition").unwrap(); - let color_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, - "ColorTexCoord").unwrap(); - let mask_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, - "MaskTexCoord").unwrap(); - let opacity_attr = device.get_vertex_attr(&alpha_tile_program.program, "Opacity").unwrap(); + 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 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(); - device.bind_buffer(&vertex_array, alpha_tile_vertex_buffer, BufferTarget::Vertex); + device.bind_buffer(&vertex_array, tile_vertex_buffer, BufferTarget::Vertex); device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor { size: 2, class: VertexAttrClass::Int, attr_type: VertexAttrType::I16, - stride: ALPHA_TILE_VERTEX_SIZE, - offset: 0, - divisor: 0, - buffer_index: 0, - }); - device.configure_vertex_attr(&vertex_array, &mask_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U16, - stride: ALPHA_TILE_VERTEX_SIZE, - offset: 4, - divisor: 0, - buffer_index: 0, - }); - device.configure_vertex_attr(&vertex_array, &color_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::F32, - stride: ALPHA_TILE_VERTEX_SIZE, - offset: 8, - divisor: 0, - buffer_index: 0, - }); - device.configure_vertex_attr(&vertex_array, &opacity_attr, &VertexAttrDescriptor { - size: 1, - class: VertexAttrClass::FloatNorm, - attr_type: VertexAttrType::U8, - stride: ALPHA_TILE_VERTEX_SIZE, - offset: 18, - divisor: 0, - buffer_index: 0, - }); - device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index); - - AlphaTileVertexArray { vertex_array } - } -} - -pub struct SolidTileVertexArray -where - D: Device, -{ - pub vertex_array: D::VertexArray, -} - -impl SolidTileVertexArray -where - D: Device, -{ - pub fn new( - device: &D, - solid_tile_program: &SolidTileProgram, - solid_tile_vertex_buffer: &D::Buffer, - quads_vertex_indices_buffer: &D::Buffer, - ) -> SolidTileVertexArray { - let vertex_array = device.create_vertex_array(); - - let tile_position_attr = - device.get_vertex_attr(&solid_tile_program.program, "TilePosition").unwrap(); - let color_tex_coord_attr = - device.get_vertex_attr(&solid_tile_program.program, "ColorTexCoord").unwrap(); - - // NB: The tile origin must be of type short, not unsigned short, to work around a macOS - // Radeon driver bug. - device.bind_buffer(&vertex_array, solid_tile_vertex_buffer, BufferTarget::Vertex); - device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::I16, - stride: SOLID_TILE_VERTEX_SIZE, + stride: TILE_VERTEX_SIZE, offset: 0, divisor: 0, buffer_index: 0, }); device.configure_vertex_attr(&vertex_array, - &color_tex_coord_attr, + &color_0_tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Float, - attr_type: VertexAttrType::F32, - stride: SOLID_TILE_VERTEX_SIZE, - offset: 4, - divisor: 0, - buffer_index: 0, - }); + 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, + }); + 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, + }); + 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, + }); + 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, + }); device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index); - SolidTileVertexArray { vertex_array } + TileVertexArray { vertex_array } } } @@ -341,7 +258,7 @@ impl CopyTileVertexArray where D: Device { size: 2, class: VertexAttrClass::Int, attr_type: VertexAttrType::I16, - stride: ALPHA_TILE_VERTEX_SIZE, + stride: TILE_VERTEX_SIZE, offset: 0, divisor: 0, buffer_index: 0, @@ -393,90 +310,57 @@ where } } -pub struct MaskTileProgram where D: Device { - pub program: D::Program, - pub fill_texture_uniform: D::Uniform, -} - -impl MaskTileProgram where D: Device { - pub fn new(fill_rule: FillRule, device: &D, resources: &dyn ResourceLoader) - -> MaskTileProgram { - let program_name = match fill_rule { - FillRule::Winding => "mask_winding", - FillRule::EvenOdd => "mask_evenodd", - }; - - let program = device.create_program_from_shader_names(resources, - program_name, - "mask", - program_name); - - let fill_texture_uniform = device.get_uniform(&program, "FillTexture"); - MaskTileProgram { program, fill_texture_uniform } - } -} - -pub struct SolidTileProgram where D: Device { +pub struct TileProgram where D: Device { pub program: D::Program, pub transform_uniform: D::Uniform, pub tile_size_uniform: D::Uniform, - pub color_texture_uniform: D::Uniform, + pub dest_texture_uniform: D::Uniform, + pub color_texture_0_uniform: D::Uniform, + pub color_texture_1_uniform: D::Uniform, + pub mask_texture_0_uniform: D::Uniform, + pub mask_texture_1_uniform: D::Uniform, + pub gamma_lut_uniform: D::Uniform, + pub color_texture_0_size_uniform: D::Uniform, + pub filter_params_0_uniform: D::Uniform, + pub filter_params_1_uniform: D::Uniform, + pub filter_params_2_uniform: D::Uniform, + pub dest_texture_size_uniform: D::Uniform, + pub ctrl_uniform: D::Uniform, } -impl SolidTileProgram where D: Device { - pub fn new(device: &D, resources: &dyn ResourceLoader, program_name: &str) - -> SolidTileProgram { - let program = device.create_program_from_shader_names(resources, - program_name, - "tile_solid", - program_name); +impl TileProgram where D: Device { + pub fn new(device: &D, resources: &dyn ResourceLoader) -> TileProgram { + 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 color_texture_uniform = device.get_uniform(&program, "ColorTexture"); - SolidTileProgram { + 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"); + let mask_texture_0_uniform = device.get_uniform(&program, "MaskTexture0"); + let mask_texture_1_uniform = device.get_uniform(&program, "MaskTexture1"); + let gamma_lut_uniform = device.get_uniform(&program, "GammaLUT"); + let color_texture_0_size_uniform = device.get_uniform(&program, "ColorTexture0Size"); + let filter_params_0_uniform = device.get_uniform(&program, "FilterParams0"); + let filter_params_1_uniform = device.get_uniform(&program, "FilterParams1"); + let filter_params_2_uniform = device.get_uniform(&program, "FilterParams2"); + let dest_texture_size_uniform = device.get_uniform(&program, "DestTextureSize"); + let ctrl_uniform = device.get_uniform(&program, "Ctrl"); + TileProgram { program, transform_uniform, tile_size_uniform, - color_texture_uniform, - } - } -} - -pub struct AlphaTileProgram where D: Device { - pub program: D::Program, - pub transform_uniform: D::Uniform, - pub tile_size_uniform: D::Uniform, - pub framebuffer_size_uniform: D::Uniform, - pub stencil_texture_uniform: D::Uniform, - pub paint_texture_uniform: D::Uniform, -} - -impl AlphaTileProgram where D: Device { - #[inline] - pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileProgram { - AlphaTileProgram::from_fragment_shader_name(device, resources, "tile_alpha") - } - - fn from_fragment_shader_name(device: &D, - resources: &dyn ResourceLoader, - fragment_shader_name: &str) - -> AlphaTileProgram { - let program = device.create_program_from_shader_names(resources, - fragment_shader_name, - "tile_alpha", - fragment_shader_name); - let transform_uniform = device.get_uniform(&program, "Transform"); - let tile_size_uniform = device.get_uniform(&program, "TileSize"); - let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); - let stencil_texture_uniform = device.get_uniform(&program, "StencilTexture"); - let paint_texture_uniform = device.get_uniform(&program, "PaintTexture"); - AlphaTileProgram { - program, - transform_uniform, - tile_size_uniform, - framebuffer_size_uniform, - stencil_texture_uniform, - paint_texture_uniform, + dest_texture_uniform, + color_texture_0_uniform, + color_texture_1_uniform, + mask_texture_0_uniform, + mask_texture_1_uniform, + gamma_lut_uniform, + color_texture_0_size_uniform, + filter_params_0_uniform, + filter_params_1_uniform, + filter_params_2_uniform, + dest_texture_size_uniform, + ctrl_uniform, } } } @@ -506,126 +390,6 @@ impl CopyTileProgram where D: Device { } } -pub struct AlphaTileBlendModeProgram where D: Device { - pub alpha_tile_program: AlphaTileProgram, - pub dest_uniform: D::Uniform, -} - -impl AlphaTileBlendModeProgram where D: Device { - pub fn new(device: &D, resources: &dyn ResourceLoader, name: &str) - -> AlphaTileBlendModeProgram { - let alpha_tile_program = - AlphaTileProgram::from_fragment_shader_name(device, resources, name); - let dest_uniform = device.get_uniform(&alpha_tile_program.program, "Dest"); - AlphaTileBlendModeProgram { alpha_tile_program, dest_uniform } - } -} - -pub struct AlphaTileHSLProgram where D: Device { - pub alpha_tile_blend_mode_program: AlphaTileBlendModeProgram, - pub blend_hsl_uniform: D::Uniform, -} - -impl AlphaTileHSLProgram where D: Device { - pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileHSLProgram { - let alpha_tile_blend_mode_program = - AlphaTileBlendModeProgram::new(device, resources, "tile_alpha_hsl"); - let blend_hsl_uniform = - device.get_uniform(&alpha_tile_blend_mode_program.alpha_tile_program.program, - "BlendHSL"); - AlphaTileHSLProgram { alpha_tile_blend_mode_program, blend_hsl_uniform } - } -} - -pub struct AlphaTileOverlayProgram where D: Device { - pub alpha_tile_blend_mode_program: AlphaTileBlendModeProgram, - pub blend_mode_uniform: D::Uniform, -} - -impl AlphaTileOverlayProgram where D: Device { - pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileOverlayProgram { - let alpha_tile_blend_mode_program = AlphaTileBlendModeProgram::new(device, - resources, - "tile_alpha_overlay"); - let blend_mode_uniform = - device.get_uniform(&alpha_tile_blend_mode_program.alpha_tile_program.program, - "BlendMode"); - AlphaTileOverlayProgram { alpha_tile_blend_mode_program, blend_mode_uniform } - } -} - -pub struct AlphaTileDodgeBurnProgram where D: Device { - pub alpha_tile_blend_mode_program: AlphaTileBlendModeProgram, - pub burn_uniform: D::Uniform, -} - -impl AlphaTileDodgeBurnProgram where D: Device { - pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileDodgeBurnProgram { - let alpha_tile_blend_mode_program = - AlphaTileBlendModeProgram::new(device, resources, "tile_alpha_dodgeburn"); - let burn_uniform = - device.get_uniform(&alpha_tile_blend_mode_program.alpha_tile_program.program, "Burn"); - AlphaTileDodgeBurnProgram { alpha_tile_blend_mode_program, burn_uniform } - } -} - -pub struct SolidTileBlurFilterProgram where D: Device { - pub solid_tile_program: SolidTileProgram, - pub src_offset_scale_uniform: D::Uniform, - pub initial_gauss_coeff_uniform: D::Uniform, - pub support_uniform: D::Uniform, -} - -impl SolidTileBlurFilterProgram where D: Device { - pub fn new(device: &D, resources: &dyn ResourceLoader) -> SolidTileBlurFilterProgram { - let solid_tile_program = SolidTileProgram::new(device, - resources, - "tile_solid_filter_blur"); - let src_offset_scale_uniform = device.get_uniform(&solid_tile_program.program, - "SrcOffsetScale"); - let initial_gauss_coeff_uniform = device.get_uniform(&solid_tile_program.program, - "InitialGaussCoeff"); - let support_uniform = device.get_uniform(&solid_tile_program.program, "Support"); - SolidTileBlurFilterProgram { - solid_tile_program, - src_offset_scale_uniform, - initial_gauss_coeff_uniform, - support_uniform, - } - } -} - -pub struct SolidTileTextFilterProgram where D: Device { - pub solid_tile_program: SolidTileProgram, - pub kernel_uniform: D::Uniform, - pub gamma_lut_uniform: D::Uniform, - pub gamma_correction_enabled_uniform: D::Uniform, - pub fg_color_uniform: D::Uniform, - pub bg_color_uniform: D::Uniform, -} - -impl SolidTileTextFilterProgram where D: Device { - pub fn new(device: &D, resources: &dyn ResourceLoader) -> SolidTileTextFilterProgram { - let solid_tile_program = SolidTileProgram::new(device, - resources, - "tile_solid_filter_text"); - let kernel_uniform = device.get_uniform(&solid_tile_program.program, "Kernel"); - let gamma_lut_uniform = device.get_uniform(&solid_tile_program.program, "GammaLUT"); - let gamma_correction_enabled_uniform = device.get_uniform(&solid_tile_program.program, - "GammaCorrectionEnabled"); - let fg_color_uniform = device.get_uniform(&solid_tile_program.program, "FGColor"); - let bg_color_uniform = device.get_uniform(&solid_tile_program.program, "BGColor"); - SolidTileTextFilterProgram { - solid_tile_program, - kernel_uniform, - gamma_lut_uniform, - gamma_correction_enabled_uniform, - fg_color_uniform, - bg_color_uniform, - } - } -} - pub struct StencilProgram where D: Device, diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index 793ae45f..98a26feb 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -55,9 +55,6 @@ pub enum RenderCommand { // Flushes the queue of fills. FlushFills, - // Render fills to a set of mask tiles. - RenderMaskTiles { tiles: Vec, fill_rule: FillRule }, - // Pushes a render target onto the stack. Draw commands go to the render target on top of the // stack. PushRenderTarget(RenderTargetId), @@ -65,11 +62,8 @@ pub enum RenderCommand { // Pops a render target from the stack. PopRenderTarget, - // Draws a batch of alpha tiles to the render target on top of the stack. - DrawAlphaTiles(AlphaTileBatch), - - // Draws a batch of solid tiles to the render target on top of the stack. - DrawSolidTiles(SolidTileBatch), + // Draws a batch of tiles to the render target on top of the stack. + DrawTiles(TileBatch), // Presents a rendered frame. Finish { build_time: Duration }, @@ -90,19 +84,20 @@ pub struct TextureLocation { } #[derive(Clone, Debug)] -pub struct AlphaTileBatch { - pub tiles: Vec, - pub color_texture_page: TexturePageId, +pub struct TileBatch { + pub tiles: Vec, + pub color_texture_0: Option, + pub color_texture_1: Option, + pub mask_0_fill_rule: Option, + pub mask_1_fill_rule: Option, pub blend_mode: BlendMode, - pub sampling_flags: TextureSamplingFlags, + pub effects: Effects, } -#[derive(Clone, Debug)] -pub struct SolidTileBatch { - pub tiles: Vec, - pub color_texture_page: TexturePageId, +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct TileBatchTexture { + pub page: TexturePageId, pub sampling_flags: TextureSamplingFlags, - pub effects: Effects, } #[derive(Clone, Copy, Debug)] @@ -132,63 +127,28 @@ pub struct FillBatchPrimitive { #[derive(Clone, Copy, Debug, Default)] #[repr(C)] -pub struct SolidTileVertex { +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_u: f32, - pub color_v: f32, -} - -#[derive(Clone, Copy, Debug, Default)] -#[repr(C)] -pub struct MaskTile { - pub upper_left: MaskTileVertex, - pub upper_right: MaskTileVertex, - pub lower_left: MaskTileVertex, - pub lower_right: MaskTileVertex, -} - -#[derive(Clone, Copy, Debug, Default)] -#[repr(C)] -pub struct AlphaTile { - pub upper_left: AlphaTileVertex, - pub upper_right: AlphaTileVertex, - pub lower_left: AlphaTileVertex, - pub lower_right: AlphaTileVertex, -} - -#[derive(Clone, Copy, Debug, Default)] -#[repr(C)] -pub struct SolidTile { - pub upper_left: SolidTileVertex, - pub upper_right: SolidTileVertex, - pub lower_left: SolidTileVertex, - pub lower_right: SolidTileVertex, -} - -#[derive(Clone, Copy, Debug, Default)] -#[repr(C)] -pub struct MaskTileVertex { - pub mask_u: u16, - pub mask_v: u16, - pub fill_u: u16, - pub fill_v: u16, - pub backdrop: i16, - pub object_index: u16, -} - -#[derive(Clone, Copy, Debug, Default)] -#[repr(C)] -pub struct AlphaTileVertex { - pub tile_x: i16, - pub tile_y: i16, - pub mask_u: u16, - pub mask_v: u16, - pub color_u: f32, - pub color_v: f32, - pub object_index: u16, - pub opacity: u8, - pub pad: u8, + 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, } impl Debug for RenderCommand { @@ -199,34 +159,25 @@ impl Debug for RenderCommand { write!(formatter, "AllocateTexturePages(x{})", pages.len()) } RenderCommand::UploadTexelData { ref texels, location } => { - write!(formatter, "UploadTexelData({:?}, {:?})", texels, location) + write!(formatter, "UploadTexelData(x{:?}, {:?})", texels.len(), location) } RenderCommand::DeclareRenderTarget { id, location } => { write!(formatter, "DeclareRenderTarget({:?}, {:?})", id, location) } RenderCommand::AddFills(ref fills) => write!(formatter, "AddFills(x{})", fills.len()), RenderCommand::FlushFills => write!(formatter, "FlushFills"), - RenderCommand::RenderMaskTiles { ref tiles, fill_rule } => { - write!(formatter, "RenderMaskTiles(x{}, {:?})", tiles.len(), fill_rule) - } RenderCommand::PushRenderTarget(render_target_id) => { write!(formatter, "PushRenderTarget({:?})", render_target_id) } RenderCommand::PopRenderTarget => write!(formatter, "PopRenderTarget"), - RenderCommand::DrawAlphaTiles(ref batch) => { + RenderCommand::DrawTiles(ref batch) => { write!(formatter, - "DrawAlphaTiles(x{}, {:?}, {:?}, {:?})", + "DrawTiles(x{}, C0 {:?}, C1 {:?}, M0 {:?}, {:?})", batch.tiles.len(), - batch.color_texture_page, - batch.blend_mode, - batch.sampling_flags) - } - RenderCommand::DrawSolidTiles(ref batch) => { - write!(formatter, - "DrawSolidTiles(x{}, {:?}, {:?})", - batch.tiles.len(), - batch.color_texture_page, - batch.sampling_flags) + batch.color_texture_0, + batch.color_texture_1, + batch.mask_0_fill_rule, + batch.blend_mode) } RenderCommand::Finish { .. } => write!(formatter, "Finish"), } diff --git a/renderer/src/paint.rs b/renderer/src/paint.rs index cf9395e9..965cada6 100644 --- a/renderer/src/paint.rs +++ b/renderer/src/paint.rs @@ -161,6 +161,10 @@ pub struct PaintInfo { /// /// The indices of this vector are render target IDs. pub render_target_metadata: Vec, + /// The page containing the opacity tile. + pub opacity_tile_page: TexturePageId, + /// The transform for the opacity tile. + pub opacity_tile_transform: Transform2F, } #[derive(Debug)] @@ -212,6 +216,7 @@ impl Palette { } // Assign paint locations. + let opacity_tile_builder = OpacityTileBuilder::new(&mut allocator); let mut solid_color_tile_builder = SolidColorTileBuilder::new(); let mut gradient_tile_builder = GradientTileBuilder::new(); for paint in &self.paints { @@ -344,6 +349,7 @@ impl Palette { // Draw to texels. // // TODO(pcwalton): Do more of this on GPU. + opacity_tile_builder.render(&mut page_texels); for (paint, metadata) in self.paints.iter().zip(paint_metadata.iter()) { let texture_page = metadata.location.page; let texels = &mut page_texels[texture_page.0 as usize]; @@ -392,7 +398,13 @@ impl Palette { } } - PaintInfo { render_commands, paint_metadata, render_target_metadata } + PaintInfo { + render_commands, + paint_metadata, + render_target_metadata, + opacity_tile_page: opacity_tile_builder.tile_location.page, + opacity_tile_transform: opacity_tile_builder.tile_transform(&allocator), + } } // TODO(pcwalton): This is slow. Do on GPU instead. @@ -599,6 +611,38 @@ fn rect_to_inset_uv(rect: RectI, texture_scale: Vector2F) -> RectF { rect_to_uv(rect, texture_scale).contract(texture_scale.scale(0.5)) } +// Opacity allocation + +struct OpacityTileBuilder { + tile_location: TextureLocation, +} + +impl OpacityTileBuilder { + fn new(allocator: &mut TextureAllocator) -> OpacityTileBuilder { + OpacityTileBuilder { + tile_location: allocator.allocate(Vector2I::splat(16), AllocationMode::Atlas), + } + } + + fn render(&self, page_texels: &mut [Texels]) { + let texels = &mut page_texels[self.tile_location.page.0 as usize]; + for y in 0..16 { + for x in 0..16 { + let color = ColorU::new(0xff, 0xff, 0xff, y * 16 + x); + let coords = self.tile_location.rect.origin() + Vector2I::new(x as i32, y as i32); + texels.put_texel(coords, color); + } + } + } + + fn tile_transform(&self, allocator: &TextureAllocator) -> Transform2F { + let texture_scale = allocator.page_scale(self.tile_location.page); + let matrix = Matrix2x2F::from_scale(texture_scale.scale(16.0)); + let vector = rect_to_uv(self.tile_location.rect, texture_scale).origin(); + Transform2F { matrix, vector } + } +} + // Solid color allocation struct SolidColorTileBuilder(Option); diff --git a/renderer/src/tiles.rs b/renderer/src/tiles.rs index 8336c3fa..2c2a7da9 100644 --- a/renderer/src/tiles.rs +++ b/renderer/src/tiles.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::builder::{BuiltPath, ObjectBuilder, SceneBuilder, SolidTileInfo}; +use crate::builder::{BuiltPath, ObjectBuilder, Occluder, SceneBuilder, SolidTiles}; use crate::gpu_data::TileObjectPrimitive; use crate::paint::PaintMetadata; use pathfinder_content::effects::BlendMode; @@ -18,6 +18,7 @@ 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}; use std::cmp::Ordering; use std::mem; @@ -33,7 +34,6 @@ pub(crate) struct Tiler<'a> { pub(crate) object_builder: ObjectBuilder, outline: &'a Outline, path_info: TilingPathInfo<'a>, - object_index: u16, point_queue: SortedVector, active_edges: SortedVector, @@ -49,6 +49,7 @@ pub(crate) enum TilingPathInfo<'a> { #[derive(Clone, Copy)] pub(crate) struct DrawTilingPathInfo<'a> { 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>, @@ -61,20 +62,18 @@ impl<'a> Tiler<'a> { outline: &'a Outline, fill_rule: FillRule, view_box: RectF, - object_index: u16, path_info: TilingPathInfo<'a>, ) -> Tiler<'a> { let bounds = outline .bounds() .intersection(view_box) .unwrap_or(RectF::default()); - let object_builder = ObjectBuilder::new(bounds, fill_rule); + let object_builder = ObjectBuilder::new(bounds, view_box, fill_rule, &path_info); Tiler { scene_builder, object_builder, outline, - object_index, path_info, point_queue: SortedVector::new(), @@ -124,107 +123,54 @@ impl<'a> Tiler<'a> { } fn pack_and_cull(&mut self) { - match self.path_info { - TilingPathInfo::Clip => self.pack_and_cull_clip_path(), - TilingPathInfo::Draw { .. } => self.pack_and_cull_draw_path(), - } - } - - fn pack_and_cull_draw_path(&mut self) { let draw_tiling_path_info = match self.path_info { - TilingPathInfo::Clip => unreachable!(), + TilingPathInfo::Clip => return, TilingPathInfo::Draw(draw_tiling_path_info) => draw_tiling_path_info, }; + let blend_mode_is_destructive = draw_tiling_path_info.blend_mode.is_destructive(); + for (draw_tile_index, draw_tile) in self.object_builder .built_path .tiles .data .iter() .enumerate() { - let tile_coords = self.object_builder - .local_tile_index_to_coords(draw_tile_index as u32); + let packed_tile = PackedTile::new(draw_tile_index as u32, + draw_tile, + &draw_tiling_path_info, + &self.object_builder); - // Figure out what clip tile we need, if any. - let clip_tile = match draw_tiling_path_info.built_clip_path { - None => None, - Some(built_clip_path) => { - match built_clip_path.tiles.get(tile_coords) { - None => { - // This tile is outside of the bounds of the clip path entirely. We can - // cull it. - continue; + match packed_tile.tile_type { + TileType::Solid => { + match self.object_builder.built_path.solid_tiles { + SolidTiles::Occluders(ref mut occluders) => { + occluders.push(Occluder::new(packed_tile.tile_coords)); } - Some(clip_tile) if clip_tile.is_solid() => { - if clip_tile.backdrop != 0 { - // The clip tile is fully opaque, so this tile isn't clipped at - // all. - None - } else { - // This tile is completely clipped out. Cull it. - continue; - } + SolidTiles::Regular(ref mut solid_tiles) => { + packed_tile.add_to(solid_tiles, &draw_tiling_path_info); } - Some(clip_tile) => Some(clip_tile), } } - }; - - if clip_tile.is_none() && draw_tile.is_solid() { - // This is the simple case of a solid tile with no clip, so there are optimization - // opportunities. First, tiles that must be blank per the fill rule are always - // skipped. - match (self.object_builder.built_path.fill_rule, draw_tile.backdrop) { - (FillRule::Winding, 0) => continue, - (FillRule::Winding, _) => {} - (FillRule::EvenOdd, backdrop) if backdrop % 2 == 0 => continue, - (FillRule::EvenOdd, _) => {} + TileType::SingleMask => { + packed_tile.add_to(&mut self.object_builder.built_path.single_mask_tiles, + &draw_tiling_path_info); } - - // Next, if this is a solid tile that completely occludes the background, record - // that fact and stop here. - if draw_tiling_path_info.paint_metadata.is_opaque && - draw_tiling_path_info.blend_mode.occludes_backdrop() && - draw_tiling_path_info.opacity == !0 { - self.object_builder - .built_path - .solid_tiles - .push(SolidTileInfo::new(tile_coords)); - continue; + TileType::DualMask => { + packed_tile.add_to(&mut self.object_builder.built_path.dual_mask_tiles, + &draw_tiling_path_info); + } + TileType::Empty if blend_mode_is_destructive => { + packed_tile.add_to(&mut self.object_builder.built_path.empty_tiles, + &draw_tiling_path_info); + } + TileType::Empty => { + // Just cull. } } - - // Allocate a mask tile. - let mask_tile_index = self.scene_builder.allocate_mask_tile_index(); - - // Add the clip primitive to the mask framebuffer, if necessary. - if let Some(clip_tile) = clip_tile { - ObjectBuilder::push_mask_tile(&mut self.object_builder.built_path.mask_tiles, - clip_tile, - mask_tile_index, - self.object_index); - } - - // Add the primitive to the mask framebuffer. - ObjectBuilder::push_mask_tile(&mut self.object_builder.built_path.mask_tiles, - draw_tile, - mask_tile_index, - self.object_index); - - // Add the primitive to draw the mask. - ObjectBuilder::push_alpha_tile(&mut self.object_builder.built_path.alpha_tiles, - mask_tile_index, - tile_coords, - self.object_index, - &draw_tiling_path_info); - } } - fn pack_and_cull_clip_path(&mut self) { - // TODO(pcwalton) - } - fn process_old_active_edges(&mut self, tile_y: i32) { let mut current_tile_x = self.object_builder.tile_rect().min_x(); let mut current_subtile_x = 0.0; @@ -435,6 +381,123 @@ impl<'a> Tiler<'a> { } } +impl<'a> TilingPathInfo<'a> { + pub(crate) fn has_destructive_blend_mode(&self) -> bool { + match *self { + TilingPathInfo::Draw(ref draw_tiling_path_info) => { + draw_tiling_path_info.blend_mode.is_destructive() + } + TilingPathInfo::Clip => false, + } + } +} + +pub(crate) struct PackedTile<'a> { + pub(crate) tile_type: TileType, + pub(crate) tile_coords: Vector2I, + pub(crate) draw_tile: &'a TileObjectPrimitive, + pub(crate) clip_tile: Option<&'a TileObjectPrimitive>, +} + +#[derive(Clone, Copy, PartialEq)] +pub(crate) enum TileType { + Solid, + Empty, + SingleMask, + DualMask, +} + +impl<'a> PackedTile<'a> { + fn new(draw_tile_index: u32, + draw_tile: &'a TileObjectPrimitive, + draw_tiling_path_info: &DrawTilingPathInfo<'a>, + object_builder: &ObjectBuilder) + -> PackedTile<'a> { + let tile_coords = object_builder.local_tile_index_to_coords(draw_tile_index as u32); + + // Figure out what clip tile we need, if any. + let clip_tile = match draw_tiling_path_info.built_clip_path { + None => None, + Some(built_clip_path) => { + match built_clip_path.tiles.get(tile_coords) { + None => { + // This tile is outside of the bounds of the clip path entirely. We can + // cull it. + return PackedTile { + tile_type: TileType::Empty, + tile_coords, + draw_tile, + clip_tile: None, + }; + } + Some(clip_tile) if clip_tile.is_solid() => { + if clip_tile.backdrop != 0 { + // The clip tile is fully opaque, so this tile isn't clipped at + // all. + None + } else { + // This tile is completely clipped out. Cull it. + return PackedTile { + tile_type: TileType::Empty, + tile_coords, + draw_tile, + clip_tile: None, + }; + } + } + Some(clip_tile) => Some(clip_tile), + } + } + }; + + if clip_tile.is_none() { + if draw_tile.is_solid() { + // This is the simple case of a solid tile with no clip, so there are optimization + // opportunities. First, tiles that must be blank per the fill rule are always + // skipped. + match (object_builder.built_path.fill_rule, draw_tile.backdrop) { + (FillRule::Winding, 0) => { + return PackedTile { + tile_type: TileType::Empty, + tile_coords, + draw_tile, + clip_tile, + }; + } + (FillRule::Winding, _) => {} + (FillRule::EvenOdd, backdrop) if backdrop % 2 == 0 => { + return PackedTile { + tile_type: TileType::Empty, + tile_coords, + draw_tile, + clip_tile, + }; + } + (FillRule::EvenOdd, _) => {} + } + + // Next, if this is a solid tile that completely occludes the background, record + // that fact. Otherwise, add a regular solid tile. + return PackedTile { + tile_type: TileType::Solid, + tile_coords, + draw_tile, + clip_tile, + }; + } + + return PackedTile { + tile_type: TileType::SingleMask, + tile_coords, + draw_tile, + clip_tile, + }; + } + + PackedTile { tile_type: TileType::DualMask, tile_coords, draw_tile, clip_tile } + } +} + pub fn round_rect_out_to_tile_bounds(rect: RectF) -> RectI { rect.scale_xy(Vector2F::new( 1.0 / TILE_WIDTH as f32, diff --git a/renderer/src/z_buffer.rs b/renderer/src/z_buffer.rs index b5ee49e6..0010e243 100644 --- a/renderer/src/z_buffer.rs +++ b/renderer/src/z_buffer.rs @@ -10,12 +10,12 @@ //! Software occlusion culling. -use crate::builder::SolidTileInfo; -use crate::gpu_data::{SolidTile, SolidTileBatch, SolidTileVertex}; +use crate::builder::Occluder; +use crate::gpu_data::{Tile, TileBatch, TileBatchTexture, TileVertex}; use crate::paint::{PaintId, PaintMetadata}; use crate::tile_map::DenseTileMap; use crate::tiles; -use pathfinder_content::effects::{CompositeOp, Effects, Filter}; +use pathfinder_content::effects::{BlendMode, Effects}; use pathfinder_geometry::rect::RectF; use pathfinder_geometry::vector::{Vector2F, Vector2I}; use vec_map::VecMap; @@ -26,7 +26,7 @@ pub(crate) struct ZBuffer { } pub(crate) struct SolidTiles { - pub(crate) batches: Vec, + pub(crate) batches: Vec, } #[derive(Clone, Copy)] @@ -48,7 +48,7 @@ impl ZBuffer { } pub(crate) fn update(&mut self, - solid_tiles: &[SolidTileInfo], + solid_tiles: &[Occluder], depth: u32, metadata: DepthMetadata) { self.depth_metadata.insert(depth as usize, metadata); @@ -77,76 +77,92 @@ impl ZBuffer { // Create a batch if necessary. match solid_tiles.batches.last() { - Some(ref batch) if batch.color_texture_page == paint_metadata.location.page && - batch.sampling_flags == paint_metadata.sampling_flags => {} + Some(TileBatch { + color_texture_0: Some(TileBatchTexture { page, sampling_flags }), + .. + }) if *page == paint_metadata.location.page && + *sampling_flags == paint_metadata.sampling_flags => {} _ => { // Batch break. // // TODO(pcwalton): We could be more aggressive with batching here, since we // know there are no overlaps. - solid_tiles.batches.push(SolidTileBatch { - color_texture_page: paint_metadata.location.page, - sampling_flags: paint_metadata.sampling_flags, + solid_tiles.batches.push(TileBatch { + color_texture_0: Some(TileBatchTexture { + page: paint_metadata.location.page, + sampling_flags: paint_metadata.sampling_flags, + }), + color_texture_1: None, tiles: vec![], - effects: Effects::new(Filter::Composite(CompositeOp::SrcOver)), + effects: Effects::default(), + blend_mode: BlendMode::default(), + mask_0_fill_rule: None, + mask_1_fill_rule: None, }); } } let batch = solid_tiles.batches.last_mut().unwrap(); - batch.tiles.push(SolidTile::from_paint_metadata(tile_position, paint_metadata)); + batch.tiles.push(Tile::new_solid_with_paint_metadata(tile_position, paint_metadata)); } solid_tiles } } -impl SolidTile { - pub(crate) fn from_paint_metadata(tile_position: Vector2I, paint_metadata: &PaintMetadata) - -> SolidTile { - SolidTile { - upper_left: SolidTileVertex::from_paint_metadata(tile_position, paint_metadata), - upper_right: SolidTileVertex::from_paint_metadata(tile_position + Vector2I::new(1, 0), - paint_metadata), - lower_left: SolidTileVertex::from_paint_metadata(tile_position + Vector2I::new(0, 1), - paint_metadata), - lower_right: SolidTileVertex::from_paint_metadata(tile_position + Vector2I::new(1, 1), - paint_metadata), +impl Tile { + pub(crate) fn new_solid_with_paint_metadata(tile_position: Vector2I, + paint_metadata: &PaintMetadata) + -> Tile { + Tile { + upper_left: TileVertex::new_solid_from_paint_metadata(tile_position, paint_metadata), + upper_right: TileVertex::new_solid_from_paint_metadata(tile_position + + Vector2I::new(1, 0), + paint_metadata), + lower_left: TileVertex::new_solid_from_paint_metadata(tile_position + + Vector2I::new(0, 1), + paint_metadata), + lower_right: TileVertex::new_solid_from_paint_metadata(tile_position + + Vector2I::new(1, 1), + paint_metadata), } } - // The texture rect is in normalized coordinates. - pub(crate) fn from_texture_rect(tile_position: Vector2I, texture_rect: RectF) -> SolidTile { - SolidTile { - upper_left: SolidTileVertex::new(tile_position, texture_rect.origin()), - upper_right: SolidTileVertex::new(tile_position + Vector2I::new(1, 0), - texture_rect.upper_right()), - lower_left: SolidTileVertex::new(tile_position + Vector2I::new(0, 1), - texture_rect.lower_left()), - lower_right: SolidTileVertex::new(tile_position + Vector2I::new(1, 1), - texture_rect.lower_right()), + pub(crate) fn new_solid_from_texture_rect(tile_position: Vector2I, texture_rect: RectF) + -> Tile { + Tile { + upper_left: TileVertex::new_solid_from_uv(tile_position, texture_rect.origin()), + upper_right: TileVertex::new_solid_from_uv(tile_position + Vector2I::new(1, 0), + texture_rect.upper_right()), + lower_left: TileVertex::new_solid_from_uv(tile_position + Vector2I::new(0, 1), + texture_rect.lower_left()), + lower_right: TileVertex::new_solid_from_uv(tile_position + Vector2I::new(1, 1), + texture_rect.lower_right()), } } } -impl SolidTileVertex { - fn new(tile_position: Vector2I, color_tex_coords: Vector2F) -> SolidTileVertex { - SolidTileVertex { +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_u: color_tex_coords.x(), - color_v: color_tex_coords.y(), + 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, + mask_0_backdrop: 0, + mask_1_backdrop: 0, } } - fn from_paint_metadata(tile_position: Vector2I, paint_metadata: &PaintMetadata) - -> SolidTileVertex { + fn new_solid_from_paint_metadata(tile_position: Vector2I, paint_metadata: &PaintMetadata) + -> TileVertex { let color_uv = paint_metadata.calculate_tex_coords(tile_position); - SolidTileVertex { - tile_x: tile_position.x() as i16, - tile_y: tile_position.y() as i16, - color_u: color_uv.x(), - color_v: color_uv.y(), - } + TileVertex::new_solid_from_uv(tile_position, color_uv) } } diff --git a/resources/MANIFEST b/resources/MANIFEST index d7bb44ee..91a0f954 100644 --- a/resources/MANIFEST +++ b/resources/MANIFEST @@ -13,27 +13,14 @@ shaders/gl3/demo_ground.fs.glsl shaders/gl3/demo_ground.vs.glsl shaders/gl3/fill.fs.glsl shaders/gl3/fill.vs.glsl -shaders/gl3/mask.vs.glsl -shaders/gl3/mask_evenodd.fs.glsl -shaders/gl3/mask_winding.fs.glsl shaders/gl3/reproject.fs.glsl shaders/gl3/reproject.vs.glsl shaders/gl3/stencil.fs.glsl shaders/gl3/stencil.vs.glsl -shaders/gl3/tile_alpha.fs.glsl -shaders/gl3/tile_alpha.vs.glsl -shaders/gl3/tile_alpha_difference.fs.glsl -shaders/gl3/tile_alpha_dodgeburn.fs.glsl -shaders/gl3/tile_alpha_exclusion.fs.glsl -shaders/gl3/tile_alpha_hsl.fs.glsl -shaders/gl3/tile_alpha_overlay.fs.glsl -shaders/gl3/tile_alpha_softlight.fs.glsl +shaders/gl3/tile.fs.glsl +shaders/gl3/tile.vs.glsl shaders/gl3/tile_copy.fs.glsl shaders/gl3/tile_copy.vs.glsl -shaders/gl3/tile_solid.fs.glsl -shaders/gl3/tile_solid.vs.glsl -shaders/gl3/tile_solid_filter_blur.fs.glsl -shaders/gl3/tile_solid_filter_text.fs.glsl shaders/metal/blit.fs.metal shaders/metal/blit.vs.metal shaders/metal/debug_solid.fs.metal @@ -44,27 +31,14 @@ shaders/metal/demo_ground.fs.metal shaders/metal/demo_ground.vs.metal shaders/metal/fill.fs.metal shaders/metal/fill.vs.metal -shaders/metal/mask.vs.metal -shaders/metal/mask_evenodd.fs.metal -shaders/metal/mask_winding.fs.metal shaders/metal/reproject.fs.metal shaders/metal/reproject.vs.metal shaders/metal/stencil.fs.metal shaders/metal/stencil.vs.metal -shaders/metal/tile_alpha.fs.metal -shaders/metal/tile_alpha.vs.metal -shaders/metal/tile_alpha_difference.fs.metal -shaders/metal/tile_alpha_dodgeburn.fs.metal -shaders/metal/tile_alpha_exclusion.fs.metal -shaders/metal/tile_alpha_hsl.fs.metal -shaders/metal/tile_alpha_overlay.fs.metal -shaders/metal/tile_alpha_softlight.fs.metal +shaders/metal/tile.fs.metal +shaders/metal/tile.vs.metal shaders/metal/tile_copy.fs.metal shaders/metal/tile_copy.vs.metal -shaders/metal/tile_solid.fs.metal -shaders/metal/tile_solid.vs.metal -shaders/metal/tile_solid_filter_blur.fs.metal -shaders/metal/tile_solid_filter_text.fs.metal textures/area-lut.png textures/debug-corner-fill.png textures/debug-corner-outline.png diff --git a/resources/shaders/gl3/blit.vs.glsl b/resources/shaders/gl3/blit.vs.glsl index 6203f17a..7af88564 100644 --- a/resources/shaders/gl3/blit.vs.glsl +++ b/resources/shaders/gl3/blit.vs.glsl @@ -14,12 +14,16 @@ precision highp float; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main(){ - vTexCoord = aPosition; - gl_Position = vec4(mix(aPosition, vec2(- 1.0), vec2(1.0)), 0.0, 1.0); + vec2 texCoord = vec2(aPosition); + + + + vTexCoord = texCoord; + gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), vec2(aPosition)), 0.0, 1.0); } diff --git a/resources/shaders/gl3/mask.vs.glsl b/resources/shaders/gl3/mask.vs.glsl deleted file mode 100644 index b5a7a1e1..00000000 --- a/resources/shaders/gl3/mask.vs.glsl +++ /dev/null @@ -1,34 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - -precision highp float; - -in vec2 aPosition; -in vec2 aFillTexCoord; -in int aBackdrop; - -out vec2 vFillTexCoord; -out float vBackdrop; - -void main(){ - vec2 position = mix(vec2(- 1.0), vec2(1.0), aPosition); - - - - - vFillTexCoord = aFillTexCoord; - vBackdrop = float(aBackdrop); - gl_Position = vec4(position, 0.0, 1.0); -} - diff --git a/resources/shaders/gl3/mask_evenodd.fs.glsl b/resources/shaders/gl3/mask_evenodd.fs.glsl deleted file mode 100644 index 30f58910..00000000 --- a/resources/shaders/gl3/mask_evenodd.fs.glsl +++ /dev/null @@ -1,28 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - -precision highp float; - -uniform sampler2D uFillTexture; - -in vec2 vFillTexCoord; -in float vBackdrop; - -out vec4 oFragColor; - -void main(){ - float alpha = texture(uFillTexture, vFillTexCoord). r + vBackdrop; - oFragColor = vec4(1.0 - abs(1.0 - mod(alpha, 2.0))); -} - diff --git a/resources/shaders/gl3/mask_winding.fs.glsl b/resources/shaders/gl3/mask_winding.fs.glsl deleted file mode 100644 index e810930a..00000000 --- a/resources/shaders/gl3/mask_winding.fs.glsl +++ /dev/null @@ -1,27 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - -precision highp float; - -uniform sampler2D uFillTexture; - -in vec2 vFillTexCoord; -in float vBackdrop; - -out vec4 oFragColor; - -void main(){ - oFragColor = vec4(abs(texture(uFillTexture, vFillTexCoord). r + vBackdrop)); -} - diff --git a/resources/shaders/gl3/tile.fs.glsl b/resources/shaders/gl3/tile.fs.glsl new file mode 100644 index 00000000..a811e4ee --- /dev/null +++ b/resources/shaders/gl3/tile.fs.glsl @@ -0,0 +1,463 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#extension GL_GOOGLE_include_directive : enable + +precision highp float; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +uniform sampler2D uColorTexture0; +uniform sampler2D uColorTexture1; +uniform sampler2D uMaskTexture0; +uniform sampler2D uMaskTexture1; +uniform sampler2D uDestTexture; +uniform sampler2D uGammaLUT; +uniform vec4 uFilterParams0; +uniform vec4 uFilterParams1; +uniform vec4 uFilterParams2; +uniform vec2 uDestTextureSize; +uniform vec2 uColorTexture0Size; +uniform int uCtrl; + +in vec3 vMaskTexCoord0; +in vec3 vMaskTexCoord1; +in vec2 vColorTexCoord0; +in vec2 vColorTexCoord1; + +out vec4 oFragColor; + + + +vec4 sampleColor(sampler2D colorTexture, vec2 colorTexCoord){ + return texture(colorTexture, colorTexCoord); +} + + + +float filterTextSample1Tap(float offset, sampler2D colorTexture, vec2 colorTexCoord){ + return texture(colorTexture, colorTexCoord + vec2(offset, 0.0)). r; +} + + +void filterTextSample9Tap(out vec4 outAlphaLeft, + out float outAlphaCenter, + out vec4 outAlphaRight, + sampler2D colorTexture, + vec2 colorTexCoord, + vec4 kernel, + float onePixel){ + bool wide = kernel . x > 0.0; + outAlphaLeft = + vec4(wide ? filterTextSample1Tap(- 4.0 * onePixel, colorTexture, colorTexCoord): 0.0, + filterTextSample1Tap(- 3.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(- 2.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(- 1.0 * onePixel, colorTexture, colorTexCoord)); + outAlphaCenter = filterTextSample1Tap(0.0, colorTexture, colorTexCoord); + outAlphaRight = + vec4(filterTextSample1Tap(1.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(2.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(3.0 * onePixel, colorTexture, colorTexCoord), + wide ? filterTextSample1Tap(4.0 * onePixel, colorTexture, colorTexCoord): 0.0); +} + +float filterTextConvolve7Tap(vec4 alpha0, vec3 alpha1, vec4 kernel){ + return dot(alpha0, kernel)+ dot(alpha1, kernel . zyx); +} + +float filterTextGammaCorrectChannel(float bgColor, float fgColor, sampler2D gammaLUT){ + return texture(gammaLUT, vec2(fgColor, 1.0 - bgColor)). r; +} + + +vec3 filterTextGammaCorrect(vec3 bgColor, vec3 fgColor, sampler2D gammaLUT){ + return vec3(filterTextGammaCorrectChannel(bgColor . r, fgColor . r, gammaLUT), + filterTextGammaCorrectChannel(bgColor . g, fgColor . g, gammaLUT), + filterTextGammaCorrectChannel(bgColor . b, fgColor . b, gammaLUT)); +} + + + + + + +vec4 filterText(vec2 colorTexCoord, + sampler2D colorTexture, + sampler2D gammaLUT, + vec2 colorTextureSize, + vec4 filterParams0, + vec4 filterParams1, + vec4 filterParams2){ + + vec4 kernel = filterParams0; + vec3 bgColor = filterParams1 . rgb; + vec3 fgColor = filterParams2 . rgb; + bool gammaCorrectionEnabled = filterParams2 . a != 0.0; + + + vec3 alpha; + if(kernel . w == 0.0){ + alpha = texture(colorTexture, colorTexCoord). rrr; + } else { + vec4 alphaLeft, alphaRight; + float alphaCenter; + filterTextSample9Tap(alphaLeft, + alphaCenter, + alphaRight, + colorTexture, + colorTexCoord, + kernel, + 1.0 / colorTextureSize . x); + + float r = filterTextConvolve7Tap(alphaLeft, vec3(alphaCenter, alphaRight . xy), kernel); + float g = filterTextConvolve7Tap(vec4(alphaLeft . yzw, alphaCenter), alphaRight . xyz, kernel); + float b = filterTextConvolve7Tap(vec4(alphaLeft . zw, alphaCenter, alphaRight . x), + alphaRight . yzw, + kernel); + + alpha = vec3(r, g, b); + } + + + if(gammaCorrectionEnabled) + alpha = filterTextGammaCorrect(bgColor, alpha, gammaLUT); + + + return vec4(mix(bgColor, fgColor, alpha), 1.0); +} + + + + + + + + +vec4 filterBlur(vec2 colorTexCoord, + sampler2D colorTexture, + vec2 colorTextureSize, + vec4 filterParams0, + vec4 filterParams1){ + + vec2 srcOffsetScale = filterParams0 . xy / colorTextureSize; + int support = int(filterParams0 . z); + vec3 gaussCoeff = filterParams1 . xyz; + + + float gaussSum = gaussCoeff . x; + vec4 color = texture(colorTexture, colorTexCoord)* gaussCoeff . x; + gaussCoeff . xy *= gaussCoeff . yz; + + + + + + + + + + for(int i = 1;i <= support;i += 2){ + float gaussPartialSum = gaussCoeff . x; + gaussCoeff . xy *= gaussCoeff . yz; + gaussPartialSum += gaussCoeff . x; + + vec2 srcOffset = srcOffsetScale *(float(i)+ gaussCoeff . x / gaussPartialSum); + color +=(texture(colorTexture, colorTexCoord - srcOffset)+ + texture(colorTexture, colorTexCoord + srcOffset))* gaussPartialSum; + + gaussSum += 2.0 * gaussPartialSum; + gaussCoeff . xy *= gaussCoeff . yz; + } + + + return color / gaussSum; +} + +vec4 filterNone(vec2 colorTexCoord, sampler2D colorTexture){ + return sampleColor(colorTexture, colorTexCoord); +} + +vec4 filterColor(vec2 colorTexCoord, + sampler2D colorTexture, + sampler2D gammaLUT, + vec2 colorTextureSize, + vec4 filterParams0, + vec4 filterParams1, + vec4 filterParams2, + int colorFilter){ + switch(colorFilter){ + case 0x3 : + return filterBlur(colorTexCoord, + colorTexture, + colorTextureSize, + filterParams0, + filterParams1); + case 0x2 : + return filterText(colorTexCoord, + colorTexture, + gammaLUT, + colorTextureSize, + filterParams0, + filterParams1, + filterParams2); + } + return filterNone(colorTexCoord, colorTexture); +} + + + +vec3 compositeSelect(bvec3 cond, vec3 ifTrue, vec3 ifFalse){ + return vec3(cond . x ? ifTrue . x : ifFalse . x, + cond . y ? ifTrue . y : ifFalse . y, + cond . z ? ifTrue . z : ifFalse . z); +} + +float compositeDivide(float num, float denom){ + return denom != 0.0 ? num / denom : 0.0; +} + +vec3 compositeColorDodge(vec3 destColor, vec3 srcColor){ + bvec3 destZero = equal(destColor, vec3(0.0)), srcOne = equal(srcColor, vec3(1.0)); + return compositeSelect(destZero, + vec3(0.0), + compositeSelect(srcOne, vec3(1.0), destColor /(vec3(1.0)- srcColor))); +} + + +vec3 compositeHSLToRGB(vec3 hsl){ + float a = hsl . y * min(hsl . z, 1.0 - hsl . z); + vec3 ks = mod(vec3(0.0, 8.0, 4.0)+ vec3(hsl . x * 1.9098593171027443), 12.0); + return hsl . zzz - clamp(min(ks - vec3(3.0), vec3(9.0)- ks), - 1.0, 1.0)* a; +} + + +vec3 compositeRGBToHSL(vec3 rgb){ + float v = max(max(rgb . r, rgb . g), rgb . b), xMin = min(min(rgb . r, rgb . g), rgb . b); + float c = v - xMin, l = mix(xMin, v, 0.5); + vec3 terms = rgb . r == v ? vec3(0.0, rgb . gb): + rgb . g == v ? vec3(2.0, rgb . br): + vec3(4.0, rgb . rg); + float h = 1.0471975511965976 * compositeDivide(terms . x * c + terms . y - terms . z, c); + float s = compositeDivide(c, v); + return vec3(h, s, l); +} + +vec3 compositeScreen(vec3 destColor, vec3 srcColor){ + return destColor + srcColor - destColor * srcColor; +} + +vec3 compositeHardLight(vec3 destColor, vec3 srcColor){ + return compositeSelect(lessThanEqual(srcColor, vec3(0.5)), + destColor * vec3(2.0)* srcColor, + compositeScreen(destColor, vec3(2.0)* srcColor - vec3(1.0))); +} + +vec3 compositeSoftLight(vec3 destColor, vec3 srcColor){ + vec3 darkenedDestColor = + compositeSelect(lessThanEqual(destColor, vec3(0.25)), + ((vec3(16.0)* destColor - 12.0)* destColor + 4.0)* destColor, + sqrt(destColor)); + vec3 factor = compositeSelect(lessThanEqual(srcColor, vec3(0.5)), + destColor *(vec3(1.0)- destColor), + darkenedDestColor - destColor); + return destColor +(srcColor * 2.0 - 1.0)* factor; +} + +vec3 compositeHSL(vec3 destColor, vec3 srcColor, int op){ + switch(op){ + case 0xc : + return vec3(srcColor . x, destColor . y, destColor . z); + case 0xd : + return vec3(destColor . x, srcColor . y, destColor . z); + case 0xe : + return vec3(srcColor . x, srcColor . y, destColor . z); + default : + return vec3(destColor . x, destColor . y, srcColor . z); + } +} + +vec3 compositeRGB(vec3 destColor, vec3 srcColor, int op){ + switch(op){ + case 0x1 : + return destColor * srcColor; + case 0x2 : + return compositeScreen(destColor, srcColor); + case 0x3 : + return compositeHardLight(srcColor, destColor); + case 0x4 : + return min(destColor, srcColor); + case 0x5 : + return max(destColor, srcColor); + case 0x6 : + return compositeColorDodge(destColor, srcColor); + case 0x7 : + return vec3(1.0)- compositeColorDodge(vec3(1.0)- destColor, vec3(1.0)- srcColor); + case 0x8 : + return compositeHardLight(destColor, srcColor); + case 0x9 : + return compositeSoftLight(destColor, srcColor); + case 0xa : + return abs(destColor - srcColor); + case 0xb : + return destColor + srcColor - vec3(2.0)* destColor * srcColor; + case 0xc : + case 0xd : + case 0xe : + case 0xf : + return compositeHSLToRGB(compositeHSL(compositeRGBToHSL(destColor), + compositeRGBToHSL(srcColor), + op)); + } + return srcColor; +} + +vec4 composite(vec4 srcColor, + sampler2D destTexture, + vec2 destTextureSize, + vec2 fragCoord, + int op){ + if(op == 0x0) + return srcColor; + + + vec2 destTexCoord = fragCoord / destTextureSize; + vec4 destColor = texture(destTexture, destTexCoord); + vec3 blendedRGB = compositeRGB(destColor . rgb, srcColor . rgb, op); + return vec4(srcColor . a *(1.0 - destColor . a)* srcColor . rgb + + srcColor . a * destColor . a * blendedRGB + + (1.0 - srcColor . a)* destColor . rgb, + 1.0); +} + + + +float sampleMask(float maskAlpha, + sampler2D maskTexture, + vec3 maskTexCoord, + int maskCtrl){ + if(maskCtrl == 0) + return maskAlpha; + float coverage = texture(maskTexture, maskTexCoord . xy). r + maskTexCoord . z; + if((maskCtrl & 0x1)!= 0) + coverage = abs(coverage); + else + coverage = 1.0 - abs(1.0 - mod(coverage, 2.0)); + return min(maskAlpha, coverage); +} + + + +void calculateColor(int ctrl){ + + int maskCtrl0 =(ctrl >> 0)& 0x3; + int maskCtrl1 =(ctrl >> 2)& 0x3; + float maskAlpha = 1.0; + maskAlpha = sampleMask(maskAlpha, uMaskTexture0, vMaskTexCoord0, maskCtrl0); + maskAlpha = sampleMask(maskAlpha, uMaskTexture1, vMaskTexCoord1, maskCtrl1); + + + vec4 color = vec4(0.0); + if(((ctrl >> 6)& 0x1)!= 0){ + int color0Filter =(ctrl >> 4)& + 0x3; + color += filterColor(vColorTexCoord0, + uColorTexture0, + uGammaLUT, + uColorTexture0Size, + uFilterParams0, + uFilterParams1, + uFilterParams2, + color0Filter); + } + if(((ctrl >> 7)& 0x1)!= 0) + color *= sampleColor(uColorTexture1, vColorTexCoord1); + + + color . a *= maskAlpha; + + + int compositeOp =(ctrl >> 8)& 0xf; + color = composite(color, uDestTexture, uDestTextureSize, gl_FragCoord . xy, compositeOp); + + + color . rgb *= color . a; + oFragColor = color; +} + + + + + +void main(){ + calculateColor(uCtrl); +} + diff --git a/resources/shaders/gl3/tile.vs.glsl b/resources/shaders/gl3/tile.vs.glsl new file mode 100644 index 00000000..e49ee79c --- /dev/null +++ b/resources/shaders/gl3/tile.vs.glsl @@ -0,0 +1,40 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + +precision highp float; + +uniform mat4 uTransform; +uniform vec2 uTileSize; + +in ivec2 aTilePosition; +in vec2 aColorTexCoord0; +in vec2 aColorTexCoord1; +in vec2 aMaskTexCoord0; +in vec2 aMaskTexCoord1; +in ivec2 aMaskBackdrop; + +out vec3 vMaskTexCoord0; +out vec3 vMaskTexCoord1; +out vec2 vColorTexCoord0; +out vec2 vColorTexCoord1; + +void main(){ + vec2 position = vec2(aTilePosition)* uTileSize; + vColorTexCoord0 = aColorTexCoord0; + vColorTexCoord1 = aColorTexCoord1; + vMaskTexCoord0 = vec3(aMaskTexCoord0, float(aMaskBackdrop . x)); + vMaskTexCoord1 = vec3(aMaskTexCoord1, float(aMaskBackdrop . y)); + gl_Position = uTransform * vec4(position, 0.0, 1.0); +} + diff --git a/resources/shaders/gl3/tile_alpha.fs.glsl b/resources/shaders/gl3/tile_alpha.fs.glsl deleted file mode 100644 index af6cae62..00000000 --- a/resources/shaders/gl3/tile_alpha.fs.glsl +++ /dev/null @@ -1,70 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -out vec4 oFragColor; - - - - - - - - - - - - -uniform sampler2D uStencilTexture; -uniform sampler2D uPaintTexture; -uniform sampler2D uDest; -uniform vec2 uFramebufferSize; - -in vec2 vColorTexCoord; -in vec2 vMaskTexCoord; -in float vOpacity; - - -vec4 sampleSrcColor(){ - float coverage = texture(uStencilTexture, vMaskTexCoord). r; - vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); - return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity); -} - -vec4 sampleDestColor(){ - vec2 destTexCoord = gl_FragCoord . xy / uFramebufferSize; - return texture(uDest, destTexCoord); -} - - -vec4 blendColors(vec4 destRGBA, vec4 srcRGBA, vec3 blendedRGB){ - return vec4(srcRGBA . a *(1.0 - destRGBA . a)* srcRGBA . rgb + - srcRGBA . a * destRGBA . a * blendedRGB + - (1.0 - srcRGBA . a)* destRGBA . a * destRGBA . rgb, - 1.0); -} - -vec3 select3(bvec3 cond, vec3 a, vec3 b){ - return vec3(cond . x ? a . x : b . x, cond . y ? a . y : b . y, cond . z ? a . z : b . z); -} - - -void main(){ - vec4 srcRGBA = sampleSrcColor(); - oFragColor = vec4(srcRGBA . rgb * srcRGBA . a, srcRGBA . a); -} - diff --git a/resources/shaders/gl3/tile_alpha.vs.glsl b/resources/shaders/gl3/tile_alpha.vs.glsl deleted file mode 100644 index 1a1d565d..00000000 --- a/resources/shaders/gl3/tile_alpha.vs.glsl +++ /dev/null @@ -1,37 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - -precision highp float; - -uniform mat4 uTransform; -uniform vec2 uTileSize; - -in ivec2 aTilePosition; -in vec2 aColorTexCoord; -in vec2 aMaskTexCoord; -in float aOpacity; - -out vec2 vColorTexCoord; -out vec2 vMaskTexCoord; -out float vOpacity; - -void main(){ - vec2 position = vec2(aTilePosition)* uTileSize; - - vMaskTexCoord = aMaskTexCoord; - vColorTexCoord = aColorTexCoord; - vOpacity = aOpacity; - gl_Position = uTransform * vec4(position, 0.0, 1.0); -} - diff --git a/resources/shaders/gl3/tile_alpha_difference.fs.glsl b/resources/shaders/gl3/tile_alpha_difference.fs.glsl deleted file mode 100644 index 1c61a8b6..00000000 --- a/resources/shaders/gl3/tile_alpha_difference.fs.glsl +++ /dev/null @@ -1,76 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - - - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -out vec4 oFragColor; - - - - - - - - - - - - -uniform sampler2D uStencilTexture; -uniform sampler2D uPaintTexture; -uniform sampler2D uDest; -uniform vec2 uFramebufferSize; - -in vec2 vColorTexCoord; -in vec2 vMaskTexCoord; -in float vOpacity; - - -vec4 sampleSrcColor(){ - float coverage = texture(uStencilTexture, vMaskTexCoord). r; - vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); - return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity); -} - -vec4 sampleDestColor(){ - vec2 destTexCoord = gl_FragCoord . xy / uFramebufferSize; - return texture(uDest, destTexCoord); -} - - -vec4 blendColors(vec4 destRGBA, vec4 srcRGBA, vec3 blendedRGB){ - return vec4(srcRGBA . a *(1.0 - destRGBA . a)* srcRGBA . rgb + - srcRGBA . a * destRGBA . a * blendedRGB + - (1.0 - srcRGBA . a)* destRGBA . a * destRGBA . rgb, - 1.0); -} - -vec3 select3(bvec3 cond, vec3 a, vec3 b){ - return vec3(cond . x ? a . x : b . x, cond . y ? a . y : b . y, cond . z ? a . z : b . z); -} - - -void main(){ - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - vec3 blended = abs(destRGBA . rgb - srcRGBA . rgb); - - oFragColor = blendColors(destRGBA, srcRGBA, blended); -} - diff --git a/resources/shaders/gl3/tile_alpha_dodgeburn.fs.glsl b/resources/shaders/gl3/tile_alpha_dodgeburn.fs.glsl deleted file mode 100644 index 7b501af2..00000000 --- a/resources/shaders/gl3/tile_alpha_dodgeburn.fs.glsl +++ /dev/null @@ -1,87 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - - - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -uniform int uBurn; - -out vec4 oFragColor; - - - - - - - - - - - - -uniform sampler2D uStencilTexture; -uniform sampler2D uPaintTexture; -uniform sampler2D uDest; -uniform vec2 uFramebufferSize; - -in vec2 vColorTexCoord; -in vec2 vMaskTexCoord; -in float vOpacity; - - -vec4 sampleSrcColor(){ - float coverage = texture(uStencilTexture, vMaskTexCoord). r; - vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); - return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity); -} - -vec4 sampleDestColor(){ - vec2 destTexCoord = gl_FragCoord . xy / uFramebufferSize; - return texture(uDest, destTexCoord); -} - - -vec4 blendColors(vec4 destRGBA, vec4 srcRGBA, vec3 blendedRGB){ - return vec4(srcRGBA . a *(1.0 - destRGBA . a)* srcRGBA . rgb + - srcRGBA . a * destRGBA . a * blendedRGB + - (1.0 - srcRGBA . a)* destRGBA . a * destRGBA . rgb, - 1.0); -} - -vec3 select3(bvec3 cond, vec3 a, vec3 b){ - return vec3(cond . x ? a . x : b . x, cond . y ? a . y : b . y, cond . z ? a . z : b . z); -} - - -void main(){ - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - vec3 dest = uBurn == 0 ? destRGBA . rgb : vec3(1.0)- destRGBA . rgb; - vec3 src = uBurn == 0 ? vec3(1.0)- srcRGBA . rgb : srcRGBA . rgb; - - bvec3 srcNonzero = notEqual(src, vec3(0.0)); - vec3 blended = min(vec3(srcNonzero . x ? dest . x / src . x : 1.0, - srcNonzero . y ? dest . y / src . y : 1.0, - srcNonzero . z ? dest . z / src . z : 1.0), - vec3(1.0)); - if(uBurn != 0) - blended = vec3(1.0)- blended; - - oFragColor = blendColors(destRGBA, srcRGBA, blended); -} - diff --git a/resources/shaders/gl3/tile_alpha_exclusion.fs.glsl b/resources/shaders/gl3/tile_alpha_exclusion.fs.glsl deleted file mode 100644 index dc6e8fae..00000000 --- a/resources/shaders/gl3/tile_alpha_exclusion.fs.glsl +++ /dev/null @@ -1,77 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - - - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -out vec4 oFragColor; - - - - - - - - - - - - -uniform sampler2D uStencilTexture; -uniform sampler2D uPaintTexture; -uniform sampler2D uDest; -uniform vec2 uFramebufferSize; - -in vec2 vColorTexCoord; -in vec2 vMaskTexCoord; -in float vOpacity; - - -vec4 sampleSrcColor(){ - float coverage = texture(uStencilTexture, vMaskTexCoord). r; - vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); - return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity); -} - -vec4 sampleDestColor(){ - vec2 destTexCoord = gl_FragCoord . xy / uFramebufferSize; - return texture(uDest, destTexCoord); -} - - -vec4 blendColors(vec4 destRGBA, vec4 srcRGBA, vec3 blendedRGB){ - return vec4(srcRGBA . a *(1.0 - destRGBA . a)* srcRGBA . rgb + - srcRGBA . a * destRGBA . a * blendedRGB + - (1.0 - srcRGBA . a)* destRGBA . a * destRGBA . rgb, - 1.0); -} - -vec3 select3(bvec3 cond, vec3 a, vec3 b){ - return vec3(cond . x ? a . x : b . x, cond . y ? a . y : b . y, cond . z ? a . z : b . z); -} - - -void main(){ - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - vec3 dest = destRGBA . rgb, src = srcRGBA . rgb; - vec3 blended = dest + src - dest * src * 2.0; - - oFragColor = blendColors(destRGBA, srcRGBA, blended); -} - diff --git a/resources/shaders/gl3/tile_alpha_hsl.fs.glsl b/resources/shaders/gl3/tile_alpha_hsl.fs.glsl deleted file mode 100644 index 278cccf6..00000000 --- a/resources/shaders/gl3/tile_alpha_hsl.fs.glsl +++ /dev/null @@ -1,116 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -uniform ivec3 uBlendHSL; - -out vec4 oFragColor; - - - - - - - - - - - - -uniform sampler2D uStencilTexture; -uniform sampler2D uPaintTexture; -uniform sampler2D uDest; -uniform vec2 uFramebufferSize; - -in vec2 vColorTexCoord; -in vec2 vMaskTexCoord; -in float vOpacity; - - -vec4 sampleSrcColor(){ - float coverage = texture(uStencilTexture, vMaskTexCoord). r; - vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); - return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity); -} - -vec4 sampleDestColor(){ - vec2 destTexCoord = gl_FragCoord . xy / uFramebufferSize; - return texture(uDest, destTexCoord); -} - - -vec4 blendColors(vec4 destRGBA, vec4 srcRGBA, vec3 blendedRGB){ - return vec4(srcRGBA . a *(1.0 - destRGBA . a)* srcRGBA . rgb + - srcRGBA . a * destRGBA . a * blendedRGB + - (1.0 - srcRGBA . a)* destRGBA . a * destRGBA . rgb, - 1.0); -} - -vec3 select3(bvec3 cond, vec3 a, vec3 b){ - return vec3(cond . x ? a . x : b . x, cond . y ? a . y : b . y, cond . z ? a . z : b . z); -} - - - - - - - - - - -vec3 convertHSLToRGB(vec3 hsl){ - float a = hsl . y * min(hsl . z, 1.0 - hsl . z); - vec3 ks = mod(vec3(0.0, 8.0, 4.0)+ vec3(hsl . x * 1.9098593171027443), 12.0); - return hsl . zzz - clamp(min(ks - vec3(3.0), vec3(9.0)- ks), - 1.0, 1.0)* a; -} - - -vec3 convertRGBToHSL(vec3 rgb){ - float v = max((rgb . x, rgb . y), rgb . z); - float c = v - min((rgb . x, rgb . y), rgb . z); - float l = v - 0.5 * c; - - vec3 tmp = vec3(0.0); - bvec3 is_v = equal(rgb, vec3(v)); - if(is_v . r) - tmp = vec3(0.0, rgb . gb); - else if(is_v . g) - tmp = vec3(2.0, rgb . br); - else if(is_v . b) - tmp = vec3(4.0, rgb . rg); - float h = 1.0471975511965976 *(tmp . x +(tmp . y - tmp . z)/ c); - - float s = 0.0; - if(l > 0.0 && l < 1.0) - s =(v - l)/ min(l, 1.0 - l); - - return vec3(h, s, l); -} - -void main(){ - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - vec3 destHSL = convertRGBToHSL(destRGBA . rgb); - vec3 srcHSL = convertRGBToHSL(srcRGBA . rgb); - vec3 blendedHSL = select3(equal(uBlendHSL, ivec3(0)), destHSL, srcHSL); - vec3 blendedRGB = convertHSLToRGB(blendedHSL); - - oFragColor = blendColors(destRGBA, srcRGBA, blendedRGB); -} - diff --git a/resources/shaders/gl3/tile_alpha_overlay.fs.glsl b/resources/shaders/gl3/tile_alpha_overlay.fs.glsl deleted file mode 100644 index 4d352986..00000000 --- a/resources/shaders/gl3/tile_alpha_overlay.fs.glsl +++ /dev/null @@ -1,97 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - - - -#extension GL_GOOGLE_include_directive : enable - - - - - - -precision highp float; - -uniform int uBlendMode; - -out vec4 oFragColor; - - - - - - - - - - - - -uniform sampler2D uStencilTexture; -uniform sampler2D uPaintTexture; -uniform sampler2D uDest; -uniform vec2 uFramebufferSize; - -in vec2 vColorTexCoord; -in vec2 vMaskTexCoord; -in float vOpacity; - - -vec4 sampleSrcColor(){ - float coverage = texture(uStencilTexture, vMaskTexCoord). r; - vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); - return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity); -} - -vec4 sampleDestColor(){ - vec2 destTexCoord = gl_FragCoord . xy / uFramebufferSize; - return texture(uDest, destTexCoord); -} - - -vec4 blendColors(vec4 destRGBA, vec4 srcRGBA, vec3 blendedRGB){ - return vec4(srcRGBA . a *(1.0 - destRGBA . a)* srcRGBA . rgb + - srcRGBA . a * destRGBA . a * blendedRGB + - (1.0 - srcRGBA . a)* destRGBA . a * destRGBA . rgb, - 1.0); -} - -vec3 select3(bvec3 cond, vec3 a, vec3 b){ - return vec3(cond . x ? a . x : b . x, cond . y ? a . y : b . y, cond . z ? a . z : b . z); -} - - -void main(){ - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - bool reversed = uBlendMode == 3; - vec3 src = reversed ? srcRGBA . rgb : destRGBA . rgb; - vec3 dest = reversed ? destRGBA . rgb : srcRGBA . rgb; - - vec3 multiply = src * dest; - vec3 blended; - if(uBlendMode == 0){ - blended = multiply; - } else { - vec3 screen = dest + src - multiply; - if(uBlendMode == 1) - blended = screen; - else - blended = select3(lessThanEqual(src, vec3(0.5)), multiply, screen * 2.0 - 1.0); - } - - oFragColor = blendColors(destRGBA, srcRGBA, blended); -} - diff --git a/resources/shaders/gl3/tile_alpha_softlight.fs.glsl b/resources/shaders/gl3/tile_alpha_softlight.fs.glsl deleted file mode 100644 index e1a00f65..00000000 --- a/resources/shaders/gl3/tile_alpha_softlight.fs.glsl +++ /dev/null @@ -1,83 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - - - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -out vec4 oFragColor; - - - - - - - - - - - - -uniform sampler2D uStencilTexture; -uniform sampler2D uPaintTexture; -uniform sampler2D uDest; -uniform vec2 uFramebufferSize; - -in vec2 vColorTexCoord; -in vec2 vMaskTexCoord; -in float vOpacity; - - -vec4 sampleSrcColor(){ - float coverage = texture(uStencilTexture, vMaskTexCoord). r; - vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); - return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity); -} - -vec4 sampleDestColor(){ - vec2 destTexCoord = gl_FragCoord . xy / uFramebufferSize; - return texture(uDest, destTexCoord); -} - - -vec4 blendColors(vec4 destRGBA, vec4 srcRGBA, vec3 blendedRGB){ - return vec4(srcRGBA . a *(1.0 - destRGBA . a)* srcRGBA . rgb + - srcRGBA . a * destRGBA . a * blendedRGB + - (1.0 - srcRGBA . a)* destRGBA . a * destRGBA . rgb, - 1.0); -} - -vec3 select3(bvec3 cond, vec3 a, vec3 b){ - return vec3(cond . x ? a . x : b . x, cond . y ? a . y : b . y, cond . z ? a . z : b . z); -} - - -void main(){ - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - - - - vec3 dest = destRGBA . rgb, src = srcRGBA . rgb; - bvec3 destDark = lessThanEqual(dest, vec3(0.25)), srcDark = lessThanEqual(src, vec3(0.5)); - vec3 d = select3(destDark,(dest * 16.0 - 12.0)* dest + 4.0, inversesqrt(dest)); - vec3 x = select3(srcDark, vec3(1.0)- dest, d - 1.0); - vec3 blended = dest *((src * 2.0 - 1.0)* x + 1.0); - - oFragColor = blendColors(destRGBA, srcRGBA, blended); -} - diff --git a/resources/shaders/gl3/tile_solid.fs.glsl b/resources/shaders/gl3/tile_solid.fs.glsl deleted file mode 100644 index e3c9c942..00000000 --- a/resources/shaders/gl3/tile_solid.fs.glsl +++ /dev/null @@ -1,27 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - -precision highp float; - -uniform sampler2D uColorTexture; - -in vec2 vColorTexCoord; - -out vec4 oFragColor; - -void main(){ - vec4 color = texture(uColorTexture, vColorTexCoord); - oFragColor = vec4(color . rgb * color . a, color . a); -} - diff --git a/resources/shaders/gl3/tile_solid.vs.glsl b/resources/shaders/gl3/tile_solid.vs.glsl deleted file mode 100644 index ce32a520..00000000 --- a/resources/shaders/gl3/tile_solid.vs.glsl +++ /dev/null @@ -1,30 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - -precision highp float; - -uniform mat4 uTransform; -uniform vec2 uTileSize; - -in ivec2 aTilePosition; -in vec2 aColorTexCoord; - -out vec2 vColorTexCoord; - -void main(){ - vec2 position = vec2(aTilePosition)* uTileSize; - vColorTexCoord = aColorTexCoord; - gl_Position = uTransform * vec4(position, 0.0, 1.0); -} - diff --git a/resources/shaders/gl3/tile_solid_filter_blur.fs.glsl b/resources/shaders/gl3/tile_solid_filter_blur.fs.glsl deleted file mode 100644 index 90418115..00000000 --- a/resources/shaders/gl3/tile_solid_filter_blur.fs.glsl +++ /dev/null @@ -1,69 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - - - - - - - - - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -uniform sampler2D uColorTexture; -uniform vec2 uSrcOffsetScale; -uniform vec3 uInitialGaussCoeff; -uniform int uSupport; - -in vec2 vColorTexCoord; - -out vec4 oFragColor; - -void main(){ - - vec3 gaussCoeff = uInitialGaussCoeff; - float gaussSum = gaussCoeff . x; - vec4 color = texture(uColorTexture, vColorTexCoord)* gaussCoeff . x; - gaussCoeff . xy *= gaussCoeff . yz; - - - - - - - - - - for(int i = 1;i <= uSupport;i += 2){ - float gaussPartialSum = gaussCoeff . x; - gaussCoeff . xy *= gaussCoeff . yz; - gaussPartialSum += gaussCoeff . x; - - vec2 srcOffset = uSrcOffsetScale *(float(i)+ gaussCoeff . x / gaussPartialSum); - color +=(texture(uColorTexture, vColorTexCoord - srcOffset)+ - texture(uColorTexture, vColorTexCoord + srcOffset))* gaussPartialSum; - - gaussSum += 2.0 * gaussPartialSum; - gaussCoeff . xy *= gaussCoeff . yz; - } - - - color /= gaussSum; - color . rgb *= color . a; - oFragColor = color; -} - diff --git a/resources/shaders/gl3/tile_solid_filter_text.fs.glsl b/resources/shaders/gl3/tile_solid_filter_text.fs.glsl deleted file mode 100644 index a2ecb916..00000000 --- a/resources/shaders/gl3/tile_solid_filter_text.fs.glsl +++ /dev/null @@ -1,124 +0,0 @@ -#version {{version}} -// Automatically generated from files in pathfinder/shaders/. Do not edit! - - - - - - - - - - - - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -uniform sampler2D uColorTexture; -uniform vec2 uSrcSize; -uniform vec4 uFGColor; -uniform vec4 uBGColor; -uniform int uGammaCorrectionEnabled; - -in vec2 vColorTexCoord; - -out vec4 oFragColor; - - - - - - - - - - - - - - -uniform sampler2D uGammaLUT; - -float gammaCorrectChannel(float bgColor, float fgColor){ - return texture(uGammaLUT, vec2(fgColor, 1.0 - bgColor)). r; -} - - -vec3 gammaCorrect(vec3 bgColor, vec3 fgColor){ - return vec3(gammaCorrectChannel(bgColor . r, fgColor . r), - gammaCorrectChannel(bgColor . g, fgColor . g), - gammaCorrectChannel(bgColor . b, fgColor . b)); -} - - - - - - - - - - - - - -uniform vec4 uKernel; - - - -float sample1Tap(float offset); - - -void sample9Tap(out vec4 outAlphaLeft, - out float outAlphaCenter, - out vec4 outAlphaRight, - float onePixel){ - outAlphaLeft = vec4(uKernel . x > 0.0 ? sample1Tap(- 4.0 * onePixel): 0.0, - sample1Tap(- 3.0 * onePixel), - sample1Tap(- 2.0 * onePixel), - sample1Tap(- 1.0 * onePixel)); - outAlphaCenter = sample1Tap(0.0); - outAlphaRight = vec4(sample1Tap(1.0 * onePixel), - sample1Tap(2.0 * onePixel), - sample1Tap(3.0 * onePixel), - uKernel . x > 0.0 ? sample1Tap(4.0 * onePixel): 0.0); -} - - -float convolve7Tap(vec4 alpha0, vec3 alpha1){ - return dot(alpha0, uKernel)+ dot(alpha1, uKernel . zyx); -} - - - -float sample1Tap(float offset){ - return texture(uColorTexture, vec2(vColorTexCoord . x + offset, vColorTexCoord . y)). r; -} - -void main(){ - - vec3 alpha; - if(uKernel . w == 0.0){ - alpha = texture(uColorTexture, vColorTexCoord). rrr; - } else { - vec4 alphaLeft, alphaRight; - float alphaCenter; - sample9Tap(alphaLeft, alphaCenter, alphaRight, 1.0 / uSrcSize . x); - - float r = convolve7Tap(alphaLeft, vec3(alphaCenter, alphaRight . xy)); - float g = convolve7Tap(vec4(alphaLeft . yzw, alphaCenter), alphaRight . xyz); - float b = convolve7Tap(vec4(alphaLeft . zw, alphaCenter, alphaRight . x), alphaRight . yzw); - - alpha = vec3(r, g, b); - } - - - if(uGammaCorrectionEnabled != 0) - alpha = gammaCorrect(uBGColor . rgb, alpha); - - - oFragColor = vec4(mix(uBGColor . rgb, uFGColor . rgb, alpha), 1.0); -} - diff --git a/resources/shaders/metal/blit.vs.metal b/resources/shaders/metal/blit.vs.metal index 38e49044..701d97f0 100644 --- a/resources/shaders/metal/blit.vs.metal +++ b/resources/shaders/metal/blit.vs.metal @@ -12,14 +12,16 @@ struct main0_out struct main0_in { - float2 aPosition [[attribute(0)]]; + int2 aPosition [[attribute(0)]]; }; vertex main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - out.vTexCoord = in.aPosition; - out.gl_Position = float4(mix(in.aPosition, float2(-1.0), float2(1.0)), 0.0, 1.0); + float2 texCoord = float2(in.aPosition); + texCoord.y = 1.0 - texCoord.y; + out.vTexCoord = texCoord; + out.gl_Position = float4(mix(float2(-1.0), float2(1.0), float2(in.aPosition)), 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/mask.vs.metal b/resources/shaders/metal/mask.vs.metal deleted file mode 100644 index b5698991..00000000 --- a/resources/shaders/metal/mask.vs.metal +++ /dev/null @@ -1,31 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#include -#include - -using namespace metal; - -struct main0_out -{ - float2 vFillTexCoord [[user(locn0)]]; - float vBackdrop [[user(locn1)]]; - float4 gl_Position [[position]]; -}; - -struct main0_in -{ - float2 aPosition [[attribute(0)]]; - float2 aFillTexCoord [[attribute(1)]]; - int aBackdrop [[attribute(2)]]; -}; - -vertex main0_out main0(main0_in in [[stage_in]]) -{ - main0_out out = {}; - float2 position = mix(float2(-1.0), float2(1.0), in.aPosition); - position.y = -position.y; - out.vFillTexCoord = in.aFillTexCoord; - out.vBackdrop = float(in.aBackdrop); - out.gl_Position = float4(position, 0.0, 1.0); - return out; -} - diff --git a/resources/shaders/metal/mask_evenodd.fs.metal b/resources/shaders/metal/mask_evenodd.fs.metal deleted file mode 100644 index 8ecd4c23..00000000 --- a/resources/shaders/metal/mask_evenodd.fs.metal +++ /dev/null @@ -1,40 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - texture2d uFillTexture [[id(0)]]; - sampler uFillTextureSmplr [[id(1)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vFillTexCoord [[user(locn0)]]; - float vBackdrop [[user(locn1)]]; -}; - -// Implementation of the GLSL mod() function, which is slightly different than Metal fmod() -template -Tx mod(Tx x, Ty y) -{ - return x - y * floor(x / y); -} - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) -{ - main0_out out = {}; - float alpha = spvDescriptorSet0.uFillTexture.sample(spvDescriptorSet0.uFillTextureSmplr, in.vFillTexCoord).x + in.vBackdrop; - out.oFragColor = float4(1.0 - abs(1.0 - mod(alpha, 2.0))); - return out; -} - diff --git a/resources/shaders/metal/mask_winding.fs.metal b/resources/shaders/metal/mask_winding.fs.metal deleted file mode 100644 index c59d0cbe..00000000 --- a/resources/shaders/metal/mask_winding.fs.metal +++ /dev/null @@ -1,30 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - texture2d uFillTexture [[id(0)]]; - sampler uFillTextureSmplr [[id(1)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vFillTexCoord [[user(locn0)]]; - float vBackdrop [[user(locn1)]]; -}; - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) -{ - main0_out out = {}; - out.oFragColor = float4(abs(spvDescriptorSet0.uFillTexture.sample(spvDescriptorSet0.uFillTextureSmplr, in.vFillTexCoord).x + in.vBackdrop)); - return out; -} - diff --git a/resources/shaders/metal/tile.fs.metal b/resources/shaders/metal/tile.fs.metal new file mode 100644 index 00000000..da381fb9 --- /dev/null +++ b/resources/shaders/metal/tile.fs.metal @@ -0,0 +1,540 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct spvDescriptorSetBuffer0 +{ + texture2d uMaskTexture0 [[id(0)]]; + sampler uMaskTexture0Smplr [[id(1)]]; + texture2d uMaskTexture1 [[id(2)]]; + sampler uMaskTexture1Smplr [[id(3)]]; + texture2d uColorTexture0 [[id(4)]]; + sampler uColorTexture0Smplr [[id(5)]]; + texture2d uGammaLUT [[id(6)]]; + sampler uGammaLUTSmplr [[id(7)]]; + constant float2* uColorTexture0Size [[id(8)]]; + constant float4* uFilterParams0 [[id(9)]]; + constant float4* uFilterParams1 [[id(10)]]; + constant float4* uFilterParams2 [[id(11)]]; + texture2d uColorTexture1 [[id(12)]]; + sampler uColorTexture1Smplr [[id(13)]]; + texture2d uDestTexture [[id(14)]]; + sampler uDestTextureSmplr [[id(15)]]; + constant float2* uDestTextureSize [[id(16)]]; + constant int* uCtrl [[id(17)]]; +}; + +constant float3 _862 = {}; + +struct main0_out +{ + float4 oFragColor [[color(0)]]; +}; + +struct main0_in +{ + float3 vMaskTexCoord0 [[user(locn0)]]; + float3 vMaskTexCoord1 [[user(locn1)]]; + float2 vColorTexCoord0 [[user(locn2)]]; + float2 vColorTexCoord1 [[user(locn3)]]; +}; + +// Implementation of the GLSL mod() function, which is slightly different than Metal fmod() +template +Tx mod(Tx x, Ty y) +{ + return x - y * floor(x / y); +} + +float sampleMask(thread const float& maskAlpha, thread const texture2d maskTexture, thread const sampler maskTextureSmplr, thread const float3& maskTexCoord, thread const int& maskCtrl) +{ + if (maskCtrl == 0) + { + return maskAlpha; + } + float coverage = maskTexture.sample(maskTextureSmplr, maskTexCoord.xy).x + maskTexCoord.z; + if ((maskCtrl & 1) != 0) + { + coverage = abs(coverage); + } + else + { + coverage = 1.0 - abs(1.0 - mod(coverage, 2.0)); + } + return fast::min(maskAlpha, coverage); +} + +float4 filterBlur(thread const float2& colorTexCoord, thread const texture2d colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTextureSize, thread const float4& filterParams0, thread const float4& filterParams1) +{ + float2 srcOffsetScale = filterParams0.xy / colorTextureSize; + int support = int(filterParams0.z); + float3 gaussCoeff = filterParams1.xyz; + float gaussSum = gaussCoeff.x; + float4 color = colorTexture.sample(colorTextureSmplr, colorTexCoord) * gaussCoeff.x; + float2 _435 = gaussCoeff.xy * gaussCoeff.yz; + gaussCoeff = float3(_435.x, _435.y, gaussCoeff.z); + for (int i = 1; i <= support; i += 2) + { + float gaussPartialSum = gaussCoeff.x; + float2 _455 = gaussCoeff.xy * gaussCoeff.yz; + gaussCoeff = float3(_455.x, _455.y, gaussCoeff.z); + gaussPartialSum += gaussCoeff.x; + float2 srcOffset = srcOffsetScale * (float(i) + (gaussCoeff.x / gaussPartialSum)); + color += ((colorTexture.sample(colorTextureSmplr, (colorTexCoord - srcOffset)) + colorTexture.sample(colorTextureSmplr, (colorTexCoord + srcOffset))) * gaussPartialSum); + gaussSum += (2.0 * gaussPartialSum); + float2 _495 = gaussCoeff.xy * gaussCoeff.yz; + gaussCoeff = float3(_495.x, _495.y, gaussCoeff.z); + } + return color / float4(gaussSum); +} + +float filterTextSample1Tap(thread const float& offset, thread const texture2d colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTexCoord) +{ + return colorTexture.sample(colorTextureSmplr, (colorTexCoord + float2(offset, 0.0))).x; +} + +void filterTextSample9Tap(thread float4& outAlphaLeft, thread float& outAlphaCenter, thread float4& outAlphaRight, thread const texture2d colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTexCoord, thread const float4& kernel0, thread const float& onePixel) +{ + bool wide = kernel0.x > 0.0; + float _183; + if (wide) + { + float param = (-4.0) * onePixel; + float2 param_1 = colorTexCoord; + _183 = filterTextSample1Tap(param, colorTexture, colorTextureSmplr, param_1); + } + else + { + _183 = 0.0; + } + float param_2 = (-3.0) * onePixel; + float2 param_3 = colorTexCoord; + float param_4 = (-2.0) * onePixel; + float2 param_5 = colorTexCoord; + float param_6 = (-1.0) * onePixel; + float2 param_7 = colorTexCoord; + outAlphaLeft = float4(_183, filterTextSample1Tap(param_2, colorTexture, colorTextureSmplr, param_3), filterTextSample1Tap(param_4, colorTexture, colorTextureSmplr, param_5), filterTextSample1Tap(param_6, colorTexture, colorTextureSmplr, param_7)); + float param_8 = 0.0; + float2 param_9 = colorTexCoord; + outAlphaCenter = filterTextSample1Tap(param_8, colorTexture, colorTextureSmplr, param_9); + float param_10 = 1.0 * onePixel; + float2 param_11 = colorTexCoord; + float param_12 = 2.0 * onePixel; + float2 param_13 = colorTexCoord; + float param_14 = 3.0 * onePixel; + float2 param_15 = colorTexCoord; + float _243; + if (wide) + { + float param_16 = 4.0 * onePixel; + float2 param_17 = colorTexCoord; + _243 = filterTextSample1Tap(param_16, colorTexture, colorTextureSmplr, param_17); + } + else + { + _243 = 0.0; + } + outAlphaRight = float4(filterTextSample1Tap(param_10, colorTexture, colorTextureSmplr, param_11), filterTextSample1Tap(param_12, colorTexture, colorTextureSmplr, param_13), filterTextSample1Tap(param_14, colorTexture, colorTextureSmplr, param_15), _243); +} + +float filterTextConvolve7Tap(thread const float4& alpha0, thread const float3& alpha1, thread const float4& kernel0) +{ + return dot(alpha0, kernel0) + dot(alpha1, kernel0.zyx); +} + +float filterTextGammaCorrectChannel(thread const float& bgColor, thread const float& fgColor, thread const texture2d gammaLUT, thread const sampler gammaLUTSmplr) +{ + return gammaLUT.sample(gammaLUTSmplr, float2(fgColor, 1.0 - bgColor)).x; +} + +float3 filterTextGammaCorrect(thread const float3& bgColor, thread const float3& fgColor, thread const texture2d gammaLUT, thread const sampler gammaLUTSmplr) +{ + float param = bgColor.x; + float param_1 = fgColor.x; + float param_2 = bgColor.y; + float param_3 = fgColor.y; + float param_4 = bgColor.z; + float param_5 = fgColor.z; + return float3(filterTextGammaCorrectChannel(param, param_1, gammaLUT, gammaLUTSmplr), filterTextGammaCorrectChannel(param_2, param_3, gammaLUT, gammaLUTSmplr), filterTextGammaCorrectChannel(param_4, param_5, gammaLUT, gammaLUTSmplr)); +} + +float4 filterText(thread const float2& colorTexCoord, thread const texture2d colorTexture, thread const sampler colorTextureSmplr, thread const texture2d gammaLUT, thread const sampler gammaLUTSmplr, thread const float2& colorTextureSize, thread const float4& filterParams0, thread const float4& filterParams1, thread const float4& filterParams2) +{ + float4 kernel0 = filterParams0; + float3 bgColor = filterParams1.xyz; + float3 fgColor = filterParams2.xyz; + bool gammaCorrectionEnabled = filterParams2.w != 0.0; + float3 alpha; + if (kernel0.w == 0.0) + { + alpha = colorTexture.sample(colorTextureSmplr, colorTexCoord).xxx; + } + else + { + float2 param_3 = colorTexCoord; + float4 param_4 = kernel0; + float param_5 = 1.0 / colorTextureSize.x; + float4 param; + float param_1; + float4 param_2; + filterTextSample9Tap(param, param_1, param_2, colorTexture, colorTextureSmplr, param_3, param_4, param_5); + float4 alphaLeft = param; + float alphaCenter = param_1; + float4 alphaRight = param_2; + float4 param_6 = alphaLeft; + float3 param_7 = float3(alphaCenter, alphaRight.xy); + float4 param_8 = kernel0; + float r = filterTextConvolve7Tap(param_6, param_7, param_8); + float4 param_9 = float4(alphaLeft.yzw, alphaCenter); + float3 param_10 = alphaRight.xyz; + float4 param_11 = kernel0; + float g = filterTextConvolve7Tap(param_9, param_10, param_11); + float4 param_12 = float4(alphaLeft.zw, alphaCenter, alphaRight.x); + float3 param_13 = alphaRight.yzw; + float4 param_14 = kernel0; + float b = filterTextConvolve7Tap(param_12, param_13, param_14); + alpha = float3(r, g, b); + } + if (gammaCorrectionEnabled) + { + float3 param_15 = bgColor; + float3 param_16 = alpha; + alpha = filterTextGammaCorrect(param_15, param_16, gammaLUT, gammaLUTSmplr); + } + return float4(mix(bgColor, fgColor, alpha), 1.0); +} + +float4 sampleColor(thread const texture2d colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTexCoord) +{ + return colorTexture.sample(colorTextureSmplr, colorTexCoord); +} + +float4 filterNone(thread const float2& colorTexCoord, thread const texture2d colorTexture, thread const sampler colorTextureSmplr) +{ + float2 param = colorTexCoord; + return sampleColor(colorTexture, colorTextureSmplr, param); +} + +float4 filterColor(thread const float2& colorTexCoord, thread const texture2d colorTexture, thread const sampler colorTextureSmplr, thread const texture2d gammaLUT, thread const sampler gammaLUTSmplr, thread const float2& colorTextureSize, thread const float4& filterParams0, thread const float4& filterParams1, thread const float4& filterParams2, thread const int& colorFilter) +{ + switch (colorFilter) + { + case 3: + { + float2 param = colorTexCoord; + float2 param_1 = colorTextureSize; + float4 param_2 = filterParams0; + float4 param_3 = filterParams1; + return filterBlur(param, colorTexture, colorTextureSmplr, param_1, param_2, param_3); + } + case 2: + { + float2 param_4 = colorTexCoord; + float2 param_5 = colorTextureSize; + float4 param_6 = filterParams0; + float4 param_7 = filterParams1; + float4 param_8 = filterParams2; + return filterText(param_4, colorTexture, colorTextureSmplr, gammaLUT, gammaLUTSmplr, param_5, param_6, param_7, param_8); + } + } + float2 param_9 = colorTexCoord; + return filterNone(param_9, colorTexture, colorTextureSmplr); +} + +float3 compositeScreen(thread const float3& destColor, thread const float3& srcColor) +{ + return (destColor + srcColor) - (destColor * srcColor); +} + +float3 compositeSelect(thread const bool3& cond, thread const float3& ifTrue, thread const float3& ifFalse) +{ + float _546; + if (cond.x) + { + _546 = ifTrue.x; + } + else + { + _546 = ifFalse.x; + } + float _557; + if (cond.y) + { + _557 = ifTrue.y; + } + else + { + _557 = ifFalse.y; + } + float _568; + if (cond.z) + { + _568 = ifTrue.z; + } + else + { + _568 = ifFalse.z; + } + return float3(_546, _557, _568); +} + +float3 compositeHardLight(thread const float3& destColor, thread const float3& srcColor) +{ + float3 param = destColor; + float3 param_1 = (float3(2.0) * srcColor) - float3(1.0); + bool3 param_2 = srcColor <= float3(0.5); + float3 param_3 = (destColor * float3(2.0)) * srcColor; + float3 param_4 = compositeScreen(param, param_1); + return compositeSelect(param_2, param_3, param_4); +} + +float3 compositeColorDodge(thread const float3& destColor, thread const float3& srcColor) +{ + bool3 destZero = destColor == float3(0.0); + bool3 srcOne = srcColor == float3(1.0); + bool3 param = srcOne; + float3 param_1 = float3(1.0); + float3 param_2 = destColor / (float3(1.0) - srcColor); + bool3 param_3 = destZero; + float3 param_4 = float3(0.0); + float3 param_5 = compositeSelect(param, param_1, param_2); + return compositeSelect(param_3, param_4, param_5); +} + +float3 compositeSoftLight(thread const float3& destColor, thread const float3& srcColor) +{ + bool3 param = destColor <= float3(0.25); + float3 param_1 = ((((float3(16.0) * destColor) - float3(12.0)) * destColor) + float3(4.0)) * destColor; + float3 param_2 = sqrt(destColor); + float3 darkenedDestColor = compositeSelect(param, param_1, param_2); + bool3 param_3 = srcColor <= float3(0.5); + float3 param_4 = destColor * (float3(1.0) - destColor); + float3 param_5 = darkenedDestColor - destColor; + float3 factor = compositeSelect(param_3, param_4, param_5); + return destColor + (((srcColor * 2.0) - float3(1.0)) * factor); +} + +float compositeDivide(thread const float& num, thread const float& denom) +{ + float _582; + if (denom != 0.0) + { + _582 = num / denom; + } + else + { + _582 = 0.0; + } + return _582; +} + +float3 compositeRGBToHSL(thread const float3& rgb) +{ + float v = fast::max(fast::max(rgb.x, rgb.y), rgb.z); + float xMin = fast::min(fast::min(rgb.x, rgb.y), rgb.z); + float c = v - xMin; + float l = mix(xMin, v, 0.5); + float3 _688; + if (rgb.x == v) + { + _688 = float3(0.0, rgb.yz); + } + else + { + float3 _701; + if (rgb.y == v) + { + _701 = float3(2.0, rgb.zx); + } + else + { + _701 = float3(4.0, rgb.xy); + } + _688 = _701; + } + float3 terms = _688; + float param = ((terms.x * c) + terms.y) - terms.z; + float param_1 = c; + float h = 1.0471975803375244140625 * compositeDivide(param, param_1); + float param_2 = c; + float param_3 = v; + float s = compositeDivide(param_2, param_3); + return float3(h, s, l); +} + +float3 compositeHSL(thread const float3& destColor, thread const float3& srcColor, thread const int& op) +{ + switch (op) + { + case 12: + { + return float3(srcColor.x, destColor.y, destColor.z); + } + case 13: + { + return float3(destColor.x, srcColor.y, destColor.z); + } + case 14: + { + return float3(srcColor.x, srcColor.y, destColor.z); + } + default: + { + return float3(destColor.x, destColor.y, srcColor.z); + } + } +} + +float3 compositeHSLToRGB(thread const float3& hsl) +{ + float a = hsl.y * fast::min(hsl.z, 1.0 - hsl.z); + float3 ks = mod(float3(0.0, 8.0, 4.0) + float3(hsl.x * 1.90985929965972900390625), float3(12.0)); + return hsl.zzz - (fast::clamp(fast::min(ks - float3(3.0), float3(9.0) - ks), float3(-1.0), float3(1.0)) * a); +} + +float3 compositeRGB(thread const float3& destColor, thread const float3& srcColor, thread const int& op) +{ + switch (op) + { + case 1: + { + return destColor * srcColor; + } + case 2: + { + float3 param = destColor; + float3 param_1 = srcColor; + return compositeScreen(param, param_1); + } + case 3: + { + float3 param_2 = srcColor; + float3 param_3 = destColor; + return compositeHardLight(param_2, param_3); + } + case 4: + { + return fast::min(destColor, srcColor); + } + case 5: + { + return fast::max(destColor, srcColor); + } + case 6: + { + float3 param_4 = destColor; + float3 param_5 = srcColor; + return compositeColorDodge(param_4, param_5); + } + case 7: + { + float3 param_6 = float3(1.0) - destColor; + float3 param_7 = float3(1.0) - srcColor; + return float3(1.0) - compositeColorDodge(param_6, param_7); + } + case 8: + { + float3 param_8 = destColor; + float3 param_9 = srcColor; + return compositeHardLight(param_8, param_9); + } + case 9: + { + float3 param_10 = destColor; + float3 param_11 = srcColor; + return compositeSoftLight(param_10, param_11); + } + case 10: + { + return abs(destColor - srcColor); + } + case 11: + { + return (destColor + srcColor) - ((float3(2.0) * destColor) * srcColor); + } + case 12: + case 13: + case 14: + case 15: + { + float3 param_12 = destColor; + float3 param_13 = srcColor; + float3 param_14 = compositeRGBToHSL(param_12); + float3 param_15 = compositeRGBToHSL(param_13); + int param_16 = op; + float3 param_17 = compositeHSL(param_14, param_15, param_16); + return compositeHSLToRGB(param_17); + } + } + return srcColor; +} + +float4 composite(thread const float4& srcColor, thread const texture2d destTexture, thread const sampler destTextureSmplr, thread const float2& destTextureSize, thread const float2& fragCoord, thread const int& op) +{ + if (op == 0) + { + return srcColor; + } + float2 destTexCoord = fragCoord / destTextureSize; + float4 destColor = destTexture.sample(destTextureSmplr, destTexCoord); + float3 param = destColor.xyz; + float3 param_1 = srcColor.xyz; + int param_2 = op; + float3 blendedRGB = compositeRGB(param, param_1, param_2); + 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 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 float2 uDestTextureSize, thread float4& gl_FragCoord, thread float4& oFragColor) +{ + int maskCtrl0 = (ctrl >> 0) & 3; + int maskCtrl1 = (ctrl >> 2) & 3; + float maskAlpha = 1.0; + float param = maskAlpha; + float3 param_1 = vMaskTexCoord0; + int param_2 = maskCtrl0; + maskAlpha = sampleMask(param, uMaskTexture0, uMaskTexture0Smplr, param_1, param_2); + float param_3 = maskAlpha; + float3 param_4 = vMaskTexCoord1; + int param_5 = maskCtrl1; + maskAlpha = sampleMask(param_3, uMaskTexture1, uMaskTexture1Smplr, param_4, param_5); + float4 color = float4(0.0); + if (((ctrl >> 6) & 1) != 0) + { + int color0Filter = (ctrl >> 4) & 3; + float2 param_6 = vColorTexCoord0; + float2 param_7 = uColorTexture0Size; + float4 param_8 = uFilterParams0; + float4 param_9 = uFilterParams1; + float4 param_10 = uFilterParams2; + int param_11 = color0Filter; + color += filterColor(param_6, uColorTexture0, uColorTexture0Smplr, uGammaLUT, uGammaLUTSmplr, param_7, param_8, param_9, param_10, param_11); + } + if (((ctrl >> 7) & 1) != 0) + { + float2 param_12 = vColorTexCoord1; + color *= sampleColor(uColorTexture1, uColorTexture1Smplr, param_12); + } + color.w *= maskAlpha; + int compositeOp = (ctrl >> 8) & 15; + float4 param_13 = color; + float2 param_14 = uDestTextureSize; + float2 param_15 = gl_FragCoord.xy; + int param_16 = compositeOp; + color = composite(param_13, uDestTexture, uDestTextureSmplr, param_14, param_15, param_16); + float3 _1159 = color.xyz * color.w; + color = float4(_1159.x, _1159.y, _1159.z, color.w); + oFragColor = color; +} + +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) +{ + 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), (*spvDescriptorSet0.uFilterParams0), (*spvDescriptorSet0.uFilterParams1), (*spvDescriptorSet0.uFilterParams2), spvDescriptorSet0.uColorTexture1, spvDescriptorSet0.uColorTexture1Smplr, in.vColorTexCoord1, spvDescriptorSet0.uDestTexture, spvDescriptorSet0.uDestTextureSmplr, (*spvDescriptorSet0.uDestTextureSize), gl_FragCoord, out.oFragColor); + return out; +} + diff --git a/resources/shaders/metal/tile_solid.vs.metal b/resources/shaders/metal/tile.vs.metal similarity index 52% rename from resources/shaders/metal/tile_solid.vs.metal rename to resources/shaders/metal/tile.vs.metal index 4b344eef..d0b8400d 100644 --- a/resources/shaders/metal/tile_solid.vs.metal +++ b/resources/shaders/metal/tile.vs.metal @@ -12,21 +12,31 @@ struct spvDescriptorSetBuffer0 struct main0_out { - float2 vColorTexCoord [[user(locn0)]]; + float3 vMaskTexCoord0 [[user(locn0)]]; + float3 vMaskTexCoord1 [[user(locn1)]]; + float2 vColorTexCoord0 [[user(locn2)]]; + float2 vColorTexCoord1 [[user(locn3)]]; float4 gl_Position [[position]]; }; struct main0_in { int2 aTilePosition [[attribute(0)]]; - float2 aColorTexCoord [[attribute(1)]]; + float2 aColorTexCoord0 [[attribute(1)]]; + float2 aColorTexCoord1 [[attribute(2)]]; + float2 aMaskTexCoord0 [[attribute(3)]]; + float2 aMaskTexCoord1 [[attribute(4)]]; + int2 aMaskBackdrop [[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.vColorTexCoord = in.aColorTexCoord; + 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)); out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0); return out; } diff --git a/resources/shaders/metal/tile_alpha.fs.metal b/resources/shaders/metal/tile_alpha.fs.metal deleted file mode 100644 index 3281ab94..00000000 --- a/resources/shaders/metal/tile_alpha.fs.metal +++ /dev/null @@ -1,43 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - texture2d uStencilTexture [[id(0)]]; - sampler uStencilTextureSmplr [[id(1)]]; - texture2d uPaintTexture [[id(2)]]; - sampler uPaintTextureSmplr [[id(3)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vColorTexCoord [[user(locn0)]]; - float2 vMaskTexCoord [[user(locn1)]]; - float vOpacity [[user(locn2)]]; -}; - -float4 sampleSrcColor(thread texture2d uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity) -{ - float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; - float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); - return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity); -} - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) -{ - main0_out out = {}; - float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity); - out.oFragColor = float4(srcRGBA.xyz * srcRGBA.w, srcRGBA.w); - return out; -} - diff --git a/resources/shaders/metal/tile_alpha.vs.metal b/resources/shaders/metal/tile_alpha.vs.metal deleted file mode 100644 index d999eb0f..00000000 --- a/resources/shaders/metal/tile_alpha.vs.metal +++ /dev/null @@ -1,39 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - constant float2* uTileSize [[id(0)]]; - constant float4x4* uTransform [[id(1)]]; -}; - -struct main0_out -{ - float2 vColorTexCoord [[user(locn0)]]; - float2 vMaskTexCoord [[user(locn1)]]; - float vOpacity [[user(locn2)]]; - float4 gl_Position [[position]]; -}; - -struct main0_in -{ - int2 aTilePosition [[attribute(0)]]; - float2 aColorTexCoord [[attribute(1)]]; - float2 aMaskTexCoord [[attribute(2)]]; - float aOpacity [[attribute(3)]]; -}; - -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.vMaskTexCoord = in.aMaskTexCoord; - out.vColorTexCoord = in.aColorTexCoord; - out.vOpacity = in.aOpacity; - out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0); - return out; -} - diff --git a/resources/shaders/metal/tile_alpha_difference.fs.metal b/resources/shaders/metal/tile_alpha_difference.fs.metal deleted file mode 100644 index 8d32de9e..00000000 --- a/resources/shaders/metal/tile_alpha_difference.fs.metal +++ /dev/null @@ -1,62 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - texture2d uStencilTexture [[id(0)]]; - sampler uStencilTextureSmplr [[id(1)]]; - texture2d uPaintTexture [[id(2)]]; - sampler uPaintTextureSmplr [[id(3)]]; - constant float2* uFramebufferSize [[id(4)]]; - texture2d uDest [[id(5)]]; - sampler uDestSmplr [[id(6)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vColorTexCoord [[user(locn0)]]; - float2 vMaskTexCoord [[user(locn1)]]; - float vOpacity [[user(locn2)]]; -}; - -float4 sampleSrcColor(thread texture2d uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity) -{ - float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; - float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); - return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity); -} - -float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d uDest, thread const sampler uDestSmplr) -{ - float2 destTexCoord = gl_FragCoord.xy / uFramebufferSize; - return uDest.sample(uDestSmplr, destTexCoord); -} - -float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB) -{ - return float4(((srcRGBA.xyz * (srcRGBA.w * (1.0 - destRGBA.w))) + (blendedRGB * (srcRGBA.w * destRGBA.w))) + (destRGBA.xyz * ((1.0 - srcRGBA.w) * destRGBA.w)), 1.0); -} - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) -{ - main0_out out = {}; - float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity); - float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); - float3 blended = abs(destRGBA.xyz - srcRGBA.xyz); - float4 param = destRGBA; - float4 param_1 = srcRGBA; - float3 param_2 = blended; - out.oFragColor = blendColors(param, param_1, param_2); - return out; -} - diff --git a/resources/shaders/metal/tile_alpha_dodgeburn.fs.metal b/resources/shaders/metal/tile_alpha_dodgeburn.fs.metal deleted file mode 100644 index 5a8f4c0b..00000000 --- a/resources/shaders/metal/tile_alpha_dodgeburn.fs.metal +++ /dev/null @@ -1,115 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - texture2d uStencilTexture [[id(0)]]; - sampler uStencilTextureSmplr [[id(1)]]; - texture2d uPaintTexture [[id(2)]]; - sampler uPaintTextureSmplr [[id(3)]]; - constant float2* uFramebufferSize [[id(4)]]; - texture2d uDest [[id(5)]]; - sampler uDestSmplr [[id(6)]]; - constant int* uBurn [[id(7)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vColorTexCoord [[user(locn0)]]; - float2 vMaskTexCoord [[user(locn1)]]; - float vOpacity [[user(locn2)]]; -}; - -float4 sampleSrcColor(thread texture2d uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity) -{ - float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; - float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); - return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity); -} - -float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d uDest, thread const sampler uDestSmplr) -{ - float2 destTexCoord = gl_FragCoord.xy / uFramebufferSize; - return uDest.sample(uDestSmplr, destTexCoord); -} - -float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB) -{ - return float4(((srcRGBA.xyz * (srcRGBA.w * (1.0 - destRGBA.w))) + (blendedRGB * (srcRGBA.w * destRGBA.w))) + (destRGBA.xyz * ((1.0 - srcRGBA.w) * destRGBA.w)), 1.0); -} - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) -{ - main0_out out = {}; - float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity); - float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); - float3 _122; - if ((*spvDescriptorSet0.uBurn) == 0) - { - _122 = destRGBA.xyz; - } - else - { - _122 = float3(1.0) - destRGBA.xyz; - } - float3 dest = _122; - float3 _136; - if ((*spvDescriptorSet0.uBurn) == 0) - { - _136 = float3(1.0) - srcRGBA.xyz; - } - else - { - _136 = srcRGBA.xyz; - } - float3 src = _136; - bool3 srcNonzero = src != float3(0.0); - float _157; - if (srcNonzero.x) - { - _157 = dest.x / src.x; - } - else - { - _157 = 1.0; - } - float _170; - if (srcNonzero.y) - { - _170 = dest.y / src.y; - } - else - { - _170 = 1.0; - } - float _183; - if (srcNonzero.z) - { - _183 = dest.z / src.z; - } - else - { - _183 = 1.0; - } - float3 blended = fast::min(float3(_157, _170, _183), float3(1.0)); - if ((*spvDescriptorSet0.uBurn) != 0) - { - blended = float3(1.0) - blended; - } - float4 param = destRGBA; - float4 param_1 = srcRGBA; - float3 param_2 = blended; - out.oFragColor = blendColors(param, param_1, param_2); - return out; -} - diff --git a/resources/shaders/metal/tile_alpha_exclusion.fs.metal b/resources/shaders/metal/tile_alpha_exclusion.fs.metal deleted file mode 100644 index a5b8415d..00000000 --- a/resources/shaders/metal/tile_alpha_exclusion.fs.metal +++ /dev/null @@ -1,64 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - texture2d uStencilTexture [[id(0)]]; - sampler uStencilTextureSmplr [[id(1)]]; - texture2d uPaintTexture [[id(2)]]; - sampler uPaintTextureSmplr [[id(3)]]; - constant float2* uFramebufferSize [[id(4)]]; - texture2d uDest [[id(5)]]; - sampler uDestSmplr [[id(6)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vColorTexCoord [[user(locn0)]]; - float2 vMaskTexCoord [[user(locn1)]]; - float vOpacity [[user(locn2)]]; -}; - -float4 sampleSrcColor(thread texture2d uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity) -{ - float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; - float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); - return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity); -} - -float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d uDest, thread const sampler uDestSmplr) -{ - float2 destTexCoord = gl_FragCoord.xy / uFramebufferSize; - return uDest.sample(uDestSmplr, destTexCoord); -} - -float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB) -{ - return float4(((srcRGBA.xyz * (srcRGBA.w * (1.0 - destRGBA.w))) + (blendedRGB * (srcRGBA.w * destRGBA.w))) + (destRGBA.xyz * ((1.0 - srcRGBA.w) * destRGBA.w)), 1.0); -} - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) -{ - main0_out out = {}; - float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity); - float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); - float3 dest = destRGBA.xyz; - float3 src = srcRGBA.xyz; - float3 blended = (dest + src) - ((dest * src) * 2.0); - float4 param = destRGBA; - float4 param_1 = srcRGBA; - float3 param_2 = blended; - out.oFragColor = blendColors(param, param_1, param_2); - return out; -} - diff --git a/resources/shaders/metal/tile_alpha_hsl.fs.metal b/resources/shaders/metal/tile_alpha_hsl.fs.metal deleted file mode 100644 index 7b2072c0..00000000 --- a/resources/shaders/metal/tile_alpha_hsl.fs.metal +++ /dev/null @@ -1,152 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - texture2d uStencilTexture [[id(0)]]; - sampler uStencilTextureSmplr [[id(1)]]; - texture2d uPaintTexture [[id(2)]]; - sampler uPaintTextureSmplr [[id(3)]]; - constant float2* uFramebufferSize [[id(4)]]; - texture2d uDest [[id(5)]]; - sampler uDestSmplr [[id(6)]]; - constant int3* uBlendHSL [[id(7)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vColorTexCoord [[user(locn0)]]; - float2 vMaskTexCoord [[user(locn1)]]; - float vOpacity [[user(locn2)]]; -}; - -// Implementation of the GLSL mod() function, which is slightly different than Metal fmod() -template -Tx mod(Tx x, Ty y) -{ - return x - y * floor(x / y); -} - -float4 sampleSrcColor(thread texture2d uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity) -{ - float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; - float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); - return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity); -} - -float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d uDest, thread const sampler uDestSmplr) -{ - float2 destTexCoord = gl_FragCoord.xy / uFramebufferSize; - return uDest.sample(uDestSmplr, destTexCoord); -} - -float3 convertRGBToHSL(thread const float3& rgb) -{ - float v = fast::max(rgb.y, rgb.z); - float c = v - fast::min(rgb.y, rgb.z); - float l = v - (0.5 * c); - float3 tmp = float3(0.0); - bool3 is_v = rgb == float3(v); - if (is_v.x) - { - tmp = float3(0.0, rgb.yz); - } - else - { - if (is_v.y) - { - tmp = float3(2.0, rgb.zx); - } - else - { - if (is_v.z) - { - tmp = float3(4.0, rgb.xy); - } - } - } - float h = 1.0471975803375244140625 * (tmp.x + ((tmp.y - tmp.z) / c)); - float s = 0.0; - if ((l > 0.0) && (l < 1.0)) - { - s = (v - l) / fast::min(l, 1.0 - l); - } - return float3(h, s, l); -} - -float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b) -{ - float _129; - if (cond.x) - { - _129 = a.x; - } - else - { - _129 = b.x; - } - float _141; - if (cond.y) - { - _141 = a.y; - } - else - { - _141 = b.y; - } - float _153; - if (cond.z) - { - _153 = a.z; - } - else - { - _153 = b.z; - } - return float3(_129, _141, _153); -} - -float3 convertHSLToRGB(thread const float3& hsl) -{ - float a = hsl.y * fast::min(hsl.z, 1.0 - hsl.z); - float3 ks = mod(float3(0.0, 8.0, 4.0) + float3(hsl.x * 1.90985929965972900390625), float3(12.0)); - return hsl.zzz - (fast::clamp(fast::min(ks - float3(3.0), float3(9.0) - ks), float3(-1.0), float3(1.0)) * a); -} - -float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB) -{ - return float4(((srcRGBA.xyz * (srcRGBA.w * (1.0 - destRGBA.w))) + (blendedRGB * (srcRGBA.w * destRGBA.w))) + (destRGBA.xyz * ((1.0 - srcRGBA.w) * destRGBA.w)), 1.0); -} - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) -{ - main0_out out = {}; - float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity); - float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); - float3 param = destRGBA.xyz; - float3 destHSL = convertRGBToHSL(param); - float3 param_1 = srcRGBA.xyz; - float3 srcHSL = convertRGBToHSL(param_1); - bool3 param_2 = (*spvDescriptorSet0.uBlendHSL) == int3(0); - float3 param_3 = destHSL; - float3 param_4 = srcHSL; - float3 blendedHSL = select3(param_2, param_3, param_4); - float3 param_5 = blendedHSL; - float3 blendedRGB = convertHSLToRGB(param_5); - float4 param_6 = destRGBA; - float4 param_7 = srcRGBA; - float3 param_8 = blendedRGB; - out.oFragColor = blendColors(param_6, param_7, param_8); - return out; -} - diff --git a/resources/shaders/metal/tile_alpha_overlay.fs.metal b/resources/shaders/metal/tile_alpha_overlay.fs.metal deleted file mode 100644 index 0c5ebd53..00000000 --- a/resources/shaders/metal/tile_alpha_overlay.fs.metal +++ /dev/null @@ -1,136 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - texture2d uStencilTexture [[id(0)]]; - sampler uStencilTextureSmplr [[id(1)]]; - texture2d uPaintTexture [[id(2)]]; - sampler uPaintTextureSmplr [[id(3)]]; - constant float2* uFramebufferSize [[id(4)]]; - texture2d uDest [[id(5)]]; - sampler uDestSmplr [[id(6)]]; - constant int* uBlendMode [[id(7)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vColorTexCoord [[user(locn0)]]; - float2 vMaskTexCoord [[user(locn1)]]; - float vOpacity [[user(locn2)]]; -}; - -float4 sampleSrcColor(thread texture2d uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity) -{ - float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; - float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); - return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity); -} - -float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d uDest, thread const sampler uDestSmplr) -{ - float2 destTexCoord = gl_FragCoord.xy / uFramebufferSize; - return uDest.sample(uDestSmplr, destTexCoord); -} - -float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b) -{ - float _122; - if (cond.x) - { - _122 = a.x; - } - else - { - _122 = b.x; - } - float _134; - if (cond.y) - { - _134 = a.y; - } - else - { - _134 = b.y; - } - float _146; - if (cond.z) - { - _146 = a.z; - } - else - { - _146 = b.z; - } - return float3(_122, _134, _146); -} - -float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB) -{ - return float4(((srcRGBA.xyz * (srcRGBA.w * (1.0 - destRGBA.w))) + (blendedRGB * (srcRGBA.w * destRGBA.w))) + (destRGBA.xyz * ((1.0 - srcRGBA.w) * destRGBA.w)), 1.0); -} - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) -{ - main0_out out = {}; - float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity); - float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); - bool reversed = (*spvDescriptorSet0.uBlendMode) == 3; - float3 _171; - if (reversed) - { - _171 = srcRGBA.xyz; - } - else - { - _171 = destRGBA.xyz; - } - float3 src = _171; - float3 _182; - if (reversed) - { - _182 = destRGBA.xyz; - } - else - { - _182 = srcRGBA.xyz; - } - float3 dest = _182; - float3 multiply = src * dest; - float3 blended; - if ((*spvDescriptorSet0.uBlendMode) == 0) - { - blended = multiply; - } - else - { - float3 screen = (dest + src) - multiply; - if ((*spvDescriptorSet0.uBlendMode) == 1) - { - blended = screen; - } - else - { - bool3 param = src <= float3(0.5); - float3 param_1 = multiply; - float3 param_2 = (screen * 2.0) - float3(1.0); - blended = select3(param, param_1, param_2); - } - } - float4 param_3 = destRGBA; - float4 param_4 = srcRGBA; - float3 param_5 = blended; - out.oFragColor = blendColors(param_3, param_4, param_5); - return out; -} - diff --git a/resources/shaders/metal/tile_alpha_softlight.fs.metal b/resources/shaders/metal/tile_alpha_softlight.fs.metal deleted file mode 100644 index 3d356a2b..00000000 --- a/resources/shaders/metal/tile_alpha_softlight.fs.metal +++ /dev/null @@ -1,106 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - texture2d uStencilTexture [[id(0)]]; - sampler uStencilTextureSmplr [[id(1)]]; - texture2d uPaintTexture [[id(2)]]; - sampler uPaintTextureSmplr [[id(3)]]; - constant float2* uFramebufferSize [[id(4)]]; - texture2d uDest [[id(5)]]; - sampler uDestSmplr [[id(6)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vColorTexCoord [[user(locn0)]]; - float2 vMaskTexCoord [[user(locn1)]]; - float vOpacity [[user(locn2)]]; -}; - -float4 sampleSrcColor(thread texture2d uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity) -{ - float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; - float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); - return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity); -} - -float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d uDest, thread const sampler uDestSmplr) -{ - float2 destTexCoord = gl_FragCoord.xy / uFramebufferSize; - return uDest.sample(uDestSmplr, destTexCoord); -} - -float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b) -{ - float _122; - if (cond.x) - { - _122 = a.x; - } - else - { - _122 = b.x; - } - float _134; - if (cond.y) - { - _134 = a.y; - } - else - { - _134 = b.y; - } - float _146; - if (cond.z) - { - _146 = a.z; - } - else - { - _146 = b.z; - } - return float3(_122, _134, _146); -} - -float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB) -{ - return float4(((srcRGBA.xyz * (srcRGBA.w * (1.0 - destRGBA.w))) + (blendedRGB * (srcRGBA.w * destRGBA.w))) + (destRGBA.xyz * ((1.0 - srcRGBA.w) * destRGBA.w)), 1.0); -} - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) -{ - main0_out out = {}; - float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity); - float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); - float3 dest = destRGBA.xyz; - float3 src = srcRGBA.xyz; - bool3 destDark = dest <= float3(0.25); - bool3 srcDark = src <= float3(0.5); - bool3 param = destDark; - float3 param_1 = (((dest * 16.0) - float3(12.0)) * dest) + float3(4.0); - float3 param_2 = rsqrt(dest); - float3 d = select3(param, param_1, param_2); - bool3 param_3 = srcDark; - float3 param_4 = float3(1.0) - dest; - float3 param_5 = d - float3(1.0); - float3 x = select3(param_3, param_4, param_5); - float3 blended = dest * ((((src * 2.0) - float3(1.0)) * x) + float3(1.0)); - float4 param_6 = destRGBA; - float4 param_7 = srcRGBA; - float3 param_8 = blended; - out.oFragColor = blendColors(param_6, param_7, param_8); - return out; -} - diff --git a/resources/shaders/metal/tile_solid.fs.metal b/resources/shaders/metal/tile_solid.fs.metal deleted file mode 100644 index be2e95f1..00000000 --- a/resources/shaders/metal/tile_solid.fs.metal +++ /dev/null @@ -1,30 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - texture2d uColorTexture [[id(0)]]; - sampler uColorTextureSmplr [[id(1)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vColorTexCoord [[user(locn0)]]; -}; - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) -{ - main0_out out = {}; - float4 color = spvDescriptorSet0.uColorTexture.sample(spvDescriptorSet0.uColorTextureSmplr, in.vColorTexCoord); - out.oFragColor = float4(color.xyz * color.w, color.w); - return out; -} - diff --git a/resources/shaders/metal/tile_solid_filter_blur.fs.metal b/resources/shaders/metal/tile_solid_filter_blur.fs.metal deleted file mode 100644 index 27c849c7..00000000 --- a/resources/shaders/metal/tile_solid_filter_blur.fs.metal +++ /dev/null @@ -1,52 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - constant float3* uInitialGaussCoeff [[id(0)]]; - texture2d uColorTexture [[id(1)]]; - sampler uColorTextureSmplr [[id(2)]]; - constant int* uSupport [[id(3)]]; - constant float2* uSrcOffsetScale [[id(4)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vColorTexCoord [[user(locn0)]]; -}; - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) -{ - main0_out out = {}; - float3 gaussCoeff = (*spvDescriptorSet0.uInitialGaussCoeff); - float gaussSum = gaussCoeff.x; - float4 color = spvDescriptorSet0.uColorTexture.sample(spvDescriptorSet0.uColorTextureSmplr, in.vColorTexCoord) * gaussCoeff.x; - float2 _39 = gaussCoeff.xy * gaussCoeff.yz; - gaussCoeff = float3(_39.x, _39.y, gaussCoeff.z); - for (int i = 1; i <= (*spvDescriptorSet0.uSupport); i += 2) - { - float gaussPartialSum = gaussCoeff.x; - float2 _64 = gaussCoeff.xy * gaussCoeff.yz; - gaussCoeff = float3(_64.x, _64.y, gaussCoeff.z); - gaussPartialSum += gaussCoeff.x; - float2 srcOffset = (*spvDescriptorSet0.uSrcOffsetScale) * (float(i) + (gaussCoeff.x / gaussPartialSum)); - color += ((spvDescriptorSet0.uColorTexture.sample(spvDescriptorSet0.uColorTextureSmplr, (in.vColorTexCoord - srcOffset)) + spvDescriptorSet0.uColorTexture.sample(spvDescriptorSet0.uColorTextureSmplr, (in.vColorTexCoord + srcOffset))) * gaussPartialSum); - gaussSum += (2.0 * gaussPartialSum); - float2 _108 = gaussCoeff.xy * gaussCoeff.yz; - gaussCoeff = float3(_108.x, _108.y, gaussCoeff.z); - } - color /= float4(gaussSum); - float3 _123 = color.xyz * color.w; - color = float4(_123.x, _123.y, _123.z, color.w); - out.oFragColor = color; - return out; -} - diff --git a/resources/shaders/metal/tile_solid_filter_text.fs.metal b/resources/shaders/metal/tile_solid_filter_text.fs.metal deleted file mode 100644 index 8e9dc32c..00000000 --- a/resources/shaders/metal/tile_solid_filter_text.fs.metal +++ /dev/null @@ -1,130 +0,0 @@ -// Automatically generated from files in pathfinder/shaders/. Do not edit! -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct spvDescriptorSetBuffer0 -{ - texture2d uGammaLUT [[id(0)]]; - sampler uGammaLUTSmplr [[id(1)]]; - constant float4* uKernel [[id(2)]]; - texture2d uColorTexture [[id(3)]]; - sampler uColorTextureSmplr [[id(4)]]; - constant float2* uSrcSize [[id(5)]]; - constant int* uGammaCorrectionEnabled [[id(6)]]; - constant float4* uBGColor [[id(7)]]; - constant float4* uFGColor [[id(8)]]; -}; - -struct main0_out -{ - float4 oFragColor [[color(0)]]; -}; - -struct main0_in -{ - float2 vColorTexCoord [[user(locn0)]]; -}; - -float sample1Tap(thread const float& offset, thread texture2d uColorTexture, thread const sampler uColorTextureSmplr, thread float2& vColorTexCoord) -{ - return uColorTexture.sample(uColorTextureSmplr, float2(vColorTexCoord.x + offset, vColorTexCoord.y)).x; -} - -void sample9Tap(thread float4& outAlphaLeft, thread float& outAlphaCenter, thread float4& outAlphaRight, thread const float& onePixel, thread float4 uKernel, thread texture2d uColorTexture, thread const sampler uColorTextureSmplr, thread float2& vColorTexCoord) -{ - float _89; - if (uKernel.x > 0.0) - { - float param = (-4.0) * onePixel; - _89 = sample1Tap(param, uColorTexture, uColorTextureSmplr, vColorTexCoord); - } - else - { - _89 = 0.0; - } - float param_1 = (-3.0) * onePixel; - float param_2 = (-2.0) * onePixel; - float param_3 = (-1.0) * onePixel; - outAlphaLeft = float4(_89, sample1Tap(param_1, uColorTexture, uColorTextureSmplr, vColorTexCoord), sample1Tap(param_2, uColorTexture, uColorTextureSmplr, vColorTexCoord), sample1Tap(param_3, uColorTexture, uColorTextureSmplr, vColorTexCoord)); - float param_4 = 0.0; - outAlphaCenter = sample1Tap(param_4, uColorTexture, uColorTextureSmplr, vColorTexCoord); - float param_5 = 1.0 * onePixel; - float param_6 = 2.0 * onePixel; - float param_7 = 3.0 * onePixel; - float _134; - if (uKernel.x > 0.0) - { - float param_8 = 4.0 * onePixel; - _134 = sample1Tap(param_8, uColorTexture, uColorTextureSmplr, vColorTexCoord); - } - else - { - _134 = 0.0; - } - outAlphaRight = float4(sample1Tap(param_5, uColorTexture, uColorTextureSmplr, vColorTexCoord), sample1Tap(param_6, uColorTexture, uColorTextureSmplr, vColorTexCoord), sample1Tap(param_7, uColorTexture, uColorTextureSmplr, vColorTexCoord), _134); -} - -float convolve7Tap(thread const float4& alpha0, thread const float3& alpha1, thread float4 uKernel) -{ - return dot(alpha0, uKernel) + dot(alpha1, uKernel.zyx); -} - -float gammaCorrectChannel(thread const float& bgColor, thread const float& fgColor, thread texture2d uGammaLUT, thread const sampler uGammaLUTSmplr) -{ - return uGammaLUT.sample(uGammaLUTSmplr, float2(fgColor, 1.0 - bgColor)).x; -} - -float3 gammaCorrect(thread const float3& bgColor, thread const float3& fgColor, thread texture2d uGammaLUT, thread const sampler uGammaLUTSmplr) -{ - float param = bgColor.x; - float param_1 = fgColor.x; - float param_2 = bgColor.y; - float param_3 = fgColor.y; - float param_4 = bgColor.z; - float param_5 = fgColor.z; - return float3(gammaCorrectChannel(param, param_1, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_2, param_3, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_4, param_5, uGammaLUT, uGammaLUTSmplr)); -} - -fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) -{ - main0_out out = {}; - float3 alpha; - if ((*spvDescriptorSet0.uKernel).w == 0.0) - { - alpha = spvDescriptorSet0.uColorTexture.sample(spvDescriptorSet0.uColorTextureSmplr, in.vColorTexCoord).xxx; - } - else - { - float param_3 = 1.0 / (*spvDescriptorSet0.uSrcSize).x; - float4 param; - float param_1; - float4 param_2; - sample9Tap(param, param_1, param_2, param_3, (*spvDescriptorSet0.uKernel), spvDescriptorSet0.uColorTexture, spvDescriptorSet0.uColorTextureSmplr, in.vColorTexCoord); - float4 alphaLeft = param; - float alphaCenter = param_1; - float4 alphaRight = param_2; - float4 param_4 = alphaLeft; - float3 param_5 = float3(alphaCenter, alphaRight.xy); - float r = convolve7Tap(param_4, param_5, (*spvDescriptorSet0.uKernel)); - float4 param_6 = float4(alphaLeft.yzw, alphaCenter); - float3 param_7 = alphaRight.xyz; - float g = convolve7Tap(param_6, param_7, (*spvDescriptorSet0.uKernel)); - float4 param_8 = float4(alphaLeft.zw, alphaCenter, alphaRight.x); - float3 param_9 = alphaRight.yzw; - float b = convolve7Tap(param_8, param_9, (*spvDescriptorSet0.uKernel)); - alpha = float3(r, g, b); - } - if ((*spvDescriptorSet0.uGammaCorrectionEnabled) != 0) - { - float3 param_10 = (*spvDescriptorSet0.uBGColor).xyz; - float3 param_11 = alpha; - alpha = gammaCorrect(param_10, param_11, spvDescriptorSet0.uGammaLUT, spvDescriptorSet0.uGammaLUTSmplr); - } - out.oFragColor = float4(mix((*spvDescriptorSet0.uBGColor).xyz, (*spvDescriptorSet0.uFGColor).xyz, alpha), 1.0); - return out; -} - diff --git a/shaders/Makefile b/shaders/Makefile index 8c16cdba..64535afe 100644 --- a/shaders/Makefile +++ b/shaders/Makefile @@ -13,33 +13,17 @@ SHADERS=\ demo_ground.vs.glsl \ fill.fs.glsl \ fill.vs.glsl \ - mask.vs.glsl \ - mask_evenodd.fs.glsl \ - mask_winding.fs.glsl \ reproject.fs.glsl \ reproject.vs.glsl \ stencil.fs.glsl \ stencil.vs.glsl \ - tile_alpha.fs.glsl \ - tile_alpha.vs.glsl \ - tile_alpha_difference.fs.glsl \ - tile_alpha_dodgeburn.fs.glsl \ - tile_alpha_exclusion.fs.glsl \ - tile_alpha_hsl.fs.glsl \ - tile_alpha_overlay.fs.glsl \ - tile_alpha_softlight.fs.glsl \ + tile.fs.glsl \ + tile.vs.glsl \ tile_copy.fs.glsl \ tile_copy.vs.glsl \ - tile_solid.fs.glsl \ - tile_solid.vs.glsl \ - tile_solid_filter_blur.fs.glsl \ - tile_solid_filter_text.fs.glsl \ $(EMPTY) INCLUDES=\ - tile_alpha_sample.inc.glsl \ - tile_solid_filter_text_convolve.inc.glsl \ - tile_solid_filter_text_gamma_correct.inc.glsl \ $(EMPTY) OUT=\ diff --git a/shaders/blit.vs.glsl b/shaders/blit.vs.glsl index 81f4e4e1..249ac1f5 100644 --- a/shaders/blit.vs.glsl +++ b/shaders/blit.vs.glsl @@ -12,11 +12,15 @@ precision highp float; -in vec2 aPosition; +in ivec2 aPosition; out vec2 vTexCoord; void main() { - vTexCoord = aPosition; - gl_Position = vec4(mix(aPosition, vec2(-1.0), vec2(1.0)), 0.0, 1.0); + vec2 texCoord = vec2(aPosition); +#ifdef PF_ORIGIN_UPPER_LEFT + texCoord.y = 1.0 - texCoord.y; +#endif + vTexCoord = texCoord; + gl_Position = vec4(mix(vec2(-1.0), vec2(1.0), vec2(aPosition)), 0.0, 1.0); } diff --git a/shaders/mask.vs.glsl b/shaders/mask.vs.glsl deleted file mode 100644 index 4495bbe9..00000000 --- a/shaders/mask.vs.glsl +++ /dev/null @@ -1,31 +0,0 @@ -#version 330 - -// pathfinder/shaders/mask_winding.vs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -in vec2 aPosition; -in vec2 aFillTexCoord; -in int aBackdrop; - -out vec2 vFillTexCoord; -out float vBackdrop; - -void main() { - vec2 position = mix(vec2(-1.0), vec2(1.0), aPosition); -#ifdef PF_ORIGIN_UPPER_LEFT - position.y = -position.y; -#endif - - vFillTexCoord = aFillTexCoord; - vBackdrop = float(aBackdrop); - gl_Position = vec4(position, 0.0, 1.0); -} diff --git a/shaders/mask_evenodd.fs.glsl b/shaders/mask_evenodd.fs.glsl deleted file mode 100644 index 9d704519..00000000 --- a/shaders/mask_evenodd.fs.glsl +++ /dev/null @@ -1,25 +0,0 @@ -#version 330 - -// pathfinder/shaders/mask_evenodd.fs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -uniform sampler2D uFillTexture; - -in vec2 vFillTexCoord; -in float vBackdrop; - -out vec4 oFragColor; - -void main() { - float alpha = texture(uFillTexture, vFillTexCoord).r + vBackdrop; - oFragColor = vec4(1.0 - abs(1.0 - mod(alpha, 2.0))); -} diff --git a/shaders/mask_winding.fs.glsl b/shaders/mask_winding.fs.glsl deleted file mode 100644 index b9210492..00000000 --- a/shaders/mask_winding.fs.glsl +++ /dev/null @@ -1,24 +0,0 @@ -#version 330 - -// pathfinder/shaders/mask_winding.fs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -uniform sampler2D uFillTexture; - -in vec2 vFillTexCoord; -in float vBackdrop; - -out vec4 oFragColor; - -void main() { - oFragColor = vec4(abs(texture(uFillTexture, vFillTexCoord).r + vBackdrop)); -} diff --git a/shaders/tile.fs.glsl b/shaders/tile.fs.glsl new file mode 100644 index 00000000..282108d6 --- /dev/null +++ b/shaders/tile.fs.glsl @@ -0,0 +1,460 @@ +#version 330 + +// pathfinder/shaders/tile.fs.glsl +// +// Copyright © 2020 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Mask UV 0 Mask UV 1 +// + + +// | | +// +-----v-----+ +-----v-----+ +// | | MIN | | +// | Mask 0 +-----> Mask 1 +------+ +// | | | | | +// +-----------+ +-----------+ v +-------------+ +// Apply | | GPU +// Mask +----> Composite +---->Blender +// ^ | | +// +-----------+ +-----------+ | +-------------+ +// | | | | | +// | Color 0 +-----> Color 1 +------+ +// | Filter | × | | +// | | | | +// +-----^-----+ +-----^-----+ +// | | +// + + +// Color UV 0 Color UV 1 + +#extension GL_GOOGLE_include_directive : enable + +precision highp float; + +#define FRAC_6_PI 1.9098593171027443 +#define FRAC_PI_3 1.0471975511965976 + +#define COMBINER_CTRL_MASK_MASK 0x3 +#define COMBINER_CTRL_MASK_WINDING 0x1 +#define COMBINER_CTRL_MASK_EVEN_ODD 0x2 + +#define COMBINER_CTRL_COLOR_ENABLE_MASK 0x1 + +#define COMBINER_CTRL_FILTER_MASK 0x3 +#define COMBINER_CTRL_FILTER_RADIAL_GRADIENT 0x1 +#define COMBINER_CTRL_FILTER_TEXT 0x2 +#define COMBINER_CTRL_FILTER_BLUR 0x3 + +#define COMBINER_CTRL_COMPOSITE_MASK 0xf +#define COMBINER_CTRL_COMPOSITE_NORMAL 0x0 +#define COMBINER_CTRL_COMPOSITE_MULTIPLY 0x1 +#define COMBINER_CTRL_COMPOSITE_SCREEN 0x2 +#define COMBINER_CTRL_COMPOSITE_OVERLAY 0x3 +#define COMBINER_CTRL_COMPOSITE_DARKEN 0x4 +#define COMBINER_CTRL_COMPOSITE_LIGHTEN 0x5 +#define COMBINER_CTRL_COMPOSITE_COLOR_DODGE 0x6 +#define COMBINER_CTRL_COMPOSITE_COLOR_BURN 0x7 +#define COMBINER_CTRL_COMPOSITE_HARD_LIGHT 0x8 +#define COMBINER_CTRL_COMPOSITE_SOFT_LIGHT 0x9 +#define COMBINER_CTRL_COMPOSITE_DIFFERENCE 0xa +#define COMBINER_CTRL_COMPOSITE_EXCLUSION 0xb +#define COMBINER_CTRL_COMPOSITE_HUE 0xc +#define COMBINER_CTRL_COMPOSITE_SATURATION 0xd +#define COMBINER_CTRL_COMPOSITE_COLOR 0xe +#define COMBINER_CTRL_COMPOSITE_LUMINOSITY 0xf + +#define COMBINER_CTRL_MASK_0_SHIFT 0 +#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; +uniform sampler2D uGammaLUT; +uniform vec4 uFilterParams0; +uniform vec4 uFilterParams1; +uniform vec4 uFilterParams2; +uniform vec2 uDestTextureSize; +uniform vec2 uColorTexture0Size; +uniform int uCtrl; + +in vec3 vMaskTexCoord0; +in vec3 vMaskTexCoord1; +in vec2 vColorTexCoord0; +in vec2 vColorTexCoord1; + +out vec4 oFragColor; + +// Color sampling + +vec4 sampleColor(sampler2D colorTexture, vec2 colorTexCoord) { + return texture(colorTexture, colorTexCoord); +} + +// Text filter + +float filterTextSample1Tap(float offset, sampler2D colorTexture, vec2 colorTexCoord) { + return texture(colorTexture, colorTexCoord + vec2(offset, 0.0)).r; +} + +// Samples 9 taps around the current pixel. +void filterTextSample9Tap(out vec4 outAlphaLeft, + out float outAlphaCenter, + out vec4 outAlphaRight, + sampler2D colorTexture, + vec2 colorTexCoord, + vec4 kernel, + float onePixel) { + bool wide = kernel.x > 0.0; + outAlphaLeft = + vec4(wide ? filterTextSample1Tap(-4.0 * onePixel, colorTexture, colorTexCoord) : 0.0, + filterTextSample1Tap(-3.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(-2.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(-1.0 * onePixel, colorTexture, colorTexCoord)); + outAlphaCenter = filterTextSample1Tap(0.0, colorTexture, colorTexCoord); + outAlphaRight = + vec4(filterTextSample1Tap(1.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(2.0 * onePixel, colorTexture, colorTexCoord), + filterTextSample1Tap(3.0 * onePixel, colorTexture, colorTexCoord), + wide ? filterTextSample1Tap(4.0 * onePixel, colorTexture, colorTexCoord) : 0.0); +} + +float filterTextConvolve7Tap(vec4 alpha0, vec3 alpha1, vec4 kernel) { + return dot(alpha0, kernel) + dot(alpha1, kernel.zyx); +} + +float filterTextGammaCorrectChannel(float bgColor, float fgColor, sampler2D gammaLUT) { + return texture(gammaLUT, vec2(fgColor, 1.0 - bgColor)).r; +} + +// `fgColor` is in linear space. +vec3 filterTextGammaCorrect(vec3 bgColor, vec3 fgColor, sampler2D gammaLUT) { + return vec3(filterTextGammaCorrectChannel(bgColor.r, fgColor.r, gammaLUT), + filterTextGammaCorrectChannel(bgColor.g, fgColor.g, gammaLUT), + filterTextGammaCorrectChannel(bgColor.b, fgColor.b, gammaLUT)); +} + +// | x y z w +// --------------+-------------------------------------------------------- +// filterParams0 | kernel[0] kernel[1] kernel[2] kernel[3] +// filterParams1 | bgColor.r bgColor.g bgColor.b - +// filterParams2 | fgColor.r fgColor.g fgColor.b gammaCorrectionEnabled +vec4 filterText(vec2 colorTexCoord, + sampler2D colorTexture, + sampler2D gammaLUT, + vec2 colorTextureSize, + vec4 filterParams0, + vec4 filterParams1, + vec4 filterParams2) { + // Unpack. + vec4 kernel = filterParams0; + vec3 bgColor = filterParams1.rgb; + vec3 fgColor = filterParams2.rgb; + bool gammaCorrectionEnabled = filterParams2.a != 0.0; + + // Apply defringing if necessary. + vec3 alpha; + if (kernel.w == 0.0) { + alpha = texture(colorTexture, colorTexCoord).rrr; + } else { + vec4 alphaLeft, alphaRight; + float alphaCenter; + filterTextSample9Tap(alphaLeft, + alphaCenter, + alphaRight, + colorTexture, + colorTexCoord, + kernel, + 1.0 / colorTextureSize.x); + + float r = filterTextConvolve7Tap(alphaLeft, vec3(alphaCenter, alphaRight.xy), kernel); + float g = filterTextConvolve7Tap(vec4(alphaLeft.yzw, alphaCenter), alphaRight.xyz, kernel); + float b = filterTextConvolve7Tap(vec4(alphaLeft.zw, alphaCenter, alphaRight.x), + alphaRight.yzw, + kernel); + + alpha = vec3(r, g, b); + } + + // Apply gamma correction if necessary. + if (gammaCorrectionEnabled) + alpha = filterTextGammaCorrect(bgColor, alpha, gammaLUT); + + // Finish. + return vec4(mix(bgColor, fgColor, alpha), 1.0); +} + +// Filters + +// | x y z w +// --------------+---------------------------------------------------- +// filterParams0 | srcOffset.x srcOffset.y support - +// filterParams1 | gaussCoeff.x gaussCoeff.y gaussCoeff.z - +// filterParams2 | - - - - +vec4 filterBlur(vec2 colorTexCoord, + sampler2D colorTexture, + vec2 colorTextureSize, + vec4 filterParams0, + vec4 filterParams1) { + // Unpack. + vec2 srcOffsetScale = filterParams0.xy / colorTextureSize; + int support = int(filterParams0.z); + vec3 gaussCoeff = filterParams1.xyz; + + // Set up our incremental calculation. + float gaussSum = gaussCoeff.x; + vec4 color = texture(colorTexture, colorTexCoord) * gaussCoeff.x; + gaussCoeff.xy *= gaussCoeff.yz; + + // This is a common trick that lets us use the texture filtering hardware to evaluate two + // texels at a time. The basic principle is that, if c0 and c1 are colors of adjacent texels + // and k0 and k1 are arbitrary factors, the formula `k0 * c0 + k1 * c1` is equivalent to + // `(k0 + k1) * lerp(c0, c1, k1 / (k0 + k1))`. Linear interpolation, as performed by the + // texturing hardware when sampling adjacent pixels in one direction, evaluates + // `lerp(c0, c1, t)` where t is the offset from the texel with color `c0`. To evaluate the + // formula `k0 * c0 + k1 * c1`, therefore, we can use the texture hardware to perform linear + // interpolation with `t = k1 / (k0 + k1)`. + for (int i = 1; i <= support; i += 2) { + float gaussPartialSum = gaussCoeff.x; + gaussCoeff.xy *= gaussCoeff.yz; + gaussPartialSum += gaussCoeff.x; + + vec2 srcOffset = srcOffsetScale * (float(i) + gaussCoeff.x / gaussPartialSum); + color += (texture(colorTexture, colorTexCoord - srcOffset) + + texture(colorTexture, colorTexCoord + srcOffset)) * gaussPartialSum; + + gaussSum += 2.0 * gaussPartialSum; + gaussCoeff.xy *= gaussCoeff.yz; + } + + // Finish. + return color / gaussSum; +} + +vec4 filterNone(vec2 colorTexCoord, sampler2D colorTexture) { + return sampleColor(colorTexture, colorTexCoord); +} + +vec4 filterColor(vec2 colorTexCoord, + sampler2D colorTexture, + sampler2D gammaLUT, + vec2 colorTextureSize, + vec4 filterParams0, + vec4 filterParams1, + vec4 filterParams2, + int colorFilter) { + switch (colorFilter) { + case COMBINER_CTRL_FILTER_BLUR: + return filterBlur(colorTexCoord, + colorTexture, + colorTextureSize, + filterParams0, + filterParams1); + case COMBINER_CTRL_FILTER_TEXT: + return filterText(colorTexCoord, + colorTexture, + gammaLUT, + colorTextureSize, + filterParams0, + filterParams1, + filterParams2); + } + return filterNone(colorTexCoord, colorTexture); +} + +// Compositing + +vec3 compositeSelect(bvec3 cond, vec3 ifTrue, vec3 ifFalse) { + return vec3(cond.x ? ifTrue.x : ifFalse.x, + cond.y ? ifTrue.y : ifFalse.y, + cond.z ? ifTrue.z : ifFalse.z); +} + +float compositeDivide(float num, float denom) { + return denom != 0.0 ? num / denom : 0.0; +} + +vec3 compositeColorDodge(vec3 destColor, vec3 srcColor) { + bvec3 destZero = equal(destColor, vec3(0.0)), srcOne = equal(srcColor, vec3(1.0)); + return compositeSelect(destZero, + vec3(0.0), + compositeSelect(srcOne, vec3(1.0), destColor / (vec3(1.0) - srcColor))); +} + +// https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative +vec3 compositeHSLToRGB(vec3 hsl) { + float a = hsl.y * min(hsl.z, 1.0 - hsl.z); + vec3 ks = mod(vec3(0.0, 8.0, 4.0) + vec3(hsl.x * FRAC_6_PI), 12.0); + return hsl.zzz - clamp(min(ks - vec3(3.0), vec3(9.0) - ks), -1.0, 1.0) * a; +} + +// https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB +vec3 compositeRGBToHSL(vec3 rgb) { + float v = max(max(rgb.r, rgb.g), rgb.b), xMin = min(min(rgb.r, rgb.g), rgb.b); + float c = v - xMin, l = mix(xMin, v, 0.5); + vec3 terms = rgb.r == v ? vec3(0.0, rgb.gb) : + rgb.g == v ? vec3(2.0, rgb.br) : + vec3(4.0, rgb.rg); + float h = FRAC_PI_3 * compositeDivide(terms.x * c + terms.y - terms.z, c); + float s = compositeDivide(c, v); + return vec3(h, s, l); +} + +vec3 compositeScreen(vec3 destColor, vec3 srcColor) { + return destColor + srcColor - destColor * srcColor; +} + +vec3 compositeHardLight(vec3 destColor, vec3 srcColor) { + return compositeSelect(lessThanEqual(srcColor, vec3(0.5)), + destColor * vec3(2.0) * srcColor, + compositeScreen(destColor, vec3(2.0) * srcColor - vec3(1.0))); +} + +vec3 compositeSoftLight(vec3 destColor, vec3 srcColor) { + vec3 darkenedDestColor = + compositeSelect(lessThanEqual(destColor, vec3(0.25)), + ((vec3(16.0) * destColor - 12.0) * destColor + 4.0) * destColor, + sqrt(destColor)); + vec3 factor = compositeSelect(lessThanEqual(srcColor, vec3(0.5)), + destColor * (vec3(1.0) - destColor), + darkenedDestColor - destColor); + return destColor + (srcColor * 2.0 - 1.0) * factor; +} + +vec3 compositeHSL(vec3 destColor, vec3 srcColor, int op) { + switch (op) { + case COMBINER_CTRL_COMPOSITE_HUE: + return vec3(srcColor.x, destColor.y, destColor.z); + case COMBINER_CTRL_COMPOSITE_SATURATION: + return vec3(destColor.x, srcColor.y, destColor.z); + case COMBINER_CTRL_COMPOSITE_COLOR: + return vec3(srcColor.x, srcColor.y, destColor.z); + default: + return vec3(destColor.x, destColor.y, srcColor.z); + } +} + +vec3 compositeRGB(vec3 destColor, vec3 srcColor, int op) { + switch (op) { + case COMBINER_CTRL_COMPOSITE_MULTIPLY: + return destColor * srcColor; + case COMBINER_CTRL_COMPOSITE_SCREEN: + return compositeScreen(destColor, srcColor); + case COMBINER_CTRL_COMPOSITE_OVERLAY: + return compositeHardLight(srcColor, destColor); + case COMBINER_CTRL_COMPOSITE_DARKEN: + return min(destColor, srcColor); + case COMBINER_CTRL_COMPOSITE_LIGHTEN: + return max(destColor, srcColor); + case COMBINER_CTRL_COMPOSITE_COLOR_DODGE: + return compositeColorDodge(destColor, srcColor); + case COMBINER_CTRL_COMPOSITE_COLOR_BURN: + return vec3(1.0) - compositeColorDodge(vec3(1.0) - destColor, vec3(1.0) - srcColor); + case COMBINER_CTRL_COMPOSITE_HARD_LIGHT: + return compositeHardLight(destColor, srcColor); + case COMBINER_CTRL_COMPOSITE_SOFT_LIGHT: + return compositeSoftLight(destColor, srcColor); + case COMBINER_CTRL_COMPOSITE_DIFFERENCE: + return abs(destColor - srcColor); + case COMBINER_CTRL_COMPOSITE_EXCLUSION: + return destColor + srcColor - vec3(2.0) * destColor * srcColor; + case COMBINER_CTRL_COMPOSITE_HUE: + case COMBINER_CTRL_COMPOSITE_SATURATION: + case COMBINER_CTRL_COMPOSITE_COLOR: + case COMBINER_CTRL_COMPOSITE_LUMINOSITY: + return compositeHSLToRGB(compositeHSL(compositeRGBToHSL(destColor), + compositeRGBToHSL(srcColor), + op)); + } + return srcColor; +} + +vec4 composite(vec4 srcColor, + sampler2D destTexture, + vec2 destTextureSize, + vec2 fragCoord, + int op) { + if (op == COMBINER_CTRL_COMPOSITE_NORMAL) + return srcColor; + + // FIXME(pcwalton): What should the output alpha be here? + vec2 destTexCoord = fragCoord / destTextureSize; + vec4 destColor = texture(destTexture, destTexCoord); + vec3 blendedRGB = compositeRGB(destColor.rgb, srcColor.rgb, op); + return vec4(srcColor.a * (1.0 - destColor.a) * srcColor.rgb + + srcColor.a * destColor.a * blendedRGB + + (1.0 - srcColor.a) * destColor.rgb, + 1.0); +} + +// Masks + +float sampleMask(float maskAlpha, + sampler2D maskTexture, + vec3 maskTexCoord, + int maskCtrl) { + if (maskCtrl == 0) + return maskAlpha; + float coverage = texture(maskTexture, maskTexCoord.xy).r + maskTexCoord.z; + if ((maskCtrl & COMBINER_CTRL_MASK_WINDING) != 0) + coverage = abs(coverage); + else + coverage = 1.0 - abs(1.0 - mod(coverage, 2.0)); + return min(maskAlpha, coverage); +} + +// Main function + +void calculateColor(int ctrl) { + // Sample mask. + int maskCtrl0 = (ctrl >> COMBINER_CTRL_MASK_0_SHIFT) & COMBINER_CTRL_MASK_MASK; + int maskCtrl1 = (ctrl >> COMBINER_CTRL_MASK_1_SHIFT) & COMBINER_CTRL_MASK_MASK; + float maskAlpha = 1.0; + maskAlpha = sampleMask(maskAlpha, uMaskTexture0, vMaskTexCoord0, maskCtrl0); + maskAlpha = sampleMask(maskAlpha, uMaskTexture1, vMaskTexCoord1, maskCtrl1); + + // Sample color. + vec4 color = vec4(0.0); + if (((ctrl >> COMBINER_CTRL_COLOR_0_ENABLE_SHIFT) & COMBINER_CTRL_COLOR_ENABLE_MASK) != 0) { + int color0Filter = (ctrl >> COMBINER_CTRL_COLOR_0_FILTER_SHIFT) & + COMBINER_CTRL_FILTER_MASK; + color += filterColor(vColorTexCoord0, + uColorTexture0, + uGammaLUT, + uColorTexture0Size, + uFilterParams0, + uFilterParams1, + 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 composite. + int compositeOp = (ctrl >> COMBINER_CTRL_COMPOSITE_SHIFT) & COMBINER_CTRL_COMPOSITE_MASK; + color = composite(color, uDestTexture, uDestTextureSize, gl_FragCoord.xy, compositeOp); + + // Premultiply alpha. + color.rgb *= color.a; + oFragColor = color; +} + +// Entry point +// +// TODO(pcwalton): Generate this dynamically. + +void main() { + calculateColor(uCtrl); +} diff --git a/shaders/tile_alpha.vs.glsl b/shaders/tile.vs.glsl similarity index 56% rename from shaders/tile_alpha.vs.glsl rename to shaders/tile.vs.glsl index ac480182..7d2419b7 100644 --- a/shaders/tile_alpha.vs.glsl +++ b/shaders/tile.vs.glsl @@ -1,6 +1,6 @@ #version 330 -// pathfinder/shaders/tile_alpha.vs.glsl +// pathfinder/shaders/tile.vs.glsl // // Copyright © 2020 The Pathfinder Project Developers. // @@ -16,19 +16,22 @@ uniform mat4 uTransform; uniform vec2 uTileSize; in ivec2 aTilePosition; -in vec2 aColorTexCoord; -in vec2 aMaskTexCoord; -in float aOpacity; +in vec2 aColorTexCoord0; +in vec2 aColorTexCoord1; +in vec2 aMaskTexCoord0; +in vec2 aMaskTexCoord1; +in ivec2 aMaskBackdrop; -out vec2 vColorTexCoord; -out vec2 vMaskTexCoord; -out float vOpacity; +out vec3 vMaskTexCoord0; +out vec3 vMaskTexCoord1; +out vec2 vColorTexCoord0; +out vec2 vColorTexCoord1; void main() { vec2 position = vec2(aTilePosition) * uTileSize; - - vMaskTexCoord = aMaskTexCoord; - vColorTexCoord = aColorTexCoord; - vOpacity = aOpacity; + vColorTexCoord0 = aColorTexCoord0; + vColorTexCoord1 = aColorTexCoord1; + vMaskTexCoord0 = vec3(aMaskTexCoord0, float(aMaskBackdrop.x)); + vMaskTexCoord1 = vec3(aMaskTexCoord1, float(aMaskBackdrop.y)); gl_Position = uTransform * vec4(position, 0.0, 1.0); } diff --git a/shaders/tile_alpha.fs.glsl b/shaders/tile_alpha.fs.glsl deleted file mode 100644 index dbb498c4..00000000 --- a/shaders/tile_alpha.fs.glsl +++ /dev/null @@ -1,24 +0,0 @@ -#version 330 - -// pathfinder/shaders/tile_alpha.fs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -out vec4 oFragColor; - -#include "tile_alpha_sample.inc.glsl" - -void main() { - vec4 srcRGBA = sampleSrcColor(); - oFragColor = vec4(srcRGBA.rgb * srcRGBA.a, srcRGBA.a); -} diff --git a/shaders/tile_alpha_difference.fs.glsl b/shaders/tile_alpha_difference.fs.glsl deleted file mode 100644 index 54d3996d..00000000 --- a/shaders/tile_alpha_difference.fs.glsl +++ /dev/null @@ -1,30 +0,0 @@ -#version 330 - -// pathfinder/shaders/tile_alpha_difference.fs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// The difference blend mode. - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -out vec4 oFragColor; - -#include "tile_alpha_sample.inc.glsl" - -void main() { - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - vec3 blended = abs(destRGBA.rgb - srcRGBA.rgb); - - oFragColor = blendColors(destRGBA, srcRGBA, blended); -} diff --git a/shaders/tile_alpha_dodgeburn.fs.glsl b/shaders/tile_alpha_dodgeburn.fs.glsl deleted file mode 100644 index 568f6979..00000000 --- a/shaders/tile_alpha_dodgeburn.fs.glsl +++ /dev/null @@ -1,41 +0,0 @@ -#version 330 - -// pathfinder/shaders/tile_alpha_dodgeburn.fs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Color dodge and color burn blend modes. - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -uniform int uBurn; - -out vec4 oFragColor; - -#include "tile_alpha_sample.inc.glsl" - -void main() { - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - vec3 dest = uBurn == 0 ? destRGBA.rgb : vec3(1.0) - destRGBA.rgb; - vec3 src = uBurn == 0 ? vec3(1.0) - srcRGBA.rgb : srcRGBA.rgb; - - bvec3 srcNonzero = notEqual(src, vec3(0.0)); - vec3 blended = min(vec3(srcNonzero.x ? dest.x / src.x : 1.0, - srcNonzero.y ? dest.y / src.y : 1.0, - srcNonzero.z ? dest.z / src.z : 1.0), - vec3(1.0)); - if (uBurn != 0) - blended = vec3(1.0) - blended; - - oFragColor = blendColors(destRGBA, srcRGBA, blended); -} diff --git a/shaders/tile_alpha_exclusion.fs.glsl b/shaders/tile_alpha_exclusion.fs.glsl deleted file mode 100644 index ebf20f27..00000000 --- a/shaders/tile_alpha_exclusion.fs.glsl +++ /dev/null @@ -1,31 +0,0 @@ -#version 330 - -// pathfinder/shaders/tile_alpha_exclusion.fs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// The exclusion blend mode. - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -out vec4 oFragColor; - -#include "tile_alpha_sample.inc.glsl" - -void main() { - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - vec3 dest = destRGBA.rgb, src = srcRGBA.rgb; - vec3 blended = dest + src - dest * src * 2.0; - - oFragColor = blendColors(destRGBA, srcRGBA, blended); -} diff --git a/shaders/tile_alpha_hsl.fs.glsl b/shaders/tile_alpha_hsl.fs.glsl deleted file mode 100644 index 7b74eebc..00000000 --- a/shaders/tile_alpha_hsl.fs.glsl +++ /dev/null @@ -1,70 +0,0 @@ -#version 330 - -// pathfinder/shaders/tile_alpha_hsl.fs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -uniform ivec3 uBlendHSL; - -out vec4 oFragColor; - -#include "tile_alpha_sample.inc.glsl" - -#define PI_2 6.283185307179586 -#define DEG_30_INV 1.9098593171027443 -#define DEG_60 1.0471975511965976 - -#define BLEND_TERM_DEST 0 -#define BLEND_TERM_SRC 1 - -// https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative -vec3 convertHSLToRGB(vec3 hsl) { - float a = hsl.y * min(hsl.z, 1.0 - hsl.z); - vec3 ks = mod(vec3(0.0, 8.0, 4.0) + vec3(hsl.x * DEG_30_INV), 12.0); - return hsl.zzz - clamp(min(ks - vec3(3.0), vec3(9.0) - ks), -1.0, 1.0) * a; -} - -// https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB -vec3 convertRGBToHSL(vec3 rgb) { - float v = max((rgb.x, rgb.y), rgb.z); - float c = v - min((rgb.x, rgb.y), rgb.z); - float l = v - 0.5 * c; - - vec3 tmp = vec3(0.0); - bvec3 is_v = equal(rgb, vec3(v)); - if (is_v.r) - tmp = vec3(0.0, rgb.gb); - else if (is_v.g) - tmp = vec3(2.0, rgb.br); - else if (is_v.b) - tmp = vec3(4.0, rgb.rg); - float h = DEG_60 * (tmp.x + (tmp.y - tmp.z) / c); - - float s = 0.0; - if (l > 0.0 && l < 1.0) - s = (v - l) / min(l, 1.0 - l); - - return vec3(h, s, l); -} - -void main() { - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - vec3 destHSL = convertRGBToHSL(destRGBA.rgb); - vec3 srcHSL = convertRGBToHSL(srcRGBA.rgb); - vec3 blendedHSL = select3(equal(uBlendHSL, ivec3(BLEND_TERM_DEST)), destHSL, srcHSL); - vec3 blendedRGB = convertHSLToRGB(blendedHSL); - - oFragColor = blendColors(destRGBA, srcRGBA, blendedRGB); -} diff --git a/shaders/tile_alpha_overlay.fs.glsl b/shaders/tile_alpha_overlay.fs.glsl deleted file mode 100644 index eb8e6cd3..00000000 --- a/shaders/tile_alpha_overlay.fs.glsl +++ /dev/null @@ -1,51 +0,0 @@ -#version 330 - -// pathfinder/shaders/tile_alpha_overlay.fs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Multiply, screen, overlay, and hard light filters. - -#extension GL_GOOGLE_include_directive : enable - -#define OVERLAY_BLEND_MODE_MULTIPLY 0 -#define OVERLAY_BLEND_MODE_SCREEN 1 -#define OVERLAY_BLEND_MODE_HARD_LIGHT 2 -#define OVERLAY_BLEND_MODE_OVERLAY 3 - -precision highp float; - -uniform int uBlendMode; - -out vec4 oFragColor; - -#include "tile_alpha_sample.inc.glsl" - -void main() { - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - bool reversed = uBlendMode == OVERLAY_BLEND_MODE_OVERLAY; - vec3 src = reversed ? srcRGBA.rgb : destRGBA.rgb; - vec3 dest = reversed ? destRGBA.rgb : srcRGBA.rgb; - - vec3 multiply = src * dest; - vec3 blended; - if (uBlendMode == OVERLAY_BLEND_MODE_MULTIPLY) { - blended = multiply; - } else { - vec3 screen = dest + src - multiply; - if (uBlendMode == OVERLAY_BLEND_MODE_SCREEN) - blended = screen; - else - blended = select3(lessThanEqual(src, vec3(0.5)), multiply, screen * 2.0 - 1.0); - } - - oFragColor = blendColors(destRGBA, srcRGBA, blended); -} diff --git a/shaders/tile_alpha_sample.inc.glsl b/shaders/tile_alpha_sample.inc.glsl deleted file mode 100644 index b1858f1f..00000000 --- a/shaders/tile_alpha_sample.inc.glsl +++ /dev/null @@ -1,42 +0,0 @@ -// pathfinder/shaders/tile_alpha_sample.inc.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -uniform sampler2D uStencilTexture; -uniform sampler2D uPaintTexture; -uniform sampler2D uDest; -uniform vec2 uFramebufferSize; - -in vec2 vColorTexCoord; -in vec2 vMaskTexCoord; -in float vOpacity; - -// NB: This does not premultiply. -vec4 sampleSrcColor() { - float coverage = texture(uStencilTexture, vMaskTexCoord).r; - vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); - return vec4(srcRGBA.rgb, srcRGBA.a * coverage * vOpacity); -} - -vec4 sampleDestColor() { - vec2 destTexCoord = gl_FragCoord.xy / uFramebufferSize; - return texture(uDest, destTexCoord); -} - -// FIXME(pcwalton): What should the output alpha be here? -vec4 blendColors(vec4 destRGBA, vec4 srcRGBA, vec3 blendedRGB) { - return vec4(srcRGBA.a * (1.0 - destRGBA.a) * srcRGBA.rgb + - srcRGBA.a * destRGBA.a * blendedRGB + - (1.0 - srcRGBA.a) * destRGBA.a * destRGBA.rgb, - 1.0); -} - -vec3 select3(bvec3 cond, vec3 a, vec3 b) { - return vec3(cond.x ? a.x : b.x, cond.y ? a.y : b.y, cond.z ? a.z : b.z); -} diff --git a/shaders/tile_alpha_softlight.fs.glsl b/shaders/tile_alpha_softlight.fs.glsl deleted file mode 100644 index 4911986c..00000000 --- a/shaders/tile_alpha_softlight.fs.glsl +++ /dev/null @@ -1,37 +0,0 @@ -#version 330 - -// pathfinder/shaders/tile_alpha_softlight.fs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// The soft light blend mode. - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -out vec4 oFragColor; - -#include "tile_alpha_sample.inc.glsl" - -void main() { - vec4 srcRGBA = sampleSrcColor(); - vec4 destRGBA = sampleDestColor(); - - // B(Cb, Cs) = Cb*(1 + (2*Cs - 1)*X) - // where X = if Cs <= 0.5 then 1 - Cb else D - 1 - // and D = if Cb <= 0.25 then (16*Cb - 12)*Cb + 4 else 1/sqrt(Cb) - vec3 dest = destRGBA.rgb, src = srcRGBA.rgb; - bvec3 destDark = lessThanEqual(dest, vec3(0.25)), srcDark = lessThanEqual(src, vec3(0.5)); - vec3 d = select3(destDark, (dest * 16.0 - 12.0) * dest + 4.0, inversesqrt(dest)); - vec3 x = select3(srcDark, vec3(1.0) - dest, d - 1.0); - vec3 blended = dest * ((src * 2.0 - 1.0) * x + 1.0); - - oFragColor = blendColors(destRGBA, srcRGBA, blended); -} diff --git a/shaders/tile_solid.fs.glsl b/shaders/tile_solid.fs.glsl deleted file mode 100644 index dcd2c19c..00000000 --- a/shaders/tile_solid.fs.glsl +++ /dev/null @@ -1,24 +0,0 @@ -#version 330 - -// pathfinder/shaders/tile_solid.fs.glsl -// -// Copyright © 2019 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -uniform sampler2D uColorTexture; - -in vec2 vColorTexCoord; - -out vec4 oFragColor; - -void main() { - vec4 color = texture(uColorTexture, vColorTexCoord); - oFragColor = vec4(color.rgb * color.a, color.a); -} diff --git a/shaders/tile_solid.vs.glsl b/shaders/tile_solid.vs.glsl deleted file mode 100644 index bfbec286..00000000 --- a/shaders/tile_solid.vs.glsl +++ /dev/null @@ -1,27 +0,0 @@ -#version 330 - -// pathfinder/shaders/tile_solid.vs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -precision highp float; - -uniform mat4 uTransform; -uniform vec2 uTileSize; - -in ivec2 aTilePosition; -in vec2 aColorTexCoord; - -out vec2 vColorTexCoord; - -void main() { - vec2 position = vec2(aTilePosition) * uTileSize; - vColorTexCoord = aColorTexCoord; - gl_Position = uTransform * vec4(position, 0.0, 1.0); -} diff --git a/shaders/tile_solid_filter_blur.fs.glsl b/shaders/tile_solid_filter_blur.fs.glsl deleted file mode 100644 index 04f8bd3e..00000000 --- a/shaders/tile_solid_filter_blur.fs.glsl +++ /dev/null @@ -1,66 +0,0 @@ -#version 330 - -// pathfinder/shaders/tile_solid_filter_blur.fs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// TODO(pcwalton): This could be significantly optimized by operating on a -// sparse per-tile basis. - -// The technique here is "Incremental Computation of the Gaussian", GPU Gems 3, chapter 40: -// https://developer.nvidia.com/gpugems/gpugems3/part-vi-gpu-computing/chapter-40-incremental-computation-gaussian -// -// It's the same technique WebRender uses. - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -uniform sampler2D uColorTexture; -uniform vec2 uSrcOffsetScale; -uniform vec3 uInitialGaussCoeff; -uniform int uSupport; - -in vec2 vColorTexCoord; - -out vec4 oFragColor; - -void main() { - // Set up our incremental calculation. - vec3 gaussCoeff = uInitialGaussCoeff; - float gaussSum = gaussCoeff.x; - vec4 color = texture(uColorTexture, vColorTexCoord) * gaussCoeff.x; - gaussCoeff.xy *= gaussCoeff.yz; - - // This is a common trick that lets us use the texture filtering hardware to evaluate two - // texels at a time. The basic principle is that, if c0 and c1 are colors of adjacent texels - // and k0 and k1 are arbitrary factors, the formula `k0 * c0 + k1 * c1` is equivalent to - // `(k0 + k1) * lerp(c0, c1, k1 / (k0 + k1))`. Linear interpolation, as performed by the - // texturing hardware when sampling adjacent pixels in one direction, evaluates - // `lerp(c0, c1, t)` where t is the offset from the texel with color `c0`. To evaluate the - // formula `k0 * c0 + k1 * c1`, therefore, we can use the texture hardware to perform linear - // interpolation with `t = k1 / (k0 + k1)`. - for (int i = 1; i <= uSupport; i += 2) { - float gaussPartialSum = gaussCoeff.x; - gaussCoeff.xy *= gaussCoeff.yz; - gaussPartialSum += gaussCoeff.x; - - vec2 srcOffset = uSrcOffsetScale * (float(i) + gaussCoeff.x / gaussPartialSum); - color += (texture(uColorTexture, vColorTexCoord - srcOffset) + - texture(uColorTexture, vColorTexCoord + srcOffset)) * gaussPartialSum; - - gaussSum += 2.0 * gaussPartialSum; - gaussCoeff.xy *= gaussCoeff.yz; - } - - // Finish. - color /= gaussSum; - color.rgb *= color.a; - oFragColor = color; -} diff --git a/shaders/tile_solid_filter_text.fs.glsl b/shaders/tile_solid_filter_text.fs.glsl deleted file mode 100644 index e39d5d67..00000000 --- a/shaders/tile_solid_filter_text.fs.glsl +++ /dev/null @@ -1,58 +0,0 @@ -#version 330 - -// pathfinder/shaders/tile_solid_filter_text.fs.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#extension GL_GOOGLE_include_directive : enable - -precision highp float; - -uniform sampler2D uColorTexture; -uniform vec2 uSrcSize; -uniform vec4 uFGColor; -uniform vec4 uBGColor; -uniform int uGammaCorrectionEnabled; - -in vec2 vColorTexCoord; - -out vec4 oFragColor; - -#include "tile_solid_filter_text_gamma_correct.inc.glsl" -#include "tile_solid_filter_text_convolve.inc.glsl" - -// Convolve horizontally in this pass. -float sample1Tap(float offset) { - return texture(uColorTexture, vec2(vColorTexCoord.x + offset, vColorTexCoord.y)).r; -} - -void main() { - // Apply defringing if necessary. - vec3 alpha; - if (uKernel.w == 0.0) { - alpha = texture(uColorTexture, vColorTexCoord).rrr; - } else { - vec4 alphaLeft, alphaRight; - float alphaCenter; - sample9Tap(alphaLeft, alphaCenter, alphaRight, 1.0 / uSrcSize.x); - - float r = convolve7Tap(alphaLeft, vec3(alphaCenter, alphaRight.xy)); - float g = convolve7Tap(vec4(alphaLeft.yzw, alphaCenter), alphaRight.xyz); - float b = convolve7Tap(vec4(alphaLeft.zw, alphaCenter, alphaRight.x), alphaRight.yzw); - - alpha = vec3(r, g, b); - } - - // Apply gamma correction if necessary. - if (uGammaCorrectionEnabled != 0) - alpha = gammaCorrect(uBGColor.rgb, alpha); - - // Finish. - oFragColor = vec4(mix(uBGColor.rgb, uFGColor.rgb, alpha), 1.0); -} diff --git a/shaders/tile_solid_filter_text_convolve.inc.glsl b/shaders/tile_solid_filter_text_convolve.inc.glsl deleted file mode 100644 index 220a151f..00000000 --- a/shaders/tile_solid_filter_text_convolve.inc.glsl +++ /dev/null @@ -1,37 +0,0 @@ -// pathfinder/shaders/tile_solid_filter_text_convolve.inc.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Zero if no convolution is to be performed. -uniform vec4 uKernel; - -// This function is expected to return the alpha value of the pixel at the -// given offset in pixels. Offset 0.0 represents the current pixel. -float sample1Tap(float offset); - -// Samples 9 taps around the current pixel. -void sample9Tap(out vec4 outAlphaLeft, - out float outAlphaCenter, - out vec4 outAlphaRight, - float onePixel) { - outAlphaLeft = vec4(uKernel.x > 0.0 ? sample1Tap(-4.0 * onePixel) : 0.0, - sample1Tap(-3.0 * onePixel), - sample1Tap(-2.0 * onePixel), - sample1Tap(-1.0 * onePixel)); - outAlphaCenter = sample1Tap(0.0); - outAlphaRight = vec4(sample1Tap(1.0 * onePixel), - sample1Tap(2.0 * onePixel), - sample1Tap(3.0 * onePixel), - uKernel.x > 0.0 ? sample1Tap(4.0 * onePixel) : 0.0); -} - -// Convolves 7 values with the kernel. -float convolve7Tap(vec4 alpha0, vec3 alpha1) { - return dot(alpha0, uKernel) + dot(alpha1, uKernel.zyx); -} diff --git a/shaders/tile_solid_filter_text_gamma_correct.inc.glsl b/shaders/tile_solid_filter_text_gamma_correct.inc.glsl deleted file mode 100644 index 181817bc..00000000 --- a/shaders/tile_solid_filter_text_gamma_correct.inc.glsl +++ /dev/null @@ -1,24 +0,0 @@ -// pathfinder/shaders/tile_solid_filter_text_gamma_correct.inc.glsl -// -// Copyright © 2020 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// The lookup table for gamma correction, in the same format WebRender -// expects. -uniform sampler2D uGammaLUT; - -float gammaCorrectChannel(float bgColor, float fgColor) { - return texture(uGammaLUT, vec2(fgColor, 1.0 - bgColor)).r; -} - -// `fgColor` is in linear space. -vec3 gammaCorrect(vec3 bgColor, vec3 fgColor) { - return vec3(gammaCorrectChannel(bgColor.r, fgColor.r), - gammaCorrectChannel(bgColor.g, fgColor.g), - gammaCorrectChannel(bgColor.b, fgColor.b)); -}