diff --git a/gpu/compute.go b/gpu/compute.go index 0ab2f23b..efad666e 100644 --- a/gpu/compute.go +++ b/gpu/compute.go @@ -173,16 +173,12 @@ const ( pathSize = 12 binSize = 8 - pathsegSize = 44 + pathsegSize = 48 annoSize = 28 - stateSize = 60 + stateSize = 56 stateStride = 4 + 2*stateSize ) -const ( - flagEndPath = 16 // FLAG_END_PATH from elements.comp -) - // mem.h constants. const ( memNoError = 0 // NO_ERROR @@ -680,49 +676,14 @@ func encodePath(pathData []byte, stroke clip.StrokeStyle, dashes dashOp) encoder q := quad.quad enc.quad(q.From, q.Ctrl, q.To, false) } - if len(quads) > 0 { - enc.scene[len(enc.scene)-1][0] |= (flagEndPath << 16) - } return enc } - var ( - prevTo f32.Point - hasPrev bool - ) for len(pathData) >= scene.CommandSize+4 { cmd := ops.DecodeCommand(pathData[4:]) - switch cmd.Op() { - case scene.OpFillLine: - from, to := scene.DecodeLine(cmd) - if hasPrev && from != prevTo { - enc.scene[len(enc.scene)-1][0] |= (flagEndPath << 16) - } - hasPrev = true - prevTo = to - case scene.OpFillQuad: - from, _, to := scene.DecodeQuad(cmd) - if hasPrev && from != prevTo { - enc.scene[len(enc.scene)-1][0] |= (flagEndPath << 16) - } - hasPrev = true - prevTo = to - case scene.OpFillCubic: - from, _, _, to := scene.DecodeCubic(cmd) - if hasPrev && from != prevTo { - enc.scene[len(enc.scene)-1][0] |= (flagEndPath << 16) - } - hasPrev = true - prevTo = to - default: - panic("unsupported path scene command") - } enc.scene = append(enc.scene, cmd) enc.npathseg++ pathData = pathData[scene.CommandSize+4:] } - if hasPrev { - enc.scene[len(enc.scene)-1][0] |= (flagEndPath << 16) - } return enc } @@ -1049,10 +1010,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, 0) - e.line(c1, c2, stroke, 0) - e.line(c2, c3, stroke, 0) - e.line(c3, c0, stroke, flagEndPath) + e.line(c0, c1, stroke) + e.line(c1, c2, stroke) + e.line(c2, c3, stroke) + e.line(c3, c0, stroke) } func (e *encoder) fill(col color.RGBA) { @@ -1071,8 +1032,8 @@ func (e *encoder) fillImage(index int) { e.npath++ } -func (e *encoder) line(start, end f32.Point, stroke bool, flags uint32) { - e.scene = append(e.scene, scene.Line(start, end, stroke, flags)) +func (e *encoder) line(start, end f32.Point, stroke bool) { + e.scene = append(e.scene, scene.Line(start, end, stroke)) e.npathseg++ } diff --git a/gpu/gpu.go b/gpu/gpu.go index 65686ce1..626c8535 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -1506,16 +1506,16 @@ func (d *drawOps) boundsForTransformedRect(r f32.Rectangle, tr f32.Affine2D) (au buf := aux bo := binary.LittleEndian bo.PutUint32(buf, 0) // Contour - ops.EncodeCommand(buf[4:], scene.Line(r.Min, f32.Pt(r.Max.X, r.Min.Y), false, 0)) + ops.EncodeCommand(buf[4:], scene.Line(r.Min, f32.Pt(r.Max.X, r.Min.Y), false)) buf = buf[4+scene.CommandSize:] bo.PutUint32(buf, 0) - ops.EncodeCommand(buf[4:], scene.Line(f32.Pt(r.Max.X, r.Min.Y), r.Max, false, 0)) + ops.EncodeCommand(buf[4:], scene.Line(f32.Pt(r.Max.X, r.Min.Y), r.Max, false)) buf = buf[4+scene.CommandSize:] bo.PutUint32(buf, 0) - ops.EncodeCommand(buf[4:], scene.Line(r.Max, f32.Pt(r.Min.X, r.Max.Y), false, 0)) + ops.EncodeCommand(buf[4:], scene.Line(r.Max, f32.Pt(r.Min.X, r.Max.Y), false)) buf = buf[4+scene.CommandSize:] bo.PutUint32(buf, 0) - ops.EncodeCommand(buf[4:], scene.Line(f32.Pt(r.Min.X, r.Max.Y), r.Min, false, 0)) + ops.EncodeCommand(buf[4:], scene.Line(f32.Pt(r.Min.X, r.Max.Y), r.Min, false)) } // establish the transform mapping from bounds rectangle to transformed corners diff --git a/gpu/shaders.go b/gpu/shaders.go index 4ef02174..4004ed24 100644 --- a/gpu/shaders.go +++ b/gpu/shaders.go @@ -139,7 +139,7 @@ var ( } shader_elements_comp = driver.ShaderSources{ Name: "elements.comp", - GLSL310ES: "#version 310 es\nlayout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct ElementRef\n{\n uint offset;\n};\n\nstruct LineSegRef\n{\n uint offset;\n};\n\nstruct LineSeg\n{\n vec2 p0;\n vec2 p1;\n};\n\nstruct QuadSegRef\n{\n uint offset;\n};\n\nstruct QuadSeg\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n};\n\nstruct CubicSegRef\n{\n uint offset;\n};\n\nstruct CubicSeg\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n vec2 p3;\n};\n\nstruct FillRef\n{\n uint offset;\n};\n\nstruct Fill\n{\n uint rgba_color;\n};\n\nstruct FillImageRef\n{\n uint offset;\n};\n\nstruct FillImage\n{\n uint index;\n ivec2 offset;\n};\n\nstruct StrokeRef\n{\n uint offset;\n};\n\nstruct Stroke\n{\n uint rgba_color;\n};\n\nstruct SetLineWidthRef\n{\n uint offset;\n};\n\nstruct SetLineWidth\n{\n float width;\n};\n\nstruct TransformRef\n{\n uint offset;\n};\n\nstruct Transform\n{\n vec4 mat;\n vec2 translate;\n};\n\nstruct ClipRef\n{\n uint offset;\n};\n\nstruct Clip\n{\n vec4 bbox;\n};\n\nstruct StateRef\n{\n uint offset;\n};\n\nstruct State\n{\n vec4 mat;\n vec2 translate;\n vec4 bbox;\n 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", + 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) ? 1 : 2);\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) ? 1 : 2);\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) ? 1 : 2);\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", } shader_intersect_frag = driver.ShaderSources{ Name: "intersect.frag", @@ -188,7 +188,7 @@ var ( } shader_path_coarse_comp = driver.ShaderSources{ Name: "path_coarse.comp", - GLSL310ES: "#version 310 es\nlayout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in;\n\nstruct Alloc\n{\n uint offset;\n};\n\nstruct MallocResult\n{\n Alloc alloc;\n bool failed;\n};\n\nstruct PathStrokeCubicRef\n{\n uint offset;\n};\n\nstruct PathStrokeCubic\n{\n vec2 p0;\n vec2 p1;\n vec2 p2;\n 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", + 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 1u:\n case 2u:\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 == 1u;\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 == 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_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", } shader_stencil_frag = driver.ShaderSources{ Name: "stencil.frag", diff --git a/gpu/shaders/elements.comp b/gpu/shaders/elements.comp index f58d805d..2cf725d5 100644 --- a/gpu/shaders/elements.comp +++ b/gpu/shaders/elements.comp @@ -62,8 +62,6 @@ 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) @@ -89,45 +87,32 @@ 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 | FLAG_START_PATH)) | b.flags; + c.flags = (a.flags & (FLAG_SET_LINEWIDTH | FLAG_SET_BBOX)) | 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_flags = Element_tag(ref); + uint tag = 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; - // flags contain FLAG_END_PATH for segments last in their path. - uint flags = tag_flags >> 16; - switch (tag_flags & 0xffff) { + switch (tag) { 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: @@ -135,7 +120,6 @@ 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: @@ -143,7 +127,6 @@ 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: @@ -183,7 +166,6 @@ 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]; @@ -218,7 +200,6 @@ 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; @@ -232,7 +213,6 @@ 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); @@ -243,7 +223,6 @@ 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; } @@ -254,7 +233,6 @@ 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; @@ -334,7 +312,6 @@ 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); @@ -346,9 +323,7 @@ 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_flags = Element_tag(this_ref); - uint tag = tag_flags & 0xffff; - uint flags = tag_flags >> 16; + uint tag = Element_tag(this_ref); switch (tag) { case Element_FillLine: case Element_StrokeLine: @@ -359,7 +334,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.succ_ix = (flags & FLAG_END_PATH) == 0 ? st.pathseg_count : st.tail; + path_cubic.p3 = p1; path_cubic.path_ix = st.path_count; if (tag == Element_StrokeLine) { path_cubic.stroke = get_linewidth(st); @@ -383,7 +358,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.succ_ix = (flags & FLAG_END_PATH) == 0 ? st.pathseg_count : st.tail; + path_cubic.p3 = p2; path_cubic.path_ix = st.path_count; if (tag == Element_StrokeQuad) { path_cubic.stroke = get_linewidth(st); @@ -404,7 +379,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.succ_ix = (flags & FLAG_END_PATH) == 0 ? st.pathseg_count : st.tail; + path_cubic.p3 = st.mat.xy * cubic.p3.x + st.mat.zw * cubic.p3.y + st.translate; 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 d843945e..4f77ff9b 100644 --- a/gpu/shaders/path_coarse.comp +++ b/gpu/shaders/path_coarse.comp @@ -86,14 +86,6 @@ 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; @@ -110,9 +102,7 @@ void main() { case PathSeg_FillCubic: case PathSeg_StrokeCubic: PathStrokeCubic cubic = PathSeg_StrokeCubic_read(conf.pathseg_alloc, ref); - 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; + vec2 err_v = 3.0 * (cubic.p2 - cubic.p1) + cubic.p0 - cubic.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); @@ -122,8 +112,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, p3, t); - vec2 qp1 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, p3, t - 0.5 * 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); qp1 = 2.0 * qp1 - 0.5 * (qp0 + qp2); SubdivResult params = estimate_subdiv(qp0, qp1, qp2, sqrt(REM_ACCURACY)); val += params.val; @@ -143,8 +133,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, p3, t); - vec2 qp1 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, p3, t - 0.5 * 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); 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); @@ -154,7 +144,7 @@ void main() { while (n_out == n || target < val_sum + params.val) { vec2 p1; if (n_out == n) { - p1 = p3; + p1 = cubic.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 d7326586..a1700900 100644 --- a/gpu/shaders/pathseg.h +++ b/gpu/shaders/pathseg.h @@ -18,11 +18,11 @@ struct PathFillCubic { vec2 p0; vec2 p1; vec2 p2; - uint succ_ix; + vec2 p3; uint path_ix; }; -#define PathFillCubic_size 32 +#define PathFillCubic_size 36 PathFillCubicRef PathFillCubic_index(PathFillCubicRef ref, uint index) { return PathFillCubicRef(ref.offset + index * PathFillCubic_size); @@ -32,12 +32,12 @@ struct PathStrokeCubic { vec2 p0; vec2 p1; vec2 p2; - uint succ_ix; + vec2 p3; uint path_ix; vec2 stroke; }; -#define PathStrokeCubic_size 40 +#define PathStrokeCubic_size 44 PathStrokeCubicRef PathStrokeCubic_index(PathStrokeCubicRef ref, uint index) { return PathStrokeCubicRef(ref.offset + index * PathStrokeCubic_size); @@ -46,7 +46,7 @@ PathStrokeCubicRef PathStrokeCubic_index(PathStrokeCubicRef ref, uint index) { #define PathSeg_Nop 0 #define PathSeg_FillCubic 1 #define PathSeg_StrokeCubic 2 -#define PathSeg_size 44 +#define PathSeg_size 48 PathSegRef PathSeg_index(PathSegRef ref, uint index) { return PathSegRef(ref.offset + index * PathSeg_size); @@ -62,12 +62,13 @@ 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.succ_ix = raw6; - s.path_ix = raw7; + s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7)); + s.path_ix = raw8; return s; } @@ -79,8 +80,9 @@ 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, s.succ_ix); - write_mem(a, ix + 7, s.path_ix); + 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); } PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) { @@ -95,13 +97,14 @@ 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.succ_ix = raw6; - s.path_ix = raw7; - s.stroke = vec2(uintBitsToFloat(raw8), uintBitsToFloat(raw9)); + s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7)); + s.path_ix = raw8; + s.stroke = vec2(uintBitsToFloat(raw9), uintBitsToFloat(raw10)); return s; } @@ -113,10 +116,11 @@ 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, 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)); + 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)); } uint PathSeg_tag(Alloc a, PathSegRef ref) { diff --git a/gpu/shaders/state.h b/gpu/shaders/state.h index d86b8279..8479dcf2 100644 --- a/gpu/shaders/state.h +++ b/gpu/shaders/state.h @@ -10,14 +10,13 @@ struct State { vec4 mat; vec2 translate; vec4 bbox; - uint tail; float linewidth; uint flags; uint path_count; uint pathseg_count; }; -#define State_size 60 +#define State_size 56 StateRef State_index(StateRef ref, uint index) { return StateRef(ref.offset + index * State_size); @@ -39,16 +38,14 @@ 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.tail = raw10; - s.linewidth = uintBitsToFloat(raw11); - s.flags = raw12; - s.path_count = raw13; - s.pathseg_count = raw14; + s.linewidth = uintBitsToFloat(raw10); + s.flags = raw11; + s.path_count = raw12; + s.pathseg_count = raw13; return s; } @@ -64,10 +61,9 @@ 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] = 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; + state[ix + 10] = floatBitsToUint(s.linewidth); + state[ix + 11] = s.flags; + state[ix + 12] = s.path_count; + state[ix + 13] = s.pathseg_count; } diff --git a/internal/scene/scene.go b/internal/scene/scene.go index 11717344..6c88d021 100644 --- a/internal/scene/scene.go +++ b/internal/scene/scene.go @@ -42,13 +42,13 @@ func (c Command) Op() Op { return Op(c[0]) } -func Line(start, end f32.Point, stroke bool, flags uint32) Command { +func Line(start, end f32.Point, stroke bool) Command { tag := uint32(OpFillLine) if stroke { tag = uint32(OpStrokeLine) } return Command{ - 0: flags<<16 | tag, + 0: tag, 1: math.Float32bits(start.X), 2: math.Float32bits(start.Y), 3: math.Float32bits(end.X), diff --git a/op/clip/clip.go b/op/clip/clip.go index 282142b5..14e348e2 100644 --- a/op/clip/clip.go +++ b/op/clip/clip.go @@ -141,7 +141,7 @@ func (p *Path) LineTo(to f32.Point) { data := p.ops.Write(scene.CommandSize + 4) bo := binary.LittleEndian bo.PutUint32(data[0:], uint32(p.contour)) - ops.EncodeCommand(data[4:], scene.Line(p.pen, to, false, 0)) + ops.EncodeCommand(data[4:], scene.Line(p.pen, to, false)) p.pen = to p.hasSegments = true }