diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 534879143..391db59ed 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -131,7 +131,7 @@ static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) { atomic_add(atom, id, props->crtc_id, 0); } -static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm, +static void set_plane_props(struct atomic *atom, struct wlr_box source_box, struct wlr_drm_plane *plane, uint32_t crtc_id, int32_t x, int32_t y) { uint32_t id = plane->id; const union wlr_drm_plane_props *props = &plane->props; @@ -141,12 +141,14 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm, goto error; } - uint32_t width = fb->wlr_buf->width; - uint32_t height = fb->wlr_buf->height; + uint32_t width = source_box.width ? (uint32_t)source_box.width : + fb->wlr_buf->width; + uint32_t height = source_box.height ? (uint32_t)source_box.height : + fb->wlr_buf->height; // The src_* properties are in 16.16 fixed point - atomic_add(atom, id, props->src_x, 0); - atomic_add(atom, id, props->src_y, 0); + atomic_add(atom, id, props->src_x, (uint64_t)source_box.x << 16); + atomic_add(atom, id, props->src_y, (uint64_t)source_box.y << 16); atomic_add(atom, id, props->src_w, (uint64_t)width << 16); atomic_add(atom, id, props->src_h, (uint64_t)height << 16); atomic_add(atom, id, props->crtc_w, width); @@ -239,20 +241,36 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, atomic_add(&atom, crtc->id, crtc->props.mode_id, mode_id); atomic_add(&atom, crtc->id, crtc->props.active, active); if (active) { + struct wlr_box source_box; + if (state->committed & WLR_OUTPUT_STATE_SOURCE_BOX) { + /** + * Grab source box from output in order to crop the + * buffer. + */ + source_box = state->source_box; + } + else { + // Use dummy source box + source_box.x = source_box.y = source_box.width = + source_box.height = 0; + } if (crtc->props.gamma_lut != 0) { atomic_add(&atom, crtc->id, crtc->props.gamma_lut, gamma_lut); } if (crtc->props.vrr_enabled != 0) { atomic_add(&atom, crtc->id, crtc->props.vrr_enabled, vrr_enabled); } - set_plane_props(&atom, drm, crtc->primary, crtc->id, 0, 0); + set_plane_props(&atom, source_box, crtc->primary, crtc->id, 0, 0); if (crtc->primary->props.fb_damage_clips != 0) { atomic_add(&atom, crtc->primary->id, crtc->primary->props.fb_damage_clips, fb_damage_clips); } if (crtc->cursor) { if (drm_connector_is_cursor_visible(conn)) { - set_plane_props(&atom, drm, crtc->cursor, crtc->id, + // Ensure source_box is unset for cursor plane + source_box.x = source_box.y = source_box.width = + source_box.height = 0; + set_plane_props(&atom, source_box, crtc->cursor, crtc->id, conn->cursor_x, conn->cursor_y); } else { plane_disable(&atom, crtc->cursor); diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 01d4a2fda..316335493 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -16,6 +16,7 @@ #include #include #include +#include struct wlr_output_mode { int32_t width, height; @@ -72,6 +73,7 @@ enum wlr_output_state_field { WLR_OUTPUT_STATE_TRANSFORM = 1 << 5, WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED = 1 << 6, WLR_OUTPUT_STATE_GAMMA_LUT = 1 << 7, + WLR_OUTPUT_STATE_SOURCE_BOX = 1 << 8, }; enum wlr_output_state_mode_type { @@ -89,6 +91,9 @@ struct wlr_output_state { float scale; enum wl_output_transform transform; bool adaptive_sync_enabled; + /* allow partial buffer scanout for tiling displays + * only valid if WLR_OUTPUT_STATE_SOURCE_BOX */ + struct wlr_box source_box; // source box for respective output // only valid if WLR_OUTPUT_STATE_BUFFER struct wlr_buffer *buffer; @@ -372,6 +377,14 @@ uint32_t wlr_output_preferred_read_format(struct wlr_output *output); */ void wlr_output_set_damage(struct wlr_output *output, pixman_region32_t *damage); +/** + * This can be used in case the output buffer is larger than the buffer that + * is supposed to be presented on the actual screen attached to the DRM + * connector. Current use case are hi-res tiling displays which use multiple + * DRM connectors to make up the full monitor. + */ +void wlr_output_set_source_box(struct wlr_output *output, + struct wlr_box source_box); /** * Test whether the pending output state would be accepted by the backend. If * this function returns true, `wlr_output_commit` can only fail due to a diff --git a/types/output/output.c b/types/output/output.c index 4e3f403ff..7d092abd9 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -714,6 +714,12 @@ void wlr_output_attach_buffer(struct wlr_output *output, output->pending.buffer = wlr_buffer_lock(buffer); } +void wlr_output_set_source_box(struct wlr_output *output, + struct wlr_box source_box) { + output->pending.source_box = source_box; + output->pending.committed |= WLR_OUTPUT_STATE_SOURCE_BOX; +} + void wlr_output_send_frame(struct wlr_output *output) { output->frame_pending = false; if (output->enabled) {