Buffer Damage
Vlad Zahorodnii
vlad.zahorodnii at kde.org
Mon Jan 4 11:23:26 UTC 2021
Hi,
I've noticed that uploading data from shared client memory buffers to
textures hurts performance really bad in kwin. Sometimes, it takes about
40ms to attach a client buffer to a texture. Since most compositors
don't take any precautions of uploading the buffer data asynchronously,
you may also experience this problem with weston, sway, etc.
One way to prevent stalling the compositor is to apply the committed
state after updating the texture. In other words, when a surface is
committed, you enqueue the pending state and kick off an upload job on a
different thread. Once the upload job has completed, remove the cached
state from the queue and (depending on if it's a synchronized
sub-surface) apply it. This solution has a lot in common with how the
linux-explicit-synchronization protocol should be ideally implemented.
Another way to address this issue is to use PBOs. Even though they
drastically improve the performance, the resulting upload times are
still too high (at least that is the case on my machine).
The tricky thing about the queue-based solution is that every shared
memory client buffer will have to have its own texture and therefore
there must be some way to indicate the buffer damage. At the moment, if
a client feeds the compositor with shared memory client buffers, all
those buffers will be attached to a single texture and therefore the
surface damage is sort of (but not really) equivalent to the buffer damage.
Given that the wl_surface object has a method with a name of
damage_buffer, I should clarify what I mean by "surface damage" and
"buffer damage". A surface damage indicates the area of the surface that
has changed between two consecutive commits. A buffer damage is the area
of the buffer that has changed since last time it was used. To get more
detailed explanation of the difference between the surface damage and
the buffer damage, please refer to the EGL_KHR_partial_update spec.
wl_surface_damage() and wl_surface_damage_buffer() specify the surface
damage.
The compositor could keep the last N surface damages and then accumulate
them to get the buffer damage, but it's a heuristic, it doesn't always
produce the right results... It would be great if the wl_buffer
interface had a method to specify the buffer damage, e.g.
wl_buffer_damage(buffer, ... buffer_damage); <-- this one
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, ... surface_damage);
wl_surface_commit(surface);
The buffer damage and the surface damage are not the same and there is
no **strong** connection between the two, for example, if the buffer
damage is empty, it doesn't imply that the surface damage is also empty
(and vice versa). It can be the case if the client has pre-rendered N
buffers and simply cycles between them.
What is your opinion about buffer damage? Do you think it makes sense or
are there alternatives that don't require changing the core wayland
protocols?
Cheers,
Vlad
More information about the wayland-devel
mailing list