diff --git a/piet-gpu/bin/winit.rs b/piet-gpu/bin/winit.rs index 420ffa5..5eb5be6 100644 --- a/piet-gpu/bin/winit.rs +++ b/piet-gpu/bin/winit.rs @@ -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)?; diff --git a/piet-gpu/shader/backdrop.comp b/piet-gpu/shader/backdrop.comp index 8461275..b640d14 100644 --- a/piet-gpu/shader/backdrop.comp +++ b/piet-gpu/shader/backdrop.comp @@ -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; diff --git a/piet-gpu/shader/backdrop.spv b/piet-gpu/shader/backdrop.spv index 9233dd0..26aeb4c 100644 Binary files a/piet-gpu/shader/backdrop.spv and b/piet-gpu/shader/backdrop.spv differ diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index a4837bd..76d7fc6 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -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); + } } } diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 763da55..7d0b629 100644 Binary files a/piet-gpu/shader/coarse.spv and b/piet-gpu/shader/coarse.spv differ diff --git a/piet-gpu/shader/elements.comp b/piet-gpu/shader/elements.comp index 7fb02fc..56ad6e2 100644 --- a/piet-gpu/shader/elements.comp +++ b/piet-gpu/shader/elements.comp @@ -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; diff --git a/piet-gpu/shader/elements.spv b/piet-gpu/shader/elements.spv index d1ca8dd..6bd53b3 100644 Binary files a/piet-gpu/shader/elements.spv and b/piet-gpu/shader/elements.spv differ diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index 36140f4..1d706a6 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -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; - 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]); - } - blend_spill++; - } + 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++) { - blend_stack[blend_slot][k] = packsRGB(vec4(rgb[k], clamp(abs(area[k]), 0.0, 1.0))); + uvec2 offset = chunk_offset(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_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; - 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--; + 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++) { - vec4 rgba = unpacksRGB(blend_stack[blend_slot][k]); - rgb[k] = mix(rgba.rgb, rgb[k], area[k] * rgba.a); + uvec2 offset = chunk_offset(k); + 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)); } } diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index 5c4e11c..bd14134 100644 Binary files a/piet-gpu/shader/kernel4.spv and b/piet-gpu/shader/kernel4.spv differ diff --git a/piet-gpu/shader/kernel4_idx.spv b/piet-gpu/shader/kernel4_idx.spv index 8aba85e..0443678 100644 Binary files a/piet-gpu/shader/kernel4_idx.spv and b/piet-gpu/shader/kernel4_idx.spv differ diff --git a/piet-gpu/shader/mem.h b/piet-gpu/shader/mem.h index 7b2a02a..6e6e775 100644 --- a/piet-gpu/shader/mem.h +++ b/piet-gpu/shader/mem.h @@ -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; +} diff --git a/piet-gpu/shader/setup.h b/piet-gpu/shader/setup.h index 1230320..3ed1690 100644 --- a/piet-gpu/shader/setup.h +++ b/piet-gpu/shader/setup.h @@ -45,7 +45,10 @@ 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; + return flags & 0x1; } diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index 29a1fa4..8e5be4d 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -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(); } diff --git a/piet-gpu/src/render_ctx.rs b/piet-gpu/src/render_ctx.rs index e33974c..74503ef 100644 --- a/piet-gpu/src/render_ctx.rs +++ b/piet-gpu/src/render_ctx.rs @@ -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) -> Result { @@ -177,8 +182,7 @@ impl RenderContext for PietGpuRenderContext { _brush: &impl IntoBrush, _width: f64, _style: &StrokeStyle, - ) { - } + ) {} fn fill(&mut self, shape: impl Shape, brush: &impl IntoBrush) { 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, _interp: InterpolationMode, - ) { - } + ) {} fn draw_image_area( &mut self, @@ -289,8 +292,7 @@ impl RenderContext for PietGpuRenderContext { _src_rect: impl Into, _dst_rect: impl Into, _interp: InterpolationMode, - ) { - } + ) {} fn blurred_rect(&mut self, _rect: Rect, _blur_radius: f64, _brush: &impl IntoBrush) {} @@ -321,7 +323,7 @@ impl PietGpuRenderContext { self.pathseg_count += 1; } - fn encode_path(&mut self, path: impl Iterator, is_fill: bool) { + fn encode_path(&mut self, path: impl Iterator, is_fill: bool) { if is_fill { self.encode_path_inner( path.flat_map(|el| { @@ -339,7 +341,7 @@ impl PietGpuRenderContext { } } - fn encode_path_inner(&mut self, path: impl Iterator) { + fn encode_path_inner(&mut self, path: impl Iterator) { let flatten = false; if flatten { let mut start_pt = None; @@ -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) + } +} \ No newline at end of file