mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 12:41:30 +11:00
Merge branch 'master' into android2
This commit is contained in:
commit
e1aced9c5a
|
@ -41,7 +41,7 @@ fn main() -> Result<(), Error> {
|
|||
render_scene(&mut ctx);
|
||||
let n_paths = ctx.path_count();
|
||||
let n_pathseg = ctx.pathseg_count();
|
||||
let n_trans = ctx.pathseg_count();
|
||||
let n_trans = ctx.trans_count();
|
||||
let scene = ctx.get_scene_buf();
|
||||
|
||||
let renderer = Renderer::new(&session, scene, n_paths, n_pathseg, n_trans)?;
|
||||
|
|
|
@ -48,13 +48,13 @@ void main() {
|
|||
if (element_ix < conf.n_elements) {
|
||||
AnnotatedTag tag = Annotated_tag(conf.anno_alloc, ref);
|
||||
switch (tag.tag) {
|
||||
case Annotated_Image:
|
||||
case Annotated_BeginClip:
|
||||
case Annotated_Color:
|
||||
if (fill_mode_from_flags(tag.flags) != MODE_NONZERO) {
|
||||
break;
|
||||
}
|
||||
// Fall through.
|
||||
case Annotated_Image:
|
||||
case Annotated_BeginClip:
|
||||
PathRef path_ref = PathRef(conf.tile_alloc.offset + element_ix * Path_size);
|
||||
Path path = Path_read(conf.tile_alloc, path_ref);
|
||||
sh_row_width[th_ix] = path.bbox.z - path.bbox.x;
|
||||
|
|
Binary file not shown.
|
@ -91,6 +91,23 @@ bool alloc_cmd(inout Alloc cmd_alloc, inout CmdRef cmd_ref, inout uint cmd_limit
|
|||
return true;
|
||||
}
|
||||
|
||||
void write_fill(Alloc alloc, inout CmdRef cmd_ref, uint flags, Tile tile, float linewidth) {
|
||||
if (fill_mode_from_flags(flags) == MODE_NONZERO) {
|
||||
if (tile.tile.offset != 0) {
|
||||
CmdFill cmd_fill = CmdFill(tile.tile.offset, tile.backdrop);
|
||||
Cmd_Fill_write(alloc, cmd_ref, cmd_fill);
|
||||
cmd_ref.offset += 4 + CmdFill_size;
|
||||
} else {
|
||||
Cmd_Solid_write(alloc, cmd_ref);
|
||||
cmd_ref.offset += 4;
|
||||
}
|
||||
} else {
|
||||
CmdStroke cmd_stroke = CmdStroke(tile.tile.offset, 0.5 * linewidth);
|
||||
Cmd_Stroke_write(alloc, cmd_ref, cmd_stroke);
|
||||
cmd_ref.offset += 4 + CmdStroke_size;
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
if (mem_error != NO_ERROR) {
|
||||
return;
|
||||
|
@ -135,6 +152,12 @@ void main() {
|
|||
uint part_start_ix = 0;
|
||||
uint ready_ix = 0;
|
||||
|
||||
// Leave room for the fine rasterizer scratch allocation.
|
||||
Alloc scratch_alloc = slice_mem(cmd_alloc, 0, Alloc_size);
|
||||
cmd_ref.offset += Alloc_size;
|
||||
|
||||
uint num_begin_slots = 0;
|
||||
uint begin_slot = 0;
|
||||
while (true) {
|
||||
for (uint i = 0; i < N_SLICE; i++) {
|
||||
sh_bitmaps[i][th_ix] = 0;
|
||||
|
@ -320,20 +343,7 @@ void main() {
|
|||
if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) {
|
||||
break;
|
||||
}
|
||||
if (fill_mode_from_flags(tag.flags) == MODE_NONZERO) {
|
||||
if (tile.tile.offset != 0) {
|
||||
CmdFill cmd_fill = CmdFill(tile.tile.offset, tile.backdrop);
|
||||
Cmd_Fill_write(cmd_alloc, cmd_ref, cmd_fill);
|
||||
cmd_ref.offset += 4 + CmdFill_size;
|
||||
} else {
|
||||
Cmd_Solid_write(cmd_alloc, cmd_ref);
|
||||
cmd_ref.offset += 4;
|
||||
}
|
||||
} else {
|
||||
CmdStroke cmd_stroke = CmdStroke(tile.tile.offset, 0.5 * fill.linewidth);
|
||||
Cmd_Stroke_write(cmd_alloc, cmd_ref, cmd_stroke);
|
||||
cmd_ref.offset += 4 + CmdStroke_size;
|
||||
}
|
||||
write_fill(cmd_alloc, cmd_ref, tag.flags, tile, fill.linewidth);
|
||||
Cmd_Color_write(cmd_alloc, cmd_ref, CmdColor(fill.rgba_color));
|
||||
cmd_ref.offset += 4 + CmdColor_size;
|
||||
break;
|
||||
|
@ -344,20 +354,7 @@ void main() {
|
|||
if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) {
|
||||
break;
|
||||
}
|
||||
if (fill_mode_from_flags(tag.flags) == MODE_NONZERO) {
|
||||
if (tile.tile.offset != 0) {
|
||||
CmdFill cmd_fill = CmdFill(tile.tile.offset, tile.backdrop);
|
||||
Cmd_Fill_write(cmd_alloc, cmd_ref, cmd_fill);
|
||||
cmd_ref.offset += 4 + CmdFill_size;
|
||||
} else {
|
||||
Cmd_Solid_write(cmd_alloc, cmd_ref);
|
||||
cmd_ref.offset += 4;
|
||||
}
|
||||
} else {
|
||||
CmdStroke cmd_stroke = CmdStroke(tile.tile.offset, 0.5 * fill_img.linewidth);
|
||||
Cmd_Stroke_write(cmd_alloc, cmd_ref, cmd_stroke);
|
||||
cmd_ref.offset += 4 + CmdStroke_size;
|
||||
}
|
||||
write_fill(cmd_alloc, cmd_ref, tag.flags, tile, fill_img.linewidth);
|
||||
Cmd_Image_write(cmd_alloc, cmd_ref, CmdImage(fill_img.index, fill_img.offset));
|
||||
cmd_ref.offset += 4 + CmdImage_size;
|
||||
break;
|
||||
|
@ -373,27 +370,14 @@ void main() {
|
|||
if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) {
|
||||
break;
|
||||
}
|
||||
if (fill_mode_from_flags(tag.flags) == MODE_NONZERO) {
|
||||
if (tile.tile.offset != 0) {
|
||||
CmdFill cmd_fill = CmdFill(tile.tile.offset, tile.backdrop);
|
||||
Cmd_Fill_write(cmd_alloc, cmd_ref, cmd_fill);
|
||||
cmd_ref.offset += 4 + CmdFill_size;
|
||||
} else {
|
||||
// TODO: here is where a bunch of optimization magic should happen
|
||||
float alpha = tile.backdrop == 0 ? 0.0 : 1.0;
|
||||
Cmd_Alpha_write(cmd_alloc, cmd_ref, CmdAlpha(alpha));
|
||||
cmd_ref.offset += 4 + CmdAlpha_size;
|
||||
}
|
||||
} else {
|
||||
CmdStroke cmd_stroke = CmdStroke(tile.tile.offset, 0.5 * begin_clip.linewidth);
|
||||
Cmd_Stroke_write(cmd_alloc, cmd_ref, cmd_stroke);
|
||||
cmd_ref.offset += 4 + CmdStroke_size;
|
||||
}
|
||||
write_fill(cmd_alloc, cmd_ref, tag.flags, tile, begin_clip.linewidth);
|
||||
Cmd_BeginClip_write(cmd_alloc, cmd_ref);
|
||||
cmd_ref.offset += 4;
|
||||
if (clip_depth < 32) {
|
||||
clip_one_mask &= ~(1 << clip_depth);
|
||||
}
|
||||
begin_slot++;
|
||||
num_begin_slots = max(num_begin_slots, begin_slot);
|
||||
}
|
||||
clip_depth++;
|
||||
break;
|
||||
|
@ -405,6 +389,7 @@ void main() {
|
|||
}
|
||||
Cmd_Solid_write(cmd_alloc, cmd_ref);
|
||||
cmd_ref.offset += 4;
|
||||
begin_slot--;
|
||||
Cmd_EndClip_write(cmd_alloc, cmd_ref);
|
||||
cmd_ref.offset += 4;
|
||||
}
|
||||
|
@ -432,5 +417,13 @@ void main() {
|
|||
}
|
||||
if (bin_tile_x + tile_x < conf.width_in_tiles && bin_tile_y + tile_y < conf.height_in_tiles) {
|
||||
Cmd_End_write(cmd_alloc, cmd_ref);
|
||||
if (num_begin_slots > 0) {
|
||||
// Write scratch allocation: one state per BeginClip per rasterizer chunk.
|
||||
uint scratch_size = num_begin_slots * TILE_WIDTH_PX * TILE_HEIGHT_PX * CLIP_STATE_SIZE * 4;
|
||||
MallocResult scratch = malloc(scratch_size);
|
||||
// Ignore scratch.failed; we don't use the allocation and kernel4
|
||||
// checks for memory overflow before using it.
|
||||
alloc_write(scratch_alloc, scratch_alloc.offset, scratch.alloc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -386,10 +386,10 @@ void main() {
|
|||
case Element_BeginClip:
|
||||
Clip begin_clip = Element_BeginClip_read(this_ref);
|
||||
AnnoBeginClip anno_begin_clip;
|
||||
// This is the absolute bbox, it's been transformed during encoding.
|
||||
anno_begin_clip.bbox = begin_clip.bbox;
|
||||
if (is_stroke) {
|
||||
vec2 lw = get_linewidth(st);
|
||||
// This is the absolute bbox, it's been transformed during encoding.
|
||||
anno_begin_clip.bbox = begin_clip.bbox + vec4(-lw, lw);
|
||||
anno_begin_clip.linewidth = st.linewidth * sqrt(abs(st.mat.x * st.mat.w - st.mat.y * st.mat.z));
|
||||
} else {
|
||||
anno_begin_clip.bbox = begin_clip.bbox;
|
||||
|
|
Binary file not shown.
|
@ -37,30 +37,6 @@ layout(rgba8, set = 0, binding = 3) uniform readonly image2D images[1];
|
|||
#include "ptcl.h"
|
||||
#include "tile.h"
|
||||
|
||||
#define BLEND_STACK_SIZE 4
|
||||
|
||||
// Layout of a clip scratch frame:
|
||||
// Each frame is WIDTH * HEIGHT 32-bit words, then a link reference.
|
||||
|
||||
// Link offset and frame size in 32-bit words.
|
||||
#define CLIP_LINK_OFFSET (TILE_WIDTH_PX * TILE_HEIGHT_PX)
|
||||
#define CLIP_BUF_SIZE (CLIP_LINK_OFFSET + 1)
|
||||
|
||||
shared MallocResult sh_clip_alloc;
|
||||
|
||||
// Allocate a scratch buffer for clipping.
|
||||
MallocResult alloc_clip_buf(uint link) {
|
||||
if (gl_LocalInvocationID.x == 0 && gl_LocalInvocationID.y == 0) {
|
||||
MallocResult m = malloc(CLIP_BUF_SIZE * 4);
|
||||
if (!m.failed) {
|
||||
write_mem(m.alloc, (m.alloc.offset >> 2) + CLIP_LINK_OFFSET, link);
|
||||
}
|
||||
sh_clip_alloc = m;
|
||||
}
|
||||
barrier();
|
||||
return sh_clip_alloc;
|
||||
}
|
||||
|
||||
vec3 tosRGB(vec3 rgb) {
|
||||
bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308));
|
||||
vec3 below = vec3(12.92)*rgb;
|
||||
|
@ -117,27 +93,31 @@ void main() {
|
|||
Alloc cmd_alloc = slice_mem(conf.ptcl_alloc, tile_ix * PTCL_INITIAL_ALLOC, PTCL_INITIAL_ALLOC);
|
||||
CmdRef cmd_ref = CmdRef(cmd_alloc.offset);
|
||||
|
||||
// Read scrach space allocation, written first in the command list.
|
||||
Alloc scratch_alloc = alloc_read(cmd_alloc, cmd_ref.offset);
|
||||
cmd_ref.offset += Alloc_size;
|
||||
|
||||
uvec2 xy_uint = uvec2(gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_WorkGroupID.x, gl_LocalInvocationID.y + TILE_HEIGHT_PX * gl_WorkGroupID.y);
|
||||
vec2 xy = vec2(xy_uint);
|
||||
vec3 rgb[CHUNK];
|
||||
uint blend_stack[BLEND_STACK_SIZE][CHUNK];
|
||||
uint blend_spill = 0;
|
||||
uint blend_sp = 0;
|
||||
Alloc clip_tos = new_alloc(0, 0);
|
||||
vec4 rgba[CHUNK];
|
||||
for (uint i = 0; i < CHUNK; i++) {
|
||||
rgb[i] = vec3(0.5);
|
||||
rgba[i] = vec4(0.0);
|
||||
// TODO: remove this debug image support when the actual image method is plumbed.
|
||||
#ifdef DEBUG_IMAGES
|
||||
#ifdef ENABLE_IMAGE_INDICES
|
||||
if (xy_uint.x < 1024 && xy_uint.y < 1024) {
|
||||
rgb[i] = imageLoad(images[gl_WorkGroupID.x / 64], ivec2(xy_uint + chunk_offset(i))/4).rgb;
|
||||
rgba[i] = imageLoad(images[gl_WorkGroupID.x / 64], ivec2(xy_uint + chunk_offset(i))/4);
|
||||
}
|
||||
#else
|
||||
if (xy_uint.x < 1024 && xy_uint.y < 1024) {
|
||||
rgb[i] = imageLoad(images[0], ivec2(xy_uint + chunk_offset(i))/4).rgb;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
float area[CHUNK];
|
||||
uint clip_depth = 0;
|
||||
while (true) {
|
||||
uint tag = Cmd_tag(cmd_alloc, cmd_ref).tag;
|
||||
if (tag == Cmd_End) {
|
||||
|
@ -216,7 +196,7 @@ void main() {
|
|||
vec4 fg = unpacksRGB(color.rgba_color);
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
vec4 fg_k = fg * area[k];
|
||||
rgb[k] = rgb[k] * (1.0 - fg_k.a) + fg_k.rgb;
|
||||
rgba[k] = rgba[k] * (1.0 - fg_k.a) + fg_k;
|
||||
}
|
||||
cmd_ref.offset += 4 + CmdColor_size;
|
||||
break;
|
||||
|
@ -225,58 +205,46 @@ void main() {
|
|||
vec4 img[CHUNK] = fillImage(xy_uint, fill_img);
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
vec4 fg_k = img[k] * area[k];
|
||||
rgb[k] = rgb[k] * (1.0 - fg_k.a) + fg_k.rgb;
|
||||
rgba[k] = rgba[k] * (1.0 - fg_k.a) + fg_k;
|
||||
}
|
||||
cmd_ref.offset += 4 + CmdImage_size;
|
||||
break;
|
||||
case Cmd_BeginClip:
|
||||
uint blend_slot = blend_sp % BLEND_STACK_SIZE;
|
||||
if (blend_sp == blend_spill + BLEND_STACK_SIZE) {
|
||||
// spill to scratch buffer
|
||||
MallocResult m = alloc_clip_buf(clip_tos.offset);
|
||||
if (m.failed) {
|
||||
return;
|
||||
}
|
||||
clip_tos = m.alloc;
|
||||
uint base_ix = (clip_tos.offset >> 2) + gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y;
|
||||
uint base_ix = (scratch_alloc.offset >> 2) + CLIP_STATE_SIZE * (clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX +
|
||||
gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y);
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
uvec2 offset = chunk_offset(k);
|
||||
write_mem(clip_tos, base_ix + offset.x + offset.y * TILE_WIDTH_PX, blend_stack[blend_slot][k]);
|
||||
uint srgb = packsRGB(vec4(rgba[k]));
|
||||
float alpha = clamp(abs(area[k]), 0.0, 1.0);
|
||||
write_mem(scratch_alloc, base_ix + 0 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX), srgb);
|
||||
write_mem(scratch_alloc, base_ix + 1 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX), floatBitsToUint(alpha));
|
||||
rgba[k] = vec4(0.0);
|
||||
}
|
||||
blend_spill++;
|
||||
}
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
blend_stack[blend_slot][k] = packsRGB(vec4(rgb[k], clamp(abs(area[k]), 0.0, 1.0)));
|
||||
}
|
||||
blend_sp++;
|
||||
clip_depth++;
|
||||
cmd_ref.offset += 4;
|
||||
break;
|
||||
case Cmd_EndClip:
|
||||
blend_slot = (blend_sp - 1) % BLEND_STACK_SIZE;
|
||||
if (blend_sp == blend_spill) {
|
||||
uint base_ix = (clip_tos.offset >> 2) + gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y;
|
||||
clip_depth--;
|
||||
base_ix = (scratch_alloc.offset >> 2) + CLIP_STATE_SIZE * (clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX +
|
||||
gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y);
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
uvec2 offset = chunk_offset(k);
|
||||
blend_stack[blend_slot][k] = read_mem(clip_tos, base_ix + offset.x + offset.y * TILE_WIDTH_PX);
|
||||
}
|
||||
clip_tos.offset = read_mem(clip_tos, (clip_tos.offset >> 2) + CLIP_LINK_OFFSET);
|
||||
blend_spill--;
|
||||
}
|
||||
blend_sp--;
|
||||
for (uint k = 0; k < CHUNK; k++) {
|
||||
vec4 rgba = unpacksRGB(blend_stack[blend_slot][k]);
|
||||
rgb[k] = mix(rgba.rgb, rgb[k], area[k] * rgba.a);
|
||||
uint srgb = read_mem(scratch_alloc, base_ix + 0 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX));
|
||||
uint alpha = read_mem(scratch_alloc, base_ix + 1 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX));
|
||||
vec4 bg = unpacksRGB(srgb);
|
||||
vec4 fg = rgba[k] * area[k] * uintBitsToFloat(alpha);
|
||||
rgba[k] = bg * (1.0 - fg.a) + fg;
|
||||
}
|
||||
cmd_ref.offset += 4;
|
||||
break;
|
||||
case Cmd_Jump:
|
||||
cmd_ref = CmdRef(Cmd_Jump_read(cmd_alloc, cmd_ref).new_ref);
|
||||
cmd_alloc.offset = cmd_ref.offset;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i = 0; i < CHUNK; i++) {
|
||||
imageStore(image, ivec2(xy_uint + chunk_offset(i)), vec4(tosRGB(rgb[i]), 1.0));
|
||||
imageStore(image, ivec2(xy_uint + chunk_offset(i)), vec4(tosRGB(rgba[i].rgb), rgba[i].a));
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -21,7 +21,11 @@ layout(set = 0, binding = 0) buffer Memory {
|
|||
#define ERR_OUT_OF_BOUNDS 2
|
||||
#define ERR_UNALIGNED_ACCESS 3
|
||||
|
||||
#ifdef MEM_DEBUG
|
||||
#define Alloc_size 16
|
||||
#else
|
||||
#define Alloc_size 8
|
||||
#endif
|
||||
|
||||
// Alloc represents a memory allocation.
|
||||
struct Alloc {
|
||||
|
@ -39,7 +43,7 @@ struct MallocResult {
|
|||
bool failed;
|
||||
};
|
||||
|
||||
// new_alloc synthesizes an Alloc when its offset and size are derived.
|
||||
// new_alloc synthesizes an Alloc from an offset and size.
|
||||
Alloc new_alloc(uint offset, uint size) {
|
||||
Alloc a;
|
||||
a.offset = offset;
|
||||
|
@ -118,3 +122,21 @@ Alloc slice_mem(Alloc a, uint offset, uint size) {
|
|||
#endif
|
||||
return new_alloc(a.offset + offset, size);
|
||||
}
|
||||
|
||||
// alloc_write writes alloc to memory at offset bytes.
|
||||
void alloc_write(Alloc a, uint offset, Alloc alloc) {
|
||||
write_mem(a, offset >> 2, alloc.offset);
|
||||
#ifdef MEM_DEBUG
|
||||
write_mem(a, (offset >> 2) + 1, alloc.size);
|
||||
#endif
|
||||
}
|
||||
|
||||
// alloc_read reads an Alloc from memory at offset bytes.
|
||||
Alloc alloc_read(Alloc a, uint offset) {
|
||||
Alloc alloc;
|
||||
alloc.offset = read_mem(a, offset >> 2);
|
||||
#ifdef MEM_DEBUG
|
||||
alloc.size = read_mem(a, (offset >> 2) + 1);
|
||||
#endif
|
||||
return alloc;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,9 @@ struct Config {
|
|||
#define MODE_NONZERO 0
|
||||
#define MODE_STROKE 1
|
||||
|
||||
// Size of kernel4 clip state, in words.
|
||||
#define CLIP_STATE_SIZE 2
|
||||
|
||||
// fill_mode_from_flags extracts the fill mode from tag flags.
|
||||
uint fill_mode_from_flags(uint flags) {
|
||||
return flags & 0x1;
|
||||
|
|
|
@ -127,25 +127,12 @@ 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),
|
||||
);
|
||||
// Alpha compositing tests.
|
||||
rc.fill(diamond(Point::new(1024.0, 100.0)), &Color::Rgba32(0xff0000ff));
|
||||
rc.fill(diamond(Point::new(1024.0, 125.0)), &Color::Rgba32(0x00ff0080));
|
||||
rc.save();
|
||||
rc.clip(diamond(Point::new(1024.0, 150.0)));
|
||||
rc.fill(
|
||||
diamond(Point::new(1024.0, 175.0)),
|
||||
&Color::Rgba32(0x0000ba80),
|
||||
);
|
||||
rc.fill(diamond(Point::new(1024.0, 175.0)), &Color::Rgba32(0x0000ff80));
|
||||
rc.restore();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,19 @@
|
|||
use std::{borrow::Cow, ops::RangeBounds};
|
||||
|
||||
use piet_gpu_types::encoder::{Encode, Encoder};
|
||||
|
||||
use piet_gpu_types::scene::{
|
||||
Clip, CubicSeg, Element, FillColor, LineSeg, QuadSeg, SetFillMode, SetLineWidth, Transform,
|
||||
};
|
||||
|
||||
use piet::{
|
||||
kurbo::{Affine, Insets, PathEl, Point, Rect, Shape, Size},
|
||||
HitTestPosition, TextAttribute, TextStorage,
|
||||
HitTestPosition,
|
||||
kurbo::{Affine, Insets, PathEl, Point, Rect, Shape, Size}, TextAttribute, TextStorage,
|
||||
};
|
||||
|
||||
use piet::{
|
||||
Color, Error, FixedGradient, FontFamily, HitTestPoint, ImageFormat, InterpolationMode,
|
||||
IntoBrush, LineMetric, RenderContext, StrokeStyle, Text, TextLayout, TextLayoutBuilder,
|
||||
};
|
||||
|
||||
use piet_gpu_types::encoder::{Encode, Encoder};
|
||||
use piet_gpu_types::scene::{
|
||||
Clip, CubicSeg, Element, FillColor, LineSeg, QuadSeg, SetFillMode, SetLineWidth, Transform,
|
||||
};
|
||||
|
||||
pub struct PietGpuImage;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -139,7 +137,14 @@ impl RenderContext for PietGpuRenderContext {
|
|||
}
|
||||
|
||||
fn solid_brush(&mut self, color: Color) -> Self::Brush {
|
||||
PietGpuBrush::Solid(color.as_rgba_u32())
|
||||
// kernel4 expects colors encoded in alpha-premultiplied sRGB:
|
||||
//
|
||||
// [α,sRGB(α⋅R),sRGB(α⋅G),sRGB(α⋅B)]
|
||||
//
|
||||
// See also http://ssp.impulsetrain.com/gamma-premult.html.
|
||||
let (r, g, b, a) = color.as_rgba();
|
||||
let premul = Color::rgba(to_srgb(from_srgb(r) * a), to_srgb(from_srgb(g) * a), to_srgb(from_srgb(b) * a), a);
|
||||
PietGpuBrush::Solid(premul.as_rgba_u32())
|
||||
}
|
||||
|
||||
fn gradient(&mut self, _gradient: impl Into<FixedGradient>) -> Result<Self::Brush, Error> {
|
||||
|
@ -177,8 +182,7 @@ impl RenderContext for PietGpuRenderContext {
|
|||
_brush: &impl IntoBrush<Self>,
|
||||
_width: f64,
|
||||
_style: &StrokeStyle,
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
|
||||
fn fill(&mut self, shape: impl Shape, brush: &impl IntoBrush<Self>) {
|
||||
let brush = brush.make_brush(self, || shape.bounding_box()).into_owned();
|
||||
|
@ -280,8 +284,7 @@ impl RenderContext for PietGpuRenderContext {
|
|||
_image: &Self::Image,
|
||||
_rect: impl Into<Rect>,
|
||||
_interp: InterpolationMode,
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
|
||||
fn draw_image_area(
|
||||
&mut self,
|
||||
|
@ -289,8 +292,7 @@ impl RenderContext for PietGpuRenderContext {
|
|||
_src_rect: impl Into<Rect>,
|
||||
_dst_rect: impl Into<Rect>,
|
||||
_interp: InterpolationMode,
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
|
||||
fn blurred_rect(&mut self, _rect: Rect, _blur_radius: f64, _brush: &impl IntoBrush<Self>) {}
|
||||
|
||||
|
@ -587,3 +589,21 @@ fn to_scene_transform(transform: Affine) -> Transform {
|
|||
translate: [c[4] as f32, c[5] as f32],
|
||||
}
|
||||
}
|
||||
|
||||
fn to_srgb(f: f64) -> f64 {
|
||||
if f <= 0.0031308 {
|
||||
f * 12.92
|
||||
} else {
|
||||
let a = 0.055;
|
||||
(1. + a) * f64::powf(f, f64::recip(2.4)) - a
|
||||
}
|
||||
}
|
||||
|
||||
fn from_srgb(f: f64) -> f64 {
|
||||
if f <= 0.04045 {
|
||||
f / 12.92
|
||||
} else {
|
||||
let a = 0.055;
|
||||
f64::powf((f + a) * f64::recip(1. + a), 2.4)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue