From 678bfedfca949b54854f47319de6c6075fec3494 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Mon, 22 Mar 2021 14:12:05 +0100 Subject: [PATCH] kernel4: assume colors in alpha-premultiplied sRGB format See http://ssp.impulsetrain.com/gamma-premult.html for a description of the format. Pre-multiplied alpha only matters for translucent objects; draw a few such shapes in the test render. Signed-off-by: Elias Naur --- piet-gpu/shader/kernel4.comp | 10 ++++++---- piet-gpu/src/lib.rs | 30 +++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index 647d3d8..fc2523e 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -207,17 +207,19 @@ void main() { break; case Cmd_Color: CmdColor color = Cmd_Color_read(cmd_alloc, cmd_ref); - vec4 fg_rgba = unpacksRGB(color.rgba_color); + vec4 fg = unpacksRGB(color.rgba_color); for (uint k = 0; k < CHUNK; k++) { - rgb[k] = mix(rgb[k], fg_rgba.rgb, area[k] * fg_rgba.a); + vec4 fg_k = fg * area[k]; + rgb[k] = rgb[k] * (1.0 - fg_k.a) + fg_k.rgb; } cmd_ref.offset += 4 + CmdColor_size; break; case Cmd_Image: CmdImage fill_img = Cmd_Image_read(cmd_alloc, cmd_ref); - vec4 rgba[CHUNK] = fillImage(xy_uint, fill_img); + vec4 img[CHUNK] = fillImage(xy_uint, fill_img); for (uint k = 0; k < CHUNK; k++) { - rgb[k] = mix(rgb[k], rgba[k].rgb, area[k] * rgba[k].a); + vec4 fg_k = img[k] * area[k]; + rgb[k] = rgb[k] * (1.0 - fg_k.a) + fg_k.rgb; } cmd_ref.offset += 4 + CmdImage_size; break; diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index ac83c7e..3e46eae 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -7,7 +7,7 @@ pub use render_ctx::PietGpuRenderContext; use rand::{Rng, RngCore}; -use piet::kurbo::{BezPath, Circle, Point, Vec2}; +use piet::kurbo::{BezPath, Circle, Point, Shape, Vec2}; use piet::{Color, ImageFormat, RenderContext}; use piet_gpu_types::encoder::Encode; @@ -74,6 +74,7 @@ pub fn render_scene(rc: &mut impl RenderContext) { ); //render_cardioid(rc); render_clip_test(rc); + render_alpha_test(rc); //render_tiger(rc); } @@ -124,6 +125,33 @@ fn render_clip_test(rc: &mut impl RenderContext) { } } +#[allow(unused)] +fn render_alpha_test(rc: &mut impl RenderContext) { + // Alpha compositing tests. kernel4 expects colors encoded in alpha-premultiplied sRGB: + // + // [α,sRGB(α⋅R),sRGB(α⋅G),sRGB(α⋅B)] + // + // See also http://ssp.impulsetrain.com/gamma-premult.html. + rc.fill(diamond(Point::new(1024.0, 100.0)), &Color::Rgba32(0xff0000ff)); + rc.fill(diamond(Point::new(1024.0, 125.0)), &Color::Rgba32(0x00ba0080)); + rc.save(); + rc.clip(diamond(Point::new(1024.0, 150.0))); + rc.fill(diamond(Point::new(1024.0, 175.0)), &Color::Rgba32(0x0000ba80)); + rc.restore(); +} + +fn diamond(origin: Point) -> impl Shape { + let mut path = BezPath::new(); + const SIZE: f64 = 50.0; + path.move_to((origin.x, origin.y - SIZE)); + path.line_to((origin.x + SIZE, origin.y)); + path.line_to((origin.x, origin.y + SIZE)); + path.line_to((origin.x - SIZE, origin.y)); + path.close_path(); + return path; +} + +#[allow(unused)] fn render_tiger(rc: &mut impl RenderContext) { let xml_str = std::str::from_utf8(include_bytes!("../Ghostscript_Tiger.svg")).unwrap(); let start = std::time::Instant::now();