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

output: take a wlr_buffer in set_cursor #2507

Merged
merged 7 commits into from
Jun 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions backend/drm/backend.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <assert.h>
#include <errno.h>
#include <drm_fourcc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -238,6 +239,35 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
goto error_event;
}

if (drm->parent) {
// We'll perform a multi-GPU copy for all submitted buffers, we need
// to be able to texture from them
struct wlr_renderer *renderer = drm->renderer.wlr_rend;
const struct wlr_drm_format_set *texture_formats =
wlr_renderer_get_dmabuf_texture_formats(renderer);
if (texture_formats == NULL) {
wlr_log(WLR_ERROR, "Failed to query renderer texture formats");
goto error_event;
}

for (size_t i = 0; i < texture_formats->len; i++) {
const struct wlr_drm_format *fmt = texture_formats->formats[i];
if (fmt->len == 0) {
// Modifiers aren't supported. The implicit modifier changes
// from a GPU to the other, so we can only accept linear
// buffers
wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format,
DRM_FORMAT_MOD_LINEAR);
continue;
}

for (size_t j = 0; j < fmt->len; j++) {
wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format,
fmt->modifiers[j]);
}
}
}

drm->session_destroy.notify = handle_session_destroy;
wl_signal_add(&session->events.destroy, &drm->session_destroy);

Expand Down
175 changes: 86 additions & 89 deletions backend/drm/drm.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,20 @@
#include "backend/drm/iface.h"
#include "backend/drm/util.h"
#include "render/pixel_format.h"
#include "render/drm_format_set.h"
#include "render/swapchain.h"
#include "render/wlr_renderer.h"
#include "types/wlr_buffer.h"
#include "util/signal.h"

