Skip to content

wlr_mirror: adds mirroring of variable source on a single destination output

Alexander Courtis requested to merge alex-courtis/wlroots:wlr_mirror_v1 into master

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:

wlr_mirror_v1_scale.svg

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.

Edited by Alexander Courtis

Merge request reports