mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 20:51:29 +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);
|
render_scene(&mut ctx);
|
||||||
let n_paths = ctx.path_count();
|
let n_paths = ctx.path_count();
|
||||||
let n_pathseg = ctx.pathseg_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 scene = ctx.get_scene_buf();
|
||||||
|
|
||||||
let renderer = Renderer::new(&session, scene, n_paths, n_pathseg, n_trans)?;
|
let renderer = Renderer::new(&session, scene, n_paths, n_pathseg, n_trans)?;
|
||||||
|
|
|
@ -48,13 +48,13 @@ void main() {
|
||||||
if (element_ix < conf.n_elements) {
|
if (element_ix < conf.n_elements) {
|
||||||
AnnotatedTag tag = Annotated_tag(conf.anno_alloc, ref);
|
AnnotatedTag tag = Annotated_tag(conf.anno_alloc, ref);
|
||||||
switch (tag.tag) {
|
switch (tag.tag) {
|
||||||
|
case Annotated_Image:
|
||||||
|
case Annotated_BeginClip:
|
||||||
case Annotated_Color:
|
case Annotated_Color:
|
||||||
if (fill_mode_from_flags(tag.flags) != MODE_NONZERO) {
|
if (fill_mode_from_flags(tag.flags) != MODE_NONZERO) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Fall through.
|
// Fall through.
|
||||||
case Annotated_Image:
|
|
||||||
case Annotated_BeginClip:
|
|
||||||
PathRef path_ref = PathRef(conf.tile_alloc.offset + element_ix * Path_size);
|
PathRef path_ref = PathRef(conf.tile_alloc.offset + element_ix * Path_size);
|
||||||
Path path = Path_read(conf.tile_alloc, path_ref);
|
Path path = Path_read(conf.tile_alloc, path_ref);
|
||||||
sh_row_width[th_ix] = path.bbox.z - path.bbox.x;
|
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;
|
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() {
|
void main() {
|
||||||
if (mem_error != NO_ERROR) {
|
if (mem_error != NO_ERROR) {
|
||||||
return;
|
return;
|
||||||
|
@ -135,6 +152,12 @@ void main() {
|
||||||
uint part_start_ix = 0;
|
uint part_start_ix = 0;
|
||||||
uint ready_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) {
|
while (true) {
|
||||||
for (uint i = 0; i < N_SLICE; i++) {
|
for (uint i = 0; i < N_SLICE; i++) {
|
||||||
sh_bitmaps[i][th_ix] = 0;
|
sh_bitmaps[i][th_ix] = 0;
|
||||||
|
@ -320,20 +343,7 @@ void main() {
|
||||||
if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) {
|
if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (fill_mode_from_flags(tag.flags) == MODE_NONZERO) {
|
write_fill(cmd_alloc, cmd_ref, tag.flags, tile, fill.linewidth);
|
||||||
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;
|
|
||||||
}
|
|
||||||
Cmd_Color_write(cmd_alloc, cmd_ref, CmdColor(fill.rgba_color));
|
Cmd_Color_write(cmd_alloc, cmd_ref, CmdColor(fill.rgba_color));
|
||||||
cmd_ref.offset += 4 + CmdColor_size;
|
cmd_ref.offset += 4 + CmdColor_size;
|
||||||
break;
|
break;
|
||||||
|
@ -344,20 +354,7 @@ void main() {
|
||||||
if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) {
|
if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (fill_mode_from_flags(tag.flags) == MODE_NONZERO) {
|
write_fill(cmd_alloc, cmd_ref, tag.flags, tile, fill_img.linewidth);
|
||||||
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;
|
|
||||||
}
|
|
||||||
Cmd_Image_write(cmd_alloc, cmd_ref, CmdImage(fill_img.index, fill_img.offset));
|
Cmd_Image_write(cmd_alloc, cmd_ref, CmdImage(fill_img.index, fill_img.offset));
|
||||||
cmd_ref.offset += 4 + CmdImage_size;
|
cmd_ref.offset += 4 + CmdImage_size;
|
||||||
break;
|
break;
|
||||||
|
@ -373,27 +370,14 @@ void main() {
|
||||||
if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) {
|
if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (fill_mode_from_flags(tag.flags) == MODE_NONZERO) {
|
write_fill(cmd_alloc, cmd_ref, tag.flags, tile, begin_clip.linewidth);
|
||||||
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;
|
|
||||||
}
|
|
||||||
Cmd_BeginClip_write(cmd_alloc, cmd_ref);
|
Cmd_BeginClip_write(cmd_alloc, cmd_ref);
|
||||||
cmd_ref.offset += 4;
|
cmd_ref.offset += 4;
|
||||||
if (clip_depth < 32) {
|
if (clip_depth < 32) {
|
||||||
clip_one_mask &= ~(1 << clip_depth);
|
clip_one_mask &= ~(1 << clip_depth);
|
||||||
}
|
}
|
||||||
|
begin_slot++;
|
||||||
|
num_begin_slots = max(num_begin_slots, begin_slot);
|
||||||
}
|
}
|
||||||
clip_depth++;
|
clip_depth++;
|
||||||
break;
|
break;
|
||||||
|
@ -405,6 +389,7 @@ void main() {
|
||||||
}
|
}
|
||||||
Cmd_Solid_write(cmd_alloc, cmd_ref);
|
Cmd_Solid_write(cmd_alloc, cmd_ref);
|
||||||
cmd_ref.offset += 4;
|
cmd_ref.offset += 4;
|
||||||
|
begin_slot--;
|
||||||
Cmd_EndClip_write(cmd_alloc, cmd_ref);
|
Cmd_EndClip_write(cmd_alloc, cmd_ref);
|
||||||
cmd_ref.offset += 4;
|
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) {
|
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);
|
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:
|
case Element_BeginClip:
|
||||||
Clip begin_clip = Element_BeginClip_read(this_ref);
|
Clip begin_clip = Element_BeginClip_read(this_ref);
|
||||||
AnnoBeginClip anno_begin_clip;
|
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) {
|
if (is_stroke) {
|
||||||
vec2 lw = get_linewidth(st);
|
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));
|
anno_begin_clip.linewidth = st.linewidth * sqrt(abs(st.mat.x * st.mat.w - st.mat.y * st.mat.z));
|
||||||
} else {
|
} else {
|
||||||
anno_begin_clip.bbox = begin_clip.bbox;
|
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 "ptcl.h"
|
||||||
#include "tile.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) {
|
vec3 tosRGB(vec3 rgb) {
|
||||||
bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308));
|
bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308));
|
||||||
vec3 below = vec3(12.92)*rgb;
|
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);
|
Alloc cmd_alloc = slice_mem(conf.ptcl_alloc, tile_ix * PTCL_INITIAL_ALLOC, PTCL_INITIAL_ALLOC);
|
||||||
CmdRef cmd_ref = CmdRef(cmd_alloc.offset);
|
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);
|
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);
|
vec2 xy = vec2(xy_uint);
|
||||||
vec3 rgb[CHUNK];
|
vec4 rgba[CHUNK];
|
||||||
uint blend_stack[BLEND_STACK_SIZE][CHUNK];
|
|
||||||
uint blend_spill = 0;
|
|
||||||
uint blend_sp = 0;
|
|
||||||
Alloc clip_tos = new_alloc(0, 0);
|
|
||||||
for (uint i = 0; i < CHUNK; i++) {
|
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
|
#ifdef ENABLE_IMAGE_INDICES
|
||||||
if (xy_uint.x < 1024 && xy_uint.y < 1024) {
|
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
|
#else
|
||||||
if (xy_uint.x < 1024 && xy_uint.y < 1024) {
|
if (xy_uint.x < 1024 && xy_uint.y < 1024) {
|
||||||
rgb[i] = imageLoad(images[0], ivec2(xy_uint + chunk_offset(i))/4).rgb;
|
rgb[i] = imageLoad(images[0], ivec2(xy_uint + chunk_offset(i))/4).rgb;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
float area[CHUNK];
|
float area[CHUNK];
|
||||||
|
uint clip_depth = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
uint tag = Cmd_tag(cmd_alloc, cmd_ref).tag;
|
uint tag = Cmd_tag(cmd_alloc, cmd_ref).tag;
|
||||||
if (tag == Cmd_End) {
|
if (tag == Cmd_End) {
|
||||||
|
@ -216,7 +196,7 @@ void main() {
|
||||||
vec4 fg = unpacksRGB(color.rgba_color);
|
vec4 fg = unpacksRGB(color.rgba_color);
|
||||||
for (uint k = 0; k < CHUNK; k++) {
|
for (uint k = 0; k < CHUNK; k++) {
|
||||||
vec4 fg_k = fg * area[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;
|
cmd_ref.offset += 4 + CmdColor_size;
|
||||||
break;
|
break;
|
||||||
|
@ -225,58 +205,46 @@ void main() {
|
||||||
vec4 img[CHUNK] = fillImage(xy_uint, fill_img);
|
vec4 img[CHUNK] = fillImage(xy_uint, fill_img);
|
||||||
for (uint k = 0; k < CHUNK; k++) {
|
for (uint k = 0; k < CHUNK; k++) {
|
||||||
vec4 fg_k = img[k] * area[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;
|
cmd_ref.offset += 4 + CmdImage_size;
|
||||||
break;
|
break;
|
||||||
case Cmd_BeginClip:
|
case Cmd_BeginClip:
|
||||||
uint blend_slot = blend_sp % BLEND_STACK_SIZE;
|
uint base_ix = (scratch_alloc.offset >> 2) + CLIP_STATE_SIZE * (clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX +
|
||||||
if (blend_sp == blend_spill + BLEND_STACK_SIZE) {
|
gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y);
|
||||||
// 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++) {
|
for (uint k = 0; k < CHUNK; k++) {
|
||||||
uvec2 offset = chunk_offset(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++;
|
clip_depth++;
|
||||||
}
|
|
||||||
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++;
|
|
||||||
cmd_ref.offset += 4;
|
cmd_ref.offset += 4;
|
||||||
break;
|
break;
|
||||||
case Cmd_EndClip:
|
case Cmd_EndClip:
|
||||||
blend_slot = (blend_sp - 1) % BLEND_STACK_SIZE;
|
clip_depth--;
|
||||||
if (blend_sp == blend_spill) {
|
base_ix = (scratch_alloc.offset >> 2) + CLIP_STATE_SIZE * (clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX +
|
||||||
uint base_ix = (clip_tos.offset >> 2) + gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y;
|
gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y);
|
||||||
for (uint k = 0; k < CHUNK; k++) {
|
for (uint k = 0; k < CHUNK; k++) {
|
||||||
uvec2 offset = chunk_offset(k);
|
uvec2 offset = chunk_offset(k);
|
||||||
blend_stack[blend_slot][k] = read_mem(clip_tos, base_ix + offset.x + offset.y * TILE_WIDTH_PX);
|
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));
|
||||||
clip_tos.offset = read_mem(clip_tos, (clip_tos.offset >> 2) + CLIP_LINK_OFFSET);
|
vec4 bg = unpacksRGB(srgb);
|
||||||
blend_spill--;
|
vec4 fg = rgba[k] * area[k] * uintBitsToFloat(alpha);
|
||||||
}
|
rgba[k] = bg * (1.0 - fg.a) + fg;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
cmd_ref.offset += 4;
|
cmd_ref.offset += 4;
|
||||||
break;
|
break;
|
||||||
case Cmd_Jump:
|
case Cmd_Jump:
|
||||||
cmd_ref = CmdRef(Cmd_Jump_read(cmd_alloc, cmd_ref).new_ref);
|
cmd_ref = CmdRef(Cmd_Jump_read(cmd_alloc, cmd_ref).new_ref);
|
||||||
cmd_alloc.offset = cmd_ref.offset;
|
cmd_alloc.offset = cmd_ref.offset;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint i = 0; i < CHUNK; i++) {
|
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_OUT_OF_BOUNDS 2
|
||||||
#define ERR_UNALIGNED_ACCESS 3
|
#define ERR_UNALIGNED_ACCESS 3
|
||||||
|
|
||||||
|
#ifdef MEM_DEBUG
|
||||||
|
#define Alloc_size 16
|
||||||
|
#else
|
||||||
#define Alloc_size 8
|
#define Alloc_size 8
|
||||||
|
#endif
|
||||||
|
|
||||||
// Alloc represents a memory allocation.
|
// Alloc represents a memory allocation.
|
||||||
struct Alloc {
|
struct Alloc {
|
||||||
|
@ -39,7 +43,7 @@ struct MallocResult {
|
||||||
bool failed;
|
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 new_alloc(uint offset, uint size) {
|
||||||
Alloc a;
|
Alloc a;
|
||||||
a.offset = offset;
|
a.offset = offset;
|
||||||
|
@ -118,3 +122,21 @@ Alloc slice_mem(Alloc a, uint offset, uint size) {
|
||||||
#endif
|
#endif
|
||||||
return new_alloc(a.offset + offset, size);
|
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_NONZERO 0
|
||||||
#define MODE_STROKE 1
|
#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.
|
// fill_mode_from_flags extracts the fill mode from tag flags.
|
||||||
uint fill_mode_from_flags(uint flags) {
|
uint fill_mode_from_flags(uint flags) {
|
||||||
return flags & 0x1;
|
return flags & 0x1;
|
||||||
|
|
|
@ -127,25 +127,12 @@ fn render_clip_test(rc: &mut impl RenderContext) {
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn render_alpha_test(rc: &mut impl RenderContext) {
|
fn render_alpha_test(rc: &mut impl RenderContext) {
|
||||||
// Alpha compositing tests. kernel4 expects colors encoded in alpha-premultiplied sRGB:
|
// Alpha compositing tests.
|
||||||
//
|
rc.fill(diamond(Point::new(1024.0, 100.0)), &Color::Rgba32(0xff0000ff));
|
||||||
// [α,sRGB(α⋅R),sRGB(α⋅G),sRGB(α⋅B)]
|
rc.fill(diamond(Point::new(1024.0, 125.0)), &Color::Rgba32(0x00ff0080));
|
||||||
//
|
|
||||||
// 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.save();
|
||||||
rc.clip(diamond(Point::new(1024.0, 150.0)));
|
rc.clip(diamond(Point::new(1024.0, 150.0)));
|
||||||
rc.fill(
|
rc.fill(diamond(Point::new(1024.0, 175.0)), &Color::Rgba32(0x0000ff80));
|
||||||
diamond(Point::new(1024.0, 175.0)),
|
|
||||||
&Color::Rgba32(0x0000ba80),
|
|
||||||
);
|
|
||||||
rc.restore();
|
rc.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
use std::{borrow::Cow, ops::RangeBounds};
|
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::{
|
use piet::{
|
||||||
kurbo::{Affine, Insets, PathEl, Point, Rect, Shape, Size},
|
HitTestPosition,
|
||||||
HitTestPosition, TextAttribute, TextStorage,
|
kurbo::{Affine, Insets, PathEl, Point, Rect, Shape, Size}, TextAttribute, TextStorage,
|
||||||
};
|
};
|
||||||
|
|
||||||
use piet::{
|
use piet::{
|
||||||
Color, Error, FixedGradient, FontFamily, HitTestPoint, ImageFormat, InterpolationMode,
|
Color, Error, FixedGradient, FontFamily, HitTestPoint, ImageFormat, InterpolationMode,
|
||||||
IntoBrush, LineMetric, RenderContext, StrokeStyle, Text, TextLayout, TextLayoutBuilder,
|
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;
|
pub struct PietGpuImage;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -139,7 +137,14 @@ impl RenderContext for PietGpuRenderContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solid_brush(&mut self, color: Color) -> Self::Brush {
|
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> {
|
fn gradient(&mut self, _gradient: impl Into<FixedGradient>) -> Result<Self::Brush, Error> {
|
||||||
|
@ -177,8 +182,7 @@ impl RenderContext for PietGpuRenderContext {
|
||||||
_brush: &impl IntoBrush<Self>,
|
_brush: &impl IntoBrush<Self>,
|
||||||
_width: f64,
|
_width: f64,
|
||||||
_style: &StrokeStyle,
|
_style: &StrokeStyle,
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
fn fill(&mut self, shape: impl Shape, brush: &impl IntoBrush<Self>) {
|
fn fill(&mut self, shape: impl Shape, brush: &impl IntoBrush<Self>) {
|
||||||
let brush = brush.make_brush(self, || shape.bounding_box()).into_owned();
|
let brush = brush.make_brush(self, || shape.bounding_box()).into_owned();
|
||||||
|
@ -280,8 +284,7 @@ impl RenderContext for PietGpuRenderContext {
|
||||||
_image: &Self::Image,
|
_image: &Self::Image,
|
||||||
_rect: impl Into<Rect>,
|
_rect: impl Into<Rect>,
|
||||||
_interp: InterpolationMode,
|
_interp: InterpolationMode,
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_image_area(
|
fn draw_image_area(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -289,8 +292,7 @@ impl RenderContext for PietGpuRenderContext {
|
||||||
_src_rect: impl Into<Rect>,
|
_src_rect: impl Into<Rect>,
|
||||||
_dst_rect: impl Into<Rect>,
|
_dst_rect: impl Into<Rect>,
|
||||||
_interp: InterpolationMode,
|
_interp: InterpolationMode,
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
fn blurred_rect(&mut self, _rect: Rect, _blur_radius: f64, _brush: &impl IntoBrush<Self>) {}
|
fn blurred_rect(&mut self, _rect: Rect, _blur_radius: f64, _brush: &impl IntoBrush<Self>) {}
|
||||||
|
|
||||||
|
@ -321,7 +323,7 @@ impl PietGpuRenderContext {
|
||||||
self.pathseg_count += 1;
|
self.pathseg_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_path(&mut self, path: impl Iterator<Item = PathEl>, is_fill: bool) {
|
fn encode_path(&mut self, path: impl Iterator<Item=PathEl>, is_fill: bool) {
|
||||||
if is_fill {
|
if is_fill {
|
||||||
self.encode_path_inner(
|
self.encode_path_inner(
|
||||||
path.flat_map(|el| {
|
path.flat_map(|el| {
|
||||||
|
@ -339,7 +341,7 @@ impl PietGpuRenderContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_path_inner(&mut self, path: impl Iterator<Item = PathEl>) {
|
fn encode_path_inner(&mut self, path: impl Iterator<Item=PathEl>) {
|
||||||
let flatten = false;
|
let flatten = false;
|
||||||
if flatten {
|
if flatten {
|
||||||
let mut start_pt = None;
|
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],
|
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