// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Also licensed under MIT license, at your choice. // This is a cut'n'paste w/ backdrop. struct Tile { backdrop: i32, segments: u32, } {{> segment}} {{> config}} @group(0) @binding(0) var config: Config; @group(0) @binding(1) var tiles: array; @group(0) @binding(2) var segments: array; // This will become a texture, but keeping things simple for now @group(0) @binding(3) var output: array; let PIXELS_PER_THREAD = 4u; @compute @workgroup_size(4, 16) fn main( @builtin(global_invocation_id) global_id: vec3, @builtin(local_invocation_id) local_id: vec3, @builtin(workgroup_id) wg_id: vec3, ) { let tile_ix = wg_id.y * config.width_in_tiles + wg_id.x; let xy = vec2(f32(global_id.x * PIXELS_PER_THREAD), f32(global_id.y)); let tile = tiles[tile_ix]; var area: array; let backdrop_f = f32(tile.backdrop); for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) { area[i] = backdrop_f; } var segment_ix = tile.segments; while segment_ix != 0u { let segment = segments[segment_ix]; let y = segment.origin.y - xy.y; let y0 = clamp(y, 0.0, 1.0); let y1 = clamp(y + segment.delta.y, 0.0, 1.0); let dy = y0 - y1; if dy != 0.0 { let vec_y_recip = 1.0 / segment.delta.y; let t0 = (y0 - y) * vec_y_recip; let t1 = (y1 - y) * vec_y_recip; let startx = segment.origin.x - xy.x; let x0 = startx + t0 * segment.delta.x; let x1 = startx + t1 * segment.delta.x; let xmin0 = min(x0, x1); let xmax0 = max(x0, x1); for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) { let i_f = f32(i); let xmin = min(xmin0 - i_f, 1.0) - 1.0e-6; let xmax = xmax0 - i_f; let b = min(xmax, 1.0); let c = max(b, 0.0); let d = max(xmin, 0.0); let a = (b + 0.5 * (d * d - c * c) - xmin) / (xmax - xmin); area[i] += a * dy; } } let y_edge = sign(segment.delta.x) * clamp(xy.y - segment.y_edge + 1.0, 0.0, 1.0); for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) { area[i] += y_edge; } segment_ix = segment.next; } // nonzero winding rule for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) { area[i] = abs(area[i]); } let bytes = pack4x8unorm(vec4(area[0], area[1], area[2], area[3])); let out_ix = global_id.y * (config.width_in_tiles * 4u) + global_id.x; output[out_ix] = bytes; }