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