Replace the individual tile shaders with an ubershader

This commit is contained in:
Patrick Walton 2020-03-19 16:44:45 -07:00
parent 51277a2027
commit 0c93045f50
68 changed files with 2673 additions and 4325 deletions

4
Cargo.lock generated
View File

@ -1131,6 +1131,9 @@ dependencies = [
name = "instant" name = "instant"
version = "0.1.2" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "iovec" name = "iovec"
@ -1808,6 +1811,7 @@ dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_color 0.1.0", "pathfinder_color 0.1.0",
"pathfinder_content 0.1.0", "pathfinder_content 0.1.0",

View File

@ -12,7 +12,7 @@
use pathfinder_color::ColorU; use pathfinder_color::ColorU;
use pathfinder_content::dash::OutlineDash; 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::fill::FillRule;
use pathfinder_content::gradient::Gradient; use pathfinder_content::gradient::Gradient;
use pathfinder_content::outline::{ArcDirection, Contour, Outline}; use pathfinder_content::outline::{ArcDirection, Contour, Outline};
@ -251,11 +251,9 @@ impl CanvasRenderingContext2D {
let transform = self.current_state.transform; let transform = self.current_state.transform;
let clip_path = self.current_state.clip_path; let clip_path = self.current_state.clip_path;
let blend_mode = self.current_state.global_composite_operation.to_blend_mode(); 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; let opacity = (self.current_state.global_alpha * 255.0) as u8;
if !self.current_state.shadow_paint.is_fully_transparent() { 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 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); let paint = self.current_state.resolve_paint(&self.current_state.shadow_paint);
@ -273,10 +271,8 @@ impl CanvasRenderingContext2D {
self.scene.push_path(path); self.scene.push_path(path);
self.composite_shadow_blur_render_targets_if_needed(shadow_blur_render_target_ids); 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); outline.transform(&transform);
let mut path = DrawPath::new(outline, paint_id); let mut path = DrawPath::new(outline, paint_id);
@ -285,18 +281,6 @@ impl CanvasRenderingContext2D {
path.set_blend_mode(blend_mode); path.set_blend_mode(blend_mode);
path.set_opacity(opacity); path.set_opacity(opacity);
self.scene.push_path(path); 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<CompositeOp>)
-> Option<RenderTargetId> {
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]> { 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]) Some([render_target_id_a, render_target_id_b])
} }
fn composite_render_target_if_needed(&mut self,
composite_op: Option<CompositeOp>,
render_target_id: Option<RenderTargetId>) {
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( fn composite_shadow_blur_render_targets_if_needed(
&mut self, &mut self,
render_target_ids: Option<[RenderTargetId; 2]>) { render_target_ids: Option<[RenderTargetId; 2]>) {
@ -679,6 +650,7 @@ pub enum CompositeOperation {
impl CompositeOperation { impl CompositeOperation {
fn to_blend_mode(self) -> BlendMode { fn to_blend_mode(self) -> BlendMode {
match self { match self {
CompositeOperation::Copy => BlendMode::Copy,
CompositeOperation::SourceAtop => BlendMode::SrcAtop, CompositeOperation::SourceAtop => BlendMode::SrcAtop,
CompositeOperation::DestinationOver => BlendMode::DestOver, CompositeOperation::DestinationOver => BlendMode::DestOver,
CompositeOperation::DestinationOut => BlendMode::DestOut, CompositeOperation::DestinationOut => BlendMode::DestOut,
@ -699,43 +671,11 @@ impl CompositeOperation {
CompositeOperation::Saturation => BlendMode::Saturation, CompositeOperation::Saturation => BlendMode::Saturation,
CompositeOperation::Color => BlendMode::Color, CompositeOperation::Color => BlendMode::Color,
CompositeOperation::Luminosity => BlendMode::Luminosity, CompositeOperation::Luminosity => BlendMode::Luminosity,
CompositeOperation::SourceOver | CompositeOperation::SourceOver => BlendMode::SrcOver,
CompositeOperation::SourceIn | CompositeOperation::SourceIn => BlendMode::SrcIn,
CompositeOperation::SourceOut | CompositeOperation::SourceOut => BlendMode::SrcOut,
CompositeOperation::DestinationIn | CompositeOperation::DestinationIn => BlendMode::DestIn,
CompositeOperation::DestinationAtop | CompositeOperation::DestinationAtop => BlendMode::DestAtop,
CompositeOperation::Copy => BlendMode::SrcOver,
}
}
fn to_composite_op(self) -> Option<CompositeOp> {
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,
} }
} }
} }

View File

@ -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; pub const MAX_STEM_DARKENING_PIXELS_PER_EM: f32 = 72.0;
/// Effects that can be applied to a layer. /// Effects that can be applied to a layer.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Default)]
pub struct Effects { pub struct Effects {
/// The shader that should be used when compositing this layer onto its destination. /// The shader that should be used when compositing this layer onto its destination.
pub filter: Filter, pub filter: Filter,
@ -38,11 +38,8 @@ pub struct Effects {
/// The shader that should be used when compositing this layer onto its destination. /// The shader that should be used when compositing this layer onto its destination.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub enum Filter { pub enum Filter {
/// A Porter-Duff compositing operation. /// No special filter.
/// None,
/// 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),
/// Performs postprocessing operations useful for monochrome text. /// Performs postprocessing operations useful for monochrome text.
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. /// 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)] #[derive(Clone, Copy, PartialEq, Debug)]
pub enum BlendMode { pub enum BlendMode {
// Supported by GPU blender // Porter-Duff, supported by GPU blender
Clear, Clear,
Copy,
SrcIn,
SrcOut,
SrcOver, SrcOver,
DestOver,
DestOut,
SrcAtop, SrcAtop,
DestIn,
DestOut,
DestOver,
DestAtop,
Xor, Xor,
Lighter, Lighter,
Lighten,
Darken,
// Overlay // Others, unsupported by GPU blender
Darken,
Lighten,
Multiply, Multiply,
Screen, Screen,
HardLight, HardLight,
Overlay, Overlay,
// Dodge/burn
ColorDodge, ColorDodge,
ColorBurn, ColorBurn,
// Soft light
SoftLight, SoftLight,
// Difference
Difference, Difference,
// Exclusion
Exclusion, Exclusion,
// HSL
Hue, Hue,
Saturation, Saturation,
Color, Color,
@ -138,13 +109,6 @@ pub enum BlurDirection {
Y, Y,
} }
impl Default for CompositeOp {
#[inline]
fn default() -> CompositeOp {
CompositeOp::SrcOver
}
}
impl Default for BlendMode { impl Default for BlendMode {
#[inline] #[inline]
fn default() -> BlendMode { fn default() -> BlendMode {
@ -152,6 +116,13 @@ impl Default for BlendMode {
} }
} }
impl Default for Filter {
#[inline]
fn default() -> Filter {
Filter::None
}
}
impl Effects { impl Effects {
#[inline] #[inline]
pub fn new(filter: Filter) -> Effects { pub fn new(filter: Filter) -> Effects {
@ -173,6 +144,44 @@ impl BlendMode {
BlendMode::Lighter | BlendMode::Lighter |
BlendMode::Lighten | BlendMode::Lighten |
BlendMode::Darken | 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::Multiply |
BlendMode::Screen | BlendMode::Screen |
BlendMode::HardLight | BlendMode::HardLight |

View File

@ -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<GLDevice>) { fn reset_render_state(&self, render_state: &RenderState<GLDevice>) {
self.reset_render_options(&render_state.options); self.reset_render_options(&render_state.options);
for texture_unit in 0..(render_state.textures.len() as u32) { for texture_unit in 0..(render_state.textures.len() as u32) {
self.unbind_texture(texture_unit); self.unbind_texture(texture_unit);
} }
render_state.uniforms.iter().for_each(|(uniform, data)| self.unset_uniform(uniform, data));
self.unuse_program(); self.unuse_program();
self.unbind_vertex_array(); self.unbind_vertex_array();
} }

View File

@ -11,21 +11,22 @@
//! Packs data onto the GPU. //! Packs data onto the GPU.
use crate::concurrent::executor::Executor; use crate::concurrent::executor::Executor;
use crate::gpu::renderer::{BlendModeProgram, MASK_TILES_ACROSS}; use crate::gpu::renderer::{BlendModeExt, MASK_TILES_ACROSS, MASK_TILES_DOWN};
use crate::gpu_data::{AlphaTile, AlphaTileBatch, AlphaTileVertex, FillBatchPrimitive, MaskTile}; use crate::gpu_data::{FillBatchPrimitive, RenderCommand, TexturePageId, Tile, TileBatch};
use crate::gpu_data::{MaskTileVertex, RenderCommand, SolidTile, SolidTileBatch}; use crate::gpu_data::{TileBatchTexture, TileObjectPrimitive, TileVertex};
use crate::gpu_data::{TexturePageId, TileObjectPrimitive};
use crate::options::{PreparedBuildOptions, RenderCommandListener}; use crate::options::{PreparedBuildOptions, RenderCommandListener};
use crate::paint::{PaintInfo, PaintMetadata, RenderTargetMetadata}; use crate::paint::{PaintInfo, PaintMetadata, RenderTargetMetadata};
use crate::scene::{DisplayItem, Scene}; use crate::scene::{DisplayItem, Scene};
use crate::tile_map::DenseTileMap; 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 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::fill::FillRule;
use pathfinder_content::render_target::RenderTargetId; use pathfinder_content::render_target::RenderTargetId;
use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8}; use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8};
use pathfinder_geometry::rect::{RectF, RectI}; use pathfinder_geometry::rect::{RectF, RectI};
use pathfinder_geometry::transform2d::Transform2F;
use pathfinder_geometry::util; use pathfinder_geometry::util;
use pathfinder_geometry::vector::{Vector2F, Vector2I}; use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_gpu::TextureSamplingFlags; use pathfinder_gpu::TextureSamplingFlags;
@ -39,7 +40,6 @@ pub(crate) struct SceneBuilder<'a> {
built_options: &'a PreparedBuildOptions, built_options: &'a PreparedBuildOptions,
next_alpha_tile_index: AtomicUsize, next_alpha_tile_index: AtomicUsize,
next_mask_tile_index: AtomicUsize,
pub(crate) listener: Box<dyn RenderCommandListener>, pub(crate) listener: Box<dyn RenderCommandListener>,
} }
@ -55,21 +55,32 @@ pub(crate) struct ObjectBuilder {
struct BuiltDrawPath { struct BuiltDrawPath {
path: BuiltPath, path: BuiltPath,
blend_mode: BlendMode, blend_mode: BlendMode,
sampling_flags: TextureSamplingFlags, color_texture_page_0: TexturePageId,
color_texture_page: TexturePageId, color_texture_page_1: TexturePageId,
sampling_flags_0: TextureSamplingFlags,
sampling_flags_1: TextureSamplingFlags,
mask_0_fill_rule: FillRule,
mask_1_fill_rule: Option<FillRule>,
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct BuiltPath { pub(crate) struct BuiltPath {
pub mask_tiles: Vec<MaskTile>, pub solid_tiles: SolidTiles,
pub alpha_tiles: Vec<AlphaTile>, pub empty_tiles: Vec<Tile>,
pub solid_tiles: Vec<SolidTileInfo>, pub single_mask_tiles: Vec<Tile>,
pub dual_mask_tiles: Vec<Tile>,
pub tiles: DenseTileMap<TileObjectPrimitive>, pub tiles: DenseTileMap<TileObjectPrimitive>,
pub fill_rule: FillRule, pub fill_rule: FillRule,
} }
#[derive(Clone, Debug)]
pub(crate) enum SolidTiles {
Occluders(Vec<Occluder>),
Regular(Vec<Tile>),
}
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub(crate) struct SolidTileInfo { pub(crate) struct Occluder {
pub(crate) coords: Vector2I, pub(crate) coords: Vector2I,
} }
@ -82,10 +93,7 @@ impl<'a> SceneBuilder<'a> {
SceneBuilder { SceneBuilder {
scene, scene,
built_options, built_options,
next_alpha_tile_index: AtomicUsize::new(0), next_alpha_tile_index: AtomicUsize::new(0),
next_mask_tile_index: AtomicUsize::new(0),
listener, listener,
} }
} }
@ -113,6 +121,8 @@ impl<'a> SceneBuilder<'a> {
render_commands, render_commands,
paint_metadata, paint_metadata,
render_target_metadata, render_target_metadata,
opacity_tile_page,
opacity_tile_transform,
} = self.scene.build_paint_info(); } = self.scene.build_paint_info();
for render_command in render_commands { for render_command in render_commands {
self.listener.send(render_command); 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 effective_view_box = self.scene.effective_view_box(self.built_options);
let built_clip_paths = executor.build_vector(clip_path_count, |path_index| { 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| { let built_draw_paths = executor.build_vector(draw_path_count, |path_index| {
self.build_draw_path(path_index, self.build_draw_path(DrawPathBuildParams {
effective_view_box, path_build_params: PathBuildParams {
&self.built_options, path_index,
&self.scene, view_box: effective_view_box,
&paint_metadata, built_options: &self.built_options,
&built_clip_paths) scene: &self.scene,
},
paint_metadata: &paint_metadata,
opacity_tile_page,
opacity_tile_transform,
built_clip_paths: &built_clip_paths,
})
}); });
self.finish_building(&paint_metadata, self.finish_building(&paint_metadata, &render_target_metadata, built_draw_paths);
&render_target_metadata,
built_clip_paths,
built_draw_paths);
let build_time = Instant::now() - start_time; let build_time = Instant::now() - start_time;
self.listener.send(RenderCommand::Finish { build_time }); self.listener.send(RenderCommand::Finish { build_time });
} }
fn build_clip_path( fn build_clip_path(&self, params: PathBuildParams) -> BuiltPath {
&self, let PathBuildParams { path_index, view_box, built_options, scene } = params;
path_index: usize,
view_box: RectF,
built_options: &PreparedBuildOptions,
scene: &Scene,
) -> BuiltPath {
let path_object = &scene.clip_paths[path_index]; let path_object = &scene.clip_paths[path_index];
let outline = scene.apply_render_options(path_object.outline(), built_options); let outline = scene.apply_render_options(path_object.outline(), built_options);
@ -156,7 +169,6 @@ impl<'a> SceneBuilder<'a> {
&outline, &outline,
path_object.fill_rule(), path_object.fill_rule(),
view_box, view_box,
path_index as u16,
TilingPathInfo::Clip); TilingPathInfo::Clip);
tiler.generate_tiles(); tiler.generate_tiles();
@ -165,15 +177,15 @@ impl<'a> SceneBuilder<'a> {
tiler.object_builder.built_path tiler.object_builder.built_path
} }
fn build_draw_path( fn build_draw_path(&self, params: DrawPathBuildParams) -> BuiltDrawPath {
&self, let DrawPathBuildParams {
path_index: usize, path_build_params: PathBuildParams { path_index, view_box, built_options, scene },
view_box: RectF, paint_metadata,
built_options: &PreparedBuildOptions, opacity_tile_page,
scene: &Scene, opacity_tile_transform,
paint_metadata: &[PaintMetadata], built_clip_paths,
built_clip_paths: &[BuiltPath], } = params;
) -> BuiltDrawPath {
let path_object = &scene.paths[path_index]; let path_object = &scene.paths[path_index];
let outline = scene.apply_render_options(path_object.outline(), built_options); let outline = scene.apply_render_options(path_object.outline(), built_options);
@ -186,9 +198,9 @@ impl<'a> SceneBuilder<'a> {
&outline, &outline,
path_object.fill_rule(), path_object.fill_rule(),
view_box, view_box,
path_index as u16,
TilingPathInfo::Draw(DrawTilingPathInfo { TilingPathInfo::Draw(DrawTilingPathInfo {
paint_metadata, paint_metadata,
opacity_tile_transform,
blend_mode: path_object.blend_mode(), blend_mode: path_object.blend_mode(),
opacity: path_object.opacity(), opacity: path_object.opacity(),
built_clip_path, built_clip_path,
@ -201,26 +213,21 @@ impl<'a> SceneBuilder<'a> {
BuiltDrawPath { BuiltDrawPath {
path: tiler.object_builder.built_path, path: tiler.object_builder.built_path,
blend_mode: path_object.blend_mode(), blend_mode: path_object.blend_mode(),
color_texture_page: paint_metadata.location.page, color_texture_page_0: paint_metadata.location.page,
sampling_flags: paint_metadata.sampling_flags, 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, fn cull_tiles(&self,
paint_metadata: &[PaintMetadata], paint_metadata: &[PaintMetadata],
render_target_metadata: &[RenderTargetMetadata], render_target_metadata: &[RenderTargetMetadata],
built_clip_paths: Vec<BuiltPath>,
built_draw_paths: Vec<BuiltDrawPath>) built_draw_paths: Vec<BuiltDrawPath>)
-> CulledTiles { -> CulledTiles {
let mut culled_tiles = CulledTiles { let mut culled_tiles = CulledTiles { display_list: vec![] };
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 remaining_layer_z_buffers = self.build_solid_tiles(&built_draw_paths); let mut remaining_layer_z_buffers = self.build_solid_tiles(&built_draw_paths);
remaining_layer_z_buffers.reverse(); 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_z_buffer = remaining_layer_z_buffers.pop().unwrap();
let first_solid_tiles = first_z_buffer.build_solid_tiles(paint_metadata); let first_solid_tiles = first_z_buffer.build_solid_tiles(paint_metadata);
for batch in first_solid_tiles.batches { 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]; 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 z_buffer = remaining_layer_z_buffers.pop().unwrap();
let solid_tiles = z_buffer.build_solid_tiles(paint_metadata); let solid_tiles = z_buffer.build_solid_tiles(paint_metadata);
for batch in solid_tiles.batches { 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); layer_z_buffers_stack.push(z_buffer);
} }
@ -271,16 +278,22 @@ impl<'a> SceneBuilder<'a> {
let uv_rect = let uv_rect =
RectI::new(tile_coords, Vector2I::splat(1)).to_f32() RectI::new(tile_coords, Vector2I::splat(1)).to_f32()
.scale_xy(uv_scale); .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, tiles,
color_texture_page: metadata.location.page, color_texture_0: Some(TileBatchTexture {
sampling_flags: TextureSamplingFlags::empty(), page: metadata.location.page,
sampling_flags: TextureSamplingFlags::empty(),
}),
color_texture_1: None,
effects, 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; current_depth += 1;
} }
@ -290,55 +303,63 @@ impl<'a> SceneBuilder<'a> {
} => { } => {
for draw_path_index in start_draw_path_index..end_draw_path_index { 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]; 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 debug_assert!(built_draw_path.path.empty_tiles.is_empty() ||
// have to break a batch due to blend mode or paint page. Note that every built_draw_path.blend_mode.is_destructive());
// path with a blend mode that requires a readable framebuffer needs its self.add_alpha_tiles(&mut culled_tiles,
// own batch. layer_z_buffer,
// &built_draw_path.path.empty_tiles,
// TODO(pcwalton): If we really wanted to, we could use tile maps to avoid current_depth,
// batch breaks in some cases… None,
match culled_tiles.display_list.last() { None,
Some(&CulledDisplayItem::DrawAlphaTiles(AlphaTileBatch { built_draw_path.blend_mode,
tiles: _, None,
color_texture_page, None);
blend_mode,
sampling_flags self.add_alpha_tiles(&mut culled_tiles,
})) if color_texture_page == built_draw_path.color_texture_page && layer_z_buffer,
blend_mode == built_draw_path.blend_mode && &built_draw_path.path.single_mask_tiles,
sampling_flags == built_draw_path.sampling_flags && current_depth,
!BlendModeProgram::from_blend_mode( color_texture_0,
blend_mode).needs_readable_framebuffer() => {} color_texture_1,
_ => { built_draw_path.blend_mode,
let batch = AlphaTileBatch { Some(built_draw_path.mask_0_fill_rule),
tiles: vec![], None);
color_texture_page: built_draw_path.color_texture_page,
blend_mode: built_draw_path.blend_mode, if let Some(mask_1_fill_rule) = built_draw_path.mask_1_fill_rule {
sampling_flags: built_draw_path.sampling_flags, self.add_alpha_tiles(&mut culled_tiles,
}; layer_z_buffer,
culled_tiles.display_list &built_draw_path.path.dual_mask_tiles,
.push(CulledDisplayItem::DrawAlphaTiles(batch)) 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. match built_draw_path.path.solid_tiles {
let culled_alpha_tiles = match *culled_tiles.display_list SolidTiles::Regular(ref tiles) => {
.last_mut() self.add_alpha_tiles(&mut culled_tiles,
.unwrap() { layer_z_buffer,
CulledDisplayItem::DrawAlphaTiles(AlphaTileBatch { tiles,
tiles: ref mut culled_alpha_tiles, current_depth,
.. color_texture_0,
}) => culled_alpha_tiles, color_texture_1,
_ => unreachable!(), built_draw_path.blend_mode,
}; None,
built_draw_path.mask_1_fill_rule);
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);
} }
SolidTiles::Occluders(_) => {}
} }
current_depth += 1; current_depth += 1;
@ -354,7 +375,7 @@ impl<'a> SceneBuilder<'a> {
let effective_view_box = self.scene.effective_view_box(self.built_options); 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_buffers = vec![ZBuffer::new(effective_view_box)];
let mut z_buffer_index_stack = vec![0]; let mut z_buffer_index_stack = vec![0];
let mut current_depth = 0; let mut current_depth = 1;
// Create Z-buffers. // Create Z-buffers.
for display_item in &self.scene.display_list { 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()]; let z_buffer = &mut z_buffers[*z_buffer_index_stack.last().unwrap()];
for (path_subindex, built_draw_path) in for (path_subindex, built_draw_path) in
built_draw_paths[start_index..end_index].iter().enumerate() { 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_index = (path_subindex + start_index) as u32;
let path = &self.scene.paths[path_index as usize]; let path = &self.scene.paths[path_index as usize];
let metadata = DepthMetadata { paint_id: path.paint() }; 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; current_depth += 1;
} }
} }
@ -390,27 +417,76 @@ impl<'a> SceneBuilder<'a> {
z_buffers z_buffers
} }
fn pack_tiles(&mut self, culled_tiles: CulledTiles) { fn add_alpha_tiles(&self,
if !culled_tiles.mask_winding_tiles.is_empty() { culled_tiles: &mut CulledTiles,
self.listener.send(RenderCommand::RenderMaskTiles { layer_z_buffer: &ZBuffer,
tiles: culled_tiles.mask_winding_tiles, alpha_tiles: &[Tile],
fill_rule: FillRule::Winding, current_depth: u32,
}); color_texture_0: Option<TileBatchTexture>,
} color_texture_1: Option<TileBatchTexture>,
if !culled_tiles.mask_evenodd_tiles.is_empty() { blend_mode: BlendMode,
self.listener.send(RenderCommand::RenderMaskTiles { mask_0_fill_rule: Option<FillRule>,
tiles: culled_tiles.mask_evenodd_tiles, mask_1_fill_rule: Option<FillRule>) {
fill_rule: FillRule::EvenOdd, 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 { for display_item in culled_tiles.display_list {
match display_item { match display_item {
CulledDisplayItem::DrawSolidTiles(batch) => { CulledDisplayItem::DrawTiles(batch) => {
self.listener.send(RenderCommand::DrawSolidTiles(batch)) self.listener.send(RenderCommand::DrawTiles(batch))
}
CulledDisplayItem::DrawAlphaTiles(batch) => {
self.listener.send(RenderCommand::DrawAlphaTiles(batch))
} }
CulledDisplayItem::PushRenderTarget(render_target_id) => { CulledDisplayItem::PushRenderTarget(render_target_id) => {
self.listener.send(RenderCommand::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, fn finish_building(&mut self,
paint_metadata: &[PaintMetadata], paint_metadata: &[PaintMetadata],
render_target_metadata: &[RenderTargetMetadata], render_target_metadata: &[RenderTargetMetadata],
built_clip_paths: Vec<BuiltPath>,
built_draw_paths: Vec<BuiltDrawPath>) { built_draw_paths: Vec<BuiltDrawPath>) {
self.listener.send(RenderCommand::FlushFills); self.listener.send(RenderCommand::FlushFills);
let culled_tiles = self.cull_tiles(paint_metadata, let culled_tiles = self.cull_tiles(paint_metadata,
render_target_metadata, render_target_metadata,
built_clip_paths,
built_draw_paths); built_draw_paths);
self.pack_tiles(culled_tiles); 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 { fn needs_readable_framebuffer(&self) -> bool {
let mut framebuffer_nesting = 0; let mut framebuffer_nesting = 0;
for display_item in &self.scene.display_list { for display_item in &self.scene.display_list {
@ -453,8 +522,7 @@ impl<'a> SceneBuilder<'a> {
} }
for path_index in start_index..end_index { for path_index in start_index..end_index {
let blend_mode = self.scene.paths[path_index as usize].blend_mode(); 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.needs_readable_framebuffer() {
if blend_mode_program.needs_readable_framebuffer() {
return true; 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 { 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 { BuiltPath {
mask_tiles: vec![], single_mask_tiles: vec![],
alpha_tiles: vec![], dual_mask_tiles: vec![],
solid_tiles: vec![], empty_tiles: vec![],
tiles: DenseTileMap::new(tiles::round_rect_out_to_tile_bounds(bounds)), 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, fill_rule,
} }
} }
} }
impl SolidTileInfo { impl Occluder {
#[inline] #[inline]
pub(crate) fn new(coords: Vector2I) -> SolidTileInfo { pub(crate) fn new(coords: Vector2I) -> Occluder {
SolidTileInfo { coords } Occluder { coords }
} }
} }
struct CulledTiles { struct CulledTiles {
mask_winding_tiles: Vec<MaskTile>,
mask_evenodd_tiles: Vec<MaskTile>,
display_list: Vec<CulledDisplayItem>, display_list: Vec<CulledDisplayItem>,
} }
enum CulledDisplayItem { enum CulledDisplayItem {
DrawSolidTiles(SolidTileBatch), DrawTiles(TileBatch),
DrawAlphaTiles(AlphaTileBatch),
PushRenderTarget(RenderTargetId), PushRenderTarget(RenderTargetId),
PopRenderTarget, PopRenderTarget,
} }
@ -506,8 +610,16 @@ pub struct TileStats {
// Utilities for built objects // Utilities for built objects
impl ObjectBuilder { impl ObjectBuilder {
pub(crate) fn new(bounds: RectF, fill_rule: FillRule) -> ObjectBuilder { pub(crate) fn new(path_bounds: RectF,
ObjectBuilder { built_path: BuiltPath::new(bounds, fill_rule), bounds, fills: vec![] } 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] #[inline]
@ -685,107 +797,81 @@ impl ObjectBuilder {
pub(crate) fn local_tile_index_to_coords(&self, tile_index: u32) -> Vector2I { pub(crate) fn local_tile_index_to_coords(&self, tile_index: u32) -> Vector2I {
self.built_path.tiles.index_to_coords(tile_index as usize) self.built_path.tiles.index_to_coords(tile_index as usize)
} }
}
pub(crate) fn push_mask_tile(mask_tiles: &mut Vec<MaskTile>, impl<'a> PackedTile<'a> {
fill_tile: &TileObjectPrimitive, pub(crate) fn add_to(&self,
mask_tile_index: u16, tiles: &mut Vec<Tile>,
object_index: u16) { draw_tiling_path_info: &DrawTilingPathInfo) {
mask_tiles.push(MaskTile { let fill_tile_index = self.draw_tile.alpha_tile_index as u16;
upper_left: MaskTileVertex::new(mask_tile_index, let fill_tile_backdrop = self.draw_tile.backdrop as i16;
fill_tile.alpha_tile_index as u16, let (clip_tile_index, clip_tile_backdrop) = match self.clip_tile {
Vector2I::default(), None => (0, 0),
object_index, Some(clip_tile) => (clip_tile.alpha_tile_index as u16, clip_tile.backdrop as i16),
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),
});
}
pub(crate) fn push_alpha_tile(alpha_tiles: &mut Vec<AlphaTile>, tiles.push(Tile {
mask_tile_index: u16, upper_left: TileVertex::new_alpha(self.tile_coords,
tile_coords: Vector2I, fill_tile_index,
object_index: u16, fill_tile_backdrop,
draw_tiling_path_info: &DrawTilingPathInfo) { clip_tile_index,
alpha_tiles.push(AlphaTile { clip_tile_backdrop,
upper_left: AlphaTileVertex::new(tile_coords, Vector2I::default(),
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,
draw_tiling_path_info), draw_tiling_path_info),
lower_left: AlphaTileVertex::new(tile_coords, upper_right: TileVertex::new_alpha(self.tile_coords,
mask_tile_index, fill_tile_index,
Vector2I::new(0, 1), fill_tile_backdrop,
object_index, clip_tile_index,
draw_tiling_path_info), clip_tile_backdrop,
lower_right: AlphaTileVertex::new(tile_coords, Vector2I::new(1, 0),
mask_tile_index, draw_tiling_path_info),
Vector2I::splat(1), lower_left: TileVertex::new_alpha(self.tile_coords,
object_index, fill_tile_index,
fill_tile_backdrop,
clip_tile_index,
clip_tile_backdrop,
Vector2I::new(0, 1),
draw_tiling_path_info), 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] #[inline]
fn new(mask_index: u16, fn new_alpha(tile_origin: Vector2I,
fill_index: u16, draw_tile_index: u16,
tile_offset: Vector2I, draw_tile_backdrop: i16,
object_index: u16, clip_tile_index: u16,
backdrop: i16) clip_tile_backdrop: i16,
-> MaskTileVertex { tile_offset: Vector2I,
let mask_uv = calculate_mask_uv(mask_index, tile_offset); draw_tiling_path_info: &DrawTilingPathInfo)
let fill_uv = calculate_mask_uv(fill_index, tile_offset); -> TileVertex {
MaskTileVertex { // TODO(pcwalton): Opacity.
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 {
let tile_position = tile_origin + tile_offset; let tile_position = tile_origin + tile_offset;
let color_uv = draw_tiling_path_info.paint_metadata.calculate_tex_coords(tile_position); let color_0_uv = draw_tiling_path_info.paint_metadata.calculate_tex_coords(tile_position);
let mask_uv = calculate_mask_uv(tile_index, tile_offset); let color_1_uv = calculate_opacity_uv(draw_tiling_path_info);
AlphaTileVertex { 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_x: tile_position.x() as i16,
tile_y: tile_position.y() as i16, tile_y: tile_position.y() as i16,
color_u: color_uv.x(), color_0_u: color_0_uv.x(),
color_v: color_uv.y(), color_0_v: color_0_uv.y(),
mask_u: mask_uv.x() as u16, color_1_u: color_1_uv.x(),
mask_v: mask_uv.y() as u16, color_1_v: color_1_uv.y(),
object_index, mask_0_u: mask_0_uv.x(),
opacity: draw_tiling_path_info.opacity, mask_0_v: mask_0_uv.y(),
pad: 0, 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_u = tile_index as i32 % MASK_TILES_ACROSS as i32;
let mask_v = 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 scale = Vector2F::new(1.0 / MASK_TILES_ACROSS as f32, 1.0 / MASK_TILES_DOWN as f32);
let mask_uv = Vector2I::new(mask_u, mask_v) + tile_offset; (Vector2I::new(mask_u, mask_v) + tile_offset).to_f32().scale_xy(scale)
mask_uv.to_f32().scale(mask_scale).to_i32()
} }
impl CulledTiles { fn calculate_opacity_uv(draw_tiling_path_info: &DrawTilingPathInfo) -> Vector2F {
fn push_mask_tiles(&mut self, built_path: &BuiltPath) { let DrawTilingPathInfo { opacity_tile_transform, opacity, .. } = *draw_tiling_path_info;
match built_path.fill_rule { let texel_coord = (Vector2I::new((opacity % 16) as i32, (opacity / 16) as i32).to_f32() +
FillRule::Winding => self.mask_winding_tiles.extend_from_slice(&built_path.mask_tiles), Vector2F::splat(0.5)).scale(1.0 / 16.0);
FillRule::EvenOdd => self.mask_evenodd_tiles.extend_from_slice(&built_path.mask_tiles), opacity_tile_transform * texel_coord
}
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -9,16 +9,13 @@
// except according to those terms. // except according to those terms.
use crate::gpu_data::FillBatchPrimitive; use crate::gpu_data::FillBatchPrimitive;
use pathfinder_content::fill::FillRule;
use pathfinder_gpu::{BufferData, BufferTarget, BufferUploadMode, Device, VertexAttrClass}; use pathfinder_gpu::{BufferData, BufferTarget, BufferUploadMode, Device, VertexAttrClass};
use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType};
use pathfinder_resources::ResourceLoader; use pathfinder_resources::ResourceLoader;
// TODO(pcwalton): Replace with `mem::size_of` calls? // TODO(pcwalton): Replace with `mem::size_of` calls?
const FILL_INSTANCE_SIZE: usize = 8; const FILL_INSTANCE_SIZE: usize = 8;
const SOLID_TILE_VERTEX_SIZE: usize = 12; const TILE_VERTEX_SIZE: usize = 40;
const ALPHA_TILE_VERTEX_SIZE: usize = 20;
const MASK_TILE_VERTEX_SIZE: usize = 12;
pub const MAX_FILLS_PER_BATCH: usize = 0x4000; pub const MAX_FILLS_PER_BATCH: usize = 0x4000;
@ -150,173 +147,93 @@ where
} }
} }
pub struct MaskTileVertexArray<D> where D: Device { pub struct TileVertexArray<D> where D: Device {
pub vertex_array: D::VertexArray, pub vertex_array: D::VertexArray,
pub vertex_buffer: D::Buffer,
} }
impl<D> MaskTileVertexArray<D> where D: Device { impl<D> TileVertexArray<D> where D: Device {
pub fn new(device: &D, pub fn new(device: &D,
mask_tile_program: &MaskTileProgram<D>, tile_program: &TileProgram<D>,
tile_vertex_buffer: &D::Buffer,
quads_vertex_indices_buffer: &D::Buffer) quads_vertex_indices_buffer: &D::Buffer)
-> MaskTileVertexArray<D> { -> TileVertexArray<D> {
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<D> where D: Device {
pub vertex_array: D::VertexArray,
}
impl<D> AlphaTileVertexArray<D> where D: Device {
pub fn new(
device: &D,
alpha_tile_program: &AlphaTileProgram<D>,
alpha_tile_vertex_buffer: &D::Buffer,
quads_vertex_indices_buffer: &D::Buffer,
) -> AlphaTileVertexArray<D> {
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let tile_position_attr = let tile_position_attr =
device.get_vertex_attr(&alpha_tile_program.program, "TilePosition").unwrap(); device.get_vertex_attr(&tile_program.program, "TilePosition").unwrap();
let color_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, let color_0_tex_coord_attr =
"ColorTexCoord").unwrap(); device.get_vertex_attr(&tile_program.program, "ColorTexCoord0").unwrap();
let mask_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, let color_1_tex_coord_attr =
"MaskTexCoord").unwrap(); device.get_vertex_attr(&tile_program.program, "ColorTexCoord1").unwrap();
let opacity_attr = device.get_vertex_attr(&alpha_tile_program.program, "Opacity").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 { device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor {
size: 2, size: 2,
class: VertexAttrClass::Int, class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16, attr_type: VertexAttrType::I16,
stride: ALPHA_TILE_VERTEX_SIZE, stride: 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<D>
where
D: Device,
{
pub vertex_array: D::VertexArray,
}
impl<D> SolidTileVertexArray<D>
where
D: Device,
{
pub fn new(
device: &D,
solid_tile_program: &SolidTileProgram<D>,
solid_tile_vertex_buffer: &D::Buffer,
quads_vertex_indices_buffer: &D::Buffer,
) -> SolidTileVertexArray<D> {
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,
offset: 0, offset: 0,
divisor: 0, divisor: 0,
buffer_index: 0, buffer_index: 0,
}); });
device.configure_vertex_attr(&vertex_array, device.configure_vertex_attr(&vertex_array,
&color_tex_coord_attr, &color_0_tex_coord_attr,
&VertexAttrDescriptor { &VertexAttrDescriptor {
size: 2, size: 2,
class: VertexAttrClass::Float, class: VertexAttrClass::Float,
attr_type: VertexAttrType::F32, attr_type: VertexAttrType::F32,
stride: SOLID_TILE_VERTEX_SIZE, stride: TILE_VERTEX_SIZE,
offset: 4, offset: 4,
divisor: 0, divisor: 0,
buffer_index: 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); device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index);
SolidTileVertexArray { vertex_array } TileVertexArray { vertex_array }
} }
} }
@ -341,7 +258,7 @@ impl<D> CopyTileVertexArray<D> where D: Device {
size: 2, size: 2,
class: VertexAttrClass::Int, class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16, attr_type: VertexAttrType::I16,
stride: ALPHA_TILE_VERTEX_SIZE, stride: TILE_VERTEX_SIZE,
offset: 0, offset: 0,
divisor: 0, divisor: 0,
buffer_index: 0, buffer_index: 0,
@ -393,90 +310,57 @@ where
} }
} }
pub struct MaskTileProgram<D> where D: Device { pub struct TileProgram<D> where D: Device {
pub program: D::Program,
pub fill_texture_uniform: D::Uniform,
}
impl<D> MaskTileProgram<D> where D: Device {
pub fn new(fill_rule: FillRule, device: &D, resources: &dyn ResourceLoader)
-> MaskTileProgram<D> {
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<D> where D: Device {
pub program: D::Program, pub program: D::Program,
pub transform_uniform: D::Uniform, pub transform_uniform: D::Uniform,
pub tile_size_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<D> SolidTileProgram<D> where D: Device { impl<D> TileProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader, program_name: &str) pub fn new(device: &D, resources: &dyn ResourceLoader) -> TileProgram<D> {
-> SolidTileProgram<D> { let program = device.create_program(resources, "tile");
let program = device.create_program_from_shader_names(resources,
program_name,
"tile_solid",
program_name);
let transform_uniform = device.get_uniform(&program, "Transform"); let transform_uniform = device.get_uniform(&program, "Transform");
let tile_size_uniform = device.get_uniform(&program, "TileSize"); let tile_size_uniform = device.get_uniform(&program, "TileSize");
let color_texture_uniform = device.get_uniform(&program, "ColorTexture"); let dest_texture_uniform = device.get_uniform(&program, "DestTexture");
SolidTileProgram { 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, program,
transform_uniform, transform_uniform,
tile_size_uniform, tile_size_uniform,
color_texture_uniform, dest_texture_uniform,
} color_texture_0_uniform,
} color_texture_1_uniform,
} mask_texture_0_uniform,
mask_texture_1_uniform,
pub struct AlphaTileProgram<D> where D: Device { gamma_lut_uniform,
pub program: D::Program, color_texture_0_size_uniform,
pub transform_uniform: D::Uniform, filter_params_0_uniform,
pub tile_size_uniform: D::Uniform, filter_params_1_uniform,
pub framebuffer_size_uniform: D::Uniform, filter_params_2_uniform,
pub stencil_texture_uniform: D::Uniform, dest_texture_size_uniform,
pub paint_texture_uniform: D::Uniform, ctrl_uniform,
}
impl<D> AlphaTileProgram<D> where D: Device {
#[inline]
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileProgram<D> {
AlphaTileProgram::from_fragment_shader_name(device, resources, "tile_alpha")
}
fn from_fragment_shader_name(device: &D,
resources: &dyn ResourceLoader,
fragment_shader_name: &str)
-> AlphaTileProgram<D> {
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,
} }
} }
} }
@ -506,126 +390,6 @@ impl<D> CopyTileProgram<D> where D: Device {
} }
} }
pub struct AlphaTileBlendModeProgram<D> where D: Device {
pub alpha_tile_program: AlphaTileProgram<D>,
pub dest_uniform: D::Uniform,
}
impl<D> AlphaTileBlendModeProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader, name: &str)
-> AlphaTileBlendModeProgram<D> {
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<D> where D: Device {
pub alpha_tile_blend_mode_program: AlphaTileBlendModeProgram<D>,
pub blend_hsl_uniform: D::Uniform,
}
impl<D> AlphaTileHSLProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileHSLProgram<D> {
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<D> where D: Device {
pub alpha_tile_blend_mode_program: AlphaTileBlendModeProgram<D>,
pub blend_mode_uniform: D::Uniform,
}
impl<D> AlphaTileOverlayProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileOverlayProgram<D> {
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<D> where D: Device {
pub alpha_tile_blend_mode_program: AlphaTileBlendModeProgram<D>,
pub burn_uniform: D::Uniform,
}
impl<D> AlphaTileDodgeBurnProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileDodgeBurnProgram<D> {
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<D> where D: Device {
pub solid_tile_program: SolidTileProgram<D>,
pub src_offset_scale_uniform: D::Uniform,
pub initial_gauss_coeff_uniform: D::Uniform,
pub support_uniform: D::Uniform,
}
impl<D> SolidTileBlurFilterProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> SolidTileBlurFilterProgram<D> {
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<D> where D: Device {
pub solid_tile_program: SolidTileProgram<D>,
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<D> SolidTileTextFilterProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> SolidTileTextFilterProgram<D> {
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<D> pub struct StencilProgram<D>
where where
D: Device, D: Device,

View File

@ -55,9 +55,6 @@ pub enum RenderCommand {
// Flushes the queue of fills. // Flushes the queue of fills.
FlushFills, FlushFills,
// Render fills to a set of mask tiles.
RenderMaskTiles { tiles: Vec<MaskTile>, fill_rule: FillRule },
// Pushes a render target onto the stack. Draw commands go to the render target on top of the // Pushes a render target onto the stack. Draw commands go to the render target on top of the
// stack. // stack.
PushRenderTarget(RenderTargetId), PushRenderTarget(RenderTargetId),
@ -65,11 +62,8 @@ pub enum RenderCommand {
// Pops a render target from the stack. // Pops a render target from the stack.
PopRenderTarget, PopRenderTarget,
// Draws a batch of alpha tiles to the render target on top of the stack. // Draws a batch of tiles to the render target on top of the stack.
DrawAlphaTiles(AlphaTileBatch), DrawTiles(TileBatch),
// Draws a batch of solid tiles to the render target on top of the stack.
DrawSolidTiles(SolidTileBatch),
// Presents a rendered frame. // Presents a rendered frame.
Finish { build_time: Duration }, Finish { build_time: Duration },
@ -90,19 +84,20 @@ pub struct TextureLocation {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct AlphaTileBatch { pub struct TileBatch {
pub tiles: Vec<AlphaTile>, pub tiles: Vec<Tile>,
pub color_texture_page: TexturePageId, pub color_texture_0: Option<TileBatchTexture>,
pub color_texture_1: Option<TileBatchTexture>,
pub mask_0_fill_rule: Option<FillRule>,
pub mask_1_fill_rule: Option<FillRule>,
pub blend_mode: BlendMode, pub blend_mode: BlendMode,
pub sampling_flags: TextureSamplingFlags, pub effects: Effects,
} }
#[derive(Clone, Debug)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct SolidTileBatch { pub struct TileBatchTexture {
pub tiles: Vec<SolidTile>, pub page: TexturePageId,
pub color_texture_page: TexturePageId,
pub sampling_flags: TextureSamplingFlags, pub sampling_flags: TextureSamplingFlags,
pub effects: Effects,
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -132,63 +127,28 @@ pub struct FillBatchPrimitive {
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
#[repr(C)] #[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_x: i16,
pub tile_y: i16, pub tile_y: i16,
pub color_u: f32, pub color_0_u: f32,
pub color_v: f32, pub color_0_v: f32,
} pub color_1_u: f32,
pub color_1_v: f32,
#[derive(Clone, Copy, Debug, Default)] pub mask_0_u: f32,
#[repr(C)] pub mask_0_v: f32,
pub struct MaskTile { pub mask_1_u: f32,
pub upper_left: MaskTileVertex, pub mask_1_v: f32,
pub upper_right: MaskTileVertex, pub mask_0_backdrop: i16,
pub lower_left: MaskTileVertex, pub mask_1_backdrop: i16,
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,
} }
impl Debug for RenderCommand { impl Debug for RenderCommand {
@ -199,34 +159,25 @@ impl Debug for RenderCommand {
write!(formatter, "AllocateTexturePages(x{})", pages.len()) write!(formatter, "AllocateTexturePages(x{})", pages.len())
} }
RenderCommand::UploadTexelData { ref texels, location } => { RenderCommand::UploadTexelData { ref texels, location } => {
write!(formatter, "UploadTexelData({:?}, {:?})", texels, location) write!(formatter, "UploadTexelData(x{:?}, {:?})", texels.len(), location)
} }
RenderCommand::DeclareRenderTarget { id, location } => { RenderCommand::DeclareRenderTarget { id, location } => {
write!(formatter, "DeclareRenderTarget({:?}, {:?})", id, location) write!(formatter, "DeclareRenderTarget({:?}, {:?})", id, location)
} }
RenderCommand::AddFills(ref fills) => write!(formatter, "AddFills(x{})", fills.len()), RenderCommand::AddFills(ref fills) => write!(formatter, "AddFills(x{})", fills.len()),
RenderCommand::FlushFills => write!(formatter, "FlushFills"), RenderCommand::FlushFills => write!(formatter, "FlushFills"),
RenderCommand::RenderMaskTiles { ref tiles, fill_rule } => {
write!(formatter, "RenderMaskTiles(x{}, {:?})", tiles.len(), fill_rule)
}
RenderCommand::PushRenderTarget(render_target_id) => { RenderCommand::PushRenderTarget(render_target_id) => {
write!(formatter, "PushRenderTarget({:?})", render_target_id) write!(formatter, "PushRenderTarget({:?})", render_target_id)
} }
RenderCommand::PopRenderTarget => write!(formatter, "PopRenderTarget"), RenderCommand::PopRenderTarget => write!(formatter, "PopRenderTarget"),
RenderCommand::DrawAlphaTiles(ref batch) => { RenderCommand::DrawTiles(ref batch) => {
write!(formatter, write!(formatter,
"DrawAlphaTiles(x{}, {:?}, {:?}, {:?})", "DrawTiles(x{}, C0 {:?}, C1 {:?}, M0 {:?}, {:?})",
batch.tiles.len(), batch.tiles.len(),
batch.color_texture_page, batch.color_texture_0,
batch.blend_mode, batch.color_texture_1,
batch.sampling_flags) batch.mask_0_fill_rule,
} batch.blend_mode)
RenderCommand::DrawSolidTiles(ref batch) => {
write!(formatter,
"DrawSolidTiles(x{}, {:?}, {:?})",
batch.tiles.len(),
batch.color_texture_page,
batch.sampling_flags)
} }
RenderCommand::Finish { .. } => write!(formatter, "Finish"), RenderCommand::Finish { .. } => write!(formatter, "Finish"),
} }

View File

@ -161,6 +161,10 @@ pub struct PaintInfo {
/// ///
/// The indices of this vector are render target IDs. /// The indices of this vector are render target IDs.
pub render_target_metadata: Vec<RenderTargetMetadata>, pub render_target_metadata: Vec<RenderTargetMetadata>,
/// The page containing the opacity tile.
pub opacity_tile_page: TexturePageId,
/// The transform for the opacity tile.
pub opacity_tile_transform: Transform2F,
} }
#[derive(Debug)] #[derive(Debug)]
@ -212,6 +216,7 @@ impl Palette {
} }
// Assign paint locations. // Assign paint locations.
let opacity_tile_builder = OpacityTileBuilder::new(&mut allocator);
let mut solid_color_tile_builder = SolidColorTileBuilder::new(); let mut solid_color_tile_builder = SolidColorTileBuilder::new();
let mut gradient_tile_builder = GradientTileBuilder::new(); let mut gradient_tile_builder = GradientTileBuilder::new();
for paint in &self.paints { for paint in &self.paints {
@ -344,6 +349,7 @@ impl Palette {
// Draw to texels. // Draw to texels.
// //
// TODO(pcwalton): Do more of this on GPU. // 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()) { for (paint, metadata) in self.paints.iter().zip(paint_metadata.iter()) {
let texture_page = metadata.location.page; let texture_page = metadata.location.page;
let texels = &mut page_texels[texture_page.0 as usize]; 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. // 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)) 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 // Solid color allocation
struct SolidColorTileBuilder(Option<SolidColorTileBuilderData>); struct SolidColorTileBuilder(Option<SolidColorTileBuilderData>);

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // 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::gpu_data::TileObjectPrimitive;
use crate::paint::PaintMetadata; use crate::paint::PaintMetadata;
use pathfinder_content::effects::BlendMode; use pathfinder_content::effects::BlendMode;
@ -18,6 +18,7 @@ use pathfinder_content::segment::Segment;
use pathfinder_content::sorted_vector::SortedVector; use pathfinder_content::sorted_vector::SortedVector;
use pathfinder_geometry::line_segment::LineSegment2F; use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_geometry::rect::{RectF, RectI}; use pathfinder_geometry::rect::{RectF, RectI};
use pathfinder_geometry::transform2d::Transform2F;
use pathfinder_geometry::vector::{Vector2F, Vector2I}; use pathfinder_geometry::vector::{Vector2F, Vector2I};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::mem; use std::mem;
@ -33,7 +34,6 @@ pub(crate) struct Tiler<'a> {
pub(crate) object_builder: ObjectBuilder, pub(crate) object_builder: ObjectBuilder,
outline: &'a Outline, outline: &'a Outline,
path_info: TilingPathInfo<'a>, path_info: TilingPathInfo<'a>,
object_index: u16,
point_queue: SortedVector<QueuedEndpoint>, point_queue: SortedVector<QueuedEndpoint>,
active_edges: SortedVector<ActiveEdge>, active_edges: SortedVector<ActiveEdge>,
@ -49,6 +49,7 @@ pub(crate) enum TilingPathInfo<'a> {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub(crate) struct DrawTilingPathInfo<'a> { pub(crate) struct DrawTilingPathInfo<'a> {
pub(crate) paint_metadata: &'a PaintMetadata, pub(crate) paint_metadata: &'a PaintMetadata,
pub(crate) opacity_tile_transform: Transform2F,
pub(crate) blend_mode: BlendMode, pub(crate) blend_mode: BlendMode,
pub(crate) opacity: u8, pub(crate) opacity: u8,
pub(crate) built_clip_path: Option<&'a BuiltPath>, pub(crate) built_clip_path: Option<&'a BuiltPath>,
@ -61,20 +62,18 @@ impl<'a> Tiler<'a> {
outline: &'a Outline, outline: &'a Outline,
fill_rule: FillRule, fill_rule: FillRule,
view_box: RectF, view_box: RectF,
object_index: u16,
path_info: TilingPathInfo<'a>, path_info: TilingPathInfo<'a>,
) -> Tiler<'a> { ) -> Tiler<'a> {
let bounds = outline let bounds = outline
.bounds() .bounds()
.intersection(view_box) .intersection(view_box)
.unwrap_or(RectF::default()); .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 { Tiler {
scene_builder, scene_builder,
object_builder, object_builder,
outline, outline,
object_index,
path_info, path_info,
point_queue: SortedVector::new(), point_queue: SortedVector::new(),
@ -124,107 +123,54 @@ impl<'a> Tiler<'a> {
} }
fn pack_and_cull(&mut self) { 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 { 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, 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 for (draw_tile_index, draw_tile) in self.object_builder
.built_path .built_path
.tiles .tiles
.data .data
.iter() .iter()
.enumerate() { .enumerate() {
let tile_coords = self.object_builder let packed_tile = PackedTile::new(draw_tile_index as u32,
.local_tile_index_to_coords(draw_tile_index as u32); draw_tile,
&draw_tiling_path_info,
&self.object_builder);
// Figure out what clip tile we need, if any. match packed_tile.tile_type {
let clip_tile = match draw_tiling_path_info.built_clip_path { TileType::Solid => {
None => None, match self.object_builder.built_path.solid_tiles {
Some(built_clip_path) => { SolidTiles::Occluders(ref mut occluders) => {
match built_clip_path.tiles.get(tile_coords) { occluders.push(Occluder::new(packed_tile.tile_coords));
None => {
// This tile is outside of the bounds of the clip path entirely. We can
// cull it.
continue;
} }
Some(clip_tile) if clip_tile.is_solid() => { SolidTiles::Regular(ref mut solid_tiles) => {
if clip_tile.backdrop != 0 { packed_tile.add_to(solid_tiles, &draw_tiling_path_info);
// 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;
}
} }
Some(clip_tile) => Some(clip_tile),
} }
} }
}; TileType::SingleMask => {
packed_tile.add_to(&mut self.object_builder.built_path.single_mask_tiles,
if clip_tile.is_none() && draw_tile.is_solid() { &draw_tiling_path_info);
// 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::DualMask => {
// Next, if this is a solid tile that completely occludes the background, record packed_tile.add_to(&mut self.object_builder.built_path.dual_mask_tiles,
// that fact and stop here. &draw_tiling_path_info);
if draw_tiling_path_info.paint_metadata.is_opaque && }
draw_tiling_path_info.blend_mode.occludes_backdrop() && TileType::Empty if blend_mode_is_destructive => {
draw_tiling_path_info.opacity == !0 { packed_tile.add_to(&mut self.object_builder.built_path.empty_tiles,
self.object_builder &draw_tiling_path_info);
.built_path }
.solid_tiles TileType::Empty => {
.push(SolidTileInfo::new(tile_coords)); // Just cull.
continue;
} }
} }
// 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) { 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_tile_x = self.object_builder.tile_rect().min_x();
let mut current_subtile_x = 0.0; 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 { pub fn round_rect_out_to_tile_bounds(rect: RectF) -> RectI {
rect.scale_xy(Vector2F::new( rect.scale_xy(Vector2F::new(
1.0 / TILE_WIDTH as f32, 1.0 / TILE_WIDTH as f32,

View File

@ -10,12 +10,12 @@
//! Software occlusion culling. //! Software occlusion culling.
use crate::builder::SolidTileInfo; use crate::builder::Occluder;
use crate::gpu_data::{SolidTile, SolidTileBatch, SolidTileVertex}; use crate::gpu_data::{Tile, TileBatch, TileBatchTexture, TileVertex};
use crate::paint::{PaintId, PaintMetadata}; use crate::paint::{PaintId, PaintMetadata};
use crate::tile_map::DenseTileMap; use crate::tile_map::DenseTileMap;
use crate::tiles; use crate::tiles;
use pathfinder_content::effects::{CompositeOp, Effects, Filter}; use pathfinder_content::effects::{BlendMode, Effects};
use pathfinder_geometry::rect::RectF; use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::vector::{Vector2F, Vector2I}; use pathfinder_geometry::vector::{Vector2F, Vector2I};
use vec_map::VecMap; use vec_map::VecMap;
@ -26,7 +26,7 @@ pub(crate) struct ZBuffer {
} }
pub(crate) struct SolidTiles { pub(crate) struct SolidTiles {
pub(crate) batches: Vec<SolidTileBatch>, pub(crate) batches: Vec<TileBatch>,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -48,7 +48,7 @@ impl ZBuffer {
} }
pub(crate) fn update(&mut self, pub(crate) fn update(&mut self,
solid_tiles: &[SolidTileInfo], solid_tiles: &[Occluder],
depth: u32, depth: u32,
metadata: DepthMetadata) { metadata: DepthMetadata) {
self.depth_metadata.insert(depth as usize, metadata); self.depth_metadata.insert(depth as usize, metadata);
@ -77,76 +77,92 @@ impl ZBuffer {
// Create a batch if necessary. // Create a batch if necessary.
match solid_tiles.batches.last() { match solid_tiles.batches.last() {
Some(ref batch) if batch.color_texture_page == paint_metadata.location.page && Some(TileBatch {
batch.sampling_flags == paint_metadata.sampling_flags => {} color_texture_0: Some(TileBatchTexture { page, sampling_flags }),
..
}) if *page == paint_metadata.location.page &&
*sampling_flags == paint_metadata.sampling_flags => {}
_ => { _ => {
// Batch break. // Batch break.
// //
// TODO(pcwalton): We could be more aggressive with batching here, since we // TODO(pcwalton): We could be more aggressive with batching here, since we
// know there are no overlaps. // know there are no overlaps.
solid_tiles.batches.push(SolidTileBatch { solid_tiles.batches.push(TileBatch {
color_texture_page: paint_metadata.location.page, color_texture_0: Some(TileBatchTexture {
sampling_flags: paint_metadata.sampling_flags, page: paint_metadata.location.page,
sampling_flags: paint_metadata.sampling_flags,
}),
color_texture_1: None,
tiles: vec![], 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(); 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 solid_tiles
} }
} }
impl SolidTile { impl Tile {
pub(crate) fn from_paint_metadata(tile_position: Vector2I, paint_metadata: &PaintMetadata) pub(crate) fn new_solid_with_paint_metadata(tile_position: Vector2I,
-> SolidTile { paint_metadata: &PaintMetadata)
SolidTile { -> Tile {
upper_left: SolidTileVertex::from_paint_metadata(tile_position, paint_metadata), Tile {
upper_right: SolidTileVertex::from_paint_metadata(tile_position + Vector2I::new(1, 0), upper_left: TileVertex::new_solid_from_paint_metadata(tile_position, paint_metadata),
paint_metadata), upper_right: TileVertex::new_solid_from_paint_metadata(tile_position +
lower_left: SolidTileVertex::from_paint_metadata(tile_position + Vector2I::new(0, 1), Vector2I::new(1, 0),
paint_metadata), paint_metadata),
lower_right: SolidTileVertex::from_paint_metadata(tile_position + Vector2I::new(1, 1), lower_left: TileVertex::new_solid_from_paint_metadata(tile_position +
paint_metadata), 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 new_solid_from_texture_rect(tile_position: Vector2I, texture_rect: RectF)
pub(crate) fn from_texture_rect(tile_position: Vector2I, texture_rect: RectF) -> SolidTile { -> Tile {
SolidTile { Tile {
upper_left: SolidTileVertex::new(tile_position, texture_rect.origin()), upper_left: TileVertex::new_solid_from_uv(tile_position, texture_rect.origin()),
upper_right: SolidTileVertex::new(tile_position + Vector2I::new(1, 0), upper_right: TileVertex::new_solid_from_uv(tile_position + Vector2I::new(1, 0),
texture_rect.upper_right()), texture_rect.upper_right()),
lower_left: SolidTileVertex::new(tile_position + Vector2I::new(0, 1), lower_left: TileVertex::new_solid_from_uv(tile_position + Vector2I::new(0, 1),
texture_rect.lower_left()), texture_rect.lower_left()),
lower_right: SolidTileVertex::new(tile_position + Vector2I::new(1, 1), lower_right: TileVertex::new_solid_from_uv(tile_position + Vector2I::new(1, 1),
texture_rect.lower_right()), texture_rect.lower_right()),
} }
} }
} }
impl SolidTileVertex { impl TileVertex {
fn new(tile_position: Vector2I, color_tex_coords: Vector2F) -> SolidTileVertex { fn new_solid_from_uv(tile_position: Vector2I, color_0_uv: Vector2F) -> TileVertex {
SolidTileVertex { TileVertex {
tile_x: tile_position.x() as i16, tile_x: tile_position.x() as i16,
tile_y: tile_position.y() as i16, tile_y: tile_position.y() as i16,
color_u: color_tex_coords.x(), color_0_u: color_0_uv.x(),
color_v: color_tex_coords.y(), 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) fn new_solid_from_paint_metadata(tile_position: Vector2I, paint_metadata: &PaintMetadata)
-> SolidTileVertex { -> TileVertex {
let color_uv = paint_metadata.calculate_tex_coords(tile_position); let color_uv = paint_metadata.calculate_tex_coords(tile_position);
SolidTileVertex { TileVertex::new_solid_from_uv(tile_position, color_uv)
tile_x: tile_position.x() as i16,
tile_y: tile_position.y() as i16,
color_u: color_uv.x(),
color_v: color_uv.y(),
}
} }
} }

View File

@ -13,27 +13,14 @@ shaders/gl3/demo_ground.fs.glsl
shaders/gl3/demo_ground.vs.glsl shaders/gl3/demo_ground.vs.glsl
shaders/gl3/fill.fs.glsl shaders/gl3/fill.fs.glsl
shaders/gl3/fill.vs.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.fs.glsl
shaders/gl3/reproject.vs.glsl shaders/gl3/reproject.vs.glsl
shaders/gl3/stencil.fs.glsl shaders/gl3/stencil.fs.glsl
shaders/gl3/stencil.vs.glsl shaders/gl3/stencil.vs.glsl
shaders/gl3/tile_alpha.fs.glsl shaders/gl3/tile.fs.glsl
shaders/gl3/tile_alpha.vs.glsl shaders/gl3/tile.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_copy.fs.glsl shaders/gl3/tile_copy.fs.glsl
shaders/gl3/tile_copy.vs.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.fs.metal
shaders/metal/blit.vs.metal shaders/metal/blit.vs.metal
shaders/metal/debug_solid.fs.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/demo_ground.vs.metal
shaders/metal/fill.fs.metal shaders/metal/fill.fs.metal
shaders/metal/fill.vs.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.fs.metal
shaders/metal/reproject.vs.metal shaders/metal/reproject.vs.metal
shaders/metal/stencil.fs.metal shaders/metal/stencil.fs.metal
shaders/metal/stencil.vs.metal shaders/metal/stencil.vs.metal
shaders/metal/tile_alpha.fs.metal shaders/metal/tile.fs.metal
shaders/metal/tile_alpha.vs.metal shaders/metal/tile.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_copy.fs.metal shaders/metal/tile_copy.fs.metal
shaders/metal/tile_copy.vs.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/area-lut.png
textures/debug-corner-fill.png textures/debug-corner-fill.png
textures/debug-corner-outline.png textures/debug-corner-outline.png

View File

@ -14,12 +14,16 @@
precision highp float; precision highp float;
in vec2 aPosition; in ivec2 aPosition;
out vec2 vTexCoord; out vec2 vTexCoord;
void main(){ void main(){
vTexCoord = aPosition; vec2 texCoord = vec2(aPosition);
gl_Position = vec4(mix(aPosition, vec2(- 1.0), vec2(1.0)), 0.0, 1.0);
vTexCoord = texCoord;
gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), vec2(aPosition)), 0.0, 1.0);
} }

View File

@ -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);
}

View File

@ -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)));
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -12,14 +12,16 @@ struct main0_out
struct main0_in struct main0_in
{ {
float2 aPosition [[attribute(0)]]; int2 aPosition [[attribute(0)]];
}; };
vertex main0_out main0(main0_in in [[stage_in]]) vertex main0_out main0(main0_in in [[stage_in]])
{ {
main0_out out = {}; main0_out out = {};
out.vTexCoord = in.aPosition; float2 texCoord = float2(in.aPosition);
out.gl_Position = float4(mix(in.aPosition, float2(-1.0), float2(1.0)), 0.0, 1.0); 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; return out;
} }

View File

@ -1,31 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
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;
}

View File

@ -1,40 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> 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<typename Tx, typename Ty>
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;
}

View File

@ -1,30 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> 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;
}

View File

@ -0,0 +1,540 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uMaskTexture0 [[id(0)]];
sampler uMaskTexture0Smplr [[id(1)]];
texture2d<float> uMaskTexture1 [[id(2)]];
sampler uMaskTexture1Smplr [[id(3)]];
texture2d<float> uColorTexture0 [[id(4)]];
sampler uColorTexture0Smplr [[id(5)]];
texture2d<float> 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<float> uColorTexture1 [[id(12)]];
sampler uColorTexture1Smplr [[id(13)]];
texture2d<float> 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<typename Tx, typename Ty>
Tx mod(Tx x, Ty y)
{
return x - y * floor(x / y);
}
float sampleMask(thread const float& maskAlpha, thread const texture2d<float> 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<float> 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<float> 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<float> 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<float> 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<float> 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<float> colorTexture, thread const sampler colorTextureSmplr, thread const texture2d<float> 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<float> colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTexCoord)
{
return colorTexture.sample(colorTextureSmplr, colorTexCoord);
}
float4 filterNone(thread const float2& colorTexCoord, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr)
{
float2 param = colorTexCoord;
return sampleColor(colorTexture, colorTextureSmplr, param);
}
float4 filterColor(thread const float2& colorTexCoord, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const texture2d<float> 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<float> 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<float> uMaskTexture0, thread const sampler uMaskTexture0Smplr, thread float3& vMaskTexCoord0, thread texture2d<float> uMaskTexture1, thread const sampler uMaskTexture1Smplr, thread float3& vMaskTexCoord1, thread float2& vColorTexCoord0, thread texture2d<float> uColorTexture0, thread const sampler uColorTexture0Smplr, thread texture2d<float> uGammaLUT, thread const sampler uGammaLUTSmplr, thread float2 uColorTexture0Size, thread float4 uFilterParams0, thread float4 uFilterParams1, thread float4 uFilterParams2, thread texture2d<float> uColorTexture1, thread const sampler uColorTexture1Smplr, thread float2& vColorTexCoord1, thread texture2d<float> 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;
}

View File

@ -12,21 +12,31 @@ struct spvDescriptorSetBuffer0
struct main0_out 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]]; float4 gl_Position [[position]];
}; };
struct main0_in struct main0_in
{ {
int2 aTilePosition [[attribute(0)]]; 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)]]) vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{ {
main0_out out = {}; main0_out out = {};
float2 position = float2(in.aTilePosition) * (*spvDescriptorSet0.uTileSize); 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); out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0);
return out; return out;
} }

View File

@ -1,43 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uStencilTexture [[id(0)]];
sampler uStencilTextureSmplr [[id(1)]];
texture2d<float> 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<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> 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;
}

View File

@ -1,39 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
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;
}

View File

@ -1,62 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uStencilTexture [[id(0)]];
sampler uStencilTextureSmplr [[id(1)]];
texture2d<float> uPaintTexture [[id(2)]];
sampler uPaintTextureSmplr [[id(3)]];
constant float2* uFramebufferSize [[id(4)]];
texture2d<float> 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<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> 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<float> 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;
}

View File

@ -1,115 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uStencilTexture [[id(0)]];
sampler uStencilTextureSmplr [[id(1)]];
texture2d<float> uPaintTexture [[id(2)]];
sampler uPaintTextureSmplr [[id(3)]];
constant float2* uFramebufferSize [[id(4)]];
texture2d<float> 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<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> 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<float> 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;
}

View File

@ -1,64 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uStencilTexture [[id(0)]];
sampler uStencilTextureSmplr [[id(1)]];
texture2d<float> uPaintTexture [[id(2)]];
sampler uPaintTextureSmplr [[id(3)]];
constant float2* uFramebufferSize [[id(4)]];
texture2d<float> 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<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> 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<float> 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;
}

View File

@ -1,152 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uStencilTexture [[id(0)]];
sampler uStencilTextureSmplr [[id(1)]];
texture2d<float> uPaintTexture [[id(2)]];
sampler uPaintTextureSmplr [[id(3)]];
constant float2* uFramebufferSize [[id(4)]];
texture2d<float> 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<typename Tx, typename Ty>
Tx mod(Tx x, Ty y)
{
return x - y * floor(x / y);
}
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> 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<float> 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;
}

View File

@ -1,136 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uStencilTexture [[id(0)]];
sampler uStencilTextureSmplr [[id(1)]];
texture2d<float> uPaintTexture [[id(2)]];
sampler uPaintTextureSmplr [[id(3)]];
constant float2* uFramebufferSize [[id(4)]];
texture2d<float> 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<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> 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<float> 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;
}

View File

@ -1,106 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uStencilTexture [[id(0)]];
sampler uStencilTextureSmplr [[id(1)]];
texture2d<float> uPaintTexture [[id(2)]];
sampler uPaintTextureSmplr [[id(3)]];
constant float2* uFramebufferSize [[id(4)]];
texture2d<float> 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<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> 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<float> 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;
}

View File

@ -1,30 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> 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;
}

View File

@ -1,52 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float3* uInitialGaussCoeff [[id(0)]];
texture2d<float> 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;
}

View File

@ -1,130 +0,0 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uGammaLUT [[id(0)]];
sampler uGammaLUTSmplr [[id(1)]];
constant float4* uKernel [[id(2)]];
texture2d<float> 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<float> 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<float> 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<float> 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<float> 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;
}

View File

@ -13,33 +13,17 @@ SHADERS=\
demo_ground.vs.glsl \ demo_ground.vs.glsl \
fill.fs.glsl \ fill.fs.glsl \
fill.vs.glsl \ fill.vs.glsl \
mask.vs.glsl \
mask_evenodd.fs.glsl \
mask_winding.fs.glsl \
reproject.fs.glsl \ reproject.fs.glsl \
reproject.vs.glsl \ reproject.vs.glsl \
stencil.fs.glsl \ stencil.fs.glsl \
stencil.vs.glsl \ stencil.vs.glsl \
tile_alpha.fs.glsl \ tile.fs.glsl \
tile_alpha.vs.glsl \ tile.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_copy.fs.glsl \ tile_copy.fs.glsl \
tile_copy.vs.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) $(EMPTY)
INCLUDES=\ INCLUDES=\
tile_alpha_sample.inc.glsl \
tile_solid_filter_text_convolve.inc.glsl \
tile_solid_filter_text_gamma_correct.inc.glsl \
$(EMPTY) $(EMPTY)
OUT=\ OUT=\

View File

@ -12,11 +12,15 @@
precision highp float; precision highp float;
in vec2 aPosition; in ivec2 aPosition;
out vec2 vTexCoord; out vec2 vTexCoord;
void main() { void main() {
vTexCoord = aPosition; vec2 texCoord = vec2(aPosition);
gl_Position = vec4(mix(aPosition, vec2(-1.0), vec2(1.0)), 0.0, 1.0); #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);
} }

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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)));
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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));
}

460
shaders/tile.fs.glsl Normal file
View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -1,6 +1,6 @@
#version 330 #version 330
// pathfinder/shaders/tile_alpha.vs.glsl // pathfinder/shaders/tile.vs.glsl
// //
// Copyright © 2020 The Pathfinder Project Developers. // Copyright © 2020 The Pathfinder Project Developers.
// //
@ -16,19 +16,22 @@ uniform mat4 uTransform;
uniform vec2 uTileSize; uniform vec2 uTileSize;
in ivec2 aTilePosition; in ivec2 aTilePosition;
in vec2 aColorTexCoord; in vec2 aColorTexCoord0;
in vec2 aMaskTexCoord; in vec2 aColorTexCoord1;
in float aOpacity; in vec2 aMaskTexCoord0;
in vec2 aMaskTexCoord1;
in ivec2 aMaskBackdrop;
out vec2 vColorTexCoord; out vec3 vMaskTexCoord0;
out vec2 vMaskTexCoord; out vec3 vMaskTexCoord1;
out float vOpacity; out vec2 vColorTexCoord0;
out vec2 vColorTexCoord1;
void main() { void main() {
vec2 position = vec2(aTilePosition) * uTileSize; vec2 position = vec2(aTilePosition) * uTileSize;
vColorTexCoord0 = aColorTexCoord0;
vMaskTexCoord = aMaskTexCoord; vColorTexCoord1 = aColorTexCoord1;
vColorTexCoord = aColorTexCoord; vMaskTexCoord0 = vec3(aMaskTexCoord0, float(aMaskBackdrop.x));
vOpacity = aOpacity; vMaskTexCoord1 = vec3(aMaskTexCoord1, float(aMaskBackdrop.y));
gl_Position = uTransform * vec4(position, 0.0, 1.0); gl_Position = uTransform * vec4(position, 0.0, 1.0);
} }

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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));
}