diff --git a/Cargo.lock b/Cargo.lock index 08e1b167..bb7bf19d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/content/src/effects.rs b/content/src/effects.rs new file mode 100644 index 00000000..92ded519 --- /dev/null +++ b/content/src/effects.rs @@ -0,0 +1,72 @@ +// pathfinder/content/src/effects.rs +// +// Copyright © 2020 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! 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, + /// 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 + } +} diff --git a/content/src/lib.rs b/content/src/lib.rs index 2a7d68f4..095b40a1 100644 --- a/content/src/lib.rs +++ b/content/src/lib.rs @@ -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; diff --git a/demo/common/Cargo.toml b/demo/common/Cargo.toml index 0beb480c..1a94097e 100644 --- a/demo/common/Cargo.toml +++ b/demo/common/Cargo.toml @@ -24,6 +24,9 @@ version = "0.4" [dependencies.pathfinder_color] path = "../../color" +[dependencies.pathfinder_content] +path = "../../content" + [dependencies.pathfinder_export] path = "../../export" diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index eccbf217..81968f07 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -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) +fn load_scene(resource_loader: &dyn ResourceLoader, input_path: &SVGPath, effects: Option) -> (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) -> BuiltSVG { +fn build_svg_tree(tree: &Tree, effects: Option) -> 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 { +fn build_effects(ui_model: &DemoUIModel) -> Option { 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 + } }, }) } diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index 2f754b5a..fdc3d39a 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -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), DrawAlphaTiles(Vec), - PushLayer { effects: PostprocessOptions }, + PushLayer { effects: Effects }, PopLayer, } diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index bbec59d8..41ae72d1 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -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, layer_framebuffer_stack: Vec>, - // Postprocessing shader - postprocess_program: PostprocessProgram, - postprocess_vertex_array: PostprocessVertexArray, + // Filter shaders + filter_basic_program: FilterBasicProgram, + filter_basic_vertex_array: FilterBasicVertexArray, + filter_text_program: FilterTextProgram, + filter_text_vertex_array: FilterTextVertexArray, 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, + 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, + fg_color: ColorF, + bg_color: ColorF, + defringing_kernel: Option, + 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 { @@ -847,7 +917,7 @@ where }) } - fn clear_color_for_draw_operation(&mut self) -> Option { + fn clear_color_for_draw_operation(&self) -> Option { 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, - pub gamma_correction: bool, -} - // Render stats #[derive(Clone, Copy, Debug, Default)] @@ -1047,6 +1108,6 @@ impl FramebufferCache where D: Device { struct LayerFramebufferInfo where D: Device { framebuffer: D::Framebuffer, - effects: PostprocessOptions, + effects: Effects, must_preserve_contents: bool, } diff --git a/renderer/src/gpu/shaders.rs b/renderer/src/gpu/shaders.rs index 1aa9745d..3b9222d6 100644 --- a/renderer/src/gpu/shaders.rs +++ b/renderer/src/gpu/shaders.rs @@ -388,69 +388,44 @@ impl AlphaTileProgram where D: Device { } } -pub struct PostprocessProgram -where - D: Device, -{ +pub struct FilterBasicProgram 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 PostprocessProgram -where - D: Device, -{ - pub fn new(device: &D, resources: &dyn ResourceLoader) -> PostprocessProgram { - let program = device.create_program(resources, "post"); +impl FilterBasicProgram where D: Device { + pub fn new(device: &D, resources: &dyn ResourceLoader) -> FilterBasicProgram { + 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 -where - D: Device, -{ +pub struct FilterBasicVertexArray where D: Device { pub vertex_array: D::VertexArray, } -impl PostprocessVertexArray -where - D: Device, -{ +impl FilterBasicVertexArray where D: Device { pub fn new( device: &D, - postprocess_program: &PostprocessProgram, + fill_basic_program: &FilterBasicProgram, quad_vertex_positions_buffer: &D::Buffer, quad_vertex_indices_buffer: &D::Buffer, - ) -> PostprocessVertexArray { + ) -> FilterBasicVertexArray { 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 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 FilterTextProgram where D: Device { + pub fn new(device: &D, resources: &dyn ResourceLoader) -> FilterTextProgram { + 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 where D: Device { + pub vertex_array: D::VertexArray, +} + +impl FilterTextVertexArray where D: Device { + pub fn new( + device: &D, + fill_text_program: &FilterTextProgram, + quad_vertex_positions_buffer: &D::Buffer, + quad_vertex_indices_buffer: &D::Buffer, + ) -> FilterTextVertexArray { + 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 } } } diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index 7318be65..c8e6f623 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -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 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), FlushFills, RenderMaskTiles { tiles: Vec, fill_rule: FillRule }, - PushLayer { effects: PostprocessOptions }, + PushLayer { effects: Effects }, PopLayer, DrawAlphaTiles(Vec), DrawSolidTiles(Vec), diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index 05715479..b12d8fbc 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -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; diff --git a/renderer/src/post.rs b/renderer/src/post.rs deleted file mode 100644 index 0e30dcb8..00000000 --- a/renderer/src/post.rs +++ /dev/null @@ -1,33 +0,0 @@ -// pathfinder/renderer/src/post.rs -// -// Copyright © 2019 The Pathfinder Project Developers. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! 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; diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index a178d003..383a108b 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -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, } diff --git a/resources/shaders/gl3/filter.vs.glsl b/resources/shaders/gl3/filter.vs.glsl new file mode 100644 index 00000000..a1d8effb --- /dev/null +++ b/resources/shaders/gl3/filter.vs.glsl @@ -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); +} + diff --git a/resources/shaders/gl3/filter_basic.fs.glsl b/resources/shaders/gl3/filter_basic.fs.glsl new file mode 100644 index 00000000..d9181eb4 --- /dev/null +++ b/resources/shaders/gl3/filter_basic.fs.glsl @@ -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); +} + diff --git a/resources/shaders/gl3/filter_text.fs.glsl b/resources/shaders/gl3/filter_text.fs.glsl new file mode 100644 index 00000000..b9de3d7b --- /dev/null +++ b/resources/shaders/gl3/filter_text.fs.glsl @@ -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); +} + diff --git a/resources/shaders/metal/demo_ground.fs.metal b/resources/shaders/metal/demo_ground.fs.metal index 1b64111f..7d54eaf1 100644 --- a/resources/shaders/metal/demo_ground.fs.metal +++ b/resources/shaders/metal/demo_ground.fs.metal @@ -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; } diff --git a/resources/shaders/metal/fill.fs.metal b/resources/shaders/metal/fill.fs.metal index bfa765e5..04b844ad 100644 --- a/resources/shaders/metal/fill.fs.metal +++ b/resources/shaders/metal/fill.fs.metal @@ -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); diff --git a/resources/shaders/metal/filter.vs.metal b/resources/shaders/metal/filter.vs.metal new file mode 100644 index 00000000..f7385038 --- /dev/null +++ b/resources/shaders/metal/filter.vs.metal @@ -0,0 +1,27 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! +#include +#include + +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; +} + diff --git a/resources/shaders/metal/filter_basic.fs.metal b/resources/shaders/metal/filter_basic.fs.metal new file mode 100644 index 00000000..a5f680a1 --- /dev/null +++ b/resources/shaders/metal/filter_basic.fs.metal @@ -0,0 +1,29 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! +#include +#include + +using namespace metal; + +struct spvDescriptorSetBuffer0 +{ + texture2d 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; +} + diff --git a/resources/shaders/metal/filter_text.fs.metal b/resources/shaders/metal/filter_text.fs.metal new file mode 100644 index 00000000..e13bec29 --- /dev/null +++ b/resources/shaders/metal/filter_text.fs.metal @@ -0,0 +1,130 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct spvDescriptorSetBuffer0 +{ + texture2d uGammaLUT [[id(0)]]; + sampler uGammaLUTSmplr [[id(1)]]; + constant float4* uKernel [[id(2)]]; + texture2d 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 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 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 uGammaLUT, thread const sampler uGammaLUTSmplr) +{ + return uGammaLUT.sample(uGammaLUTSmplr, float2(fgColor, 1.0 - bgColor)).x; +} + +float3 gammaCorrect(thread const float3& bgColor, thread const float3& fgColor, thread texture2d uGammaLUT, thread const sampler uGammaLUTSmplr) +{ + float param = bgColor.x; + float param_1 = fgColor.x; + float param_2 = bgColor.y; + float param_3 = fgColor.y; + float param_4 = bgColor.z; + float param_5 = fgColor.z; + return float3(gammaCorrectChannel(param, param_1, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_2, param_3, uGammaLUT, uGammaLUTSmplr), gammaCorrectChannel(param_4, param_5, uGammaLUT, uGammaLUTSmplr)); +} + +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) +{ + main0_out out = {}; + float3 alpha; + if ((*spvDescriptorSet0.uKernel).w == 0.0) + { + alpha = spvDescriptorSet0.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; +} + diff --git a/shaders/Makefile b/shaders/Makefile index 634331bc..c03cf84b 100644 --- a/shaders/Makefile +++ b/shaders/Makefile @@ -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=\ diff --git a/shaders/post.vs.glsl b/shaders/filter.vs.glsl similarity index 87% rename from shaders/post.vs.glsl rename to shaders/filter.vs.glsl index 52cf3eea..0d6d47cb 100644 --- a/shaders/post.vs.glsl +++ b/shaders/filter.vs.glsl @@ -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 or the MIT license diff --git a/shaders/filter_basic.fs.glsl b/shaders/filter_basic.fs.glsl new file mode 100644 index 00000000..635e5784 --- /dev/null +++ b/shaders/filter_basic.fs.glsl @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// TODO(pcwalton): This could be significantly optimized by operating on a +// sparse per-tile basis. + +#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); +} diff --git a/shaders/post.fs.glsl b/shaders/filter_text.fs.glsl similarity index 92% rename from shaders/post.fs.glsl rename to shaders/filter_text.fs.glsl index 62d40494..d714ad2d 100644 --- a/shaders/post.fs.glsl +++ b/shaders/filter_text.fs.glsl @@ -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) { diff --git a/shaders/post_convolve.inc.glsl b/shaders/filter_text_convolve.inc.glsl similarity index 96% rename from shaders/post_convolve.inc.glsl rename to shaders/filter_text_convolve.inc.glsl index 1bf3e2ce..cbeded95 100644 --- a/shaders/post_convolve.inc.glsl +++ b/shaders/filter_text_convolve.inc.glsl @@ -1,4 +1,4 @@ -// pathfinder/shaders/post_convolve.inc.glsl +// pathfinder/shaders/filter_text_convolve.inc.glsl // // Copyright © 2019 The Pathfinder Project Developers. // diff --git a/shaders/post_gamma_correct.inc.glsl b/shaders/filter_text_gamma_correct.inc.glsl similarity index 93% rename from shaders/post_gamma_correct.inc.glsl rename to shaders/filter_text_gamma_correct.inc.glsl index 11f47d2a..d72ef159 100644 --- a/shaders/post_gamma_correct.inc.glsl +++ b/shaders/filter_text_gamma_correct.inc.glsl @@ -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. //