Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit

Permalink
backend/drm: implement the output layer API
Browse files Browse the repository at this point in the history
Delegate all of the work to libliftoff.
  • Loading branch information
emersion committed Aug 18, 2021
1 parent 04642fd commit 7d2be3b
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 2 deletions.
57 changes: 57 additions & 0 deletions backend/drm/drm.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,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
Expand All @@ -432,6 +437,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;
}
Expand Down Expand Up @@ -543,6 +553,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) {
Expand Down Expand Up @@ -600,6 +627,8 @@ static bool drm_connector_test(struct wlr_output *output) {
return true;
}

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;
Expand Down Expand Up @@ -657,6 +686,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;
Expand Down Expand Up @@ -1105,6 +1136,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,
Expand All @@ -1115,6 +1165,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) {
Expand Down Expand Up @@ -1572,6 +1624,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
Expand Down
66 changes: 64 additions & 2 deletions backend/drm/libliftoff.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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,
Expand Down
13 changes: 13 additions & 0 deletions include/backend/drm/drm.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,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"
Expand Down Expand Up @@ -38,6 +39,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;

Expand Down

0 comments on commit 7d2be3b

Please sign in to comment.