diff --git a/gpu/compute.go b/gpu/compute.go index ab7e9e51..bf06db4b 100644 --- a/gpu/compute.go +++ b/gpu/compute.go @@ -153,9 +153,9 @@ const ( pathSize = 12 binSize = 8 - pathsegSize = 48 + pathsegSize = 44 annoSize = 28 - stateSize = 56 + stateSize = 60 stateStride = 4 + 2*stateSize sceneElemSize = 36 ) @@ -178,6 +178,10 @@ const ( elemFillImage ) +const ( + flagEndPath = 16 // FLAG_END_PATH from elements.comp +) + // mem.h constants. const ( memNoError = 0 // NO_ERROR @@ -647,6 +651,10 @@ func (g *compute) encodeClipStack(clip, bounds f32.Rectangle, p *pathOp) int { // renderer. func encodePath(p []byte) encoder { var enc encoder + var ( + prevTo f32.Point + hasPrev bool + ) for len(p) > 0 { // p contains quadratic curves encoded in vertex structs. vertex := p[:vertStride] @@ -663,12 +671,20 @@ func encodePath(p []byte) encoder { math.Float32frombits(bo.Uint32(vertex[24:])), math.Float32frombits(bo.Uint32(vertex[28:])), ) + if hasPrev && from != prevTo { + enc.scene[len(enc.scene)-1][0] = (flagEndPath << 16) | enc.scene[len(enc.scene)-1][0] + } + hasPrev = true + prevTo = to enc.quad(from, ctrl, to, false) // The vertex is duplicated 4 times, one for each corner of quads drawn // by the old renderer. p = p[vertStride*4:] } + if hasPrev { + enc.scene[len(enc.scene)-1][0] = (flagEndPath << 16) | enc.scene[len(enc.scene)-1][0] + } return enc } @@ -1018,10 +1034,10 @@ func (e *encoder) endClip(bbox f32.Rectangle) { func (e *encoder) rect(r f32.Rectangle, stroke bool) { // 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, stroke, 0) + e.line(c1, c2, stroke, 0) + e.line(c2, c3, stroke, 0) + e.line(c3, c0, stroke, flagEndPath) } func (e *encoder) fill(col color.RGBA) { @@ -1043,13 +1059,13 @@ func (e *encoder) fillImage(index int, offset image.Point) { e.npath++ } -func (e *encoder) line(start, end f32.Point, stroke bool) { +func (e *encoder) line(start, end f32.Point, stroke bool, flags uint32) { tag := uint32(elemFillLine) if stroke { tag = elemStrokeLine } e.scene = append(e.scene, sceneElem{ - 0: tag, + 0: flags<<16 | tag, 1: math.Float32bits(start.X), 2: math.Float32bits(start.Y), 3: math.Float32bits(end.X), diff --git a/gpu/shaders.go b/gpu/shaders.go index 7e0c8383..2ffa70ed 100644 --- a/gpu/shaders.go +++ b/gpu/shaders.go @@ -605,7 +605,7 @@ var ( } shader_elements_comp = backend.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};\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 vec2 stroke;\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};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _282;\n\nlayout(binding = 2, std430) readonly buffer SceneBuf\n{\n uint scene[];\n} _306;\n\nlayout(binding = 3, std430) coherent buffer StateBuf\n{\n uint part_counter;\n uint state[];\n} _780;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _2430;\n\nshared uint sh_part_ix;\nshared vec4 sh_mat[32];\nshared vec2 sh_translate[32];\nshared vec4 sh_bbox[32];\nshared float sh_width[32];\nshared uint sh_flags[32];\nshared uint sh_path_count[32];\nshared uint sh_pathseg_count[32];\nshared State sh_prefix;\n\nuint Element_tag(ElementRef ref)\n{\n return _306.scene[ref.offset >> uint(2)];\n}\n\nLineSeg LineSeg_read(LineSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _306.scene[ix + 0u];\n uint raw1 = _306.scene[ix + 1u];\n uint raw2 = _306.scene[ix + 2u];\n uint raw3 = _306.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 = _306.scene[ix + 0u];\n uint raw1 = _306.scene[ix + 1u];\n uint raw2 = _306.scene[ix + 2u];\n uint raw3 = _306.scene[ix + 3u];\n uint raw4 = _306.scene[ix + 4u];\n uint raw5 = _306.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 = _306.scene[ix + 0u];\n uint raw1 = _306.scene[ix + 1u];\n uint raw2 = _306.scene[ix + 2u];\n uint raw3 = _306.scene[ix + 3u];\n uint raw4 = _306.scene[ix + 4u];\n uint raw5 = _306.scene[ix + 5u];\n uint raw6 = _306.scene[ix + 6u];\n uint raw7 = _306.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 = _306.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 = _306.scene[ix + 0u];\n uint raw1 = _306.scene[ix + 1u];\n uint raw2 = _306.scene[ix + 2u];\n uint raw3 = _306.scene[ix + 3u];\n uint raw4 = _306.scene[ix + 4u];\n uint raw5 = _306.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 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 _1778 = min(line.p0, line.p1);\n c.bbox = vec4(_1778.x, _1778.y, c.bbox.z, c.bbox.w);\n vec2 _1786 = max(line.p0, line.p1);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1786.x, _1786.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 _1803 = min(min(quad.p0, quad.p1), quad.p2);\n c.bbox = vec4(_1803.x, _1803.y, c.bbox.z, c.bbox.w);\n vec2 _1814 = max(max(quad.p0, quad.p1), quad.p2);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1814.x, _1814.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 _1834 = min(min(cubic.p0, cubic.p1), min(cubic.p2, cubic.p3));\n c.bbox = vec4(_1834.x, _1834.y, c.bbox.z, c.bbox.w);\n vec2 _1848 = max(max(cubic.p0, cubic.p1), max(cubic.p2, cubic.p3));\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1848.x, _1848.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 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 _1549 = (a.flags & 4u) == 0u;\n bool _1557;\n if (_1549)\n {\n _1557 = b.bbox.z <= b.bbox.x;\n }\n else\n {\n _1557 = _1549;\n }\n bool _1565;\n if (_1557)\n {\n _1565 = b.bbox.w <= b.bbox.y;\n }\n else\n {\n _1565 = _1557;\n }\n if (_1565)\n {\n c.bbox = a.bbox;\n }\n else\n {\n bool _1575 = (a.flags & 4u) == 0u;\n bool _1582;\n if (_1575)\n {\n _1582 = (b.flags & 2u) == 0u;\n }\n else\n {\n _1582 = _1575;\n }\n bool _1599;\n if (_1582)\n {\n bool _1589 = a.bbox.z > a.bbox.x;\n bool _1598;\n if (!_1589)\n {\n _1598 = a.bbox.w > a.bbox.y;\n }\n else\n {\n _1598 = _1589;\n }\n _1599 = _1598;\n }\n else\n {\n _1599 = _1582;\n }\n if (_1599)\n {\n vec2 _1608 = min(a.bbox.xy, c.bbox.xy);\n c.bbox = vec4(_1608.x, _1608.y, c.bbox.z, c.bbox.w);\n vec2 _1618 = max(a.bbox.zw, c.bbox.zw);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1618.x, _1618.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 _1704;\n if ((b.flags & 1u) == 0u)\n {\n _1704 = a.linewidth;\n }\n else\n {\n _1704 = b.linewidth;\n }\n c.linewidth = _1704;\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 return c;\n}\n\nStateRef state_aggregate_ref(uint partition_ix)\n{\n return StateRef(4u + (partition_ix * 116u));\n}\n\nvoid State_write(StateRef ref, State s)\n{\n uint ix = ref.offset >> uint(2);\n _780.state[ix + 0u] = floatBitsToUint(s.mat.x);\n _780.state[ix + 1u] = floatBitsToUint(s.mat.y);\n _780.state[ix + 2u] = floatBitsToUint(s.mat.z);\n _780.state[ix + 3u] = floatBitsToUint(s.mat.w);\n _780.state[ix + 4u] = floatBitsToUint(s.translate.x);\n _780.state[ix + 5u] = floatBitsToUint(s.translate.y);\n _780.state[ix + 6u] = floatBitsToUint(s.bbox.x);\n _780.state[ix + 7u] = floatBitsToUint(s.bbox.y);\n _780.state[ix + 8u] = floatBitsToUint(s.bbox.z);\n _780.state[ix + 9u] = floatBitsToUint(s.bbox.w);\n _780.state[ix + 10u] = floatBitsToUint(s.linewidth);\n _780.state[ix + 11u] = s.flags;\n _780.state[ix + 12u] = s.path_count;\n _780.state[ix + 13u] = s.pathseg_count;\n}\n\nStateRef state_prefix_ref(uint partition_ix)\n{\n return StateRef((4u + (partition_ix * 116u)) + 56u);\n}\n\nuint state_flag_index(uint partition_ix)\n{\n return partition_ix * 29u;\n}\n\nState State_read(StateRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _780.state[ix + 0u];\n uint raw1 = _780.state[ix + 1u];\n uint raw2 = _780.state[ix + 2u];\n uint raw3 = _780.state[ix + 3u];\n uint raw4 = _780.state[ix + 4u];\n uint raw5 = _780.state[ix + 5u];\n uint raw6 = _780.state[ix + 6u];\n uint raw7 = _780.state[ix + 7u];\n uint raw8 = _780.state[ix + 8u];\n uint raw9 = _780.state[ix + 9u];\n uint raw10 = _780.state[ix + 10u];\n uint raw11 = _780.state[ix + 11u];\n uint raw12 = _780.state[ix + 12u];\n uint raw13 = _780.state[ix + 13u];\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 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 _282.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 = floatBitsToUint(s.stroke.x);\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.y);\n write_mem(param_30, param_31, param_32);\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 = _306.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 = _306.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 = _306.scene[ix + 0u];\n uint raw1 = _306.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 = _306.scene[ix + 0u];\n uint raw1 = _306.scene[ix + 1u];\n uint raw2 = _306.scene[ix + 2u];\n uint raw3 = _306.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 main()\n{\n if (_282.mem_error != 0u)\n {\n return;\n }\n if (gl_LocalInvocationID.x == 0u)\n {\n uint _1917 = atomicAdd(_780.part_counter, 1u);\n sh_part_ix = _1917;\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_mat[gl_LocalInvocationID.x] = agg.mat;\n sh_translate[gl_LocalInvocationID.x] = agg.translate;\n sh_bbox[gl_LocalInvocationID.x] = agg.bbox;\n sh_width[gl_LocalInvocationID.x] = agg.linewidth;\n sh_flags[gl_LocalInvocationID.x] = agg.flags;\n sh_path_count[gl_LocalInvocationID.x] = agg.path_count;\n sh_pathseg_count[gl_LocalInvocationID.x] = agg.pathseg_count;\n State other;\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 uint ix_1 = gl_LocalInvocationID.x - uint(1 << int(i_1));\n other.mat = sh_mat[ix_1];\n other.translate = sh_translate[ix_1];\n other.bbox = sh_bbox[ix_1];\n other.linewidth = sh_width[ix_1];\n other.flags = sh_flags[ix_1];\n other.path_count = sh_path_count[ix_1];\n other.pathseg_count = sh_pathseg_count[ix_1];\n State param_6 = other;\n State param_7 = agg;\n agg = combine_state(param_6, param_7);\n }\n barrier();\n sh_mat[gl_LocalInvocationID.x] = agg.mat;\n sh_translate[gl_LocalInvocationID.x] = agg.translate;\n sh_bbox[gl_LocalInvocationID.x] = agg.bbox;\n sh_width[gl_LocalInvocationID.x] = agg.linewidth;\n sh_flags[gl_LocalInvocationID.x] = agg.flags;\n sh_path_count[gl_LocalInvocationID.x] = agg.path_count;\n sh_pathseg_count[gl_LocalInvocationID.x] = agg.pathseg_count;\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 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 _780.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 = _780.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 _780.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 uint ix_2 = gl_LocalInvocationID.x - 1u;\n State other_1;\n other_1.mat = sh_mat[ix_2];\n other_1.translate = sh_translate[ix_2];\n other_1.bbox = sh_bbox[ix_2];\n other_1.linewidth = sh_width[ix_2];\n other_1.flags = sh_flags[ix_2];\n other_1.path_count = sh_path_count[ix_2];\n other_1.pathseg_count = sh_pathseg_count[ix_2];\n State param_35 = row;\n State param_36 = other_1;\n row = combine_state(param_35, param_36);\n }\n vec2 p0;\n vec2 p1;\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 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 p0 = ((st.mat.xy * line.p0.x) + (st.mat.zw * line.p0.y)) + st.translate;\n p1 = ((st.mat.xy * line.p1.x) + (st.mat.zw * line.p1.y)) + st.translate;\n path_cubic.p0 = p0;\n path_cubic.p1 = mix(p0, p1, vec2(0.3333333432674407958984375));\n path_cubic.p2 = mix(p1, p0, vec2(0.3333333432674407958984375));\n path_cubic.p3 = p1;\n path_cubic.path_ix = st.path_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(_2430.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 48u));\n out_tag = uint((tag == 2u) ? 3 : 4);\n param_44.offset = _2430.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 = _2430.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 p0 = ((st.mat.xy * quad.p0.x) + (st.mat.zw * quad.p0.y)) + st.translate;\n p1 = ((st.mat.xy * quad.p1.x) + (st.mat.zw * quad.p1.y)) + st.translate;\n vec2 p2 = ((st.mat.xy * quad.p2.x) + (st.mat.zw * quad.p2.y)) + st.translate;\n path_cubic.p0 = p0;\n path_cubic.p1 = mix(p1, p0, vec2(0.3333333432674407958984375));\n path_cubic.p2 = mix(p1, p2, vec2(0.3333333432674407958984375));\n path_cubic.p3 = p2;\n path_cubic.path_ix = st.path_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(_2430.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 48u));\n out_tag = uint((tag == 4u) ? 3 : 4);\n param_52.offset = _2430.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 = _2430.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 = ((st.mat.xy * cubic.p0.x) + (st.mat.zw * cubic.p0.y)) + st.translate;\n path_cubic.p1 = ((st.mat.xy * cubic.p1.x) + (st.mat.zw * cubic.p1.y)) + st.translate;\n path_cubic.p2 = ((st.mat.xy * cubic.p2.x) + (st.mat.zw * cubic.p2.y)) + st.translate;\n path_cubic.p3 = ((st.mat.xy * cubic.p3.x) + (st.mat.zw * cubic.p3.y)) + st.translate;\n path_cubic.path_ix = st.path_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(_2430.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 48u));\n out_tag = uint((tag == 6u) ? 3 : 4);\n param_60.offset = _2430.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 = _2430.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(_2430.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_68.offset = _2430.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(_2430.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_72.offset = _2430.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(_2430.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_76.offset = _2430.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(_2430.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_80.offset = _2430.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(_2430.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_84.offset = _2430.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 }\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 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 uint tail;\n float linewidth;\n uint flags;\n uint path_count;\n uint pathseg_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 uint succ_ix;\n uint path_ix;\n vec2 stroke;\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};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _282;\n\nlayout(binding = 2, std430) readonly buffer SceneBuf\n{\n uint scene[];\n} _306;\n\nlayout(binding = 3, std430) coherent buffer StateBuf\n{\n uint part_counter;\n uint state[];\n} _780;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _2521;\n\nshared uint sh_part_ix;\nshared vec4 sh_mat[32];\nshared vec2 sh_translate[32];\nshared vec4 sh_bbox[32];\nshared float sh_width[32];\nshared uint sh_tail[32];\nshared uint sh_flags[32];\nshared uint sh_path_count[32];\nshared uint sh_pathseg_count[32];\nshared State sh_prefix;\n\nuint Element_tag(ElementRef ref)\n{\n return _306.scene[ref.offset >> uint(2)];\n}\n\nLineSeg LineSeg_read(LineSegRef ref)\n{\n uint ix = ref.offset >> uint(2);\n uint raw0 = _306.scene[ix + 0u];\n uint raw1 = _306.scene[ix + 1u];\n uint raw2 = _306.scene[ix + 2u];\n uint raw3 = _306.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 = _306.scene[ix + 0u];\n uint raw1 = _306.scene[ix + 1u];\n uint raw2 = _306.scene[ix + 2u];\n uint raw3 = _306.scene[ix + 3u];\n uint raw4 = _306.scene[ix + 4u];\n uint raw5 = _306.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 = _306.scene[ix + 0u];\n uint raw1 = _306.scene[ix + 1u];\n uint raw2 = _306.scene[ix + 2u];\n uint raw3 = _306.scene[ix + 3u];\n uint raw4 = _306.scene[ix + 4u];\n uint raw5 = _306.scene[ix + 5u];\n uint raw6 = _306.scene[ix + 6u];\n uint raw7 = _306.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 = _306.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 = _306.scene[ix + 0u];\n uint raw1 = _306.scene[ix + 1u];\n uint raw2 = _306.scene[ix + 2u];\n uint raw3 = _306.scene[ix + 3u];\n uint raw4 = _306.scene[ix + 4u];\n uint raw5 = _306.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_flags = 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.tail = 0u;\n c.path_count = 0u;\n c.pathseg_count = 0u;\n uint flags = tag_flags >> uint(16);\n switch (tag_flags & 65535u)\n {\n case 2u:\n case 1u:\n {\n ElementRef param_1 = ref;\n LineSeg line = Element_FillLine_read(param_1);\n vec2 _1827 = min(line.p0, line.p1);\n c.bbox = vec4(_1827.x, _1827.y, c.bbox.z, c.bbox.w);\n vec2 _1835 = max(line.p0, line.p1);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1835.x, _1835.y);\n c.pathseg_count = 1u;\n c.flags = flags;\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 _1854 = min(min(quad.p0, quad.p1), quad.p2);\n c.bbox = vec4(_1854.x, _1854.y, c.bbox.z, c.bbox.w);\n vec2 _1865 = max(max(quad.p0, quad.p1), quad.p2);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1865.x, _1865.y);\n c.pathseg_count = 1u;\n c.flags = flags;\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 _1887 = min(min(cubic.p0, cubic.p1), min(cubic.p2, cubic.p3));\n c.bbox = vec4(_1887.x, _1887.y, c.bbox.z, c.bbox.w);\n vec2 _1901 = max(max(cubic.p0, cubic.p1), max(cubic.p2, cubic.p3));\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1901.x, _1901.y);\n c.pathseg_count = 1u;\n c.flags = flags;\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 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 _1552 = (a.flags & 4u) == 0u;\n bool _1560;\n if (_1552)\n {\n _1560 = b.bbox.z <= b.bbox.x;\n }\n else\n {\n _1560 = _1552;\n }\n bool _1568;\n if (_1560)\n {\n _1568 = b.bbox.w <= b.bbox.y;\n }\n else\n {\n _1568 = _1560;\n }\n if (_1568)\n {\n c.bbox = a.bbox;\n }\n else\n {\n bool _1578 = (a.flags & 4u) == 0u;\n bool _1585;\n if (_1578)\n {\n _1585 = (b.flags & 2u) == 0u;\n }\n else\n {\n _1585 = _1578;\n }\n bool _1602;\n if (_1585)\n {\n bool _1592 = a.bbox.z > a.bbox.x;\n bool _1601;\n if (!_1592)\n {\n _1601 = a.bbox.w > a.bbox.y;\n }\n else\n {\n _1601 = _1592;\n }\n _1602 = _1601;\n }\n else\n {\n _1602 = _1585;\n }\n if (_1602)\n {\n vec2 _1611 = min(a.bbox.xy, c.bbox.xy);\n c.bbox = vec4(_1611.x, _1611.y, c.bbox.z, c.bbox.w);\n vec2 _1621 = max(a.bbox.zw, c.bbox.zw);\n c.bbox = vec4(c.bbox.x, c.bbox.y, _1621.x, _1621.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 _1707;\n if ((b.flags & 1u) == 0u)\n {\n _1707 = a.linewidth;\n }\n else\n {\n _1707 = b.linewidth;\n }\n c.linewidth = _1707;\n c.flags = (a.flags & 11u) | b.flags;\n c.flags |= ((a.flags & 4u) >> uint(1));\n c.flags |= ((a.flags & 16u) >> uint(1));\n c.path_count = a.path_count + b.path_count;\n c.pathseg_count = a.pathseg_count + b.pathseg_count;\n c.tail = a.tail;\n bool _1759 = (a.flags & 16u) != 0u;\n bool _1766;\n if (_1759)\n {\n _1766 = (b.flags & 8u) == 0u;\n }\n else\n {\n _1766 = _1759;\n }\n if (_1766)\n {\n c.tail = a.pathseg_count;\n }\n else\n {\n if ((b.flags & 8u) != 0u)\n {\n c.tail = b.tail + a.pathseg_count;\n }\n }\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 _780.state[ix + 0u] = floatBitsToUint(s.mat.x);\n _780.state[ix + 1u] = floatBitsToUint(s.mat.y);\n _780.state[ix + 2u] = floatBitsToUint(s.mat.z);\n _780.state[ix + 3u] = floatBitsToUint(s.mat.w);\n _780.state[ix + 4u] = floatBitsToUint(s.translate.x);\n _780.state[ix + 5u] = floatBitsToUint(s.translate.y);\n _780.state[ix + 6u] = floatBitsToUint(s.bbox.x);\n _780.state[ix + 7u] = floatBitsToUint(s.bbox.y);\n _780.state[ix + 8u] = floatBitsToUint(s.bbox.z);\n _780.state[ix + 9u] = floatBitsToUint(s.bbox.w);\n _780.state[ix + 10u] = s.tail;\n _780.state[ix + 11u] = floatBitsToUint(s.linewidth);\n _780.state[ix + 12u] = s.flags;\n _780.state[ix + 13u] = s.path_count;\n _780.state[ix + 14u] = s.pathseg_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 = _780.state[ix + 0u];\n uint raw1 = _780.state[ix + 1u];\n uint raw2 = _780.state[ix + 2u];\n uint raw3 = _780.state[ix + 3u];\n uint raw4 = _780.state[ix + 4u];\n uint raw5 = _780.state[ix + 5u];\n uint raw6 = _780.state[ix + 6u];\n uint raw7 = _780.state[ix + 7u];\n uint raw8 = _780.state[ix + 8u];\n uint raw9 = _780.state[ix + 9u];\n uint raw10 = _780.state[ix + 10u];\n uint raw11 = _780.state[ix + 11u];\n uint raw12 = _780.state[ix + 12u];\n uint raw13 = _780.state[ix + 13u];\n uint raw14 = _780.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.tail = raw10;\n s.linewidth = uintBitsToFloat(raw11);\n s.flags = raw12;\n s.path_count = raw13;\n s.pathseg_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 _282.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 = s.succ_ix;\n write_mem(param_18, param_19, param_20);\n Alloc param_21 = a;\n uint param_22 = ix + 7u;\n uint param_23 = s.path_ix;\n write_mem(param_21, param_22, param_23);\n Alloc param_24 = a;\n uint param_25 = ix + 8u;\n uint param_26 = floatBitsToUint(s.stroke.x);\n write_mem(param_24, param_25, param_26);\n Alloc param_27 = a;\n uint param_28 = ix + 9u;\n uint param_29 = floatBitsToUint(s.stroke.y);\n write_mem(param_27, param_28, param_29);\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 = _306.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 = _306.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 = _306.scene[ix + 0u];\n uint raw1 = _306.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 = _306.scene[ix + 0u];\n uint raw1 = _306.scene[ix + 1u];\n uint raw2 = _306.scene[ix + 2u];\n uint raw3 = _306.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 main()\n{\n if (_282.mem_error != 0u)\n {\n return;\n }\n if (gl_LocalInvocationID.x == 0u)\n {\n uint _1972 = atomicAdd(_780.part_counter, 1u);\n sh_part_ix = _1972;\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_mat[gl_LocalInvocationID.x] = agg.mat;\n sh_translate[gl_LocalInvocationID.x] = agg.translate;\n sh_bbox[gl_LocalInvocationID.x] = agg.bbox;\n sh_width[gl_LocalInvocationID.x] = agg.linewidth;\n sh_tail[gl_LocalInvocationID.x] = agg.tail;\n sh_flags[gl_LocalInvocationID.x] = agg.flags;\n sh_path_count[gl_LocalInvocationID.x] = agg.path_count;\n sh_pathseg_count[gl_LocalInvocationID.x] = agg.pathseg_count;\n State other;\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 uint ix_1 = gl_LocalInvocationID.x - uint(1 << int(i_1));\n other.mat = sh_mat[ix_1];\n other.translate = sh_translate[ix_1];\n other.bbox = sh_bbox[ix_1];\n other.linewidth = sh_width[ix_1];\n other.flags = sh_flags[ix_1];\n other.tail = sh_tail[ix_1];\n other.path_count = sh_path_count[ix_1];\n other.pathseg_count = sh_pathseg_count[ix_1];\n State param_6 = other;\n State param_7 = agg;\n agg = combine_state(param_6, param_7);\n }\n barrier();\n sh_mat[gl_LocalInvocationID.x] = agg.mat;\n sh_translate[gl_LocalInvocationID.x] = agg.translate;\n sh_bbox[gl_LocalInvocationID.x] = agg.bbox;\n sh_width[gl_LocalInvocationID.x] = agg.linewidth;\n sh_flags[gl_LocalInvocationID.x] = agg.flags;\n sh_tail[gl_LocalInvocationID.x] = agg.tail;\n sh_path_count[gl_LocalInvocationID.x] = agg.path_count;\n sh_pathseg_count[gl_LocalInvocationID.x] = agg.pathseg_count;\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.tail = 0u;\n exclusive.path_count = 0u;\n exclusive.pathseg_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 _780.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 = _780.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 _780.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 uint ix_2 = gl_LocalInvocationID.x - 1u;\n State other_1;\n other_1.mat = sh_mat[ix_2];\n other_1.translate = sh_translate[ix_2];\n other_1.bbox = sh_bbox[ix_2];\n other_1.linewidth = sh_width[ix_2];\n other_1.flags = sh_flags[ix_2];\n other_1.tail = sh_tail[ix_2];\n other_1.path_count = sh_path_count[ix_2];\n other_1.pathseg_count = sh_pathseg_count[ix_2];\n State param_35 = row;\n State param_36 = other_1;\n row = combine_state(param_35, param_36);\n }\n vec2 p0;\n vec2 p1;\n PathStrokeCubic path_cubic;\n uint _2491;\n PathSegRef path_out_ref;\n uint out_tag;\n Alloc param_44;\n Alloc param_47;\n uint _2631;\n Alloc param_52;\n Alloc param_55;\n uint _2750;\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 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_flags = Element_tag(param_41);\n uint tag = tag_flags & 65535u;\n uint flags = tag_flags >> uint(16);\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 p0 = ((st.mat.xy * line.p0.x) + (st.mat.zw * line.p0.y)) + st.translate;\n p1 = ((st.mat.xy * line.p1.x) + (st.mat.zw * line.p1.y)) + st.translate;\n path_cubic.p0 = p0;\n path_cubic.p1 = mix(p0, p1, vec2(0.3333333432674407958984375));\n path_cubic.p2 = mix(p1, p0, vec2(0.3333333432674407958984375));\n if ((flags & 16u) == 0u)\n {\n _2491 = st.pathseg_count;\n }\n else\n {\n _2491 = st.tail;\n }\n path_cubic.succ_ix = _2491;\n path_cubic.path_ix = st.path_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(_2521.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 44u));\n out_tag = uint((tag == 2u) ? 1 : 2);\n param_44.offset = _2521.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 = _2521.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 p0 = ((st.mat.xy * quad.p0.x) + (st.mat.zw * quad.p0.y)) + st.translate;\n p1 = ((st.mat.xy * quad.p1.x) + (st.mat.zw * quad.p1.y)) + st.translate;\n vec2 p2 = ((st.mat.xy * quad.p2.x) + (st.mat.zw * quad.p2.y)) + st.translate;\n path_cubic.p0 = p0;\n path_cubic.p1 = mix(p1, p0, vec2(0.3333333432674407958984375));\n path_cubic.p2 = mix(p1, p2, vec2(0.3333333432674407958984375));\n if ((flags & 16u) == 0u)\n {\n _2631 = st.pathseg_count;\n }\n else\n {\n _2631 = st.tail;\n }\n path_cubic.succ_ix = _2631;\n path_cubic.path_ix = st.path_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(_2521.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 44u));\n out_tag = uint((tag == 4u) ? 1 : 2);\n param_52.offset = _2521.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 = _2521.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 = ((st.mat.xy * cubic.p0.x) + (st.mat.zw * cubic.p0.y)) + st.translate;\n path_cubic.p1 = ((st.mat.xy * cubic.p1.x) + (st.mat.zw * cubic.p1.y)) + st.translate;\n path_cubic.p2 = ((st.mat.xy * cubic.p2.x) + (st.mat.zw * cubic.p2.y)) + st.translate;\n if ((flags & 16u) == 0u)\n {\n _2750 = st.pathseg_count;\n }\n else\n {\n _2750 = st.tail;\n }\n path_cubic.succ_ix = _2750;\n path_cubic.path_ix = st.path_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(_2521.conf.pathseg_alloc.offset + ((st.pathseg_count - 1u) * 44u));\n out_tag = uint((tag == 6u) ? 1 : 2);\n param_60.offset = _2521.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 = _2521.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(_2521.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_68.offset = _2521.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(_2521.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_72.offset = _2521.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(_2521.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_76.offset = _2521.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(_2521.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_80.offset = _2521.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(_2521.conf.anno_alloc.offset + ((st.path_count - 1u) * 28u));\n param_84.offset = _2521.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 }\n }\n}\n\n", } shader_intersect_frag = backend.ShaderSources{ Name: "intersect.frag", @@ -834,7 +834,7 @@ var ( } shader_path_coarse_comp = backend.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 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 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};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _135;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _685;\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 = _135.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 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.stroke = vec2(uintBitsToFloat(raw9), uintBitsToFloat(raw10));\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\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 _141 = atomicAdd(_135.mem_offset, size);\n uint offset = _141;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_135.memory.length())) * 4))\n {\n r.failed = true;\n uint _162 = atomicMax(_135.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 _135.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 (_135.mem_error != 0u)\n {\n return;\n }\n uint element_ix = gl_GlobalInvocationID.x;\n PathSegRef ref = PathSegRef(_685.conf.pathseg_alloc.offset + (element_ix * 48u));\n uint tag = 0u;\n if (element_ix < _685.conf.n_pathseg)\n {\n Alloc param;\n param.offset = _685.conf.pathseg_alloc.offset;\n PathSegRef param_1 = ref;\n tag = PathSeg_tag(param, param_1);\n }\n switch (tag)\n {\n case 3u:\n case 4u:\n {\n Alloc param_2;\n param_2.offset = _685.conf.pathseg_alloc.offset;\n PathSegRef param_3 = ref;\n PathStrokeCubic cubic = PathSeg_StrokeCubic_read(param_2, param_3);\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_4 = cubic.p0;\n vec2 param_5 = cubic.p1;\n vec2 param_6 = cubic.p2;\n vec2 param_7 = cubic.p3;\n float param_8 = t;\n vec2 qp2 = eval_cubic(param_4, param_5, param_6, param_7, param_8);\n vec2 param_9 = cubic.p0;\n vec2 param_10 = cubic.p1;\n vec2 param_11 = cubic.p2;\n vec2 param_12 = cubic.p3;\n float param_13 = t - (0.5 * _step);\n vec2 qp1 = eval_cubic(param_9, param_10, param_11, param_12, param_13);\n qp1 = (qp1 * 2.0) - ((qp0 + qp2) * 0.5);\n vec2 param_14 = qp0;\n vec2 param_15 = qp1;\n vec2 param_16 = qp2;\n float param_17 = 0.4743416607379913330078125;\n SubdivResult params = estimate_subdiv(param_14, param_15, param_16, param_17);\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_18;\n param_18.offset = _685.conf.tile_alloc.offset;\n PathRef param_19 = PathRef(_685.conf.tile_alloc.offset + (path_ix * 12u));\n Path path = Path_read(param_18, param_19);\n uint param_20 = path.tiles.offset;\n uint param_21 = ((path.bbox.z - path.bbox.x) * (path.bbox.w - path.bbox.y)) * 8u;\n Alloc path_alloc = new_alloc(param_20, param_21);\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 _1103;\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_22 = cubic.p0;\n vec2 param_23 = cubic.p1;\n vec2 param_24 = cubic.p2;\n vec2 param_25 = cubic.p3;\n float param_26 = t_1;\n vec2 qp2_1 = eval_cubic(param_22, param_23, param_24, param_25, param_26);\n vec2 param_27 = cubic.p0;\n vec2 param_28 = cubic.p1;\n vec2 param_29 = cubic.p2;\n vec2 param_30 = cubic.p3;\n float param_31 = t_1 - (0.5 * _step);\n vec2 qp1_1 = eval_cubic(param_27, param_28, param_29, param_30, param_31);\n qp1_1 = (qp1_1 * 2.0) - ((qp0 + qp2_1) * 0.5);\n vec2 param_32 = qp0;\n vec2 param_33 = qp1_1;\n vec2 param_34 = qp2_1;\n float param_35 = 0.4743416607379913330078125;\n SubdivResult params_1 = estimate_subdiv(param_32, param_33, param_34, param_35);\n float param_36 = params_1.a0;\n float u0 = approx_parabola_inv_integral(param_36);\n float param_37 = params_1.a2;\n float u2 = approx_parabola_inv_integral(param_37);\n float uscale = 1.0 / (u2 - u0);\n float target = float(n_out) * v_step;\n for (;;)\n {\n bool _996 = uint(n_out) == n;\n bool _1006;\n if (!_996)\n {\n _1006 = target < (val_sum + params_1.val);\n }\n else\n {\n _1006 = _996;\n }\n if (_1006)\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_38 = a;\n float au = approx_parabola_inv_integral(param_38);\n float t_2 = (au - u0) * uscale;\n vec2 param_39 = qp0;\n vec2 param_40 = qp1_1;\n vec2 param_41 = qp2_1;\n float param_42 = t_2;\n p1 = eval_quad(param_39, param_40, param_41, param_42);\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 _1103 = 1000000000.0;\n }\n else\n {\n _1103 = dx / dy;\n }\n float invslope = _1103;\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_43 = n_tile_alloc * 24u;\n MallocResult _1219 = malloc(param_43);\n MallocResult tile_alloc = _1219;\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 _1273 = tag == 3u;\n bool _1283;\n if (_1273)\n {\n _1283 = min(p0.y, p1.y) < tile_y0;\n }\n else\n {\n _1283 = _1273;\n }\n bool _1290;\n if (_1283)\n {\n _1290 = xbackdrop < bbox.z;\n }\n else\n {\n _1290 = _1283;\n }\n if (_1290)\n {\n int backdrop = (p1.y < p0.y) ? 1 : (-1);\n TileRef param_44 = path.tiles;\n uint param_45 = uint(base + xbackdrop);\n TileRef tile_ref = Tile_index(param_44, param_45);\n uint tile_el = tile_ref.offset >> uint(2);\n Alloc param_46 = path_alloc;\n uint param_47 = tile_el + 1u;\n if (touch_mem(param_46, param_47))\n {\n uint _1328 = atomicAdd(_135.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_48 = TileRef(path.tiles.offset);\n uint param_49 = uint(base + x);\n TileRef tile_ref_1 = Tile_index(param_48, param_49);\n uint tile_el_1 = tile_ref_1.offset >> uint(2);\n uint old = 0u;\n Alloc param_50 = path_alloc;\n uint param_51 = tile_el_1;\n if (touch_mem(param_50, param_51))\n {\n uint _1431 = atomicExchange(_135.memory[tile_el_1], tile_offset);\n old = _1431;\n }\n tile_seg.origin = p0;\n tile_seg.vector = p1 - p0;\n float y_edge = 0.0;\n if (tag == 3u)\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_52 = tile_alloc.alloc;\n TileSegRef param_53 = TileSegRef(tile_offset);\n TileSeg param_54 = tile_seg;\n TileSeg_write(param_52, param_53, param_54);\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 PathStrokeCubicRef\n{\n uint offset;\n};\n\nstruct PathStrokeCubic\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n uint succ_ix;\n uint path_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 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};\n\nlayout(binding = 0, std430) buffer Memory\n{\n uint mem_offset;\n uint mem_error;\n uint memory[];\n} _140;\n\nlayout(binding = 1, std430) readonly buffer ConfigBuf\n{\n Config conf;\n} _704;\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 = _140.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 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.succ_ix = raw6;\n s.path_ix = raw7;\n s.stroke = vec2(uintBitsToFloat(raw8), uintBitsToFloat(raw9));\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\nvec2 PathSeg_Cubic_read_p0(Alloc a, PathSegRef ref)\n{\n uint ix = (ref.offset + 4u) >> 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 return vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));\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 _146 = atomicAdd(_140.mem_offset, size);\n uint offset = _146;\n uint param = offset;\n uint param_1 = size;\n r.alloc = new_alloc(param, param_1);\n if ((offset + size) > uint(int(uint(_140.memory.length())) * 4))\n {\n r.failed = true;\n uint _167 = atomicMax(_140.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 _140.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 (_140.mem_error != 0u)\n {\n return;\n }\n uint element_ix = gl_GlobalInvocationID.x;\n PathSegRef ref = PathSegRef(_704.conf.pathseg_alloc.offset + (element_ix * 44u));\n uint tag = 0u;\n if (element_ix < _704.conf.n_pathseg)\n {\n Alloc param;\n param.offset = _704.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 = _704.conf.pathseg_alloc.offset;\n PathSegRef param_3 = ref;\n PathStrokeCubic cubic = PathSeg_StrokeCubic_read(param_2, param_3);\n PathSegRef succ_ref = PathSegRef(_704.conf.pathseg_alloc.offset + (cubic.succ_ix * 44u));\n Alloc param_4;\n param_4.offset = _704.conf.pathseg_alloc.offset;\n PathSegRef param_5 = succ_ref;\n vec2 p3 = PathSeg_Cubic_read_p0(param_4, param_5);\n vec2 err_v = (((cubic.p2 - cubic.p1) * 3.0) + cubic.p0) - 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 = 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 = 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 = _704.conf.tile_alloc.offset;\n PathRef param_21 = PathRef(_704.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 _1133;\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 = 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 = 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 _1027 = uint(n_out) == n;\n bool _1037;\n if (!_1027)\n {\n _1037 = target < (val_sum + params_1.val);\n }\n else\n {\n _1037 = _1027;\n }\n if (_1037)\n {\n if (uint(n_out) == n)\n {\n p1 = 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 _1133 = 1000000000.0;\n }\n else\n {\n _1133 = dx / dy;\n }\n float invslope = _1133;\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 _1249 = malloc(param_45);\n MallocResult tile_alloc = _1249;\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 _1303 = tag == 1u;\n bool _1313;\n if (_1303)\n {\n _1313 = min(p0.y, p1.y) < tile_y0;\n }\n else\n {\n _1313 = _1303;\n }\n bool _1320;\n if (_1313)\n {\n _1320 = xbackdrop < bbox.z;\n }\n else\n {\n _1320 = _1313;\n }\n if (_1320)\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 _1358 = atomicAdd(_140.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 _1461 = atomicExchange(_140.memory[tile_el_1], tile_offset);\n old = _1461;\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", } shader_stencil_frag = backend.ShaderSources{ Name: "stencil.frag", diff --git a/gpu/shaders/elements.comp b/gpu/shaders/elements.comp index 2cf725d5..f58d805d 100644 --- a/gpu/shaders/elements.comp +++ b/gpu/shaders/elements.comp @@ -62,6 +62,8 @@ uint state_flag_index(uint partition_ix) { #define FLAG_SET_LINEWIDTH 1 #define FLAG_SET_BBOX 2 #define FLAG_RESET_BBOX 4 +#define FLAG_START_PATH 8 +#define FLAG_END_PATH 16 // This is almost like a monoid (the interaction between transformation and // bounding boxes is approximate) @@ -87,32 +89,45 @@ 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_START_PATH)) | b.flags; c.flags |= (a.flags & FLAG_RESET_BBOX) >> 1; + c.flags |= (a.flags & FLAG_END_PATH) >> 1; c.path_count = a.path_count + b.path_count; c.pathseg_count = a.pathseg_count + b.pathseg_count; + + c.tail = a.tail; + if ((a.flags & FLAG_END_PATH) != 0 && (b.flags & FLAG_START_PATH) == 0) { + c.tail = a.pathseg_count; + } else if ((b.flags & FLAG_START_PATH) != 0) { + c.tail = b.tail + a.pathseg_count; + } + return c; } 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_flags = Element_tag(ref); State c; c.bbox = vec4(0.0, 0.0, 0.0, 0.0); c.mat = vec4(1.0, 0.0, 0.0, 1.0); c.translate = vec2(0.0, 0.0); c.linewidth = 1.0; // TODO should be 0.0 c.flags = 0; + c.tail = 0; c.path_count = 0; c.pathseg_count = 0; - switch (tag) { + // flags contain FLAG_END_PATH for segments last in their path. + uint flags = tag_flags >> 16; + switch (tag_flags & 0xffff) { case Element_FillLine: case Element_StrokeLine: LineSeg line = Element_FillLine_read(ref); c.bbox.xy = min(line.p0, line.p1); c.bbox.zw = max(line.p0, line.p1); c.pathseg_count = 1; + c.flags = flags; break; case Element_FillQuad: case Element_StrokeQuad: @@ -120,6 +135,7 @@ State map_element(ElementRef 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; + c.flags = flags; break; case Element_FillCubic: case Element_StrokeCubic: @@ -127,6 +143,7 @@ State map_element(ElementRef 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; + c.flags = flags; break; case Element_Fill: case Element_FillImage: @@ -166,6 +183,7 @@ shared vec2 sh_translate[WG_SIZE]; shared vec4 sh_bbox[WG_SIZE]; shared float sh_width[WG_SIZE]; shared uint sh_flags[WG_SIZE]; +shared uint sh_tail[WG_SIZE]; shared uint sh_path_count[WG_SIZE]; shared uint sh_pathseg_count[WG_SIZE]; @@ -200,6 +218,7 @@ void main() { sh_translate[gl_LocalInvocationID.x] = agg.translate; sh_bbox[gl_LocalInvocationID.x] = agg.bbox; sh_width[gl_LocalInvocationID.x] = agg.linewidth; + sh_tail[gl_LocalInvocationID.x] = agg.tail; sh_flags[gl_LocalInvocationID.x] = agg.flags; sh_path_count[gl_LocalInvocationID.x] = agg.path_count; sh_pathseg_count[gl_LocalInvocationID.x] = agg.pathseg_count; @@ -213,6 +232,7 @@ void main() { other.bbox = sh_bbox[ix]; other.linewidth = sh_width[ix]; other.flags = sh_flags[ix]; + other.tail = sh_tail[ix]; other.path_count = sh_path_count[ix]; other.pathseg_count = sh_pathseg_count[ix]; agg = combine_state(other, agg); @@ -223,6 +243,7 @@ void main() { sh_bbox[gl_LocalInvocationID.x] = agg.bbox; sh_width[gl_LocalInvocationID.x] = agg.linewidth; sh_flags[gl_LocalInvocationID.x] = agg.flags; + sh_tail[gl_LocalInvocationID.x] = agg.tail; sh_path_count[gl_LocalInvocationID.x] = agg.path_count; sh_pathseg_count[gl_LocalInvocationID.x] = agg.pathseg_count; } @@ -233,6 +254,7 @@ void main() { exclusive.translate = vec2(0.0, 0.0); exclusive.linewidth = 1.0; //TODO should be 0.0 exclusive.flags = 0; + exclusive.tail = 0; exclusive.path_count = 0; exclusive.pathseg_count = 0; @@ -312,6 +334,7 @@ void main() { other.bbox = sh_bbox[ix]; other.linewidth = sh_width[ix]; other.flags = sh_flags[ix]; + other.tail = sh_tail[ix]; other.path_count = sh_path_count[ix]; other.pathseg_count = sh_pathseg_count[ix]; row = combine_state(row, other); @@ -323,7 +346,9 @@ 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); + uint tag_flags = Element_tag(this_ref); + uint tag = tag_flags & 0xffff; + uint flags = tag_flags >> 16; switch (tag) { case Element_FillLine: case Element_StrokeLine: @@ -334,7 +359,7 @@ void main() { path_cubic.p0 = p0; path_cubic.p1 = mix(p0, p1, 1.0 / 3.0); path_cubic.p2 = mix(p1, p0, 1.0 / 3.0); - path_cubic.p3 = p1; + path_cubic.succ_ix = (flags & FLAG_END_PATH) == 0 ? st.pathseg_count : st.tail; path_cubic.path_ix = st.path_count; if (tag == Element_StrokeLine) { path_cubic.stroke = get_linewidth(st); @@ -358,7 +383,7 @@ void main() { path_cubic.p0 = p0; path_cubic.p1 = mix(p1, p0, 1.0 / 3.0); path_cubic.p2 = mix(p1, p2, 1.0 / 3.0); - path_cubic.p3 = p2; + path_cubic.succ_ix = (flags & FLAG_END_PATH) == 0 ? st.pathseg_count : st.tail; path_cubic.path_ix = st.path_count; if (tag == Element_StrokeQuad) { path_cubic.stroke = get_linewidth(st); @@ -379,7 +404,7 @@ void main() { path_cubic.p0 = st.mat.xy * cubic.p0.x + st.mat.zw * cubic.p0.y + st.translate; path_cubic.p1 = st.mat.xy * cubic.p1.x + st.mat.zw * cubic.p1.y + st.translate; path_cubic.p2 = st.mat.xy * cubic.p2.x + st.mat.zw * cubic.p2.y + st.translate; - path_cubic.p3 = st.mat.xy * cubic.p3.x + st.mat.zw * cubic.p3.y + st.translate; + path_cubic.succ_ix = (flags & FLAG_END_PATH) == 0 ? st.pathseg_count : st.tail; path_cubic.path_ix = st.path_count; if (tag == Element_StrokeCubic) { path_cubic.stroke = get_linewidth(st); diff --git a/gpu/shaders/path_coarse.comp b/gpu/shaders/path_coarse.comp index 4f77ff9b..d843945e 100644 --- a/gpu/shaders/path_coarse.comp +++ b/gpu/shaders/path_coarse.comp @@ -86,6 +86,14 @@ SubdivResult estimate_subdiv(vec2 p0, vec2 p1, vec2 p2, float sqrt_tol) { return SubdivResult(val, a0, a2); } +// PathSeg_Cubic_read_p0 is like PathSeg_StrokeCubic_read except it only reads p0. +vec2 PathSeg_Cubic_read_p0(Alloc a, PathSegRef ref) { + uint ix = (ref.offset + 4) >> 2; + uint raw0 = read_mem(a, ix + 0); + uint raw1 = read_mem(a, ix + 1); + return vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); +} + void main() { if (mem_error != NO_ERROR) { return; @@ -102,7 +110,9 @@ void main() { case PathSeg_FillCubic: case PathSeg_StrokeCubic: PathStrokeCubic cubic = PathSeg_StrokeCubic_read(conf.pathseg_alloc, ref); - vec2 err_v = 3.0 * (cubic.p2 - cubic.p1) + cubic.p0 - cubic.p3; + PathSegRef succ_ref = PathSegRef(conf.pathseg_alloc.offset + cubic.succ_ix * PathSeg_size); + vec2 p3 = PathSeg_Cubic_read_p0(conf.pathseg_alloc, succ_ref); + vec2 err_v = 3.0 * (cubic.p2 - cubic.p1) + cubic.p0 - p3; float err = err_v.x * err_v.x + err_v.y * err_v.y; // The number of quadratics. uint n_quads = max(uint(ceil(pow(err * (1.0 / MAX_HYPOT2), 1.0 / 6.0))), 1); @@ -112,8 +122,8 @@ void main() { float step = 1.0 / float(n_quads); for (uint i = 0; i < n_quads; i++) { float t = float(i + 1) * step; - vec2 qp2 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, cubic.p3, t); - vec2 qp1 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, cubic.p3, t - 0.5 * step); + vec2 qp2 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, p3, t); + vec2 qp1 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, p3, t - 0.5 * step); qp1 = 2.0 * qp1 - 0.5 * (qp0 + qp2); SubdivResult params = estimate_subdiv(qp0, qp1, qp2, sqrt(REM_ACCURACY)); val += params.val; @@ -133,8 +143,8 @@ void main() { float val_sum = 0.0; for (uint i = 0; i < n_quads; i++) { float t = float(i + 1) * step; - vec2 qp2 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, cubic.p3, t); - vec2 qp1 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, cubic.p3, t - 0.5 * step); + vec2 qp2 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, p3, t); + vec2 qp1 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, p3, t - 0.5 * step); qp1 = 2.0 * qp1 - 0.5 * (qp0 + qp2); SubdivResult params = estimate_subdiv(qp0, qp1, qp2, sqrt(REM_ACCURACY)); float u0 = approx_parabola_inv_integral(params.a0); @@ -144,7 +154,7 @@ void main() { while (n_out == n || target < val_sum + params.val) { vec2 p1; if (n_out == n) { - p1 = cubic.p3; + p1 = p3; } else { float u = (target - val_sum) / params.val; float a = mix(params.a0, params.a2, u); diff --git a/gpu/shaders/pathseg.h b/gpu/shaders/pathseg.h index 00509fbf..d7326586 100644 --- a/gpu/shaders/pathseg.h +++ b/gpu/shaders/pathseg.h @@ -2,14 +2,6 @@ // Code auto-generated by piet-gpu-derive -struct PathFillLineRef { - uint offset; -}; - -struct PathStrokeLineRef { - uint offset; -}; - struct PathFillCubicRef { uint offset; }; @@ -22,40 +14,15 @@ struct PathSegRef { uint offset; }; -struct PathFillLine { - vec2 p0; - vec2 p1; - uint path_ix; -}; - -#define PathFillLine_size 20 - -PathFillLineRef PathFillLine_index(PathFillLineRef ref, uint index) { - return PathFillLineRef(ref.offset + index * PathFillLine_size); -} - -struct PathStrokeLine { - vec2 p0; - vec2 p1; - uint path_ix; - vec2 stroke; -}; - -#define PathStrokeLine_size 28 - -PathStrokeLineRef PathStrokeLine_index(PathStrokeLineRef ref, uint index) { - return PathStrokeLineRef(ref.offset + index * PathStrokeLine_size); -} - struct PathFillCubic { vec2 p0; vec2 p1; vec2 p2; - vec2 p3; + uint succ_ix; uint path_ix; }; -#define PathFillCubic_size 36 +#define PathFillCubic_size 32 PathFillCubicRef PathFillCubic_index(PathFillCubicRef ref, uint index) { return PathFillCubicRef(ref.offset + index * PathFillCubic_size); @@ -65,79 +32,26 @@ struct PathStrokeCubic { vec2 p0; vec2 p1; vec2 p2; - vec2 p3; + uint succ_ix; uint path_ix; vec2 stroke; }; -#define PathStrokeCubic_size 44 +#define PathStrokeCubic_size 40 PathStrokeCubicRef PathStrokeCubic_index(PathStrokeCubicRef ref, uint index) { return PathStrokeCubicRef(ref.offset + index * PathStrokeCubic_size); } #define PathSeg_Nop 0 -#define PathSeg_FillLine 1 -#define PathSeg_StrokeLine 2 -#define PathSeg_FillCubic 3 -#define PathSeg_StrokeCubic 4 -#define PathSeg_size 48 +#define PathSeg_FillCubic 1 +#define PathSeg_StrokeCubic 2 +#define PathSeg_size 44 PathSegRef PathSeg_index(PathSegRef ref, uint index) { return PathSegRef(ref.offset + index * PathSeg_size); } -PathFillLine PathFillLine_read(Alloc a, PathFillLineRef 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); - PathFillLine s; - s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); - s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); - s.path_ix = raw4; - return s; -} - -void PathFillLine_write(Alloc a, PathFillLineRef ref, PathFillLine 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, s.path_ix); -} - -PathStrokeLine PathStrokeLine_read(Alloc a, PathStrokeLineRef 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); - PathStrokeLine s; - s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1)); - s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3)); - s.path_ix = raw4; - s.stroke = vec2(uintBitsToFloat(raw5), uintBitsToFloat(raw6)); - return s; -} - -void PathStrokeLine_write(Alloc a, PathStrokeLineRef ref, PathStrokeLine 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, s.path_ix); - write_mem(a, ix + 5, floatBitsToUint(s.stroke.x)); - write_mem(a, ix + 6, floatBitsToUint(s.stroke.y)); -} - PathFillCubic PathFillCubic_read(Alloc a, PathFillCubicRef ref) { uint ix = ref.offset >> 2; uint raw0 = read_mem(a, ix + 0); @@ -148,13 +62,12 @@ PathFillCubic PathFillCubic_read(Alloc a, PathFillCubicRef ref) { 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); 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.succ_ix = raw6; + s.path_ix = raw7; return s; } @@ -166,9 +79,8 @@ void PathFillCubic_write(Alloc a, PathFillCubicRef ref, PathFillCubic s) { 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 + 6, s.succ_ix); + write_mem(a, ix + 7, s.path_ix); } PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) { @@ -183,14 +95,13 @@ PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) { uint raw7 = read_mem(a, ix + 7); uint raw8 = read_mem(a, ix + 8); uint raw9 = read_mem(a, ix + 9); - uint raw10 = read_mem(a, ix + 10); PathStrokeCubic 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.stroke = vec2(uintBitsToFloat(raw9), uintBitsToFloat(raw10)); + s.succ_ix = raw6; + s.path_ix = raw7; + s.stroke = vec2(uintBitsToFloat(raw8), uintBitsToFloat(raw9)); return s; } @@ -202,25 +113,16 @@ void PathStrokeCubic_write(Alloc a, PathStrokeCubicRef ref, PathStrokeCubic s) { 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, floatBitsToUint(s.stroke.x)); - write_mem(a, ix + 10, floatBitsToUint(s.stroke.y)); + write_mem(a, ix + 6, s.succ_ix); + write_mem(a, ix + 7, s.path_ix); + write_mem(a, ix + 8, floatBitsToUint(s.stroke.x)); + write_mem(a, ix + 9, floatBitsToUint(s.stroke.y)); } uint PathSeg_tag(Alloc a, PathSegRef ref) { return read_mem(a, ref.offset >> 2); } -PathFillLine PathSeg_FillLine_read(Alloc a, PathSegRef ref) { - return PathFillLine_read(a, PathFillLineRef(ref.offset + 4)); -} - -PathStrokeLine PathSeg_StrokeLine_read(Alloc a, PathSegRef ref) { - return PathStrokeLine_read(a, PathStrokeLineRef(ref.offset + 4)); -} - PathFillCubic PathSeg_FillCubic_read(Alloc a, PathSegRef ref) { return PathFillCubic_read(a, PathFillCubicRef(ref.offset + 4)); } @@ -233,16 +135,6 @@ void PathSeg_Nop_write(Alloc a, PathSegRef ref) { write_mem(a, ref.offset >> 2, PathSeg_Nop); } -void PathSeg_FillLine_write(Alloc a, PathSegRef ref, PathFillLine s) { - write_mem(a, ref.offset >> 2, PathSeg_FillLine); - PathFillLine_write(a, PathFillLineRef(ref.offset + 4), s); -} - -void PathSeg_StrokeLine_write(Alloc a, PathSegRef ref, PathStrokeLine s) { - write_mem(a, ref.offset >> 2, PathSeg_StrokeLine); - PathStrokeLine_write(a, PathStrokeLineRef(ref.offset + 4), s); -} - 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); diff --git a/gpu/shaders/state.h b/gpu/shaders/state.h index 8479dcf2..d86b8279 100644 --- a/gpu/shaders/state.h +++ b/gpu/shaders/state.h @@ -10,13 +10,14 @@ struct State { vec4 mat; vec2 translate; vec4 bbox; + uint tail; float linewidth; uint flags; uint path_count; uint pathseg_count; }; -#define State_size 56 +#define State_size 60 StateRef State_index(StateRef ref, uint index) { return StateRef(ref.offset + index * State_size); @@ -38,14 +39,16 @@ State State_read(StateRef ref) { uint raw11 = state[ix + 11]; uint raw12 = state[ix + 12]; uint raw13 = state[ix + 13]; + uint raw14 = state[ix + 14]; State s; s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3)); s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); s.bbox = vec4(uintBitsToFloat(raw6), uintBitsToFloat(raw7), uintBitsToFloat(raw8), uintBitsToFloat(raw9)); - s.linewidth = uintBitsToFloat(raw10); - s.flags = raw11; - s.path_count = raw12; - s.pathseg_count = raw13; + s.tail = raw10; + s.linewidth = uintBitsToFloat(raw11); + s.flags = raw12; + s.path_count = raw13; + s.pathseg_count = raw14; return s; } @@ -61,9 +64,10 @@ void State_write(StateRef ref, State s) { state[ix + 7] = floatBitsToUint(s.bbox.y); state[ix + 8] = floatBitsToUint(s.bbox.z); state[ix + 9] = floatBitsToUint(s.bbox.w); - state[ix + 10] = floatBitsToUint(s.linewidth); - state[ix + 11] = s.flags; - state[ix + 12] = s.path_count; - state[ix + 13] = s.pathseg_count; + state[ix + 10] = s.tail; + state[ix + 11] = floatBitsToUint(s.linewidth); + state[ix + 12] = s.flags; + state[ix + 13] = s.path_count; + state[ix + 14] = s.pathseg_count; }