diff --git a/gpu/compute.go b/gpu/compute.go index 922110d5..51329f7f 100644 --- a/gpu/compute.go +++ b/gpu/compute.go @@ -176,7 +176,7 @@ const ( pathSize = 12 binSize = 8 pathsegSize = 52 - annoSize = 28 + annoSize = 32 transSize = 24 stateSize = 60 stateStride = 4 + 2*stateSize @@ -346,8 +346,8 @@ func (g *compute) encode(viewport image.Point) error { g.enc.transform(flipY) if g.drawOps.clear { g.drawOps.clear = false - g.enc.rect(f32.Rectangle{Max: layout.FPt(viewport)}, false) - g.enc.fill(f32color.NRGBAToRGBA(g.drawOps.clearColor.SRGB())) + g.enc.rect(f32.Rectangle{Max: layout.FPt(viewport)}) + g.enc.fillColor(f32color.NRGBAToRGBA(g.drawOps.clearColor.SRGB())) } return g.encodeOps(flipY, viewport, g.drawOps.allImageOps) } @@ -639,10 +639,10 @@ func (g *compute) encodeOps(trans f32.Affine2D, viewport image.Point, ops []imag // Add fill command, its offset is resolved and filled in renderMaterials. g.enc.fillImage(0) case materialColor: - g.enc.fill(f32color.NRGBAToRGBA(op.material.color.SRGB())) + g.enc.fillColor(f32color.NRGBAToRGBA(op.material.color.SRGB())) case materialLinearGradient: // TODO: implement. - g.enc.fill(f32color.NRGBAToRGBA(op.material.color1.SRGB())) + g.enc.fillColor(f32color.NRGBAToRGBA(op.material.color1.SRGB())) default: panic("not implemented") } @@ -668,7 +668,7 @@ func (g *compute) encodeClipStack(clip, bounds f32.Rectangle, p *pathOp) int { g.enc.append(pathData.computePath) g.enc.transform(p.trans.Invert()) } else { - g.enc.rect(bounds, false) + g.enc.rect(bounds) } return nclips } @@ -680,7 +680,7 @@ func encodePath(pathData []byte, stroke clip.StrokeStyle, dashes dashOp) encoder quads = quads.stroke(stroke, dashes) for _, quad := range quads { q := quad.quad - enc.quad(q.From, q.Ctrl, q.To, false) + enc.quad(q.From, q.Ctrl, q.To) } return enc } @@ -999,12 +999,11 @@ func (e *encoder) transform(m f32.Affine2D) { } func (e *encoder) lineWidth(width float32) { - e.scene = append(e.scene, scene.LineWidth(width)) + e.scene = append(e.scene, scene.SetLineWidth(width)) } -func (e *encoder) stroke(col color.RGBA) { - e.scene = append(e.scene, scene.Stroke(col)) - e.npath++ +func (e *encoder) fillMode(mode scene.FillMode) { + e.scene = append(e.scene, scene.SetFillMode(mode)) } func (e *encoder) beginClip(bbox f32.Rectangle) { @@ -1017,17 +1016,17 @@ func (e *encoder) endClip(bbox f32.Rectangle) { e.npath++ } -func (e *encoder) rect(r f32.Rectangle, stroke bool) { +func (e *encoder) rect(r f32.Rectangle) { // Rectangle corners, clock-wise. c0, c1, c2, c3 := r.Min, f32.Pt(r.Min.X, r.Max.Y), r.Max, f32.Pt(r.Max.X, r.Min.Y) - e.line(c0, c1, stroke) - e.line(c1, c2, stroke) - e.line(c2, c3, stroke) - e.line(c3, c0, stroke) + e.line(c0, c1) + e.line(c1, c2) + e.line(c2, c3) + e.line(c3, c0) } -func (e *encoder) fill(col color.RGBA) { - e.scene = append(e.scene, scene.Fill(col)) +func (e *encoder) fillColor(col color.RGBA) { + e.scene = append(e.scene, scene.FillColor(col)) e.npath++ } @@ -1042,12 +1041,12 @@ func (e *encoder) fillImage(index int) { e.npath++ } -func (e *encoder) line(start, end f32.Point, stroke bool) { - e.scene = append(e.scene, scene.Line(start, end, stroke)) +func (e *encoder) line(start, end f32.Point) { + e.scene = append(e.scene, scene.Line(start, end)) e.npathseg++ } -func (e *encoder) quad(start, ctrl, end f32.Point, stroke bool) { - e.scene = append(e.scene, scene.Quad(start, ctrl, end, stroke)) +func (e *encoder) quad(start, ctrl, end f32.Point) { + e.scene = append(e.scene, scene.Quad(start, ctrl, end)) e.npathseg++ } diff --git a/gpu/gpu.go b/gpu/gpu.go index 626c8535..f685db51 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -1393,18 +1393,18 @@ func decodeToOutlineQuads(qs *quadSplitter, tr f32.Affine2D, pathData []byte) { qs.contour = bo.Uint32(pathData) cmd := ops.DecodeCommand(pathData[4:]) switch cmd.Op() { - case scene.OpFillLine: + case scene.OpLine: var q quadSegment q.From, q.To = scene.DecodeLine(cmd) q.Ctrl = q.From.Add(q.To).Mul(.5) q = q.Transform(tr) qs.splitAndEncode(q) - case scene.OpFillQuad: + case scene.OpQuad: var q quadSegment q.From, q.Ctrl, q.To = scene.DecodeQuad(cmd) q = q.Transform(tr) qs.splitAndEncode(q) - case scene.OpFillCubic: + case scene.OpCubic: for _, q := range splitCubic(scene.DecodeCubic(cmd)) { q = q.Transform(tr) qs.splitAndEncode(q) @@ -1424,7 +1424,7 @@ func decodeToStrokeQuads(pathData []byte) strokeQuads { contour := bo.Uint32(pathData) cmd := ops.DecodeCommand(pathData[4:]) switch cmd.Op() { - case scene.OpFillLine: + case scene.OpLine: var q quadSegment q.From, q.To = scene.DecodeLine(cmd) q.Ctrl = q.From.Add(q.To).Mul(.5) @@ -1433,7 +1433,7 @@ func decodeToStrokeQuads(pathData []byte) strokeQuads { quad: q, } quads = append(quads, quad) - case scene.OpFillQuad: + case scene.OpQuad: var q quadSegment q.From, q.Ctrl, q.To = scene.DecodeQuad(cmd) quad := strokeQuad{ @@ -1441,7 +1441,7 @@ func decodeToStrokeQuads(pathData []byte) strokeQuads { quad: q, } quads = append(quads, quad) - case scene.OpFillCubic: + case scene.OpCubic: for _, q := range splitCubic(scene.DecodeCubic(cmd)) { quad := strokeQuad{ contour: contour, @@ -1506,16 +1506,16 @@ func (d *drawOps) boundsForTransformedRect(r f32.Rectangle, tr f32.Affine2D) (au buf := aux bo := binary.LittleEndian bo.PutUint32(buf, 0) // Contour - ops.EncodeCommand(buf[4:], scene.Line(r.Min, f32.Pt(r.Max.X, r.Min.Y), false)) + ops.EncodeCommand(buf[4:], scene.Line(r.Min, f32.Pt(r.Max.X, r.Min.Y))) buf = buf[4+scene.CommandSize:] bo.PutUint32(buf, 0) - ops.EncodeCommand(buf[4:], scene.Line(f32.Pt(r.Max.X, r.Min.Y), r.Max, false)) + ops.EncodeCommand(buf[4:], scene.Line(f32.Pt(r.Max.X, r.Min.Y), r.Max)) buf = buf[4+scene.CommandSize:] bo.PutUint32(buf, 0) - ops.EncodeCommand(buf[4:], scene.Line(r.Max, f32.Pt(r.Min.X, r.Max.Y), false)) + ops.EncodeCommand(buf[4:], scene.Line(r.Max, f32.Pt(r.Min.X, r.Max.Y))) buf = buf[4+scene.CommandSize:] bo.PutUint32(buf, 0) - ops.EncodeCommand(buf[4:], scene.Line(f32.Pt(r.Min.X, r.Max.Y), r.Min, false)) + ops.EncodeCommand(buf[4:], scene.Line(f32.Pt(r.Min.X, r.Max.Y), r.Min)) } // establish the transform mapping from bounds rectangle to transformed corners diff --git a/gpu/shaders.go b/gpu/shaders.go index eac11955..17f5f1ee 100644 --- a/gpu/shaders.go +++ b/gpu/shaders.go @@ -7,11 +7,11 @@ import "gioui.org/gpu/internal/driver" var ( shader_backdrop_comp = driver.ShaderSources{ Name: "backdrop.comp", - GLSL310ES: "#version 310 es\nlayout(local_size_x = 128, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct AnnotatedRef\n{\n uint offset;\n};\n\nstruct PathRef\n{\n uint offset;\n};\n\nstruct TileRef\n{\n uint offset;\n};\n\nstruct Path\n{\n uvec4 bbox;\n TileRef tiles;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _72;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _176;\n\nshared uint sh_row_width[128];\nshared Alloc sh_row_alloc[128];\nshared uint sh_row_count[128];\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _72.memory[offset];\n return v;\n}\n\nuint Annotated_tag(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n return read_mem(param, param_1);\n}\n\nPath Path_read(Alloc a, PathRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Path s;\n s.bbox = uvec4(raw0 & 65535u, raw0 >> uint(16), raw1 & 65535u, raw1 >> uint(16));\n s.tiles = TileRef(raw2);\n return s;\n}\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _72.memory[offset] = val;\n}\n\nvoid main()\n{\n if (_72.mem_error != 0u)\n {\n return;\n }\n uint th_ix = gl_LocalInvocationID.x;\n uint element_ix = gl_GlobalInvocationID.x;\n AnnotatedRef ref = AnnotatedRef(_176.conf.anno_alloc.offset + (element_ix * 28u));\n uint row_count = 0u;\n if (element_ix < _176.conf.n_elements)\n {\n Alloc param;\n param.offset = _176.conf.anno_alloc.offset;\n AnnotatedRef param_1 = ref;\n uint tag = Annotated_tag(param, param_1);\n switch (tag)\n {\n case 2u:\n case 3u:\n case 4u:\n {\n PathRef path_ref = PathRef(_176.conf.tile_alloc.offset + (element_ix * 12u));\n Alloc param_2;\n param_2.offset = _176.conf.tile_alloc.offset;\n PathRef param_3 = path_ref;\n Path path = Path_read(param_2, param_3);\n sh_row_width[th_ix] = path.bbox.z - path.bbox.x;\n row_count = path.bbox.w - path.bbox.y;\n bool _242 = row_count == 1u;\n bool _248;\n if (_242)\n {\n _248 = path.bbox.y > 0u;\n }\n else\n {\n _248 = _242;\n }\n if (_248)\n {\n row_count = 0u;\n }\n uint param_4 = path.tiles.offset;\n uint param_5 = ((path.bbox.z - path.bbox.x) * (path.bbox.w - path.bbox.y)) * 8u;\n Alloc path_alloc = new_alloc(param_4, param_5);\n sh_row_alloc[th_ix] = path_alloc;\n break;\n }\n }\n }\n sh_row_count[th_ix] = row_count;\n for (uint i = 0u; i < 7u; i++)\n {\n barrier();\n if (th_ix >= uint(1 << int(i)))\n {\n row_count += sh_row_count[th_ix - uint(1 << int(i))];\n }\n barrier();\n sh_row_count[th_ix] = row_count;\n }\n barrier();\n uint total_rows = sh_row_count[127];\n uint _370;\n for (uint row = th_ix; row < total_rows; row += 128u)\n {\n uint el_ix = 0u;\n for (uint i_1 = 0u; i_1 < 7u; i_1++)\n {\n uint probe = el_ix + uint(64 >> int(i_1));\n if (row >= sh_row_count[probe - 1u])\n {\n el_ix = probe;\n }\n }\n uint width = sh_row_width[el_ix];\n if (width > 0u)\n {\n Alloc tiles_alloc = sh_row_alloc[el_ix];\n if (el_ix > 0u)\n {\n _370 = sh_row_count[el_ix - 1u];\n }\n else\n {\n _370 = 0u;\n }\n uint seq_ix = row - _370;\n uint tile_el_ix = ((tiles_alloc.offset >> uint(2)) + 1u) + ((seq_ix * 2u) * width);\n Alloc param_6 = tiles_alloc;\n uint param_7 = tile_el_ix;\n uint sum = read_mem(param_6, param_7);\n for (uint x = 1u; x < width; x++)\n {\n tile_el_ix += 2u;\n Alloc param_8 = tiles_alloc;\n uint param_9 = tile_el_ix;\n sum += read_mem(param_8, param_9);\n Alloc param_10 = tiles_alloc;\n uint param_11 = tile_el_ix;\n uint param_12 = sum;\n write_mem(param_10, param_11, param_12);\n }\n }\n }\n}\n\n", + GLSL310ES: "#version 310 es\nlayout(local_size_x = 128, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct AnnotatedRef\n{\n uint offset;\n};\n\nstruct AnnotatedTag\n{\n uint tag;\n uint flags;\n};\n\nstruct PathRef\n{\n uint offset;\n};\n\nstruct TileRef\n{\n uint offset;\n};\n\nstruct Path\n{\n uvec4 bbox;\n TileRef tiles;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _77;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _191;\n\nshared uint sh_row_width[128];\nshared Alloc sh_row_alloc[128];\nshared uint sh_row_count[128];\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _77.memory[offset];\n return v;\n}\n\nAnnotatedTag Annotated_tag(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint tag_and_flags = read_mem(param, param_1);\n return AnnotatedTag(tag_and_flags & 65535u, tag_and_flags >> uint(16));\n}\n\nuint fill_mode_from_flags(uint flags)\n{\n return flags & 1u;\n}\n\nPath Path_read(Alloc a, PathRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Path s;\n s.bbox = uvec4(raw0 & 65535u, raw0 >> uint(16), raw1 & 65535u, raw1 >> uint(16));\n s.tiles = TileRef(raw2);\n return s;\n}\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _77.memory[offset] = val;\n}\n\nvoid main()\n{\n if (_77.mem_error != 0u)\n {\n return;\n }\n uint th_ix = gl_LocalInvocationID.x;\n uint element_ix = gl_GlobalInvocationID.x;\n AnnotatedRef ref = AnnotatedRef(_191.conf.anno_alloc.offset + (element_ix * 32u));\n uint row_count = 0u;\n if (element_ix < _191.conf.n_elements)\n {\n Alloc param;\n param.offset = _191.conf.anno_alloc.offset;\n AnnotatedRef param_1 = ref;\n AnnotatedTag tag = Annotated_tag(param, param_1);\n switch (tag.tag)\n {\n case 1u:\n {\n uint param_2 = tag.flags;\n if (fill_mode_from_flags(param_2) != 0u)\n {\n break;\n }\n uint _237 = element_ix * 12u;\n uint _238 = _191.conf.tile_alloc.offset + _237;\n PathRef _239 = PathRef(_238);\n PathRef path_ref = _239;\n Alloc param_3;\n param_3.offset = _191.conf.tile_alloc.offset;\n PathRef _247 = path_ref;\n PathRef param_4 = _247;\n Path _248 = Path_read(param_3, param_4);\n Path path = _248;\n uint _255 = path.bbox.z;\n uint _257 = path.bbox.x;\n uint _258 = _255 - _257;\n sh_row_width[th_ix] = _258;\n uint _263 = path.bbox.w;\n uint _265 = path.bbox.y;\n uint _266 = _263 - _265;\n row_count = _266;\n uint _267 = row_count;\n bool _268 = _267 == 1u;\n bool _274;\n if (_268)\n {\n uint _272 = path.bbox.y;\n bool _273 = _272 > 0u;\n _274 = _273;\n }\n else\n {\n _274 = _268;\n }\n if (_274)\n {\n row_count = 0u;\n }\n uint _279 = path.bbox.z;\n uint _281 = path.bbox.x;\n uint _282 = _279 - _281;\n uint _284 = path.bbox.w;\n uint _286 = path.bbox.y;\n uint _287 = _284 - _286;\n uint _288 = _282 * _287;\n uint _290 = _288 * 8u;\n uint _293 = path.tiles.offset;\n uint param_5 = _293;\n uint param_6 = _290;\n Alloc _295 = new_alloc(param_5, param_6);\n Alloc path_alloc = _295;\n Alloc _300 = path_alloc;\n sh_row_alloc[th_ix] = _300;\n break;\n }\n case 2u:\n case 3u:\n {\n uint _237 = element_ix * 12u;\n uint _238 = _191.conf.tile_alloc.offset + _237;\n PathRef _239 = PathRef(_238);\n PathRef path_ref = _239;\n Alloc param_3;\n param_3.offset = _191.conf.tile_alloc.offset;\n PathRef _247 = path_ref;\n PathRef param_4 = _247;\n Path _248 = Path_read(param_3, param_4);\n Path path = _248;\n uint _255 = path.bbox.z;\n uint _257 = path.bbox.x;\n uint _258 = _255 - _257;\n sh_row_width[th_ix] = _258;\n uint _263 = path.bbox.w;\n uint _265 = path.bbox.y;\n uint _266 = _263 - _265;\n row_count = _266;\n uint _267 = row_count;\n bool _268 = _267 == 1u;\n bool _274;\n if (_268)\n {\n uint _272 = path.bbox.y;\n bool _273 = _272 > 0u;\n _274 = _273;\n }\n else\n {\n _274 = _268;\n }\n if (_274)\n {\n row_count = 0u;\n }\n uint _279 = path.bbox.z;\n uint _281 = path.bbox.x;\n uint _282 = _279 - _281;\n uint _284 = path.bbox.w;\n uint _286 = path.bbox.y;\n uint _287 = _284 - _286;\n uint _288 = _282 * _287;\n uint _290 = _288 * 8u;\n uint _293 = path.tiles.offset;\n uint param_5 = _293;\n uint param_6 = _290;\n Alloc _295 = new_alloc(param_5, param_6);\n Alloc path_alloc = _295;\n Alloc _300 = path_alloc;\n sh_row_alloc[th_ix] = _300;\n break;\n }\n }\n }\n sh_row_count[th_ix] = row_count;\n for (uint i = 0u; i < 7u; i++)\n {\n barrier();\n if (th_ix >= uint(1 << int(i)))\n {\n row_count += sh_row_count[th_ix - uint(1 << int(i))];\n }\n barrier();\n sh_row_count[th_ix] = row_count;\n }\n barrier();\n uint total_rows = sh_row_count[127];\n uint _396;\n for (uint row = th_ix; row < total_rows; row += 128u)\n {\n uint el_ix = 0u;\n for (uint i_1 = 0u; i_1 < 7u; i_1++)\n {\n uint probe = el_ix + uint(64 >> int(i_1));\n if (row >= sh_row_count[probe - 1u])\n {\n el_ix = probe;\n }\n }\n uint width = sh_row_width[el_ix];\n if (width > 0u)\n {\n Alloc tiles_alloc = sh_row_alloc[el_ix];\n if (el_ix > 0u)\n {\n _396 = sh_row_count[el_ix - 1u];\n }\n else\n {\n _396 = 0u;\n }\n uint seq_ix = row - _396;\n uint tile_el_ix = ((tiles_alloc.offset >> uint(2)) + 1u) + ((seq_ix * 2u) * width);\n Alloc param_7 = tiles_alloc;\n uint param_8 = tile_el_ix;\n uint sum = read_mem(param_7, param_8);\n for (uint x = 1u; x < width; x++)\n {\n tile_el_ix += 2u;\n Alloc param_9 = tiles_alloc;\n uint param_10 = tile_el_ix;\n sum += read_mem(param_9, param_10);\n Alloc param_11 = tiles_alloc;\n uint param_12 = tile_el_ix;\n uint param_13 = sum;\n write_mem(param_11, param_12, param_13);\n }\n }\n }\n}\n\n", } shader_binning_comp = driver.ShaderSources{ Name: "binning.comp", - GLSL310ES: "#version 310 es\nlayout(local_size_x = 128, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct MallocResult\n{\n Alloc alloc;\n bool failed;\n};\n\nstruct AnnoFillRef\n{\n uint offset;\n};\n\nstruct AnnoFill\n{\n vec4 bbox;\n uint rgba_color;\n};\n\nstruct AnnotatedRef\n{\n uint offset;\n};\n\nstruct BinInstanceRef\n{\n uint offset;\n};\n\nstruct BinInstance\n{\n uint element_ix;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _87;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _254;\n\nshared uint bitmaps[4][128];\nshared bool sh_alloc_failed;\nshared uint count[4][128];\nshared Alloc sh_chunk_alloc[128];\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _87.memory[offset];\n return v;\n}\n\nuint Annotated_tag(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n return read_mem(param, param_1);\n}\n\nAnnoFill AnnoFill_read(Alloc a, AnnoFillRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n AnnoFill s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.rgba_color = raw4;\n return s;\n}\n\nAnnoFill Annotated_Fill_read(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n AnnoFillRef param_1 = AnnoFillRef(ref.offset + 4u);\n return AnnoFill_read(param, param_1);\n}\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nMallocResult malloc(uint size)\n{\n MallocResult r;\n r.failed = false;\n uint _93 = atomicAdd(_87.mem_offset, size);\n uint offset = _93;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_87.memory.length())) * 4))\n {\n r.failed = true;\n uint _114 = atomicMax(_87.mem_error, 1u);\n return r;\n }\n return r;\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _87.memory[offset] = val;\n}\n\nvoid BinInstance_write(Alloc a, BinInstanceRef ref, BinInstance s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.element_ix;\n write_mem(param, param_1, param_2);\n}\n\nvoid main()\n{\n if (_87.mem_error != 0u)\n {\n return;\n }\n uint my_n_elements = _254.conf.n_elements;\n uint my_partition = gl_WorkGroupID.x;\n for (uint i = 0u; i < 4u; i++)\n {\n bitmaps[i][gl_LocalInvocationID.x] = 0u;\n }\n if (gl_LocalInvocationID.x == 0u)\n {\n sh_alloc_failed = false;\n }\n barrier();\n uint element_ix = (my_partition * 128u) + gl_LocalInvocationID.x;\n AnnotatedRef ref = AnnotatedRef(_254.conf.anno_alloc.offset + (element_ix * 28u));\n uint tag = 0u;\n if (element_ix < my_n_elements)\n {\n Alloc param;\n param.offset = _254.conf.anno_alloc.offset;\n AnnotatedRef param_1 = ref;\n tag = Annotated_tag(param, param_1);\n }\n int x0 = 0;\n int y0 = 0;\n int x1 = 0;\n int y1 = 0;\n switch (tag)\n {\n case 2u:\n case 3u:\n case 1u:\n case 4u:\n case 5u:\n {\n Alloc param_2;\n param_2.offset = _254.conf.anno_alloc.offset;\n AnnotatedRef param_3 = ref;\n AnnoFill fill = Annotated_Fill_read(param_2, param_3);\n x0 = int(floor(fill.bbox.x * 0.001953125));\n y0 = int(floor(fill.bbox.y * 0.00390625));\n x1 = int(ceil(fill.bbox.z * 0.001953125));\n y1 = int(ceil(fill.bbox.w * 0.00390625));\n break;\n }\n }\n uint width_in_bins = ((_254.conf.width_in_tiles + 16u) - 1u) / 16u;\n uint height_in_bins = ((_254.conf.height_in_tiles + 8u) - 1u) / 8u;\n x0 = clamp(x0, 0, int(width_in_bins));\n x1 = clamp(x1, x0, int(width_in_bins));\n y0 = clamp(y0, 0, int(height_in_bins));\n y1 = clamp(y1, y0, int(height_in_bins));\n if (x0 == x1)\n {\n y1 = y0;\n }\n int x = x0;\n int y = y0;\n uint my_slice = gl_LocalInvocationID.x / 32u;\n uint my_mask = uint(1 << int(gl_LocalInvocationID.x & 31u));\n while (y < y1)\n {\n uint _438 = atomicOr(bitmaps[my_slice][(uint(y) * width_in_bins) + uint(x)], my_mask);\n x++;\n if (x == x1)\n {\n x = x0;\n y++;\n }\n }\n barrier();\n uint element_count = 0u;\n for (uint i_1 = 0u; i_1 < 4u; i_1++)\n {\n element_count += uint(bitCount(bitmaps[i_1][gl_LocalInvocationID.x]));\n count[i_1][gl_LocalInvocationID.x] = element_count;\n }\n uint param_4 = 0u;\n uint param_5 = 0u;\n Alloc chunk_alloc = new_alloc(param_4, param_5);\n if (element_count != 0u)\n {\n uint param_6 = element_count * 4u;\n MallocResult _487 = malloc(param_6);\n MallocResult chunk = _487;\n chunk_alloc = chunk.alloc;\n sh_chunk_alloc[gl_LocalInvocationID.x] = chunk_alloc;\n if (chunk.failed)\n {\n sh_alloc_failed = true;\n }\n }\n uint out_ix = (_254.conf.bin_alloc.offset >> uint(2)) + (((my_partition * 128u) + gl_LocalInvocationID.x) * 2u);\n Alloc param_7;\n param_7.offset = _254.conf.bin_alloc.offset;\n uint param_8 = out_ix;\n uint param_9 = element_count;\n write_mem(param_7, param_8, param_9);\n Alloc param_10;\n param_10.offset = _254.conf.bin_alloc.offset;\n uint param_11 = out_ix + 1u;\n uint param_12 = chunk_alloc.offset;\n write_mem(param_10, param_11, param_12);\n barrier();\n if (sh_alloc_failed)\n {\n return;\n }\n x = x0;\n y = y0;\n while (y < y1)\n {\n uint bin_ix = (uint(y) * width_in_bins) + uint(x);\n uint out_mask = bitmaps[my_slice][bin_ix];\n if ((out_mask & my_mask) != 0u)\n {\n uint idx = uint(bitCount(out_mask & (my_mask - 1u)));\n if (my_slice > 0u)\n {\n idx += count[my_slice - 1u][bin_ix];\n }\n Alloc out_alloc = sh_chunk_alloc[bin_ix];\n uint out_offset = out_alloc.offset + (idx * 4u);\n Alloc param_13 = out_alloc;\n BinInstanceRef param_14 = BinInstanceRef(out_offset);\n BinInstance param_15 = BinInstance(element_ix);\n BinInstance_write(param_13, param_14, param_15);\n }\n x++;\n if (x == x1)\n {\n x = x0;\n y++;\n }\n }\n}\n\n", + GLSL310ES: "#version 310 es\nlayout(local_size_x = 128, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct MallocResult\n{\n Alloc alloc;\n bool failed;\n};\n\nstruct AnnoEndClipRef\n{\n uint offset;\n};\n\nstruct AnnoEndClip\n{\n vec4 bbox;\n};\n\nstruct AnnotatedRef\n{\n uint offset;\n};\n\nstruct AnnotatedTag\n{\n uint tag;\n uint flags;\n};\n\nstruct BinInstanceRef\n{\n uint offset;\n};\n\nstruct BinInstance\n{\n uint element_ix;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _88;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _254;\n\nshared uint bitmaps[4][128];\nshared bool sh_alloc_failed;\nshared uint count[4][128];\nshared Alloc sh_chunk_alloc[128];\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _88.memory[offset];\n return v;\n}\n\nAnnotatedTag Annotated_tag(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint tag_and_flags = read_mem(param, param_1);\n return AnnotatedTag(tag_and_flags & 65535u, tag_and_flags >> uint(16));\n}\n\nAnnoEndClip AnnoEndClip_read(Alloc a, AnnoEndClipRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n AnnoEndClip s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n return s;\n}\n\nAnnoEndClip Annotated_EndClip_read(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n AnnoEndClipRef param_1 = AnnoEndClipRef(ref.offset + 4u);\n return AnnoEndClip_read(param, param_1);\n}\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nMallocResult malloc(uint size)\n{\n MallocResult r;\n r.failed = false;\n uint _94 = atomicAdd(_88.mem_offset, size);\n uint offset = _94;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_88.memory.length())) * 4))\n {\n r.failed = true;\n uint _115 = atomicMax(_88.mem_error, 1u);\n return r;\n }\n return r;\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _88.memory[offset] = val;\n}\n\nvoid BinInstance_write(Alloc a, BinInstanceRef ref, BinInstance s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.element_ix;\n write_mem(param, param_1, param_2);\n}\n\nvoid main()\n{\n if (_88.mem_error != 0u)\n {\n return;\n }\n uint my_n_elements = _254.conf.n_elements;\n uint my_partition = gl_WorkGroupID.x;\n for (uint i = 0u; i < 4u; i++)\n {\n bitmaps[i][gl_LocalInvocationID.x] = 0u;\n }\n if (gl_LocalInvocationID.x == 0u)\n {\n sh_alloc_failed = false;\n }\n barrier();\n uint element_ix = (my_partition * 128u) + gl_LocalInvocationID.x;\n AnnotatedRef ref = AnnotatedRef(_254.conf.anno_alloc.offset + (element_ix * 32u));\n uint tag = 0u;\n if (element_ix < my_n_elements)\n {\n Alloc param;\n param.offset = _254.conf.anno_alloc.offset;\n AnnotatedRef param_1 = ref;\n tag = Annotated_tag(param, param_1).tag;\n }\n int x0 = 0;\n int y0 = 0;\n int x1 = 0;\n int y1 = 0;\n switch (tag)\n {\n case 1u:\n case 2u:\n case 3u:\n case 4u:\n {\n Alloc param_2;\n param_2.offset = _254.conf.anno_alloc.offset;\n AnnotatedRef param_3 = ref;\n AnnoEndClip clip = Annotated_EndClip_read(param_2, param_3);\n x0 = int(floor(clip.bbox.x * 0.001953125));\n y0 = int(floor(clip.bbox.y * 0.00390625));\n x1 = int(ceil(clip.bbox.z * 0.001953125));\n y1 = int(ceil(clip.bbox.w * 0.00390625));\n break;\n }\n }\n uint width_in_bins = ((_254.conf.width_in_tiles + 16u) - 1u) / 16u;\n uint height_in_bins = ((_254.conf.height_in_tiles + 8u) - 1u) / 8u;\n x0 = clamp(x0, 0, int(width_in_bins));\n x1 = clamp(x1, x0, int(width_in_bins));\n y0 = clamp(y0, 0, int(height_in_bins));\n y1 = clamp(y1, y0, int(height_in_bins));\n if (x0 == x1)\n {\n y1 = y0;\n }\n int x = x0;\n int y = y0;\n uint my_slice = gl_LocalInvocationID.x / 32u;\n uint my_mask = uint(1 << int(gl_LocalInvocationID.x & 31u));\n while (y < y1)\n {\n uint _438 = atomicOr(bitmaps[my_slice][(uint(y) * width_in_bins) + uint(x)], my_mask);\n x++;\n if (x == x1)\n {\n x = x0;\n y++;\n }\n }\n barrier();\n uint element_count = 0u;\n for (uint i_1 = 0u; i_1 < 4u; i_1++)\n {\n element_count += uint(bitCount(bitmaps[i_1][gl_LocalInvocationID.x]));\n count[i_1][gl_LocalInvocationID.x] = element_count;\n }\n uint param_4 = 0u;\n uint param_5 = 0u;\n Alloc chunk_alloc = new_alloc(param_4, param_5);\n if (element_count != 0u)\n {\n uint param_6 = element_count * 4u;\n MallocResult _487 = malloc(param_6);\n MallocResult chunk = _487;\n chunk_alloc = chunk.alloc;\n sh_chunk_alloc[gl_LocalInvocationID.x] = chunk_alloc;\n if (chunk.failed)\n {\n sh_alloc_failed = true;\n }\n }\n uint out_ix = (_254.conf.bin_alloc.offset >> uint(2)) + (((my_partition * 128u) + gl_LocalInvocationID.x) * 2u);\n Alloc param_7;\n param_7.offset = _254.conf.bin_alloc.offset;\n uint param_8 = out_ix;\n uint param_9 = element_count;\n write_mem(param_7, param_8, param_9);\n Alloc param_10;\n param_10.offset = _254.conf.bin_alloc.offset;\n uint param_11 = out_ix + 1u;\n uint param_12 = chunk_alloc.offset;\n write_mem(param_10, param_11, param_12);\n barrier();\n if (sh_alloc_failed)\n {\n return;\n }\n x = x0;\n y = y0;\n while (y < y1)\n {\n uint bin_ix = (uint(y) * width_in_bins) + uint(x);\n uint out_mask = bitmaps[my_slice][bin_ix];\n if ((out_mask & my_mask) != 0u)\n {\n uint idx = uint(bitCount(out_mask & (my_mask - 1u)));\n if (my_slice > 0u)\n {\n idx += count[my_slice - 1u][bin_ix];\n }\n Alloc out_alloc = sh_chunk_alloc[bin_ix];\n uint out_offset = out_alloc.offset + (idx * 4u);\n Alloc param_13 = out_alloc;\n BinInstanceRef param_14 = BinInstanceRef(out_offset);\n BinInstance param_15 = BinInstance(element_ix);\n BinInstance_write(param_13, param_14, param_15);\n }\n x++;\n if (x == x1)\n {\n x = x0;\n y++;\n }\n }\n}\n\n", } shader_blit_frag = [...]driver.ShaderSources{ { @@ -66,7 +66,7 @@ var ( } shader_coarse_comp = driver.ShaderSources{ Name: "coarse.comp", - GLSL310ES: "#version 310 es\nlayout(local_size_x = 128, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct MallocResult\n{\n Alloc alloc;\n bool failed;\n};\n\nstruct AnnoFillRef\n{\n uint offset;\n};\n\nstruct AnnoFill\n{\n vec4 bbox;\n uint rgba_color;\n};\n\nstruct AnnoFillImageRef\n{\n uint offset;\n};\n\nstruct AnnoFillImage\n{\n vec4 bbox;\n uint index;\n ivec2 offset;\n};\n\nstruct AnnoStrokeRef\n{\n uint offset;\n};\n\nstruct AnnoStroke\n{\n vec4 bbox;\n uint rgba_color;\n float linewidth;\n};\n\nstruct AnnotatedRef\n{\n uint offset;\n};\n\nstruct BinInstanceRef\n{\n uint offset;\n};\n\nstruct BinInstance\n{\n uint element_ix;\n};\n\nstruct PathRef\n{\n uint offset;\n};\n\nstruct TileRef\n{\n uint offset;\n};\n\nstruct Path\n{\n uvec4 bbox;\n TileRef tiles;\n};\n\nstruct TileSegRef\n{\n uint offset;\n};\n\nstruct Tile\n{\n TileSegRef tile;\n int backdrop;\n};\n\nstruct CmdStrokeRef\n{\n uint offset;\n};\n\nstruct CmdStroke\n{\n uint tile_ref;\n float half_width;\n uint rgba_color;\n};\n\nstruct CmdFillRef\n{\n uint offset;\n};\n\nstruct CmdFill\n{\n uint tile_ref;\n int backdrop;\n uint rgba_color;\n};\n\nstruct CmdFillImageRef\n{\n uint offset;\n};\n\nstruct CmdFillImage\n{\n uint tile_ref;\n int backdrop;\n uint index;\n ivec2 offset;\n};\n\nstruct CmdBeginClipRef\n{\n uint offset;\n};\n\nstruct CmdBeginClip\n{\n uint tile_ref;\n int backdrop;\n};\n\nstruct CmdBeginSolidClipRef\n{\n uint offset;\n};\n\nstruct CmdBeginSolidClip\n{\n float alpha;\n};\n\nstruct CmdEndClipRef\n{\n uint offset;\n};\n\nstruct CmdEndClip\n{\n float alpha;\n};\n\nstruct CmdSolidRef\n{\n uint offset;\n};\n\nstruct CmdSolid\n{\n uint rgba_color;\n};\n\nstruct CmdSolidImageRef\n{\n uint offset;\n};\n\nstruct CmdSolidImage\n{\n uint index;\n ivec2 offset;\n};\n\nstruct CmdJumpRef\n{\n uint offset;\n};\n\nstruct CmdJump\n{\n uint new_ref;\n};\n\nstruct CmdRef\n{\n uint offset;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _307;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _1176;\n\nshared uint sh_bitmaps[4][128];\nshared Alloc sh_part_elements[128];\nshared uint sh_part_count[128];\nshared uint sh_elements[128];\nshared uint sh_tile_stride[128];\nshared uint sh_tile_width[128];\nshared uint sh_tile_x0[128];\nshared uint sh_tile_y0[128];\nshared uint sh_tile_base[128];\nshared uint sh_tile_count[128];\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nAlloc slice_mem(Alloc a, uint offset, uint size)\n{\n uint param = a.offset + offset;\n uint param_1 = size;\n return new_alloc(param, param_1);\n}\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _307.memory[offset];\n return v;\n}\n\nBinInstanceRef BinInstance_index(BinInstanceRef ref, uint index)\n{\n return BinInstanceRef(ref.offset + (index * 4u));\n}\n\nBinInstance BinInstance_read(Alloc a, BinInstanceRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n BinInstance s;\n s.element_ix = raw0;\n return s;\n}\n\nuint Annotated_tag(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n return read_mem(param, param_1);\n}\n\nPath Path_read(Alloc a, PathRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Path s;\n s.bbox = uvec4(raw0 & 65535u, raw0 >> uint(16), raw1 & 65535u, raw1 >> uint(16));\n s.tiles = TileRef(raw2);\n return s;\n}\n\nvoid write_tile_alloc(uint el_ix, Alloc a)\n{\n}\n\nAlloc read_tile_alloc(uint el_ix)\n{\n uint param = 0u;\n uint param_1 = uint(int(uint(_307.memory.length())) * 4);\n return new_alloc(param, param_1);\n}\n\nTile Tile_read(Alloc a, TileRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Tile s;\n s.tile = TileSegRef(raw0);\n s.backdrop = int(raw1);\n return s;\n}\n\nAnnoFill AnnoFill_read(Alloc a, AnnoFillRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n AnnoFill s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.rgba_color = raw4;\n return s;\n}\n\nAnnoFill Annotated_Fill_read(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n AnnoFillRef param_1 = AnnoFillRef(ref.offset + 4u);\n return AnnoFill_read(param, param_1);\n}\n\nMallocResult malloc(uint size)\n{\n MallocResult r;\n r.failed = false;\n uint _313 = atomicAdd(_307.mem_offset, size);\n uint offset = _313;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_307.memory.length())) * 4))\n {\n r.failed = true;\n uint _334 = atomicMax(_307.mem_error, 1u);\n return r;\n }\n return r;\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _307.memory[offset] = val;\n}\n\nvoid CmdJump_write(Alloc a, CmdJumpRef ref, CmdJump s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.new_ref;\n write_mem(param, param_1, param_2);\n}\n\nvoid Cmd_Jump_write(Alloc a, CmdRef ref, CmdJump s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 9u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdJumpRef param_4 = CmdJumpRef(ref.offset + 4u);\n CmdJump param_5 = s;\n CmdJump_write(param_3, param_4, param_5);\n}\n\nbool alloc_cmd(inout Alloc cmd_alloc, inout CmdRef cmd_ref, inout uint cmd_limit)\n{\n if (cmd_ref.offset < cmd_limit)\n {\n return true;\n }\n uint param = 1024u;\n MallocResult _1136 = malloc(param);\n MallocResult new_cmd = _1136;\n if (new_cmd.failed)\n {\n return false;\n }\n CmdJump jump = CmdJump(new_cmd.alloc.offset);\n Alloc param_1 = cmd_alloc;\n CmdRef param_2 = cmd_ref;\n CmdJump param_3 = jump;\n Cmd_Jump_write(param_1, param_2, param_3);\n cmd_alloc = new_cmd.alloc;\n cmd_ref = CmdRef(cmd_alloc.offset);\n cmd_limit = (cmd_alloc.offset + 1024u) - 40u;\n return true;\n}\n\nvoid CmdFill_write(Alloc a, CmdFillRef ref, CmdFill s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.tile_ref;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = uint(s.backdrop);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = s.rgba_color;\n write_mem(param_6, param_7, param_8);\n}\n\nvoid Cmd_Fill_write(Alloc a, CmdRef ref, CmdFill s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 1u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdFillRef param_4 = CmdFillRef(ref.offset + 4u);\n CmdFill param_5 = s;\n CmdFill_write(param_3, param_4, param_5);\n}\n\nvoid CmdSolid_write(Alloc a, CmdSolidRef ref, CmdSolid s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.rgba_color;\n write_mem(param, param_1, param_2);\n}\n\nvoid Cmd_Solid_write(Alloc a, CmdRef ref, CmdSolid s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 7u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdSolidRef param_4 = CmdSolidRef(ref.offset + 4u);\n CmdSolid param_5 = s;\n CmdSolid_write(param_3, param_4, param_5);\n}\n\nAnnoFillImage AnnoFillImage_read(Alloc a, AnnoFillImageRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n Alloc param_10 = a;\n uint param_11 = ix + 5u;\n uint raw5 = read_mem(param_10, param_11);\n AnnoFillImage s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.index = raw4;\n s.offset = ivec2(int(raw5 << uint(16)) >> 16, int(raw5) >> 16);\n return s;\n}\n\nAnnoFillImage Annotated_FillImage_read(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n AnnoFillImageRef param_1 = AnnoFillImageRef(ref.offset + 4u);\n return AnnoFillImage_read(param, param_1);\n}\n\nvoid CmdFillImage_write(Alloc a, CmdFillImageRef ref, CmdFillImage s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.tile_ref;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = uint(s.backdrop);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = s.index;\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = (uint(s.offset.x) & 65535u) | (uint(s.offset.y) << uint(16));\n write_mem(param_9, param_10, param_11);\n}\n\nvoid Cmd_FillImage_write(Alloc a, CmdRef ref, CmdFillImage s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 2u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdFillImageRef param_4 = CmdFillImageRef(ref.offset + 4u);\n CmdFillImage param_5 = s;\n CmdFillImage_write(param_3, param_4, param_5);\n}\n\nvoid CmdSolidImage_write(Alloc a, CmdSolidImageRef ref, CmdSolidImage s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.index;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = (uint(s.offset.x) & 65535u) | (uint(s.offset.y) << uint(16));\n write_mem(param_3, param_4, param_5);\n}\n\nvoid Cmd_SolidImage_write(Alloc a, CmdRef ref, CmdSolidImage s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 8u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdSolidImageRef param_4 = CmdSolidImageRef(ref.offset + 4u);\n CmdSolidImage param_5 = s;\n CmdSolidImage_write(param_3, param_4, param_5);\n}\n\nvoid CmdBeginClip_write(Alloc a, CmdBeginClipRef ref, CmdBeginClip s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.tile_ref;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = uint(s.backdrop);\n write_mem(param_3, param_4, param_5);\n}\n\nvoid Cmd_BeginClip_write(Alloc a, CmdRef ref, CmdBeginClip s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 3u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdBeginClipRef param_4 = CmdBeginClipRef(ref.offset + 4u);\n CmdBeginClip param_5 = s;\n CmdBeginClip_write(param_3, param_4, param_5);\n}\n\nvoid CmdBeginSolidClip_write(Alloc a, CmdBeginSolidClipRef ref, CmdBeginSolidClip s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.alpha);\n write_mem(param, param_1, param_2);\n}\n\nvoid Cmd_BeginSolidClip_write(Alloc a, CmdRef ref, CmdBeginSolidClip s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 4u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdBeginSolidClipRef param_4 = CmdBeginSolidClipRef(ref.offset + 4u);\n CmdBeginSolidClip param_5 = s;\n CmdBeginSolidClip_write(param_3, param_4, param_5);\n}\n\nvoid CmdEndClip_write(Alloc a, CmdEndClipRef ref, CmdEndClip s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.alpha);\n write_mem(param, param_1, param_2);\n}\n\nvoid Cmd_EndClip_write(Alloc a, CmdRef ref, CmdEndClip s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 5u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdEndClipRef param_4 = CmdEndClipRef(ref.offset + 4u);\n CmdEndClip param_5 = s;\n CmdEndClip_write(param_3, param_4, param_5);\n}\n\nAnnoStroke AnnoStroke_read(Alloc a, AnnoStrokeRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n Alloc param_10 = a;\n uint param_11 = ix + 5u;\n uint raw5 = read_mem(param_10, param_11);\n AnnoStroke s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.rgba_color = raw4;\n s.linewidth = uintBitsToFloat(raw5);\n return s;\n}\n\nAnnoStroke Annotated_Stroke_read(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n AnnoStrokeRef param_1 = AnnoStrokeRef(ref.offset + 4u);\n return AnnoStroke_read(param, param_1);\n}\n\nvoid CmdStroke_write(Alloc a, CmdStrokeRef ref, CmdStroke s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.tile_ref;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.half_width);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = s.rgba_color;\n write_mem(param_6, param_7, param_8);\n}\n\nvoid Cmd_Stroke_write(Alloc a, CmdRef ref, CmdStroke s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 6u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdStrokeRef param_4 = CmdStrokeRef(ref.offset + 4u);\n CmdStroke param_5 = s;\n CmdStroke_write(param_3, param_4, param_5);\n}\n\nvoid Cmd_End_write(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 0u;\n write_mem(param, param_1, param_2);\n}\n\nvoid main()\n{\n if (_307.mem_error != 0u)\n {\n return;\n }\n uint width_in_bins = ((_1176.conf.width_in_tiles + 16u) - 1u) / 16u;\n uint bin_ix = (width_in_bins * gl_WorkGroupID.y) + gl_WorkGroupID.x;\n uint partition_ix = 0u;\n uint n_partitions = ((_1176.conf.n_elements + 128u) - 1u) / 128u;\n uint th_ix = gl_LocalInvocationID.x;\n uint bin_tile_x = 16u * gl_WorkGroupID.x;\n uint bin_tile_y = 8u * gl_WorkGroupID.y;\n uint tile_x = gl_LocalInvocationID.x % 16u;\n uint tile_y = gl_LocalInvocationID.x / 16u;\n uint this_tile_ix = (((bin_tile_y + tile_y) * _1176.conf.width_in_tiles) + bin_tile_x) + tile_x;\n Alloc param;\n param.offset = _1176.conf.ptcl_alloc.offset;\n uint param_1 = this_tile_ix * 1024u;\n uint param_2 = 1024u;\n Alloc cmd_alloc = slice_mem(param, param_1, param_2);\n CmdRef cmd_ref = CmdRef(cmd_alloc.offset);\n uint cmd_limit = (cmd_ref.offset + 1024u) - 40u;\n uint clip_depth = 0u;\n uint clip_zero_depth = 0u;\n uint clip_one_mask = 0u;\n uint rd_ix = 0u;\n uint wr_ix = 0u;\n uint part_start_ix = 0u;\n uint ready_ix = 0u;\n Alloc param_3;\n Alloc param_5;\n uint _1452;\n uint element_ix;\n AnnotatedRef ref;\n Alloc param_13;\n Alloc param_15;\n uint tile_count;\n Alloc param_21;\n uint _1764;\n bool include_tile;\n Alloc param_26;\n Tile tile_1;\n Alloc param_31;\n CmdFill cmd_fill;\n Alloc param_45;\n CmdFillImage cmd_fill_img;\n CmdSolidImage cmd_solid_img;\n CmdBeginClip cmd_begin_clip;\n Alloc param_77;\n CmdStroke cmd_stroke;\n while (true)\n {\n for (uint i = 0u; i < 4u; i++)\n {\n sh_bitmaps[i][th_ix] = 0u;\n }\n bool _1504;\n for (;;)\n {\n if ((ready_ix == wr_ix) && (partition_ix < n_partitions))\n {\n part_start_ix = ready_ix;\n uint count = 0u;\n bool _1302 = th_ix < 128u;\n bool _1310;\n if (_1302)\n {\n _1310 = (partition_ix + th_ix) < n_partitions;\n }\n else\n {\n _1310 = _1302;\n }\n if (_1310)\n {\n uint in_ix = (_1176.conf.bin_alloc.offset >> uint(2)) + ((((partition_ix + th_ix) * 128u) + bin_ix) * 2u);\n param_3.offset = _1176.conf.bin_alloc.offset;\n uint param_4 = in_ix;\n count = read_mem(param_3, param_4);\n param_5.offset = _1176.conf.bin_alloc.offset;\n uint param_6 = in_ix + 1u;\n uint offset = read_mem(param_5, param_6);\n uint param_7 = offset;\n uint param_8 = count * 4u;\n sh_part_elements[th_ix] = new_alloc(param_7, param_8);\n }\n for (uint i_1 = 0u; i_1 < 7u; i_1++)\n {\n if (th_ix < 128u)\n {\n sh_part_count[th_ix] = count;\n }\n barrier();\n if (th_ix < 128u)\n {\n if (th_ix >= uint(1 << int(i_1)))\n {\n count += sh_part_count[th_ix - uint(1 << int(i_1))];\n }\n }\n barrier();\n }\n if (th_ix < 128u)\n {\n sh_part_count[th_ix] = part_start_ix + count;\n }\n barrier();\n ready_ix = sh_part_count[127];\n partition_ix += 128u;\n }\n uint ix = rd_ix + th_ix;\n if ((ix >= wr_ix) && (ix < ready_ix))\n {\n uint part_ix = 0u;\n for (uint i_2 = 0u; i_2 < 7u; i_2++)\n {\n uint probe = part_ix + uint(64 >> int(i_2));\n if (ix >= sh_part_count[probe - 1u])\n {\n part_ix = probe;\n }\n }\n if (part_ix > 0u)\n {\n _1452 = sh_part_count[part_ix - 1u];\n }\n else\n {\n _1452 = part_start_ix;\n }\n ix -= _1452;\n Alloc bin_alloc = sh_part_elements[part_ix];\n BinInstanceRef inst_ref = BinInstanceRef(bin_alloc.offset);\n BinInstanceRef param_9 = inst_ref;\n uint param_10 = ix;\n Alloc param_11 = bin_alloc;\n BinInstanceRef param_12 = BinInstance_index(param_9, param_10);\n BinInstance inst = BinInstance_read(param_11, param_12);\n sh_elements[th_ix] = inst.element_ix;\n }\n barrier();\n wr_ix = min((rd_ix + 128u), ready_ix);\n bool _1494 = (wr_ix - rd_ix) < 128u;\n if (_1494)\n {\n _1504 = (wr_ix < ready_ix) || (partition_ix < n_partitions);\n }\n else\n {\n _1504 = _1494;\n }\n if (_1504)\n {\n continue;\n }\n else\n {\n break;\n }\n }\n uint tag = 0u;\n if ((th_ix + rd_ix) < wr_ix)\n {\n element_ix = sh_elements[th_ix];\n ref = AnnotatedRef(_1176.conf.anno_alloc.offset + (element_ix * 28u));\n param_13.offset = _1176.conf.anno_alloc.offset;\n AnnotatedRef param_14 = ref;\n tag = Annotated_tag(param_13, param_14);\n }\n switch (tag)\n {\n case 2u:\n case 3u:\n case 1u:\n case 4u:\n case 5u:\n {\n uint path_ix = element_ix;\n param_15.offset = _1176.conf.tile_alloc.offset;\n PathRef param_16 = PathRef(_1176.conf.tile_alloc.offset + (path_ix * 12u));\n Path path = Path_read(param_15, param_16);\n uint stride = path.bbox.z - path.bbox.x;\n sh_tile_stride[th_ix] = stride;\n int dx = int(path.bbox.x) - int(bin_tile_x);\n int dy = int(path.bbox.y) - int(bin_tile_y);\n int x0 = clamp(dx, 0, 16);\n int y0 = clamp(dy, 0, 8);\n int x1 = clamp(int(path.bbox.z) - int(bin_tile_x), 0, 16);\n int y1 = clamp(int(path.bbox.w) - int(bin_tile_y), 0, 8);\n sh_tile_width[th_ix] = uint(x1 - x0);\n sh_tile_x0[th_ix] = uint(x0);\n sh_tile_y0[th_ix] = uint(y0);\n tile_count = uint(x1 - x0) * uint(y1 - y0);\n uint base = path.tiles.offset - (((uint(dy) * stride) + uint(dx)) * 8u);\n sh_tile_base[th_ix] = base;\n uint param_17 = path.tiles.offset;\n uint param_18 = ((path.bbox.z - path.bbox.x) * (path.bbox.w - path.bbox.y)) * 8u;\n Alloc path_alloc = new_alloc(param_17, param_18);\n uint param_19 = th_ix;\n Alloc param_20 = path_alloc;\n write_tile_alloc(param_19, param_20);\n break;\n }\n default:\n {\n tile_count = 0u;\n break;\n }\n }\n sh_tile_count[th_ix] = tile_count;\n for (uint i_3 = 0u; i_3 < 7u; i_3++)\n {\n barrier();\n if (th_ix >= uint(1 << int(i_3)))\n {\n tile_count += sh_tile_count[th_ix - uint(1 << int(i_3))];\n }\n barrier();\n sh_tile_count[th_ix] = tile_count;\n }\n barrier();\n uint total_tile_count = sh_tile_count[127];\n for (uint ix_1 = th_ix; ix_1 < total_tile_count; ix_1 += 128u)\n {\n uint el_ix = 0u;\n for (uint i_4 = 0u; i_4 < 7u; i_4++)\n {\n uint probe_1 = el_ix + uint(64 >> int(i_4));\n if (ix_1 >= sh_tile_count[probe_1 - 1u])\n {\n el_ix = probe_1;\n }\n }\n AnnotatedRef ref_1 = AnnotatedRef(_1176.conf.anno_alloc.offset + (sh_elements[el_ix] * 28u));\n param_21.offset = _1176.conf.anno_alloc.offset;\n AnnotatedRef param_22 = ref_1;\n uint tag_1 = Annotated_tag(param_21, param_22);\n if (el_ix > 0u)\n {\n _1764 = sh_tile_count[el_ix - 1u];\n }\n else\n {\n _1764 = 0u;\n }\n uint seq_ix = ix_1 - _1764;\n uint width = sh_tile_width[el_ix];\n uint x = sh_tile_x0[el_ix] + (seq_ix % width);\n uint y = sh_tile_y0[el_ix] + (seq_ix / width);\n if ((tag_1 == 4u) || (tag_1 == 5u))\n {\n include_tile = true;\n }\n else\n {\n uint param_23 = el_ix;\n Alloc param_24 = read_tile_alloc(param_23);\n TileRef param_25 = TileRef(sh_tile_base[el_ix] + (((sh_tile_stride[el_ix] * y) + x) * 8u));\n Tile tile = Tile_read(param_24, param_25);\n bool _1825 = tile.tile.offset != 0u;\n bool _1832;\n if (!_1825)\n {\n _1832 = tile.backdrop != 0;\n }\n else\n {\n _1832 = _1825;\n }\n include_tile = _1832;\n }\n if (include_tile)\n {\n uint el_slice = el_ix / 32u;\n uint el_mask = uint(1 << int(el_ix & 31u));\n uint _1853 = atomicOr(sh_bitmaps[el_slice][(y * 16u) + x], el_mask);\n }\n }\n barrier();\n uint slice_ix = 0u;\n uint bitmap = sh_bitmaps[0][th_ix];\n while (true)\n {\n if (bitmap == 0u)\n {\n slice_ix++;\n if (slice_ix == 4u)\n {\n break;\n }\n bitmap = sh_bitmaps[slice_ix][th_ix];\n if (bitmap == 0u)\n {\n continue;\n }\n }\n uint element_ref_ix = (slice_ix * 32u) + uint(findLSB(bitmap));\n uint element_ix_1 = sh_elements[element_ref_ix];\n bitmap &= (bitmap - 1u);\n ref = AnnotatedRef(_1176.conf.anno_alloc.offset + (element_ix_1 * 28u));\n param_26.offset = _1176.conf.anno_alloc.offset;\n AnnotatedRef param_27 = ref;\n tag = Annotated_tag(param_26, param_27);\n if (clip_zero_depth == 0u)\n {\n switch (tag)\n {\n case 2u:\n {\n uint param_28 = element_ref_ix;\n Alloc param_29 = read_tile_alloc(param_28);\n TileRef param_30 = TileRef(sh_tile_base[element_ref_ix] + (((sh_tile_stride[element_ref_ix] * tile_y) + tile_x) * 8u));\n tile_1 = Tile_read(param_29, param_30);\n param_31.offset = _1176.conf.anno_alloc.offset;\n AnnotatedRef param_32 = ref;\n AnnoFill fill = Annotated_Fill_read(param_31, param_32);\n Alloc param_33 = cmd_alloc;\n CmdRef param_34 = cmd_ref;\n uint param_35 = cmd_limit;\n bool _1961 = alloc_cmd(param_33, param_34, param_35);\n cmd_alloc = param_33;\n cmd_ref = param_34;\n cmd_limit = param_35;\n if (!_1961)\n {\n break;\n }\n if (tile_1.tile.offset != 0u)\n {\n cmd_fill.tile_ref = tile_1.tile.offset;\n cmd_fill.backdrop = tile_1.backdrop;\n cmd_fill.rgba_color = fill.rgba_color;\n Alloc param_36 = cmd_alloc;\n CmdRef param_37 = cmd_ref;\n CmdFill param_38 = cmd_fill;\n Cmd_Fill_write(param_36, param_37, param_38);\n }\n else\n {\n Alloc param_39 = cmd_alloc;\n CmdRef param_40 = cmd_ref;\n CmdSolid param_41 = CmdSolid(fill.rgba_color);\n Cmd_Solid_write(param_39, param_40, param_41);\n }\n cmd_ref.offset += 20u;\n break;\n }\n case 3u:\n {\n uint param_42 = element_ref_ix;\n Alloc param_43 = read_tile_alloc(param_42);\n TileRef param_44 = TileRef(sh_tile_base[element_ref_ix] + (((sh_tile_stride[element_ref_ix] * tile_y) + tile_x) * 8u));\n tile_1 = Tile_read(param_43, param_44);\n param_45.offset = _1176.conf.anno_alloc.offset;\n AnnotatedRef param_46 = ref;\n AnnoFillImage fill_img = Annotated_FillImage_read(param_45, param_46);\n Alloc param_47 = cmd_alloc;\n CmdRef param_48 = cmd_ref;\n uint param_49 = cmd_limit;\n bool _2041 = alloc_cmd(param_47, param_48, param_49);\n cmd_alloc = param_47;\n cmd_ref = param_48;\n cmd_limit = param_49;\n if (!_2041)\n {\n break;\n }\n if (tile_1.tile.offset != 0u)\n {\n cmd_fill_img.tile_ref = tile_1.tile.offset;\n cmd_fill_img.backdrop = tile_1.backdrop;\n cmd_fill_img.index = fill_img.index;\n cmd_fill_img.offset = fill_img.offset;\n Alloc param_50 = cmd_alloc;\n CmdRef param_51 = cmd_ref;\n CmdFillImage param_52 = cmd_fill_img;\n Cmd_FillImage_write(param_50, param_51, param_52);\n }\n else\n {\n cmd_solid_img.index = fill_img.index;\n cmd_solid_img.offset = fill_img.offset;\n Alloc param_53 = cmd_alloc;\n CmdRef param_54 = cmd_ref;\n CmdSolidImage param_55 = cmd_solid_img;\n Cmd_SolidImage_write(param_53, param_54, param_55);\n }\n cmd_ref.offset += 20u;\n break;\n }\n case 4u:\n {\n uint param_56 = element_ref_ix;\n Alloc param_57 = read_tile_alloc(param_56);\n TileRef param_58 = TileRef(sh_tile_base[element_ref_ix] + (((sh_tile_stride[element_ref_ix] * tile_y) + tile_x) * 8u));\n tile_1 = Tile_read(param_57, param_58);\n bool _2115 = tile_1.tile.offset == 0u;\n bool _2121;\n if (_2115)\n {\n _2121 = tile_1.backdrop == 0;\n }\n else\n {\n _2121 = _2115;\n }\n if (_2121)\n {\n clip_zero_depth = clip_depth + 1u;\n }\n else\n {\n if ((tile_1.tile.offset == 0u) && (clip_depth < 32u))\n {\n clip_one_mask |= uint(1 << int(clip_depth));\n }\n else\n {\n Alloc param_59 = cmd_alloc;\n CmdRef param_60 = cmd_ref;\n uint param_61 = cmd_limit;\n bool _2147 = alloc_cmd(param_59, param_60, param_61);\n cmd_alloc = param_59;\n cmd_ref = param_60;\n cmd_limit = param_61;\n if (!_2147)\n {\n break;\n }\n if (tile_1.tile.offset != 0u)\n {\n cmd_begin_clip.tile_ref = tile_1.tile.offset;\n cmd_begin_clip.backdrop = tile_1.backdrop;\n Alloc param_62 = cmd_alloc;\n CmdRef param_63 = cmd_ref;\n CmdBeginClip param_64 = cmd_begin_clip;\n Cmd_BeginClip_write(param_62, param_63, param_64);\n }\n else\n {\n float alpha = (tile_1.backdrop == 0) ? 0.0 : 1.0;\n Alloc param_65 = cmd_alloc;\n CmdRef param_66 = cmd_ref;\n CmdBeginSolidClip param_67 = CmdBeginSolidClip(alpha);\n Cmd_BeginSolidClip_write(param_65, param_66, param_67);\n }\n cmd_ref.offset += 20u;\n if (clip_depth < 32u)\n {\n clip_one_mask &= uint(~(1 << int(clip_depth)));\n }\n }\n }\n clip_depth++;\n break;\n }\n case 5u:\n {\n clip_depth--;\n bool _2210 = clip_depth >= 32u;\n bool _2220;\n if (!_2210)\n {\n _2220 = (clip_one_mask & uint(1 << int(clip_depth))) == 0u;\n }\n else\n {\n _2220 = _2210;\n }\n if (_2220)\n {\n Alloc param_68 = cmd_alloc;\n CmdRef param_69 = cmd_ref;\n uint param_70 = cmd_limit;\n bool _2229 = alloc_cmd(param_68, param_69, param_70);\n cmd_alloc = param_68;\n cmd_ref = param_69;\n cmd_limit = param_70;\n if (!_2229)\n {\n break;\n }\n Alloc param_71 = cmd_alloc;\n CmdRef param_72 = cmd_ref;\n CmdEndClip param_73 = CmdEndClip(1.0);\n Cmd_EndClip_write(param_71, param_72, param_73);\n cmd_ref.offset += 20u;\n }\n break;\n }\n case 1u:\n {\n uint param_74 = element_ref_ix;\n Alloc param_75 = read_tile_alloc(param_74);\n TileRef param_76 = TileRef(sh_tile_base[element_ref_ix] + (((sh_tile_stride[element_ref_ix] * tile_y) + tile_x) * 8u));\n tile_1 = Tile_read(param_75, param_76);\n param_77.offset = _1176.conf.anno_alloc.offset;\n AnnotatedRef param_78 = ref;\n AnnoStroke stroke = Annotated_Stroke_read(param_77, param_78);\n cmd_stroke.tile_ref = tile_1.tile.offset;\n cmd_stroke.half_width = 0.5 * stroke.linewidth;\n cmd_stroke.rgba_color = stroke.rgba_color;\n Alloc param_79 = cmd_alloc;\n CmdRef param_80 = cmd_ref;\n uint param_81 = cmd_limit;\n bool _2295 = alloc_cmd(param_79, param_80, param_81);\n cmd_alloc = param_79;\n cmd_ref = param_80;\n cmd_limit = param_81;\n if (!_2295)\n {\n break;\n }\n Alloc param_82 = cmd_alloc;\n CmdRef param_83 = cmd_ref;\n CmdStroke param_84 = cmd_stroke;\n Cmd_Stroke_write(param_82, param_83, param_84);\n cmd_ref.offset += 20u;\n break;\n }\n }\n }\n else\n {\n switch (tag)\n {\n case 4u:\n {\n clip_depth++;\n break;\n }\n case 5u:\n {\n if (clip_depth == clip_zero_depth)\n {\n clip_zero_depth = 0u;\n }\n clip_depth--;\n break;\n }\n }\n }\n }\n barrier();\n rd_ix += 128u;\n if ((rd_ix >= ready_ix) && (partition_ix >= n_partitions))\n {\n break;\n }\n }\n bool _2350 = (bin_tile_x + tile_x) < _1176.conf.width_in_tiles;\n bool _2359;\n if (_2350)\n {\n _2359 = (bin_tile_y + tile_y) < _1176.conf.height_in_tiles;\n }\n else\n {\n _2359 = _2350;\n }\n if (_2359)\n {\n Alloc param_85 = cmd_alloc;\n CmdRef param_86 = cmd_ref;\n Cmd_End_write(param_85, param_86);\n }\n}\n\n", + GLSL310ES: "#version 310 es\nlayout(local_size_x = 128, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct MallocResult\n{\n Alloc alloc;\n bool failed;\n};\n\nstruct AnnoImageRef\n{\n uint offset;\n};\n\nstruct AnnoImage\n{\n vec4 bbox;\n float linewidth;\n uint index;\n ivec2 offset;\n};\n\nstruct AnnoColorRef\n{\n uint offset;\n};\n\nstruct AnnoColor\n{\n vec4 bbox;\n float linewidth;\n uint rgba_color;\n};\n\nstruct AnnoBeginClipRef\n{\n uint offset;\n};\n\nstruct AnnoBeginClip\n{\n vec4 bbox;\n float linewidth;\n};\n\nstruct AnnotatedRef\n{\n uint offset;\n};\n\nstruct AnnotatedTag\n{\n uint tag;\n uint flags;\n};\n\nstruct BinInstanceRef\n{\n uint offset;\n};\n\nstruct BinInstance\n{\n uint element_ix;\n};\n\nstruct PathRef\n{\n uint offset;\n};\n\nstruct TileRef\n{\n uint offset;\n};\n\nstruct Path\n{\n uvec4 bbox;\n TileRef tiles;\n};\n\nstruct TileSegRef\n{\n uint offset;\n};\n\nstruct Tile\n{\n TileSegRef tile;\n int backdrop;\n};\n\nstruct CmdStrokeRef\n{\n uint offset;\n};\n\nstruct CmdStroke\n{\n uint tile_ref;\n float half_width;\n};\n\nstruct CmdFillRef\n{\n uint offset;\n};\n\nstruct CmdFill\n{\n uint tile_ref;\n int backdrop;\n};\n\nstruct CmdColorRef\n{\n uint offset;\n};\n\nstruct CmdColor\n{\n uint rgba_color;\n};\n\nstruct CmdImageRef\n{\n uint offset;\n};\n\nstruct CmdImage\n{\n uint index;\n ivec2 offset;\n};\n\nstruct CmdAlphaRef\n{\n uint offset;\n};\n\nstruct CmdAlpha\n{\n float alpha;\n};\n\nstruct CmdJumpRef\n{\n uint offset;\n};\n\nstruct CmdJump\n{\n uint new_ref;\n};\n\nstruct CmdRef\n{\n uint offset;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _276;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _1033;\n\nshared uint sh_bitmaps[4][128];\nshared Alloc sh_part_elements[128];\nshared uint sh_part_count[128];\nshared uint sh_elements[128];\nshared uint sh_tile_stride[128];\nshared uint sh_tile_width[128];\nshared uint sh_tile_x0[128];\nshared uint sh_tile_y0[128];\nshared uint sh_tile_base[128];\nshared uint sh_tile_count[128];\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nAlloc slice_mem(Alloc a, uint offset, uint size)\n{\n uint param = a.offset + offset;\n uint param_1 = size;\n return new_alloc(param, param_1);\n}\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _276.memory[offset];\n return v;\n}\n\nBinInstanceRef BinInstance_index(BinInstanceRef ref, uint index)\n{\n return BinInstanceRef(ref.offset + (index * 4u));\n}\n\nBinInstance BinInstance_read(Alloc a, BinInstanceRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n BinInstance s;\n s.element_ix = raw0;\n return s;\n}\n\nAnnotatedTag Annotated_tag(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint tag_and_flags = read_mem(param, param_1);\n return AnnotatedTag(tag_and_flags & 65535u, tag_and_flags >> uint(16));\n}\n\nPath Path_read(Alloc a, PathRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Path s;\n s.bbox = uvec4(raw0 & 65535u, raw0 >> uint(16), raw1 & 65535u, raw1 >> uint(16));\n s.tiles = TileRef(raw2);\n return s;\n}\n\nvoid write_tile_alloc(uint el_ix, Alloc a)\n{\n}\n\nAlloc read_tile_alloc(uint el_ix)\n{\n uint param = 0u;\n uint param_1 = uint(int(uint(_276.memory.length())) * 4);\n return new_alloc(param, param_1);\n}\n\nTile Tile_read(Alloc a, TileRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Tile s;\n s.tile = TileSegRef(raw0);\n s.backdrop = int(raw1);\n return s;\n}\n\nAnnoColor AnnoColor_read(Alloc a, AnnoColorRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n Alloc param_10 = a;\n uint param_11 = ix + 5u;\n uint raw5 = read_mem(param_10, param_11);\n AnnoColor s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.linewidth = uintBitsToFloat(raw4);\n s.rgba_color = raw5;\n return s;\n}\n\nAnnoColor Annotated_Color_read(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n AnnoColorRef param_1 = AnnoColorRef(ref.offset + 4u);\n return AnnoColor_read(param, param_1);\n}\n\nMallocResult malloc(uint size)\n{\n MallocResult r;\n r.failed = false;\n uint _282 = atomicAdd(_276.mem_offset, size);\n uint offset = _282;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_276.memory.length())) * 4))\n {\n r.failed = true;\n uint _303 = atomicMax(_276.mem_error, 1u);\n return r;\n }\n return r;\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _276.memory[offset] = val;\n}\n\nvoid CmdJump_write(Alloc a, CmdJumpRef ref, CmdJump s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.new_ref;\n write_mem(param, param_1, param_2);\n}\n\nvoid Cmd_Jump_write(Alloc a, CmdRef ref, CmdJump s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 9u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdJumpRef param_4 = CmdJumpRef(ref.offset + 4u);\n CmdJump param_5 = s;\n CmdJump_write(param_3, param_4, param_5);\n}\n\nbool alloc_cmd(inout Alloc cmd_alloc, inout CmdRef cmd_ref, inout uint cmd_limit)\n{\n if (cmd_ref.offset < cmd_limit)\n {\n return true;\n }\n uint param = 1024u;\n MallocResult _993 = malloc(param);\n MallocResult new_cmd = _993;\n if (new_cmd.failed)\n {\n return false;\n }\n CmdJump jump = CmdJump(new_cmd.alloc.offset);\n Alloc param_1 = cmd_alloc;\n CmdRef param_2 = cmd_ref;\n CmdJump param_3 = jump;\n Cmd_Jump_write(param_1, param_2, param_3);\n cmd_alloc = new_cmd.alloc;\n cmd_ref = CmdRef(cmd_alloc.offset);\n cmd_limit = (cmd_alloc.offset + 1024u) - 36u;\n return true;\n}\n\nuint fill_mode_from_flags(uint flags)\n{\n return flags & 1u;\n}\n\nvoid CmdFill_write(Alloc a, CmdFillRef ref, CmdFill s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.tile_ref;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = uint(s.backdrop);\n write_mem(param_3, param_4, param_5);\n}\n\nvoid Cmd_Fill_write(Alloc a, CmdRef ref, CmdFill s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 1u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdFillRef param_4 = CmdFillRef(ref.offset + 4u);\n CmdFill param_5 = s;\n CmdFill_write(param_3, param_4, param_5);\n}\n\nvoid Cmd_Solid_write(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 3u;\n write_mem(param, param_1, param_2);\n}\n\nvoid CmdStroke_write(Alloc a, CmdStrokeRef ref, CmdStroke s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.tile_ref;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.half_width);\n write_mem(param_3, param_4, param_5);\n}\n\nvoid Cmd_Stroke_write(Alloc a, CmdRef ref, CmdStroke s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 2u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdStrokeRef param_4 = CmdStrokeRef(ref.offset + 4u);\n CmdStroke param_5 = s;\n CmdStroke_write(param_3, param_4, param_5);\n}\n\nvoid CmdColor_write(Alloc a, CmdColorRef ref, CmdColor s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.rgba_color;\n write_mem(param, param_1, param_2);\n}\n\nvoid Cmd_Color_write(Alloc a, CmdRef ref, CmdColor s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 5u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdColorRef param_4 = CmdColorRef(ref.offset + 4u);\n CmdColor param_5 = s;\n CmdColor_write(param_3, param_4, param_5);\n}\n\nAnnoImage AnnoImage_read(Alloc a, AnnoImageRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n Alloc param_10 = a;\n uint param_11 = ix + 5u;\n uint raw5 = read_mem(param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 6u;\n uint raw6 = read_mem(param_12, param_13);\n AnnoImage s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.linewidth = uintBitsToFloat(raw4);\n s.index = raw5;\n s.offset = ivec2(int(raw6 << uint(16)) >> 16, int(raw6) >> 16);\n return s;\n}\n\nAnnoImage Annotated_Image_read(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n AnnoImageRef param_1 = AnnoImageRef(ref.offset + 4u);\n return AnnoImage_read(param, param_1);\n}\n\nvoid CmdImage_write(Alloc a, CmdImageRef ref, CmdImage s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.index;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = (uint(s.offset.x) & 65535u) | (uint(s.offset.y) << uint(16));\n write_mem(param_3, param_4, param_5);\n}\n\nvoid Cmd_Image_write(Alloc a, CmdRef ref, CmdImage s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 6u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdImageRef param_4 = CmdImageRef(ref.offset + 4u);\n CmdImage param_5 = s;\n CmdImage_write(param_3, param_4, param_5);\n}\n\nAnnoBeginClip AnnoBeginClip_read(Alloc a, AnnoBeginClipRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n AnnoBeginClip s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.linewidth = uintBitsToFloat(raw4);\n return s;\n}\n\nAnnoBeginClip Annotated_BeginClip_read(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n AnnoBeginClipRef param_1 = AnnoBeginClipRef(ref.offset + 4u);\n return AnnoBeginClip_read(param, param_1);\n}\n\nvoid CmdAlpha_write(Alloc a, CmdAlphaRef ref, CmdAlpha s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.alpha);\n write_mem(param, param_1, param_2);\n}\n\nvoid Cmd_Alpha_write(Alloc a, CmdRef ref, CmdAlpha s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 4u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n CmdAlphaRef param_4 = CmdAlphaRef(ref.offset + 4u);\n CmdAlpha param_5 = s;\n CmdAlpha_write(param_3, param_4, param_5);\n}\n\nvoid Cmd_BeginClip_write(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 7u;\n write_mem(param, param_1, param_2);\n}\n\nvoid Cmd_EndClip_write(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 8u;\n write_mem(param, param_1, param_2);\n}\n\nvoid Cmd_End_write(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 0u;\n write_mem(param, param_1, param_2);\n}\n\nvoid main()\n{\n if (_276.mem_error != 0u)\n {\n return;\n }\n uint width_in_bins = ((_1033.conf.width_in_tiles + 16u) - 1u) / 16u;\n uint bin_ix = (width_in_bins * gl_WorkGroupID.y) + gl_WorkGroupID.x;\n uint partition_ix = 0u;\n uint n_partitions = ((_1033.conf.n_elements + 128u) - 1u) / 128u;\n uint th_ix = gl_LocalInvocationID.x;\n uint bin_tile_x = 16u * gl_WorkGroupID.x;\n uint bin_tile_y = 8u * gl_WorkGroupID.y;\n uint tile_x = gl_LocalInvocationID.x % 16u;\n uint tile_y = gl_LocalInvocationID.x / 16u;\n uint this_tile_ix = (((bin_tile_y + tile_y) * _1033.conf.width_in_tiles) + bin_tile_x) + tile_x;\n Alloc param;\n param.offset = _1033.conf.ptcl_alloc.offset;\n uint param_1 = this_tile_ix * 1024u;\n uint param_2 = 1024u;\n Alloc cmd_alloc = slice_mem(param, param_1, param_2);\n CmdRef cmd_ref = CmdRef(cmd_alloc.offset);\n uint cmd_limit = (cmd_ref.offset + 1024u) - 36u;\n uint clip_depth = 0u;\n uint clip_zero_depth = 0u;\n uint clip_one_mask = 0u;\n uint rd_ix = 0u;\n uint wr_ix = 0u;\n uint part_start_ix = 0u;\n uint ready_ix = 0u;\n Alloc param_3;\n Alloc param_5;\n uint _1309;\n uint element_ix;\n AnnotatedRef ref;\n Alloc param_13;\n Alloc param_15;\n uint tile_count;\n Alloc param_21;\n uint _1623;\n bool include_tile;\n Alloc param_26;\n Tile tile_1;\n Alloc param_31;\n Alloc param_51;\n Alloc param_71;\n while (true)\n {\n for (uint i = 0u; i < 4u; i++)\n {\n sh_bitmaps[i][th_ix] = 0u;\n }\n bool _1361;\n for (;;)\n {\n if ((ready_ix == wr_ix) && (partition_ix < n_partitions))\n {\n part_start_ix = ready_ix;\n uint count = 0u;\n bool _1159 = th_ix < 128u;\n bool _1167;\n if (_1159)\n {\n _1167 = (partition_ix + th_ix) < n_partitions;\n }\n else\n {\n _1167 = _1159;\n }\n if (_1167)\n {\n uint in_ix = (_1033.conf.bin_alloc.offset >> uint(2)) + ((((partition_ix + th_ix) * 128u) + bin_ix) * 2u);\n param_3.offset = _1033.conf.bin_alloc.offset;\n uint param_4 = in_ix;\n count = read_mem(param_3, param_4);\n param_5.offset = _1033.conf.bin_alloc.offset;\n uint param_6 = in_ix + 1u;\n uint offset = read_mem(param_5, param_6);\n uint param_7 = offset;\n uint param_8 = count * 4u;\n sh_part_elements[th_ix] = new_alloc(param_7, param_8);\n }\n for (uint i_1 = 0u; i_1 < 7u; i_1++)\n {\n if (th_ix < 128u)\n {\n sh_part_count[th_ix] = count;\n }\n barrier();\n if (th_ix < 128u)\n {\n if (th_ix >= uint(1 << int(i_1)))\n {\n count += sh_part_count[th_ix - uint(1 << int(i_1))];\n }\n }\n barrier();\n }\n if (th_ix < 128u)\n {\n sh_part_count[th_ix] = part_start_ix + count;\n }\n barrier();\n ready_ix = sh_part_count[127];\n partition_ix += 128u;\n }\n uint ix = rd_ix + th_ix;\n if ((ix >= wr_ix) && (ix < ready_ix))\n {\n uint part_ix = 0u;\n for (uint i_2 = 0u; i_2 < 7u; i_2++)\n {\n uint probe = part_ix + uint(64 >> int(i_2));\n if (ix >= sh_part_count[probe - 1u])\n {\n part_ix = probe;\n }\n }\n if (part_ix > 0u)\n {\n _1309 = sh_part_count[part_ix - 1u];\n }\n else\n {\n _1309 = part_start_ix;\n }\n ix -= _1309;\n Alloc bin_alloc = sh_part_elements[part_ix];\n BinInstanceRef inst_ref = BinInstanceRef(bin_alloc.offset);\n BinInstanceRef param_9 = inst_ref;\n uint param_10 = ix;\n Alloc param_11 = bin_alloc;\n BinInstanceRef param_12 = BinInstance_index(param_9, param_10);\n BinInstance inst = BinInstance_read(param_11, param_12);\n sh_elements[th_ix] = inst.element_ix;\n }\n barrier();\n wr_ix = min((rd_ix + 128u), ready_ix);\n bool _1351 = (wr_ix - rd_ix) < 128u;\n if (_1351)\n {\n _1361 = (wr_ix < ready_ix) || (partition_ix < n_partitions);\n }\n else\n {\n _1361 = _1351;\n }\n if (_1361)\n {\n continue;\n }\n else\n {\n break;\n }\n }\n uint tag = 0u;\n if ((th_ix + rd_ix) < wr_ix)\n {\n element_ix = sh_elements[th_ix];\n ref = AnnotatedRef(_1033.conf.anno_alloc.offset + (element_ix * 32u));\n param_13.offset = _1033.conf.anno_alloc.offset;\n AnnotatedRef param_14 = ref;\n tag = Annotated_tag(param_13, param_14).tag;\n }\n switch (tag)\n {\n case 1u:\n case 2u:\n case 3u:\n case 4u:\n {\n uint path_ix = element_ix;\n param_15.offset = _1033.conf.tile_alloc.offset;\n PathRef param_16 = PathRef(_1033.conf.tile_alloc.offset + (path_ix * 12u));\n Path path = Path_read(param_15, param_16);\n uint stride = path.bbox.z - path.bbox.x;\n sh_tile_stride[th_ix] = stride;\n int dx = int(path.bbox.x) - int(bin_tile_x);\n int dy = int(path.bbox.y) - int(bin_tile_y);\n int x0 = clamp(dx, 0, 16);\n int y0 = clamp(dy, 0, 8);\n int x1 = clamp(int(path.bbox.z) - int(bin_tile_x), 0, 16);\n int y1 = clamp(int(path.bbox.w) - int(bin_tile_y), 0, 8);\n sh_tile_width[th_ix] = uint(x1 - x0);\n sh_tile_x0[th_ix] = uint(x0);\n sh_tile_y0[th_ix] = uint(y0);\n tile_count = uint(x1 - x0) * uint(y1 - y0);\n uint base = path.tiles.offset - (((uint(dy) * stride) + uint(dx)) * 8u);\n sh_tile_base[th_ix] = base;\n uint param_17 = path.tiles.offset;\n uint param_18 = ((path.bbox.z - path.bbox.x) * (path.bbox.w - path.bbox.y)) * 8u;\n Alloc path_alloc = new_alloc(param_17, param_18);\n uint param_19 = th_ix;\n Alloc param_20 = path_alloc;\n write_tile_alloc(param_19, param_20);\n break;\n }\n default:\n {\n tile_count = 0u;\n break;\n }\n }\n sh_tile_count[th_ix] = tile_count;\n for (uint i_3 = 0u; i_3 < 7u; i_3++)\n {\n barrier();\n if (th_ix >= uint(1 << int(i_3)))\n {\n tile_count += sh_tile_count[th_ix - uint(1 << int(i_3))];\n }\n barrier();\n sh_tile_count[th_ix] = tile_count;\n }\n barrier();\n uint total_tile_count = sh_tile_count[127];\n for (uint ix_1 = th_ix; ix_1 < total_tile_count; ix_1 += 128u)\n {\n uint el_ix = 0u;\n for (uint i_4 = 0u; i_4 < 7u; i_4++)\n {\n uint probe_1 = el_ix + uint(64 >> int(i_4));\n if (ix_1 >= sh_tile_count[probe_1 - 1u])\n {\n el_ix = probe_1;\n }\n }\n AnnotatedRef ref_1 = AnnotatedRef(_1033.conf.anno_alloc.offset + (sh_elements[el_ix] * 32u));\n param_21.offset = _1033.conf.anno_alloc.offset;\n AnnotatedRef param_22 = ref_1;\n uint tag_1 = Annotated_tag(param_21, param_22).tag;\n if (el_ix > 0u)\n {\n _1623 = sh_tile_count[el_ix - 1u];\n }\n else\n {\n _1623 = 0u;\n }\n uint seq_ix = ix_1 - _1623;\n uint width = sh_tile_width[el_ix];\n uint x = sh_tile_x0[el_ix] + (seq_ix % width);\n uint y = sh_tile_y0[el_ix] + (seq_ix / width);\n if ((tag_1 == 3u) || (tag_1 == 4u))\n {\n include_tile = true;\n }\n else\n {\n uint param_23 = el_ix;\n Alloc param_24 = read_tile_alloc(param_23);\n TileRef param_25 = TileRef(sh_tile_base[el_ix] + (((sh_tile_stride[el_ix] * y) + x) * 8u));\n Tile tile = Tile_read(param_24, param_25);\n bool _1684 = tile.tile.offset != 0u;\n bool _1691;\n if (!_1684)\n {\n _1691 = tile.backdrop != 0;\n }\n else\n {\n _1691 = _1684;\n }\n include_tile = _1691;\n }\n if (include_tile)\n {\n uint el_slice = el_ix / 32u;\n uint el_mask = uint(1 << int(el_ix & 31u));\n uint _1711 = atomicOr(sh_bitmaps[el_slice][(y * 16u) + x], el_mask);\n }\n }\n barrier();\n uint slice_ix = 0u;\n uint bitmap = sh_bitmaps[0][th_ix];\n while (true)\n {\n if (bitmap == 0u)\n {\n slice_ix++;\n if (slice_ix == 4u)\n {\n break;\n }\n bitmap = sh_bitmaps[slice_ix][th_ix];\n if (bitmap == 0u)\n {\n continue;\n }\n }\n uint element_ref_ix = (slice_ix * 32u) + uint(findLSB(bitmap));\n uint element_ix_1 = sh_elements[element_ref_ix];\n bitmap &= (bitmap - 1u);\n ref = AnnotatedRef(_1033.conf.anno_alloc.offset + (element_ix_1 * 32u));\n param_26.offset = _1033.conf.anno_alloc.offset;\n AnnotatedRef param_27 = ref;\n AnnotatedTag tag_2 = Annotated_tag(param_26, param_27);\n if (clip_zero_depth == 0u)\n {\n switch (tag_2.tag)\n {\n case 1u:\n {\n uint param_28 = element_ref_ix;\n Alloc param_29 = read_tile_alloc(param_28);\n TileRef param_30 = TileRef(sh_tile_base[element_ref_ix] + (((sh_tile_stride[element_ref_ix] * tile_y) + tile_x) * 8u));\n tile_1 = Tile_read(param_29, param_30);\n param_31.offset = _1033.conf.anno_alloc.offset;\n AnnotatedRef param_32 = ref;\n AnnoColor fill = Annotated_Color_read(param_31, param_32);\n Alloc param_33 = cmd_alloc;\n CmdRef param_34 = cmd_ref;\n uint param_35 = cmd_limit;\n bool _1821 = alloc_cmd(param_33, param_34, param_35);\n cmd_alloc = param_33;\n cmd_ref = param_34;\n cmd_limit = param_35;\n if (!_1821)\n {\n break;\n }\n uint param_36 = tag_2.flags;\n if (fill_mode_from_flags(param_36) == 0u)\n {\n if (tile_1.tile.offset != 0u)\n {\n CmdFill cmd_fill = CmdFill(tile_1.tile.offset, tile_1.backdrop);\n Alloc param_37 = cmd_alloc;\n CmdRef param_38 = cmd_ref;\n CmdFill param_39 = cmd_fill;\n Cmd_Fill_write(param_37, param_38, param_39);\n cmd_ref.offset += 12u;\n }\n else\n {\n Alloc param_40 = cmd_alloc;\n CmdRef param_41 = cmd_ref;\n Cmd_Solid_write(param_40, param_41);\n cmd_ref.offset += 4u;\n }\n }\n else\n {\n CmdStroke cmd_stroke = CmdStroke(tile_1.tile.offset, 0.5 * fill.linewidth);\n Alloc param_42 = cmd_alloc;\n CmdRef param_43 = cmd_ref;\n CmdStroke param_44 = cmd_stroke;\n Cmd_Stroke_write(param_42, param_43, param_44);\n cmd_ref.offset += 12u;\n }\n Alloc param_45 = cmd_alloc;\n CmdRef param_46 = cmd_ref;\n CmdColor param_47 = CmdColor(fill.rgba_color);\n Cmd_Color_write(param_45, param_46, param_47);\n cmd_ref.offset += 8u;\n break;\n }\n case 2u:\n {\n uint param_48 = element_ref_ix;\n Alloc param_49 = read_tile_alloc(param_48);\n TileRef param_50 = TileRef(sh_tile_base[element_ref_ix] + (((sh_tile_stride[element_ref_ix] * tile_y) + tile_x) * 8u));\n tile_1 = Tile_read(param_49, param_50);\n param_51.offset = _1033.conf.anno_alloc.offset;\n AnnotatedRef param_52 = ref;\n AnnoImage fill_img = Annotated_Image_read(param_51, param_52);\n Alloc param_53 = cmd_alloc;\n CmdRef param_54 = cmd_ref;\n uint param_55 = cmd_limit;\n bool _1936 = alloc_cmd(param_53, param_54, param_55);\n cmd_alloc = param_53;\n cmd_ref = param_54;\n cmd_limit = param_55;\n if (!_1936)\n {\n break;\n }\n uint param_56 = tag_2.flags;\n if (fill_mode_from_flags(param_56) == 0u)\n {\n if (tile_1.tile.offset != 0u)\n {\n CmdFill cmd_fill_1 = CmdFill(tile_1.tile.offset, tile_1.backdrop);\n Alloc param_57 = cmd_alloc;\n CmdRef param_58 = cmd_ref;\n CmdFill param_59 = cmd_fill_1;\n Cmd_Fill_write(param_57, param_58, param_59);\n cmd_ref.offset += 12u;\n }\n else\n {\n Alloc param_60 = cmd_alloc;\n CmdRef param_61 = cmd_ref;\n Cmd_Solid_write(param_60, param_61);\n cmd_ref.offset += 4u;\n }\n }\n else\n {\n CmdStroke cmd_stroke_1 = CmdStroke(tile_1.tile.offset, 0.5 * fill_img.linewidth);\n Alloc param_62 = cmd_alloc;\n CmdRef param_63 = cmd_ref;\n CmdStroke param_64 = cmd_stroke_1;\n Cmd_Stroke_write(param_62, param_63, param_64);\n cmd_ref.offset += 12u;\n }\n Alloc param_65 = cmd_alloc;\n CmdRef param_66 = cmd_ref;\n CmdImage param_67 = CmdImage(fill_img.index, fill_img.offset);\n Cmd_Image_write(param_65, param_66, param_67);\n cmd_ref.offset += 12u;\n break;\n }\n case 3u:\n {\n uint param_68 = element_ref_ix;\n Alloc param_69 = read_tile_alloc(param_68);\n TileRef param_70 = TileRef(sh_tile_base[element_ref_ix] + (((sh_tile_stride[element_ref_ix] * tile_y) + tile_x) * 8u));\n tile_1 = Tile_read(param_69, param_70);\n bool _2039 = tile_1.tile.offset == 0u;\n bool _2045;\n if (_2039)\n {\n _2045 = tile_1.backdrop == 0;\n }\n else\n {\n _2045 = _2039;\n }\n if (_2045)\n {\n clip_zero_depth = clip_depth + 1u;\n }\n else\n {\n if ((tile_1.tile.offset == 0u) && (clip_depth < 32u))\n {\n clip_one_mask |= uint(1 << int(clip_depth));\n }\n else\n {\n param_71.offset = _1033.conf.anno_alloc.offset;\n AnnotatedRef param_72 = ref;\n AnnoBeginClip begin_clip = Annotated_BeginClip_read(param_71, param_72);\n Alloc param_73 = cmd_alloc;\n CmdRef param_74 = cmd_ref;\n uint param_75 = cmd_limit;\n bool _2080 = alloc_cmd(param_73, param_74, param_75);\n cmd_alloc = param_73;\n cmd_ref = param_74;\n cmd_limit = param_75;\n if (!_2080)\n {\n break;\n }\n uint param_76 = tag_2.flags;\n if (fill_mode_from_flags(param_76) == 0u)\n {\n if (tile_1.tile.offset != 0u)\n {\n CmdFill cmd_fill_2 = CmdFill(tile_1.tile.offset, tile_1.backdrop);\n Alloc param_77 = cmd_alloc;\n CmdRef param_78 = cmd_ref;\n CmdFill param_79 = cmd_fill_2;\n Cmd_Fill_write(param_77, param_78, param_79);\n cmd_ref.offset += 12u;\n }\n else\n {\n float alpha = (tile_1.backdrop == 0) ? 0.0 : 1.0;\n Alloc param_80 = cmd_alloc;\n CmdRef param_81 = cmd_ref;\n CmdAlpha param_82 = CmdAlpha(alpha);\n Cmd_Alpha_write(param_80, param_81, param_82);\n cmd_ref.offset += 8u;\n }\n }\n else\n {\n CmdStroke cmd_stroke_2 = CmdStroke(tile_1.tile.offset, 0.5 * begin_clip.linewidth);\n Alloc param_83 = cmd_alloc;\n CmdRef param_84 = cmd_ref;\n CmdStroke param_85 = cmd_stroke_2;\n Cmd_Stroke_write(param_83, param_84, param_85);\n cmd_ref.offset += 12u;\n }\n Alloc param_86 = cmd_alloc;\n CmdRef param_87 = cmd_ref;\n Cmd_BeginClip_write(param_86, param_87);\n cmd_ref.offset += 4u;\n if (clip_depth < 32u)\n {\n clip_one_mask &= uint(~(1 << int(clip_depth)));\n }\n }\n }\n clip_depth++;\n break;\n }\n case 4u:\n {\n clip_depth--;\n bool _2181 = clip_depth >= 32u;\n bool _2191;\n if (!_2181)\n {\n _2191 = (clip_one_mask & uint(1 << int(clip_depth))) == 0u;\n }\n else\n {\n _2191 = _2181;\n }\n if (_2191)\n {\n Alloc param_88 = cmd_alloc;\n CmdRef param_89 = cmd_ref;\n uint param_90 = cmd_limit;\n bool _2200 = alloc_cmd(param_88, param_89, param_90);\n cmd_alloc = param_88;\n cmd_ref = param_89;\n cmd_limit = param_90;\n if (!_2200)\n {\n break;\n }\n Alloc param_91 = cmd_alloc;\n CmdRef param_92 = cmd_ref;\n Cmd_Solid_write(param_91, param_92);\n cmd_ref.offset += 4u;\n Alloc param_93 = cmd_alloc;\n CmdRef param_94 = cmd_ref;\n Cmd_EndClip_write(param_93, param_94);\n cmd_ref.offset += 4u;\n }\n break;\n }\n }\n }\n else\n {\n switch (tag_2.tag)\n {\n case 3u:\n {\n clip_depth++;\n break;\n }\n case 4u:\n {\n if (clip_depth == clip_zero_depth)\n {\n clip_zero_depth = 0u;\n }\n clip_depth--;\n break;\n }\n }\n }\n }\n barrier();\n rd_ix += 128u;\n if ((rd_ix >= ready_ix) && (partition_ix >= n_partitions))\n {\n break;\n }\n }\n bool _2263 = (bin_tile_x + tile_x) < _1033.conf.width_in_tiles;\n bool _2272;\n if (_2263)\n {\n _2272 = (bin_tile_y + tile_y) < _1033.conf.height_in_tiles;\n }\n else\n {\n _2272 = _2263;\n }\n if (_2272)\n {\n Alloc param_95 = cmd_alloc;\n CmdRef param_96 = cmd_ref;\n Cmd_End_write(param_95, param_96);\n }\n}\n\n", } shader_copy_frag = driver.ShaderSources{ Name: "copy.frag", @@ -139,7 +139,7 @@ var ( } shader_elements_comp = driver.ShaderSources{ Name: "elements.comp", - GLSL310ES: "#version 310 es\nlayout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct ElementRef\n{\n uint offset;\n};\n\nstruct LineSegRef\n{\n uint offset;\n};\n\nstruct LineSeg\n{\n vec2 p0;\n vec2 p1;\n};\n\nstruct QuadSegRef\n{\n uint offset;\n};\n\nstruct QuadSeg\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n};\n\nstruct CubicSegRef\n{\n uint offset;\n};\n\nstruct CubicSeg\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n vec2 p3;\n};\n\nstruct FillRef\n{\n uint offset;\n};\n\nstruct Fill\n{\n uint rgba_color;\n};\n\nstruct FillImageRef\n{\n uint offset;\n};\n\nstruct FillImage\n{\n uint index;\n ivec2 offset;\n};\n\nstruct StrokeRef\n{\n uint offset;\n};\n\nstruct Stroke\n{\n uint rgba_color;\n};\n\nstruct SetLineWidthRef\n{\n uint offset;\n};\n\nstruct SetLineWidth\n{\n float width;\n};\n\nstruct TransformRef\n{\n uint offset;\n};\n\nstruct Transform\n{\n vec4 mat;\n vec2 translate;\n};\n\nstruct ClipRef\n{\n uint offset;\n};\n\nstruct Clip\n{\n vec4 bbox;\n};\n\nstruct StateRef\n{\n uint offset;\n};\n\nstruct State\n{\n vec4 mat;\n vec2 translate;\n vec4 bbox;\n float linewidth;\n uint flags;\n uint path_count;\n uint pathseg_count;\n uint trans_count;\n};\n\nstruct AnnoFillRef\n{\n uint offset;\n};\n\nstruct AnnoFill\n{\n vec4 bbox;\n uint rgba_color;\n};\n\nstruct AnnoFillImageRef\n{\n uint offset;\n};\n\nstruct AnnoFillImage\n{\n vec4 bbox;\n uint index;\n ivec2 offset;\n};\n\nstruct AnnoStrokeRef\n{\n uint offset;\n};\n\nstruct AnnoStroke\n{\n vec4 bbox;\n uint rgba_color;\n float linewidth;\n};\n\nstruct AnnoClipRef\n{\n uint offset;\n};\n\nstruct AnnoClip\n{\n vec4 bbox;\n};\n\nstruct AnnotatedRef\n{\n uint offset;\n};\n\nstruct PathStrokeCubicRef\n{\n uint offset;\n};\n\nstruct PathStrokeCubic\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n vec2 p3;\n uint path_ix;\n uint trans_ix;\n vec2 stroke;\n};\n\nstruct TransformSegRef\n{\n uint offset;\n};\n\nstruct TransformSeg\n{\n vec4 mat;\n vec2 translate;\n};\n\nstruct PathSegRef\n{\n uint offset;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _292;\n\nlayout(binding = 2, std430) readonly buffer SceneBuf\n{\n uint scene[];\n} _316;\n\nlayout(binding = 3, std430) coherent buffer StateBuf\n{\n uint part_counter;\n uint state[];\n} _790;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _2380;\n\nshared uint sh_part_ix;\nshared State sh_state[32];\nshared State sh_prefix;\n\nuint Element_tag(ElementRef ref)\n{\n return _316.scene[ref.offset >> uint(2)];\n}\n\nLineSeg LineSeg_read(LineSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _316.scene[ix + 0u];\n uint raw1 = _316.scene[ix + 1u];\n uint raw2 = _316.scene[ix + 2u];\n uint raw3 = _316.scene[ix + 3u];\n LineSeg s;\n s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));\n s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n return s;\n}\n\nLineSeg Element_FillLine_read(ElementRef ref)\n{\n LineSegRef param = LineSegRef(ref.offset + 4u);\n return LineSeg_read(param);\n}\n\nQuadSeg QuadSeg_read(QuadSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _316.scene[ix + 0u];\n uint raw1 = _316.scene[ix + 1u];\n uint raw2 = _316.scene[ix + 2u];\n uint raw3 = _316.scene[ix + 3u];\n uint raw4 = _316.scene[ix + 4u];\n uint raw5 = _316.scene[ix + 5u];\n QuadSeg s;\n s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));\n s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n return s;\n}\n\nQuadSeg Element_FillQuad_read(ElementRef ref)\n{\n QuadSegRef param = QuadSegRef(ref.offset + 4u);\n return QuadSeg_read(param);\n}\n\nCubicSeg CubicSeg_read(CubicSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _316.scene[ix + 0u];\n uint raw1 = _316.scene[ix + 1u];\n uint raw2 = _316.scene[ix + 2u];\n uint raw3 = _316.scene[ix + 3u];\n uint raw4 = _316.scene[ix + 4u];\n uint raw5 = _316.scene[ix + 5u];\n uint raw6 = _316.scene[ix + 6u];\n uint raw7 = _316.scene[ix + 7u];\n CubicSeg s;\n s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));\n s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7));\n return s;\n}\n\nCubicSeg Element_FillCubic_read(ElementRef ref)\n{\n CubicSegRef param = CubicSegRef(ref.offset + 4u);\n return CubicSeg_read(param);\n}\n\nSetLineWidth SetLineWidth_read(SetLineWidthRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _316.scene[ix + 0u];\n SetLineWidth s;\n s.width = uintBitsToFloat(raw0);\n return s;\n}\n\nSetLineWidth Element_SetLineWidth_read(ElementRef ref)\n{\n SetLineWidthRef param = SetLineWidthRef(ref.offset + 4u);\n return SetLineWidth_read(param);\n}\n\nTransform Transform_read(TransformRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _316.scene[ix + 0u];\n uint raw1 = _316.scene[ix + 1u];\n uint raw2 = _316.scene[ix + 2u];\n uint raw3 = _316.scene[ix + 3u];\n uint raw4 = _316.scene[ix + 4u];\n uint raw5 = _316.scene[ix + 5u];\n Transform s;\n s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n return s;\n}\n\nTransform Element_Transform_read(ElementRef ref)\n{\n TransformRef param = TransformRef(ref.offset + 4u);\n return Transform_read(param);\n}\n\nState map_element(ElementRef ref)\n{\n ElementRef param = ref;\n uint tag = Element_tag(param);\n State c;\n c.bbox = vec4(0.0);\n c.mat = vec4(1.0, 0.0, 0.0, 1.0);\n c.translate = vec2(0.0);\n c.linewidth = 1.0;\n c.flags = 0u;\n c.path_count = 0u;\n c.pathseg_count = 0u;\n c.trans_count = 0u;\n switch (tag)\n {\n case 2u:\n case 1u:\n {\n ElementRef param_1 = ref;\n LineSeg line = Element_FillLine_read(param_1);\n vec2 _1882 = min(line.p0, line.p1);\n c.bbox = vec4(_1882.x, _1882.y, c.bbox.z, c.bbox.w);\n vec2 _1890 = max(line.p0, line.p1);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1890.x, _1890.y);\n c.pathseg_count = 1u;\n break;\n }\n case 4u:\n case 3u:\n {\n ElementRef param_2 = ref;\n QuadSeg quad = Element_FillQuad_read(param_2);\n vec2 _1907 = min(min(quad.p0, quad.p1), quad.p2);\n c.bbox = vec4(_1907.x, _1907.y, c.bbox.z, c.bbox.w);\n vec2 _1918 = max(max(quad.p0, quad.p1), quad.p2);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1918.x, _1918.y);\n c.pathseg_count = 1u;\n break;\n }\n case 6u:\n case 5u:\n {\n ElementRef param_3 = ref;\n CubicSeg cubic = Element_FillCubic_read(param_3);\n vec2 _1938 = min(min(cubic.p0, cubic.p1), min(cubic.p2, cubic.p3));\n c.bbox = vec4(_1938.x, _1938.y, c.bbox.z, c.bbox.w);\n vec2 _1952 = max(max(cubic.p0, cubic.p1), max(cubic.p2, cubic.p3));\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1952.x, _1952.y);\n c.pathseg_count = 1u;\n break;\n }\n case 8u:\n case 13u:\n case 7u:\n case 11u:\n {\n c.flags = 4u;\n c.path_count = 1u;\n break;\n }\n case 12u:\n {\n c.path_count = 1u;\n break;\n }\n case 9u:\n {\n ElementRef param_4 = ref;\n SetLineWidth lw = Element_SetLineWidth_read(param_4);\n c.linewidth = lw.width;\n c.flags = 1u;\n break;\n }\n case 10u:\n {\n ElementRef param_5 = ref;\n Transform t = Element_Transform_read(param_5);\n c.mat = t.mat;\n c.translate = t.translate;\n c.trans_count = 1u;\n break;\n }\n }\n return c;\n}\n\nElementRef Element_index(ElementRef ref, uint index)\n{\n return ElementRef(ref.offset + (index * 36u));\n}\n\nState combine_state(State a, State b)\n{\n State c;\n c.bbox.x = (min(a.mat.x * b.bbox.x, a.mat.x * b.bbox.z) + min(a.mat.z * b.bbox.y, a.mat.z * b.bbox.w)) + a.translate.x;\n c.bbox.y = (min(a.mat.y * b.bbox.x, a.mat.y * b.bbox.z) + min(a.mat.w * b.bbox.y, a.mat.w * b.bbox.w)) + a.translate.y;\n c.bbox.z = (max(a.mat.x * b.bbox.x, a.mat.x * b.bbox.z) + max(a.mat.z * b.bbox.y, a.mat.z * b.bbox.w)) + a.translate.x;\n c.bbox.w = (max(a.mat.y * b.bbox.x, a.mat.y * b.bbox.z) + max(a.mat.w * b.bbox.y, a.mat.w * b.bbox.w)) + a.translate.y;\n bool _1646 = (a.flags & 4u) == 0u;\n bool _1654;\n if (_1646)\n {\n _1654 = b.bbox.z <= b.bbox.x;\n }\n else\n {\n _1654 = _1646;\n }\n bool _1662;\n if (_1654)\n {\n _1662 = b.bbox.w <= b.bbox.y;\n }\n else\n {\n _1662 = _1654;\n }\n if (_1662)\n {\n c.bbox = a.bbox;\n }\n else\n {\n bool _1672 = (a.flags & 4u) == 0u;\n bool _1679;\n if (_1672)\n {\n _1679 = (b.flags & 2u) == 0u;\n }\n else\n {\n _1679 = _1672;\n }\n bool _1696;\n if (_1679)\n {\n bool _1686 = a.bbox.z > a.bbox.x;\n bool _1695;\n if (!_1686)\n {\n _1695 = a.bbox.w > a.bbox.y;\n }\n else\n {\n _1695 = _1686;\n }\n _1696 = _1695;\n }\n else\n {\n _1696 = _1679;\n }\n if (_1696)\n {\n vec2 _1705 = min(a.bbox.xy, c.bbox.xy);\n c.bbox = vec4(_1705.x, _1705.y, c.bbox.z, c.bbox.w);\n vec2 _1715 = max(a.bbox.zw, c.bbox.zw);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1715.x, _1715.y);\n }\n }\n c.mat.x = (a.mat.x * b.mat.x) + (a.mat.z * b.mat.y);\n c.mat.y = (a.mat.y * b.mat.x) + (a.mat.w * b.mat.y);\n c.mat.z = (a.mat.x * b.mat.z) + (a.mat.z * b.mat.w);\n c.mat.w = (a.mat.y * b.mat.z) + (a.mat.w * b.mat.w);\n c.translate.x = ((a.mat.x * b.translate.x) + (a.mat.z * b.translate.y)) + a.translate.x;\n c.translate.y = ((a.mat.y * b.translate.x) + (a.mat.w * b.translate.y)) + a.translate.y;\n float _1801;\n if ((b.flags & 1u) == 0u)\n {\n _1801 = a.linewidth;\n }\n else\n {\n _1801 = b.linewidth;\n }\n c.linewidth = _1801;\n c.flags = (a.flags & 3u) | b.flags;\n c.flags |= ((a.flags & 4u) >> uint(1));\n c.path_count = a.path_count + b.path_count;\n c.pathseg_count = a.pathseg_count + b.pathseg_count;\n c.trans_count = a.trans_count + b.trans_count;\n return c;\n}\n\nStateRef state_aggregate_ref(uint partition_ix)\n{\n return StateRef(4u + (partition_ix * 124u));\n}\n\nvoid State_write(StateRef ref, State s)\n{\n uint ix = ref.offset >> uint(2);\n _790.state[ix + 0u] = floatBitsToUint(s.mat.x);\n _790.state[ix + 1u] = floatBitsToUint(s.mat.y);\n _790.state[ix + 2u] = floatBitsToUint(s.mat.z);\n _790.state[ix + 3u] = floatBitsToUint(s.mat.w);\n _790.state[ix + 4u] = floatBitsToUint(s.translate.x);\n _790.state[ix + 5u] = floatBitsToUint(s.translate.y);\n _790.state[ix + 6u] = floatBitsToUint(s.bbox.x);\n _790.state[ix + 7u] = floatBitsToUint(s.bbox.y);\n _790.state[ix + 8u] = floatBitsToUint(s.bbox.z);\n _790.state[ix + 9u] = floatBitsToUint(s.bbox.w);\n _790.state[ix + 10u] = floatBitsToUint(s.linewidth);\n _790.state[ix + 11u] = s.flags;\n _790.state[ix + 12u] = s.path_count;\n _790.state[ix + 13u] = s.pathseg_count;\n _790.state[ix + 14u] = s.trans_count;\n}\n\nStateRef state_prefix_ref(uint partition_ix)\n{\n return StateRef((4u + (partition_ix * 124u)) + 60u);\n}\n\nuint state_flag_index(uint partition_ix)\n{\n return partition_ix * 31u;\n}\n\nState State_read(StateRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _790.state[ix + 0u];\n uint raw1 = _790.state[ix + 1u];\n uint raw2 = _790.state[ix + 2u];\n uint raw3 = _790.state[ix + 3u];\n uint raw4 = _790.state[ix + 4u];\n uint raw5 = _790.state[ix + 5u];\n uint raw6 = _790.state[ix + 6u];\n uint raw7 = _790.state[ix + 7u];\n uint raw8 = _790.state[ix + 8u];\n uint raw9 = _790.state[ix + 9u];\n uint raw10 = _790.state[ix + 10u];\n uint raw11 = _790.state[ix + 11u];\n uint raw12 = _790.state[ix + 12u];\n uint raw13 = _790.state[ix + 13u];\n uint raw14 = _790.state[ix + 14u];\n State s;\n s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n s.bbox = vec4(uintBitsToFloat(raw6), uintBitsToFloat(raw7), uintBitsToFloat(raw8), uintBitsToFloat(raw9));\n s.linewidth = uintBitsToFloat(raw10);\n s.flags = raw11;\n s.path_count = raw12;\n s.pathseg_count = raw13;\n s.trans_count = raw14;\n return s;\n}\n\nLineSeg Element_StrokeLine_read(ElementRef ref)\n{\n LineSegRef param = LineSegRef(ref.offset + 4u);\n return LineSeg_read(param);\n}\n\nvec2 get_linewidth(State st)\n{\n return vec2(length(st.mat.xz), length(st.mat.yw)) * (0.5 * st.linewidth);\n}\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _292.memory[offset] = val;\n}\n\nvoid PathStrokeCubic_write(Alloc a, PathStrokeCubicRef ref, PathStrokeCubic s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.p0.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.p0.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.p1.x);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.p1.y);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = floatBitsToUint(s.p2.x);\n write_mem(param_12, param_13, param_14);\n Alloc param_15 = a;\n uint param_16 = ix + 5u;\n uint param_17 = floatBitsToUint(s.p2.y);\n write_mem(param_15, param_16, param_17);\n Alloc param_18 = a;\n uint param_19 = ix + 6u;\n uint param_20 = floatBitsToUint(s.p3.x);\n write_mem(param_18, param_19, param_20);\n Alloc param_21 = a;\n uint param_22 = ix + 7u;\n uint param_23 = floatBitsToUint(s.p3.y);\n write_mem(param_21, param_22, param_23);\n Alloc param_24 = a;\n uint param_25 = ix + 8u;\n uint param_26 = s.path_ix;\n write_mem(param_24, param_25, param_26);\n Alloc param_27 = a;\n uint param_28 = ix + 9u;\n uint param_29 = s.trans_ix;\n write_mem(param_27, param_28, param_29);\n Alloc param_30 = a;\n uint param_31 = ix + 10u;\n uint param_32 = floatBitsToUint(s.stroke.x);\n write_mem(param_30, param_31, param_32);\n Alloc param_33 = a;\n uint param_34 = ix + 11u;\n uint param_35 = floatBitsToUint(s.stroke.y);\n write_mem(param_33, param_34, param_35);\n}\n\nQuadSeg Element_StrokeQuad_read(ElementRef ref)\n{\n QuadSegRef param = QuadSegRef(ref.offset + 4u);\n return QuadSeg_read(param);\n}\n\nCubicSeg Element_StrokeCubic_read(ElementRef ref)\n{\n CubicSegRef param = CubicSegRef(ref.offset + 4u);\n return CubicSeg_read(param);\n}\n\nStroke Stroke_read(StrokeRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _316.scene[ix + 0u];\n Stroke s;\n s.rgba_color = raw0;\n return s;\n}\n\nStroke Element_Stroke_read(ElementRef ref)\n{\n StrokeRef param = StrokeRef(ref.offset + 4u);\n return Stroke_read(param);\n}\n\nvoid AnnoStroke_write(Alloc a, AnnoStrokeRef ref, AnnoStroke s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.bbox.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.bbox.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.bbox.z);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.bbox.w);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = s.rgba_color;\n write_mem(param_12, param_13, param_14);\n Alloc param_15 = a;\n uint param_16 = ix + 5u;\n uint param_17 = floatBitsToUint(s.linewidth);\n write_mem(param_15, param_16, param_17);\n}\n\nvoid Annotated_Stroke_write(Alloc a, AnnotatedRef ref, AnnoStroke s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 1u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n AnnoStrokeRef param_4 = AnnoStrokeRef(ref.offset + 4u);\n AnnoStroke param_5 = s;\n AnnoStroke_write(param_3, param_4, param_5);\n}\n\nFill Fill_read(FillRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _316.scene[ix + 0u];\n Fill s;\n s.rgba_color = raw0;\n return s;\n}\n\nFill Element_Fill_read(ElementRef ref)\n{\n FillRef param = FillRef(ref.offset + 4u);\n return Fill_read(param);\n}\n\nvoid AnnoFill_write(Alloc a, AnnoFillRef ref, AnnoFill s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.bbox.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.bbox.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.bbox.z);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.bbox.w);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = s.rgba_color;\n write_mem(param_12, param_13, param_14);\n}\n\nvoid Annotated_Fill_write(Alloc a, AnnotatedRef ref, AnnoFill s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 2u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n AnnoFillRef param_4 = AnnoFillRef(ref.offset + 4u);\n AnnoFill param_5 = s;\n AnnoFill_write(param_3, param_4, param_5);\n}\n\nFillImage FillImage_read(FillImageRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _316.scene[ix + 0u];\n uint raw1 = _316.scene[ix + 1u];\n FillImage s;\n s.index = raw0;\n s.offset = ivec2(int(raw1 << uint(16)) >> 16, int(raw1) >> 16);\n return s;\n}\n\nFillImage Element_FillImage_read(ElementRef ref)\n{\n FillImageRef param = FillImageRef(ref.offset + 4u);\n return FillImage_read(param);\n}\n\nvoid AnnoFillImage_write(Alloc a, AnnoFillImageRef ref, AnnoFillImage s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.bbox.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.bbox.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.bbox.z);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.bbox.w);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = s.index;\n write_mem(param_12, param_13, param_14);\n Alloc param_15 = a;\n uint param_16 = ix + 5u;\n uint param_17 = (uint(s.offset.x) & 65535u) | (uint(s.offset.y) << uint(16));\n write_mem(param_15, param_16, param_17);\n}\n\nvoid Annotated_FillImage_write(Alloc a, AnnotatedRef ref, AnnoFillImage s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 3u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n AnnoFillImageRef param_4 = AnnoFillImageRef(ref.offset + 4u);\n AnnoFillImage param_5 = s;\n AnnoFillImage_write(param_3, param_4, param_5);\n}\n\nClip Clip_read(ClipRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _316.scene[ix + 0u];\n uint raw1 = _316.scene[ix + 1u];\n uint raw2 = _316.scene[ix + 2u];\n uint raw3 = _316.scene[ix + 3u];\n Clip s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n return s;\n}\n\nClip Element_BeginClip_read(ElementRef ref)\n{\n ClipRef param = ClipRef(ref.offset + 4u);\n return Clip_read(param);\n}\n\nvoid AnnoClip_write(Alloc a, AnnoClipRef ref, AnnoClip s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.bbox.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.bbox.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.bbox.z);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.bbox.w);\n write_mem(param_9, param_10, param_11);\n}\n\nvoid Annotated_BeginClip_write(Alloc a, AnnotatedRef ref, AnnoClip s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 4u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n AnnoClipRef param_4 = AnnoClipRef(ref.offset + 4u);\n AnnoClip param_5 = s;\n AnnoClip_write(param_3, param_4, param_5);\n}\n\nClip Element_EndClip_read(ElementRef ref)\n{\n ClipRef param = ClipRef(ref.offset + 4u);\n return Clip_read(param);\n}\n\nvoid Annotated_EndClip_write(Alloc a, AnnotatedRef ref, AnnoClip s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 5u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n AnnoClipRef param_4 = AnnoClipRef(ref.offset + 4u);\n AnnoClip param_5 = s;\n AnnoClip_write(param_3, param_4, param_5);\n}\n\nvoid TransformSeg_write(Alloc a, TransformSegRef ref, TransformSeg s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.mat.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.mat.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.mat.z);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.mat.w);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = floatBitsToUint(s.translate.x);\n write_mem(param_12, param_13, param_14);\n Alloc param_15 = a;\n uint param_16 = ix + 5u;\n uint param_17 = floatBitsToUint(s.translate.y);\n write_mem(param_15, param_16, param_17);\n}\n\nvoid main()\n{\n if (_292.mem_error != 0u)\n {\n return;\n }\n if (gl_LocalInvocationID.x == 0u)\n {\n uint _2022 = atomicAdd(_790.part_counter, 1u);\n sh_part_ix = _2022;\n }\n barrier();\n uint part_ix = sh_part_ix;\n uint ix = (part_ix * 128u) + (gl_LocalInvocationID.x * 4u);\n ElementRef ref = ElementRef(ix * 36u);\n ElementRef param = ref;\n State th_state[4];\n th_state[0] = map_element(param);\n for (uint i = 1u; i < 4u; i++)\n {\n ElementRef param_1 = ref;\n uint param_2 = i;\n ElementRef param_3 = Element_index(param_1, param_2);\n State param_4 = th_state[i - 1u];\n State param_5 = map_element(param_3);\n th_state[i] = combine_state(param_4, param_5);\n }\n State agg = th_state[3];\n sh_state[gl_LocalInvocationID.x] = agg;\n for (uint i_1 = 0u; i_1 < 5u; i_1++)\n {\n barrier();\n if (gl_LocalInvocationID.x >= uint(1 << int(i_1)))\n {\n State other = sh_state[gl_LocalInvocationID.x - uint(1 << int(i_1))];\n State param_6 = other;\n State param_7 = agg;\n agg = combine_state(param_6, param_7);\n }\n barrier();\n sh_state[gl_LocalInvocationID.x] = agg;\n }\n State exclusive;\n exclusive.bbox = vec4(0.0);\n exclusive.mat = vec4(1.0, 0.0, 0.0, 1.0);\n exclusive.translate = vec2(0.0);\n exclusive.linewidth = 1.0;\n exclusive.flags = 0u;\n exclusive.path_count = 0u;\n exclusive.pathseg_count = 0u;\n exclusive.trans_count = 0u;\n if (gl_LocalInvocationID.x == 31u)\n {\n uint param_8 = part_ix;\n StateRef param_9 = state_aggregate_ref(param_8);\n State param_10 = agg;\n State_write(param_9, param_10);\n uint flag = 1u;\n memoryBarrierBuffer();\n if (part_ix == 0u)\n {\n uint param_11 = part_ix;\n StateRef param_12 = state_prefix_ref(param_11);\n State param_13 = agg;\n State_write(param_12, param_13);\n flag = 2u;\n }\n uint param_14 = part_ix;\n _790.state[state_flag_index(param_14)] = flag;\n if (part_ix != 0u)\n {\n uint look_back_ix = part_ix - 1u;\n uint their_ix = 0u;\n State their_agg;\n while (true)\n {\n uint param_15 = look_back_ix;\n flag = _790.state[state_flag_index(param_15)];\n if (flag == 2u)\n {\n uint param_16 = look_back_ix;\n StateRef param_17 = state_prefix_ref(param_16);\n State their_prefix = State_read(param_17);\n State param_18 = their_prefix;\n State param_19 = exclusive;\n exclusive = combine_state(param_18, param_19);\n break;\n }\n else\n {\n if (flag == 1u)\n {\n uint param_20 = look_back_ix;\n StateRef param_21 = state_aggregate_ref(param_20);\n their_agg = State_read(param_21);\n State param_22 = their_agg;\n State param_23 = exclusive;\n exclusive = combine_state(param_22, param_23);\n look_back_ix--;\n their_ix = 0u;\n continue;\n }\n }\n ElementRef ref_1 = ElementRef(((look_back_ix * 128u) + their_ix) * 36u);\n ElementRef param_24 = ref_1;\n State s = map_element(param_24);\n if (their_ix == 0u)\n {\n their_agg = s;\n }\n else\n {\n State param_25 = their_agg;\n State param_26 = s;\n their_agg = combine_state(param_25, param_26);\n }\n their_ix++;\n if (their_ix == 128u)\n {\n State param_27 = their_agg;\n State param_28 = exclusive;\n exclusive = combine_state(param_27, param_28);\n if (look_back_ix == 0u)\n {\n break;\n }\n look_back_ix--;\n their_ix = 0u;\n }\n }\n State param_29 = exclusive;\n State param_30 = agg;\n State inclusive_prefix = combine_state(param_29, param_30);\n sh_prefix = exclusive;\n uint param_31 = part_ix;\n StateRef param_32 = state_prefix_ref(param_31);\n State param_33 = inclusive_prefix;\n State_write(param_32, param_33);\n memoryBarrierBuffer();\n flag = 2u;\n uint param_34 = part_ix;\n _790.state[state_flag_index(param_34)] = flag;\n }\n }\n barrier();\n if (part_ix != 0u)\n {\n exclusive = sh_prefix;\n }\n State row = exclusive;\n if (gl_LocalInvocationID.x > 0u)\n {\n State other_1 = sh_state[gl_LocalInvocationID.x - 1u];\n State param_35 = row;\n State param_36 = other_1;\n row = combine_state(param_35, param_36);\n }\n PathStrokeCubic path_cubic;\n PathSegRef path_out_ref;\n uint out_tag;\n Alloc param_44;\n Alloc param_47;\n Alloc param_52;\n Alloc param_55;\n Alloc param_60;\n Alloc param_63;\n AnnoStroke anno_stroke;\n AnnotatedRef out_ref;\n Alloc param_68;\n AnnoFill anno_fill;\n Alloc param_72;\n AnnoFillImage anno_fill_img;\n Alloc param_76;\n Alloc param_80;\n Alloc param_84;\n Alloc param_87;\n for (uint i_2 = 0u; i_2 < 4u; i_2++)\n {\n State param_37 = row;\n State param_38 = th_state[i_2];\n State st = combine_state(param_37, param_38);\n ElementRef param_39 = ref;\n uint param_40 = i_2;\n ElementRef this_ref = Element_index(param_39, param_40);\n ElementRef param_41 = this_ref;\n uint tag = Element_tag(param_41);\n switch (tag)\n {\n case 2u:\n case 1u:\n {\n ElementRef param_42 = this_ref;\n LineSeg line = Element_StrokeLine_read(param_42);\n path_cubic.p0 = line.p0;\n path_cubic.p1 = mix(line.p0, line.p1, vec2(0.3333333432674407958984375));\n path_cubic.p2 = mix(line.p1, line.p0, vec2(0.3333333432674407958984375));\n path_cubic.p3 = line.p1;\n path_cubic.path_ix = st.path_count;\n path_cubic.trans_ix = st.trans_count;\n if (tag == 1u)\n {\n State param_43 = st;\n path_cubic.stroke = get_linewidth(param_43);\n }\n else\n {\n path_cubic.stroke = vec2(0.0);\n }\n path_out_ref = PathSegRef(_2380.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 52u));\n out_tag = uint((tag == 2u) ? 1 : 2);\n param_44.offset = _2380.conf.pathseg_alloc.offset;\n uint param_45 = path_out_ref.offset >> uint(2);\n uint param_46 = out_tag;\n write_mem(param_44, param_45, param_46);\n param_47.offset = _2380.conf.pathseg_alloc.offset;\n PathStrokeCubicRef param_48 = PathStrokeCubicRef(path_out_ref.offset + 4u);\n PathStrokeCubic param_49 = path_cubic;\n PathStrokeCubic_write(param_47, param_48, param_49);\n break;\n }\n case 4u:\n case 3u:\n {\n ElementRef param_50 = this_ref;\n QuadSeg quad = Element_StrokeQuad_read(param_50);\n path_cubic.p0 = quad.p0;\n path_cubic.p1 = mix(quad.p1, quad.p0, vec2(0.3333333432674407958984375));\n path_cubic.p2 = mix(quad.p1, quad.p2, vec2(0.3333333432674407958984375));\n path_cubic.p3 = quad.p2;\n path_cubic.path_ix = st.path_count;\n path_cubic.trans_ix = st.trans_count;\n if (tag == 3u)\n {\n State param_51 = st;\n path_cubic.stroke = get_linewidth(param_51);\n }\n else\n {\n path_cubic.stroke = vec2(0.0);\n }\n path_out_ref = PathSegRef(_2380.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 52u));\n out_tag = uint((tag == 4u) ? 1 : 2);\n param_52.offset = _2380.conf.pathseg_alloc.offset;\n uint param_53 = path_out_ref.offset >> uint(2);\n uint param_54 = out_tag;\n write_mem(param_52, param_53, param_54);\n param_55.offset = _2380.conf.pathseg_alloc.offset;\n PathStrokeCubicRef param_56 = PathStrokeCubicRef(path_out_ref.offset + 4u);\n PathStrokeCubic param_57 = path_cubic;\n PathStrokeCubic_write(param_55, param_56, param_57);\n break;\n }\n case 6u:\n case 5u:\n {\n ElementRef param_58 = this_ref;\n CubicSeg cubic = Element_StrokeCubic_read(param_58);\n path_cubic.p0 = cubic.p0;\n path_cubic.p1 = cubic.p1;\n path_cubic.p2 = cubic.p2;\n path_cubic.p3 = cubic.p3;\n path_cubic.path_ix = st.path_count;\n path_cubic.trans_ix = st.trans_count;\n if (tag == 5u)\n {\n State param_59 = st;\n path_cubic.stroke = get_linewidth(param_59);\n }\n else\n {\n path_cubic.stroke = vec2(0.0);\n }\n path_out_ref = PathSegRef(_2380.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 52u));\n out_tag = uint((tag == 6u) ? 1 : 2);\n param_60.offset = _2380.conf.pathseg_alloc.offset;\n uint param_61 = path_out_ref.offset >> uint(2);\n uint param_62 = out_tag;\n write_mem(param_60, param_61, param_62);\n param_63.offset = _2380.conf.pathseg_alloc.offset;\n PathStrokeCubicRef param_64 = PathStrokeCubicRef(path_out_ref.offset + 4u);\n PathStrokeCubic param_65 = path_cubic;\n PathStrokeCubic_write(param_63, param_64, param_65);\n break;\n }\n case 7u:\n {\n ElementRef param_66 = this_ref;\n Stroke stroke = Element_Stroke_read(param_66);\n anno_stroke.rgba_color = stroke.rgba_color;\n State param_67 = st;\n vec2 lw = get_linewidth(param_67);\n anno_stroke.bbox = st.bbox + vec4(-lw, lw);\n anno_stroke.linewidth = st.linewidth * sqrt(abs((st.mat.x * st.mat.w) - (st.mat.y * st.mat.z)));\n out_ref = AnnotatedRef(_2380.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_68.offset = _2380.conf.anno_alloc.offset;\n AnnotatedRef param_69 = out_ref;\n AnnoStroke param_70 = anno_stroke;\n Annotated_Stroke_write(param_68, param_69, param_70);\n break;\n }\n case 8u:\n {\n ElementRef param_71 = this_ref;\n Fill fill = Element_Fill_read(param_71);\n anno_fill.rgba_color = fill.rgba_color;\n anno_fill.bbox = st.bbox;\n out_ref = AnnotatedRef(_2380.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_72.offset = _2380.conf.anno_alloc.offset;\n AnnotatedRef param_73 = out_ref;\n AnnoFill param_74 = anno_fill;\n Annotated_Fill_write(param_72, param_73, param_74);\n break;\n }\n case 13u:\n {\n ElementRef param_75 = this_ref;\n FillImage fill_img = Element_FillImage_read(param_75);\n anno_fill_img.index = fill_img.index;\n anno_fill_img.offset = fill_img.offset;\n anno_fill_img.bbox = st.bbox;\n out_ref = AnnotatedRef(_2380.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_76.offset = _2380.conf.anno_alloc.offset;\n AnnotatedRef param_77 = out_ref;\n AnnoFillImage param_78 = anno_fill_img;\n Annotated_FillImage_write(param_76, param_77, param_78);\n break;\n }\n case 11u:\n {\n ElementRef param_79 = this_ref;\n Clip begin_clip = Element_BeginClip_read(param_79);\n AnnoClip anno_begin_clip = AnnoClip(begin_clip.bbox);\n anno_begin_clip.bbox = begin_clip.bbox;\n out_ref = AnnotatedRef(_2380.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_80.offset = _2380.conf.anno_alloc.offset;\n AnnotatedRef param_81 = out_ref;\n AnnoClip param_82 = anno_begin_clip;\n Annotated_BeginClip_write(param_80, param_81, param_82);\n break;\n }\n case 12u:\n {\n ElementRef param_83 = this_ref;\n Clip end_clip = Element_EndClip_read(param_83);\n AnnoClip anno_end_clip = AnnoClip(end_clip.bbox);\n out_ref = AnnotatedRef(_2380.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_84.offset = _2380.conf.anno_alloc.offset;\n AnnotatedRef param_85 = out_ref;\n AnnoClip param_86 = anno_end_clip;\n Annotated_EndClip_write(param_84, param_85, param_86);\n break;\n }\n case 10u:\n {\n TransformSeg transform = TransformSeg(st.mat, st.translate);\n TransformSegRef trans_ref = TransformSegRef(_2380.conf.trans_alloc.offset + ((st.trans_count - 1u) * 24u));\n param_87.offset = _2380.conf.trans_alloc.offset;\n TransformSegRef param_88 = trans_ref;\n TransformSeg param_89 = transform;\n TransformSeg_write(param_87, param_88, param_89);\n break;\n }\n }\n }\n}\n\n", + GLSL310ES: "#version 310 es\nlayout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct ElementRef\n{\n uint offset;\n};\n\nstruct LineSegRef\n{\n uint offset;\n};\n\nstruct LineSeg\n{\n vec2 p0;\n vec2 p1;\n};\n\nstruct QuadSegRef\n{\n uint offset;\n};\n\nstruct QuadSeg\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n};\n\nstruct CubicSegRef\n{\n uint offset;\n};\n\nstruct CubicSeg\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n vec2 p3;\n};\n\nstruct FillColorRef\n{\n uint offset;\n};\n\nstruct FillColor\n{\n uint rgba_color;\n};\n\nstruct FillImageRef\n{\n uint offset;\n};\n\nstruct FillImage\n{\n uint index;\n ivec2 offset;\n};\n\nstruct SetLineWidthRef\n{\n uint offset;\n};\n\nstruct SetLineWidth\n{\n float width;\n};\n\nstruct TransformRef\n{\n uint offset;\n};\n\nstruct Transform\n{\n vec4 mat;\n vec2 translate;\n};\n\nstruct ClipRef\n{\n uint offset;\n};\n\nstruct Clip\n{\n vec4 bbox;\n};\n\nstruct SetFillModeRef\n{\n uint offset;\n};\n\nstruct SetFillMode\n{\n uint fill_mode;\n};\n\nstruct ElementTag\n{\n uint tag;\n uint flags;\n};\n\nstruct StateRef\n{\n uint offset;\n};\n\nstruct State\n{\n vec4 mat;\n vec2 translate;\n vec4 bbox;\n float linewidth;\n uint flags;\n uint path_count;\n uint pathseg_count;\n uint trans_count;\n};\n\nstruct AnnoImageRef\n{\n uint offset;\n};\n\nstruct AnnoImage\n{\n vec4 bbox;\n float linewidth;\n uint index;\n ivec2 offset;\n};\n\nstruct AnnoColorRef\n{\n uint offset;\n};\n\nstruct AnnoColor\n{\n vec4 bbox;\n float linewidth;\n uint rgba_color;\n};\n\nstruct AnnoBeginClipRef\n{\n uint offset;\n};\n\nstruct AnnoBeginClip\n{\n vec4 bbox;\n float linewidth;\n};\n\nstruct AnnoEndClipRef\n{\n uint offset;\n};\n\nstruct AnnoEndClip\n{\n vec4 bbox;\n};\n\nstruct AnnotatedRef\n{\n uint offset;\n};\n\nstruct PathCubicRef\n{\n uint offset;\n};\n\nstruct PathCubic\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n vec2 p3;\n uint path_ix;\n uint trans_ix;\n vec2 stroke;\n};\n\nstruct PathSegRef\n{\n uint offset;\n};\n\nstruct TransformSegRef\n{\n uint offset;\n};\n\nstruct TransformSeg\n{\n vec4 mat;\n vec2 translate;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _294;\n\nlayout(binding = 2, std430) readonly buffer SceneBuf\n{\n uint scene[];\n} _323;\n\nlayout(binding = 3, std430) coherent buffer StateBuf\n{\n uint part_counter;\n uint state[];\n} _779;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _2435;\n\nshared uint sh_part_ix;\nshared State sh_state[32];\nshared State sh_prefix;\n\nElementTag Element_tag(ElementRef ref)\n{\n uint tag_and_flags = _323.scene[ref.offset >> uint(2)];\n return ElementTag(tag_and_flags & 65535u, tag_and_flags >> uint(16));\n}\n\nLineSeg LineSeg_read(LineSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _323.scene[ix + 0u];\n uint raw1 = _323.scene[ix + 1u];\n uint raw2 = _323.scene[ix + 2u];\n uint raw3 = _323.scene[ix + 3u];\n LineSeg s;\n s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));\n s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n return s;\n}\n\nLineSeg Element_Line_read(ElementRef ref)\n{\n LineSegRef param = LineSegRef(ref.offset + 4u);\n return LineSeg_read(param);\n}\n\nQuadSeg QuadSeg_read(QuadSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _323.scene[ix + 0u];\n uint raw1 = _323.scene[ix + 1u];\n uint raw2 = _323.scene[ix + 2u];\n uint raw3 = _323.scene[ix + 3u];\n uint raw4 = _323.scene[ix + 4u];\n uint raw5 = _323.scene[ix + 5u];\n QuadSeg s;\n s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));\n s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n return s;\n}\n\nQuadSeg Element_Quad_read(ElementRef ref)\n{\n QuadSegRef param = QuadSegRef(ref.offset + 4u);\n return QuadSeg_read(param);\n}\n\nCubicSeg CubicSeg_read(CubicSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _323.scene[ix + 0u];\n uint raw1 = _323.scene[ix + 1u];\n uint raw2 = _323.scene[ix + 2u];\n uint raw3 = _323.scene[ix + 3u];\n uint raw4 = _323.scene[ix + 4u];\n uint raw5 = _323.scene[ix + 5u];\n uint raw6 = _323.scene[ix + 6u];\n uint raw7 = _323.scene[ix + 7u];\n CubicSeg s;\n s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));\n s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7));\n return s;\n}\n\nCubicSeg Element_Cubic_read(ElementRef ref)\n{\n CubicSegRef param = CubicSegRef(ref.offset + 4u);\n return CubicSeg_read(param);\n}\n\nSetLineWidth SetLineWidth_read(SetLineWidthRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _323.scene[ix + 0u];\n SetLineWidth s;\n s.width = uintBitsToFloat(raw0);\n return s;\n}\n\nSetLineWidth Element_SetLineWidth_read(ElementRef ref)\n{\n SetLineWidthRef param = SetLineWidthRef(ref.offset + 4u);\n return SetLineWidth_read(param);\n}\n\nTransform Transform_read(TransformRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _323.scene[ix + 0u];\n uint raw1 = _323.scene[ix + 1u];\n uint raw2 = _323.scene[ix + 2u];\n uint raw3 = _323.scene[ix + 3u];\n uint raw4 = _323.scene[ix + 4u];\n uint raw5 = _323.scene[ix + 5u];\n Transform s;\n s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n return s;\n}\n\nTransform Element_Transform_read(ElementRef ref)\n{\n TransformRef param = TransformRef(ref.offset + 4u);\n return Transform_read(param);\n}\n\nSetFillMode SetFillMode_read(SetFillModeRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _323.scene[ix + 0u];\n SetFillMode s;\n s.fill_mode = raw0;\n return s;\n}\n\nSetFillMode Element_SetFillMode_read(ElementRef ref)\n{\n SetFillModeRef param = SetFillModeRef(ref.offset + 4u);\n return SetFillMode_read(param);\n}\n\nState map_element(ElementRef ref)\n{\n ElementRef param = ref;\n uint tag = Element_tag(param).tag;\n State c;\n c.bbox = vec4(0.0);\n c.mat = vec4(1.0, 0.0, 0.0, 1.0);\n c.translate = vec2(0.0);\n c.linewidth = 1.0;\n c.flags = 0u;\n c.path_count = 0u;\n c.pathseg_count = 0u;\n c.trans_count = 0u;\n switch (tag)\n {\n case 1u:\n {\n ElementRef param_1 = ref;\n LineSeg line = Element_Line_read(param_1);\n vec2 _1919 = min(line.p0, line.p1);\n c.bbox = vec4(_1919.x, _1919.y, c.bbox.z, c.bbox.w);\n vec2 _1927 = max(line.p0, line.p1);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1927.x, _1927.y);\n c.pathseg_count = 1u;\n break;\n }\n case 2u:\n {\n ElementRef param_2 = ref;\n QuadSeg quad = Element_Quad_read(param_2);\n vec2 _1944 = min(min(quad.p0, quad.p1), quad.p2);\n c.bbox = vec4(_1944.x, _1944.y, c.bbox.z, c.bbox.w);\n vec2 _1955 = max(max(quad.p0, quad.p1), quad.p2);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1955.x, _1955.y);\n c.pathseg_count = 1u;\n break;\n }\n case 3u:\n {\n ElementRef param_3 = ref;\n CubicSeg cubic = Element_Cubic_read(param_3);\n vec2 _1975 = min(min(cubic.p0, cubic.p1), min(cubic.p2, cubic.p3));\n c.bbox = vec4(_1975.x, _1975.y, c.bbox.z, c.bbox.w);\n vec2 _1989 = max(max(cubic.p0, cubic.p1), max(cubic.p2, cubic.p3));\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1989.x, _1989.y);\n c.pathseg_count = 1u;\n break;\n }\n case 4u:\n case 9u:\n case 7u:\n {\n c.flags = 4u;\n c.path_count = 1u;\n break;\n }\n case 8u:\n {\n c.path_count = 1u;\n break;\n }\n case 5u:\n {\n ElementRef param_4 = ref;\n SetLineWidth lw = Element_SetLineWidth_read(param_4);\n c.linewidth = lw.width;\n c.flags = 1u;\n break;\n }\n case 6u:\n {\n ElementRef param_5 = ref;\n Transform t = Element_Transform_read(param_5);\n c.mat = t.mat;\n c.translate = t.translate;\n c.trans_count = 1u;\n break;\n }\n case 10u:\n {\n ElementRef param_6 = ref;\n SetFillMode fm = Element_SetFillMode_read(param_6);\n c.flags = 8u | (fm.fill_mode << uint(4));\n break;\n }\n }\n return c;\n}\n\nElementRef Element_index(ElementRef ref, uint index)\n{\n return ElementRef(ref.offset + (index * 36u));\n}\n\nState combine_state(State a, State b)\n{\n State c;\n c.bbox.x = (min(a.mat.x * b.bbox.x, a.mat.x * b.bbox.z) + min(a.mat.z * b.bbox.y, a.mat.z * b.bbox.w)) + a.translate.x;\n c.bbox.y = (min(a.mat.y * b.bbox.x, a.mat.y * b.bbox.z) + min(a.mat.w * b.bbox.y, a.mat.w * b.bbox.w)) + a.translate.y;\n c.bbox.z = (max(a.mat.x * b.bbox.x, a.mat.x * b.bbox.z) + max(a.mat.z * b.bbox.y, a.mat.z * b.bbox.w)) + a.translate.x;\n c.bbox.w = (max(a.mat.y * b.bbox.x, a.mat.y * b.bbox.z) + max(a.mat.w * b.bbox.y, a.mat.w * b.bbox.w)) + a.translate.y;\n bool _1657 = (a.flags & 4u) == 0u;\n bool _1665;\n if (_1657)\n {\n _1665 = b.bbox.z <= b.bbox.x;\n }\n else\n {\n _1665 = _1657;\n }\n bool _1673;\n if (_1665)\n {\n _1673 = b.bbox.w <= b.bbox.y;\n }\n else\n {\n _1673 = _1665;\n }\n if (_1673)\n {\n c.bbox = a.bbox;\n }\n else\n {\n bool _1683 = (a.flags & 4u) == 0u;\n bool _1690;\n if (_1683)\n {\n _1690 = (b.flags & 2u) == 0u;\n }\n else\n {\n _1690 = _1683;\n }\n bool _1707;\n if (_1690)\n {\n bool _1697 = a.bbox.z > a.bbox.x;\n bool _1706;\n if (!_1697)\n {\n _1706 = a.bbox.w > a.bbox.y;\n }\n else\n {\n _1706 = _1697;\n }\n _1707 = _1706;\n }\n else\n {\n _1707 = _1690;\n }\n if (_1707)\n {\n vec2 _1716 = min(a.bbox.xy, c.bbox.xy);\n c.bbox = vec4(_1716.x, _1716.y, c.bbox.z, c.bbox.w);\n vec2 _1726 = max(a.bbox.zw, c.bbox.zw);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1726.x, _1726.y);\n }\n }\n c.mat.x = (a.mat.x * b.mat.x) + (a.mat.z * b.mat.y);\n c.mat.y = (a.mat.y * b.mat.x) + (a.mat.w * b.mat.y);\n c.mat.z = (a.mat.x * b.mat.z) + (a.mat.z * b.mat.w);\n c.mat.w = (a.mat.y * b.mat.z) + (a.mat.w * b.mat.w);\n c.translate.x = ((a.mat.x * b.translate.x) + (a.mat.z * b.translate.y)) + a.translate.x;\n c.translate.y = ((a.mat.y * b.translate.x) + (a.mat.w * b.translate.y)) + a.translate.y;\n float _1812;\n if ((b.flags & 1u) == 0u)\n {\n _1812 = a.linewidth;\n }\n else\n {\n _1812 = b.linewidth;\n }\n c.linewidth = _1812;\n c.flags = (a.flags & 11u) | b.flags;\n c.flags |= ((a.flags & 4u) >> uint(1));\n uint _1842;\n if ((b.flags & 8u) == 0u)\n {\n _1842 = a.flags;\n }\n else\n {\n _1842 = b.flags;\n }\n uint fill_mode = _1842;\n fill_mode &= 16u;\n c.flags = (c.flags & 4294967279u) | fill_mode;\n c.path_count = a.path_count + b.path_count;\n c.pathseg_count = a.pathseg_count + b.pathseg_count;\n c.trans_count = a.trans_count + b.trans_count;\n return c;\n}\n\nStateRef state_aggregate_ref(uint partition_ix)\n{\n return StateRef(4u + (partition_ix * 124u));\n}\n\nvoid State_write(StateRef ref, State s)\n{\n uint ix = ref.offset >> uint(2);\n _779.state[ix + 0u] = floatBitsToUint(s.mat.x);\n _779.state[ix + 1u] = floatBitsToUint(s.mat.y);\n _779.state[ix + 2u] = floatBitsToUint(s.mat.z);\n _779.state[ix + 3u] = floatBitsToUint(s.mat.w);\n _779.state[ix + 4u] = floatBitsToUint(s.translate.x);\n _779.state[ix + 5u] = floatBitsToUint(s.translate.y);\n _779.state[ix + 6u] = floatBitsToUint(s.bbox.x);\n _779.state[ix + 7u] = floatBitsToUint(s.bbox.y);\n _779.state[ix + 8u] = floatBitsToUint(s.bbox.z);\n _779.state[ix + 9u] = floatBitsToUint(s.bbox.w);\n _779.state[ix + 10u] = floatBitsToUint(s.linewidth);\n _779.state[ix + 11u] = s.flags;\n _779.state[ix + 12u] = s.path_count;\n _779.state[ix + 13u] = s.pathseg_count;\n _779.state[ix + 14u] = s.trans_count;\n}\n\nStateRef state_prefix_ref(uint partition_ix)\n{\n return StateRef((4u + (partition_ix * 124u)) + 60u);\n}\n\nuint state_flag_index(uint partition_ix)\n{\n return partition_ix * 31u;\n}\n\nState State_read(StateRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _779.state[ix + 0u];\n uint raw1 = _779.state[ix + 1u];\n uint raw2 = _779.state[ix + 2u];\n uint raw3 = _779.state[ix + 3u];\n uint raw4 = _779.state[ix + 4u];\n uint raw5 = _779.state[ix + 5u];\n uint raw6 = _779.state[ix + 6u];\n uint raw7 = _779.state[ix + 7u];\n uint raw8 = _779.state[ix + 8u];\n uint raw9 = _779.state[ix + 9u];\n uint raw10 = _779.state[ix + 10u];\n uint raw11 = _779.state[ix + 11u];\n uint raw12 = _779.state[ix + 12u];\n uint raw13 = _779.state[ix + 13u];\n uint raw14 = _779.state[ix + 14u];\n State s;\n s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n s.bbox = vec4(uintBitsToFloat(raw6), uintBitsToFloat(raw7), uintBitsToFloat(raw8), uintBitsToFloat(raw9));\n s.linewidth = uintBitsToFloat(raw10);\n s.flags = raw11;\n s.path_count = raw12;\n s.pathseg_count = raw13;\n s.trans_count = raw14;\n return s;\n}\n\nuint fill_mode_from_flags(uint flags)\n{\n return flags & 1u;\n}\n\nvec2 get_linewidth(State st)\n{\n return vec2(length(st.mat.xz), length(st.mat.yw)) * (0.5 * st.linewidth);\n}\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _294.memory[offset] = val;\n}\n\nvoid PathCubic_write(Alloc a, PathCubicRef ref, PathCubic s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.p0.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.p0.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.p1.x);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.p1.y);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = floatBitsToUint(s.p2.x);\n write_mem(param_12, param_13, param_14);\n Alloc param_15 = a;\n uint param_16 = ix + 5u;\n uint param_17 = floatBitsToUint(s.p2.y);\n write_mem(param_15, param_16, param_17);\n Alloc param_18 = a;\n uint param_19 = ix + 6u;\n uint param_20 = floatBitsToUint(s.p3.x);\n write_mem(param_18, param_19, param_20);\n Alloc param_21 = a;\n uint param_22 = ix + 7u;\n uint param_23 = floatBitsToUint(s.p3.y);\n write_mem(param_21, param_22, param_23);\n Alloc param_24 = a;\n uint param_25 = ix + 8u;\n uint param_26 = s.path_ix;\n write_mem(param_24, param_25, param_26);\n Alloc param_27 = a;\n uint param_28 = ix + 9u;\n uint param_29 = s.trans_ix;\n write_mem(param_27, param_28, param_29);\n Alloc param_30 = a;\n uint param_31 = ix + 10u;\n uint param_32 = floatBitsToUint(s.stroke.x);\n write_mem(param_30, param_31, param_32);\n Alloc param_33 = a;\n uint param_34 = ix + 11u;\n uint param_35 = floatBitsToUint(s.stroke.y);\n write_mem(param_33, param_34, param_35);\n}\n\nvoid PathSeg_Cubic_write(Alloc a, PathSegRef ref, uint flags, PathCubic s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = (flags << uint(16)) | 1u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n PathCubicRef param_4 = PathCubicRef(ref.offset + 4u);\n PathCubic param_5 = s;\n PathCubic_write(param_3, param_4, param_5);\n}\n\nFillColor FillColor_read(FillColorRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _323.scene[ix + 0u];\n FillColor s;\n s.rgba_color = raw0;\n return s;\n}\n\nFillColor Element_FillColor_read(ElementRef ref)\n{\n FillColorRef param = FillColorRef(ref.offset + 4u);\n return FillColor_read(param);\n}\n\nvoid AnnoColor_write(Alloc a, AnnoColorRef ref, AnnoColor s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.bbox.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.bbox.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.bbox.z);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.bbox.w);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = floatBitsToUint(s.linewidth);\n write_mem(param_12, param_13, param_14);\n Alloc param_15 = a;\n uint param_16 = ix + 5u;\n uint param_17 = s.rgba_color;\n write_mem(param_15, param_16, param_17);\n}\n\nvoid Annotated_Color_write(Alloc a, AnnotatedRef ref, uint flags, AnnoColor s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = (flags << uint(16)) | 1u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n AnnoColorRef param_4 = AnnoColorRef(ref.offset + 4u);\n AnnoColor param_5 = s;\n AnnoColor_write(param_3, param_4, param_5);\n}\n\nFillImage FillImage_read(FillImageRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _323.scene[ix + 0u];\n uint raw1 = _323.scene[ix + 1u];\n FillImage s;\n s.index = raw0;\n s.offset = ivec2(int(raw1 << uint(16)) >> 16, int(raw1) >> 16);\n return s;\n}\n\nFillImage Element_FillImage_read(ElementRef ref)\n{\n FillImageRef param = FillImageRef(ref.offset + 4u);\n return FillImage_read(param);\n}\n\nvoid AnnoImage_write(Alloc a, AnnoImageRef ref, AnnoImage s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.bbox.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.bbox.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.bbox.z);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.bbox.w);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = floatBitsToUint(s.linewidth);\n write_mem(param_12, param_13, param_14);\n Alloc param_15 = a;\n uint param_16 = ix + 5u;\n uint param_17 = s.index;\n write_mem(param_15, param_16, param_17);\n Alloc param_18 = a;\n uint param_19 = ix + 6u;\n uint param_20 = (uint(s.offset.x) & 65535u) | (uint(s.offset.y) << uint(16));\n write_mem(param_18, param_19, param_20);\n}\n\nvoid Annotated_Image_write(Alloc a, AnnotatedRef ref, uint flags, AnnoImage s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = (flags << uint(16)) | 2u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n AnnoImageRef param_4 = AnnoImageRef(ref.offset + 4u);\n AnnoImage param_5 = s;\n AnnoImage_write(param_3, param_4, param_5);\n}\n\nClip Clip_read(ClipRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _323.scene[ix + 0u];\n uint raw1 = _323.scene[ix + 1u];\n uint raw2 = _323.scene[ix + 2u];\n uint raw3 = _323.scene[ix + 3u];\n Clip s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n return s;\n}\n\nClip Element_BeginClip_read(ElementRef ref)\n{\n ClipRef param = ClipRef(ref.offset + 4u);\n return Clip_read(param);\n}\n\nvoid AnnoBeginClip_write(Alloc a, AnnoBeginClipRef ref, AnnoBeginClip s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.bbox.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.bbox.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.bbox.z);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.bbox.w);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = floatBitsToUint(s.linewidth);\n write_mem(param_12, param_13, param_14);\n}\n\nvoid Annotated_BeginClip_write(Alloc a, AnnotatedRef ref, uint flags, AnnoBeginClip s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = (flags << uint(16)) | 3u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n AnnoBeginClipRef param_4 = AnnoBeginClipRef(ref.offset + 4u);\n AnnoBeginClip param_5 = s;\n AnnoBeginClip_write(param_3, param_4, param_5);\n}\n\nClip Element_EndClip_read(ElementRef ref)\n{\n ClipRef param = ClipRef(ref.offset + 4u);\n return Clip_read(param);\n}\n\nvoid AnnoEndClip_write(Alloc a, AnnoEndClipRef ref, AnnoEndClip s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.bbox.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.bbox.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.bbox.z);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.bbox.w);\n write_mem(param_9, param_10, param_11);\n}\n\nvoid Annotated_EndClip_write(Alloc a, AnnotatedRef ref, AnnoEndClip s)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint param_2 = 4u;\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n AnnoEndClipRef param_4 = AnnoEndClipRef(ref.offset + 4u);\n AnnoEndClip param_5 = s;\n AnnoEndClip_write(param_3, param_4, param_5);\n}\n\nvoid TransformSeg_write(Alloc a, TransformSegRef ref, TransformSeg s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.mat.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.mat.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.mat.z);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.mat.w);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = floatBitsToUint(s.translate.x);\n write_mem(param_12, param_13, param_14);\n Alloc param_15 = a;\n uint param_16 = ix + 5u;\n uint param_17 = floatBitsToUint(s.translate.y);\n write_mem(param_15, param_16, param_17);\n}\n\nvoid main()\n{\n if (_294.mem_error != 0u)\n {\n return;\n }\n if (gl_LocalInvocationID.x == 0u)\n {\n uint _2069 = atomicAdd(_779.part_counter, 1u);\n sh_part_ix = _2069;\n }\n barrier();\n uint part_ix = sh_part_ix;\n uint ix = (part_ix * 128u) + (gl_LocalInvocationID.x * 4u);\n ElementRef ref = ElementRef(ix * 36u);\n ElementRef param = ref;\n State th_state[4];\n th_state[0] = map_element(param);\n for (uint i = 1u; i < 4u; i++)\n {\n ElementRef param_1 = ref;\n uint param_2 = i;\n ElementRef param_3 = Element_index(param_1, param_2);\n State param_4 = th_state[i - 1u];\n State param_5 = map_element(param_3);\n th_state[i] = combine_state(param_4, param_5);\n }\n State agg = th_state[3];\n sh_state[gl_LocalInvocationID.x] = agg;\n for (uint i_1 = 0u; i_1 < 5u; i_1++)\n {\n barrier();\n if (gl_LocalInvocationID.x >= uint(1 << int(i_1)))\n {\n State other = sh_state[gl_LocalInvocationID.x - uint(1 << int(i_1))];\n State param_6 = other;\n State param_7 = agg;\n agg = combine_state(param_6, param_7);\n }\n barrier();\n sh_state[gl_LocalInvocationID.x] = agg;\n }\n State exclusive;\n exclusive.bbox = vec4(0.0);\n exclusive.mat = vec4(1.0, 0.0, 0.0, 1.0);\n exclusive.translate = vec2(0.0);\n exclusive.linewidth = 1.0;\n exclusive.flags = 0u;\n exclusive.path_count = 0u;\n exclusive.pathseg_count = 0u;\n exclusive.trans_count = 0u;\n if (gl_LocalInvocationID.x == 31u)\n {\n uint param_8 = part_ix;\n StateRef param_9 = state_aggregate_ref(param_8);\n State param_10 = agg;\n State_write(param_9, param_10);\n uint flag = 1u;\n memoryBarrierBuffer();\n if (part_ix == 0u)\n {\n uint param_11 = part_ix;\n StateRef param_12 = state_prefix_ref(param_11);\n State param_13 = agg;\n State_write(param_12, param_13);\n flag = 2u;\n }\n uint param_14 = part_ix;\n _779.state[state_flag_index(param_14)] = flag;\n if (part_ix != 0u)\n {\n uint look_back_ix = part_ix - 1u;\n uint their_ix = 0u;\n State their_agg;\n while (true)\n {\n uint param_15 = look_back_ix;\n flag = _779.state[state_flag_index(param_15)];\n if (flag == 2u)\n {\n uint param_16 = look_back_ix;\n StateRef param_17 = state_prefix_ref(param_16);\n State their_prefix = State_read(param_17);\n State param_18 = their_prefix;\n State param_19 = exclusive;\n exclusive = combine_state(param_18, param_19);\n break;\n }\n else\n {\n if (flag == 1u)\n {\n uint param_20 = look_back_ix;\n StateRef param_21 = state_aggregate_ref(param_20);\n their_agg = State_read(param_21);\n State param_22 = their_agg;\n State param_23 = exclusive;\n exclusive = combine_state(param_22, param_23);\n look_back_ix--;\n their_ix = 0u;\n continue;\n }\n }\n ElementRef ref_1 = ElementRef(((look_back_ix * 128u) + their_ix) * 36u);\n ElementRef param_24 = ref_1;\n State s = map_element(param_24);\n if (their_ix == 0u)\n {\n their_agg = s;\n }\n else\n {\n State param_25 = their_agg;\n State param_26 = s;\n their_agg = combine_state(param_25, param_26);\n }\n their_ix++;\n if (their_ix == 128u)\n {\n State param_27 = their_agg;\n State param_28 = exclusive;\n exclusive = combine_state(param_27, param_28);\n if (look_back_ix == 0u)\n {\n break;\n }\n look_back_ix--;\n their_ix = 0u;\n }\n }\n State param_29 = exclusive;\n State param_30 = agg;\n State inclusive_prefix = combine_state(param_29, param_30);\n sh_prefix = exclusive;\n uint param_31 = part_ix;\n StateRef param_32 = state_prefix_ref(param_31);\n State param_33 = inclusive_prefix;\n State_write(param_32, param_33);\n memoryBarrierBuffer();\n flag = 2u;\n uint param_34 = part_ix;\n _779.state[state_flag_index(param_34)] = flag;\n }\n }\n barrier();\n if (part_ix != 0u)\n {\n exclusive = sh_prefix;\n }\n State row = exclusive;\n if (gl_LocalInvocationID.x > 0u)\n {\n State other_1 = sh_state[gl_LocalInvocationID.x - 1u];\n State param_35 = row;\n State param_36 = other_1;\n row = combine_state(param_35, param_36);\n }\n PathCubic path_cubic;\n PathSegRef path_out_ref;\n Alloc param_45;\n Alloc param_51;\n Alloc param_57;\n AnnoColor anno_fill;\n AnnotatedRef out_ref;\n Alloc param_63;\n AnnoImage anno_img;\n Alloc param_69;\n AnnoBeginClip anno_begin_clip;\n Alloc param_75;\n Alloc param_80;\n Alloc param_83;\n for (uint i_2 = 0u; i_2 < 4u; i_2++)\n {\n State param_37 = row;\n State param_38 = th_state[i_2];\n State st = combine_state(param_37, param_38);\n ElementRef param_39 = ref;\n uint param_40 = i_2;\n ElementRef this_ref = Element_index(param_39, param_40);\n ElementRef param_41 = this_ref;\n ElementTag tag = Element_tag(param_41);\n uint param_42 = st.flags >> uint(4);\n uint fill_mode = fill_mode_from_flags(param_42);\n bool is_stroke = fill_mode == 1u;\n switch (tag.tag)\n {\n case 1u:\n {\n ElementRef param_43 = this_ref;\n LineSeg line = Element_Line_read(param_43);\n path_cubic.p0 = line.p0;\n path_cubic.p1 = mix(line.p0, line.p1, vec2(0.3333333432674407958984375));\n path_cubic.p2 = mix(line.p1, line.p0, vec2(0.3333333432674407958984375));\n path_cubic.p3 = line.p1;\n path_cubic.path_ix = st.path_count;\n path_cubic.trans_ix = st.trans_count;\n if (is_stroke)\n {\n State param_44 = st;\n path_cubic.stroke = get_linewidth(param_44);\n }\n else\n {\n path_cubic.stroke = vec2(0.0);\n }\n path_out_ref = PathSegRef(_2435.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 52u));\n param_45.offset = _2435.conf.pathseg_alloc.offset;\n PathSegRef param_46 = path_out_ref;\n uint param_47 = fill_mode;\n PathCubic param_48 = path_cubic;\n PathSeg_Cubic_write(param_45, param_46, param_47, param_48);\n break;\n }\n case 2u:\n {\n ElementRef param_49 = this_ref;\n QuadSeg quad = Element_Quad_read(param_49);\n path_cubic.p0 = quad.p0;\n path_cubic.p1 = mix(quad.p1, quad.p0, vec2(0.3333333432674407958984375));\n path_cubic.p2 = mix(quad.p1, quad.p2, vec2(0.3333333432674407958984375));\n path_cubic.p3 = quad.p2;\n path_cubic.path_ix = st.path_count;\n path_cubic.trans_ix = st.trans_count;\n if (is_stroke)\n {\n State param_50 = st;\n path_cubic.stroke = get_linewidth(param_50);\n }\n else\n {\n path_cubic.stroke = vec2(0.0);\n }\n path_out_ref = PathSegRef(_2435.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 52u));\n param_51.offset = _2435.conf.pathseg_alloc.offset;\n PathSegRef param_52 = path_out_ref;\n uint param_53 = fill_mode;\n PathCubic param_54 = path_cubic;\n PathSeg_Cubic_write(param_51, param_52, param_53, param_54);\n break;\n }\n case 3u:\n {\n ElementRef param_55 = this_ref;\n CubicSeg cubic = Element_Cubic_read(param_55);\n path_cubic.p0 = cubic.p0;\n path_cubic.p1 = cubic.p1;\n path_cubic.p2 = cubic.p2;\n path_cubic.p3 = cubic.p3;\n path_cubic.path_ix = st.path_count;\n path_cubic.trans_ix = st.trans_count;\n if (is_stroke)\n {\n State param_56 = st;\n path_cubic.stroke = get_linewidth(param_56);\n }\n else\n {\n path_cubic.stroke = vec2(0.0);\n }\n path_out_ref = PathSegRef(_2435.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 52u));\n param_57.offset = _2435.conf.pathseg_alloc.offset;\n PathSegRef param_58 = path_out_ref;\n uint param_59 = fill_mode;\n PathCubic param_60 = path_cubic;\n PathSeg_Cubic_write(param_57, param_58, param_59, param_60);\n break;\n }\n case 4u:\n {\n ElementRef param_61 = this_ref;\n FillColor fill = Element_FillColor_read(param_61);\n anno_fill.rgba_color = fill.rgba_color;\n if (is_stroke)\n {\n State param_62 = st;\n vec2 lw = get_linewidth(param_62);\n anno_fill.bbox = st.bbox + vec4(-lw, lw);\n anno_fill.linewidth = st.linewidth * sqrt(abs((st.mat.x * st.mat.w) - (st.mat.y * st.mat.z)));\n }\n else\n {\n anno_fill.bbox = st.bbox;\n anno_fill.linewidth = 0.0;\n }\n out_ref = AnnotatedRef(_2435.conf.anno_alloc.offset + ((st.path_count - 1u) * 32u));\n param_63.offset = _2435.conf.anno_alloc.offset;\n AnnotatedRef param_64 = out_ref;\n uint param_65 = fill_mode;\n AnnoColor param_66 = anno_fill;\n Annotated_Color_write(param_63, param_64, param_65, param_66);\n break;\n }\n case 9u:\n {\n ElementRef param_67 = this_ref;\n FillImage fill_img = Element_FillImage_read(param_67);\n anno_img.index = fill_img.index;\n anno_img.offset = fill_img.offset;\n if (is_stroke)\n {\n State param_68 = st;\n vec2 lw_1 = get_linewidth(param_68);\n anno_img.bbox = st.bbox + vec4(-lw_1, lw_1);\n anno_img.linewidth = st.linewidth * sqrt(abs((st.mat.x * st.mat.w) - (st.mat.y * st.mat.z)));\n }\n else\n {\n anno_img.bbox = st.bbox;\n anno_img.linewidth = 0.0;\n }\n out_ref = AnnotatedRef(_2435.conf.anno_alloc.offset + ((st.path_count - 1u) * 32u));\n param_69.offset = _2435.conf.anno_alloc.offset;\n AnnotatedRef param_70 = out_ref;\n uint param_71 = fill_mode;\n AnnoImage param_72 = anno_img;\n Annotated_Image_write(param_69, param_70, param_71, param_72);\n break;\n }\n case 7u:\n {\n ElementRef param_73 = this_ref;\n Clip begin_clip = Element_BeginClip_read(param_73);\n if (is_stroke)\n {\n State param_74 = st;\n vec2 lw_2 = get_linewidth(param_74);\n anno_begin_clip.bbox = begin_clip.bbox + vec4(-lw_2, lw_2);\n anno_begin_clip.linewidth = st.linewidth * sqrt(abs((st.mat.x * st.mat.w) - (st.mat.y * st.mat.z)));\n }\n else\n {\n anno_begin_clip.bbox = begin_clip.bbox;\n anno_fill.linewidth = 0.0;\n }\n out_ref = AnnotatedRef(_2435.conf.anno_alloc.offset + ((st.path_count - 1u) * 32u));\n param_75.offset = _2435.conf.anno_alloc.offset;\n AnnotatedRef param_76 = out_ref;\n uint param_77 = fill_mode;\n AnnoBeginClip param_78 = anno_begin_clip;\n Annotated_BeginClip_write(param_75, param_76, param_77, param_78);\n break;\n }\n case 8u:\n {\n ElementRef param_79 = this_ref;\n Clip end_clip = Element_EndClip_read(param_79);\n AnnoEndClip anno_end_clip = AnnoEndClip(end_clip.bbox);\n out_ref = AnnotatedRef(_2435.conf.anno_alloc.offset + ((st.path_count - 1u) * 32u));\n param_80.offset = _2435.conf.anno_alloc.offset;\n AnnotatedRef param_81 = out_ref;\n AnnoEndClip param_82 = anno_end_clip;\n Annotated_EndClip_write(param_80, param_81, param_82);\n break;\n }\n case 6u:\n {\n TransformSeg transform = TransformSeg(st.mat, st.translate);\n TransformSegRef trans_ref = TransformSegRef(_2435.conf.trans_alloc.offset + ((st.trans_count - 1u) * 24u));\n param_83.offset = _2435.conf.trans_alloc.offset;\n TransformSegRef param_84 = trans_ref;\n TransformSeg param_85 = transform;\n TransformSeg_write(param_83, param_84, param_85);\n break;\n }\n }\n }\n}\n\n", } shader_intersect_frag = driver.ShaderSources{ Name: "intersect.frag", @@ -166,7 +166,7 @@ var ( } shader_kernel4_comp = driver.ShaderSources{ Name: "kernel4.comp", - GLSL310ES: "#version 310 es\nlayout(local_size_x = 32, local_size_y = 4, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct MallocResult\n{\n Alloc alloc;\n bool failed;\n};\n\nstruct CmdStrokeRef\n{\n uint offset;\n};\n\nstruct CmdStroke\n{\n uint tile_ref;\n float half_width;\n uint rgba_color;\n};\n\nstruct CmdFillRef\n{\n uint offset;\n};\n\nstruct CmdFill\n{\n uint tile_ref;\n int backdrop;\n uint rgba_color;\n};\n\nstruct CmdFillImageRef\n{\n uint offset;\n};\n\nstruct CmdFillImage\n{\n uint tile_ref;\n int backdrop;\n uint index;\n ivec2 offset;\n};\n\nstruct CmdBeginClipRef\n{\n uint offset;\n};\n\nstruct CmdBeginClip\n{\n uint tile_ref;\n int backdrop;\n};\n\nstruct CmdBeginSolidClipRef\n{\n uint offset;\n};\n\nstruct CmdBeginSolidClip\n{\n float alpha;\n};\n\nstruct CmdEndClipRef\n{\n uint offset;\n};\n\nstruct CmdEndClip\n{\n float alpha;\n};\n\nstruct CmdSolidRef\n{\n uint offset;\n};\n\nstruct CmdSolid\n{\n uint rgba_color;\n};\n\nstruct CmdSolidImageRef\n{\n uint offset;\n};\n\nstruct CmdSolidImage\n{\n uint index;\n ivec2 offset;\n};\n\nstruct CmdJumpRef\n{\n uint offset;\n};\n\nstruct CmdJump\n{\n uint new_ref;\n};\n\nstruct CmdRef\n{\n uint offset;\n};\n\nstruct TileSegRef\n{\n uint offset;\n};\n\nstruct TileSeg\n{\n vec2 origin;\n vec2 vector;\n float y_edge;\n TileSegRef next;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _237;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _1138;\n\nlayout(binding = 3, rgba8) uniform readonly highp image2D images[1];\nlayout(binding = 2, rgba8) uniform writeonly highp image2D image;\n\nshared MallocResult sh_clip_alloc;\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nAlloc slice_mem(Alloc a, uint offset, uint size)\n{\n uint param = a.offset + offset;\n uint param_1 = size;\n return new_alloc(param, param_1);\n}\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _237.memory[offset];\n return v;\n}\n\nuint Cmd_tag(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n return read_mem(param, param_1);\n}\n\nCmdStroke CmdStroke_read(Alloc a, CmdStrokeRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n CmdStroke s;\n s.tile_ref = raw0;\n s.half_width = uintBitsToFloat(raw1);\n s.rgba_color = raw2;\n return s;\n}\n\nCmdStroke Cmd_Stroke_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdStrokeRef param_1 = CmdStrokeRef(ref.offset + 4u);\n return CmdStroke_read(param, param_1);\n}\n\nTileSeg TileSeg_read(Alloc a, TileSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n Alloc param_10 = a;\n uint param_11 = ix + 5u;\n uint raw5 = read_mem(param_10, param_11);\n TileSeg s;\n s.origin = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));\n s.vector = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.y_edge = uintBitsToFloat(raw4);\n s.next = TileSegRef(raw5);\n return s;\n}\n\nvec3 fromsRGB(vec3 srgb)\n{\n bvec3 cutoff = greaterThanEqual(srgb, vec3(0.040449999272823333740234375));\n vec3 below = srgb / vec3(12.9200000762939453125);\n vec3 above = pow((srgb + vec3(0.054999999701976776123046875)) / vec3(1.05499994754791259765625), vec3(2.400000095367431640625));\n return mix(below, above, cutoff);\n}\n\nvec4 unpacksRGB(uint srgba)\n{\n vec4 color = unpackUnorm4x8(srgba).wzyx;\n vec3 param = color.xyz;\n return vec4(fromsRGB(param), color.w);\n}\n\nCmdFill CmdFill_read(Alloc a, CmdFillRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n CmdFill s;\n s.tile_ref = raw0;\n s.backdrop = int(raw1);\n s.rgba_color = raw2;\n return s;\n}\n\nCmdFill Cmd_Fill_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdFillRef param_1 = CmdFillRef(ref.offset + 4u);\n return CmdFill_read(param, param_1);\n}\n\nfloat[8] computeArea(vec2 xy, int backdrop, uint tile_ref)\n{\n float area[8];\n for (uint k = 0u; k < 8u; k++)\n {\n area[k] = float(backdrop);\n }\n TileSegRef tile_seg_ref = TileSegRef(tile_ref);\n do\n {\n uint param = tile_seg_ref.offset;\n uint param_1 = 24u;\n Alloc param_2 = new_alloc(param, param_1);\n TileSegRef param_3 = tile_seg_ref;\n TileSeg seg = TileSeg_read(param_2, param_3);\n for (uint k_1 = 0u; k_1 < 8u; k_1++)\n {\n vec2 my_xy = vec2(xy.x, xy.y + float(k_1 * 4u));\n vec2 start = seg.origin - my_xy;\n vec2 end = start + seg.vector;\n vec2 window = clamp(vec2(start.y, end.y), vec2(0.0), vec2(1.0));\n if (!(window.x == window.y))\n {\n vec2 t = (window - vec2(start.y)) / vec2(seg.vector.y);\n vec2 xs = vec2(mix(start.x, end.x, t.x), mix(start.x, end.x, t.y));\n float xmin = min(min(xs.x, xs.y), 1.0) - 9.9999999747524270787835121154785e-07;\n float xmax = max(xs.x, xs.y);\n float b = min(xmax, 1.0);\n float c = max(b, 0.0);\n float d = max(xmin, 0.0);\n float a = ((b + (0.5 * ((d * d) - (c * c)))) - xmin) / (xmax - xmin);\n area[k_1] += (a * (window.x - window.y));\n }\n area[k_1] += (sign(seg.vector.x) * clamp((my_xy.y - seg.y_edge) + 1.0, 0.0, 1.0));\n }\n tile_seg_ref = seg.next;\n } while (tile_seg_ref.offset != 0u);\n for (uint k_2 = 0u; k_2 < 8u; k_2++)\n {\n area[k_2] = min(abs(area[k_2]), 1.0);\n }\n return area;\n}\n\nCmdFillImage CmdFillImage_read(Alloc a, CmdFillImageRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n CmdFillImage s;\n s.tile_ref = raw0;\n s.backdrop = int(raw1);\n s.index = raw2;\n s.offset = ivec2(int(raw3 << uint(16)) >> 16, int(raw3) >> 16);\n return s;\n}\n\nCmdFillImage Cmd_FillImage_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdFillImageRef param_1 = CmdFillImageRef(ref.offset + 4u);\n return CmdFillImage_read(param, param_1);\n}\n\nvec4[8] fillImage(uvec2 xy, CmdSolidImage cmd_img)\n{\n vec4 rgba[8];\n for (uint i = 0u; i < 8u; i++)\n {\n ivec2 uv = ivec2(int(xy.x), int(xy.y + (i * 4u))) + cmd_img.offset;\n vec4 fg_rgba = imageLoad(images[0], uv);\n vec3 param = fg_rgba.xyz;\n vec3 _1111 = fromsRGB(param);\n fg_rgba = vec4(_1111.x, _1111.y, _1111.z, fg_rgba.w);\n rgba[i] = fg_rgba;\n }\n return rgba;\n}\n\nMallocResult malloc(uint size)\n{\n MallocResult r;\n r.failed = false;\n uint _243 = atomicAdd(_237.mem_offset, size);\n uint offset = _243;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_237.memory.length())) * 4))\n {\n r.failed = true;\n uint _264 = atomicMax(_237.mem_error, 1u);\n return r;\n }\n return r;\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _237.memory[offset] = val;\n}\n\nMallocResult alloc_clip_buf(uint link)\n{\n bool _755 = gl_LocalInvocationID.x == 0u;\n bool _761;\n if (_755)\n {\n _761 = gl_LocalInvocationID.y == 0u;\n }\n else\n {\n _761 = _755;\n }\n if (_761)\n {\n uint param = 4100u;\n MallocResult _767 = malloc(param);\n MallocResult m = _767;\n if (!m.failed)\n {\n Alloc param_1 = m.alloc;\n uint param_2 = (m.alloc.offset >> uint(2)) + 1024u;\n uint param_3 = link;\n write_mem(param_1, param_2, param_3);\n }\n sh_clip_alloc = m;\n }\n barrier();\n return sh_clip_alloc;\n}\n\nCmdBeginClip CmdBeginClip_read(Alloc a, CmdBeginClipRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n CmdBeginClip s;\n s.tile_ref = raw0;\n s.backdrop = int(raw1);\n return s;\n}\n\nCmdBeginClip Cmd_BeginClip_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdBeginClipRef param_1 = CmdBeginClipRef(ref.offset + 4u);\n return CmdBeginClip_read(param, param_1);\n}\n\nvec3 tosRGB(vec3 rgb)\n{\n bvec3 cutoff = greaterThanEqual(rgb, vec3(0.003130800090730190277099609375));\n vec3 below = vec3(12.9200000762939453125) * rgb;\n vec3 above = (vec3(1.05499994754791259765625) * pow(rgb, vec3(0.416660010814666748046875))) - vec3(0.054999999701976776123046875);\n return mix(below, above, cutoff);\n}\n\nuint packsRGB(inout vec4 rgba)\n{\n vec3 param = rgba.xyz;\n rgba = vec4(tosRGB(param), rgba.w);\n return packUnorm4x8(rgba.wzyx);\n}\n\nCmdBeginSolidClip CmdBeginSolidClip_read(Alloc a, CmdBeginSolidClipRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n CmdBeginSolidClip s;\n s.alpha = uintBitsToFloat(raw0);\n return s;\n}\n\nCmdBeginSolidClip Cmd_BeginSolidClip_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdBeginSolidClipRef param_1 = CmdBeginSolidClipRef(ref.offset + 4u);\n return CmdBeginSolidClip_read(param, param_1);\n}\n\nCmdEndClip CmdEndClip_read(Alloc a, CmdEndClipRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n CmdEndClip s;\n s.alpha = uintBitsToFloat(raw0);\n return s;\n}\n\nCmdEndClip Cmd_EndClip_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdEndClipRef param_1 = CmdEndClipRef(ref.offset + 4u);\n return CmdEndClip_read(param, param_1);\n}\n\nCmdSolid CmdSolid_read(Alloc a, CmdSolidRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n CmdSolid s;\n s.rgba_color = raw0;\n return s;\n}\n\nCmdSolid Cmd_Solid_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdSolidRef param_1 = CmdSolidRef(ref.offset + 4u);\n return CmdSolid_read(param, param_1);\n}\n\nCmdSolidImage CmdSolidImage_read(Alloc a, CmdSolidImageRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n CmdSolidImage s;\n s.index = raw0;\n s.offset = ivec2(int(raw1 << uint(16)) >> 16, int(raw1) >> 16);\n return s;\n}\n\nCmdSolidImage Cmd_SolidImage_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdSolidImageRef param_1 = CmdSolidImageRef(ref.offset + 4u);\n return CmdSolidImage_read(param, param_1);\n}\n\nCmdJump CmdJump_read(Alloc a, CmdJumpRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n CmdJump s;\n s.new_ref = raw0;\n return s;\n}\n\nCmdJump Cmd_Jump_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdJumpRef param_1 = CmdJumpRef(ref.offset + 4u);\n return CmdJump_read(param, param_1);\n}\n\nvoid main()\n{\n if (_237.mem_error != 0u)\n {\n return;\n }\n uint tile_ix = (gl_WorkGroupID.y * _1138.conf.width_in_tiles) + gl_WorkGroupID.x;\n Alloc param;\n param.offset = _1138.conf.ptcl_alloc.offset;\n uint param_1 = tile_ix * 1024u;\n uint param_2 = 1024u;\n Alloc cmd_alloc = slice_mem(param, param_1, param_2);\n CmdRef cmd_ref = CmdRef(cmd_alloc.offset);\n uvec2 xy_uint = uvec2(gl_GlobalInvocationID.x, gl_LocalInvocationID.y + (32u * gl_WorkGroupID.y));\n vec2 xy = vec2(xy_uint);\n uint blend_spill = 0u;\n uint blend_sp = 0u;\n uint param_3 = 0u;\n uint param_4 = 0u;\n Alloc clip_tos = new_alloc(param_3, param_4);\n vec3 rgb[8];\n float mask[8];\n for (uint i = 0u; i < 8u; i++)\n {\n rgb[i] = vec3(0.5);\n mask[i] = 1.0;\n }\n float df[8];\n vec4 fg_rgba;\n float area[8];\n vec4 rgba[8];\n uint blend_slot;\n uint blend_stack[4][8];\n while (true)\n {\n Alloc param_5 = cmd_alloc;\n CmdRef param_6 = cmd_ref;\n uint tag = Cmd_tag(param_5, param_6);\n if (tag == 0u)\n {\n break;\n }\n switch (tag)\n {\n case 6u:\n {\n Alloc param_7 = cmd_alloc;\n CmdRef param_8 = cmd_ref;\n CmdStroke stroke = Cmd_Stroke_read(param_7, param_8);\n for (uint k = 0u; k < 8u; k++)\n {\n df[k] = 1000000000.0;\n }\n TileSegRef tile_seg_ref = TileSegRef(stroke.tile_ref);\n do\n {\n uint param_9 = tile_seg_ref.offset;\n uint param_10 = 24u;\n Alloc param_11 = new_alloc(param_9, param_10);\n TileSegRef param_12 = tile_seg_ref;\n TileSeg seg = TileSeg_read(param_11, param_12);\n vec2 line_vec = seg.vector;\n for (uint k_1 = 0u; k_1 < 8u; k_1++)\n {\n vec2 dpos = (xy + vec2(0.5)) - seg.origin;\n dpos.y += float(k_1 * 4u);\n float t = clamp(dot(line_vec, dpos) / dot(line_vec, line_vec), 0.0, 1.0);\n df[k_1] = min(df[k_1], length((line_vec * t) - dpos));\n }\n tile_seg_ref = seg.next;\n } while (tile_seg_ref.offset != 0u);\n uint param_13 = stroke.rgba_color;\n fg_rgba = unpacksRGB(param_13);\n for (uint k_2 = 0u; k_2 < 8u; k_2++)\n {\n float alpha = clamp((stroke.half_width + 0.5) - df[k_2], 0.0, 1.0);\n rgb[k_2] = mix(rgb[k_2], fg_rgba.xyz, vec3((mask[k_2] * alpha) * fg_rgba.w));\n }\n break;\n }\n case 1u:\n {\n Alloc param_14 = cmd_alloc;\n CmdRef param_15 = cmd_ref;\n CmdFill fill = Cmd_Fill_read(param_14, param_15);\n vec2 param_16 = xy;\n int param_17 = fill.backdrop;\n uint param_18 = fill.tile_ref;\n area = computeArea(param_16, param_17, param_18);\n uint param_19 = fill.rgba_color;\n fg_rgba = unpacksRGB(param_19);\n for (uint k_3 = 0u; k_3 < 8u; k_3++)\n {\n rgb[k_3] = mix(rgb[k_3], fg_rgba.xyz, vec3((mask[k_3] * area[k_3]) * fg_rgba.w));\n }\n break;\n }\n case 2u:\n {\n Alloc param_20 = cmd_alloc;\n CmdRef param_21 = cmd_ref;\n CmdFillImage fill_img = Cmd_FillImage_read(param_20, param_21);\n vec2 param_22 = xy;\n int param_23 = fill_img.backdrop;\n uint param_24 = fill_img.tile_ref;\n area = computeArea(param_22, param_23, param_24);\n uvec2 param_25 = xy_uint;\n CmdSolidImage param_26 = CmdSolidImage(fill_img.index, fill_img.offset);\n rgba = fillImage(param_25, param_26);\n for (uint k_4 = 0u; k_4 < 8u; k_4++)\n {\n rgb[k_4] = mix(rgb[k_4], rgba[k_4].xyz, vec3((mask[k_4] * area[k_4]) * rgba[k_4].w));\n }\n break;\n }\n case 3u:\n case 4u:\n {\n blend_slot = blend_sp % 4u;\n if (blend_sp == (blend_spill + 4u))\n {\n uint param_27 = clip_tos.offset;\n MallocResult _1482 = alloc_clip_buf(param_27);\n MallocResult m = _1482;\n if (m.failed)\n {\n return;\n }\n clip_tos = m.alloc;\n uint base_ix = ((clip_tos.offset >> uint(2)) + gl_LocalInvocationID.x) + (32u * gl_LocalInvocationID.y);\n for (uint k_5 = 0u; k_5 < 8u; k_5++)\n {\n Alloc param_28 = clip_tos;\n uint param_29 = base_ix + ((k_5 * 32u) * 4u);\n uint param_30 = blend_stack[blend_slot][k_5];\n write_mem(param_28, param_29, param_30);\n }\n blend_spill++;\n }\n if (tag == 3u)\n {\n Alloc param_31 = cmd_alloc;\n CmdRef param_32 = cmd_ref;\n CmdBeginClip begin_clip = Cmd_BeginClip_read(param_31, param_32);\n vec2 param_33 = xy;\n int param_34 = begin_clip.backdrop;\n uint param_35 = begin_clip.tile_ref;\n area = computeArea(param_33, param_34, param_35);\n for (uint k_6 = 0u; k_6 < 8u; k_6++)\n {\n vec4 param_36 = vec4(rgb[k_6], clamp(abs(area[k_6]), 0.0, 1.0));\n uint _1573 = packsRGB(param_36);\n blend_stack[blend_slot][k_6] = _1573;\n }\n }\n else\n {\n Alloc param_37 = cmd_alloc;\n CmdRef param_38 = cmd_ref;\n CmdBeginSolidClip begin_solid_clip = Cmd_BeginSolidClip_read(param_37, param_38);\n float solid_alpha = begin_solid_clip.alpha;\n for (uint k_7 = 0u; k_7 < 8u; k_7++)\n {\n vec4 param_39 = vec4(rgb[k_7], solid_alpha);\n uint _1606 = packsRGB(param_39);\n blend_stack[blend_slot][k_7] = _1606;\n }\n }\n blend_sp++;\n break;\n }\n case 5u:\n {\n Alloc param_40 = cmd_alloc;\n CmdRef param_41 = cmd_ref;\n CmdEndClip end_clip = Cmd_EndClip_read(param_40, param_41);\n blend_slot = (blend_sp - 1u) % 4u;\n if (blend_sp == blend_spill)\n {\n uint base_ix_1 = ((clip_tos.offset >> uint(2)) + gl_LocalInvocationID.x) + (32u * gl_LocalInvocationID.y);\n for (uint k_8 = 0u; k_8 < 8u; k_8++)\n {\n Alloc param_42 = clip_tos;\n uint param_43 = base_ix_1 + ((k_8 * 32u) * 4u);\n blend_stack[blend_slot][k_8] = read_mem(param_42, param_43);\n }\n Alloc param_44 = clip_tos;\n uint param_45 = (clip_tos.offset >> uint(2)) + 1024u;\n clip_tos.offset = read_mem(param_44, param_45);\n blend_spill--;\n }\n blend_sp--;\n for (uint k_9 = 0u; k_9 < 8u; k_9++)\n {\n uint param_46 = blend_stack[blend_slot][k_9];\n vec4 rgba_1 = unpacksRGB(param_46);\n rgb[k_9] = mix(rgba_1.xyz, rgb[k_9], vec3(end_clip.alpha * rgba_1.w));\n }\n break;\n }\n case 7u:\n {\n Alloc param_47 = cmd_alloc;\n CmdRef param_48 = cmd_ref;\n CmdSolid solid = Cmd_Solid_read(param_47, param_48);\n uint param_49 = solid.rgba_color;\n fg_rgba = unpacksRGB(param_49);\n for (uint k_10 = 0u; k_10 < 8u; k_10++)\n {\n rgb[k_10] = mix(rgb[k_10], fg_rgba.xyz, vec3(mask[k_10] * fg_rgba.w));\n }\n break;\n }\n case 8u:\n {\n Alloc param_50 = cmd_alloc;\n CmdRef param_51 = cmd_ref;\n CmdSolidImage solid_img = Cmd_SolidImage_read(param_50, param_51);\n uvec2 param_52 = xy_uint;\n CmdSolidImage param_53 = solid_img;\n rgba = fillImage(param_52, param_53);\n for (uint k_11 = 0u; k_11 < 8u; k_11++)\n {\n rgb[k_11] = mix(rgb[k_11], rgba[k_11].xyz, vec3(mask[k_11] * rgba[k_11].w));\n }\n break;\n }\n case 9u:\n {\n Alloc param_54 = cmd_alloc;\n CmdRef param_55 = cmd_ref;\n cmd_ref = CmdRef(Cmd_Jump_read(param_54, param_55).new_ref);\n cmd_alloc.offset = cmd_ref.offset;\n continue;\n }\n }\n cmd_ref.offset += 20u;\n }\n for (uint i_1 = 0u; i_1 < 8u; i_1++)\n {\n vec3 param_56 = rgb[i_1];\n imageStore(image, ivec2(int(xy_uint.x), int(xy_uint.y + (4u * i_1))), vec4(tosRGB(param_56), 1.0));\n }\n}\n\n", + GLSL310ES: "#version 310 es\nlayout(local_size_x = 32, local_size_y = 4, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct MallocResult\n{\n Alloc alloc;\n bool failed;\n};\n\nstruct CmdStrokeRef\n{\n uint offset;\n};\n\nstruct CmdStroke\n{\n uint tile_ref;\n float half_width;\n};\n\nstruct CmdFillRef\n{\n uint offset;\n};\n\nstruct CmdFill\n{\n uint tile_ref;\n int backdrop;\n};\n\nstruct CmdColorRef\n{\n uint offset;\n};\n\nstruct CmdColor\n{\n uint rgba_color;\n};\n\nstruct CmdImageRef\n{\n uint offset;\n};\n\nstruct CmdImage\n{\n uint index;\n ivec2 offset;\n};\n\nstruct CmdAlphaRef\n{\n uint offset;\n};\n\nstruct CmdAlpha\n{\n float alpha;\n};\n\nstruct CmdJumpRef\n{\n uint offset;\n};\n\nstruct CmdJump\n{\n uint new_ref;\n};\n\nstruct CmdRef\n{\n uint offset;\n};\n\nstruct CmdTag\n{\n uint tag;\n uint flags;\n};\n\nstruct TileSegRef\n{\n uint offset;\n};\n\nstruct TileSeg\n{\n vec2 origin;\n vec2 vector;\n float y_edge;\n TileSegRef next;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _190;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _749;\n\nlayout(binding = 3, rgba8) uniform readonly highp image2D images[1];\nlayout(binding = 2, rgba8) uniform writeonly highp image2D image;\n\nshared MallocResult sh_clip_alloc;\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nAlloc slice_mem(Alloc a, uint offset, uint size)\n{\n uint param = a.offset + offset;\n uint param_1 = size;\n return new_alloc(param, param_1);\n}\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _190.memory[offset];\n return v;\n}\n\nCmdTag Cmd_tag(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint tag_and_flags = read_mem(param, param_1);\n return CmdTag(tag_and_flags & 65535u, tag_and_flags >> uint(16));\n}\n\nCmdStroke CmdStroke_read(Alloc a, CmdStrokeRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n CmdStroke s;\n s.tile_ref = raw0;\n s.half_width = uintBitsToFloat(raw1);\n return s;\n}\n\nCmdStroke Cmd_Stroke_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdStrokeRef param_1 = CmdStrokeRef(ref.offset + 4u);\n return CmdStroke_read(param, param_1);\n}\n\nTileSeg TileSeg_read(Alloc a, TileSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n Alloc param_10 = a;\n uint param_11 = ix + 5u;\n uint raw5 = read_mem(param_10, param_11);\n TileSeg s;\n s.origin = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));\n s.vector = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.y_edge = uintBitsToFloat(raw4);\n s.next = TileSegRef(raw5);\n return s;\n}\n\nCmdFill CmdFill_read(Alloc a, CmdFillRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n CmdFill s;\n s.tile_ref = raw0;\n s.backdrop = int(raw1);\n return s;\n}\n\nCmdFill Cmd_Fill_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdFillRef param_1 = CmdFillRef(ref.offset + 4u);\n return CmdFill_read(param, param_1);\n}\n\nCmdAlpha CmdAlpha_read(Alloc a, CmdAlphaRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n CmdAlpha s;\n s.alpha = uintBitsToFloat(raw0);\n return s;\n}\n\nCmdAlpha Cmd_Alpha_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdAlphaRef param_1 = CmdAlphaRef(ref.offset + 4u);\n return CmdAlpha_read(param, param_1);\n}\n\nCmdColor CmdColor_read(Alloc a, CmdColorRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n CmdColor s;\n s.rgba_color = raw0;\n return s;\n}\n\nCmdColor Cmd_Color_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdColorRef param_1 = CmdColorRef(ref.offset + 4u);\n return CmdColor_read(param, param_1);\n}\n\nvec3 fromsRGB(vec3 srgb)\n{\n bvec3 cutoff = greaterThanEqual(srgb, vec3(0.040449999272823333740234375));\n vec3 below = srgb / vec3(12.9200000762939453125);\n vec3 above = pow((srgb + vec3(0.054999999701976776123046875)) / vec3(1.05499994754791259765625), vec3(2.400000095367431640625));\n return mix(below, above, cutoff);\n}\n\nvec4 unpacksRGB(uint srgba)\n{\n vec4 color = unpackUnorm4x8(srgba).wzyx;\n vec3 param = color.xyz;\n return vec4(fromsRGB(param), color.w);\n}\n\nCmdImage CmdImage_read(Alloc a, CmdImageRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n CmdImage s;\n s.index = raw0;\n s.offset = ivec2(int(raw1 << uint(16)) >> 16, int(raw1) >> 16);\n return s;\n}\n\nCmdImage Cmd_Image_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdImageRef param_1 = CmdImageRef(ref.offset + 4u);\n return CmdImage_read(param, param_1);\n}\n\nvec4[8] fillImage(uvec2 xy, CmdImage cmd_img)\n{\n vec4 rgba[8];\n for (uint i = 0u; i < 8u; i++)\n {\n ivec2 uv = ivec2(int(xy.x), int(xy.y + (i * 4u))) + cmd_img.offset;\n vec4 fg_rgba = imageLoad(images[0], uv);\n vec3 param = fg_rgba.xyz;\n vec3 _722 = fromsRGB(param);\n fg_rgba = vec4(_722.x, _722.y, _722.z, fg_rgba.w);\n rgba[i] = fg_rgba;\n }\n return rgba;\n}\n\nMallocResult malloc(uint size)\n{\n MallocResult r;\n r.failed = false;\n uint _196 = atomicAdd(_190.mem_offset, size);\n uint offset = _196;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_190.memory.length())) * 4))\n {\n r.failed = true;\n uint _217 = atomicMax(_190.mem_error, 1u);\n return r;\n }\n return r;\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _190.memory[offset] = val;\n}\n\nMallocResult alloc_clip_buf(uint link)\n{\n bool _569 = gl_LocalInvocationID.x == 0u;\n bool _575;\n if (_569)\n {\n _575 = gl_LocalInvocationID.y == 0u;\n }\n else\n {\n _575 = _569;\n }\n if (_575)\n {\n uint param = 4100u;\n MallocResult _581 = malloc(param);\n MallocResult m = _581;\n if (!m.failed)\n {\n Alloc param_1 = m.alloc;\n uint param_2 = (m.alloc.offset >> uint(2)) + 1024u;\n uint param_3 = link;\n write_mem(param_1, param_2, param_3);\n }\n sh_clip_alloc = m;\n }\n barrier();\n return sh_clip_alloc;\n}\n\nvec3 tosRGB(vec3 rgb)\n{\n bvec3 cutoff = greaterThanEqual(rgb, vec3(0.003130800090730190277099609375));\n vec3 below = vec3(12.9200000762939453125) * rgb;\n vec3 above = (vec3(1.05499994754791259765625) * pow(rgb, vec3(0.416660010814666748046875))) - vec3(0.054999999701976776123046875);\n return mix(below, above, cutoff);\n}\n\nuint packsRGB(inout vec4 rgba)\n{\n vec3 param = rgba.xyz;\n rgba = vec4(tosRGB(param), rgba.w);\n return packUnorm4x8(rgba.wzyx);\n}\n\nCmdJump CmdJump_read(Alloc a, CmdJumpRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n CmdJump s;\n s.new_ref = raw0;\n return s;\n}\n\nCmdJump Cmd_Jump_read(Alloc a, CmdRef ref)\n{\n Alloc param = a;\n CmdJumpRef param_1 = CmdJumpRef(ref.offset + 4u);\n return CmdJump_read(param, param_1);\n}\n\nvoid main()\n{\n if (_190.mem_error != 0u)\n {\n return;\n }\n uint tile_ix = (gl_WorkGroupID.y * _749.conf.width_in_tiles) + gl_WorkGroupID.x;\n Alloc param;\n param.offset = _749.conf.ptcl_alloc.offset;\n uint param_1 = tile_ix * 1024u;\n uint param_2 = 1024u;\n Alloc cmd_alloc = slice_mem(param, param_1, param_2);\n CmdRef cmd_ref = CmdRef(cmd_alloc.offset);\n uvec2 xy_uint = uvec2(gl_GlobalInvocationID.x, gl_LocalInvocationID.y + (32u * gl_WorkGroupID.y));\n vec2 xy = vec2(xy_uint);\n uint blend_spill = 0u;\n uint blend_sp = 0u;\n uint param_3 = 0u;\n uint param_4 = 0u;\n Alloc clip_tos = new_alloc(param_3, param_4);\n vec3 rgb[8];\n float mask[8];\n for (uint i = 0u; i < 8u; i++)\n {\n rgb[i] = vec3(0.5);\n mask[i] = 1.0;\n }\n float df[8];\n TileSegRef tile_seg_ref;\n float area[8];\n uint blend_slot;\n uint blend_stack[4][8];\n while (true)\n {\n Alloc param_5 = cmd_alloc;\n CmdRef param_6 = cmd_ref;\n uint tag = Cmd_tag(param_5, param_6).tag;\n if (tag == 0u)\n {\n break;\n }\n switch (tag)\n {\n case 2u:\n {\n Alloc param_7 = cmd_alloc;\n CmdRef param_8 = cmd_ref;\n CmdStroke stroke = Cmd_Stroke_read(param_7, param_8);\n for (uint k = 0u; k < 8u; k++)\n {\n df[k] = 1000000000.0;\n }\n tile_seg_ref = TileSegRef(stroke.tile_ref);\n do\n {\n uint param_9 = tile_seg_ref.offset;\n uint param_10 = 24u;\n Alloc param_11 = new_alloc(param_9, param_10);\n TileSegRef param_12 = tile_seg_ref;\n TileSeg seg = TileSeg_read(param_11, param_12);\n vec2 line_vec = seg.vector;\n for (uint k_1 = 0u; k_1 < 8u; k_1++)\n {\n vec2 dpos = (xy + vec2(0.5)) - seg.origin;\n dpos.y += float(k_1 * 4u);\n float t = clamp(dot(line_vec, dpos) / dot(line_vec, line_vec), 0.0, 1.0);\n df[k_1] = min(df[k_1], length((line_vec * t) - dpos));\n }\n tile_seg_ref = seg.next;\n } while (tile_seg_ref.offset != 0u);\n for (uint k_2 = 0u; k_2 < 8u; k_2++)\n {\n area[k_2] = clamp((stroke.half_width + 0.5) - df[k_2], 0.0, 1.0);\n }\n cmd_ref.offset += 12u;\n break;\n }\n case 1u:\n {\n Alloc param_13 = cmd_alloc;\n CmdRef param_14 = cmd_ref;\n CmdFill fill = Cmd_Fill_read(param_13, param_14);\n for (uint k_3 = 0u; k_3 < 8u; k_3++)\n {\n area[k_3] = float(fill.backdrop);\n }\n tile_seg_ref = TileSegRef(fill.tile_ref);\n do\n {\n uint param_15 = tile_seg_ref.offset;\n uint param_16 = 24u;\n Alloc param_17 = new_alloc(param_15, param_16);\n TileSegRef param_18 = tile_seg_ref;\n TileSeg seg_1 = TileSeg_read(param_17, param_18);\n for (uint k_4 = 0u; k_4 < 8u; k_4++)\n {\n vec2 my_xy = vec2(xy.x, xy.y + float(k_4 * 4u));\n vec2 start = seg_1.origin - my_xy;\n vec2 end = start + seg_1.vector;\n vec2 window = clamp(vec2(start.y, end.y), vec2(0.0), vec2(1.0));\n if (!(window.x == window.y))\n {\n vec2 t_1 = (window - vec2(start.y)) / vec2(seg_1.vector.y);\n vec2 xs = vec2(mix(start.x, end.x, t_1.x), mix(start.x, end.x, t_1.y));\n float xmin = min(min(xs.x, xs.y), 1.0) - 9.9999999747524270787835121154785e-07;\n float xmax = max(xs.x, xs.y);\n float b = min(xmax, 1.0);\n float c = max(b, 0.0);\n float d = max(xmin, 0.0);\n float a = ((b + (0.5 * ((d * d) - (c * c)))) - xmin) / (xmax - xmin);\n area[k_4] += (a * (window.x - window.y));\n }\n area[k_4] += (sign(seg_1.vector.x) * clamp((my_xy.y - seg_1.y_edge) + 1.0, 0.0, 1.0));\n }\n tile_seg_ref = seg_1.next;\n } while (tile_seg_ref.offset != 0u);\n for (uint k_5 = 0u; k_5 < 8u; k_5++)\n {\n area[k_5] = min(abs(area[k_5]), 1.0);\n }\n cmd_ref.offset += 12u;\n break;\n }\n case 3u:\n {\n for (uint k_6 = 0u; k_6 < 8u; k_6++)\n {\n area[k_6] = 1.0;\n }\n cmd_ref.offset += 4u;\n break;\n }\n case 4u:\n {\n Alloc param_19 = cmd_alloc;\n CmdRef param_20 = cmd_ref;\n CmdAlpha alpha = Cmd_Alpha_read(param_19, param_20);\n for (uint k_7 = 0u; k_7 < 8u; k_7++)\n {\n area[k_7] = alpha.alpha;\n }\n cmd_ref.offset += 8u;\n break;\n }\n case 5u:\n {\n Alloc param_21 = cmd_alloc;\n CmdRef param_22 = cmd_ref;\n CmdColor color = Cmd_Color_read(param_21, param_22);\n uint param_23 = color.rgba_color;\n vec4 fg_rgba = unpacksRGB(param_23);\n for (uint k_8 = 0u; k_8 < 8u; k_8++)\n {\n rgb[k_8] = mix(rgb[k_8], fg_rgba.xyz, vec3((mask[k_8] * area[k_8]) * fg_rgba.w));\n }\n cmd_ref.offset += 8u;\n break;\n }\n case 6u:\n {\n Alloc param_24 = cmd_alloc;\n CmdRef param_25 = cmd_ref;\n CmdImage fill_img = Cmd_Image_read(param_24, param_25);\n uvec2 param_26 = xy_uint;\n CmdImage param_27 = fill_img;\n vec4 rgba[8] = fillImage(param_26, param_27);\n for (uint k_9 = 0u; k_9 < 8u; k_9++)\n {\n rgb[k_9] = mix(rgb[k_9], rgba[k_9].xyz, vec3((mask[k_9] * area[k_9]) * rgba[k_9].w));\n }\n cmd_ref.offset += 12u;\n break;\n }\n case 7u:\n {\n blend_slot = blend_sp % 4u;\n if (blend_sp == (blend_spill + 4u))\n {\n uint param_28 = clip_tos.offset;\n MallocResult _1320 = alloc_clip_buf(param_28);\n MallocResult m = _1320;\n if (m.failed)\n {\n return;\n }\n clip_tos = m.alloc;\n uint base_ix = ((clip_tos.offset >> uint(2)) + gl_LocalInvocationID.x) + (32u * gl_LocalInvocationID.y);\n for (uint k_10 = 0u; k_10 < 8u; k_10++)\n {\n Alloc param_29 = clip_tos;\n uint param_30 = base_ix + ((k_10 * 32u) * 4u);\n uint param_31 = blend_stack[blend_slot][k_10];\n write_mem(param_29, param_30, param_31);\n }\n blend_spill++;\n }\n for (uint k_11 = 0u; k_11 < 8u; k_11++)\n {\n vec4 param_32 = vec4(rgb[k_11], clamp(abs(area[k_11]), 0.0, 1.0));\n uint _1392 = packsRGB(param_32);\n blend_stack[blend_slot][k_11] = _1392;\n }\n blend_sp++;\n cmd_ref.offset += 4u;\n break;\n }\n case 8u:\n {\n blend_slot = (blend_sp - 1u) % 4u;\n if (blend_sp == blend_spill)\n {\n uint base_ix_1 = ((clip_tos.offset >> uint(2)) + gl_LocalInvocationID.x) + (32u * gl_LocalInvocationID.y);\n for (uint k_12 = 0u; k_12 < 8u; k_12++)\n {\n Alloc param_33 = clip_tos;\n uint param_34 = base_ix_1 + ((k_12 * 32u) * 4u);\n blend_stack[blend_slot][k_12] = read_mem(param_33, param_34);\n }\n Alloc param_35 = clip_tos;\n uint param_36 = (clip_tos.offset >> uint(2)) + 1024u;\n clip_tos.offset = read_mem(param_35, param_36);\n blend_spill--;\n }\n blend_sp--;\n for (uint k_13 = 0u; k_13 < 8u; k_13++)\n {\n uint param_37 = blend_stack[blend_slot][k_13];\n vec4 rgba_1 = unpacksRGB(param_37);\n rgb[k_13] = mix(rgba_1.xyz, rgb[k_13], vec3(area[k_13] * rgba_1.w));\n }\n cmd_ref.offset += 4u;\n break;\n }\n case 9u:\n {\n Alloc param_38 = cmd_alloc;\n CmdRef param_39 = cmd_ref;\n cmd_ref = CmdRef(Cmd_Jump_read(param_38, param_39).new_ref);\n cmd_alloc.offset = cmd_ref.offset;\n continue;\n }\n }\n }\n for (uint i_1 = 0u; i_1 < 8u; i_1++)\n {\n vec3 param_40 = rgb[i_1];\n imageStore(image, ivec2(int(xy_uint.x), int(xy_uint.y + (4u * i_1))), vec4(tosRGB(param_40), 1.0));\n }\n}\n\n", } shader_material_frag = driver.ShaderSources{ Name: "material.frag", @@ -188,7 +188,7 @@ var ( } shader_path_coarse_comp = driver.ShaderSources{ Name: "path_coarse.comp", - GLSL310ES: "#version 310 es\nlayout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct MallocResult\n{\n Alloc alloc;\n bool failed;\n};\n\nstruct PathStrokeCubicRef\n{\n uint offset;\n};\n\nstruct PathStrokeCubic\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n vec2 p3;\n uint path_ix;\n uint trans_ix;\n vec2 stroke;\n};\n\nstruct PathSegRef\n{\n uint offset;\n};\n\nstruct TileRef\n{\n uint offset;\n};\n\nstruct PathRef\n{\n uint offset;\n};\n\nstruct Path\n{\n uvec4 bbox;\n TileRef tiles;\n};\n\nstruct TileSegRef\n{\n uint offset;\n};\n\nstruct TileSeg\n{\n vec2 origin;\n vec2 vector;\n float y_edge;\n TileSegRef next;\n};\n\nstruct TransformSegRef\n{\n uint offset;\n};\n\nstruct TransformSeg\n{\n vec4 mat;\n vec2 translate;\n};\n\nstruct SubdivResult\n{\n float val;\n float a0;\n float a2;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _144;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _773;\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _144.memory[offset];\n return v;\n}\n\nuint PathSeg_tag(Alloc a, PathSegRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n return read_mem(param, param_1);\n}\n\nPathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n Alloc param_10 = a;\n uint param_11 = ix + 5u;\n uint raw5 = read_mem(param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 6u;\n uint raw6 = read_mem(param_12, param_13);\n Alloc param_14 = a;\n uint param_15 = ix + 7u;\n uint raw7 = read_mem(param_14, param_15);\n Alloc param_16 = a;\n uint param_17 = ix + 8u;\n uint raw8 = read_mem(param_16, param_17);\n Alloc param_18 = a;\n uint param_19 = ix + 9u;\n uint raw9 = read_mem(param_18, param_19);\n Alloc param_20 = a;\n uint param_21 = ix + 10u;\n uint raw10 = read_mem(param_20, param_21);\n Alloc param_22 = a;\n uint param_23 = ix + 11u;\n uint raw11 = read_mem(param_22, param_23);\n PathStrokeCubic s;\n s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));\n s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7));\n s.path_ix = raw8;\n s.trans_ix = raw9;\n s.stroke = vec2(uintBitsToFloat(raw10), uintBitsToFloat(raw11));\n return s;\n}\n\nPathStrokeCubic PathSeg_StrokeCubic_read(Alloc a, PathSegRef ref)\n{\n Alloc param = a;\n PathStrokeCubicRef param_1 = PathStrokeCubicRef(ref.offset + 4u);\n return PathStrokeCubic_read(param, param_1);\n}\n\nTransformSeg TransformSeg_read(Alloc a, TransformSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n Alloc param_10 = a;\n uint param_11 = ix + 5u;\n uint raw5 = read_mem(param_10, param_11);\n TransformSeg s;\n s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n return s;\n}\n\nvec2 eval_cubic(vec2 p0, vec2 p1, vec2 p2, vec2 p3, float t)\n{\n float mt = 1.0 - t;\n return (p0 * ((mt * mt) * mt)) + (((p1 * ((mt * mt) * 3.0)) + (((p2 * (mt * 3.0)) + (p3 * t)) * t)) * t);\n}\n\nfloat approx_parabola_integral(float x)\n{\n return x * inversesqrt(sqrt(0.3300000131130218505859375 + (0.201511204242706298828125 + ((0.25 * x) * x))));\n}\n\nSubdivResult estimate_subdiv(vec2 p0, vec2 p1, vec2 p2, float sqrt_tol)\n{\n vec2 d01 = p1 - p0;\n vec2 d12 = p2 - p1;\n vec2 dd = d01 - d12;\n float _cross = ((p2.x - p0.x) * dd.y) - ((p2.y - p0.y) * dd.x);\n float x0 = ((d01.x * dd.x) + (d01.y * dd.y)) / _cross;\n float x2 = ((d12.x * dd.x) + (d12.y * dd.y)) / _cross;\n float scale = abs(_cross / (length(dd) * (x2 - x0)));\n float param = x0;\n float a0 = approx_parabola_integral(param);\n float param_1 = x2;\n float a2 = approx_parabola_integral(param_1);\n float val = 0.0;\n if (scale < 1000000000.0)\n {\n float da = abs(a2 - a0);\n float sqrt_scale = sqrt(scale);\n if (sign(x0) == sign(x2))\n {\n val = da * sqrt_scale;\n }\n else\n {\n float xmin = sqrt_tol / sqrt_scale;\n float param_2 = xmin;\n val = (sqrt_tol * da) / approx_parabola_integral(param_2);\n }\n }\n return SubdivResult(val, a0, a2);\n}\n\nPath Path_read(Alloc a, PathRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Path s;\n s.bbox = uvec4(raw0 & 65535u, raw0 >> uint(16), raw1 & 65535u, raw1 >> uint(16));\n s.tiles = TileRef(raw2);\n return s;\n}\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nfloat approx_parabola_inv_integral(float x)\n{\n return x * sqrt(0.61000001430511474609375 + (0.1520999968051910400390625 + ((0.25 * x) * x)));\n}\n\nvec2 eval_quad(vec2 p0, vec2 p1, vec2 p2, float t)\n{\n float mt = 1.0 - t;\n return (p0 * (mt * mt)) + (((p1 * (mt * 2.0)) + (p2 * t)) * t);\n}\n\nMallocResult malloc(uint size)\n{\n MallocResult r;\n r.failed = false;\n uint _150 = atomicAdd(_144.mem_offset, size);\n uint offset = _150;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_144.memory.length())) * 4))\n {\n r.failed = true;\n uint _171 = atomicMax(_144.mem_error, 1u);\n return r;\n }\n return r;\n}\n\nTileRef Tile_index(TileRef ref, uint index)\n{\n return TileRef(ref.offset + (index * 8u));\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _144.memory[offset] = val;\n}\n\nvoid TileSeg_write(Alloc a, TileSegRef ref, TileSeg s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.origin.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.origin.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.vector.x);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.vector.y);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = floatBitsToUint(s.y_edge);\n write_mem(param_12, param_13, param_14);\n Alloc param_15 = a;\n uint param_16 = ix + 5u;\n uint param_17 = s.next.offset;\n write_mem(param_15, param_16, param_17);\n}\n\nvoid main()\n{\n if (_144.mem_error != 0u)\n {\n return;\n }\n uint element_ix = gl_GlobalInvocationID.x;\n PathSegRef ref = PathSegRef(_773.conf.pathseg_alloc.offset + (element_ix * 52u));\n uint tag = 0u;\n if (element_ix < _773.conf.n_pathseg)\n {\n Alloc param;\n param.offset = _773.conf.pathseg_alloc.offset;\n PathSegRef param_1 = ref;\n tag = PathSeg_tag(param, param_1);\n }\n switch (tag)\n {\n case 1u:\n case 2u:\n {\n Alloc param_2;\n param_2.offset = _773.conf.pathseg_alloc.offset;\n PathSegRef param_3 = ref;\n PathStrokeCubic cubic = PathSeg_StrokeCubic_read(param_2, param_3);\n uint trans_ix = cubic.trans_ix;\n if (trans_ix > 0u)\n {\n TransformSegRef trans_ref = TransformSegRef(_773.conf.trans_alloc.offset + ((trans_ix - 1u) * 24u));\n Alloc param_4;\n param_4.offset = _773.conf.trans_alloc.offset;\n TransformSegRef param_5 = trans_ref;\n TransformSeg trans = TransformSeg_read(param_4, param_5);\n cubic.p0 = ((trans.mat.xy * cubic.p0.x) + (trans.mat.zw * cubic.p0.y)) + trans.translate;\n cubic.p1 = ((trans.mat.xy * cubic.p1.x) + (trans.mat.zw * cubic.p1.y)) + trans.translate;\n cubic.p2 = ((trans.mat.xy * cubic.p2.x) + (trans.mat.zw * cubic.p2.y)) + trans.translate;\n cubic.p3 = ((trans.mat.xy * cubic.p3.x) + (trans.mat.zw * cubic.p3.y)) + trans.translate;\n }\n vec2 err_v = (((cubic.p2 - cubic.p1) * 3.0) + cubic.p0) - cubic.p3;\n float err = (err_v.x * err_v.x) + (err_v.y * err_v.y);\n uint n_quads = max(uint(ceil(pow(err * 3.7037036418914794921875, 0.16666667163372039794921875))), 1u);\n float val = 0.0;\n vec2 qp0 = cubic.p0;\n float _step = 1.0 / float(n_quads);\n for (uint i = 0u; i < n_quads; i++)\n {\n float t = float(i + 1u) * _step;\n vec2 param_6 = cubic.p0;\n vec2 param_7 = cubic.p1;\n vec2 param_8 = cubic.p2;\n vec2 param_9 = cubic.p3;\n float param_10 = t;\n vec2 qp2 = eval_cubic(param_6, param_7, param_8, param_9, param_10);\n vec2 param_11 = cubic.p0;\n vec2 param_12 = cubic.p1;\n vec2 param_13 = cubic.p2;\n vec2 param_14 = cubic.p3;\n float param_15 = t - (0.5 * _step);\n vec2 qp1 = eval_cubic(param_11, param_12, param_13, param_14, param_15);\n qp1 = (qp1 * 2.0) - ((qp0 + qp2) * 0.5);\n vec2 param_16 = qp0;\n vec2 param_17 = qp1;\n vec2 param_18 = qp2;\n float param_19 = 0.4743416607379913330078125;\n SubdivResult params = estimate_subdiv(param_16, param_17, param_18, param_19);\n val += params.val;\n qp0 = qp2;\n }\n uint n = max(uint(ceil((val * 0.5) / 0.4743416607379913330078125)), 1u);\n uint path_ix = cubic.path_ix;\n Alloc param_20;\n param_20.offset = _773.conf.tile_alloc.offset;\n PathRef param_21 = PathRef(_773.conf.tile_alloc.offset + (path_ix * 12u));\n Path path = Path_read(param_20, param_21);\n uint param_22 = path.tiles.offset;\n uint param_23 = ((path.bbox.z - path.bbox.x) * (path.bbox.w - path.bbox.y)) * 8u;\n Alloc path_alloc = new_alloc(param_22, param_23);\n ivec4 bbox = ivec4(path.bbox);\n vec2 p0 = cubic.p0;\n qp0 = cubic.p0;\n float v_step = val / float(n);\n int n_out = 1;\n float val_sum = 0.0;\n vec2 p1;\n float _1285;\n TileSeg tile_seg;\n for (uint i_1 = 0u; i_1 < n_quads; i_1++)\n {\n float t_1 = float(i_1 + 1u) * _step;\n vec2 param_24 = cubic.p0;\n vec2 param_25 = cubic.p1;\n vec2 param_26 = cubic.p2;\n vec2 param_27 = cubic.p3;\n float param_28 = t_1;\n vec2 qp2_1 = eval_cubic(param_24, param_25, param_26, param_27, param_28);\n vec2 param_29 = cubic.p0;\n vec2 param_30 = cubic.p1;\n vec2 param_31 = cubic.p2;\n vec2 param_32 = cubic.p3;\n float param_33 = t_1 - (0.5 * _step);\n vec2 qp1_1 = eval_cubic(param_29, param_30, param_31, param_32, param_33);\n qp1_1 = (qp1_1 * 2.0) - ((qp0 + qp2_1) * 0.5);\n vec2 param_34 = qp0;\n vec2 param_35 = qp1_1;\n vec2 param_36 = qp2_1;\n float param_37 = 0.4743416607379913330078125;\n SubdivResult params_1 = estimate_subdiv(param_34, param_35, param_36, param_37);\n float param_38 = params_1.a0;\n float u0 = approx_parabola_inv_integral(param_38);\n float param_39 = params_1.a2;\n float u2 = approx_parabola_inv_integral(param_39);\n float uscale = 1.0 / (u2 - u0);\n float target = float(n_out) * v_step;\n for (;;)\n {\n bool _1178 = uint(n_out) == n;\n bool _1188;\n if (!_1178)\n {\n _1188 = target < (val_sum + params_1.val);\n }\n else\n {\n _1188 = _1178;\n }\n if (_1188)\n {\n if (uint(n_out) == n)\n {\n p1 = cubic.p3;\n }\n else\n {\n float u = (target - val_sum) / params_1.val;\n float a = mix(params_1.a0, params_1.a2, u);\n float param_40 = a;\n float au = approx_parabola_inv_integral(param_40);\n float t_2 = (au - u0) * uscale;\n vec2 param_41 = qp0;\n vec2 param_42 = qp1_1;\n vec2 param_43 = qp2_1;\n float param_44 = t_2;\n p1 = eval_quad(param_41, param_42, param_43, param_44);\n }\n float xmin = min(p0.x, p1.x) - cubic.stroke.x;\n float xmax = max(p0.x, p1.x) + cubic.stroke.x;\n float ymin = min(p0.y, p1.y) - cubic.stroke.y;\n float ymax = max(p0.y, p1.y) + cubic.stroke.y;\n float dx = p1.x - p0.x;\n float dy = p1.y - p0.y;\n if (abs(dy) < 9.999999717180685365747194737196e-10)\n {\n _1285 = 1000000000.0;\n }\n else\n {\n _1285 = dx / dy;\n }\n float invslope = _1285;\n float c = (cubic.stroke.x + (abs(invslope) * (16.0 + cubic.stroke.y))) * 0.03125;\n float b = invslope;\n float a_1 = (p0.x - ((p0.y - 16.0) * b)) * 0.03125;\n int x0 = int(floor(xmin * 0.03125));\n int x1 = int(floor(xmax * 0.03125) + 1.0);\n int y0 = int(floor(ymin * 0.03125));\n int y1 = int(floor(ymax * 0.03125) + 1.0);\n x0 = clamp(x0, bbox.x, bbox.z);\n y0 = clamp(y0, bbox.y, bbox.w);\n x1 = clamp(x1, bbox.x, bbox.z);\n y1 = clamp(y1, bbox.y, bbox.w);\n float xc = a_1 + (b * float(y0));\n int stride = bbox.z - bbox.x;\n int base = ((y0 - bbox.y) * stride) - bbox.x;\n uint n_tile_alloc = uint((x1 - x0) * (y1 - y0));\n uint param_45 = n_tile_alloc * 24u;\n MallocResult _1400 = malloc(param_45);\n MallocResult tile_alloc = _1400;\n if (tile_alloc.failed)\n {\n return;\n }\n uint tile_offset = tile_alloc.alloc.offset;\n int xray = int(floor(p0.x * 0.03125));\n int last_xray = int(floor(p1.x * 0.03125));\n if (p0.y > p1.y)\n {\n int tmp = xray;\n xray = last_xray;\n last_xray = tmp;\n }\n for (int y = y0; y < y1; y++)\n {\n float tile_y0 = float(y * 32);\n int xbackdrop = max((xray + 1), bbox.x);\n bool _1454 = tag == 1u;\n bool _1464;\n if (_1454)\n {\n _1464 = min(p0.y, p1.y) < tile_y0;\n }\n else\n {\n _1464 = _1454;\n }\n bool _1471;\n if (_1464)\n {\n _1471 = xbackdrop < bbox.z;\n }\n else\n {\n _1471 = _1464;\n }\n if (_1471)\n {\n int backdrop = (p1.y < p0.y) ? 1 : (-1);\n TileRef param_46 = path.tiles;\n uint param_47 = uint(base + xbackdrop);\n TileRef tile_ref = Tile_index(param_46, param_47);\n uint tile_el = tile_ref.offset >> uint(2);\n Alloc param_48 = path_alloc;\n uint param_49 = tile_el + 1u;\n if (touch_mem(param_48, param_49))\n {\n uint _1509 = atomicAdd(_144.memory[tile_el + 1u], uint(backdrop));\n }\n }\n int next_xray = last_xray;\n if (y < (y1 - 1))\n {\n float tile_y1 = float((y + 1) * 32);\n float x_edge = mix(p0.x, p1.x, (tile_y1 - p0.y) / dy);\n next_xray = int(floor(x_edge * 0.03125));\n }\n int min_xray = min(xray, next_xray);\n int max_xray = max(xray, next_xray);\n int xx0 = min(int(floor(xc - c)), min_xray);\n int xx1 = max(int(ceil(xc + c)), (max_xray + 1));\n xx0 = clamp(xx0, x0, x1);\n xx1 = clamp(xx1, x0, x1);\n for (int x = xx0; x < xx1; x++)\n {\n float tile_x0 = float(x * 32);\n TileRef param_50 = TileRef(path.tiles.offset);\n uint param_51 = uint(base + x);\n TileRef tile_ref_1 = Tile_index(param_50, param_51);\n uint tile_el_1 = tile_ref_1.offset >> uint(2);\n uint old = 0u;\n Alloc param_52 = path_alloc;\n uint param_53 = tile_el_1;\n if (touch_mem(param_52, param_53))\n {\n uint _1612 = atomicExchange(_144.memory[tile_el_1], tile_offset);\n old = _1612;\n }\n tile_seg.origin = p0;\n tile_seg.vector = p1 - p0;\n float y_edge = 0.0;\n if (tag == 1u)\n {\n y_edge = mix(p0.y, p1.y, (tile_x0 - p0.x) / dx);\n if (min(p0.x, p1.x) < tile_x0)\n {\n vec2 p = vec2(tile_x0, y_edge);\n if (p0.x > p1.x)\n {\n tile_seg.vector = p - p0;\n }\n else\n {\n tile_seg.origin = p;\n tile_seg.vector = p1 - p;\n }\n if (tile_seg.vector.x == 0.0)\n {\n tile_seg.vector.x = sign(p1.x - p0.x) * 9.999999717180685365747194737196e-10;\n }\n }\n if ((x <= min_xray) || (max_xray < x))\n {\n y_edge = 1000000000.0;\n }\n }\n tile_seg.y_edge = y_edge;\n tile_seg.next.offset = old;\n Alloc param_54 = tile_alloc.alloc;\n TileSegRef param_55 = TileSegRef(tile_offset);\n TileSeg param_56 = tile_seg;\n TileSeg_write(param_54, param_55, param_56);\n tile_offset += 24u;\n }\n xc += b;\n base += stride;\n xray = next_xray;\n }\n n_out++;\n target += v_step;\n p0 = p1;\n continue;\n }\n else\n {\n break;\n }\n }\n val_sum += params_1.val;\n qp0 = qp2_1;\n }\n break;\n }\n }\n}\n\n", + GLSL310ES: "#version 310 es\nlayout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct MallocResult\n{\n Alloc alloc;\n bool failed;\n};\n\nstruct PathCubicRef\n{\n uint offset;\n};\n\nstruct PathCubic\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n vec2 p3;\n uint path_ix;\n uint trans_ix;\n vec2 stroke;\n};\n\nstruct PathSegRef\n{\n uint offset;\n};\n\nstruct PathSegTag\n{\n uint tag;\n uint flags;\n};\n\nstruct TileRef\n{\n uint offset;\n};\n\nstruct PathRef\n{\n uint offset;\n};\n\nstruct Path\n{\n uvec4 bbox;\n TileRef tiles;\n};\n\nstruct TileSegRef\n{\n uint offset;\n};\n\nstruct TileSeg\n{\n vec2 origin;\n vec2 vector;\n float y_edge;\n TileSegRef next;\n};\n\nstruct TransformSegRef\n{\n uint offset;\n};\n\nstruct TransformSeg\n{\n vec4 mat;\n vec2 translate;\n};\n\nstruct SubdivResult\n{\n float val;\n float a0;\n float a2;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _149;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _788;\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _149.memory[offset];\n return v;\n}\n\nPathSegTag PathSeg_tag(Alloc a, PathSegRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint tag_and_flags = read_mem(param, param_1);\n return PathSegTag(tag_and_flags & 65535u, tag_and_flags >> uint(16));\n}\n\nPathCubic PathCubic_read(Alloc a, PathCubicRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n Alloc param_10 = a;\n uint param_11 = ix + 5u;\n uint raw5 = read_mem(param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 6u;\n uint raw6 = read_mem(param_12, param_13);\n Alloc param_14 = a;\n uint param_15 = ix + 7u;\n uint raw7 = read_mem(param_14, param_15);\n Alloc param_16 = a;\n uint param_17 = ix + 8u;\n uint raw8 = read_mem(param_16, param_17);\n Alloc param_18 = a;\n uint param_19 = ix + 9u;\n uint raw9 = read_mem(param_18, param_19);\n Alloc param_20 = a;\n uint param_21 = ix + 10u;\n uint raw10 = read_mem(param_20, param_21);\n Alloc param_22 = a;\n uint param_23 = ix + 11u;\n uint raw11 = read_mem(param_22, param_23);\n PathCubic s;\n s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));\n s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7));\n s.path_ix = raw8;\n s.trans_ix = raw9;\n s.stroke = vec2(uintBitsToFloat(raw10), uintBitsToFloat(raw11));\n return s;\n}\n\nPathCubic PathSeg_Cubic_read(Alloc a, PathSegRef ref)\n{\n Alloc param = a;\n PathCubicRef param_1 = PathCubicRef(ref.offset + 4u);\n return PathCubic_read(param, param_1);\n}\n\nTransformSeg TransformSeg_read(Alloc a, TransformSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n Alloc param_10 = a;\n uint param_11 = ix + 5u;\n uint raw5 = read_mem(param_10, param_11);\n TransformSeg s;\n s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));\n return s;\n}\n\nvec2 eval_cubic(vec2 p0, vec2 p1, vec2 p2, vec2 p3, float t)\n{\n float mt = 1.0 - t;\n return (p0 * ((mt * mt) * mt)) + (((p1 * ((mt * mt) * 3.0)) + (((p2 * (mt * 3.0)) + (p3 * t)) * t)) * t);\n}\n\nfloat approx_parabola_integral(float x)\n{\n return x * inversesqrt(sqrt(0.3300000131130218505859375 + (0.201511204242706298828125 + ((0.25 * x) * x))));\n}\n\nSubdivResult estimate_subdiv(vec2 p0, vec2 p1, vec2 p2, float sqrt_tol)\n{\n vec2 d01 = p1 - p0;\n vec2 d12 = p2 - p1;\n vec2 dd = d01 - d12;\n float _cross = ((p2.x - p0.x) * dd.y) - ((p2.y - p0.y) * dd.x);\n float x0 = ((d01.x * dd.x) + (d01.y * dd.y)) / _cross;\n float x2 = ((d12.x * dd.x) + (d12.y * dd.y)) / _cross;\n float scale = abs(_cross / (length(dd) * (x2 - x0)));\n float param = x0;\n float a0 = approx_parabola_integral(param);\n float param_1 = x2;\n float a2 = approx_parabola_integral(param_1);\n float val = 0.0;\n if (scale < 1000000000.0)\n {\n float da = abs(a2 - a0);\n float sqrt_scale = sqrt(scale);\n if (sign(x0) == sign(x2))\n {\n val = da * sqrt_scale;\n }\n else\n {\n float xmin = sqrt_tol / sqrt_scale;\n float param_2 = xmin;\n val = (sqrt_tol * da) / approx_parabola_integral(param_2);\n }\n }\n return SubdivResult(val, a0, a2);\n}\n\nuint fill_mode_from_flags(uint flags)\n{\n return flags & 1u;\n}\n\nPath Path_read(Alloc a, PathRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Path s;\n s.bbox = uvec4(raw0 & 65535u, raw0 >> uint(16), raw1 & 65535u, raw1 >> uint(16));\n s.tiles = TileRef(raw2);\n return s;\n}\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nfloat approx_parabola_inv_integral(float x)\n{\n return x * sqrt(0.61000001430511474609375 + (0.1520999968051910400390625 + ((0.25 * x) * x)));\n}\n\nvec2 eval_quad(vec2 p0, vec2 p1, vec2 p2, float t)\n{\n float mt = 1.0 - t;\n return (p0 * (mt * mt)) + (((p1 * (mt * 2.0)) + (p2 * t)) * t);\n}\n\nMallocResult malloc(uint size)\n{\n MallocResult r;\n r.failed = false;\n uint _155 = atomicAdd(_149.mem_offset, size);\n uint offset = _155;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_149.memory.length())) * 4))\n {\n r.failed = true;\n uint _176 = atomicMax(_149.mem_error, 1u);\n return r;\n }\n return r;\n}\n\nTileRef Tile_index(TileRef ref, uint index)\n{\n return TileRef(ref.offset + (index * 8u));\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _149.memory[offset] = val;\n}\n\nvoid TileSeg_write(Alloc a, TileSegRef ref, TileSeg s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = floatBitsToUint(s.origin.x);\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = floatBitsToUint(s.origin.y);\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = floatBitsToUint(s.vector.x);\n write_mem(param_6, param_7, param_8);\n Alloc param_9 = a;\n uint param_10 = ix + 3u;\n uint param_11 = floatBitsToUint(s.vector.y);\n write_mem(param_9, param_10, param_11);\n Alloc param_12 = a;\n uint param_13 = ix + 4u;\n uint param_14 = floatBitsToUint(s.y_edge);\n write_mem(param_12, param_13, param_14);\n Alloc param_15 = a;\n uint param_16 = ix + 5u;\n uint param_17 = s.next.offset;\n write_mem(param_15, param_16, param_17);\n}\n\nvoid main()\n{\n if (_149.mem_error != 0u)\n {\n return;\n }\n uint element_ix = gl_GlobalInvocationID.x;\n PathSegRef ref = PathSegRef(_788.conf.pathseg_alloc.offset + (element_ix * 52u));\n PathSegTag tag = PathSegTag(0u, 0u);\n if (element_ix < _788.conf.n_pathseg)\n {\n Alloc param;\n param.offset = _788.conf.pathseg_alloc.offset;\n PathSegRef param_1 = ref;\n tag = PathSeg_tag(param, param_1);\n }\n switch (tag.tag)\n {\n case 1u:\n {\n Alloc param_2;\n param_2.offset = _788.conf.pathseg_alloc.offset;\n PathSegRef param_3 = ref;\n PathCubic cubic = PathSeg_Cubic_read(param_2, param_3);\n uint trans_ix = cubic.trans_ix;\n if (trans_ix > 0u)\n {\n TransformSegRef trans_ref = TransformSegRef(_788.conf.trans_alloc.offset + ((trans_ix - 1u) * 24u));\n Alloc param_4;\n param_4.offset = _788.conf.trans_alloc.offset;\n TransformSegRef param_5 = trans_ref;\n TransformSeg trans = TransformSeg_read(param_4, param_5);\n cubic.p0 = ((trans.mat.xy * cubic.p0.x) + (trans.mat.zw * cubic.p0.y)) + trans.translate;\n cubic.p1 = ((trans.mat.xy * cubic.p1.x) + (trans.mat.zw * cubic.p1.y)) + trans.translate;\n cubic.p2 = ((trans.mat.xy * cubic.p2.x) + (trans.mat.zw * cubic.p2.y)) + trans.translate;\n cubic.p3 = ((trans.mat.xy * cubic.p3.x) + (trans.mat.zw * cubic.p3.y)) + trans.translate;\n }\n vec2 err_v = (((cubic.p2 - cubic.p1) * 3.0) + cubic.p0) - cubic.p3;\n float err = (err_v.x * err_v.x) + (err_v.y * err_v.y);\n uint n_quads = max(uint(ceil(pow(err * 3.7037036418914794921875, 0.16666667163372039794921875))), 1u);\n float val = 0.0;\n vec2 qp0 = cubic.p0;\n float _step = 1.0 / float(n_quads);\n for (uint i = 0u; i < n_quads; i++)\n {\n float t = float(i + 1u) * _step;\n vec2 param_6 = cubic.p0;\n vec2 param_7 = cubic.p1;\n vec2 param_8 = cubic.p2;\n vec2 param_9 = cubic.p3;\n float param_10 = t;\n vec2 qp2 = eval_cubic(param_6, param_7, param_8, param_9, param_10);\n vec2 param_11 = cubic.p0;\n vec2 param_12 = cubic.p1;\n vec2 param_13 = cubic.p2;\n vec2 param_14 = cubic.p3;\n float param_15 = t - (0.5 * _step);\n vec2 qp1 = eval_cubic(param_11, param_12, param_13, param_14, param_15);\n qp1 = (qp1 * 2.0) - ((qp0 + qp2) * 0.5);\n vec2 param_16 = qp0;\n vec2 param_17 = qp1;\n vec2 param_18 = qp2;\n float param_19 = 0.4743416607379913330078125;\n SubdivResult params = estimate_subdiv(param_16, param_17, param_18, param_19);\n val += params.val;\n qp0 = qp2;\n }\n uint n = max(uint(ceil((val * 0.5) / 0.4743416607379913330078125)), 1u);\n uint param_20 = tag.flags;\n bool is_stroke = fill_mode_from_flags(param_20) == 1u;\n uint path_ix = cubic.path_ix;\n Alloc param_21;\n param_21.offset = _788.conf.tile_alloc.offset;\n PathRef param_22 = PathRef(_788.conf.tile_alloc.offset + (path_ix * 12u));\n Path path = Path_read(param_21, param_22);\n uint param_23 = path.tiles.offset;\n uint param_24 = ((path.bbox.z - path.bbox.x) * (path.bbox.w - path.bbox.y)) * 8u;\n Alloc path_alloc = new_alloc(param_23, param_24);\n ivec4 bbox = ivec4(path.bbox);\n vec2 p0 = cubic.p0;\n qp0 = cubic.p0;\n float v_step = val / float(n);\n int n_out = 1;\n float val_sum = 0.0;\n vec2 p1;\n float _1309;\n TileSeg tile_seg;\n for (uint i_1 = 0u; i_1 < n_quads; i_1++)\n {\n float t_1 = float(i_1 + 1u) * _step;\n vec2 param_25 = cubic.p0;\n vec2 param_26 = cubic.p1;\n vec2 param_27 = cubic.p2;\n vec2 param_28 = cubic.p3;\n float param_29 = t_1;\n vec2 qp2_1 = eval_cubic(param_25, param_26, param_27, param_28, param_29);\n vec2 param_30 = cubic.p0;\n vec2 param_31 = cubic.p1;\n vec2 param_32 = cubic.p2;\n vec2 param_33 = cubic.p3;\n float param_34 = t_1 - (0.5 * _step);\n vec2 qp1_1 = eval_cubic(param_30, param_31, param_32, param_33, param_34);\n qp1_1 = (qp1_1 * 2.0) - ((qp0 + qp2_1) * 0.5);\n vec2 param_35 = qp0;\n vec2 param_36 = qp1_1;\n vec2 param_37 = qp2_1;\n float param_38 = 0.4743416607379913330078125;\n SubdivResult params_1 = estimate_subdiv(param_35, param_36, param_37, param_38);\n float param_39 = params_1.a0;\n float u0 = approx_parabola_inv_integral(param_39);\n float param_40 = params_1.a2;\n float u2 = approx_parabola_inv_integral(param_40);\n float uscale = 1.0 / (u2 - u0);\n float target = float(n_out) * v_step;\n for (;;)\n {\n bool _1202 = uint(n_out) == n;\n bool _1212;\n if (!_1202)\n {\n _1212 = target < (val_sum + params_1.val);\n }\n else\n {\n _1212 = _1202;\n }\n if (_1212)\n {\n if (uint(n_out) == n)\n {\n p1 = cubic.p3;\n }\n else\n {\n float u = (target - val_sum) / params_1.val;\n float a = mix(params_1.a0, params_1.a2, u);\n float param_41 = a;\n float au = approx_parabola_inv_integral(param_41);\n float t_2 = (au - u0) * uscale;\n vec2 param_42 = qp0;\n vec2 param_43 = qp1_1;\n vec2 param_44 = qp2_1;\n float param_45 = t_2;\n p1 = eval_quad(param_42, param_43, param_44, param_45);\n }\n float xmin = min(p0.x, p1.x) - cubic.stroke.x;\n float xmax = max(p0.x, p1.x) + cubic.stroke.x;\n float ymin = min(p0.y, p1.y) - cubic.stroke.y;\n float ymax = max(p0.y, p1.y) + cubic.stroke.y;\n float dx = p1.x - p0.x;\n float dy = p1.y - p0.y;\n if (abs(dy) < 9.999999717180685365747194737196e-10)\n {\n _1309 = 1000000000.0;\n }\n else\n {\n _1309 = dx / dy;\n }\n float invslope = _1309;\n float c = (cubic.stroke.x + (abs(invslope) * (16.0 + cubic.stroke.y))) * 0.03125;\n float b = invslope;\n float a_1 = (p0.x - ((p0.y - 16.0) * b)) * 0.03125;\n int x0 = int(floor(xmin * 0.03125));\n int x1 = int(floor(xmax * 0.03125) + 1.0);\n int y0 = int(floor(ymin * 0.03125));\n int y1 = int(floor(ymax * 0.03125) + 1.0);\n x0 = clamp(x0, bbox.x, bbox.z);\n y0 = clamp(y0, bbox.y, bbox.w);\n x1 = clamp(x1, bbox.x, bbox.z);\n y1 = clamp(y1, bbox.y, bbox.w);\n float xc = a_1 + (b * float(y0));\n int stride = bbox.z - bbox.x;\n int base = ((y0 - bbox.y) * stride) - bbox.x;\n uint n_tile_alloc = uint((x1 - x0) * (y1 - y0));\n uint param_46 = n_tile_alloc * 24u;\n MallocResult _1424 = malloc(param_46);\n MallocResult tile_alloc = _1424;\n if (tile_alloc.failed)\n {\n return;\n }\n uint tile_offset = tile_alloc.alloc.offset;\n int xray = int(floor(p0.x * 0.03125));\n int last_xray = int(floor(p1.x * 0.03125));\n if (p0.y > p1.y)\n {\n int tmp = xray;\n xray = last_xray;\n last_xray = tmp;\n }\n for (int y = y0; y < y1; y++)\n {\n float tile_y0 = float(y * 32);\n int xbackdrop = max((xray + 1), bbox.x);\n bool _1478 = !is_stroke;\n bool _1488;\n if (_1478)\n {\n _1488 = min(p0.y, p1.y) < tile_y0;\n }\n else\n {\n _1488 = _1478;\n }\n bool _1495;\n if (_1488)\n {\n _1495 = xbackdrop < bbox.z;\n }\n else\n {\n _1495 = _1488;\n }\n if (_1495)\n {\n int backdrop = (p1.y < p0.y) ? 1 : (-1);\n TileRef param_47 = path.tiles;\n uint param_48 = uint(base + xbackdrop);\n TileRef tile_ref = Tile_index(param_47, param_48);\n uint tile_el = tile_ref.offset >> uint(2);\n Alloc param_49 = path_alloc;\n uint param_50 = tile_el + 1u;\n if (touch_mem(param_49, param_50))\n {\n uint _1533 = atomicAdd(_149.memory[tile_el + 1u], uint(backdrop));\n }\n }\n int next_xray = last_xray;\n if (y < (y1 - 1))\n {\n float tile_y1 = float((y + 1) * 32);\n float x_edge = mix(p0.x, p1.x, (tile_y1 - p0.y) / dy);\n next_xray = int(floor(x_edge * 0.03125));\n }\n int min_xray = min(xray, next_xray);\n int max_xray = max(xray, next_xray);\n int xx0 = min(int(floor(xc - c)), min_xray);\n int xx1 = max(int(ceil(xc + c)), (max_xray + 1));\n xx0 = clamp(xx0, x0, x1);\n xx1 = clamp(xx1, x0, x1);\n for (int x = xx0; x < xx1; x++)\n {\n float tile_x0 = float(x * 32);\n TileRef param_51 = TileRef(path.tiles.offset);\n uint param_52 = uint(base + x);\n TileRef tile_ref_1 = Tile_index(param_51, param_52);\n uint tile_el_1 = tile_ref_1.offset >> uint(2);\n uint old = 0u;\n Alloc param_53 = path_alloc;\n uint param_54 = tile_el_1;\n if (touch_mem(param_53, param_54))\n {\n uint _1636 = atomicExchange(_149.memory[tile_el_1], tile_offset);\n old = _1636;\n }\n tile_seg.origin = p0;\n tile_seg.vector = p1 - p0;\n float y_edge = 0.0;\n if (!is_stroke)\n {\n y_edge = mix(p0.y, p1.y, (tile_x0 - p0.x) / dx);\n if (min(p0.x, p1.x) < tile_x0)\n {\n vec2 p = vec2(tile_x0, y_edge);\n if (p0.x > p1.x)\n {\n tile_seg.vector = p - p0;\n }\n else\n {\n tile_seg.origin = p;\n tile_seg.vector = p1 - p;\n }\n if (tile_seg.vector.x == 0.0)\n {\n tile_seg.vector.x = sign(p1.x - p0.x) * 9.999999717180685365747194737196e-10;\n }\n }\n if ((x <= min_xray) || (max_xray < x))\n {\n y_edge = 1000000000.0;\n }\n }\n tile_seg.y_edge = y_edge;\n tile_seg.next.offset = old;\n Alloc param_55 = tile_alloc.alloc;\n TileSegRef param_56 = TileSegRef(tile_offset);\n TileSeg param_57 = tile_seg;\n TileSeg_write(param_55, param_56, param_57);\n tile_offset += 24u;\n }\n xc += b;\n base += stride;\n xray = next_xray;\n }\n n_out++;\n target += v_step;\n p0 = p1;\n continue;\n }\n else\n {\n break;\n }\n }\n val_sum += params_1.val;\n qp0 = qp2_1;\n }\n break;\n }\n }\n}\n\n", } shader_stencil_frag = driver.ShaderSources{ Name: "stencil.frag", @@ -214,6 +214,6 @@ var ( } shader_tile_alloc_comp = driver.ShaderSources{ Name: "tile_alloc.comp", - GLSL310ES: "#version 310 es\nlayout(local_size_x = 128, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct MallocResult\n{\n Alloc alloc;\n bool failed;\n};\n\nstruct AnnoFillRef\n{\n uint offset;\n};\n\nstruct AnnoFill\n{\n vec4 bbox;\n uint rgba_color;\n};\n\nstruct AnnotatedRef\n{\n uint offset;\n};\n\nstruct PathRef\n{\n uint offset;\n};\n\nstruct TileRef\n{\n uint offset;\n};\n\nstruct Path\n{\n uvec4 bbox;\n TileRef tiles;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _95;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _310;\n\nshared uint sh_tile_count[128];\nshared MallocResult sh_tile_alloc;\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _95.memory[offset];\n return v;\n}\n\nuint Annotated_tag(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n return read_mem(param, param_1);\n}\n\nAnnoFill AnnoFill_read(Alloc a, AnnoFillRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n Alloc param_8 = a;\n uint param_9 = ix + 4u;\n uint raw4 = read_mem(param_8, param_9);\n AnnoFill s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n s.rgba_color = raw4;\n return s;\n}\n\nAnnoFill Annotated_Fill_read(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n AnnoFillRef param_1 = AnnoFillRef(ref.offset + 4u);\n return AnnoFill_read(param, param_1);\n}\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nMallocResult malloc(uint size)\n{\n MallocResult r;\n r.failed = false;\n uint _101 = atomicAdd(_95.mem_offset, size);\n uint offset = _101;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_95.memory.length())) * 4))\n {\n r.failed = true;\n uint _122 = atomicMax(_95.mem_error, 1u);\n return r;\n }\n return r;\n}\n\nAlloc slice_mem(Alloc a, uint offset, uint size)\n{\n uint param = a.offset + offset;\n uint param_1 = size;\n return new_alloc(param, param_1);\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _95.memory[offset] = val;\n}\n\nvoid Path_write(Alloc a, PathRef ref, Path s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.bbox.x | (s.bbox.y << uint(16));\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = s.bbox.z | (s.bbox.w << uint(16));\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = s.tiles.offset;\n write_mem(param_6, param_7, param_8);\n}\n\nvoid main()\n{\n if (_95.mem_error != 0u)\n {\n return;\n }\n uint th_ix = gl_LocalInvocationID.x;\n uint element_ix = gl_GlobalInvocationID.x;\n PathRef path_ref = PathRef(_310.conf.tile_alloc.offset + (element_ix * 12u));\n AnnotatedRef ref = AnnotatedRef(_310.conf.anno_alloc.offset + (element_ix * 28u));\n uint tag = 0u;\n if (element_ix < _310.conf.n_elements)\n {\n Alloc param;\n param.offset = _310.conf.anno_alloc.offset;\n AnnotatedRef param_1 = ref;\n tag = Annotated_tag(param, param_1);\n }\n int x0 = 0;\n int y0 = 0;\n int x1 = 0;\n int y1 = 0;\n switch (tag)\n {\n case 2u:\n case 3u:\n case 1u:\n case 4u:\n case 5u:\n {\n Alloc param_2;\n param_2.offset = _310.conf.anno_alloc.offset;\n AnnotatedRef param_3 = ref;\n AnnoFill fill = Annotated_Fill_read(param_2, param_3);\n x0 = int(floor(fill.bbox.x * 0.03125));\n y0 = int(floor(fill.bbox.y * 0.03125));\n x1 = int(ceil(fill.bbox.z * 0.03125));\n y1 = int(ceil(fill.bbox.w * 0.03125));\n break;\n }\n }\n x0 = clamp(x0, 0, int(_310.conf.width_in_tiles));\n y0 = clamp(y0, 0, int(_310.conf.height_in_tiles));\n x1 = clamp(x1, 0, int(_310.conf.width_in_tiles));\n y1 = clamp(y1, 0, int(_310.conf.height_in_tiles));\n Path path;\n path.bbox = uvec4(uint(x0), uint(y0), uint(x1), uint(y1));\n uint tile_count = uint((x1 - x0) * (y1 - y0));\n if (tag == 5u)\n {\n tile_count = 0u;\n }\n sh_tile_count[th_ix] = tile_count;\n uint total_tile_count = tile_count;\n for (uint i = 0u; i < 7u; i++)\n {\n barrier();\n if (th_ix >= uint(1 << int(i)))\n {\n total_tile_count += sh_tile_count[th_ix - uint(1 << int(i))];\n }\n barrier();\n sh_tile_count[th_ix] = total_tile_count;\n }\n if (th_ix == 127u)\n {\n uint param_4 = total_tile_count * 8u;\n MallocResult _483 = malloc(param_4);\n sh_tile_alloc = _483;\n }\n barrier();\n MallocResult alloc_start = sh_tile_alloc;\n if (alloc_start.failed)\n {\n return;\n }\n if (element_ix < _310.conf.n_elements)\n {\n uint _500;\n if (th_ix > 0u)\n {\n _500 = sh_tile_count[th_ix - 1u];\n }\n else\n {\n _500 = 0u;\n }\n uint tile_subix = _500;\n Alloc param_5 = alloc_start.alloc;\n uint param_6 = 8u * tile_subix;\n uint param_7 = 8u * tile_count;\n Alloc tiles_alloc = slice_mem(param_5, param_6, param_7);\n path.tiles = TileRef(tiles_alloc.offset);\n Alloc param_8;\n param_8.offset = _310.conf.tile_alloc.offset;\n PathRef param_9 = path_ref;\n Path param_10 = path;\n Path_write(param_8, param_9, param_10);\n }\n uint total_count = sh_tile_count[127] * 2u;\n uint start_ix = alloc_start.alloc.offset >> uint(2);\n for (uint i_1 = th_ix; i_1 < total_count; i_1 += 128u)\n {\n Alloc param_11 = alloc_start.alloc;\n uint param_12 = start_ix + i_1;\n uint param_13 = 0u;\n write_mem(param_11, param_12, param_13);\n }\n}\n\n", + GLSL310ES: "#version 310 es\nlayout(local_size_x = 128, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct MallocResult\n{\n Alloc alloc;\n bool failed;\n};\n\nstruct AnnoEndClipRef\n{\n uint offset;\n};\n\nstruct AnnoEndClip\n{\n vec4 bbox;\n};\n\nstruct AnnotatedRef\n{\n uint offset;\n};\n\nstruct AnnotatedTag\n{\n uint tag;\n uint flags;\n};\n\nstruct PathRef\n{\n uint offset;\n};\n\nstruct TileRef\n{\n uint offset;\n};\n\nstruct Path\n{\n uvec4 bbox;\n TileRef tiles;\n};\n\nstruct Config\n{\n uint n_elements;\n uint n_pathseg;\n uint width_in_tiles;\n uint height_in_tiles;\n Alloc tile_alloc;\n Alloc bin_alloc;\n Alloc ptcl_alloc;\n Alloc pathseg_alloc;\n Alloc anno_alloc;\n Alloc trans_alloc;\n};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _96;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _309;\n\nshared uint sh_tile_count[128];\nshared MallocResult sh_tile_alloc;\n\nbool touch_mem(Alloc alloc, uint offset)\n{\n return true;\n}\n\nuint read_mem(Alloc alloc, uint offset)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return 0u;\n }\n uint v = _96.memory[offset];\n return v;\n}\n\nAnnotatedTag Annotated_tag(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n uint param_1 = ref.offset >> uint(2);\n uint tag_and_flags = read_mem(param, param_1);\n return AnnotatedTag(tag_and_flags & 65535u, tag_and_flags >> uint(16));\n}\n\nAnnoEndClip AnnoEndClip_read(Alloc a, AnnoEndClipRef ref)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint raw0 = read_mem(param, param_1);\n Alloc param_2 = a;\n uint param_3 = ix + 1u;\n uint raw1 = read_mem(param_2, param_3);\n Alloc param_4 = a;\n uint param_5 = ix + 2u;\n uint raw2 = read_mem(param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 3u;\n uint raw3 = read_mem(param_6, param_7);\n AnnoEndClip s;\n s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));\n return s;\n}\n\nAnnoEndClip Annotated_EndClip_read(Alloc a, AnnotatedRef ref)\n{\n Alloc param = a;\n AnnoEndClipRef param_1 = AnnoEndClipRef(ref.offset + 4u);\n return AnnoEndClip_read(param, param_1);\n}\n\nAlloc new_alloc(uint offset, uint size)\n{\n Alloc a;\n a.offset = offset;\n return a;\n}\n\nMallocResult malloc(uint size)\n{\n MallocResult r;\n r.failed = false;\n uint _102 = atomicAdd(_96.mem_offset, size);\n uint offset = _102;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_96.memory.length())) * 4))\n {\n r.failed = true;\n uint _123 = atomicMax(_96.mem_error, 1u);\n return r;\n }\n return r;\n}\n\nAlloc slice_mem(Alloc a, uint offset, uint size)\n{\n uint param = a.offset + offset;\n uint param_1 = size;\n return new_alloc(param, param_1);\n}\n\nvoid write_mem(Alloc alloc, uint offset, uint val)\n{\n Alloc param = alloc;\n uint param_1 = offset;\n if (!touch_mem(param, param_1))\n {\n return;\n }\n _96.memory[offset] = val;\n}\n\nvoid Path_write(Alloc a, PathRef ref, Path s)\n{\n uint ix = ref.offset >> uint(2);\n Alloc param = a;\n uint param_1 = ix + 0u;\n uint param_2 = s.bbox.x | (s.bbox.y << uint(16));\n write_mem(param, param_1, param_2);\n Alloc param_3 = a;\n uint param_4 = ix + 1u;\n uint param_5 = s.bbox.z | (s.bbox.w << uint(16));\n write_mem(param_3, param_4, param_5);\n Alloc param_6 = a;\n uint param_7 = ix + 2u;\n uint param_8 = s.tiles.offset;\n write_mem(param_6, param_7, param_8);\n}\n\nvoid main()\n{\n if (_96.mem_error != 0u)\n {\n return;\n }\n uint th_ix = gl_LocalInvocationID.x;\n uint element_ix = gl_GlobalInvocationID.x;\n PathRef path_ref = PathRef(_309.conf.tile_alloc.offset + (element_ix * 12u));\n AnnotatedRef ref = AnnotatedRef(_309.conf.anno_alloc.offset + (element_ix * 32u));\n uint tag = 0u;\n if (element_ix < _309.conf.n_elements)\n {\n Alloc param;\n param.offset = _309.conf.anno_alloc.offset;\n AnnotatedRef param_1 = ref;\n tag = Annotated_tag(param, param_1).tag;\n }\n int x0 = 0;\n int y0 = 0;\n int x1 = 0;\n int y1 = 0;\n switch (tag)\n {\n case 1u:\n case 2u:\n case 3u:\n case 4u:\n {\n Alloc param_2;\n param_2.offset = _309.conf.anno_alloc.offset;\n AnnotatedRef param_3 = ref;\n AnnoEndClip clip = Annotated_EndClip_read(param_2, param_3);\n x0 = int(floor(clip.bbox.x * 0.03125));\n y0 = int(floor(clip.bbox.y * 0.03125));\n x1 = int(ceil(clip.bbox.z * 0.03125));\n y1 = int(ceil(clip.bbox.w * 0.03125));\n break;\n }\n }\n x0 = clamp(x0, 0, int(_309.conf.width_in_tiles));\n y0 = clamp(y0, 0, int(_309.conf.height_in_tiles));\n x1 = clamp(x1, 0, int(_309.conf.width_in_tiles));\n y1 = clamp(y1, 0, int(_309.conf.height_in_tiles));\n Path path;\n path.bbox = uvec4(uint(x0), uint(y0), uint(x1), uint(y1));\n uint tile_count = uint((x1 - x0) * (y1 - y0));\n if (tag == 4u)\n {\n tile_count = 0u;\n }\n sh_tile_count[th_ix] = tile_count;\n uint total_tile_count = tile_count;\n for (uint i = 0u; i < 7u; i++)\n {\n barrier();\n if (th_ix >= uint(1 << int(i)))\n {\n total_tile_count += sh_tile_count[th_ix - uint(1 << int(i))];\n }\n barrier();\n sh_tile_count[th_ix] = total_tile_count;\n }\n if (th_ix == 127u)\n {\n uint param_4 = total_tile_count * 8u;\n MallocResult _482 = malloc(param_4);\n sh_tile_alloc = _482;\n }\n barrier();\n MallocResult alloc_start = sh_tile_alloc;\n if (alloc_start.failed)\n {\n return;\n }\n if (element_ix < _309.conf.n_elements)\n {\n uint _499;\n if (th_ix > 0u)\n {\n _499 = sh_tile_count[th_ix - 1u];\n }\n else\n {\n _499 = 0u;\n }\n uint tile_subix = _499;\n Alloc param_5 = alloc_start.alloc;\n uint param_6 = 8u * tile_subix;\n uint param_7 = 8u * tile_count;\n Alloc tiles_alloc = slice_mem(param_5, param_6, param_7);\n path.tiles = TileRef(tiles_alloc.offset);\n Alloc param_8;\n param_8.offset = _309.conf.tile_alloc.offset;\n PathRef param_9 = path_ref;\n Path param_10 = path;\n Path_write(param_8, param_9, param_10);\n }\n uint total_count = sh_tile_count[127] * 2u;\n uint start_ix = alloc_start.alloc.offset >> uint(2);\n for (uint i_1 = th_ix; i_1 < total_count; i_1 += 128u)\n {\n Alloc param_11 = alloc_start.alloc;\n uint param_12 = start_ix + i_1;\n uint param_13 = 0u;\n write_mem(param_11, param_12, param_13);\n }\n}\n\n", } ) diff --git a/gpu/shaders/annotated.h b/gpu/shaders/annotated.h index 40ded792..6b181559 100644 --- a/gpu/shaders/annotated.h +++ b/gpu/shaders/annotated.h @@ -2,19 +2,19 @@ // Code auto-generated by piet-gpu-derive -struct AnnoFillRef { +struct AnnoImageRef { uint offset; }; -struct AnnoFillImageRef { +struct AnnoColorRef { uint offset; }; -struct AnnoStrokeRef { +struct AnnoBeginClipRef { uint offset; }; -struct AnnoClipRef { +struct AnnoEndClipRef { uint offset; }; @@ -22,86 +22,69 @@ struct AnnotatedRef { uint offset; }; -struct AnnoFill { - vec4 bbox; - uint rgba_color; -}; - -#define AnnoFill_size 20 - -AnnoFillRef AnnoFill_index(AnnoFillRef ref, uint index) { - return AnnoFillRef(ref.offset + index * AnnoFill_size); -} - -struct AnnoFillImage { +struct AnnoImage { vec4 bbox; + float linewidth; uint index; ivec2 offset; }; -#define AnnoFillImage_size 24 +#define AnnoImage_size 28 -AnnoFillImageRef AnnoFillImage_index(AnnoFillImageRef ref, uint index) { - return AnnoFillImageRef(ref.offset + index * AnnoFillImage_size); +AnnoImageRef AnnoImage_index(AnnoImageRef ref, uint index) { + return AnnoImageRef(ref.offset + index * AnnoImage_size); } -struct AnnoStroke { +struct AnnoColor { vec4 bbox; + float linewidth; uint rgba_color; +}; + +#define AnnoColor_size 24 + +AnnoColorRef AnnoColor_index(AnnoColorRef ref, uint index) { + return AnnoColorRef(ref.offset + index * AnnoColor_size); +} + +struct AnnoBeginClip { + vec4 bbox; float linewidth; }; -#define AnnoStroke_size 24 +#define AnnoBeginClip_size 20 -AnnoStrokeRef AnnoStroke_index(AnnoStrokeRef ref, uint index) { - return AnnoStrokeRef(ref.offset + index * AnnoStroke_size); +AnnoBeginClipRef AnnoBeginClip_index(AnnoBeginClipRef ref, uint index) { + return AnnoBeginClipRef(ref.offset + index * AnnoBeginClip_size); } -struct AnnoClip { +struct AnnoEndClip { vec4 bbox; }; -#define AnnoClip_size 16 +#define AnnoEndClip_size 16 -AnnoClipRef AnnoClip_index(AnnoClipRef ref, uint index) { - return AnnoClipRef(ref.offset + index * AnnoClip_size); +AnnoEndClipRef AnnoEndClip_index(AnnoEndClipRef ref, uint index) { + return AnnoEndClipRef(ref.offset + index * AnnoEndClip_size); } #define Annotated_Nop 0 -#define Annotated_Stroke 1 -#define Annotated_Fill 2 -#define Annotated_FillImage 3 -#define Annotated_BeginClip 4 -#define Annotated_EndClip 5 -#define Annotated_size 28 +#define Annotated_Color 1 +#define Annotated_Image 2 +#define Annotated_BeginClip 3 +#define Annotated_EndClip 4 +#define Annotated_size 32 AnnotatedRef Annotated_index(AnnotatedRef ref, uint index) { return AnnotatedRef(ref.offset + index * Annotated_size); } -AnnoFill AnnoFill_read(Alloc a, AnnoFillRef ref) { - uint ix = ref.offset >> 2; - uint raw0 = read_mem(a, ix + 0); - uint raw1 = read_mem(a, ix + 1); - uint raw2 = read_mem(a, ix + 2); - uint raw3 = read_mem(a, ix + 3); - uint raw4 = read_mem(a, ix + 4); - AnnoFill s; - s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3)); - s.rgba_color = raw4; - return s; -} +struct AnnotatedTag { + uint tag; + uint flags; +}; -void AnnoFill_write(Alloc a, AnnoFillRef ref, AnnoFill s) { - uint ix = ref.offset >> 2; - write_mem(a, ix + 0, floatBitsToUint(s.bbox.x)); - write_mem(a, ix + 1, floatBitsToUint(s.bbox.y)); - write_mem(a, ix + 2, floatBitsToUint(s.bbox.z)); - write_mem(a, ix + 3, floatBitsToUint(s.bbox.w)); - write_mem(a, ix + 4, s.rgba_color); -} - -AnnoFillImage AnnoFillImage_read(Alloc a, AnnoFillImageRef ref) { +AnnoImage AnnoImage_read(Alloc a, AnnoImageRef ref) { uint ix = ref.offset >> 2; uint raw0 = read_mem(a, ix + 0); uint raw1 = read_mem(a, ix + 1); @@ -109,24 +92,27 @@ AnnoFillImage AnnoFillImage_read(Alloc a, AnnoFillImageRef ref) { uint raw3 = read_mem(a, ix + 3); uint raw4 = read_mem(a, ix + 4); uint raw5 = read_mem(a, ix + 5); - AnnoFillImage s; + uint raw6 = read_mem(a, ix + 6); + AnnoImage s; s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3)); - s.index = raw4; - s.offset = ivec2(int(raw5 << 16) >> 16, int(raw5) >> 16); + s.linewidth = uintBitsToFloat(raw4); + s.index = raw5; + s.offset = ivec2(int(raw6 << 16) >> 16, int(raw6) >> 16); return s; } -void AnnoFillImage_write(Alloc a, AnnoFillImageRef ref, AnnoFillImage s) { +void AnnoImage_write(Alloc a, AnnoImageRef ref, AnnoImage s) { uint ix = ref.offset >> 2; write_mem(a, ix + 0, floatBitsToUint(s.bbox.x)); write_mem(a, ix + 1, floatBitsToUint(s.bbox.y)); write_mem(a, ix + 2, floatBitsToUint(s.bbox.z)); write_mem(a, ix + 3, floatBitsToUint(s.bbox.w)); - write_mem(a, ix + 4, s.index); - write_mem(a, ix + 5, (uint(s.offset.x) & 0xffff) | (uint(s.offset.y) << 16)); + write_mem(a, ix + 4, floatBitsToUint(s.linewidth)); + write_mem(a, ix + 5, s.index); + write_mem(a, ix + 6, (uint(s.offset.x) & 0xffff) | (uint(s.offset.y) << 16)); } -AnnoStroke AnnoStroke_read(Alloc a, AnnoStrokeRef ref) { +AnnoColor AnnoColor_read(Alloc a, AnnoColorRef ref) { uint ix = ref.offset >> 2; uint raw0 = read_mem(a, ix + 0); uint raw1 = read_mem(a, ix + 1); @@ -134,35 +120,57 @@ AnnoStroke AnnoStroke_read(Alloc a, AnnoStrokeRef ref) { uint raw3 = read_mem(a, ix + 3); uint raw4 = read_mem(a, ix + 4); uint raw5 = read_mem(a, ix + 5); - AnnoStroke s; + AnnoColor s; s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3)); - s.rgba_color = raw4; - s.linewidth = uintBitsToFloat(raw5); + s.linewidth = uintBitsToFloat(raw4); + s.rgba_color = raw5; return s; } -void AnnoStroke_write(Alloc a, AnnoStrokeRef ref, AnnoStroke s) { +void AnnoColor_write(Alloc a, AnnoColorRef ref, AnnoColor s) { uint ix = ref.offset >> 2; write_mem(a, ix + 0, floatBitsToUint(s.bbox.x)); write_mem(a, ix + 1, floatBitsToUint(s.bbox.y)); write_mem(a, ix + 2, floatBitsToUint(s.bbox.z)); write_mem(a, ix + 3, floatBitsToUint(s.bbox.w)); - write_mem(a, ix + 4, s.rgba_color); - write_mem(a, ix + 5, floatBitsToUint(s.linewidth)); + write_mem(a, ix + 4, floatBitsToUint(s.linewidth)); + write_mem(a, ix + 5, s.rgba_color); } -AnnoClip AnnoClip_read(Alloc a, AnnoClipRef ref) { +AnnoBeginClip AnnoBeginClip_read(Alloc a, AnnoBeginClipRef ref) { uint ix = ref.offset >> 2; uint raw0 = read_mem(a, ix + 0); uint raw1 = read_mem(a, ix + 1); uint raw2 = read_mem(a, ix + 2); uint raw3 = read_mem(a, ix + 3); - AnnoClip s; + uint raw4 = read_mem(a, ix + 4); + AnnoBeginClip s; + s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3)); + s.linewidth = uintBitsToFloat(raw4); + return s; +} + +void AnnoBeginClip_write(Alloc a, AnnoBeginClipRef ref, AnnoBeginClip s) { + uint ix = ref.offset >> 2; + write_mem(a, ix + 0, floatBitsToUint(s.bbox.x)); + write_mem(a, ix + 1, floatBitsToUint(s.bbox.y)); + write_mem(a, ix + 2, floatBitsToUint(s.bbox.z)); + write_mem(a, ix + 3, floatBitsToUint(s.bbox.w)); + write_mem(a, ix + 4, floatBitsToUint(s.linewidth)); +} + +AnnoEndClip AnnoEndClip_read(Alloc a, AnnoEndClipRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = read_mem(a, ix + 0); + uint raw1 = read_mem(a, ix + 1); + uint raw2 = read_mem(a, ix + 2); + uint raw3 = read_mem(a, ix + 3); + AnnoEndClip s; s.bbox = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3)); return s; } -void AnnoClip_write(Alloc a, AnnoClipRef ref, AnnoClip s) { +void AnnoEndClip_write(Alloc a, AnnoEndClipRef ref, AnnoEndClip s) { uint ix = ref.offset >> 2; write_mem(a, ix + 0, floatBitsToUint(s.bbox.x)); write_mem(a, ix + 1, floatBitsToUint(s.bbox.y)); @@ -170,56 +178,48 @@ void AnnoClip_write(Alloc a, AnnoClipRef ref, AnnoClip s) { write_mem(a, ix + 3, floatBitsToUint(s.bbox.w)); } -uint Annotated_tag(Alloc a, AnnotatedRef ref) { - return read_mem(a, ref.offset >> 2); +AnnotatedTag Annotated_tag(Alloc a, AnnotatedRef ref) { + uint tag_and_flags = read_mem(a, ref.offset >> 2); + return AnnotatedTag(tag_and_flags & 0xffff, tag_and_flags >> 16); } -AnnoStroke Annotated_Stroke_read(Alloc a, AnnotatedRef ref) { - return AnnoStroke_read(a, AnnoStrokeRef(ref.offset + 4)); +AnnoColor Annotated_Color_read(Alloc a, AnnotatedRef ref) { + return AnnoColor_read(a, AnnoColorRef(ref.offset + 4)); } -AnnoFill Annotated_Fill_read(Alloc a, AnnotatedRef ref) { - return AnnoFill_read(a, AnnoFillRef(ref.offset + 4)); +AnnoImage Annotated_Image_read(Alloc a, AnnotatedRef ref) { + return AnnoImage_read(a, AnnoImageRef(ref.offset + 4)); } -AnnoFillImage Annotated_FillImage_read(Alloc a, AnnotatedRef ref) { - return AnnoFillImage_read(a, AnnoFillImageRef(ref.offset + 4)); +AnnoBeginClip Annotated_BeginClip_read(Alloc a, AnnotatedRef ref) { + return AnnoBeginClip_read(a, AnnoBeginClipRef(ref.offset + 4)); } -AnnoClip Annotated_BeginClip_read(Alloc a, AnnotatedRef ref) { - return AnnoClip_read(a, AnnoClipRef(ref.offset + 4)); -} - -AnnoClip Annotated_EndClip_read(Alloc a, AnnotatedRef ref) { - return AnnoClip_read(a, AnnoClipRef(ref.offset + 4)); +AnnoEndClip Annotated_EndClip_read(Alloc a, AnnotatedRef ref) { + return AnnoEndClip_read(a, AnnoEndClipRef(ref.offset + 4)); } void Annotated_Nop_write(Alloc a, AnnotatedRef ref) { write_mem(a, ref.offset >> 2, Annotated_Nop); } -void Annotated_Stroke_write(Alloc a, AnnotatedRef ref, AnnoStroke s) { - write_mem(a, ref.offset >> 2, Annotated_Stroke); - AnnoStroke_write(a, AnnoStrokeRef(ref.offset + 4), s); +void Annotated_Color_write(Alloc a, AnnotatedRef ref, uint flags, AnnoColor s) { + write_mem(a, ref.offset >> 2, (flags << 16) | Annotated_Color); + AnnoColor_write(a, AnnoColorRef(ref.offset + 4), s); } -void Annotated_Fill_write(Alloc a, AnnotatedRef ref, AnnoFill s) { - write_mem(a, ref.offset >> 2, Annotated_Fill); - AnnoFill_write(a, AnnoFillRef(ref.offset + 4), s); +void Annotated_Image_write(Alloc a, AnnotatedRef ref, uint flags, AnnoImage s) { + write_mem(a, ref.offset >> 2, (flags << 16) | Annotated_Image); + AnnoImage_write(a, AnnoImageRef(ref.offset + 4), s); } -void Annotated_FillImage_write(Alloc a, AnnotatedRef ref, AnnoFillImage s) { - write_mem(a, ref.offset >> 2, Annotated_FillImage); - AnnoFillImage_write(a, AnnoFillImageRef(ref.offset + 4), s); +void Annotated_BeginClip_write(Alloc a, AnnotatedRef ref, uint flags, AnnoBeginClip s) { + write_mem(a, ref.offset >> 2, (flags << 16) | Annotated_BeginClip); + AnnoBeginClip_write(a, AnnoBeginClipRef(ref.offset + 4), s); } -void Annotated_BeginClip_write(Alloc a, AnnotatedRef ref, AnnoClip s) { - write_mem(a, ref.offset >> 2, Annotated_BeginClip); - AnnoClip_write(a, AnnoClipRef(ref.offset + 4), s); -} - -void Annotated_EndClip_write(Alloc a, AnnotatedRef ref, AnnoClip s) { +void Annotated_EndClip_write(Alloc a, AnnotatedRef ref, AnnoEndClip s) { write_mem(a, ref.offset >> 2, Annotated_EndClip); - AnnoClip_write(a, AnnoClipRef(ref.offset + 4), s); + AnnoEndClip_write(a, AnnoEndClipRef(ref.offset + 4), s); } diff --git a/gpu/shaders/backdrop.comp b/gpu/shaders/backdrop.comp index 49de925a..84612752 100644 --- a/gpu/shaders/backdrop.comp +++ b/gpu/shaders/backdrop.comp @@ -46,10 +46,14 @@ void main() { // Work assignment: 1 thread : 1 path element uint row_count = 0; if (element_ix < conf.n_elements) { - uint tag = Annotated_tag(conf.anno_alloc, ref); - switch (tag) { - case Annotated_Fill: - case Annotated_FillImage: + AnnotatedTag tag = Annotated_tag(conf.anno_alloc, ref); + switch (tag.tag) { + 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); diff --git a/gpu/shaders/binning.comp b/gpu/shaders/binning.comp index 3a63ac2b..a43722d3 100644 --- a/gpu/shaders/binning.comp +++ b/gpu/shaders/binning.comp @@ -56,22 +56,21 @@ void main() { AnnotatedRef ref = AnnotatedRef(conf.anno_alloc.offset + element_ix * Annotated_size); uint tag = Annotated_Nop; if (element_ix < my_n_elements) { - tag = Annotated_tag(conf.anno_alloc, ref); + tag = Annotated_tag(conf.anno_alloc, ref).tag; } int x0 = 0, y0 = 0, x1 = 0, y1 = 0; switch (tag) { - case Annotated_Fill: - case Annotated_FillImage: - case Annotated_Stroke: + case Annotated_Color: + case Annotated_Image: case Annotated_BeginClip: case Annotated_EndClip: // Note: we take advantage of the fact that these drawing elements // have the bbox at the same place in their layout. - AnnoFill fill = Annotated_Fill_read(conf.anno_alloc, ref); - x0 = int(floor(fill.bbox.x * SX)); - y0 = int(floor(fill.bbox.y * SY)); - x1 = int(ceil(fill.bbox.z * SX)); - y1 = int(ceil(fill.bbox.w * SY)); + AnnoEndClip clip = Annotated_EndClip_read(conf.anno_alloc, ref); + x0 = int(floor(clip.bbox.x * SX)); + y0 = int(floor(clip.bbox.y * SY)); + x1 = int(ceil(clip.bbox.z * SX)); + y1 = int(ceil(clip.bbox.w * SY)); break; } diff --git a/gpu/shaders/coarse.comp b/gpu/shaders/coarse.comp index 069367fc..a4837bd5 100644 --- a/gpu/shaders/coarse.comp +++ b/gpu/shaders/coarse.comp @@ -70,6 +70,9 @@ Alloc read_tile_alloc(uint el_ix) { } #endif +// The maximum number of commands per annotated element. +#define ANNO_COMMANDS 2 + // Perhaps cmd_alloc should be a global? This is a style question. bool alloc_cmd(inout Alloc cmd_alloc, inout CmdRef cmd_ref, inout uint cmd_limit) { if (cmd_ref.offset < cmd_limit) { @@ -83,7 +86,8 @@ bool alloc_cmd(inout Alloc cmd_alloc, inout CmdRef cmd_ref, inout uint cmd_limit Cmd_Jump_write(cmd_alloc, cmd_ref, jump); cmd_alloc = new_cmd.alloc; cmd_ref = CmdRef(cmd_alloc.offset); - cmd_limit = cmd_alloc.offset + PTCL_INITIAL_ALLOC - 2 * Cmd_size; + // Reserve space for the maximum number of commands and a potential jump. + cmd_limit = cmd_alloc.offset + PTCL_INITIAL_ALLOC - (ANNO_COMMANDS + 1) * Cmd_size; return true; } @@ -110,7 +114,8 @@ void main() { uint this_tile_ix = (bin_tile_y + tile_y) * conf.width_in_tiles + bin_tile_x + tile_x; Alloc cmd_alloc = slice_mem(conf.ptcl_alloc, this_tile_ix * PTCL_INITIAL_ALLOC, PTCL_INITIAL_ALLOC); CmdRef cmd_ref = CmdRef(cmd_alloc.offset); - uint cmd_limit = cmd_ref.offset + PTCL_INITIAL_ALLOC - 2 * Cmd_size; + // Reserve space for the maximum number of commands and a potential jump. + uint cmd_limit = cmd_ref.offset + PTCL_INITIAL_ALLOC - (ANNO_COMMANDS + 1) * Cmd_size; // The nesting depth of the clip stack uint clip_depth = 0; // State for the "clip zero" optimization. If it's nonzero, then we are @@ -196,15 +201,14 @@ void main() { if (th_ix + rd_ix < wr_ix) { element_ix = sh_elements[th_ix]; ref = AnnotatedRef(conf.anno_alloc.offset + element_ix * Annotated_size); - tag = Annotated_tag(conf.anno_alloc, ref); + tag = Annotated_tag(conf.anno_alloc, ref).tag; } // Bounding box of element in pixel coordinates. uint tile_count; switch (tag) { - case Annotated_Fill: - case Annotated_FillImage: - case Annotated_Stroke: + case Annotated_Color: + case Annotated_Image: case Annotated_BeginClip: case Annotated_EndClip: // We have one "path" for each element, even if the element isn't @@ -256,7 +260,7 @@ void main() { } } AnnotatedRef ref = AnnotatedRef(conf.anno_alloc.offset + sh_elements[el_ix] * Annotated_size); - uint tag = Annotated_tag(conf.anno_alloc, ref); + uint tag = Annotated_tag(conf.anno_alloc, ref).tag; uint seq_ix = ix - (el_ix > 0 ? sh_tile_count[el_ix - 1] : 0); uint width = sh_tile_width[el_ix]; uint x = sh_tile_x0[el_ix] + seq_ix % width; @@ -305,49 +309,57 @@ void main() { // If that turns out to be expensive, maybe we can pack it into // shared memory (or perhaps just the tag). ref = AnnotatedRef(conf.anno_alloc.offset + element_ix * Annotated_size); - tag = Annotated_tag(conf.anno_alloc, ref); + AnnotatedTag tag = Annotated_tag(conf.anno_alloc, ref); if (clip_zero_depth == 0) { - switch (tag) { - case Annotated_Fill: + switch (tag.tag) { + case Annotated_Color: Tile tile = Tile_read(read_tile_alloc(element_ref_ix), TileRef(sh_tile_base[element_ref_ix] + (sh_tile_stride[element_ref_ix] * tile_y + tile_x) * Tile_size)); - AnnoFill fill = Annotated_Fill_read(conf.anno_alloc, ref); + AnnoColor fill = Annotated_Color_read(conf.anno_alloc, ref); if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) { break; } - if (tile.tile.offset != 0) { - CmdFill cmd_fill; - cmd_fill.tile_ref = tile.tile.offset; - cmd_fill.backdrop = tile.backdrop; - cmd_fill.rgba_color = fill.rgba_color; - Cmd_Fill_write(cmd_alloc, cmd_ref, cmd_fill); + 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 { - Cmd_Solid_write(cmd_alloc, cmd_ref, CmdSolid(fill.rgba_color)); + 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_ref.offset += Cmd_size; + Cmd_Color_write(cmd_alloc, cmd_ref, CmdColor(fill.rgba_color)); + cmd_ref.offset += 4 + CmdColor_size; break; - case Annotated_FillImage: + case Annotated_Image: tile = Tile_read(read_tile_alloc(element_ref_ix), TileRef(sh_tile_base[element_ref_ix] + (sh_tile_stride[element_ref_ix] * tile_y + tile_x) * Tile_size)); - AnnoFillImage fill_img = Annotated_FillImage_read(conf.anno_alloc, ref); + AnnoImage fill_img = Annotated_Image_read(conf.anno_alloc, ref); if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) { break; } - if (tile.tile.offset != 0) { - CmdFillImage cmd_fill_img; - cmd_fill_img.tile_ref = tile.tile.offset; - cmd_fill_img.backdrop = tile.backdrop; - cmd_fill_img.index = fill_img.index; - cmd_fill_img.offset = fill_img.offset; - Cmd_FillImage_write(cmd_alloc, cmd_ref, cmd_fill_img); + 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 { - CmdSolidImage cmd_solid_img; - cmd_solid_img.index = fill_img.index; - cmd_solid_img.offset = fill_img.offset; - Cmd_SolidImage_write(cmd_alloc, cmd_ref, cmd_solid_img); + 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_ref.offset += Cmd_size; + Cmd_Image_write(cmd_alloc, cmd_ref, CmdImage(fill_img.index, fill_img.offset)); + cmd_ref.offset += 4 + CmdImage_size; break; case Annotated_BeginClip: tile = Tile_read(read_tile_alloc(element_ref_ix), TileRef(sh_tile_base[element_ref_ix] @@ -357,20 +369,28 @@ void main() { } else if (tile.tile.offset == 0 && clip_depth < 32) { clip_one_mask |= (1 << clip_depth); } else { + AnnoBeginClip begin_clip = Annotated_BeginClip_read(conf.anno_alloc, ref); if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) { break; } - if (tile.tile.offset != 0) { - CmdBeginClip cmd_begin_clip; - cmd_begin_clip.tile_ref = tile.tile.offset; - cmd_begin_clip.backdrop = tile.backdrop; - Cmd_BeginClip_write(cmd_alloc, cmd_ref, cmd_begin_clip); + 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 { - // TODO: here is where a bunch of optimization magic should happen - float alpha = tile.backdrop == 0 ? 0.0 : 1.0; - Cmd_BeginSolidClip_write(cmd_alloc, cmd_ref, CmdBeginSolidClip(alpha)); + 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_ref.offset += Cmd_size; + Cmd_BeginClip_write(cmd_alloc, cmd_ref); + cmd_ref.offset += 4; if (clip_depth < 32) { clip_one_mask &= ~(1 << clip_depth); } @@ -383,28 +403,16 @@ void main() { if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) { break; } - Cmd_EndClip_write(cmd_alloc, cmd_ref, CmdEndClip(1.0)); - cmd_ref.offset += Cmd_size; + Cmd_Solid_write(cmd_alloc, cmd_ref); + cmd_ref.offset += 4; + Cmd_EndClip_write(cmd_alloc, cmd_ref); + cmd_ref.offset += 4; } break; - case Annotated_Stroke: - tile = Tile_read(read_tile_alloc(element_ref_ix), TileRef(sh_tile_base[element_ref_ix] - + (sh_tile_stride[element_ref_ix] * tile_y + tile_x) * Tile_size)); - AnnoStroke stroke = Annotated_Stroke_read(conf.anno_alloc, ref); - CmdStroke cmd_stroke; - cmd_stroke.tile_ref = tile.tile.offset; - cmd_stroke.half_width = 0.5 * stroke.linewidth; - cmd_stroke.rgba_color = stroke.rgba_color; - if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) { - break; - } - Cmd_Stroke_write(cmd_alloc, cmd_ref, cmd_stroke); - cmd_ref.offset += Cmd_size; - break; } } else { // In "clip zero" state, suppress all drawing - switch (tag) { + switch (tag.tag) { case Annotated_BeginClip: clip_depth++; break; diff --git a/gpu/shaders/elements.comp b/gpu/shaders/elements.comp index eb185718..7fb02fcc 100644 --- a/gpu/shaders/elements.comp +++ b/gpu/shaders/elements.comp @@ -63,6 +63,11 @@ uint state_flag_index(uint partition_ix) { #define FLAG_SET_LINEWIDTH 1 #define FLAG_SET_BBOX 2 #define FLAG_RESET_BBOX 4 +#define FLAG_SET_FILL_MODE 8 +// Fill modes take up the next bit. Non-zero fill is 0, stroke is 1. +#define LG_FILL_MODE 4 +#define FILL_MODE_BITS 1 +#define FILL_MODE_MASK (FILL_MODE_BITS << LG_FILL_MODE) // This is almost like a monoid (the interaction between transformation and // bounding boxes is approximate) @@ -88,8 +93,11 @@ State combine_state(State a, State b) { c.translate.x = a.mat.x * b.translate.x + a.mat.z * b.translate.y + a.translate.x; c.translate.y = a.mat.y * b.translate.x + a.mat.w * b.translate.y + a.translate.y; c.linewidth = (b.flags & FLAG_SET_LINEWIDTH) == 0 ? a.linewidth : b.linewidth; - c.flags = (a.flags & (FLAG_SET_LINEWIDTH | FLAG_SET_BBOX)) | b.flags; + c.flags = (a.flags & (FLAG_SET_LINEWIDTH | FLAG_SET_BBOX | FLAG_SET_FILL_MODE)) | b.flags; c.flags |= (a.flags & FLAG_RESET_BBOX) >> 1; + uint fill_mode = (b.flags & FLAG_SET_FILL_MODE) == 0 ? a.flags : b.flags; + fill_mode &= FILL_MODE_MASK; + c.flags = (c.flags & ~FILL_MODE_MASK) | fill_mode; c.path_count = a.path_count + b.path_count; c.pathseg_count = a.pathseg_count + b.pathseg_count; c.trans_count = a.trans_count + b.trans_count; @@ -99,7 +107,7 @@ State combine_state(State a, State b) { State map_element(ElementRef ref) { // TODO: it would *probably* be more efficient to make the memory read patterns less // divergent, though it would be more wasted memory. - uint tag = Element_tag(ref); + uint tag = Element_tag(ref).tag; State c; c.bbox = vec4(0.0, 0.0, 0.0, 0.0); c.mat = vec4(1.0, 0.0, 0.0, 1.0); @@ -110,30 +118,26 @@ State map_element(ElementRef ref) { c.pathseg_count = 0; c.trans_count = 0; switch (tag) { - case Element_FillLine: - case Element_StrokeLine: - LineSeg line = Element_FillLine_read(ref); + case Element_Line: + LineSeg line = Element_Line_read(ref); c.bbox.xy = min(line.p0, line.p1); c.bbox.zw = max(line.p0, line.p1); c.pathseg_count = 1; break; - case Element_FillQuad: - case Element_StrokeQuad: - QuadSeg quad = Element_FillQuad_read(ref); + case Element_Quad: + QuadSeg quad = Element_Quad_read(ref); c.bbox.xy = min(min(quad.p0, quad.p1), quad.p2); c.bbox.zw = max(max(quad.p0, quad.p1), quad.p2); c.pathseg_count = 1; break; - case Element_FillCubic: - case Element_StrokeCubic: - CubicSeg cubic = Element_FillCubic_read(ref); + case Element_Cubic: + CubicSeg cubic = Element_Cubic_read(ref); c.bbox.xy = min(min(cubic.p0, cubic.p1), min(cubic.p2, cubic.p3)); c.bbox.zw = max(max(cubic.p0, cubic.p1), max(cubic.p2, cubic.p3)); c.pathseg_count = 1; break; - case Element_Fill: + case Element_FillColor: case Element_FillImage: - case Element_Stroke: case Element_BeginClip: c.flags = FLAG_RESET_BBOX; c.path_count = 1; @@ -152,6 +156,10 @@ State map_element(ElementRef ref) { c.translate = t.translate; c.trans_count = 1; break; + case Element_SetFillMode: + SetFillMode fm = Element_SetFillMode_read(ref); + c.flags = FLAG_SET_FILL_MODE | (fm.fill_mode << LG_FILL_MODE); + break; } return c; } @@ -291,111 +299,109 @@ void main() { // gains to be had from stashing in shared memory or possibly // registers (though register pressure is an issue). ElementRef this_ref = Element_index(ref, i); - uint tag = Element_tag(this_ref); - switch (tag) { - case Element_FillLine: - case Element_StrokeLine: - LineSeg line = Element_StrokeLine_read(this_ref); - PathStrokeCubic path_cubic; + ElementTag tag = Element_tag(this_ref); + uint fill_mode = fill_mode_from_flags(st.flags >> LG_FILL_MODE); + bool is_stroke = fill_mode == MODE_STROKE; + switch (tag.tag) { + case Element_Line: + LineSeg line = Element_Line_read(this_ref); + PathCubic path_cubic; path_cubic.p0 = line.p0; path_cubic.p1 = mix(line.p0, line.p1, 1.0 / 3.0); path_cubic.p2 = mix(line.p1, line.p0, 1.0 / 3.0); path_cubic.p3 = line.p1; path_cubic.path_ix = st.path_count; path_cubic.trans_ix = st.trans_count; - if (tag == Element_StrokeLine) { + if (is_stroke) { path_cubic.stroke = get_linewidth(st); } else { path_cubic.stroke = vec2(0.0); } - // We do encoding a bit by hand to minimize divergence. Another approach - // would be to have a fill/stroke bool. PathSegRef path_out_ref = PathSegRef(conf.pathseg_alloc.offset + (st.pathseg_count - 1) * PathSeg_size); - uint out_tag = tag == Element_FillLine ? PathSeg_FillCubic : PathSeg_StrokeCubic; - write_mem(conf.pathseg_alloc, path_out_ref.offset >> 2, out_tag); - PathStrokeCubic_write(conf.pathseg_alloc, PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic); + PathSeg_Cubic_write(conf.pathseg_alloc, path_out_ref, fill_mode, path_cubic); break; - case Element_FillQuad: - case Element_StrokeQuad: - QuadSeg quad = Element_StrokeQuad_read(this_ref); + case Element_Quad: + QuadSeg quad = Element_Quad_read(this_ref); path_cubic.p0 = quad.p0; path_cubic.p1 = mix(quad.p1, quad.p0, 1.0 / 3.0); path_cubic.p2 = mix(quad.p1, quad.p2, 1.0 / 3.0); path_cubic.p3 = quad.p2; path_cubic.path_ix = st.path_count; path_cubic.trans_ix = st.trans_count; - if (tag == Element_StrokeQuad) { + if (is_stroke) { path_cubic.stroke = get_linewidth(st); } else { path_cubic.stroke = vec2(0.0); } - // We do encoding a bit by hand to minimize divergence. Another approach - // would be to have a fill/stroke bool. path_out_ref = PathSegRef(conf.pathseg_alloc.offset + (st.pathseg_count - 1) * PathSeg_size); - out_tag = tag == Element_FillQuad ? PathSeg_FillCubic : PathSeg_StrokeCubic; - write_mem(conf.pathseg_alloc, path_out_ref.offset >> 2, out_tag); - PathStrokeCubic_write(conf.pathseg_alloc, PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic); + PathSeg_Cubic_write(conf.pathseg_alloc, path_out_ref, fill_mode, path_cubic); break; - case Element_FillCubic: - case Element_StrokeCubic: - CubicSeg cubic = Element_StrokeCubic_read(this_ref); + case Element_Cubic: + CubicSeg cubic = Element_Cubic_read(this_ref); path_cubic.p0 = cubic.p0; path_cubic.p1 = cubic.p1; path_cubic.p2 = cubic.p2; path_cubic.p3 = cubic.p3; path_cubic.path_ix = st.path_count; path_cubic.trans_ix = st.trans_count; - if (tag == Element_StrokeCubic) { + if (is_stroke) { path_cubic.stroke = get_linewidth(st); } else { path_cubic.stroke = vec2(0.0); } - // We do encoding a bit by hand to minimize divergence. Another approach - // would be to have a fill/stroke bool. path_out_ref = PathSegRef(conf.pathseg_alloc.offset + (st.pathseg_count - 1) * PathSeg_size); - out_tag = tag == Element_FillCubic ? PathSeg_FillCubic : PathSeg_StrokeCubic; - write_mem(conf.pathseg_alloc, path_out_ref.offset >> 2, out_tag); - PathStrokeCubic_write(conf.pathseg_alloc, PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic); + PathSeg_Cubic_write(conf.pathseg_alloc, path_out_ref, fill_mode, path_cubic); break; - case Element_Stroke: - Stroke stroke = Element_Stroke_read(this_ref); - AnnoStroke anno_stroke; - anno_stroke.rgba_color = stroke.rgba_color; - vec2 lw = get_linewidth(st); - anno_stroke.bbox = st.bbox + vec4(-lw, lw); - anno_stroke.linewidth = st.linewidth * sqrt(abs(st.mat.x * st.mat.w - st.mat.y * st.mat.z)); - AnnotatedRef out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size); - Annotated_Stroke_write(conf.anno_alloc, out_ref, anno_stroke); - break; - case Element_Fill: - Fill fill = Element_Fill_read(this_ref); - AnnoFill anno_fill; + case Element_FillColor: + FillColor fill = Element_FillColor_read(this_ref); + AnnoColor anno_fill; anno_fill.rgba_color = fill.rgba_color; - anno_fill.bbox = st.bbox; - out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size); - Annotated_Fill_write(conf.anno_alloc, out_ref, anno_fill); + if (is_stroke) { + vec2 lw = get_linewidth(st); + anno_fill.bbox = st.bbox + vec4(-lw, lw); + anno_fill.linewidth = st.linewidth * sqrt(abs(st.mat.x * st.mat.w - st.mat.y * st.mat.z)); + } else { + anno_fill.bbox = st.bbox; + anno_fill.linewidth = 0.0; + } + AnnotatedRef out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size); + Annotated_Color_write(conf.anno_alloc, out_ref, fill_mode, anno_fill); break; case Element_FillImage: FillImage fill_img = Element_FillImage_read(this_ref); - AnnoFillImage anno_fill_img; - anno_fill_img.index = fill_img.index; - anno_fill_img.offset = fill_img.offset; - anno_fill_img.bbox = st.bbox; + AnnoImage anno_img; + anno_img.index = fill_img.index; + anno_img.offset = fill_img.offset; + if (is_stroke) { + vec2 lw = get_linewidth(st); + anno_img.bbox = st.bbox + vec4(-lw, lw); + anno_img.linewidth = st.linewidth * sqrt(abs(st.mat.x * st.mat.w - st.mat.y * st.mat.z)); + } else { + anno_img.bbox = st.bbox; + anno_img.linewidth = 0.0; + } out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size); - Annotated_FillImage_write(conf.anno_alloc, out_ref, anno_fill_img); + Annotated_Image_write(conf.anno_alloc, out_ref, fill_mode, anno_img); break; case Element_BeginClip: Clip begin_clip = Element_BeginClip_read(this_ref); - AnnoClip anno_begin_clip = AnnoClip(begin_clip.bbox); - // This is the absolute bbox, it's been transformed during encoding. - anno_begin_clip.bbox = begin_clip.bbox; + AnnoBeginClip anno_begin_clip; + 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; + anno_fill.linewidth = 0.0; + } out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size); - Annotated_BeginClip_write(conf.anno_alloc, out_ref, anno_begin_clip); + Annotated_BeginClip_write(conf.anno_alloc, out_ref, fill_mode, anno_begin_clip); break; case Element_EndClip: Clip end_clip = Element_EndClip_read(this_ref); // This bbox is expected to be the same as the begin one. - AnnoClip anno_end_clip = AnnoClip(end_clip.bbox); + AnnoEndClip anno_end_clip = AnnoEndClip(end_clip.bbox); out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size); Annotated_EndClip_write(conf.anno_alloc, out_ref, anno_end_clip); break; diff --git a/gpu/shaders/kernel4.comp b/gpu/shaders/kernel4.comp index 922ae832..b9f59dc3 100644 --- a/gpu/shaders/kernel4.comp +++ b/gpu/shaders/kernel4.comp @@ -56,40 +56,6 @@ MallocResult alloc_clip_buf(uint link) { return sh_clip_alloc; } -// Calculate coverage based on backdrop + coverage of each line segment -float[CHUNK] computeArea(vec2 xy, int backdrop, uint tile_ref) { - // Probably better to store as float, but conversion is no doubt cheap. - float area[CHUNK]; - for (uint k = 0; k < CHUNK; k++) area[k] = float(backdrop); - TileSegRef tile_seg_ref = TileSegRef(tile_ref); - do { - TileSeg seg = TileSeg_read(new_alloc(tile_seg_ref.offset, TileSeg_size), tile_seg_ref); - for (uint k = 0; k < CHUNK; k++) { - vec2 my_xy = vec2(xy.x, xy.y + float(k * CHUNK_DY)); - vec2 start = seg.origin - my_xy; - vec2 end = start + seg.vector; - vec2 window = clamp(vec2(start.y, end.y), 0.0, 1.0); - if (window.x != window.y) { - vec2 t = (window - start.y) / seg.vector.y; - vec2 xs = vec2(mix(start.x, end.x, t.x), mix(start.x, end.x, t.y)); - float xmin = min(min(xs.x, xs.y), 1.0) - 1e-6; - float xmax = max(xs.x, xs.y); - float b = min(xmax, 1.0); - float c = max(b, 0.0); - float d = max(xmin, 0.0); - float a = (b + 0.5 * (d * d - c * c) - xmin) / (xmax - xmin); - area[k] += a * (window.x - window.y); - } - area[k] += sign(seg.vector.x) * clamp(my_xy.y - seg.y_edge + 1.0, 0.0, 1.0); - } - tile_seg_ref = seg.next; - } while (tile_seg_ref.offset != 0); - for (uint k = 0; k < CHUNK; k++) { - area[k] = min(abs(area[k]), 1.0); - } - return area; -} - vec3 tosRGB(vec3 rgb) { bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308)); vec3 below = vec3(12.92)*rgb; @@ -118,7 +84,7 @@ uint packsRGB(vec4 rgba) { return packUnorm4x8(rgba.wzyx); } -vec4[CHUNK] fillImage(uvec2 xy, CmdSolidImage cmd_img) { +vec4[CHUNK] fillImage(uvec2 xy, CmdImage cmd_img) { vec4 rgba[CHUNK]; for (uint i = 0; i < CHUNK; i++) { ivec2 uv = ivec2(xy.x, xy.y + i * CHUNK_DY) + cmd_img.offset; @@ -160,8 +126,9 @@ void main() { mask[i] = 1.0; } + float area[CHUNK]; while (true) { - uint tag = Cmd_tag(cmd_alloc, cmd_ref); + uint tag = Cmd_tag(cmd_alloc, cmd_ref).tag; if (tag == Cmd_End) { break; } @@ -183,31 +150,73 @@ void main() { } tile_seg_ref = seg.next; } while (tile_seg_ref.offset != 0); - vec4 fg_rgba = unpacksRGB(stroke.rgba_color); for (uint k = 0; k < CHUNK; k++) { - float alpha = clamp(stroke.half_width + 0.5 - df[k], 0.0, 1.0); - rgb[k] = mix(rgb[k], fg_rgba.rgb, mask[k] * alpha * fg_rgba.a); + area[k] = clamp(stroke.half_width + 0.5 - df[k], 0.0, 1.0); } + cmd_ref.offset += 4 + CmdStroke_size; break; case Cmd_Fill: CmdFill fill = Cmd_Fill_read(cmd_alloc, cmd_ref); - float area[CHUNK]; - area = computeArea(xy, fill.backdrop, fill.tile_ref); - fg_rgba = unpacksRGB(fill.rgba_color); + for (uint k = 0; k < CHUNK; k++) area[k] = float(fill.backdrop); + tile_seg_ref = TileSegRef(fill.tile_ref); + // Calculate coverage based on backdrop + coverage of each line segment + do { + TileSeg seg = TileSeg_read(new_alloc(tile_seg_ref.offset, TileSeg_size), tile_seg_ref); + for (uint k = 0; k < CHUNK; k++) { + vec2 my_xy = vec2(xy.x, xy.y + float(k * CHUNK_DY)); + vec2 start = seg.origin - my_xy; + vec2 end = start + seg.vector; + vec2 window = clamp(vec2(start.y, end.y), 0.0, 1.0); + if (window.x != window.y) { + vec2 t = (window - start.y) / seg.vector.y; + vec2 xs = vec2(mix(start.x, end.x, t.x), mix(start.x, end.x, t.y)); + float xmin = min(min(xs.x, xs.y), 1.0) - 1e-6; + float xmax = max(xs.x, xs.y); + float b = min(xmax, 1.0); + float c = max(b, 0.0); + float d = max(xmin, 0.0); + float a = (b + 0.5 * (d * d - c * c) - xmin) / (xmax - xmin); + area[k] += a * (window.x - window.y); + } + area[k] += sign(seg.vector.x) * clamp(my_xy.y - seg.y_edge + 1.0, 0.0, 1.0); + } + tile_seg_ref = seg.next; + } while (tile_seg_ref.offset != 0); + for (uint k = 0; k < CHUNK; k++) { + area[k] = min(abs(area[k]), 1.0); + } + cmd_ref.offset += 4 + CmdFill_size; + break; + case Cmd_Solid: + for (uint k = 0; k < CHUNK; k++) { + area[k] = 1.0; + } + cmd_ref.offset += 4; + break; + case Cmd_Alpha: + CmdAlpha alpha = Cmd_Alpha_read(cmd_alloc, cmd_ref); + for (uint k = 0; k < CHUNK; k++) { + area[k] = alpha.alpha; + } + cmd_ref.offset += 4 + CmdAlpha_size; + break; + case Cmd_Color: + CmdColor color = Cmd_Color_read(cmd_alloc, cmd_ref); + vec4 fg_rgba = unpacksRGB(color.rgba_color); for (uint k = 0; k < CHUNK; k++) { rgb[k] = mix(rgb[k], fg_rgba.rgb, mask[k] * area[k] * fg_rgba.a); } + cmd_ref.offset += 4 + CmdColor_size; break; - case Cmd_FillImage: - CmdFillImage fill_img = Cmd_FillImage_read(cmd_alloc, cmd_ref); - area = computeArea(xy, fill_img.backdrop, fill_img.tile_ref); - vec4 rgba[CHUNK] = fillImage(xy_uint, CmdSolidImage(fill_img.index, fill_img.offset)); + case Cmd_Image: + CmdImage fill_img = Cmd_Image_read(cmd_alloc, cmd_ref); + vec4 rgba[CHUNK] = fillImage(xy_uint, fill_img); for (uint k = 0; k < CHUNK; k++) { rgb[k] = mix(rgb[k], rgba[k].rgb, mask[k] * area[k] * rgba[k].a); } + cmd_ref.offset += 4 + CmdImage_size; break; case Cmd_BeginClip: - case Cmd_BeginSolidClip: uint blend_slot = blend_sp % BLEND_STACK_SIZE; if (blend_sp == blend_spill + BLEND_STACK_SIZE) { // spill to scratch buffer @@ -222,23 +231,13 @@ void main() { } blend_spill++; } - if (tag == Cmd_BeginClip) { - CmdBeginClip begin_clip = Cmd_BeginClip_read(cmd_alloc, cmd_ref); - area = computeArea(xy, begin_clip.backdrop, begin_clip.tile_ref); - for (uint k = 0; k < CHUNK; k++) { - blend_stack[blend_slot][k] = packsRGB(vec4(rgb[k], clamp(abs(area[k]), 0.0, 1.0))); - } - } else { - CmdBeginSolidClip begin_solid_clip = Cmd_BeginSolidClip_read(cmd_alloc, cmd_ref); - float solid_alpha = begin_solid_clip.alpha; - for (uint k = 0; k < CHUNK; k++) { - blend_stack[blend_slot][k] = packsRGB(vec4(rgb[k], solid_alpha)); - } + 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; break; case Cmd_EndClip: - CmdEndClip end_clip = Cmd_EndClip_read(cmd_alloc, cmd_ref); 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; @@ -251,29 +250,15 @@ void main() { blend_sp--; for (uint k = 0; k < CHUNK; k++) { vec4 rgba = unpacksRGB(blend_stack[blend_slot][k]); - rgb[k] = mix(rgba.rgb, rgb[k], end_clip.alpha * rgba.a); - } - break; - case Cmd_Solid: - CmdSolid solid = Cmd_Solid_read(cmd_alloc, cmd_ref); - fg_rgba = unpacksRGB(solid.rgba_color); - for (uint k = 0; k < CHUNK; k++) { - rgb[k] = mix(rgb[k], fg_rgba.rgb, mask[k] * fg_rgba.a); - } - break; - case Cmd_SolidImage: - CmdSolidImage solid_img = Cmd_SolidImage_read(cmd_alloc, cmd_ref); - rgba = fillImage(xy_uint, solid_img); - for (uint k = 0; k < CHUNK; k++) { - rgb[k] = mix(rgb[k], rgba[k].rgb, mask[k] * rgba[k].a); + rgb[k] = mix(rgba.rgb, rgb[k], area[k] * rgba.a); } + 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; } - cmd_ref.offset += Cmd_size; } for (uint i = 0; i < CHUNK; i++) { diff --git a/gpu/shaders/path_coarse.comp b/gpu/shaders/path_coarse.comp index 70251bfa..51264bf2 100644 --- a/gpu/shaders/path_coarse.comp +++ b/gpu/shaders/path_coarse.comp @@ -94,14 +94,13 @@ void main() { uint element_ix = gl_GlobalInvocationID.x; PathSegRef ref = PathSegRef(conf.pathseg_alloc.offset + element_ix * PathSeg_size); - uint tag = PathSeg_Nop; + PathSegTag tag = PathSegTag(PathSeg_Nop, 0); if (element_ix < conf.n_pathseg) { tag = PathSeg_tag(conf.pathseg_alloc, ref); } - switch (tag) { - case PathSeg_FillCubic: - case PathSeg_StrokeCubic: - PathStrokeCubic cubic = PathSeg_StrokeCubic_read(conf.pathseg_alloc, ref); + switch (tag.tag) { + case PathSeg_Cubic: + PathCubic cubic = PathSeg_Cubic_read(conf.pathseg_alloc, ref); uint trans_ix = cubic.trans_ix; if (trans_ix > 0) { @@ -133,6 +132,7 @@ void main() { } uint n = max(uint(ceil(val * 0.5 / sqrt(REM_ACCURACY))), 1); + bool is_stroke = fill_mode_from_flags(tag.flags) == MODE_STROKE; uint path_ix = cubic.path_ix; Path path = Path_read(conf.tile_alloc, PathRef(conf.tile_alloc.offset + path_ix * Path_size)); Alloc path_alloc = new_alloc(path.tiles.offset, (path.bbox.z - path.bbox.x) * (path.bbox.w - path.bbox.y) * Tile_size); @@ -212,7 +212,7 @@ void main() { for (int y = y0; y < y1; y++) { float tile_y0 = float(y * TILE_HEIGHT_PX); int xbackdrop = max(xray + 1, bbox.x); - if (tag == PathSeg_FillCubic && min(p0.y, p1.y) < tile_y0 && xbackdrop < bbox.z) { + if (!is_stroke && min(p0.y, p1.y) < tile_y0 && xbackdrop < bbox.z) { int backdrop = p1.y < p0.y ? 1 : -1; TileRef tile_ref = Tile_index(path.tiles, uint(base + xbackdrop)); uint tile_el = tile_ref.offset >> 2; @@ -248,7 +248,7 @@ void main() { tile_seg.origin = p0; tile_seg.vector = p1 - p0; float y_edge = 0.0; - if (tag == PathSeg_FillCubic) { + if (!is_stroke) { y_edge = mix(p0.y, p1.y, (tile_x0 - p0.x) / dx); if (min(p0.x, p1.x) < tile_x0) { vec2 p = vec2(tile_x0, y_edge); diff --git a/gpu/shaders/pathseg.h b/gpu/shaders/pathseg.h index 7c69b9dd..749771ea 100644 --- a/gpu/shaders/pathseg.h +++ b/gpu/shaders/pathseg.h @@ -2,11 +2,7 @@ // Code auto-generated by piet-gpu-derive -struct PathFillCubicRef { - uint offset; -}; - -struct PathStrokeCubicRef { +struct PathCubicRef { uint offset; }; @@ -14,22 +10,7 @@ struct PathSegRef { uint offset; }; -struct PathFillCubic { - vec2 p0; - vec2 p1; - vec2 p2; - vec2 p3; - uint path_ix; - uint trans_ix; -}; - -#define PathFillCubic_size 40 - -PathFillCubicRef PathFillCubic_index(PathFillCubicRef ref, uint index) { - return PathFillCubicRef(ref.offset + index * PathFillCubic_size); -} - -struct PathStrokeCubic { +struct PathCubic { vec2 p0; vec2 p1; vec2 p2; @@ -39,58 +20,26 @@ struct PathStrokeCubic { vec2 stroke; }; -#define PathStrokeCubic_size 48 +#define PathCubic_size 48 -PathStrokeCubicRef PathStrokeCubic_index(PathStrokeCubicRef ref, uint index) { - return PathStrokeCubicRef(ref.offset + index * PathStrokeCubic_size); +PathCubicRef PathCubic_index(PathCubicRef ref, uint index) { + return PathCubicRef(ref.offset + index * PathCubic_size); } #define PathSeg_Nop 0 -#define PathSeg_FillCubic 1 -#define PathSeg_StrokeCubic 2 +#define PathSeg_Cubic 1 #define PathSeg_size 52 PathSegRef PathSeg_index(PathSegRef ref, uint index) { return PathSegRef(ref.offset + index * PathSeg_size); } -PathFillCubic PathFillCubic_read(Alloc a, PathFillCubicRef ref) { - uint ix = ref.offset >> 2; - uint raw0 = read_mem(a, ix + 0); - uint raw1 = read_mem(a, ix + 1); - uint raw2 = read_mem(a, ix + 2); - uint raw3 = read_mem(a, ix + 3); - uint raw4 = read_mem(a, ix + 4); - uint raw5 = read_mem(a, ix + 5); - uint raw6 = read_mem(a, ix + 6); - uint raw7 = read_mem(a, ix + 7); - uint raw8 = read_mem(a, ix + 8); - uint raw9 = read_mem(a, ix + 9); - PathFillCubic s; - s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); - s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); - s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); - s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7)); - s.path_ix = raw8; - s.trans_ix = raw9; - return s; -} +struct PathSegTag { + uint tag; + uint flags; +}; -void PathFillCubic_write(Alloc a, PathFillCubicRef ref, PathFillCubic s) { - uint ix = ref.offset >> 2; - write_mem(a, ix + 0, floatBitsToUint(s.p0.x)); - write_mem(a, ix + 1, floatBitsToUint(s.p0.y)); - write_mem(a, ix + 2, floatBitsToUint(s.p1.x)); - write_mem(a, ix + 3, floatBitsToUint(s.p1.y)); - write_mem(a, ix + 4, floatBitsToUint(s.p2.x)); - write_mem(a, ix + 5, floatBitsToUint(s.p2.y)); - write_mem(a, ix + 6, floatBitsToUint(s.p3.x)); - write_mem(a, ix + 7, floatBitsToUint(s.p3.y)); - write_mem(a, ix + 8, s.path_ix); - write_mem(a, ix + 9, s.trans_ix); -} - -PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) { +PathCubic PathCubic_read(Alloc a, PathCubicRef ref) { uint ix = ref.offset >> 2; uint raw0 = read_mem(a, ix + 0); uint raw1 = read_mem(a, ix + 1); @@ -104,7 +53,7 @@ PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) { uint raw9 = read_mem(a, ix + 9); uint raw10 = read_mem(a, ix + 10); uint raw11 = read_mem(a, ix + 11); - PathStrokeCubic s; + PathCubic s; s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); @@ -115,7 +64,7 @@ PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) { return s; } -void PathStrokeCubic_write(Alloc a, PathStrokeCubicRef ref, PathStrokeCubic s) { +void PathCubic_write(Alloc a, PathCubicRef ref, PathCubic s) { uint ix = ref.offset >> 2; write_mem(a, ix + 0, floatBitsToUint(s.p0.x)); write_mem(a, ix + 1, floatBitsToUint(s.p0.y)); @@ -131,29 +80,21 @@ void PathStrokeCubic_write(Alloc a, PathStrokeCubicRef ref, PathStrokeCubic s) { write_mem(a, ix + 11, floatBitsToUint(s.stroke.y)); } -uint PathSeg_tag(Alloc a, PathSegRef ref) { - return read_mem(a, ref.offset >> 2); +PathSegTag PathSeg_tag(Alloc a, PathSegRef ref) { + uint tag_and_flags = read_mem(a, ref.offset >> 2); + return PathSegTag(tag_and_flags & 0xffff, tag_and_flags >> 16); } -PathFillCubic PathSeg_FillCubic_read(Alloc a, PathSegRef ref) { - return PathFillCubic_read(a, PathFillCubicRef(ref.offset + 4)); -} - -PathStrokeCubic PathSeg_StrokeCubic_read(Alloc a, PathSegRef ref) { - return PathStrokeCubic_read(a, PathStrokeCubicRef(ref.offset + 4)); +PathCubic PathSeg_Cubic_read(Alloc a, PathSegRef ref) { + return PathCubic_read(a, PathCubicRef(ref.offset + 4)); } void PathSeg_Nop_write(Alloc a, PathSegRef ref) { write_mem(a, ref.offset >> 2, PathSeg_Nop); } -void PathSeg_FillCubic_write(Alloc a, PathSegRef ref, PathFillCubic s) { - write_mem(a, ref.offset >> 2, PathSeg_FillCubic); - PathFillCubic_write(a, PathFillCubicRef(ref.offset + 4), s); -} - -void PathSeg_StrokeCubic_write(Alloc a, PathSegRef ref, PathStrokeCubic s) { - write_mem(a, ref.offset >> 2, PathSeg_StrokeCubic); - PathStrokeCubic_write(a, PathStrokeCubicRef(ref.offset + 4), s); +void PathSeg_Cubic_write(Alloc a, PathSegRef ref, uint flags, PathCubic s) { + write_mem(a, ref.offset >> 2, (flags << 16) | PathSeg_Cubic); + PathCubic_write(a, PathCubicRef(ref.offset + 4), s); } diff --git a/gpu/shaders/ptcl.h b/gpu/shaders/ptcl.h index 53b98506..6267fc53 100644 --- a/gpu/shaders/ptcl.h +++ b/gpu/shaders/ptcl.h @@ -10,27 +10,15 @@ struct CmdFillRef { uint offset; }; -struct CmdFillImageRef { +struct CmdColorRef { uint offset; }; -struct CmdBeginClipRef { +struct CmdImageRef { uint offset; }; -struct CmdBeginSolidClipRef { - uint offset; -}; - -struct CmdEndClipRef { - uint offset; -}; - -struct CmdSolidRef { - uint offset; -}; - -struct CmdSolidImageRef { +struct CmdAlphaRef { uint offset; }; @@ -45,10 +33,9 @@ struct CmdRef { struct CmdStroke { uint tile_ref; float half_width; - uint rgba_color; }; -#define CmdStroke_size 12 +#define CmdStroke_size 8 CmdStrokeRef CmdStroke_index(CmdStrokeRef ref, uint index) { return CmdStrokeRef(ref.offset + index * CmdStroke_size); @@ -57,78 +44,43 @@ CmdStrokeRef CmdStroke_index(CmdStrokeRef ref, uint index) { struct CmdFill { uint tile_ref; int backdrop; - uint rgba_color; }; -#define CmdFill_size 12 +#define CmdFill_size 8 CmdFillRef CmdFill_index(CmdFillRef ref, uint index) { return CmdFillRef(ref.offset + index * CmdFill_size); } -struct CmdFillImage { - uint tile_ref; - int backdrop; - uint index; - ivec2 offset; -}; - -#define CmdFillImage_size 16 - -CmdFillImageRef CmdFillImage_index(CmdFillImageRef ref, uint index) { - return CmdFillImageRef(ref.offset + index * CmdFillImage_size); -} - -struct CmdBeginClip { - uint tile_ref; - int backdrop; -}; - -#define CmdBeginClip_size 8 - -CmdBeginClipRef CmdBeginClip_index(CmdBeginClipRef ref, uint index) { - return CmdBeginClipRef(ref.offset + index * CmdBeginClip_size); -} - -struct CmdBeginSolidClip { - float alpha; -}; - -#define CmdBeginSolidClip_size 4 - -CmdBeginSolidClipRef CmdBeginSolidClip_index(CmdBeginSolidClipRef ref, uint index) { - return CmdBeginSolidClipRef(ref.offset + index * CmdBeginSolidClip_size); -} - -struct CmdEndClip { - float alpha; -}; - -#define CmdEndClip_size 4 - -CmdEndClipRef CmdEndClip_index(CmdEndClipRef ref, uint index) { - return CmdEndClipRef(ref.offset + index * CmdEndClip_size); -} - -struct CmdSolid { +struct CmdColor { uint rgba_color; }; -#define CmdSolid_size 4 +#define CmdColor_size 4 -CmdSolidRef CmdSolid_index(CmdSolidRef ref, uint index) { - return CmdSolidRef(ref.offset + index * CmdSolid_size); +CmdColorRef CmdColor_index(CmdColorRef ref, uint index) { + return CmdColorRef(ref.offset + index * CmdColor_size); } -struct CmdSolidImage { +struct CmdImage { uint index; ivec2 offset; }; -#define CmdSolidImage_size 8 +#define CmdImage_size 8 -CmdSolidImageRef CmdSolidImage_index(CmdSolidImageRef ref, uint index) { - return CmdSolidImageRef(ref.offset + index * CmdSolidImage_size); +CmdImageRef CmdImage_index(CmdImageRef ref, uint index) { + return CmdImageRef(ref.offset + index * CmdImage_size); +} + +struct CmdAlpha { + float alpha; +}; + +#define CmdAlpha_size 4 + +CmdAlphaRef CmdAlpha_index(CmdAlphaRef ref, uint index) { + return CmdAlphaRef(ref.offset + index * CmdAlpha_size); } struct CmdJump { @@ -143,29 +95,32 @@ CmdJumpRef CmdJump_index(CmdJumpRef ref, uint index) { #define Cmd_End 0 #define Cmd_Fill 1 -#define Cmd_FillImage 2 -#define Cmd_BeginClip 3 -#define Cmd_BeginSolidClip 4 -#define Cmd_EndClip 5 -#define Cmd_Stroke 6 -#define Cmd_Solid 7 -#define Cmd_SolidImage 8 +#define Cmd_Stroke 2 +#define Cmd_Solid 3 +#define Cmd_Alpha 4 +#define Cmd_Color 5 +#define Cmd_Image 6 +#define Cmd_BeginClip 7 +#define Cmd_EndClip 8 #define Cmd_Jump 9 -#define Cmd_size 20 +#define Cmd_size 12 CmdRef Cmd_index(CmdRef ref, uint index) { return CmdRef(ref.offset + index * Cmd_size); } +struct CmdTag { + uint tag; + uint flags; +}; + CmdStroke CmdStroke_read(Alloc a, CmdStrokeRef ref) { uint ix = ref.offset >> 2; uint raw0 = read_mem(a, ix + 0); uint raw1 = read_mem(a, ix + 1); - uint raw2 = read_mem(a, ix + 2); CmdStroke s; s.tile_ref = raw0; s.half_width = uintBitsToFloat(raw1); - s.rgba_color = raw2; return s; } @@ -173,18 +128,15 @@ void CmdStroke_write(Alloc a, CmdStrokeRef ref, CmdStroke s) { uint ix = ref.offset >> 2; write_mem(a, ix + 0, s.tile_ref); write_mem(a, ix + 1, floatBitsToUint(s.half_width)); - write_mem(a, ix + 2, s.rgba_color); } CmdFill CmdFill_read(Alloc a, CmdFillRef ref) { uint ix = ref.offset >> 2; uint raw0 = read_mem(a, ix + 0); uint raw1 = read_mem(a, ix + 1); - uint raw2 = read_mem(a, ix + 2); CmdFill s; s.tile_ref = raw0; s.backdrop = int(raw1); - s.rgba_color = raw2; return s; } @@ -192,102 +144,50 @@ void CmdFill_write(Alloc a, CmdFillRef ref, CmdFill s) { uint ix = ref.offset >> 2; write_mem(a, ix + 0, s.tile_ref); write_mem(a, ix + 1, uint(s.backdrop)); - write_mem(a, ix + 2, s.rgba_color); } -CmdFillImage CmdFillImage_read(Alloc a, CmdFillImageRef ref) { +CmdColor CmdColor_read(Alloc a, CmdColorRef ref) { uint ix = ref.offset >> 2; uint raw0 = read_mem(a, ix + 0); - uint raw1 = read_mem(a, ix + 1); - uint raw2 = read_mem(a, ix + 2); - uint raw3 = read_mem(a, ix + 3); - CmdFillImage s; - s.tile_ref = raw0; - s.backdrop = int(raw1); - s.index = raw2; - s.offset = ivec2(int(raw3 << 16) >> 16, int(raw3) >> 16); - return s; -} - -void CmdFillImage_write(Alloc a, CmdFillImageRef ref, CmdFillImage s) { - uint ix = ref.offset >> 2; - write_mem(a, ix + 0, s.tile_ref); - write_mem(a, ix + 1, uint(s.backdrop)); - write_mem(a, ix + 2, s.index); - write_mem(a, ix + 3, (uint(s.offset.x) & 0xffff) | (uint(s.offset.y) << 16)); -} - -CmdBeginClip CmdBeginClip_read(Alloc a, CmdBeginClipRef ref) { - uint ix = ref.offset >> 2; - uint raw0 = read_mem(a, ix + 0); - uint raw1 = read_mem(a, ix + 1); - CmdBeginClip s; - s.tile_ref = raw0; - s.backdrop = int(raw1); - return s; -} - -void CmdBeginClip_write(Alloc a, CmdBeginClipRef ref, CmdBeginClip s) { - uint ix = ref.offset >> 2; - write_mem(a, ix + 0, s.tile_ref); - write_mem(a, ix + 1, uint(s.backdrop)); -} - -CmdBeginSolidClip CmdBeginSolidClip_read(Alloc a, CmdBeginSolidClipRef ref) { - uint ix = ref.offset >> 2; - uint raw0 = read_mem(a, ix + 0); - CmdBeginSolidClip s; - s.alpha = uintBitsToFloat(raw0); - return s; -} - -void CmdBeginSolidClip_write(Alloc a, CmdBeginSolidClipRef ref, CmdBeginSolidClip s) { - uint ix = ref.offset >> 2; - write_mem(a, ix + 0, floatBitsToUint(s.alpha)); -} - -CmdEndClip CmdEndClip_read(Alloc a, CmdEndClipRef ref) { - uint ix = ref.offset >> 2; - uint raw0 = read_mem(a, ix + 0); - CmdEndClip s; - s.alpha = uintBitsToFloat(raw0); - return s; -} - -void CmdEndClip_write(Alloc a, CmdEndClipRef ref, CmdEndClip s) { - uint ix = ref.offset >> 2; - write_mem(a, ix + 0, floatBitsToUint(s.alpha)); -} - -CmdSolid CmdSolid_read(Alloc a, CmdSolidRef ref) { - uint ix = ref.offset >> 2; - uint raw0 = read_mem(a, ix + 0); - CmdSolid s; + CmdColor s; s.rgba_color = raw0; return s; } -void CmdSolid_write(Alloc a, CmdSolidRef ref, CmdSolid s) { +void CmdColor_write(Alloc a, CmdColorRef ref, CmdColor s) { uint ix = ref.offset >> 2; write_mem(a, ix + 0, s.rgba_color); } -CmdSolidImage CmdSolidImage_read(Alloc a, CmdSolidImageRef ref) { +CmdImage CmdImage_read(Alloc a, CmdImageRef ref) { uint ix = ref.offset >> 2; uint raw0 = read_mem(a, ix + 0); uint raw1 = read_mem(a, ix + 1); - CmdSolidImage s; + CmdImage s; s.index = raw0; s.offset = ivec2(int(raw1 << 16) >> 16, int(raw1) >> 16); return s; } -void CmdSolidImage_write(Alloc a, CmdSolidImageRef ref, CmdSolidImage s) { +void CmdImage_write(Alloc a, CmdImageRef ref, CmdImage s) { uint ix = ref.offset >> 2; write_mem(a, ix + 0, s.index); write_mem(a, ix + 1, (uint(s.offset.x) & 0xffff) | (uint(s.offset.y) << 16)); } +CmdAlpha CmdAlpha_read(Alloc a, CmdAlphaRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = read_mem(a, ix + 0); + CmdAlpha s; + s.alpha = uintBitsToFloat(raw0); + return s; +} + +void CmdAlpha_write(Alloc a, CmdAlphaRef ref, CmdAlpha s) { + uint ix = ref.offset >> 2; + write_mem(a, ix + 0, floatBitsToUint(s.alpha)); +} + CmdJump CmdJump_read(Alloc a, CmdJumpRef ref) { uint ix = ref.offset >> 2; uint raw0 = read_mem(a, ix + 0); @@ -301,40 +201,29 @@ void CmdJump_write(Alloc a, CmdJumpRef ref, CmdJump s) { write_mem(a, ix + 0, s.new_ref); } -uint Cmd_tag(Alloc a, CmdRef ref) { - return read_mem(a, ref.offset >> 2); +CmdTag Cmd_tag(Alloc a, CmdRef ref) { + uint tag_and_flags = read_mem(a, ref.offset >> 2); + return CmdTag(tag_and_flags & 0xffff, tag_and_flags >> 16); } CmdFill Cmd_Fill_read(Alloc a, CmdRef ref) { return CmdFill_read(a, CmdFillRef(ref.offset + 4)); } -CmdFillImage Cmd_FillImage_read(Alloc a, CmdRef ref) { - return CmdFillImage_read(a, CmdFillImageRef(ref.offset + 4)); -} - -CmdBeginClip Cmd_BeginClip_read(Alloc a, CmdRef ref) { - return CmdBeginClip_read(a, CmdBeginClipRef(ref.offset + 4)); -} - -CmdBeginSolidClip Cmd_BeginSolidClip_read(Alloc a, CmdRef ref) { - return CmdBeginSolidClip_read(a, CmdBeginSolidClipRef(ref.offset + 4)); -} - -CmdEndClip Cmd_EndClip_read(Alloc a, CmdRef ref) { - return CmdEndClip_read(a, CmdEndClipRef(ref.offset + 4)); -} - CmdStroke Cmd_Stroke_read(Alloc a, CmdRef ref) { return CmdStroke_read(a, CmdStrokeRef(ref.offset + 4)); } -CmdSolid Cmd_Solid_read(Alloc a, CmdRef ref) { - return CmdSolid_read(a, CmdSolidRef(ref.offset + 4)); +CmdAlpha Cmd_Alpha_read(Alloc a, CmdRef ref) { + return CmdAlpha_read(a, CmdAlphaRef(ref.offset + 4)); } -CmdSolidImage Cmd_SolidImage_read(Alloc a, CmdRef ref) { - return CmdSolidImage_read(a, CmdSolidImageRef(ref.offset + 4)); +CmdColor Cmd_Color_read(Alloc a, CmdRef ref) { + return CmdColor_read(a, CmdColorRef(ref.offset + 4)); +} + +CmdImage Cmd_Image_read(Alloc a, CmdRef ref) { + return CmdImage_read(a, CmdImageRef(ref.offset + 4)); } CmdJump Cmd_Jump_read(Alloc a, CmdRef ref) { @@ -350,39 +239,36 @@ void Cmd_Fill_write(Alloc a, CmdRef ref, CmdFill s) { CmdFill_write(a, CmdFillRef(ref.offset + 4), s); } -void Cmd_FillImage_write(Alloc a, CmdRef ref, CmdFillImage s) { - write_mem(a, ref.offset >> 2, Cmd_FillImage); - CmdFillImage_write(a, CmdFillImageRef(ref.offset + 4), s); -} - -void Cmd_BeginClip_write(Alloc a, CmdRef ref, CmdBeginClip s) { - write_mem(a, ref.offset >> 2, Cmd_BeginClip); - CmdBeginClip_write(a, CmdBeginClipRef(ref.offset + 4), s); -} - -void Cmd_BeginSolidClip_write(Alloc a, CmdRef ref, CmdBeginSolidClip s) { - write_mem(a, ref.offset >> 2, Cmd_BeginSolidClip); - CmdBeginSolidClip_write(a, CmdBeginSolidClipRef(ref.offset + 4), s); -} - -void Cmd_EndClip_write(Alloc a, CmdRef ref, CmdEndClip s) { - write_mem(a, ref.offset >> 2, Cmd_EndClip); - CmdEndClip_write(a, CmdEndClipRef(ref.offset + 4), s); -} - void Cmd_Stroke_write(Alloc a, CmdRef ref, CmdStroke s) { write_mem(a, ref.offset >> 2, Cmd_Stroke); CmdStroke_write(a, CmdStrokeRef(ref.offset + 4), s); } -void Cmd_Solid_write(Alloc a, CmdRef ref, CmdSolid s) { +void Cmd_Solid_write(Alloc a, CmdRef ref) { write_mem(a, ref.offset >> 2, Cmd_Solid); - CmdSolid_write(a, CmdSolidRef(ref.offset + 4), s); } -void Cmd_SolidImage_write(Alloc a, CmdRef ref, CmdSolidImage s) { - write_mem(a, ref.offset >> 2, Cmd_SolidImage); - CmdSolidImage_write(a, CmdSolidImageRef(ref.offset + 4), s); +void Cmd_Alpha_write(Alloc a, CmdRef ref, CmdAlpha s) { + write_mem(a, ref.offset >> 2, Cmd_Alpha); + CmdAlpha_write(a, CmdAlphaRef(ref.offset + 4), s); +} + +void Cmd_Color_write(Alloc a, CmdRef ref, CmdColor s) { + write_mem(a, ref.offset >> 2, Cmd_Color); + CmdColor_write(a, CmdColorRef(ref.offset + 4), s); +} + +void Cmd_Image_write(Alloc a, CmdRef ref, CmdImage s) { + write_mem(a, ref.offset >> 2, Cmd_Image); + CmdImage_write(a, CmdImageRef(ref.offset + 4), s); +} + +void Cmd_BeginClip_write(Alloc a, CmdRef ref) { + write_mem(a, ref.offset >> 2, Cmd_BeginClip); +} + +void Cmd_EndClip_write(Alloc a, CmdRef ref) { + write_mem(a, ref.offset >> 2, Cmd_EndClip); } void Cmd_Jump_write(Alloc a, CmdRef ref, CmdJump s) { diff --git a/gpu/shaders/scene.h b/gpu/shaders/scene.h index e6ea591e..38c2549d 100644 --- a/gpu/shaders/scene.h +++ b/gpu/shaders/scene.h @@ -14,7 +14,7 @@ struct CubicSegRef { uint offset; }; -struct FillRef { +struct FillColorRef { uint offset; }; @@ -22,10 +22,6 @@ struct FillImageRef { uint offset; }; -struct StrokeRef { - uint offset; -}; - struct SetLineWidthRef { uint offset; }; @@ -38,6 +34,10 @@ struct ClipRef { uint offset; }; +struct SetFillModeRef { + uint offset; +}; + struct ElementRef { uint offset; }; @@ -78,14 +78,14 @@ CubicSegRef CubicSeg_index(CubicSegRef ref, uint index) { return CubicSegRef(ref.offset + index * CubicSeg_size); } -struct Fill { +struct FillColor { uint rgba_color; }; -#define Fill_size 4 +#define FillColor_size 4 -FillRef Fill_index(FillRef ref, uint index) { - return FillRef(ref.offset + index * Fill_size); +FillColorRef FillColor_index(FillColorRef ref, uint index) { + return FillColorRef(ref.offset + index * FillColor_size); } struct FillImage { @@ -99,16 +99,6 @@ FillImageRef FillImage_index(FillImageRef ref, uint index) { return FillImageRef(ref.offset + index * FillImage_size); } -struct Stroke { - uint rgba_color; -}; - -#define Stroke_size 4 - -StrokeRef Stroke_index(StrokeRef ref, uint index) { - return StrokeRef(ref.offset + index * Stroke_size); -} - struct SetLineWidth { float width; }; @@ -140,26 +130,38 @@ ClipRef Clip_index(ClipRef ref, uint index) { return ClipRef(ref.offset + index * Clip_size); } +struct SetFillMode { + uint fill_mode; +}; + +#define SetFillMode_size 4 + +SetFillModeRef SetFillMode_index(SetFillModeRef ref, uint index) { + return SetFillModeRef(ref.offset + index * SetFillMode_size); +} + #define Element_Nop 0 -#define Element_StrokeLine 1 -#define Element_FillLine 2 -#define Element_StrokeQuad 3 -#define Element_FillQuad 4 -#define Element_StrokeCubic 5 -#define Element_FillCubic 6 -#define Element_Stroke 7 -#define Element_Fill 8 -#define Element_SetLineWidth 9 -#define Element_Transform 10 -#define Element_BeginClip 11 -#define Element_EndClip 12 -#define Element_FillImage 13 +#define Element_Line 1 +#define Element_Quad 2 +#define Element_Cubic 3 +#define Element_FillColor 4 +#define Element_SetLineWidth 5 +#define Element_Transform 6 +#define Element_BeginClip 7 +#define Element_EndClip 8 +#define Element_FillImage 9 +#define Element_SetFillMode 10 #define Element_size 36 ElementRef Element_index(ElementRef ref, uint index) { return ElementRef(ref.offset + index * Element_size); } +struct ElementTag { + uint tag; + uint flags; +}; + LineSeg LineSeg_read(LineSegRef ref) { uint ix = ref.offset >> 2; uint raw0 = scene[ix + 0]; @@ -205,10 +207,10 @@ CubicSeg CubicSeg_read(CubicSegRef ref) { return s; } -Fill Fill_read(FillRef ref) { +FillColor FillColor_read(FillColorRef ref) { uint ix = ref.offset >> 2; uint raw0 = scene[ix + 0]; - Fill s; + FillColor s; s.rgba_color = raw0; return s; } @@ -223,14 +225,6 @@ FillImage FillImage_read(FillImageRef ref) { return s; } -Stroke Stroke_read(StrokeRef ref) { - uint ix = ref.offset >> 2; - uint raw0 = scene[ix + 0]; - Stroke s; - s.rgba_color = raw0; - return s; -} - SetLineWidth SetLineWidth_read(SetLineWidthRef ref) { uint ix = ref.offset >> 2; uint raw0 = scene[ix + 0]; @@ -264,40 +258,33 @@ Clip Clip_read(ClipRef ref) { return s; } -uint Element_tag(ElementRef ref) { - return scene[ref.offset >> 2]; +SetFillMode SetFillMode_read(SetFillModeRef ref) { + uint ix = ref.offset >> 2; + uint raw0 = scene[ix + 0]; + SetFillMode s; + s.fill_mode = raw0; + return s; } -LineSeg Element_StrokeLine_read(ElementRef ref) { +ElementTag Element_tag(ElementRef ref) { + uint tag_and_flags = scene[ref.offset >> 2]; + return ElementTag(tag_and_flags & 0xffff, tag_and_flags >> 16); +} + +LineSeg Element_Line_read(ElementRef ref) { return LineSeg_read(LineSegRef(ref.offset + 4)); } -LineSeg Element_FillLine_read(ElementRef ref) { - return LineSeg_read(LineSegRef(ref.offset + 4)); -} - -QuadSeg Element_StrokeQuad_read(ElementRef ref) { +QuadSeg Element_Quad_read(ElementRef ref) { return QuadSeg_read(QuadSegRef(ref.offset + 4)); } -QuadSeg Element_FillQuad_read(ElementRef ref) { - return QuadSeg_read(QuadSegRef(ref.offset + 4)); -} - -CubicSeg Element_StrokeCubic_read(ElementRef ref) { +CubicSeg Element_Cubic_read(ElementRef ref) { return CubicSeg_read(CubicSegRef(ref.offset + 4)); } -CubicSeg Element_FillCubic_read(ElementRef ref) { - return CubicSeg_read(CubicSegRef(ref.offset + 4)); -} - -Stroke Element_Stroke_read(ElementRef ref) { - return Stroke_read(StrokeRef(ref.offset + 4)); -} - -Fill Element_Fill_read(ElementRef ref) { - return Fill_read(FillRef(ref.offset + 4)); +FillColor Element_FillColor_read(ElementRef ref) { + return FillColor_read(FillColorRef(ref.offset + 4)); } SetLineWidth Element_SetLineWidth_read(ElementRef ref) { @@ -320,3 +307,7 @@ FillImage Element_FillImage_read(ElementRef ref) { return FillImage_read(FillImageRef(ref.offset + 4)); } +SetFillMode Element_SetFillMode_read(ElementRef ref) { + return SetFillMode_read(SetFillModeRef(ref.offset + 4)); +} + diff --git a/gpu/shaders/setup.h b/gpu/shaders/setup.h index 5d952c7e..5f76cbc7 100644 --- a/gpu/shaders/setup.h +++ b/gpu/shaders/setup.h @@ -37,3 +37,12 @@ struct Config { Alloc anno_alloc; Alloc trans_alloc; }; + +// Fill modes. +#define MODE_NONZERO 0 +#define MODE_STROKE 1 + +// fill_mode_from_flags extracts the fill mode from tag flags. +uint fill_mode_from_flags(uint flags) { + return flags & 0x1; +} diff --git a/gpu/shaders/tile_alloc.comp b/gpu/shaders/tile_alloc.comp index 896bb226..3a6e4eef 100644 --- a/gpu/shaders/tile_alloc.comp +++ b/gpu/shaders/tile_alloc.comp @@ -39,22 +39,21 @@ void main() { uint tag = Annotated_Nop; if (element_ix < conf.n_elements) { - tag = Annotated_tag(conf.anno_alloc, ref); + tag = Annotated_tag(conf.anno_alloc, ref).tag; } int x0 = 0, y0 = 0, x1 = 0, y1 = 0; switch (tag) { - case Annotated_Fill: - case Annotated_FillImage: - case Annotated_Stroke: + case Annotated_Color: + case Annotated_Image: case Annotated_BeginClip: case Annotated_EndClip: // Note: we take advantage of the fact that fills, strokes, and // clips have compatible layout. - AnnoFill fill = Annotated_Fill_read(conf.anno_alloc, ref); - x0 = int(floor(fill.bbox.x * SX)); - y0 = int(floor(fill.bbox.y * SY)); - x1 = int(ceil(fill.bbox.z * SX)); - y1 = int(ceil(fill.bbox.w * SY)); + AnnoEndClip clip = Annotated_EndClip_read(conf.anno_alloc, ref); + x0 = int(floor(clip.bbox.x * SX)); + y0 = int(floor(clip.bbox.y * SY)); + x1 = int(ceil(clip.bbox.z * SX)); + y1 = int(ceil(clip.bbox.w * SY)); break; } x0 = clamp(x0, 0, int(conf.width_in_tiles)); diff --git a/internal/scene/scene.go b/internal/scene/scene.go index 6c88d021..ab2a5faf 100644 --- a/internal/scene/scene.go +++ b/internal/scene/scene.go @@ -16,39 +16,40 @@ type Op uint32 type Command [sceneElemSize / 4]uint32 -const sceneElemSize = 36 - // GPU commands from scene.h const ( OpNop Op = iota - OpStrokeLine - OpFillLine - OpStrokeQuad - OpFillQuad - OpStrokeCubic - OpFillCubic - OpStroke - OpFill + OpLine + OpQuad + OpCubic + OpFillColor OpLineWidth OpTransform OpBeginClip OpEndClip OpFillImage + OpSetFillMode +) + +// FillModes, from setup.h. +type FillMode uint32 + +const ( + FillModeNonzero = 0 + FillModeStroke = 1 ) const CommandSize = int(unsafe.Sizeof(Command{})) +const sceneElemSize = 36 + func (c Command) Op() Op { return Op(c[0]) } -func Line(start, end f32.Point, stroke bool) Command { - tag := uint32(OpFillLine) - if stroke { - tag = uint32(OpStrokeLine) - } +func Line(start, end f32.Point) Command { return Command{ - 0: tag, + 0: uint32(OpLine), 1: math.Float32bits(start.X), 2: math.Float32bits(start.Y), 3: math.Float32bits(end.X), @@ -56,13 +57,9 @@ func Line(start, end f32.Point, stroke bool) Command { } } -func Cubic(start, ctrl0, ctrl1, end f32.Point, stroke bool) Command { - tag := uint32(OpFillCubic) - if stroke { - tag = uint32(OpStrokeCubic) - } +func Cubic(start, ctrl0, ctrl1, end f32.Point) Command { return Command{ - 0: tag, + 0: uint32(OpCubic), 1: math.Float32bits(start.X), 2: math.Float32bits(start.Y), 3: math.Float32bits(ctrl0.X), @@ -74,13 +71,9 @@ func Cubic(start, ctrl0, ctrl1, end f32.Point, stroke bool) Command { } } -func Quad(start, ctrl, end f32.Point, stroke bool) Command { - tag := uint32(OpFillQuad) - if stroke { - tag = uint32(OpStrokeQuad) - } +func Quad(start, ctrl, end f32.Point) Command { return Command{ - 0: tag, + 0: uint32(OpQuad), 1: math.Float32bits(start.X), 2: math.Float32bits(start.Y), 3: math.Float32bits(ctrl.X), @@ -103,20 +96,13 @@ func Transform(m f32.Affine2D) Command { } } -func LineWidth(width float32) Command { +func SetLineWidth(width float32) Command { return Command{ 0: uint32(OpLineWidth), 1: math.Float32bits(width), } } -func Stroke(col color.RGBA) Command { - return Command{ - 0: uint32(OpStroke), - 1: uint32(col.R)<<24 | uint32(col.G)<<16 | uint32(col.B)<<8 | uint32(col.A), - } -} - func BeginClip(bbox f32.Rectangle) Command { return Command{ 0: uint32(OpBeginClip), @@ -137,9 +123,9 @@ func EndClip(bbox f32.Rectangle) Command { } } -func Fill(col color.RGBA) Command { +func FillColor(col color.RGBA) Command { return Command{ - 0: uint32(OpFill), + 0: uint32(OpFillColor), 1: uint32(col.R)<<24 | uint32(col.G)<<16 | uint32(col.B)<<8 | uint32(col.A), } } @@ -151,8 +137,15 @@ func FillImage(index int) Command { } } +func SetFillMode(mode FillMode) Command { + return Command{ + 0: uint32(OpSetFillMode), + 1: uint32(mode), + } +} + func DecodeLine(cmd Command) (from, to f32.Point) { - if cmd[0] != uint32(OpFillLine) { + if cmd[0] != uint32(OpLine) { panic("invalid command") } from = f32.Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2])) @@ -161,7 +154,7 @@ func DecodeLine(cmd Command) (from, to f32.Point) { } func DecodeQuad(cmd Command) (from, ctrl, to f32.Point) { - if cmd[0] != uint32(OpFillQuad) { + if cmd[0] != uint32(OpQuad) { panic("invalid command") } from = f32.Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2])) @@ -171,7 +164,7 @@ func DecodeQuad(cmd Command) (from, ctrl, to f32.Point) { } func DecodeCubic(cmd Command) (from, ctrl0, ctrl1, to f32.Point) { - if cmd[0] != uint32(OpFillCubic) { + if cmd[0] != uint32(OpCubic) { panic("invalid command") } from = f32.Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2])) diff --git a/op/clip/clip.go b/op/clip/clip.go index 57a65890..aa7f24f2 100644 --- a/op/clip/clip.go +++ b/op/clip/clip.go @@ -141,7 +141,7 @@ func (p *Path) LineTo(to f32.Point) { data := p.ops.Write(scene.CommandSize + 4) bo := binary.LittleEndian bo.PutUint32(data[0:], uint32(p.contour)) - ops.EncodeCommand(data[4:], scene.Line(p.pen, to, false)) + ops.EncodeCommand(data[4:], scene.Line(p.pen, to)) p.pen = to p.hasSegments = true } @@ -160,7 +160,7 @@ func (p *Path) QuadTo(ctrl, to f32.Point) { data := p.ops.Write(scene.CommandSize + 4) bo := binary.LittleEndian bo.PutUint32(data[0:], uint32(p.contour)) - ops.EncodeCommand(data[4:], scene.Quad(p.pen, ctrl, to, false)) + ops.EncodeCommand(data[4:], scene.Quad(p.pen, ctrl, to)) p.pen = to p.hasSegments = true } @@ -306,7 +306,7 @@ func (p *Path) CubeTo(ctrl0, ctrl1, to f32.Point) { data := p.ops.Write(scene.CommandSize + 4) bo := binary.LittleEndian bo.PutUint32(data[0:], uint32(p.contour)) - ops.EncodeCommand(data[4:], scene.Cubic(p.pen, ctrl0, ctrl1, to, false)) + ops.EncodeCommand(data[4:], scene.Cubic(p.pen, ctrl0, ctrl1, to)) p.pen = to p.hasSegments = true }