From 7118c8efc19df2e3682fb027cee6d8b391a6082e Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Tue, 9 Jun 2020 10:25:22 -0700 Subject: [PATCH] Fix backdrop of segments to left of viewport Make sure we account for backdrop in segments clipped out of viewport. --- piet-gpu-hal/src/vulkan.rs | 2 +- piet-gpu/shader/path_coarse.comp | 31 ++++++++++++++++++------------- piet-gpu/shader/path_coarse.spv | Bin 20364 -> 20828 bytes 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/piet-gpu-hal/src/vulkan.rs b/piet-gpu-hal/src/vulkan.rs index 2fac015..29d4fd3 100644 --- a/piet-gpu-hal/src/vulkan.rs +++ b/piet-gpu-hal/src/vulkan.rs @@ -1016,7 +1016,7 @@ unsafe fn choose_compute_device( devices: &[vk::PhysicalDevice], surface: Option<&VkSurface>, ) -> Option<(vk::PhysicalDevice, u32)> { - for pdevice in devices { + for pdevice in &devices[0..] { let props = instance.get_physical_device_queue_family_properties(*pdevice); for (ix, info) in props.iter().enumerate() { // Check for surface presentation support diff --git a/piet-gpu/shader/path_coarse.comp b/piet-gpu/shader/path_coarse.comp index 0b3bc8f..f587079 100644 --- a/piet-gpu/shader/path_coarse.comp +++ b/piet-gpu/shader/path_coarse.comp @@ -108,6 +108,12 @@ void main() { uint width = uint(x1 - x0); sh_width[th_ix] = width; uint draw_width = min(width, uint(1.0 + ceil(2.0 * c))); + if (draw_width == 0 && bbox.x == 0 && bbox.z > 0) { + // Create opportunity to draw backdrop for segments to the left of viewport. + // Note: predicate can be strengthened to exclude segments that don't cross + // a horizontal tile boundary. + draw_width = 1; + } sh_draw_width[th_ix] = draw_width; uint tile_count = draw_width * uint(y1 - y0); @@ -148,25 +154,24 @@ void main() { int xx0 = clamp(int(floor(t - c)), x0, x1); int xx1 = clamp(int(ceil(t + c)), x0, x1); int x = xx0 + dx; + vec2 tile_xy = vec2(x * TILE_WIDTH_PX, y * TILE_HEIGHT_PX); + vec2 p0 = sh_p0[el_ix]; + vec2 p1 = sh_p1[el_ix]; + uint tile_el = (sh_base[el_ix] + uint(y * sh_stride[el_ix] + x) * Tile_size) >> 2; + if (sh_tag[el_ix] == PathSeg_FillLine && dx == 0 && min(p0.y, p1.y) <= tile_xy.y) { + int xray = max(int(ceil(t - 0.5 * b)), x0); + if (xray < sh_bbox_x1[el_ix]) { + int backdrop = p1.y < p0.y ? 1 : -1; + atomicAdd(tile[tile_el + 1 + 2 * (xray - x)], backdrop); + } + } + if (x < xx1) { uint tile_offset = alloc_start + ix * TileSeg_size; - uint tile_el = (sh_base[el_ix] + uint(y * sh_stride[el_ix] + x) * Tile_size) >> 2; uint old = atomicExchange(tile[tile_el], tile_offset); TileSeg tile_seg; - vec2 p0 = sh_p0[el_ix]; - vec2 p1 = sh_p1[el_ix]; float y_edge = 0.0; if (sh_tag[el_ix] == PathSeg_FillLine) { - vec2 tile_xy = vec2(x * TILE_WIDTH_PX, y * TILE_HEIGHT_PX); - if (dx == 0 && min(p0.y, p1.y) <= tile_xy.y) { - // TODO: need a little more work to make sure this triggers even - // when line is to the left of bbox. - int xray = max(int(ceil(t - 0.5 * b)), x0); - if (xray < sh_bbox_x1[el_ix]) { - int backdrop = p1.y < p0.y ? 1 : -1; - atomicAdd(tile[tile_el + 1 + 2 * (xray - x)], backdrop); - } - } y_edge = mix(p0.y, p1.y, (tile_xy.x - p0.x) / (p1.x - p0.x)); if (min(p0.x, p1.x) < tile_xy.x && y_edge >= tile_xy.y && y_edge < tile_xy.y + TILE_HEIGHT_PX) { if (p0.x > p1.x) { diff --git a/piet-gpu/shader/path_coarse.spv b/piet-gpu/shader/path_coarse.spv index 8c4801be420d2b7e76c75b50b16adb706dc56b66..a4db461ccbb1ba2d62df7cf8951015d7a3d2256d 100644 GIT binary patch literal 20828 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 literal 20364 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