Skip to content

Blur can sample unwritten pixels during partial repaint #3113

Description

@dmrlsn

Wayfire version

0.12.0-4c34a7bf (current master)

wlroots 0.20.2 from the Wayfire submodule.

The issue is also present in Wayfire 0.11.0.

GPU / Driver

Apple M2
Mesa 26.1.6
EGL driver: asahi
OpenGL ES 3.2

Describe the bug

With blur enabled, a magenta line can appear along the edge of a blurred
window.

I can reproduce it on current master with a minimal config.

The problem seems to be in partial rendering of the intermediate blur
buffers. render_iteration() allocates the output buffer but only renders
the current blur_region. A later blur pass can sample a one-pixel band
outside that region.

On Asahi that unwritten band is visible as magenta. On an NVIDIA system I
tested, the same pixels read back as transparent black, so the problem is
not normally visible there.

To Reproduce

Minimal config:

[output:eDP-1]
mode = 2560x1664@60000
position = 0,0
transform = normal
scale = 1.6

[core]
plugins = autostart command foreign-toplevel wayfire-shell wm-actions blur
preferred_decoration_mode = client

[autostart]
autostart_wf_shell = true

[command]
binding_terminal = <super> KEY_ENTER
command_terminal = foot

[wm-actions]
toggle_maximize = <super> KEY_M

[blur]
blur_by_default = type is "toplevel"
alpha_threshold = 0.10
alpha_exponent = 1.0
method = kawase
kawase_degrade = 10
kawase_iterations = 2
kawase_offset = 1.7
saturation = 3.0
toggle = none
  1. Start Wayfire.
  2. Open foot.
  3. Maximize the window.
  4. A magenta band is visible near the top edge of the blurred window.

Expected behavior

The blur should not sample pixels which were not rendered into the
intermediate buffer.

Screenshots / Videos / Stacktrace

Attached:

  • current master, stock blur: magenta edge visible
  • current master with the two-line guard-band change: edge is gone

Additional context

I did a few tests to check what was being sampled.

For the affected pass, the blur region starts at row 1 of a 256x162
intermediate buffer. Row 0 is therefore not written by that pass.

On the M2, reading that row before and after the draw gives:

before:     255,0,255,255
after_draw: 255,0,255,255

With ASAHI_MESA_DEBUG=nocompress:

before:     0,0,0,0
after_draw: 0,0,0,0

and the visible magenta edge disappears.

I also reproduced the same geometry on an NVIDIA RTX 2070 SUPER. The
unwritten row reads as 0,0,0,0 there. If I explicitly fill that row red
before the blur pass, the red is propagated by the blur on both GPUs.

Expanding the region by one pixel before scissoring fixes the problem in
my tests:

blur_region.expand_edges(1);
blur_region &= wlr_box{0, 0, width, height};

I tested the same change with Kawase, Gaussian and Box blur.

Image Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions