blob: 0804c8f12d8274d32856ddd7c694e92068c9591e [file] [log] [blame]
// 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);
}