mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
backend/drm: implement the output layer API
Delegate all of the work to libliftoff.
This commit is contained in:
parent
e45ddda7bc
commit
2a3861024e
3 changed files with 134 additions and 2 deletions
|
|
@ -423,6 +423,11 @@ static bool drm_crtc_commit(struct wlr_drm_connector *conn,
|
|||
if (crtc->cursor != NULL) {
|
||||
drm_fb_move(&crtc->cursor->queued_fb, &crtc->cursor->pending_fb);
|
||||
}
|
||||
|
||||
struct wlr_drm_layer *layer;
|
||||
wl_list_for_each(layer, &state->base->layers, base.pending.link) {
|
||||
drm_fb_move(&layer->queued_fb, &layer->pending_fb);
|
||||
}
|
||||
} else {
|
||||
drm_fb_clear(&crtc->primary->pending_fb);
|
||||
// The set_cursor() hook is a bit special: it's not really synchronized
|
||||
|
|
@ -431,6 +436,11 @@ static bool drm_crtc_commit(struct wlr_drm_connector *conn,
|
|||
// risk ending up in a state where we don't have a cursor FB but
|
||||
// wlr_drm_connector.cursor_enabled is true.
|
||||
// TODO: fix our output interface to avoid this issue.
|
||||
|
||||
struct wlr_drm_layer *layer;
|
||||
wl_list_for_each(layer, &state->base->layers, base.pending.link) {
|
||||
drm_fb_clear(&layer->pending_fb);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
|
@ -545,6 +555,23 @@ static bool drm_connector_set_pending_fb(struct wlr_drm_connector *conn,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void drm_connector_set_pending_layer_fbs(struct wlr_drm_connector *conn,
|
||||
const struct wlr_output_state *state) {
|
||||
struct wlr_drm_backend *drm = conn->backend;
|
||||
|
||||
struct wlr_drm_layer *layer;
|
||||
wl_list_for_each(layer, &state->layers, base.pending.link) {
|
||||
if (!(layer->base.pending.committed & WLR_OUTPUT_LAYER_STATE_BUFFER)) {
|
||||
continue;
|
||||
}
|
||||
struct wlr_buffer *buffer = layer->base.pending.buffer;
|
||||
drm_fb_clear(&layer->pending_fb);
|
||||
if (!drm_fb_import(&layer->pending_fb, drm, buffer, NULL)) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to import layer buffer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool drm_connector_alloc_crtc(struct wlr_drm_connector *conn);
|
||||
|
||||
static bool drm_connector_test(struct wlr_output *output) {
|
||||
|
|
@ -602,6 +629,8 @@ static bool drm_connector_test(struct wlr_output *output) {
|
|||
return true;
|
||||
}
|
||||
|
||||
drm_connector_set_pending_layer_fbs(conn, pending.base);
|
||||
|
||||
if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
if (!drm_connector_set_pending_fb(conn, pending.base)) {
|
||||
return false;
|
||||
|
|
@ -659,6 +688,8 @@ bool drm_connector_commit_state(struct wlr_drm_connector *conn,
|
|||
}
|
||||
}
|
||||
|
||||
drm_connector_set_pending_layer_fbs(conn, pending.base);
|
||||
|
||||
if (pending.base->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
if (!drm_connector_set_pending_fb(conn, pending.base)) {
|
||||
return false;
|
||||
|
|
@ -1036,6 +1067,25 @@ static const struct wlr_drm_format_set *drm_connector_get_primary_formats(
|
|||
return &conn->crtc->primary->formats;
|
||||
}
|
||||
|
||||
static struct wlr_output_layer *drm_connector_create_layer(
|
||||
struct wlr_output *wlr_output) {
|
||||
struct wlr_drm_layer *layer = calloc(1, sizeof(*layer));
|
||||
if (layer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_output_layer_init(&layer->base, wlr_output);
|
||||
return &layer->base;
|
||||
}
|
||||
|
||||
static void drm_connector_destroy_layer(struct wlr_output_layer *wlr_layer) {
|
||||
struct wlr_drm_layer *layer = (struct wlr_drm_layer *)wlr_layer;
|
||||
drm_fb_clear(&layer->pending_fb);
|
||||
drm_fb_clear(&layer->queued_fb);
|
||||
drm_fb_clear(&layer->current_fb);
|
||||
liftoff_layer_destroy(layer->liftoff);
|
||||
free(layer);
|
||||
}
|
||||
|
||||
static const struct wlr_output_impl output_impl = {
|
||||
.set_cursor = drm_connector_set_cursor,
|
||||
.move_cursor = drm_connector_move_cursor,
|
||||
|
|
@ -1046,6 +1096,8 @@ static const struct wlr_output_impl output_impl = {
|
|||
.get_cursor_formats = drm_connector_get_cursor_formats,
|
||||
.get_cursor_size = drm_connector_get_cursor_size,
|
||||
.get_primary_formats = drm_connector_get_primary_formats,
|
||||
.create_layer = drm_connector_create_layer,
|
||||
.destroy_layer = drm_connector_destroy_layer,
|
||||
};
|
||||
|
||||
bool wlr_output_is_drm(struct wlr_output *output) {
|
||||
|
|
@ -1543,6 +1595,11 @@ static void handle_page_flip(int fd, unsigned seq,
|
|||
&conn->crtc->cursor->queued_fb);
|
||||
}
|
||||
|
||||
struct wlr_drm_layer *layer;
|
||||
wl_list_for_each(layer, &conn->output.layers, base.current.link) {
|
||||
drm_fb_move(&layer->current_fb, &layer->queued_fb);
|
||||
}
|
||||
|
||||
uint32_t present_flags = WLR_OUTPUT_PRESENT_VSYNC |
|
||||
WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION;
|
||||
/* Don't report ZERO_COPY in multi-gpu situations, because we had to copy
|
||||
|
|
|
|||
|
|
@ -76,6 +76,37 @@ static bool disable_plane(struct wlr_drm_plane *plane) {
|
|||
return liftoff_layer_set_property(plane->liftoff_layer, "FB_ID", 0) == 0;
|
||||
}
|
||||
|
||||
static bool set_layer_props(struct wlr_drm_layer *layer, uint64_t zpos) {
|
||||
bool ok = liftoff_layer_set_property(layer->liftoff, "zpos", zpos) == 0 &&
|
||||
liftoff_layer_set_property(layer->liftoff, "CRTC_X", layer->base.pending.x) == 0 &&
|
||||
liftoff_layer_set_property(layer->liftoff, "CRTC_Y", layer->base.pending.y) == 0;
|
||||
|
||||
if (layer->base.pending.committed & WLR_OUTPUT_LAYER_STATE_BUFFER) {
|
||||
struct wlr_buffer *buffer = layer->base.pending.buffer;
|
||||
uint64_t width = buffer->width;
|
||||
uint64_t height = buffer->height;
|
||||
|
||||
ok = ok &&
|
||||
liftoff_layer_set_property(layer->liftoff, "SRC_X", 0) == 0 &&
|
||||
liftoff_layer_set_property(layer->liftoff, "SRC_Y", 0) == 0 &&
|
||||
liftoff_layer_set_property(layer->liftoff, "SRC_W", width << 16) == 0 &&
|
||||
liftoff_layer_set_property(layer->liftoff, "SRC_H", height << 16) == 0 &&
|
||||
liftoff_layer_set_property(layer->liftoff, "CRTC_W", width) == 0 &&
|
||||
liftoff_layer_set_property(layer->liftoff, "CRTC_H", height) == 0;
|
||||
|
||||
struct wlr_drm_fb *fb = layer->pending_fb;
|
||||
if (fb == NULL) {
|
||||
// We couldn't import the buffer to KMS. Force the layer to be
|
||||
// composited.
|
||||
liftoff_layer_set_fb_composited(layer->liftoff);
|
||||
} else {
|
||||
ok = ok && liftoff_layer_set_property(layer->liftoff, "FB_ID", fb->id) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool liftoff_crtc_commit(struct wlr_drm_connector *conn,
|
||||
const struct wlr_drm_connector_state *state, uint32_t flags,
|
||||
bool test_only) {
|
||||
|
|
@ -116,17 +147,41 @@ static bool liftoff_crtc_commit(struct wlr_drm_connector *conn,
|
|||
if (crtc->cursor) {
|
||||
if (drm_connector_is_cursor_visible(conn)) {
|
||||
ok = ok && set_plane_props(crtc->cursor,
|
||||
crtc->cursor->liftoff_layer,
|
||||
conn->cursor_x, conn->cursor_y, 1);
|
||||
crtc->cursor->liftoff_layer, conn->cursor_x, conn->cursor_y,
|
||||
wl_list_length(&state->base->layers) + 1);
|
||||
} else {
|
||||
ok = ok && disable_plane(crtc->cursor);
|
||||
}
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
struct wlr_drm_layer *layer;
|
||||
wl_list_for_each(layer, &state->base->layers, base.pending.link) {
|
||||
if (layer->liftoff == NULL) {
|
||||
layer->liftoff = liftoff_layer_create(crtc->liftoff);
|
||||
if (layer->liftoff == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to create libliftoff layer");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
layer->base.accepted = false;
|
||||
ok = ok && set_layer_props(layer, i + 1);
|
||||
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
ok = ok && disable_plane(crtc->primary);
|
||||
if (crtc->cursor) {
|
||||
ok = ok && disable_plane(crtc->cursor);
|
||||
}
|
||||
|
||||
struct wlr_drm_layer *layer;
|
||||
wl_list_for_each(layer, &state->base->layers, base.pending.link) {
|
||||
if (layer->liftoff != NULL) {
|
||||
liftoff_layer_set_property(layer->liftoff, "FB_ID", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
|
|
@ -148,6 +203,13 @@ static bool liftoff_crtc_commit(struct wlr_drm_connector *conn,
|
|||
goto out;
|
||||
}
|
||||
|
||||
struct wlr_drm_layer *layer;
|
||||
wl_list_for_each(layer, &state->base->layers, base.pending.link) {
|
||||
if (layer->liftoff != NULL) {
|
||||
layer->base.accepted = !liftoff_layer_needs_composition(layer->liftoff);
|
||||
}
|
||||
}
|
||||
|
||||
ret = drmModeAtomicCommit(drm->fd, req, flags, drm);
|
||||
if (ret != 0) {
|
||||
wlr_drm_conn_log_errno(conn, test_only ? WLR_DEBUG : WLR_ERROR,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <wlr/backend/drm.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
#include <wlr/types/wlr_output_layer.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include "backend/drm/iface.h"
|
||||
#include "backend/drm/properties.h"
|
||||
|
|
@ -37,6 +38,18 @@ struct wlr_drm_plane {
|
|||
struct liftoff_layer *liftoff_layer;
|
||||
};
|
||||
|
||||
struct wlr_drm_layer {
|
||||
struct wlr_output_layer base;
|
||||
struct liftoff_layer *liftoff;
|
||||
|
||||
/* Buffer to be submitted to the kernel on the next page-flip */
|
||||
struct wlr_drm_fb *pending_fb;
|
||||
/* Buffer submitted to the kernel, will be presented on next vblank */
|
||||
struct wlr_drm_fb *queued_fb;
|
||||
/* Buffer currently displayed on screen */
|
||||
struct wlr_drm_fb *current_fb;
|
||||
};
|
||||
|
||||
struct wlr_drm_crtc {
|
||||
uint32_t id;
|
||||
uint32_t lessee_id;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue