Skip to content

renderer/utils: queue surface damage when the alpha multiplier changes#2064

Open
gaoyia wants to merge 1 commit into
Smithay:masterfrom
gaoyia:patch-1
Open

renderer/utils: queue surface damage when the alpha multiplier changes#2064
gaoyia wants to merge 1 commit into
Smithay:masterfrom
gaoyia:patch-1

Conversation

@gaoyia

@gaoyia gaoyia commented Jun 12, 2026

Copy link
Copy Markdown

Summary

  • Track the last seen wp_alpha_modifier multiplier in RendererSurfaceState and queue full-surface damage from update_buffer() when it changed, so compositors using OutputDamageTracker repaint surfaces whose commit only carries a new multiplier.

Problem

WaylandSurfaceRenderElement applies AlphaModifierSurfaceCachedState at draw time, but its Element::current_commit() is tied to buffer DamageBag updates only.

When a client:

  1. calls wp_alpha_modifier_surface_v1.set_multiplier, then
  2. commits wl_surface without attaching a new buffer or sending wl_surface.damage,

the cached multiplier updates correctly, yet OutputDamageTracker sees no new damage for that element and may skip redrawing it. The on-screen pixels keep the previous opacity.

This is visible with any client that drives opacity through wp_alpha_modifier (or Chromium’s zcr_alpha_compositing extension) on an incremental KMS/GL compositor.

Solution

All in backend/renderer/utils/wayland.rs:

  • Add RendererSurfaceState::alpha_multiplier storing the multiplier that was current at the last commit (reset together with the rest of the state).
  • In update_buffer() — which on_commit_buffer_handler runs for every surface in the tree on each commit — read AlphaModifierSurfaceCachedState::multiplier() from the current (post-merge) state and compare it with the stored value. On change, add a full-buffer rectangle to the surface DamageBag.

Queueing the damage at commit time (rather than when the set_multiplier request arrives) matches the double-buffered semantics of the protocol: the multiplier only takes effect on wl_surface.commit, and that is exactly when the damage is now recorded. Compositors need no extra calls; on_commit_buffer_handler covers everything, including a multiplier set before the first buffer attach (the first buffer commit damages the whole surface anyway).

Alternatives considered

  • Queue damage from the set_multiplier request handler — simpler, but races with rendering: a frame drawn between the request and the commit consumes the damage while the old multiplier is still active, reintroducing the stale-opacity bug.
  • Bump WaylandSurfaceRenderElement::current_commit directly when the multiplier changes — affects all compositors’ damage semantics and still needs commit-time tracking.
  • Force full-output redraw on every commit — correct but defeats incremental damage tracking.

Test plan

  • Build smithay with wayland_frontend + backend_egl (or your compositor feature set).
  • Run a compositor that registers AlphaModifierState and uses OutputDamageTracker (e.g. Anvil, or a minimal test compositor).
  • Use a client that:
    • attaches an opaque wl_shm buffer,
    • binds wp_alpha_modifier_surface_v1,
    • calls set_multiplier to u32::MAX / 2,
    • commits without wl_surface.damage or re-attach.
  • Before this patch: surface opacity unchanged on screen.
  • After this patch: surface appears semi-transparent over the desktop.
  • Repeat with set_multiplier(u32::MAX) and destroy to confirm return to opaque / default.

Optional: WAYLAND_DEBUG=1 and verify set_multiplier is received; no protocol changes.

Related

  • wp_alpha_modifier staging protocol — multiplier is double-buffered on wl_surface.commit.
  • Chromium zcr_alpha_compositing_v1 — same rendering path via AlphaModifierSurfaceCachedState in downstream compositors that bridge the extension.

@gaoyia gaoyia changed the title Upstream PR: alpha modifier incremental damage renderer/utils: queue surface damage when the alpha multiplier changes Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant