Add basic postprocessing support
This commit is contained in:
parent
035baf656b
commit
ba5a0f987c
|
@ -18,15 +18,17 @@ precision highp float;
|
||||||
uniform sampler2D uSource;
|
uniform sampler2D uSource;
|
||||||
uniform sampler2D uGammaLUT;
|
uniform sampler2D uGammaLUT;
|
||||||
uniform vec2 uFramebufferSize;
|
uniform vec2 uFramebufferSize;
|
||||||
|
// Zero if no subpixel AA is to be performed.
|
||||||
uniform vec4 uKernel;
|
uniform vec4 uKernel;
|
||||||
uniform vec4 uBGColor;
|
// Zero if no gamma correction is to be performed.
|
||||||
|
uniform vec4 uGammaCorrectionBGColor;
|
||||||
|
|
||||||
in vec2 vTexCoord;
|
in vec2 vTexCoord;
|
||||||
|
|
||||||
out vec4 oFragColor;
|
out vec4 oFragColor;
|
||||||
|
|
||||||
float gammaCorrectChannel(float fgColor) {
|
float gammaCorrectChannel(float fgColor) {
|
||||||
return texture(uGammaLUT, vec2(fgColor, 1.0 - uBGColor)).r;
|
return texture(uGammaLUT, vec2(fgColor, 1.0 - uGammaCorrectionBGColor)).r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// `fgColor` is in linear space.
|
// `fgColor` is in linear space.
|
||||||
|
@ -76,7 +78,7 @@ void main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply gamma correction if necessary.
|
// Apply gamma correction if necessary.
|
||||||
if (uBGColor.a > 0.0)
|
if (uGammaCorrectionBGColor.a > 0.0)
|
||||||
fgColor = gammaCorrect(fgColor);
|
fgColor = gammaCorrect(fgColor);
|
||||||
|
|
||||||
// Finish.
|
// Finish.
|
||||||
|
|
|
@ -12,13 +12,11 @@
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
uniform vec2 uFramebufferSize;
|
|
||||||
|
|
||||||
in vec2 aPosition;
|
in vec2 aPosition;
|
||||||
|
|
||||||
out vec2 vTexCoord;
|
out vec2 vTexCoord;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vTexCoord = aPosition;
|
vTexCoord = aPosition;
|
||||||
gl_Position = vec4(aPosition / uFramebufferSize * 2.0 - 1.0, 0.0, 1.0);
|
gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ use pathfinder_gl::device::Texture;
|
||||||
use pathfinder_gl::renderer::Renderer;
|
use pathfinder_gl::renderer::Renderer;
|
||||||
use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder};
|
use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder};
|
||||||
use pathfinder_renderer::gpu_data::BuiltScene;
|
use pathfinder_renderer::gpu_data::BuiltScene;
|
||||||
|
use pathfinder_renderer::paint::ColorU;
|
||||||
|
use pathfinder_renderer::post::DEFRINGING_KERNEL_CORE_GRAPHICS;
|
||||||
use pathfinder_renderer::scene::Scene;
|
use pathfinder_renderer::scene::Scene;
|
||||||
use pathfinder_renderer::z_buffer::ZBuffer;
|
use pathfinder_renderer::z_buffer::ZBuffer;
|
||||||
use pathfinder_svg::SceneExt;
|
use pathfinder_svg::SceneExt;
|
||||||
|
@ -46,7 +48,7 @@ const MAIN_FRAMEBUFFER_HEIGHT: u32 = 800;
|
||||||
const MOUSELOOK_ROTATION_SPEED: f32 = 0.007;
|
const MOUSELOOK_ROTATION_SPEED: f32 = 0.007;
|
||||||
const CAMERA_VELOCITY: f32 = 25.0;
|
const CAMERA_VELOCITY: f32 = 25.0;
|
||||||
|
|
||||||
const BACKGROUND_COLOR: f32 = 0.22;
|
const BACKGROUND_COLOR: ColorU = ColorU { r: 32, g: 32, b: 32, a: 255 };
|
||||||
|
|
||||||
const EFFECTS_WINDOW_WIDTH: i32 = 550;
|
const EFFECTS_WINDOW_WIDTH: i32 = 550;
|
||||||
const EFFECTS_WINDOW_HEIGHT: i32 = BUTTON_HEIGHT * 3 + PADDING * 4;
|
const EFFECTS_WINDOW_HEIGHT: i32 = BUTTON_HEIGHT * 3 + PADDING * 4;
|
||||||
|
@ -129,7 +131,9 @@ fn main() {
|
||||||
|
|
||||||
let count = if frame_counter == 0 { 2 } else { 1 };
|
let count = if frame_counter == 0 { 2 } else { 1 };
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
scene_thread_proxy.sender.send(MainToSceneMsg::Build(perspective)).unwrap();
|
scene_thread_proxy.sender.send(MainToSceneMsg::Build(BuildOptions {
|
||||||
|
perspective
|
||||||
|
})).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(pcwalton): This can cause us to miss UI events if things get backed up...
|
// FIXME(pcwalton): This can cause us to miss UI events if things get backed up...
|
||||||
|
@ -204,8 +208,24 @@ fn main() {
|
||||||
tile_time
|
tile_time
|
||||||
} = scene_thread_proxy.receiver.recv().unwrap();
|
} = scene_thread_proxy.receiver.recv().unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::ClearColor(BACKGROUND_COLOR, BACKGROUND_COLOR, BACKGROUND_COLOR, 1.0);
|
gl::ClearColor(BACKGROUND_COLOR.r as f32 / 255.0,
|
||||||
|
BACKGROUND_COLOR.g as f32 / 255.0,
|
||||||
|
BACKGROUND_COLOR.b as f32 / 255.0,
|
||||||
|
BACKGROUND_COLOR.a as f32 / 255.0);
|
||||||
gl::Clear(gl::COLOR_BUFFER_BIT);
|
gl::Clear(gl::COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
if demo_ui.gamma_correction_effect_enabled {
|
||||||
|
renderer.enable_gamma_correction(BACKGROUND_COLOR);
|
||||||
|
} else {
|
||||||
|
renderer.disable_gamma_correction();
|
||||||
|
}
|
||||||
|
|
||||||
|
if demo_ui.subpixel_aa_effect_enabled {
|
||||||
|
renderer.enable_subpixel_aa(&DEFRINGING_KERNEL_CORE_GRAPHICS);
|
||||||
|
} else {
|
||||||
|
renderer.disable_subpixel_aa();
|
||||||
|
}
|
||||||
|
|
||||||
renderer.render_scene(&built_scene);
|
renderer.render_scene(&built_scene);
|
||||||
|
|
||||||
let rendering_time = renderer.shift_timer_query();
|
let rendering_time = renderer.shift_timer_query();
|
||||||
|
@ -268,9 +288,9 @@ impl SceneThread {
|
||||||
RectF32::new(Point2DF32::default(),
|
RectF32::new(Point2DF32::default(),
|
||||||
Point2DF32::new(size.width as f32, size.height as f32));
|
Point2DF32::new(size.width as f32, size.height as f32));
|
||||||
}
|
}
|
||||||
MainToSceneMsg::Build(perspective) => {
|
MainToSceneMsg::Build(build_options) => {
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let built_scene = build_scene(&self.scene, perspective, &self.options);
|
let built_scene = build_scene(&self.scene, build_options, self.options.jobs);
|
||||||
let tile_time = Instant::now() - start_time;
|
let tile_time = Instant::now() - start_time;
|
||||||
self.sender.send(SceneToMainMsg::Render { built_scene, tile_time }).unwrap();
|
self.sender.send(SceneToMainMsg::Render { built_scene, tile_time }).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -281,7 +301,11 @@ impl SceneThread {
|
||||||
|
|
||||||
enum MainToSceneMsg {
|
enum MainToSceneMsg {
|
||||||
SetDrawableSize(Size2D<u32>),
|
SetDrawableSize(Size2D<u32>),
|
||||||
Build(Option<Perspective>),
|
Build(BuildOptions),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BuildOptions {
|
||||||
|
perspective: Option<Perspective>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SceneToMainMsg {
|
enum SceneToMainMsg {
|
||||||
|
@ -344,11 +368,11 @@ fn load_scene(options: &Options) -> Scene {
|
||||||
scene
|
scene
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_scene(scene: &Scene, perspective: Option<Perspective>, options: &Options) -> BuiltScene {
|
fn build_scene(scene: &Scene, build_options: BuildOptions, jobs: Option<usize>) -> BuiltScene {
|
||||||
let z_buffer = ZBuffer::new(scene.view_box);
|
let z_buffer = ZBuffer::new(scene.view_box);
|
||||||
|
|
||||||
let render_options = RenderOptions {
|
let render_options = RenderOptions {
|
||||||
transform: match perspective {
|
transform: match build_options.perspective {
|
||||||
None => RenderTransform::Transform2D(Transform2DF32::default()),
|
None => RenderTransform::Transform2D(Transform2DF32::default()),
|
||||||
Some(perspective) => RenderTransform::Perspective(perspective),
|
Some(perspective) => RenderTransform::Perspective(perspective),
|
||||||
},
|
},
|
||||||
|
@ -356,7 +380,7 @@ fn build_scene(scene: &Scene, perspective: Option<Perspective>, options: &Option
|
||||||
};
|
};
|
||||||
|
|
||||||
let built_objects = panic::catch_unwind(|| {
|
let built_objects = panic::catch_unwind(|| {
|
||||||
match options.jobs {
|
match jobs {
|
||||||
Some(1) => scene.build_objects_sequentially(render_options, &z_buffer),
|
Some(1) => scene.build_objects_sequentially(render_options, &z_buffer),
|
||||||
_ => scene.build_objects(render_options, &z_buffer),
|
_ => scene.build_objects(render_options, &z_buffer),
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,8 +70,7 @@ pub struct Framebuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Framebuffer {
|
impl Framebuffer {
|
||||||
pub fn new(size: &Size2D<u32>) -> Framebuffer {
|
pub fn new(texture: Texture) -> Framebuffer {
|
||||||
let texture = Texture::new_r16f(size);
|
|
||||||
let mut gl_framebuffer = 0;
|
let mut gl_framebuffer = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::GenFramebuffers(1, &mut gl_framebuffer);
|
gl::GenFramebuffers(1, &mut gl_framebuffer);
|
||||||
|
@ -271,7 +270,7 @@ pub struct Texture {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Texture {
|
impl Texture {
|
||||||
fn new_r16f(size: &Size2D<u32>) -> Texture {
|
pub fn new_r16f(size: &Size2D<u32>) -> Texture {
|
||||||
let mut texture = Texture { gl_texture: 0, size: *size };
|
let mut texture = Texture { gl_texture: 0, size: *size };
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::GenTextures(1, &mut texture.gl_texture);
|
gl::GenTextures(1, &mut texture.gl_texture);
|
||||||
|
|
|
@ -14,9 +14,11 @@ use crate::device::{TimerQuery, Uniform, VertexAttr};
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use gl::types::{GLfloat, GLint, GLuint};
|
use gl::types::{GLfloat, GLint, GLuint};
|
||||||
use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive};
|
use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive};
|
||||||
use pathfinder_renderer::paint::ObjectShader;
|
use pathfinder_renderer::paint::{ColorU, ObjectShader};
|
||||||
|
use pathfinder_renderer::post::DefringingKernel;
|
||||||
use pathfinder_renderer::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
use pathfinder_renderer::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::ptr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
static QUAD_VERTEX_POSITIONS: [u8; 8] = [0, 0, 1, 0, 1, 1, 0, 1];
|
static QUAD_VERTEX_POSITIONS: [u8; 8] = [0, 0, 1, 0, 1, 1, 0, 1];
|
||||||
|
@ -47,6 +49,7 @@ pub struct Renderer {
|
||||||
fill_colors_texture: Texture,
|
fill_colors_texture: Texture,
|
||||||
|
|
||||||
// Postprocessing shader
|
// Postprocessing shader
|
||||||
|
postprocess_source_framebuffer: Option<Framebuffer>,
|
||||||
postprocess_program: PostprocessProgram,
|
postprocess_program: PostprocessProgram,
|
||||||
postprocess_vertex_array: PostprocessVertexArray,
|
postprocess_vertex_array: PostprocessVertexArray,
|
||||||
gamma_lut_texture: Texture,
|
gamma_lut_texture: Texture,
|
||||||
|
@ -58,6 +61,7 @@ pub struct Renderer {
|
||||||
|
|
||||||
// Extra info
|
// Extra info
|
||||||
main_framebuffer_size: Size2D<u32>,
|
main_framebuffer_size: Size2D<u32>,
|
||||||
|
postprocess_options: PostprocessOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
|
@ -85,8 +89,9 @@ impl Renderer {
|
||||||
let postprocess_vertex_array = PostprocessVertexArray::new(&postprocess_program,
|
let postprocess_vertex_array = PostprocessVertexArray::new(&postprocess_program,
|
||||||
&quad_vertex_positions_buffer);
|
&quad_vertex_positions_buffer);
|
||||||
|
|
||||||
let mask_framebuffer = Framebuffer::new(&Size2D::new(MASK_FRAMEBUFFER_WIDTH,
|
let mask_framebuffer_texture = Texture::new_r16f(&Size2D::new(MASK_FRAMEBUFFER_WIDTH,
|
||||||
MASK_FRAMEBUFFER_HEIGHT));
|
MASK_FRAMEBUFFER_HEIGHT));
|
||||||
|
let mask_framebuffer = Framebuffer::new(mask_framebuffer_texture);
|
||||||
|
|
||||||
let fill_colors_texture = Texture::new_rgba(&Size2D::new(FILL_COLORS_TEXTURE_WIDTH,
|
let fill_colors_texture = Texture::new_rgba(&Size2D::new(FILL_COLORS_TEXTURE_WIDTH,
|
||||||
FILL_COLORS_TEXTURE_HEIGHT));
|
FILL_COLORS_TEXTURE_HEIGHT));
|
||||||
|
@ -105,6 +110,7 @@ impl Renderer {
|
||||||
mask_framebuffer,
|
mask_framebuffer,
|
||||||
fill_colors_texture,
|
fill_colors_texture,
|
||||||
|
|
||||||
|
postprocess_source_framebuffer: None,
|
||||||
postprocess_program,
|
postprocess_program,
|
||||||
postprocess_vertex_array,
|
postprocess_vertex_array,
|
||||||
gamma_lut_texture,
|
gamma_lut_texture,
|
||||||
|
@ -115,10 +121,13 @@ impl Renderer {
|
||||||
debug_ui,
|
debug_ui,
|
||||||
|
|
||||||
main_framebuffer_size: *main_framebuffer_size,
|
main_framebuffer_size: *main_framebuffer_size,
|
||||||
|
postprocess_options: PostprocessOptions::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_scene(&mut self, built_scene: &BuiltScene) {
|
pub fn render_scene(&mut self, built_scene: &BuiltScene) {
|
||||||
|
self.init_postprocessing_framebuffer();
|
||||||
|
|
||||||
let timer_query = self.free_timer_queries.pop().unwrap_or_else(|| TimerQuery::new());
|
let timer_query = self.free_timer_queries.pop().unwrap_or_else(|| TimerQuery::new());
|
||||||
timer_query.begin();
|
timer_query.begin();
|
||||||
|
|
||||||
|
@ -133,6 +142,10 @@ impl Renderer {
|
||||||
self.draw_batch_mask_tiles(batch);
|
self.draw_batch_mask_tiles(batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.postprocessing_needed() {
|
||||||
|
self.postprocess();
|
||||||
|
}
|
||||||
|
|
||||||
timer_query.end();
|
timer_query.end();
|
||||||
self.pending_timer_queries.push_back(timer_query);
|
self.pending_timer_queries.push_back(timer_query);
|
||||||
}
|
}
|
||||||
|
@ -148,11 +161,32 @@ impl Renderer {
|
||||||
Some(result)
|
Some(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn set_main_framebuffer_size(&mut self, new_framebuffer_size: &Size2D<u32>) {
|
pub fn set_main_framebuffer_size(&mut self, new_framebuffer_size: &Size2D<u32>) {
|
||||||
self.main_framebuffer_size = *new_framebuffer_size;
|
self.main_framebuffer_size = *new_framebuffer_size;
|
||||||
self.debug_ui.set_framebuffer_size(new_framebuffer_size);
|
self.debug_ui.set_framebuffer_size(new_framebuffer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_subpixel_aa(&mut self) {
|
||||||
|
self.postprocess_options.defringing_kernel = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_subpixel_aa(&mut self, defringing_kernel: &DefringingKernel) {
|
||||||
|
self.postprocess_options.defringing_kernel = Some(*defringing_kernel);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn disable_gamma_correction(&mut self) {
|
||||||
|
self.postprocess_options.gamma_correction_bg_color = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_gamma_correction(&mut self, bg_color: ColorU) {
|
||||||
|
self.postprocess_options.gamma_correction_bg_color = Some(bg_color);
|
||||||
|
}
|
||||||
|
|
||||||
fn upload_shaders(&mut self, shaders: &[ObjectShader]) {
|
fn upload_shaders(&mut self, shaders: &[ObjectShader]) {
|
||||||
let size = Size2D::new(FILL_COLORS_TEXTURE_WIDTH, FILL_COLORS_TEXTURE_HEIGHT);
|
let size = Size2D::new(FILL_COLORS_TEXTURE_WIDTH, FILL_COLORS_TEXTURE_HEIGHT);
|
||||||
let mut fill_colors = vec![0; size.width as usize * size.height as usize * 4];
|
let mut fill_colors = vec![0; size.width as usize * size.height as usize * 4];
|
||||||
|
@ -208,11 +242,8 @@ impl Renderer {
|
||||||
|
|
||||||
fn draw_batch_mask_tiles(&mut self, batch: &Batch) {
|
fn draw_batch_mask_tiles(&mut self, batch: &Batch) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
self.bind_draw_framebuffer();
|
||||||
gl::Viewport(0,
|
self.set_main_viewport();
|
||||||
0,
|
|
||||||
self.main_framebuffer_size.width as GLint,
|
|
||||||
self.main_framebuffer_size.height as GLint);
|
|
||||||
|
|
||||||
gl::BindVertexArray(self.mask_tile_vertex_array.gl_vertex_array);
|
gl::BindVertexArray(self.mask_tile_vertex_array.gl_vertex_array);
|
||||||
gl::UseProgram(self.mask_tile_program.program.gl_program);
|
gl::UseProgram(self.mask_tile_program.program.gl_program);
|
||||||
|
@ -244,11 +275,8 @@ impl Renderer {
|
||||||
|
|
||||||
fn draw_solid_tiles(&mut self, solid_tiles: &[SolidTileScenePrimitive]) {
|
fn draw_solid_tiles(&mut self, solid_tiles: &[SolidTileScenePrimitive]) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
self.bind_draw_framebuffer();
|
||||||
gl::Viewport(0,
|
self.set_main_viewport();
|
||||||
0,
|
|
||||||
self.main_framebuffer_size.width as GLint,
|
|
||||||
self.main_framebuffer_size.height as GLint);
|
|
||||||
|
|
||||||
gl::BindVertexArray(self.solid_tile_vertex_array.gl_vertex_array);
|
gl::BindVertexArray(self.solid_tile_vertex_array.gl_vertex_array);
|
||||||
gl::UseProgram(self.solid_tile_program.program.gl_program);
|
gl::UseProgram(self.solid_tile_program.program.gl_program);
|
||||||
|
@ -269,6 +297,100 @@ impl Renderer {
|
||||||
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, solid_tiles.len() as GLint);
|
gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, solid_tiles.len() as GLint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn postprocess(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
|
self.set_main_viewport();
|
||||||
|
|
||||||
|
gl::BindVertexArray(self.postprocess_vertex_array.gl_vertex_array);
|
||||||
|
gl::UseProgram(self.postprocess_program.program.gl_program);
|
||||||
|
gl::Uniform2f(self.postprocess_program.framebuffer_size_uniform.location,
|
||||||
|
self.main_framebuffer_size.width as GLfloat,
|
||||||
|
self.main_framebuffer_size.height as GLfloat);
|
||||||
|
match self.postprocess_options.defringing_kernel {
|
||||||
|
Some(ref kernel) => {
|
||||||
|
debug_assert!(kernel.0.len() == 4);
|
||||||
|
let data: *const f32 = kernel.0.as_ptr();
|
||||||
|
gl::Uniform4fv(self.postprocess_program.kernel_uniform.location, 1, data);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
gl::Uniform4f(self.postprocess_program.kernel_uniform.location,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.postprocess_source_framebuffer.as_ref().unwrap().texture.bind(0);
|
||||||
|
gl::Uniform1i(self.postprocess_program.source_uniform.location, 0);
|
||||||
|
self.gamma_lut_texture.bind(1);
|
||||||
|
gl::Uniform1i(self.postprocess_program.gamma_lut_uniform.location, 1);
|
||||||
|
let gamma_correction_bg_color_uniform_location =
|
||||||
|
self.postprocess_program.gamma_correction_bg_color_uniform.location;
|
||||||
|
match self.postprocess_options.gamma_correction_bg_color {
|
||||||
|
None => {
|
||||||
|
gl::Uniform4f(gamma_correction_bg_color_uniform_location, 0.0, 0.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
Some(color) => {
|
||||||
|
gl::Uniform4f(gamma_correction_bg_color_uniform_location,
|
||||||
|
color.r as f32 / 255.0,
|
||||||
|
color.g as f32 / 255.0,
|
||||||
|
color.b as f32 / 255.0,
|
||||||
|
color.a as f32 / 255.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gl::Disable(gl::BLEND);
|
||||||
|
gl::DrawArrays(gl::TRIANGLE_FAN, 0, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_draw_framebuffer(&self) {
|
||||||
|
unsafe {
|
||||||
|
if self.postprocessing_needed() {
|
||||||
|
let fbo = self.postprocess_source_framebuffer.as_ref().unwrap().gl_framebuffer;
|
||||||
|
gl::BindFramebuffer(gl::FRAMEBUFFER, fbo);
|
||||||
|
} else {
|
||||||
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_main_viewport(&self) {
|
||||||
|
unsafe {
|
||||||
|
gl::Viewport(0,
|
||||||
|
0,
|
||||||
|
self.main_framebuffer_size.width as GLint,
|
||||||
|
self.main_framebuffer_size.height as GLint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_postprocessing_framebuffer(&mut self) {
|
||||||
|
if !self.postprocessing_needed() {
|
||||||
|
self.postprocess_source_framebuffer = None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref existing_framebuffer) = self.postprocess_source_framebuffer {
|
||||||
|
if existing_framebuffer.texture.size == self.main_framebuffer_size {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.postprocess_source_framebuffer =
|
||||||
|
Some(Framebuffer::new(Texture::new_rgba(&self.main_framebuffer_size)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn postprocessing_needed(&self) -> bool {
|
||||||
|
self.postprocess_options.defringing_kernel.is_some() ||
|
||||||
|
self.postprocess_options.gamma_correction_bg_color.is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
struct PostprocessOptions {
|
||||||
|
defringing_kernel: Option<DefringingKernel>,
|
||||||
|
gamma_correction_bg_color: Option<ColorU>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FillVertexArray {
|
struct FillVertexArray {
|
||||||
|
@ -481,7 +603,7 @@ struct PostprocessProgram {
|
||||||
framebuffer_size_uniform: Uniform,
|
framebuffer_size_uniform: Uniform,
|
||||||
kernel_uniform: Uniform,
|
kernel_uniform: Uniform,
|
||||||
gamma_lut_uniform: Uniform,
|
gamma_lut_uniform: Uniform,
|
||||||
bg_color_uniform: Uniform,
|
gamma_correction_bg_color_uniform: Uniform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PostprocessProgram {
|
impl PostprocessProgram {
|
||||||
|
@ -491,14 +613,14 @@ impl PostprocessProgram {
|
||||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||||
let kernel_uniform = Uniform::new(&program, "Kernel");
|
let kernel_uniform = Uniform::new(&program, "Kernel");
|
||||||
let gamma_lut_uniform = Uniform::new(&program, "GammaLUT");
|
let gamma_lut_uniform = Uniform::new(&program, "GammaLUT");
|
||||||
let bg_color_uniform = Uniform::new(&program, "BGColor");
|
let gamma_correction_bg_color_uniform = Uniform::new(&program, "GammaCorrectionBGColor");
|
||||||
PostprocessProgram {
|
PostprocessProgram {
|
||||||
program,
|
program,
|
||||||
source_uniform,
|
source_uniform,
|
||||||
framebuffer_size_uniform,
|
framebuffer_size_uniform,
|
||||||
kernel_uniform,
|
kernel_uniform,
|
||||||
gamma_lut_uniform,
|
gamma_lut_uniform,
|
||||||
bg_color_uniform,
|
gamma_correction_bg_color_uniform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
pub mod builder;
|
pub mod builder;
|
||||||
pub mod gpu_data;
|
pub mod gpu_data;
|
||||||
pub mod paint;
|
pub mod paint;
|
||||||
|
pub mod post;
|
||||||
pub mod scene;
|
pub mod scene;
|
||||||
pub mod serialization;
|
pub mod serialization;
|
||||||
pub mod tiles;
|
pub mod tiles;
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
// 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
|
||||||
|
]);
|
||||||
|
|
Loading…
Reference in New Issue