# Output management

Libweston output API revolves around two main concepts: `weston_head` and `weston_output`. A head represents a connector or a monitor (a sink) while an output represents the compositing state machine that produces content (a source) to be presented on a head. If a backend allows it, it is possible to attach more than one head to an output, in which case all those heads will have identical timings and contents (they share framebuffers if applicable).

Heads are created and destroyed automatically by libweston according to e.g. hardware features like the existence of physical connectors. Creation, hotplug events and other changes to heads are notified with `weston_compositor_add_heads_changed_listener()`. Head destruction is communicated via `weston_head_add_destroy_listener()`. Note that disconnecting a connector does not mean the head is destroyed. A head is destroyed when the connector itself disappears.

Some backends, mainly virtual and nested ones, may offer backend-specific API to create and destroy heads at will. In these cases a head does not represent anything physical but can be e.g. a window in another window system.

Outputs are explicitly created and destroyed by the libweston user at will. To make a new output or to light up a head, you create an output, attach the head(s) to it, configure it, and finally `weston_output_enable()` it to make it live.

An enabled output cannot be reconfigured, but this is intended to change in the future. You can use `weston_output_disable()` to disable an output and then reconfigure it, but this will cause visible glitches.

API

- Heads
  - `weston_head_from_resource()`
  - `weston_head_init()`
  - `weston_head_detach()`
  - `weston_head_release()`
  - `weston_head_set_device_changed()`
  - `weston_head_set_monitor_strings()`
  - `weston_head_set_non_desktop()`
  - `weston_head_set_transform()`
  - `weston_head_set_physical_size()`
  - `weston_head_set_subpixel()`
  - `weston_head_set_internal()`
  - `weston_head_set_connection_status()`
  - `weston_head_set_supported_eotf_mask()`
  - `weston_head_set_supported_colorimetry_mask()`
  - `weston_head_is_connected()`
  - `weston_head_is_enabled()`
  - `weston_head_is_device_changed()`
  - `weston_head_is_non_desktop()`
  - `weston_head_reset_device_changed()`
  - `weston_head_get_name()`
  - `weston_head_get_output()`
  - `weston_head_get_transform()`
  - `weston_head_get_display_info()`
  - `weston_head_add_destroy_listener()`
  - `weston_head_get_destroy_listener()`
  - `weston_head`
    - `compositor`
    - `backend`
    - `compositor_link`
    - `destroy_signal`
    - `output`
    - `output_link`
    - `resource_list`
    - `global`
    - `xdg_output_resource_list`
    - `mm_width`
    - `mm_height`
    - `transform`
    - `make`
    - `model`
    - `serial_number`
    - `subpixel`
    - `connection_internal`
    - `device_changed`
    - `name`
    - `connected`
    - `non_desktop`
    - `supported_eotf_mask`
    - `supported_colorimetry_mask`
    - `display_info`
    - `current_protection`
    - `cm_output_resource_list`
    - `supported_vrr_mode_mask`
    - `supported_color_format_mask`
