Overview
wlr_mirror
will render a box from the buffer of one output (src) on another output (dst). There may be many possible srcs during a mirror session.
Please see the accompanying sway pull request which implements via sway_mirror
.
The compositor is responsible for requesting mirror frames, during the ready signal handler, which is emitted at precommit for each src. The src and box may vary between frames.
The compositor must not attempt to render on dst during the mirror session. Initially, the compositor was forced to vacate via a wlr_output destroy signal, however that proved problematic and was abandoned.
There may be concurrent mirror sessions however they cannot share dst.
Transformation of src and dst is accounted for.
Cursor may be optionally renderered.
wlr_buffer_get_dmabuf
, wlr_texture_from_dmabuf
and wlr_render_subtexture_with_matrix
perform the heavy lifting.
Edit 2022/01/12: Content will be scaled to fit the width or height of dst.
Three methods of scaling the src box on dst are available: full, aspect and center:
Suggested Review Order
wlr_mirror.h
-
examples/mirror.c
- interesting parts commented, needs two physical outputs wlr_mirror.c
- sway implementation
Mirror Session
- compositor - invokes wlr_mirror_create
- mirror - subscribes to precommit for all srcs
- compositor - vacates dst
- ...
- compositor - invokes wlr_mirror_destroy
- mirror - debug logs some stats
- mirror - unsubscribes all listeners
- mirror - destroys any textures in flight
- mirror - emits destroy
- compositor (destroy) - reclaims dst
- mirror - frees
Mirror Frame Loop
- mirror (precommit) - emits ready for each src
- compositor (ready) - invokes wlr_mirror_request_box
- mirror - subscribes to above src's commit
- mirror (commit) - captures texture from dmabuf
- mirror (commit) - schedules dst frame
- mirror (frame) - transforms texture and renders
Abnormal Termination Conditions
- dst disabled/destroyed
- all srcs disabled/destroyed
-
wlr_mirror_request_box
invalid
Limitations
Only one dst per session
Additional dsts could be added with minimal effort.
srcs may only be removed during session
srcs will be removed when their output is disabled/destroyed, however new srcs may not be added.
Only one src box may be rendered for each dst frame
This prevents cases such as a floating window spanning multiple srcs, which appears to be a niche use case. This could be achieved via partial rendering of each src box on dst, or re-rendering of all subtextures each frame. Another request function such as the following could be added, along with the necessary calculation enhancements.
void wlr_mirror_request_box(struct wlr_mirror *mirror,
struct wlr_output *output_src, struct wlr_box box_this_src,
struct wlr_box box_all, int x_within_all, int y_within_all);
drm/pixman not functional
wlr_texture_from_dmabuf
is failing to capture the src buffer. The mirror session runs however a blank dst is rendererd.
Testing
Valgrind was used extensively during development. Two physical outputs were used, of differing resolutions and refresh rates.
- examples/mirror drm gles2 - success
- sway drm gles2 - success
- sway drm vulkan - fail: unable to run a compositor
- sway drm pixman - fail: see limitations
- sway wlr_wl backend - success
- sway wlr_x11 backend - success
Unit Testing Question
Unit tests were written for calculate_absolute_box
, calculate_dst_box
and calculate_render_matrix
, however not included in this MR.
Is it possible for me to add unit test functionality to wlroots? cmocka has proven to be a capable framework.