bool check_drm_features(struct wlr_drm_backend *drm) {
if (drmGetCap(drm->fd, DRM_CAP_CURSOR_WIDTH, &drm->cursor_width)) {
drm->cursor_width = 64;
}
if (drmGetCap(drm->fd, DRM_CAP_CURSOR_HEIGHT, &drm->cursor_height)) {
drm->cursor_height = 64;
}

uint64_t cap;
if (drmGetCap(drm->fd, DRM_CAP_PRIME, &cap) ||
!(cap & DRM_PRIME_CAP_IMPORT)) {
Expand Down Expand Up @@ -321,7 +331,7 @@ static bool drm_connector_attach_render(struct wlr_output *output,
static void drm_plane_set_committed(struct wlr_drm_plane *plane) {
drm_fb_move(&plane->queued_fb, &plane->pending_fb);

if (plane->queued_fb) {
if (plane->queued_fb && plane->surf.swapchain) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Random bugfix?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously all planes had a swapchain. Now that the cursor plane swapchain has been moved in common code in wlr_output.c, the cursor plane no longer has a swapchain.

wlr_swapchain_set_buffer_submitted(plane->surf.swapchain,
plane->queued_fb->wlr_buf);
}
Expand Down Expand Up @@ -668,10 +678,9 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn,

int width = mode.hdisplay;
int height = mode.vdisplay;
uint32_t format = DRM_FORMAT_ARGB8888;

bool modifiers = drm->addfb2_modifiers;
if (!drm_plane_init_surface(plane, drm, width, height, format, modifiers) ||
if (!drm_plane_init_surface(plane, drm, width, height, modifiers) ||
!drm_connector_pageflip_renderer(conn, state)) {
if (!modifiers) {
wlr_drm_conn_log(conn, WLR_ERROR, "Failed to initialize renderer:"
Expand All @@ -686,8 +695,7 @@ static bool drm_connector_init_renderer(struct wlr_drm_connector *conn,
"retrying without modifiers");
modifiers = false;

if (!drm_plane_init_surface(plane, drm, width, height, format,
modifiers)) {
if (!drm_plane_init_surface(plane, drm, width, height, modifiers)) {
return false;
}
if (!drm_connector_pageflip_renderer(conn, state)) {
Expand Down Expand Up @@ -828,9 +836,7 @@ struct wlr_output_mode *wlr_drm_connector_add_mode(struct wlr_output *output,
}

static bool drm_connector_set_cursor(struct wlr_output *output,
struct wlr_texture *texture, float scale,
enum wl_output_transform transform,
int32_t hotspot_x, int32_t hotspot_y, bool update_texture) {
struct wlr_buffer *buffer, int hotspot_x, int hotspot_y) {
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
struct wlr_drm_backend *drm = conn->backend;
struct wlr_drm_crtc *crtc = conn->crtc;
Expand All @@ -844,91 +850,59 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
return false;
}

if (!plane->surf.swapchain) {
int ret;
uint64_t w, h;
ret = drmGetCap(drm->fd, DRM_CAP_CURSOR_WIDTH, &w);
w = ret ? 64 : w;
ret = drmGetCap(drm->fd, DRM_CAP_CURSOR_HEIGHT, &h);
h = ret ? 64 : h;

if (!drm_plane_init_surface(plane, drm, w, h,
DRM_FORMAT_ARGB8888, true)) {
wlr_drm_conn_log(conn, WLR_ERROR, "Cannot allocate cursor resources");
return false;
}
}

struct wlr_box hotspot = { .x = hotspot_x, .y = hotspot_y };
wlr_box_transform(&hotspot, &hotspot,
wlr_output_transform_invert(output->transform),
plane->surf.width, plane->surf.height);

if (plane->cursor_hotspot_x != hotspot.x ||
plane->cursor_hotspot_y != hotspot.y) {
if (conn->cursor_hotspot_x != hotspot_x ||
conn->cursor_hotspot_y != hotspot_y) {
// Update cursor hotspot
conn->cursor_x -= hotspot.x - plane->cursor_hotspot_x;
conn->cursor_y -= hotspot.y - plane->cursor_hotspot_y;
plane->cursor_hotspot_x = hotspot.x;
plane->cursor_hotspot_y = hotspot.y;
conn->cursor_x -= hotspot_x - conn->cursor_hotspot_x;
conn->cursor_y -= hotspot_y - conn->cursor_hotspot_y;
conn->cursor_hotspot_x = hotspot_x;
conn->cursor_hotspot_y = hotspot_y;

wlr_output_update_needs_frame(output);
}

if (!update_texture) {
// Don't update cursor image
return true;
}

plane->cursor_enabled = false;
if (texture != NULL) {
int width = texture->width * output->scale / scale;
int height = texture->height * output->scale / scale;

if (width > (int)plane->surf.width || height > (int)plane->surf.height) {
wlr_drm_conn_log(conn, WLR_ERROR, "Cursor too large (max %dx%d)",
(int)plane->surf.width, (int)plane->surf.height);
return false;
}

if (!drm_surface_make_current(&plane->surf, NULL)) {
conn->cursor_enabled = false;
if (buffer != NULL) {
if ((uint64_t)buffer->width != drm->cursor_width ||
(uint64_t)buffer->height != drm->cursor_height) {
wlr_drm_conn_log(conn, WLR_DEBUG, "Cursor buffer size mismatch");
return false;
}

struct wlr_renderer *rend = plane->surf.renderer->wlr_rend;

struct wlr_box cursor_box = { .width = width, .height = height };
struct wlr_buffer *local_buf;
if (drm->parent) {
struct wlr_drm_format *format =
drm_plane_pick_render_format(plane, &drm->renderer);
if (format == NULL) {
wlr_log(WLR_ERROR, "Failed to pick cursor plane format");
return false;
}

float output_matrix[9];
wlr_matrix_identity(output_matrix);
if (output->transform != WL_OUTPUT_TRANSFORM_NORMAL) {
struct wlr_box tr_size = {
.width = plane->surf.width,
.height = plane->surf.height,
};
wlr_box_transform(&tr_size, &tr_size, output->transform, 0, 0);
bool ok = init_drm_surface(&plane->mgpu_surf, &drm->renderer,
buffer->width, buffer->height, format);
free(format);
if (!ok) {
return false;
}

wlr_matrix_translate(output_matrix, plane->surf.width / 2.0,
plane->surf.height / 2.0);
wlr_matrix_transform(output_matrix, output->transform);
wlr_matrix_translate(output_matrix, - tr_size.width / 2.0,
- tr_size.height / 2.0);
local_buf = drm_surface_blit(&plane->mgpu_surf, buffer);
if (local_buf == NULL) {
return false;
}
} else {
local_buf = wlr_buffer_lock(buffer);
}

float matrix[9];
wlr_matrix_project_box(matrix, &cursor_box, transform, 0,
output_matrix);

wlr_renderer_begin(rend, plane->surf.width, plane->surf.height);
wlr_renderer_clear(rend, (float[]){ 0.0, 0.0, 0.0, 0.0 });
wlr_render_texture_with_matrix(rend, texture, matrix, 1.0);
wlr_renderer_end(rend);

if (!drm_plane_lock_surface(plane, drm)) {
bool ok = drm_fb_import(&plane->pending_fb, drm, local_buf,
&plane->formats);
wlr_buffer_unlock(local_buf);
if (!ok) {
return false;
}

plane->cursor_enabled = true;
conn->cursor_enabled = true;
conn->cursor_width = buffer->width;
conn->cursor_height = buffer->height;
}

wlr_output_update_needs_frame(output);
Expand All @@ -955,8 +929,8 @@ static bool drm_connector_move_cursor(struct wlr_output *output,
wlr_output_transform_invert(output->transform);
wlr_box_transform(&box, &box, transform, width, height);

box.x -= plane->cursor_hotspot_x;
box.y -= plane->cursor_hotspot_y;
box.x -= conn->cursor_hotspot_x;
box.y -= conn->cursor_hotspot_y;

conn->cursor_x = box.x;
conn->cursor_y = box.y;
Expand All @@ -966,14 +940,11 @@ static bool drm_connector_move_cursor(struct wlr_output *output,
}

bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn) {
assert(conn->crtc != NULL && conn->crtc->cursor != NULL);
struct wlr_drm_plane *plane = conn->crtc->cursor;

return plane->cursor_enabled &&
return conn->cursor_enabled &&
conn->cursor_x < conn->output.width &&
conn->cursor_y < conn->output.height &&
conn->cursor_x + (int)plane->surf.width >= 0 &&
conn->cursor_y + (int)plane->surf.height >= 0;
conn->cursor_x + conn->cursor_width >= 0 &&
conn->cursor_y + conn->cursor_height >= 0;
}

static void dealloc_crtc(struct wlr_drm_connector *conn);
Expand Down Expand Up @@ -1004,6 +975,32 @@ static void drm_connector_destroy_output(struct wlr_output *output) {
memset(&conn->output, 0, sizeof(struct wlr_output));
}

static const struct wlr_drm_format_set *drm_connector_get_cursor_formats(
struct wlr_output *output, uint32_t buffer_caps) {
if (!(buffer_caps & WLR_BUFFER_CAP_DMABUF)) {
return NULL;
}
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
if (!conn->crtc) {
return false;
}
struct wlr_drm_plane *plane = conn->crtc->cursor;
if (!plane) {
return false;
}
if (conn->backend->parent) {
return &conn->backend->mgpu_formats;
}
return &plane->formats;
}

static void drm_connector_get_cursor_size(struct wlr_output *output,
int *width, int *height) {
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
*width = (int)drm->cursor_width;
*height = (int)drm->cursor_height;
}

static const struct wlr_output_impl output_impl = {
.set_cursor = drm_connector_set_cursor,
.move_cursor = drm_connector_move_cursor,
Expand All @@ -1014,6 +1011,8 @@ static const struct wlr_output_impl output_impl = {
.rollback_render = drm_connector_rollback_render,
.get_gamma_size = drm_connector_get_gamma_size,
.export_dmabuf = drm_connector_export_dmabuf,
.get_cursor_formats = drm_connector_get_cursor_formats,
.get_cursor_size = drm_connector_get_cursor_size,
};

bool wlr_output_is_drm(struct wlr_output *output) {
Expand Down Expand Up @@ -1093,10 +1092,8 @@ static void dealloc_crtc(struct wlr_drm_connector *conn) {

drm_plane_finish_surface(conn->crtc->primary);
drm_plane_finish_surface(conn->crtc->cursor);
if (conn->crtc->cursor != NULL) {
conn->crtc->cursor->cursor_enabled = false;
}

conn->cursor_enabled = false;
conn->crtc = NULL;
}

Expand Down
Loading