diff --git a/draw/backdrop.odin b/draw/backdrop.odin index fb22c79..44f1bf6 100644 --- a/draw/backdrop.odin +++ b/draw/backdrop.odin @@ -765,11 +765,14 @@ compute_backdrop_group_work_region :: proc( max_x += halo_logical max_y += halo_logical - // Convert to physical pixels and clamp to swapchain bounds. - phys_min_x := math.max(min_x * dpi, 0) - phys_min_y := math.max(min_y * dpi, 0) - phys_max_x := math.min(max_x * dpi, f32(swapchain_width)) - phys_max_y := math.min(max_y * dpi, f32(swapchain_height)) + // Clamp the min corner to 0, but let the max corner's 6σ halo extend past the swapchain edge + // into the working texture's unused area (at factor > 1), capped to the texture extent. Keeps + // the composite's bilinear upsample off the unwritten texels just past a clamped edge. + downsample_factor := compute_backdrop_downsample_factor(sigma_logical) + phys_min_x := max(min_x * dpi, 0) + phys_min_y := max(min_y * dpi, 0) + phys_max_x := min(max_x * dpi, f32(swapchain_width * downsample_factor)) + phys_max_y := min(max_y * dpi, f32(swapchain_height * downsample_factor)) if phys_max_x <= phys_min_x || phys_max_y <= phys_min_y do return 0, 0, 0, 0 @@ -868,12 +871,18 @@ run_backdrop_bracket :: proc( working_w := (region_w + downsample_factor - 1) / downsample_factor working_h := (region_h + downsample_factor - 1) / downsample_factor - // Working textures are sized at min factor (2). At factor=4 we have only half the texture - // area available in each axis. Clamp to the texture extent for either case. - wt_w := pipeline.cached_width / downsample_factor - wt_h := pipeline.cached_height / downsample_factor - if working_x + working_w > wt_w do working_w = wt_w - working_x - if working_y + working_h > wt_h do working_h = wt_h - working_y + // Clamp to the full texture extent (not cached/factor): the working textures are full + // swapchain res, so a factor-N group's halo can spill into the unused remainder. Writing it + // keeps the composite's bilinear upsample off unwritten texels at the right/bottom edge. + texture_width := pipeline.cached_width + texture_height := pipeline.cached_height + // Skip fully off-screen groups; also guards the unsigned clamps below from underflow. + if working_x >= texture_width || working_y >= texture_height { + i = group_end + continue + } + if working_x + working_w > texture_width do working_w = texture_width - working_x + if working_y + working_h > texture_height do working_h = texture_height - working_y if working_w == 0 || working_h == 0 { i = group_end continue