diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 9d97088f..6e62905d 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -116,7 +116,7 @@ impl DemoApp where W: Window { let resources = window.resource_loader(); let options = Options::get(); - let view_box_size = view_box_size(options.mode, &window_size, false); + let view_box_size = view_box_size(options.mode, &window_size); let built_svg = load_scene(resources, &options.input_path); let message = get_svg_building_message(&built_svg); @@ -199,9 +199,7 @@ impl DemoApp where W: Window { } fn build_scene(&mut self) { - let view_box_size = view_box_size(self.ui.mode, - &self.window_size, - self.ui.subpixel_aa_effect_enabled); + let view_box_size = view_box_size(self.ui.mode, &self.window_size); let render_transform = match self.camera { Camera::ThreeD { ref mut transform, ref mut velocity } => { @@ -232,6 +230,7 @@ impl DemoApp where W: Window { } else { None }, + subpixel_aa_enabled: self.ui.subpixel_aa_effect_enabled, barrel_distortion, })).unwrap(); } @@ -254,9 +253,7 @@ impl DemoApp where W: Window { } Event::WindowResized(new_size) => { self.window_size = new_size; - let view_box_size = view_box_size(self.ui.mode, - &self.window_size, - self.ui.subpixel_aa_effect_enabled); + let view_box_size = view_box_size(self.ui.mode, &self.window_size); self.scene_thread_proxy.set_drawable_size(view_box_size); self.renderer.set_main_framebuffer_size(self.window_size.device_size()); self.dirty = true; @@ -343,9 +340,7 @@ impl DemoApp where W: Window { let built_svg = load_scene(self.window.resource_loader(), svg_path); self.ui.message = get_svg_building_message(&built_svg); - let view_box_size = view_box_size(self.ui.mode, - &self.window_size, - self.ui.subpixel_aa_effect_enabled); + let view_box_size = view_box_size(self.ui.mode, &self.window_size); self.scene_view_box = built_svg.scene.view_box; self.monochrome_scene_color = built_svg.scene.monochrome_color(); @@ -539,24 +534,20 @@ impl DemoApp where W: Window { let render_msg = &self.current_frame.as_ref().unwrap().render_msg; let built_scene = &render_msg.render_scenes[viewport_index as usize].built_scene; - let view_box_size = view_box_size(self.ui.mode, - &self.window_size, - self.ui.subpixel_aa_effect_enabled); + let view_box_size = view_box_size(self.ui.mode, &self.window_size); let viewport_origin_x = viewport_index as i32 * view_box_size.x(); let viewport = RectI32::new(Point2DI32::new(viewport_origin_x, 0), view_box_size); self.renderer.set_viewport(viewport); match self.monochrome_scene_color { None => self.renderer.set_render_mode(RenderMode::Multicolor), - Some(fill_color) => { + Some(fg_color) => { self.renderer.set_render_mode(RenderMode::Monochrome { - fill_color: fill_color.to_f32(), - gamma_correction_bg_color: if self.ui.gamma_correction_effect_enabled { - Some(self.background_color()) - } else { - None - }, + fg_color: fg_color.to_f32(), + bg_color: self.background_color().to_f32(), + gamma_correction: self.ui.gamma_correction_effect_enabled, defringing_kernel: if self.ui.subpixel_aa_effect_enabled { + // TODO(pcwalton): Select FreeType defringing kernel as necessary. Some(DEFRINGING_KERNEL_CORE_GRAPHICS) } else { None @@ -709,6 +700,7 @@ struct BuildOptions { render_transforms: Vec, stem_darkening_font_size: Option, barrel_distortion: Option, + subpixel_aa_enabled: bool, } struct SceneToMainMsg { @@ -810,8 +802,6 @@ fn build_scene(scene: &Scene, render_transform: RenderTransform, jobs: Option) -> BuiltScene { - let z_buffer = ZBuffer::new(scene.view_box); - let render_options = RenderOptions { transform: render_transform, dilation: match build_options.stem_darkening_font_size { @@ -822,9 +812,13 @@ fn build_scene(scene: &Scene, } }, barrel_distortion: build_options.barrel_distortion, + subpixel_aa_enabled: build_options.subpixel_aa_enabled, }; let built_options = render_options.prepare(scene.bounds); + let effective_view_box = scene.effective_view_box(&built_options); + let z_buffer = ZBuffer::new(effective_view_box); + let quad = built_options.quad(); let built_objects = panic::catch_unwind(|| { @@ -846,7 +840,7 @@ fn build_scene(scene: &Scene, let mut built_scene = BuiltScene::new(scene.view_box, &quad, scene.objects.len() as u32); built_scene.shaders = scene.build_shaders(); - let mut scene_builder = SceneBuilder::new(built_objects, z_buffer, scene.view_box); + let mut scene_builder = SceneBuilder::new(built_objects, z_buffer, effective_view_box); built_scene.solid_tiles = scene_builder.build_solid_tiles(); while let Some(batch) = scene_builder.build_batch() { built_scene.batches.push(batch); @@ -966,13 +960,12 @@ fn emit_message(ui: &mut DemoUI, }); } -fn view_box_size(mode: Mode, window_size: &WindowSize, use_subpixel_aa: bool) -> Point2DI32 { +fn view_box_size(mode: Mode, window_size: &WindowSize) -> Point2DI32 { let window_drawable_size = window_size.device_size(); - let initial_size = match mode { + match mode { Mode::TwoD | Mode::ThreeD => window_drawable_size, Mode::VR => Point2DI32::new(window_drawable_size.x() / 2, window_drawable_size.y()), - }; - if use_subpixel_aa { initial_size.scale_xy(Point2DI32::new(3, 1)) } else { initial_size } + } } struct Frame { diff --git a/gl/src/lib.rs b/gl/src/lib.rs index 26197fe8..e92a52d5 100644 --- a/gl/src/lib.rs +++ b/gl/src/lib.rs @@ -364,6 +364,9 @@ impl Device for GLDevice { fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData) { unsafe { match data { + UniformData::Int(value) => { + gl::Uniform1i(uniform.location, value); ck(); + } UniformData::Mat4(data) => { assert_eq!(mem::size_of::<[F32x4; 4]>(), 4 * 4 * 4); let data_ptr: *const F32x4 = data.as_ptr(); diff --git a/gpu/src/lib.rs b/gpu/src/lib.rs index a31aa4bb..ada94cdc 100644 --- a/gpu/src/lib.rs +++ b/gpu/src/lib.rs @@ -191,6 +191,7 @@ pub enum ShaderKind { #[derive(Clone, Copy)] pub enum UniformData { + Int(i32), Mat4([F32x4; 4]), Vec2(F32x4), Vec4(F32x4), diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index d5fbd1dc..8ea876b3 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -128,6 +128,7 @@ pub struct RenderOptions { pub transform: RenderTransform, pub dilation: Point2DF32, pub barrel_distortion: Option, + pub subpixel_aa_enabled: bool, } impl RenderOptions { @@ -136,6 +137,7 @@ impl RenderOptions { transform: self.transform.prepare(bounds), dilation: self.dilation, barrel_distortion: self.barrel_distortion, + subpixel_aa_enabled: self.subpixel_aa_enabled, } } } @@ -205,6 +207,7 @@ pub struct PreparedRenderOptions { pub transform: PreparedRenderTransform, pub dilation: Point2DF32, pub barrel_distortion: Option, + pub subpixel_aa_enabled: bool, } impl PreparedRenderOptions { @@ -222,3 +225,13 @@ pub enum PreparedRenderTransform { Transform2D(Transform2DF32), Perspective { perspective: Perspective, clip_polygon: Vec, quad: [Point3DF32; 4] } } + +impl PreparedRenderTransform { + #[inline] + pub fn is_2d(&self) -> bool { + match *self { + PreparedRenderTransform::Transform2D(_) => true, + _ => false, + } + } +} diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index ec0a9bef..d07a1f97 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -15,7 +15,7 @@ use crate::scene::ObjectShader; use crate::tiles::{TILE_HEIGHT, TILE_WIDTH}; use pathfinder_geometry::basic::point::{Point2DI32, Point3DF32}; use pathfinder_geometry::basic::rect::RectI32; -use pathfinder_geometry::color::{ColorF, ColorU}; +use pathfinder_geometry::color::ColorF; use pathfinder_gpu::resources::ResourceLoader; use pathfinder_gpu::{BlendState, BufferTarget, BufferUploadMode, DepthFunc, DepthState, Device}; use pathfinder_gpu::{Primitive, RenderState, StencilFunc, StencilState, TextureFormat}; @@ -321,7 +321,7 @@ impl Renderer where D: Device { self.device.bind_vertex_array(&alpha_tile_vertex_array.vertex_array); self.device.use_program(&alpha_tile_program.program); self.device.set_uniform(&alpha_tile_program.framebuffer_size_uniform, - UniformData::Vec2(self.viewport.size().to_f32().0)); + UniformData::Vec2(self.draw_viewport().size().to_f32().0)); self.device.set_uniform(&alpha_tile_program.tile_size_uniform, UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, TILE_HEIGHT as i32, @@ -349,9 +349,13 @@ impl Renderer where D: Device { 0, 0).to_f32x4())); } - RenderMode::Monochrome { fill_color, .. } => { + RenderMode::Monochrome { .. } if self.postprocessing_needed() => { self.device.set_uniform(&self.alpha_monochrome_tile_program.fill_color_uniform, - UniformData::Vec4(fill_color.0)); + UniformData::Vec4(F32x4::splat(1.0))); + } + RenderMode::Monochrome { fg_color, .. } => { + self.device.set_uniform(&self.alpha_monochrome_tile_program.fill_color_uniform, + UniformData::Vec4(fg_color.0)); } } @@ -370,13 +374,15 @@ impl Renderer where D: Device { } fn draw_solid_tiles(&mut self, built_scene: &BuiltScene) { + self.bind_draw_framebuffer(); + let solid_tile_vertex_array = self.solid_tile_vertex_array(); let solid_tile_program = self.solid_tile_program(); self.device.bind_vertex_array(&solid_tile_vertex_array.vertex_array); self.device.use_program(&solid_tile_program.program); self.device.set_uniform(&solid_tile_program.framebuffer_size_uniform, - UniformData::Vec2(self.viewport.size().0.to_f32x4())); + UniformData::Vec2(self.draw_viewport().size().0.to_f32x4())); self.device.set_uniform(&solid_tile_program.tile_size_uniform, UniformData::Vec2(I32x4::new(TILE_WIDTH as i32, TILE_HEIGHT as i32, @@ -396,9 +402,13 @@ impl Renderer where D: Device { 0, 0).to_f32x4())); } - RenderMode::Monochrome { fill_color, .. } => { + RenderMode::Monochrome { .. } if self.postprocessing_needed() => { self.device.set_uniform(&self.solid_monochrome_tile_program.fill_color_uniform, - UniformData::Vec4(fill_color.0)); + UniformData::Vec4(F32x4::splat(1.0))); + } + RenderMode::Monochrome { fg_color, .. } => { + self.device.set_uniform(&self.solid_monochrome_tile_program.fill_color_uniform, + UniformData::Vec4(fg_color.0)); } } @@ -414,17 +424,19 @@ impl Renderer where D: Device { } fn postprocess(&mut self) { - let (fill_color, defringing_kernel, gamma_correction_bg_color); + let (fg_color, bg_color, defringing_kernel, gamma_correction_enabled); match self.render_mode { RenderMode::Multicolor => return, RenderMode::Monochrome { - fill_color: fc, - defringing_kernel: dk, - gamma_correction_bg_color: gcbc, + fg_color: fg, + bg_color: bg, + defringing_kernel: kernel, + gamma_correction, } => { - fill_color = fc; - defringing_kernel = dk; - gamma_correction_bg_color = gcbc; + fg_color = fg; + bg_color = bg; + defringing_kernel = kernel; + gamma_correction_enabled = gamma_correction; } } @@ -456,22 +468,13 @@ impl Renderer where D: Device { self.device.bind_texture(&self.gamma_lut_texture, 1); self.device.set_uniform(&self.postprocess_program.gamma_lut_uniform, UniformData::TextureUnit(1)); - let gamma_correction_bg_color_uniform = &self.postprocess_program - .gamma_correction_bg_color_uniform; - match gamma_correction_bg_color { - None => { - self.device.set_uniform(gamma_correction_bg_color_uniform, - UniformData::Vec4(F32x4::default())); - } - Some(color) => { - self.device.set_uniform(gamma_correction_bg_color_uniform, - UniformData::Vec4(color.to_f32().0)); - } - } - self.device.draw_arrays(Primitive::TriangleFan, 4, &RenderState { - blend: BlendState::RGBOneAlphaOne, - ..RenderState::default() - }); + self.device.set_uniform(&self.postprocess_program.fg_color_uniform, + UniformData::Vec4(fg_color.0)); + self.device.set_uniform(&self.postprocess_program.bg_color_uniform, + UniformData::Vec4(bg_color.0)); + self.device.set_uniform(&self.postprocess_program.gamma_correction_enabled_uniform, + UniformData::Int(gamma_correction_enabled as i32)); + self.device.draw_arrays(Primitive::TriangleFan, 4, &RenderState::default()); } fn solid_tile_program(&self) -> &SolidTileProgram { @@ -543,12 +546,14 @@ impl Renderer where D: Device { return; } + let source_framebuffer_size = self.draw_viewport().size(); match self.postprocess_source_framebuffer { Some(ref framebuffer) if self.device.texture_size(self.device.framebuffer_texture(framebuffer)) == - self.viewport.size() => {} + source_framebuffer_size => {} _ => { - let texture = self.device.create_texture(TextureFormat::R8, self.viewport.size()); + let texture = self.device.create_texture(TextureFormat::R8, + source_framebuffer_size); self.postprocess_source_framebuffer = Some(self.device.create_framebuffer(texture)) } }; @@ -559,8 +564,8 @@ impl Renderer where D: Device { fn postprocessing_needed(&self) -> bool { match self.render_mode { - RenderMode::Monochrome { ref defringing_kernel, gamma_correction_bg_color, .. } => { - defringing_kernel.is_some() || gamma_correction_bg_color.is_some() + RenderMode::Monochrome { ref defringing_kernel, gamma_correction, .. } => { + defringing_kernel.is_some() || gamma_correction } _ => false, } @@ -573,6 +578,16 @@ impl Renderer where D: Device { Some(StencilState { func: StencilFunc::Equal, reference: 1, mask: 1, write: false }) } + + fn draw_viewport(&self) -> RectI32 { + match self.render_mode { + RenderMode::Monochrome { defringing_kernel: Some(..), .. } => { + RectI32::new(Point2DI32::default(), + self.viewport.size().scale_xy(Point2DI32::new(3, 1))) + } + _ => self.viewport + } + } } struct FillVertexArray where D: Device { @@ -717,26 +732,26 @@ impl SolidTileVertexArray where D: Device { device.use_program(&solid_tile_program.program); device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex); device.configure_float_vertex_attr(&tess_coord_attr, - 2, - VertexAttrType::U8, - false, - 0, - 0, - 0); + 2, + VertexAttrType::U8, + false, + 0, + 0, + 0); device.bind_buffer(&vertex_buffer, BufferTarget::Vertex); device.configure_float_vertex_attr(&tile_origin_attr, - 2, - VertexAttrType::I16, - false, - SOLID_TILE_INSTANCE_SIZE, - 0, - 1); + 2, + VertexAttrType::I16, + false, + SOLID_TILE_INSTANCE_SIZE, + 0, + 1); device.configure_int_vertex_attr(&object_attr, - 1, - VertexAttrType::I16, - SOLID_TILE_INSTANCE_SIZE, - 4, - 1); + 1, + VertexAttrType::I16, + SOLID_TILE_INSTANCE_SIZE, + 4, + 1); SolidTileVertexArray { vertex_array, vertex_buffer } } @@ -824,8 +839,6 @@ struct AlphaTileProgram where D: Device { tile_size_uniform: D::Uniform, stencil_texture_uniform: D::Uniform, stencil_texture_size_uniform: D::Uniform, - fill_colors_texture_uniform: D::Uniform, - fill_colors_texture_size_uniform: D::Uniform, view_box_origin_uniform: D::Uniform, } @@ -839,9 +852,6 @@ impl AlphaTileProgram where D: Device { let tile_size_uniform = device.get_uniform(&program, "TileSize"); let stencil_texture_uniform = device.get_uniform(&program, "StencilTexture"); let stencil_texture_size_uniform = device.get_uniform(&program, "StencilTextureSize"); - let fill_colors_texture_uniform = device.get_uniform(&program, "FillColorsTexture"); - let fill_colors_texture_size_uniform = device.get_uniform(&program, - "FillColorsTextureSize"); let view_box_origin_uniform = device.get_uniform(&program, "ViewBoxOrigin"); AlphaTileProgram { program, @@ -849,8 +859,6 @@ impl AlphaTileProgram where D: Device { tile_size_uniform, stencil_texture_uniform, stencil_texture_size_uniform, - fill_colors_texture_uniform, - fill_colors_texture_size_uniform, view_box_origin_uniform, } } @@ -897,7 +905,9 @@ struct PostprocessProgram where D: Device { framebuffer_size_uniform: D::Uniform, kernel_uniform: D::Uniform, gamma_lut_uniform: D::Uniform, - gamma_correction_bg_color_uniform: D::Uniform, + gamma_correction_enabled_uniform: D::Uniform, + fg_color_uniform: D::Uniform, + bg_color_uniform: D::Uniform, } impl PostprocessProgram where D: Device { @@ -908,8 +918,10 @@ impl PostprocessProgram where D: Device { 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_bg_color_uniform = device.get_uniform(&program, - "GammaCorrectionBGColor"); + 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 { program, source_uniform, @@ -917,7 +929,9 @@ impl PostprocessProgram where D: Device { framebuffer_size_uniform, kernel_uniform, gamma_lut_uniform, - gamma_correction_bg_color_uniform, + gamma_correction_enabled_uniform, + fg_color_uniform, + bg_color_uniform, } } } @@ -990,9 +1004,10 @@ impl StencilVertexArray where D: Device { pub enum RenderMode { Multicolor, Monochrome { - fill_color: ColorF, + fg_color: ColorF, + bg_color: ColorF, defringing_kernel: Option, - gamma_correction_bg_color: Option, + gamma_correction: bool, }, } diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index be5422a9..7c875ad5 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -15,7 +15,9 @@ use crate::gpu_data::BuiltObject; use crate::tiles::Tiler; use crate::z_buffer::ZBuffer; use hashbrown::HashMap; +use pathfinder_geometry::basic::point::Point2DF32; use pathfinder_geometry::basic::rect::{RectF32, RectI32}; +use pathfinder_geometry::basic::transform2d::Transform2DF32; use pathfinder_geometry::color::ColorU; use pathfinder_geometry::outline::Outline; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; @@ -74,7 +76,7 @@ impl Scene { let outline = self.apply_render_options(&object.outline, &built_options); let mut tiler = Tiler::new( &outline, - self.view_box, + self.effective_view_box(&built_options), object_index as u16, ShaderId(object.paint.0), z_buffer, @@ -94,7 +96,7 @@ impl Scene { let outline = self.apply_render_options(&object.outline, &built_options); let mut tiler = Tiler::new( &outline, - self.view_box, + self.effective_view_box(&built_options), object_index as u16, ShaderId(object.paint.0), z_buffer, @@ -107,6 +109,8 @@ impl Scene { fn apply_render_options(&self, original_outline: &Outline, options: &PreparedRenderOptions) -> Outline { + let effective_view_box = self.effective_view_box(options); + let mut outline; match options.transform { PreparedRenderTransform::Perspective { ref perspective, ref clip_polygon, .. } => { @@ -121,17 +125,26 @@ impl Scene { if let Some(barrel_distortion) = options.barrel_distortion { outline.barrel_distort(barrel_distortion, perspective.window_size); } + + // TODO(pcwalton): Support subpixel AA in 3D. } } - PreparedRenderTransform::Transform2D(ref transform) => { + _ => { // TODO(pcwalton): Short circuit. outline = (*original_outline).clone(); - outline.transform(transform); - outline.clip_against_rect(self.view_box); - } - PreparedRenderTransform::None => { - outline = (*original_outline).clone(); - outline.clip_against_rect(self.view_box); + if options.transform.is_2d() || options.subpixel_aa_enabled { + let mut transform = match options.transform { + PreparedRenderTransform::Transform2D(transform) => transform, + PreparedRenderTransform::None => Transform2DF32::default(), + PreparedRenderTransform::Perspective { .. } => unreachable!(), + }; + if options.subpixel_aa_enabled { + transform = transform.post_mul(&Transform2DF32::from_scale( + &Point2DF32::new(3.0, 1.0))) + } + outline.transform(&transform); + } + outline.clip_against_rect(effective_view_box); } } @@ -141,7 +154,7 @@ impl Scene { // TODO(pcwalton): Fold this into previous passes to avoid unnecessary clones during // monotonic conversion. - outline.prepare_for_tiling(self.view_box); + outline.prepare_for_tiling(self.effective_view_box(options)); outline } @@ -155,6 +168,15 @@ impl Scene { } Some(self.paints[first_paint_id.0 as usize].color) } + + #[inline] + pub fn effective_view_box(&self, render_options: &PreparedRenderOptions) -> RectF32 { + if render_options.subpixel_aa_enabled { + self.view_box.scale_xy(Point2DF32::new(3.0, 1.0)) + } else { + self.view_box + } + } } impl Debug for Scene { diff --git a/resources/shaders/post.fs.glsl b/resources/shaders/post.fs.glsl index 364b6f2c..70597c79 100644 --- a/resources/shaders/post.fs.glsl +++ b/resources/shaders/post.fs.glsl @@ -17,6 +17,9 @@ precision highp float; uniform sampler2D uSource; uniform vec2 uSourceSize; +uniform vec4 uFGColor; +uniform vec4 uBGColor; +uniform int uGammaCorrectionEnabled; in vec2 vTexCoord; @@ -32,9 +35,9 @@ float sample1Tap(float offset) { void main() { // Apply defringing if necessary. - vec4 fgColor; + vec3 alpha; if (uKernel.w == 0.0) { - fgColor = texture(uSource, vTexCoord); + alpha = texture(uSource, vTexCoord).rrr; } else { vec4 alphaLeft, alphaRight; float alphaCenter; @@ -44,13 +47,13 @@ void main() { float g = convolve7Tap(vec4(alphaLeft.yzw, alphaCenter), alphaRight.xyz); float b = convolve7Tap(vec4(alphaLeft.zw, alphaCenter, alphaRight.x), alphaRight.yzw); - fgColor = vec4(r); + alpha = vec3(r, g, b); } // Apply gamma correction if necessary. - /*if (uGammaCorrectionBGColor.a > 0.0) - fgColor.rgb = gammaCorrect(fgColor.rgb);*/ + if (uGammaCorrectionEnabled != 0) + alpha = gammaCorrect(uBGColor.rgb, alpha); // Finish. - oFragColor = fgColor; + oFragColor = vec4(mix(uBGColor.rgb, uFGColor.rgb, alpha), 1.0); } diff --git a/resources/shaders/post_gamma_correct.inc.glsl b/resources/shaders/post_gamma_correct.inc.glsl index df25d250..85c3d803 100644 --- a/resources/shaders/post_gamma_correct.inc.glsl +++ b/resources/shaders/post_gamma_correct.inc.glsl @@ -12,17 +12,13 @@ // expects. uniform sampler2D uGammaLUT; -// The background color to blend against. Zero if no gamma correction is to be -// performed. -uniform vec4 uGammaCorrectionBGColor; - -float gammaCorrectChannel(float fgColor) { - return texture(uGammaLUT, vec2(fgColor, 1.0 - uGammaCorrectionBGColor)).r; +float gammaCorrectChannel(float bgColor, float fgColor) { + return texture(uGammaLUT, vec2(fgColor, 1.0 - bgColor)).r; } // `fgColor` is in linear space. -vec3 gammaCorrect(vec3 fgColor) { - return vec3(gammaCorrectChannel(fgColor.r), - gammaCorrectChannel(fgColor.g), - gammaCorrectChannel(fgColor.b)); +vec3 gammaCorrect(vec3 bgColor, vec3 fgColor) { + return vec3(gammaCorrectChannel(bgColor.r, fgColor.r), + gammaCorrectChannel(bgColor.g, fgColor.g), + gammaCorrectChannel(bgColor.b, fgColor.b)); }