Rename "postprocessing" to "effects" and start initial work on composite ops

This commit is contained in:
Patrick Walton 2020-02-20 14:22:07 -08:00
parent d9e994e46d
commit 16a2de88df
26 changed files with 723 additions and 167 deletions

1
Cargo.lock generated
View File

@ -1658,6 +1658,7 @@ dependencies = [
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"metal 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_color 0.1.0",
"pathfinder_content 0.1.0",
"pathfinder_export 0.1.0",
"pathfinder_geometry 0.4.0",
"pathfinder_gl 0.1.0",

72
content/src/effects.rs Normal file
View File

@ -0,0 +1,72 @@
// pathfinder/content/src/effects.rs
//
// 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.
//! Special effects that can be applied to layers.
use pathfinder_color::ColorF;
/// This intentionally does not precisely match what Core Graphics does (a
/// Lanczos function), because we don't want any ringing artefacts.
pub static DEFRINGING_KERNEL_CORE_GRAPHICS: DefringingKernel =
DefringingKernel([0.033165660, 0.102074051, 0.221434336, 0.286651906]);
pub static DEFRINGING_KERNEL_FREETYPE: DefringingKernel =
DefringingKernel([0.0, 0.031372549, 0.301960784, 0.337254902]);
/// Should match macOS 10.13 High Sierra.
pub static STEM_DARKENING_FACTORS: [f32; 2] = [0.0121, 0.0121 * 1.25];
/// Should match macOS 10.13 High Sierra.
pub const MAX_STEM_DARKENING_AMOUNT: [f32; 2] = [0.3, 0.3];
/// This value is a subjective cutoff. Above this ppem value, no stem darkening is performed.
pub const MAX_STEM_DARKENING_PIXELS_PER_EM: f32 = 72.0;
/// Effects that can be applied to a layer.
#[derive(Clone, Copy, Debug)]
pub struct Effects {
/// The shader that should be used when compositing this layer onto its destination.
pub filter: Filter,
}
/// The shader that should be used when compositing this layer onto its destination.
#[derive(Clone, Copy, Debug)]
pub enum Filter {
/// A compositing operation.
Composite(CompositeOp),
/// Performs postprocessing operations useful for monochrome text.
Text {
/// The foreground color of the text.
fg_color: ColorF,
/// The background color of the text.
bg_color: ColorF,
/// The kernel used for defringing, if subpixel AA is enabled.
defringing_kernel: Option<DefringingKernel>,
/// Whether gamma correction is used when compositing.
///
/// If this is enabled, stem darkening is advised.
gamma_correction: bool,
},
}
#[derive(Clone, Copy, Debug)]
pub enum CompositeOp {
/// The default.
SourceOver,
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct DefringingKernel(pub [f32; 4]);
impl Default for CompositeOp {
#[inline]
fn default() -> CompositeOp {
CompositeOp::SourceOver
}
}

View File

@ -19,6 +19,7 @@ extern crate log;
pub mod clip;
pub mod dash;
pub mod effects;
pub mod fill;
pub mod gradient;
pub mod orientation;

View File

@ -24,6 +24,9 @@ version = "0.4"
[dependencies.pathfinder_color]
path = "../../color"
[dependencies.pathfinder_content]
path = "../../content"
[dependencies.pathfinder_export]
path = "../../export"

View File

@ -22,6 +22,8 @@ use crate::device::{GroundProgram, GroundVertexArray};
use crate::ui::{DemoUIModel, DemoUIPresenter, ScreenshotInfo, ScreenshotType, UIAction};
use crate::window::{Event, Keycode, SVGPath, Window, WindowSize};
use clap::{App, Arg};
use pathfinder_content::effects::{DEFRINGING_KERNEL_CORE_GRAPHICS, Effects};
use pathfinder_content::effects::{Filter, STEM_DARKENING_FACTORS};
use pathfinder_export::{Export, FileFormat};
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::transform2d::Transform2F;
@ -31,9 +33,8 @@ use pathfinder_gpu::resources::ResourceLoader;
use pathfinder_gpu::Device;
use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy};
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::{PostprocessOptions, RenderStats, RenderTime, Renderer};
use pathfinder_renderer::gpu::renderer::{RenderStats, RenderTime, Renderer};
use pathfinder_renderer::options::{BuildOptions, RenderTransform};
use pathfinder_renderer::post::{DEFRINGING_KERNEL_CORE_GRAPHICS, STEM_DARKENING_FACTORS};
use pathfinder_renderer::scene::Scene;
use pathfinder_svg::BuiltSVG;
use pathfinder_ui::{MousePosition, UIEvent};
@ -742,9 +743,7 @@ pub enum UIVisibility {
All,
}
fn load_scene(resource_loader: &dyn ResourceLoader,
input_path: &SVGPath,
effects: Option<PostprocessOptions>)
fn load_scene(resource_loader: &dyn ResourceLoader, input_path: &SVGPath, effects: Option<Effects>)
-> (BuiltSVG, Tree) {
let mut data;
match *input_path {
@ -761,7 +760,7 @@ fn load_scene(resource_loader: &dyn ResourceLoader,
(built_svg, tree)
}
fn build_svg_tree(tree: &Tree, effects: Option<PostprocessOptions>) -> BuiltSVG {
fn build_svg_tree(tree: &Tree, effects: Option<Effects>) -> BuiltSVG {
let mut scene = Scene::new();
if let Some(effects) = effects {
scene.push_layer(effects);
@ -860,20 +859,22 @@ impl SceneMetadata {
}
}
fn build_effects(ui_model: &DemoUIModel) -> Option<PostprocessOptions> {
fn build_effects(ui_model: &DemoUIModel) -> Option<Effects> {
if !ui_model.gamma_correction_effect_enabled && !ui_model.subpixel_aa_effect_enabled {
return None;
}
Some(PostprocessOptions {
fg_color: ui_model.foreground_color().to_f32(),
bg_color: ui_model.background_color().to_f32(),
gamma_correction: ui_model.gamma_correction_effect_enabled,
defringing_kernel: if ui_model.subpixel_aa_effect_enabled {
// TODO(pcwalton): Select FreeType defringing kernel as necessary.
Some(DEFRINGING_KERNEL_CORE_GRAPHICS)
} else {
None
Some(Effects {
filter: Filter::Text {
fg_color: ui_model.foreground_color().to_f32(),
bg_color: ui_model.background_color().to_f32(),
gamma_correction: ui_model.gamma_correction_effect_enabled,
defringing_kernel: if ui_model.subpixel_aa_effect_enabled {
// TODO(pcwalton): Select FreeType defringing kernel as necessary.
Some(DEFRINGING_KERNEL_CORE_GRAPHICS)
} else {
None
}
},
})
}

View File

@ -11,7 +11,7 @@
//! Packs data onto the GPU.
use crate::concurrent::executor::Executor;
use crate::gpu::renderer::{MASK_TILES_ACROSS, PostprocessOptions};
use crate::gpu::renderer::MASK_TILES_ACROSS;
use crate::gpu_data::{AlphaTile, AlphaTileVertex, FillBatchPrimitive, MaskTile, MaskTileVertex};
use crate::gpu_data::{RenderCommand, SolidTileVertex, TileObjectPrimitive};
use crate::options::{PreparedBuildOptions, RenderCommandListener};
@ -20,6 +20,7 @@ use crate::scene::{DisplayItem, Scene};
use crate::tile_map::DenseTileMap;
use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH, Tiler, TilingPathInfo};
use crate::z_buffer::ZBuffer;
use pathfinder_content::effects::Effects;
use pathfinder_content::fill::FillRule;
use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8};
use pathfinder_geometry::vector::{Vector2F, Vector2I};
@ -358,7 +359,7 @@ struct CulledTiles {
enum CulledDisplayItem {
DrawSolidTiles(Vec<SolidTileVertex>),
DrawAlphaTiles(Vec<AlphaTile>),
PushLayer { effects: PostprocessOptions },
PushLayer { effects: Effects },
PopLayer,
}

View File

@ -10,16 +10,17 @@
use crate::gpu::debug::DebugUIPresenter;
use crate::gpu::options::{DestFramebuffer, RendererOptions};
use crate::gpu::shaders::{FillProgram, AlphaTileProgram, AlphaTileVertexArray, FillVertexArray};
use crate::gpu::shaders::{MAX_FILLS_PER_BATCH, MaskTileProgram, MaskTileVertexArray};
use crate::gpu::shaders::{PostprocessProgram, PostprocessVertexArray, ReprojectionProgram};
use crate::gpu::shaders::{ReprojectionVertexArray, SolidTileProgram, SolidTileVertexArray};
use crate::gpu::shaders::{AlphaTileProgram, AlphaTileVertexArray, FillProgram, FillVertexArray};
use crate::gpu::shaders::{FilterBasicProgram, FilterBasicVertexArray, FilterTextProgram};
use crate::gpu::shaders::{FilterTextVertexArray, MAX_FILLS_PER_BATCH, MaskTileProgram};
use crate::gpu::shaders::{MaskTileVertexArray, ReprojectionProgram, ReprojectionVertexArray};
use crate::gpu::shaders::{SolidTileProgram, SolidTileVertexArray};
use crate::gpu::shaders::{StencilProgram, StencilVertexArray};
use crate::gpu_data::{AlphaTile, FillBatchPrimitive, MaskTile, PaintData};
use crate::gpu_data::{RenderCommand, SolidTileVertex};
use crate::post::DefringingKernel;
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
use pathfinder_color::{self as color, ColorF};
use pathfinder_content::effects::{CompositeOp, DefringingKernel, Effects, Filter};
use pathfinder_content::fill::FillRule;
use pathfinder_geometry::vector::{Vector2I, Vector4F};
use pathfinder_geometry::rect::RectI;
@ -79,9 +80,11 @@ where
paint_texture: Option<D::Texture>,
layer_framebuffer_stack: Vec<LayerFramebufferInfo<D>>,
// Postprocessing shader
postprocess_program: PostprocessProgram<D>,
postprocess_vertex_array: PostprocessVertexArray<D>,
// Filter shaders
filter_basic_program: FilterBasicProgram<D>,
filter_basic_vertex_array: FilterBasicVertexArray<D>,
filter_text_program: FilterTextProgram<D>,
filter_text_vertex_array: FilterTextVertexArray<D>,
gamma_lut_texture: D::Texture,
// Stencil shader
@ -126,7 +129,8 @@ where
resources);
let solid_tile_program = SolidTileProgram::new(&device, resources);
let alpha_tile_program = AlphaTileProgram::new(&device, resources);
let postprocess_program = PostprocessProgram::new(&device, resources);
let filter_basic_program = FilterBasicProgram::new(&device, resources);
let filter_text_program = FilterTextProgram::new(&device, resources);
let stencil_program = StencilProgram::new(&device, resources);
let reprojection_program = ReprojectionProgram::new(&device, resources);
@ -175,9 +179,15 @@ where
&solid_tile_program,
&quads_vertex_indices_buffer,
);
let postprocess_vertex_array = PostprocessVertexArray::new(
let filter_basic_vertex_array = FilterBasicVertexArray::new(
&device,
&postprocess_program,
&filter_basic_program,
&quad_vertex_positions_buffer,
&quad_vertex_indices_buffer,
);
let filter_text_vertex_array = FilterTextVertexArray::new(
&device,
&filter_text_program,
&quad_vertex_positions_buffer,
&quad_vertex_indices_buffer,
);
@ -229,8 +239,10 @@ where
paint_texture: None,
layer_framebuffer_stack: vec![],
postprocess_program,
postprocess_vertex_array,
filter_basic_program,
filter_basic_vertex_array,
filter_text_program,
filter_text_vertex_array,
gamma_lut_texture,
stencil_program,
@ -757,12 +769,13 @@ where
}
}
fn push_layer(&mut self, effects: PostprocessOptions) {
fn push_layer(&mut self, effects: Effects) {
let main_framebuffer_size = self.main_viewport().size();
let framebuffer_size = if effects.defringing_kernel.is_some() {
main_framebuffer_size.scale_xy(Vector2I::new(3, 1))
} else {
main_framebuffer_size
let framebuffer_size = match effects.filter {
Filter::Text { defringing_kernel: Some(_), .. } => {
main_framebuffer_size.scale_xy(Vector2I::new(3, 1))
}
_ => main_framebuffer_size,
};
let framebuffer = self.framebuffer_cache.create_framebuffer(&mut self.device,
@ -780,45 +793,106 @@ where
.pop()
.expect("Where's the layer?");
let clear_color = self.clear_color_for_draw_operation();
match layer_framebuffer_info.effects.filter {
Filter::Composite(composite_op) => {
self.composite_layer(&layer_framebuffer_info, composite_op)
}
Filter::Text { fg_color, bg_color, defringing_kernel, gamma_correction } => {
self.draw_text_layer(&layer_framebuffer_info,
fg_color,
bg_color,
defringing_kernel,
gamma_correction)
}
}
let postprocess_source_framebuffer = &layer_framebuffer_info.framebuffer;
let source_texture = self
.device
.framebuffer_texture(postprocess_source_framebuffer);
self.preserve_draw_framebuffer();
self.framebuffer_cache.release_framebuffer(layer_framebuffer_info.framebuffer);
}
fn composite_layer(&self,
layer_framebuffer_info: &LayerFramebufferInfo<D>,
composite_op: CompositeOp) {
let clear_color = self.clear_color_for_draw_operation();
let source_framebuffer = &layer_framebuffer_info.framebuffer;
let source_texture = self.device.framebuffer_texture(source_framebuffer);
let source_texture_size = self.device.texture_size(source_texture);
let main_viewport = self.main_viewport();
let uniforms = vec![
(&self.filter_basic_program.framebuffer_size_uniform,
UniformData::Vec2(main_viewport.size().to_f32().0)),
(&self.filter_basic_program.source_uniform, UniformData::TextureUnit(0)),
(&self.filter_basic_program.source_size_uniform,
UniformData::Vec2(source_texture_size.0.to_f32x2())),
];
let blend_state = match composite_op {
CompositeOp::SourceOver => {
BlendState {
func: BlendFunc::RGBSrcAlphaAlphaOneMinusSrcAlpha,
..BlendState::default()
}
}
};
self.device.draw_elements(6, &RenderState {
target: &self.draw_render_target(),
program: &self.filter_basic_program.program,
vertex_array: &self.filter_basic_vertex_array.vertex_array,
primitive: Primitive::Triangles,
textures: &[&source_texture],
uniforms: &uniforms,
viewport: main_viewport,
options: RenderOptions {
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
blend: Some(blend_state),
..RenderOptions::default()
},
});
}
fn draw_text_layer(&self,
layer_framebuffer_info: &LayerFramebufferInfo<D>,
fg_color: ColorF,
bg_color: ColorF,
defringing_kernel: Option<DefringingKernel>,
gamma_correction: bool) {
let clear_color = self.clear_color_for_draw_operation();
let source_framebuffer = &layer_framebuffer_info.framebuffer;
let source_texture = self.device.framebuffer_texture(source_framebuffer);
let source_texture_size = self.device.texture_size(source_texture);
let main_viewport = self.main_viewport();
let mut uniforms = vec![
(&self.postprocess_program.framebuffer_size_uniform,
(&self.filter_text_program.framebuffer_size_uniform,
UniformData::Vec2(main_viewport.size().to_f32().0)),
(&self.postprocess_program.source_uniform, UniformData::TextureUnit(0)),
(&self.postprocess_program.source_size_uniform,
(&self.filter_text_program.source_uniform, UniformData::TextureUnit(0)),
(&self.filter_text_program.source_size_uniform,
UniformData::Vec2(source_texture_size.0.to_f32x2())),
(&self.postprocess_program.gamma_lut_uniform, UniformData::TextureUnit(1)),
(&self.postprocess_program.fg_color_uniform,
UniformData::Vec4(layer_framebuffer_info.effects.fg_color.0)),
(&self.postprocess_program.bg_color_uniform,
UniformData::Vec4(layer_framebuffer_info.effects.bg_color.0)),
(&self.postprocess_program.gamma_correction_enabled_uniform,
UniformData::Int(layer_framebuffer_info.effects.gamma_correction as i32)),
(&self.filter_text_program.gamma_lut_uniform, UniformData::TextureUnit(1)),
(&self.filter_text_program.fg_color_uniform, UniformData::Vec4(fg_color.0)),
(&self.filter_text_program.bg_color_uniform, UniformData::Vec4(bg_color.0)),
(&self.filter_text_program.gamma_correction_enabled_uniform,
UniformData::Int(gamma_correction as i32)),
];
match layer_framebuffer_info.effects.defringing_kernel {
match defringing_kernel {
Some(ref kernel) => {
uniforms.push((&self.postprocess_program.kernel_uniform,
uniforms.push((&self.filter_text_program.kernel_uniform,
UniformData::Vec4(F32x4::from_slice(&kernel.0))));
}
None => {
uniforms.push((&self.postprocess_program.kernel_uniform,
uniforms.push((&self.filter_text_program.kernel_uniform,
UniformData::Vec4(F32x4::default())));
}
}
self.device.draw_elements(6, &RenderState {
target: &self.draw_render_target(),
program: &self.postprocess_program.program,
vertex_array: &self.postprocess_vertex_array.vertex_array,
program: &self.filter_text_program.program,
vertex_array: &self.filter_text_vertex_array.vertex_array,
primitive: Primitive::Triangles,
textures: &[&source_texture, &self.gamma_lut_texture],
uniforms: &uniforms,
@ -828,10 +902,6 @@ where
..RenderOptions::default()
},
});
self.preserve_draw_framebuffer();
self.framebuffer_cache.release_framebuffer(layer_framebuffer_info.framebuffer);
}
fn stencil_state(&self) -> Option<StencilState> {
@ -847,7 +917,7 @@ where
})
}
fn clear_color_for_draw_operation(&mut self) -> Option<ColorF> {
fn clear_color_for_draw_operation(&self) -> Option<ColorF> {
let must_preserve_contents = match self.layer_framebuffer_stack.last() {
Some(ref layer_framebuffer_info) => layer_framebuffer_info.must_preserve_contents,
None => {
@ -924,15 +994,6 @@ where
}
}
// FIXME(pcwalton): Rename to `Effects` and move to `pathfinder_content`, perhaps?
#[derive(Clone, Copy, Default, Debug)]
pub struct PostprocessOptions {
pub fg_color: ColorF,
pub bg_color: ColorF,
pub defringing_kernel: Option<DefringingKernel>,
pub gamma_correction: bool,
}
// Render stats
#[derive(Clone, Copy, Debug, Default)]
@ -1047,6 +1108,6 @@ impl<D> FramebufferCache<D> where D: Device {
struct LayerFramebufferInfo<D> where D: Device {
framebuffer: D::Framebuffer,
effects: PostprocessOptions,
effects: Effects,
must_preserve_contents: bool,
}

View File

@ -388,69 +388,44 @@ impl<D> AlphaTileProgram<D> where D: Device {
}
}
pub struct PostprocessProgram<D>
where
D: Device,
{
pub struct FilterBasicProgram<D> where D: Device {
pub program: D::Program,
pub source_uniform: D::Uniform,
pub source_size_uniform: D::Uniform,
pub framebuffer_size_uniform: D::Uniform,
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> PostprocessProgram<D>
where
D: Device,
{
pub fn new(device: &D, resources: &dyn ResourceLoader) -> PostprocessProgram<D> {
let program = device.create_program(resources, "post");
impl<D> FilterBasicProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> FilterBasicProgram<D> {
let program = device.create_program_from_shader_names(resources,
"filter_basic",
"filter",
"filter_basic");
let source_uniform = device.get_uniform(&program, "Source");
let source_size_uniform = device.get_uniform(&program, "SourceSize");
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
let kernel_uniform = device.get_uniform(&program, "Kernel");
let gamma_lut_uniform = device.get_uniform(&program, "GammaLUT");
let gamma_correction_enabled_uniform = device.get_uniform(&program,
"GammaCorrectionEnabled");
let fg_color_uniform = device.get_uniform(&program, "FGColor");
let bg_color_uniform = device.get_uniform(&program, "BGColor");
PostprocessProgram {
FilterBasicProgram {
program,
source_uniform,
source_size_uniform,
framebuffer_size_uniform,
kernel_uniform,
gamma_lut_uniform,
gamma_correction_enabled_uniform,
fg_color_uniform,
bg_color_uniform,
}
}
}
pub struct PostprocessVertexArray<D>
where
D: Device,
{
pub struct FilterBasicVertexArray<D> where D: Device {
pub vertex_array: D::VertexArray,
}
impl<D> PostprocessVertexArray<D>
where
D: Device,
{
impl<D> FilterBasicVertexArray<D> where D: Device {
pub fn new(
device: &D,
postprocess_program: &PostprocessProgram<D>,
fill_basic_program: &FilterBasicProgram<D>,
quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer,
) -> PostprocessVertexArray<D> {
) -> FilterBasicVertexArray<D> {
let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&postprocess_program.program, "Position")
let position_attr = device.get_vertex_attr(&fill_basic_program.program, "Position")
.unwrap();
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
@ -465,7 +440,79 @@ where
});
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
PostprocessVertexArray { vertex_array }
FilterBasicVertexArray { vertex_array }
}
}
pub struct FilterTextProgram<D> where D: Device {
pub program: D::Program,
pub source_uniform: D::Uniform,
pub source_size_uniform: D::Uniform,
pub framebuffer_size_uniform: D::Uniform,
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> FilterTextProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> FilterTextProgram<D> {
let program = device.create_program_from_shader_names(resources,
"filter_text",
"filter",
"filter_text");
let source_uniform = device.get_uniform(&program, "Source");
let source_size_uniform = device.get_uniform(&program, "SourceSize");
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
let kernel_uniform = device.get_uniform(&program, "Kernel");
let gamma_lut_uniform = device.get_uniform(&program, "GammaLUT");
let gamma_correction_enabled_uniform = device.get_uniform(&program,
"GammaCorrectionEnabled");
let fg_color_uniform = device.get_uniform(&program, "FGColor");
let bg_color_uniform = device.get_uniform(&program, "BGColor");
FilterTextProgram {
program,
source_uniform,
source_size_uniform,
framebuffer_size_uniform,
kernel_uniform,
gamma_lut_uniform,
gamma_correction_enabled_uniform,
fg_color_uniform,
bg_color_uniform,
}
}
}
pub struct FilterTextVertexArray<D> where D: Device {
pub vertex_array: D::VertexArray,
}
impl<D> FilterTextVertexArray<D> where D: Device {
pub fn new(
device: &D,
fill_text_program: &FilterTextProgram<D>,
quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer,
) -> FilterTextVertexArray<D> {
let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&fill_text_program.program, "Position")
.unwrap();
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: 4,
offset: 0,
divisor: 0,
buffer_index: 0,
});
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
FilterTextVertexArray { vertex_array }
}
}

View File

@ -1,6 +1,6 @@
// pathfinder/renderer/src/gpu_data.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
// 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
@ -10,9 +10,9 @@
//! Packed data ready to be sent to the GPU.
use crate::gpu::renderer::PostprocessOptions;
use crate::options::BoundingQuad;
use pathfinder_color::ColorU;
use pathfinder_content::effects::Effects;
use pathfinder_content::fill::FillRule;
use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8};
use pathfinder_geometry::vector::Vector2I;
@ -25,7 +25,7 @@ pub enum RenderCommand {
AddFills(Vec<FillBatchPrimitive>),
FlushFills,
RenderMaskTiles { tiles: Vec<MaskTile>, fill_rule: FillRule },
PushLayer { effects: PostprocessOptions },
PushLayer { effects: Effects },
PopLayer,
DrawAlphaTiles(Vec<AlphaTile>),
DrawSolidTiles(Vec<SolidTileVertex>),

View File

@ -20,7 +20,6 @@ pub mod gpu;
pub mod gpu_data;
pub mod options;
pub mod paint;
pub mod post;
pub mod scene;
mod allocator;

View File

@ -1,33 +0,0 @@
// pathfinder/renderer/src/post.rs
//
// 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.
//! Functionality related to postprocessing effects.
//!
//! Since these effects run on GPU as fragment shaders, this contains no
//! implementations, just shared declarations.
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct DefringingKernel(pub [f32; 4]);
/// This intentionally does not precisely match what Core Graphics does (a
/// Lanczos function), because we don't want any ringing artefacts.
pub static DEFRINGING_KERNEL_CORE_GRAPHICS: DefringingKernel =
DefringingKernel([0.033165660, 0.102074051, 0.221434336, 0.286651906]);
pub static DEFRINGING_KERNEL_FREETYPE: DefringingKernel =
DefringingKernel([0.0, 0.031372549, 0.301960784, 0.337254902]);
/// Should match macOS 10.13 High Sierra.
pub static STEM_DARKENING_FACTORS: [f32; 2] = [0.0121, 0.0121 * 1.25];
/// Should match macOS 10.13 High Sierra.
pub const MAX_STEM_DARKENING_AMOUNT: [f32; 2] = [0.3, 0.3];
/// This value is a subjective cutoff. Above this ppem value, no stem darkening is performed.
pub const MAX_STEM_DARKENING_PIXELS_PER_EM: f32 = 72.0;

View File

@ -12,10 +12,10 @@
use crate::builder::SceneBuilder;
use crate::concurrent::executor::Executor;
use crate::gpu::renderer::PostprocessOptions;
use crate::options::{BuildOptions, PreparedBuildOptions};
use crate::options::{PreparedRenderTransform, RenderCommandListener};
use crate::paint::{Paint, PaintId, PaintInfo, Palette};
use pathfinder_content::effects::Effects;
use pathfinder_content::fill::FillRule;
use pathfinder_geometry::vector::Vector2F;
use pathfinder_geometry::rect::RectF;
@ -70,7 +70,7 @@ impl Scene {
clip_path_id
}
pub fn push_layer(&mut self, effects: PostprocessOptions) {
pub fn push_layer(&mut self, effects: Effects) {
self.display_list.push(DisplayItem::PushLayer { effects });
}
@ -234,7 +234,7 @@ pub struct ClipPathId(pub u32);
#[derive(Clone, Debug)]
pub enum DisplayItem {
DrawPaths { start_index: u32, end_index: u32 },
PushLayer { effects: PostprocessOptions },
PushLayer { effects: Effects },
PopLayer,
}

View File

@ -0,0 +1,31 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
precision highp float;
in ivec2 aPosition;
out vec2 vTexCoord;
void main(){
vec2 position = vec2(aPosition);
vTexCoord = position;
gl_Position = vec4(vec2(position)* 2.0 - 1.0, 0.0, 1.0);
}

View File

@ -0,0 +1,32 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#extension GL_GOOGLE_include_directive : enable
precision highp float;
uniform sampler2D uSource;
uniform vec2 uSourceSize;
in vec2 vTexCoord;
out vec4 oFragColor;
void main(){
oFragColor = texture(uSource, vTexCoord);
}

View File

@ -0,0 +1,127 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#extension GL_GOOGLE_include_directive : enable
precision highp float;
uniform sampler2D uSource;
uniform vec2 uSourceSize;
uniform vec4 uFGColor;
uniform vec4 uBGColor;
uniform int uGammaCorrectionEnabled;
in vec2 vTexCoord;
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(uSource, vec2(vTexCoord . x + offset, vTexCoord . y)). r;
}
void main(){
vec3 alpha;
if(uKernel . w == 0.0){
alpha = texture(uSource, vTexCoord). rrr;
} else {
vec4 alphaLeft, alphaRight;
float alphaCenter;
sample9Tap(alphaLeft, alphaCenter, alphaRight, 1.0 / uSourceSize . 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

@ -24,8 +24,7 @@ fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuff
{
main0_out out = {};
float2 texCoordPx = fract(in.vTexCoord) / fwidth(in.vTexCoord);
bool4 _33 = bool4(any(texCoordPx <= float2(1.0)));
out.oFragColor = float4(_33.x ? (*spvDescriptorSet0.uGridlineColor).x : (*spvDescriptorSet0.uGroundColor).x, _33.y ? (*spvDescriptorSet0.uGridlineColor).y : (*spvDescriptorSet0.uGroundColor).y, _33.z ? (*spvDescriptorSet0.uGridlineColor).z : (*spvDescriptorSet0.uGroundColor).z, _33.w ? (*spvDescriptorSet0.uGridlineColor).w : (*spvDescriptorSet0.uGroundColor).w);
out.oFragColor = select((*spvDescriptorSet0.uGroundColor), (*spvDescriptorSet0.uGridlineColor), bool4(any(texCoordPx <= float2(1.0))));
return out;
}

View File

@ -26,10 +26,8 @@ fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuff
main0_out out = {};
float2 from = in.vFrom;
float2 to = in.vTo;
bool2 _29 = bool2(from.x < to.x);
float2 left = float2(_29.x ? from.x : to.x, _29.y ? from.y : to.y);
bool2 _39 = bool2(from.x < to.x);
float2 right = float2(_39.x ? to.x : from.x, _39.y ? to.y : from.y);
float2 left = select(to, from, bool2(from.x < to.x));
float2 right = select(from, to, bool2(from.x < to.x));
float2 window = fast::clamp(float2(from.x, to.x), float2(-0.5), float2(0.5));
float offset = mix(window.x, window.y, 0.5) - left.x;
float t = offset / (right.x - left.x);

View File

@ -0,0 +1,27 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float2 vTexCoord [[user(locn0)]];
float4 gl_Position [[position]];
};
struct main0_in
{
int2 aPosition [[attribute(0)]];
};
vertex main0_out main0(main0_in in [[stage_in]])
{
main0_out out = {};
float2 position = float2(in.aPosition);
out.vTexCoord = position;
position.y = 1.0 - position.y;
out.gl_Position = float4((float2(position) * 2.0) - float2(1.0), 0.0, 1.0);
return out;
}

View File

@ -0,0 +1,29 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uSource [[id(0)]];
sampler uSourceSmplr [[id(1)]];
};
struct main0_out
{
float4 oFragColor [[color(0)]];
};
struct main0_in
{
float2 vTexCoord [[user(locn0)]];
};
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
out.oFragColor = spvDescriptorSet0.uSource.sample(spvDescriptorSet0.uSourceSmplr, in.vTexCoord);
return out;
}

View File

@ -0,0 +1,130 @@
// 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> uSource [[id(3)]];
sampler uSourceSmplr [[id(4)]];
constant float2* uSourceSize [[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 vTexCoord [[user(locn0)]];
};
float sample1Tap(thread const float& offset, thread texture2d<float> uSource, thread const sampler uSourceSmplr, thread float2& vTexCoord)
{
return uSource.sample(uSourceSmplr, float2(vTexCoord.x + offset, vTexCoord.y)).x;
}
void sample9Tap(thread float4& outAlphaLeft, thread float& outAlphaCenter, thread float4& outAlphaRight, thread const float& onePixel, thread float4 uKernel, thread texture2d<float> uSource, thread const sampler uSourceSmplr, thread float2& vTexCoord)
{
float _89;
if (uKernel.x > 0.0)
{
float param = (-4.0) * onePixel;
_89 = sample1Tap(param, uSource, uSourceSmplr, vTexCoord);
}
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, uSource, uSourceSmplr, vTexCoord), sample1Tap(param_2, uSource, uSourceSmplr, vTexCoord), sample1Tap(param_3, uSource, uSourceSmplr, vTexCoord));
float param_4 = 0.0;
outAlphaCenter = sample1Tap(param_4, uSource, uSourceSmplr, vTexCoord);
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, uSource, uSourceSmplr, vTexCoord);
}
else
{
_134 = 0.0;
}
outAlphaRight = float4(sample1Tap(param_5, uSource, uSourceSmplr, vTexCoord), sample1Tap(param_6, uSource, uSourceSmplr, vTexCoord), sample1Tap(param_7, uSource, uSourceSmplr, vTexCoord), _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.uSource.sample(spvDescriptorSet0.uSourceSmplr, in.vTexCoord).xxx;
}
else
{
float param_3 = 1.0 / (*spvDescriptorSet0.uSourceSize).x;
float4 param;
float param_1;
float4 param_2;
sample9Tap(param, param_1, param_2, param_3, (*spvDescriptorSet0.uKernel), spvDescriptorSet0.uSource, spvDescriptorSet0.uSourceSmplr, in.vTexCoord);
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

@ -14,8 +14,9 @@ SHADERS=\
mask.vs.glsl \
mask_evenodd.fs.glsl \
mask_winding.fs.glsl \
post.fs.glsl \
post.vs.glsl \
filter.vs.glsl \
filter_basic.fs.glsl \
filter_text.fs.glsl \
reproject.fs.glsl \
reproject.vs.glsl \
stencil.fs.glsl \
@ -27,8 +28,8 @@ SHADERS=\
$(EMPTY)
INCLUDES=\
post_convolve.inc.glsl \
post_gamma_correct.inc.glsl \
filter_text_convolve.inc.glsl \
filter_text_gamma_correct.inc.glsl \
$(EMPTY)
OUT=\

View File

@ -1,8 +1,8 @@
#version 330
// pathfinder/shaders/post.vs.glsl
// pathfinder/shaders/filter.vs.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
// 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

View File

@ -0,0 +1,29 @@
#version 330
// pathfinder/shaders/filter_basic.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.
#extension GL_GOOGLE_include_directive : enable
precision highp float;
uniform sampler2D uSource;
uniform vec2 uSourceSize;
in vec2 vTexCoord;
out vec4 oFragColor;
void main() {
oFragColor = texture(uSource, vTexCoord);
}

View File

@ -1,6 +1,6 @@
#version 330
// pathfinder/shaders/post.fs.glsl
// pathfinder/shaders/filter_text.fs.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
//
@ -27,8 +27,8 @@ in vec2 vTexCoord;
out vec4 oFragColor;
#include "post_gamma_correct.inc.glsl"
#include "post_convolve.inc.glsl"
#include "filter_text_gamma_correct.inc.glsl"
#include "filter_text_convolve.inc.glsl"
// Convolve horizontally in this pass.
float sample1Tap(float offset) {

View File

@ -1,4 +1,4 @@
// pathfinder/shaders/post_convolve.inc.glsl
// pathfinder/shaders/filter_text_convolve.inc.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
//

View File

@ -1,4 +1,4 @@
// pathfinder/shaders/post_gamma_correct.inc.glsl
// pathfinder/shaders/filter_text_gamma_correct.inc.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
//