| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #extension GL_KHR_shader_subgroup_arithmetic : enable | |
| layout(local_size_x = 256, local_size_y = 1) in; | |
| layout(std430) buffer; | |
| #include <impeller/path.glsl> | |
| layout(binding = 0) readonly buffer Cubics { | |
| uint count; | |
| CubicData data[]; | |
| } | |
| cubics; | |
| layout(binding = 1) buffer Quads { | |
| uint count; | |
| QuadData data[]; | |
| } | |
| quads; | |
| layout(binding = 2) buffer Lines { | |
| uint count; | |
| LineData data[]; | |
| } | |
| lines; | |
| layout(binding = 3) buffer Components { | |
| uint count; | |
| PathComponent data[]; | |
| } | |
| components; | |
| layout(binding = 4) buffer Polyline { | |
| uint count; | |
| vec2 data[]; | |
| } | |
| polyline; | |
| uniform Config { | |
| float cubic_accuracy; | |
| float quad_tolerance; | |
| } | |
| config; | |
| shared uvec2 cubic_ranges[512]; | |
| shared uvec2 quad_ranges[512]; | |
| shared uint scratch_count[512]; | |
| shared uint scratch_sum[512]; | |
| uint ComputePosition(uint index) { | |
| uint sum = scratch_sum[index]; | |
| for (uint position = gl_SubgroupSize - 1; position < index; | |
| position += gl_SubgroupSize) { | |
| sum += scratch_sum[position] + scratch_count[position]; | |
| } | |
| return sum; | |
| } | |
| void ProcessCubic(uint ident) { | |
| CubicData cubic; | |
| uint quad_count = 0; | |
| if (ident < cubics.count) { | |
| cubic = cubics.data[ident]; | |
| quad_count = EstimateQuadraticCount(cubic, config.cubic_accuracy); | |
| scratch_count[ident] = quad_count; | |
| } | |
| barrier(); | |
| uint offset = 0; | |
| if (quad_count > 0) { | |
| scratch_sum[ident] = subgroupExclusiveAdd(scratch_count[ident]); | |
| offset = ComputePosition(ident) + quads.count; | |
| } | |
| barrier(); | |
| if (quad_count > 0) { | |
| atomicAdd(quads.count, quad_count); | |
| cubic_ranges[ident] = uvec2(offset, quad_count); | |
| for (uint i = 0; i < quad_count; i++) { | |
| quads.data[offset + i] = GenerateQuadraticFromCubic(cubic, i, quad_count); | |
| } | |
| } | |
| } | |
| void ProcessQuad(uint ident) { | |
| QuadData quad; | |
| QuadDecomposition decomposition; | |
| if (ident < quads.count) { | |
| quad = quads.data[ident]; | |
| decomposition = DecomposeQuad(quad, config.quad_tolerance); | |
| scratch_count[ident] = decomposition.line_count; | |
| } | |
| barrier(); | |
| uint offset = 0; | |
| if (decomposition.line_count > 0) { | |
| scratch_sum[ident] = subgroupExclusiveAdd(scratch_count[ident]); | |
| offset = ComputePosition(ident) + lines.count; | |
| } | |
| barrier(); | |
| if (decomposition.line_count > 0) { | |
| atomicAdd(lines.count, decomposition.line_count); | |
| quad_ranges[ident] = uvec2(offset, decomposition.line_count); | |
| vec2 last_point = quad.p1; | |
| for (uint i = 1; i < decomposition.line_count; i++) { | |
| LineData line = | |
| LineData(last_point, GenerateLineFromQuad(quad, i, decomposition)); | |
| last_point = line.p2; | |
| lines.data[offset + i - 1] = line; | |
| } | |
| lines.data[offset + decomposition.line_count - 1] = | |
| LineData(last_point, quad.p2); | |
| } | |
| } | |
| void ProcessLine(uint ident) { | |
| if (ident == 0) { | |
| polyline.count = lines.count + 1; | |
| } | |
| PathComponent component; | |
| uvec2 range = uvec2(0, 0); | |
| if (ident < components.count) { | |
| component = components.data[ident]; | |
| if (component.count == 4) { | |
| // Determine location in quads | |
| uvec2 quad_range = cubic_ranges[component.index]; | |
| uvec2 end_range = quad_ranges[quad_range.x + quad_range.y - 1]; | |
| range.x = quad_ranges[quad_range.x].x; | |
| range.y = end_range.x + end_range.y - range.x; | |
| } else if (component.count == 3) { | |
| range = quad_ranges[component.index]; | |
| } else if (component.count == 2) { | |
| range = uvec2(component.index, 1); | |
| } | |
| scratch_count[ident] = range.y; | |
| } | |
| barrier(); | |
| if (ident < components.count) { | |
| scratch_sum[ident] = subgroupExclusiveAdd(scratch_count[ident]); | |
| uint offset = ComputePosition(ident); | |
| polyline.data[offset] = lines.data[range.x].p1; | |
| for (uint i = 0; i < range.y; i++) { | |
| polyline.data[offset + i + 1] = lines.data[range.x + i].p2; | |
| } | |
| } | |
| } | |
| void main() { | |
| uint ident = gl_GlobalInvocationID.x; | |
| // Turn each cubic into quads. | |
| ProcessCubic(ident); | |
| barrier(); | |
| // Turn each quad into lines. | |
| ProcessQuad(ident); | |
| barrier(); | |
| // Copy lines to the output buffer. | |
| ProcessLine(ident); | |
| } |