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 <mail@eliasnaur.com>
This commit is contained in:
Elias Naur 2021-03-22 14:12:05 +01:00
parent eb37db1b05
commit 678bfedfca
2 changed files with 35 additions and 5 deletions

View file

@ -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;

View file

@ -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();