- Outputs
  - `weston_repaint_status`
    - `REPAINT_NOT_SCHEDULED`
    - `REPAINT_BEGIN_FROM_IDLE`
    - `REPAINT_SCHEDULED`
    - `REPAINT_AWAITING_COMPLETION`
    - `REPAINT_DEFERRED`
  - `weston_output_copy_native_mode()`
  - `weston_output_mode_set_native()`
  - `weston_output_mode_switch_to_native()`
  - `weston_output_mode_switch_to_temporary()`
  - `weston_output_damage()`
  - `weston_output_finish_frame()`
  - `weston_output_schedule_repaint()`
  - `weston_output_emit_heads_changed()`
  - `weston_output_iterate_heads()`
  - `weston_output_attach_head()`
  - `weston_output_set_position()`
  - `weston_output_move()`
  - `weston_coord_global_from_output_point()`
  - `weston_output_color_effect_inversion()`
  - `weston_output_color_effect_cvd_correction()`
  - `weston_output_set_scale()`
  - `weston_output_set_transform()`
  - `weston_output_set_color_profile()`
  - `weston_output_set_eotf_mode()`
  - `weston_output_get_eotf_mode()`
  - `weston_output_set_colorimetry_mode()`
  - `weston_output_get_colorimetry_mode()`
  - `weston_output_get_hdr_metadata_type1()`
  - `weston_output_set_color_characteristics()`
  - `weston_output_get_color_characteristics()`
  - `weston_output_init()`
  - `weston_output_create_heads_string()`
  - `weston_output_enable()`
  - `weston_output_disable()`
  - `weston_output_add_destroy_listener()`
  - `weston_output_get_destroy_listener()`
  - `weston_output_release()`
  - `weston_output_destroy()`
  - `weston_output_get_first_head()`
  - `weston_output_get_supported_eotf_modes()`
  - `weston_output_get_supported_colorimetry_modes()`
  - `weston_output_set_ready()`
  - `weston_output_color_outcome`
    - `from_sRGB_to_output`
    - `from_sRGB_to_blend`
    - `from_blend_to_output`
    - `hdr_meta`
  - `weston_mode`
    - `flags`
    - `aspect_ratio`
    - `width`
    - `height`
    - `refresh`
    - `link`
  - `weston_output`
    - `id`
    - `name`
    - `shell_private`
    - `backend`
    - `user_destroy_signal`
    - `renderer_state`
    - `primary_plane`
    - `link`
    - `compositor`
    - `paint_node_list`
    - `paint_node_changes`
    - `matrix`
    - `inverse_matrix`
    - `animation_list`
    - `pos`
    - `width`
    - `height`
    - `gpu_track_id`
    - `paint_track_id`
    - `presentation_track_id`
    - `paint_node_z_order_list`
    - `region`
    - `repaint_needed`
    - `full_repaint_needed`
    - `will_repaint`
    - `repainted`
    - `repaint_only_on_capture`
    - `repaint_status`
    - `next_repaint`
    - `next_present`
    - `requested_present`
    - `forced_present`
    - `idle_repaint_source`
    - `frame_signal`
    - `post_latch_signal`
    - `destroy_signal`
    - `move`
    - `frame_time`
    - `frame_flags`
    - `msc`
    - `disable_planes`
    - `destroying`
    - `feedback_list`
    - `capture_info`
    - `transform`
    - `native_scale`
    - `current_scale`
    - `original_scale`
    - `native_mode`
    - `current_mode`
    - `original_mode`
    - `flags`
    - `aspect_ratio`
    - `refresh`
    - `native_mode_copy`
    - `mode_list`
    - `head_list`
    - `desired_protection`
    - `current_protection`
    - `allow_protection`
    - `power_state`
    - `repaint_delay_pacer`
    - `pixman_overdraw_pacer`
    - `start_repaint_loop`
    - `prepare_repaint`
    - `repaint`
    - `destroy`
    - `assign_planes`
    - `switch_mode`
    - `backlight_current`
    - `set_backlight`
    - `set_dpms`
    - `enabled`
    - `color_profile`
    - `from_blend_to_output_by_backend`
    - `eotf_mode`
    - `colorimetry_mode`
    - `color_characteristics`
    - `color_outcome`
    - `color_outcome_serial`
    - `color_effect`
    - `enable`
    - `disable`
    - `attach_head`
    - `detach_head`
    - `get_writeback_formats`
    - `mirror_of`
    - `vrr_mode`
    - `color_format`
    - `ready`
    - `paint_node_list_needs_rebuild`
    - `fifo_barrier_surfaces`

The following sequence diagrams show the function calls for various actions. Fig. 1 shows how DRM-backend creates and configures heads on compositor start-up. Fig. 2 shows the principle of a compositor reacting to initial heads discovered and hotplug events.

When a compositor wants to light up a monitor, it creates an output as in Fig. 3. Attaching more than one head to an output requires specific hardware support in the case of DRM-backend. Other backends are unlikely to support multiple heads per output.

A connector becoming disconnected is a common reason to destroy an output. This happens in Fig. 4.

Heads can also disappear. This is not due to normal monitor unplug but refers to the connector itself disappearing. This is particularly possible with DisplayPort Multi-Stream Transport, where unplugging a monitor will literally remove a connector from the system as that connector was provided by the monitor for daisy-chaining. One scenario of handling that is presented in Fig. 5.

Fig. 1 Heads are being created on compositor start-up with a backend that manages head lifetimes completely on its own, e.g. DRM-backend.

Fig. 2 A compositor handles libweston notification of something with heads having changed. This happens on both compositor start-up and later due to hotplug.

Fig. 3 A compositor creates and configures an output for a head or heads it wants to light up.

Fig. 4 A compositor finds out a head has been disconnected and proceeds to destroy the corresponding output.

Fig. 5 The backend realises that a piece of hardware has disappeared and needs to destroy the corresponding head. The head is released, and even when the compositor is not listening for head destroy signal, the output gets automatically disabled, though not destroyed.