backend/drm: Drop parent drm device

Compositors should instead blit to secondary drm devices themselves.
This commit is contained in:
Alexander Orzechowski 2024-05-05 13:36:33 -04:00
parent 38d761c837
commit dc7855f674
10 changed files with 13 additions and 310 deletions

View file

@ -258,7 +258,7 @@ static struct wlr_backend *attempt_drm_backend(struct wlr_backend *backend, stru
struct wlr_backend *primary_drm = NULL;
for (size_t i = 0; i < (size_t)num_gpus; ++i) {
struct wlr_backend *drm = wlr_drm_backend_create(session, gpus[i], primary_drm);
struct wlr_backend *drm = wlr_drm_backend_create(session, gpus[i]);
if (!drm) {
wlr_log(WLR_ERROR, "Failed to create DRM backend");
continue;

View file

@ -275,9 +275,9 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
}
int in_fence_fd = -1;
if (state->wait_timeline != NULL) {
in_fence_fd = wlr_drm_syncobj_timeline_export_sync_file(state->wait_timeline,
state->wait_point);
if (state->base->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
in_fence_fd = wlr_drm_syncobj_timeline_export_sync_file(state->base->wait_timeline,
state->base->wait_point);
if (in_fence_fd < 0) {
return false;
}

View file

@ -49,14 +49,9 @@ static void backend_destroy(struct wlr_backend *backend) {
wl_list_remove(&drm->session_destroy.link);
wl_list_remove(&drm->session_active.link);
wl_list_remove(&drm->parent_destroy.link);
wl_list_remove(&drm->dev_change.link);
wl_list_remove(&drm->dev_remove.link);
if (drm->parent) {
finish_drm_renderer(&drm->mgpu_renderer);
}
finish_drm_resources(drm);
struct wlr_drm_fb *fb, *fb_tmp;
@ -104,11 +99,6 @@ bool wlr_backend_is_drm(struct wlr_backend *b) {
return b->impl == &backend_impl;
}
struct wlr_backend *wlr_drm_backend_get_parent(struct wlr_backend *backend) {
struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
return drm->parent ? &drm->parent->backend : NULL;
}
static void handle_session_active(struct wl_listener *listener, void *data) {
struct wlr_drm_backend *drm =
wl_container_of(listener, drm, session_active);
@ -159,16 +149,8 @@ static void handle_session_destroy(struct wl_listener *listener, void *data) {
backend_destroy(&drm->backend);
}
static void handle_parent_destroy(struct wl_listener *listener, void *data) {
struct wlr_drm_backend *drm =
wl_container_of(listener, drm, parent_destroy);
backend_destroy(&drm->backend);
}
struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
struct wlr_device *dev, struct wlr_backend *parent) {
struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session, struct wlr_device *dev) {
assert(session && dev);
assert(!parent || wlr_backend_is_drm(parent));
char *name = drmGetDeviceNameFromFd2(dev->fd);
if (name == NULL) {
@ -201,15 +183,6 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
drm->fd = dev->fd;
drm->name = name;
if (parent != NULL) {
drm->parent = get_drm_backend_from_backend(parent);
drm->parent_destroy.notify = handle_parent_destroy;
wl_signal_add(&parent->events.destroy, &drm->parent_destroy);
} else {
wl_list_init(&drm->parent_destroy.link);
}
drm->dev_change.notify = handle_dev_change;
wl_signal_add(&dev->events.change, &drm->dev_change);
@ -234,52 +207,17 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
goto error_event;
}
if (drm->parent) {
if (!init_drm_renderer(drm, &drm->mgpu_renderer)) {
wlr_log(WLR_ERROR, "Failed to initialize renderer");
goto error_resources;
}
// 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->mgpu_renderer.wlr_rend;
const struct wlr_drm_format_set *texture_formats =
wlr_renderer_get_texture_formats(renderer, WLR_BUFFER_CAP_DMABUF);
if (texture_formats == NULL) {
wlr_log(WLR_ERROR, "Failed to query renderer texture formats");
goto error_mgpu_renderer;
}
// Forbid implicit modifiers, because their meaning changes from one
// GPU to another.
for (size_t i = 0; i < texture_formats->len; i++) {
const struct wlr_drm_format *fmt = &texture_formats->formats[i];
for (size_t j = 0; j < fmt->len; j++) {
uint64_t mod = fmt->modifiers[j];
if (mod == DRM_FORMAT_MOD_INVALID) {
continue;
}
wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format, mod);
}
}
}
drm->session_destroy.notify = handle_session_destroy;
wl_signal_add(&session->events.destroy, &drm->session_destroy);
return &drm->backend;
error_mgpu_renderer:
finish_drm_renderer(&drm->mgpu_renderer);
error_resources:
finish_drm_resources(drm);
error_event:
wl_list_remove(&drm->session_active.link);
wl_event_source_remove(drm->drm_event);
error_fd:
wl_list_remove(&drm->dev_remove.link);
wl_list_remove(&drm->dev_change.link);
wl_list_remove(&drm->parent_destroy.link);
wlr_session_close_file(drm->session, dev);
free(drm->name);
free(drm);

View file

@ -65,15 +65,6 @@ bool check_drm_features(struct wlr_drm_backend *drm) {
return false;
}
if (drm->parent) {
if (drmGetCap(drm->parent->fd, DRM_CAP_PRIME, &cap) ||
!(cap & DRM_PRIME_CAP_EXPORT)) {
wlr_log(WLR_ERROR,
"PRIME export not supported on primary GPU");
return false;
}
}
if (drmSetClientCap(drm->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) {
wlr_log(WLR_ERROR, "DRM universal planes unsupported");
return false;
@ -369,8 +360,6 @@ static void drm_plane_finish_surface(struct wlr_drm_plane *plane) {
drm_fb_clear(&plane->queued_fb);
drm_fb_clear(&plane->current_fb);
finish_drm_surface(&plane->mgpu_surf);
}
void finish_drm_resources(struct wlr_drm_backend *drm) {
@ -709,52 +698,8 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
struct wlr_drm_plane *plane = crtc->primary;
struct wlr_buffer *source_buf = state->base->buffer;
struct wlr_drm_syncobj_timeline *wait_timeline = NULL;
uint64_t wait_point = 0;
if (state->base->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
wait_timeline = state->base->wait_timeline;
wait_point = state->base->wait_point;
}
assert(state->wait_timeline == NULL);
struct wlr_buffer *local_buf;
if (drm->parent) {
struct wlr_drm_format format = {0};
if (!drm_plane_pick_render_format(plane, &format, &drm->mgpu_renderer)) {
wlr_log(WLR_ERROR, "Failed to pick primary plane format");
return false;
}
// TODO: fallback to modifier-less buffer allocation
bool ok = init_drm_surface(&plane->mgpu_surf, &drm->mgpu_renderer,
source_buf->width, source_buf->height, &format);
wlr_drm_format_finish(&format);
if (!ok) {
return false;
}
local_buf = drm_surface_blit(&plane->mgpu_surf, source_buf,
wait_timeline, wait_point);
if (local_buf == NULL) {
return false;
}
if (plane->mgpu_surf.timeline != NULL) {
state->wait_timeline = wlr_drm_syncobj_timeline_ref(plane->mgpu_surf.timeline);
state->wait_point = plane->mgpu_surf.point;
}
} else {
local_buf = wlr_buffer_lock(source_buf);
if (wait_timeline != NULL) {
state->wait_timeline = wlr_drm_syncobj_timeline_ref(wait_timeline);
state->wait_point = wait_point;
}
}
bool ok = drm_fb_import(&state->primary_fb, drm, local_buf,
bool ok = drm_fb_import(&state->primary_fb, drm, source_buf,
&plane->formats);
wlr_buffer_unlock(local_buf);
if (!ok) {
wlr_drm_conn_log(conn, WLR_DEBUG,
"Failed to import buffer for scan-out");
@ -769,7 +714,7 @@ static bool drm_connector_set_pending_layer_fbs(struct wlr_drm_connector *conn,
struct wlr_drm_backend *drm = conn->backend;
struct wlr_drm_crtc *crtc = conn->crtc;
if (!crtc || drm->parent) {
if (!crtc) {
return false;
}
@ -828,12 +773,6 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
return false;
}
if (test_only && conn->backend->parent) {
// If we're running as a secondary GPU, we can't perform an atomic
// commit without blitting a buffer.
return true;
}
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
if (!drm_connector_state_update_primary_fb(conn, conn_state)) {
return false;
@ -898,13 +837,6 @@ static bool drm_connector_commit_state(struct wlr_drm_connector *conn,
goto out;
}
if (test_only && conn->backend->parent) {
// If we're running as a secondary GPU, we can't perform an atomic
// commit without blitting a buffer.
ok = true;
goto out;
}
if (!pending.active && conn->crtc == NULL) {
// Disabling an already-disabled connector
ok = true;
@ -1094,28 +1026,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
return false;
}
struct wlr_buffer *local_buf;
if (drm->parent) {
struct wlr_drm_format format = {0};
if (!drm_plane_pick_render_format(plane, &format, &drm->mgpu_renderer)) {
wlr_log(WLR_ERROR, "Failed to pick cursor plane format");
return false;
}
bool ok = init_drm_surface(&plane->mgpu_surf, &drm->mgpu_renderer,
buffer->width, buffer->height, &format);
wlr_drm_format_finish(&format);
if (!ok) {
return false;
}
local_buf = drm_surface_blit(&plane->mgpu_surf, buffer, NULL, 0);
if (local_buf == NULL) {
return false;
}
} else {
local_buf = wlr_buffer_lock(buffer);
}
struct wlr_buffer *local_buf = wlr_buffer_lock(buffer);
bool ok = drm_fb_import(&conn->cursor_pending_fb, drm, local_buf,
&plane->formats);
@ -1209,9 +1120,6 @@ static const struct wlr_drm_format_set *drm_connector_get_cursor_formats(
if (!plane) {
return NULL;
}
if (conn->backend->parent) {
return &conn->backend->mgpu_formats;
}
return &plane->formats;
}
@ -1238,9 +1146,6 @@ static const struct wlr_drm_format_set *drm_connector_get_primary_formats(
if (!drm_connector_alloc_crtc(conn)) {
return NULL;
}
if (conn->backend->parent) {
return &conn->backend->mgpu_formats;
}
return &conn->crtc->primary->formats;
}
@ -1647,9 +1552,6 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
}
output->timeline = drm->iface != &legacy_iface;
if (drm->parent) {
output->timeline = output->timeline && drm->mgpu_renderer.wlr_rend->features.timeline;
}
memset(wlr_conn->max_bpc_bounds, 0, sizeof(wlr_conn->max_bpc_bounds));
if (wlr_conn->props.max_bpc != 0) {
@ -2000,13 +1902,6 @@ bool commit_drm_device(struct wlr_drm_backend *drm,
modeset |= output_state->base.allow_reconfiguration;
}
if (test_only && drm->parent) {
// If we're running as a secondary GPU, we can't perform an atomic
// commit without blitting a buffer.
ok = true;
goto out;
}
uint32_t flags = 0;
if (!test_only) {
flags |= DRM_MODE_PAGE_FLIP_EVENT;
@ -2039,7 +1934,8 @@ static void handle_page_flip(int fd, unsigned seq,
conn->pending_page_flip = NULL;
}
uint32_t present_flags = WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION;
uint32_t present_flags = WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION |
WLR_OUTPUT_PRESENT_ZERO_COPY;
if (!page_flip->async) {
present_flags |= WLR_OUTPUT_PRESENT_VSYNC;
}
@ -2074,14 +1970,6 @@ static void handle_page_flip(int fd, unsigned seq,
drm_fb_move(&layer->current_fb, &layer->queued_fb);
}
/* Don't report ZERO_COPY in multi-gpu situations, because we had to copy
* data between the GPUs, even if we were using the direct scanout
* interface.
*/
if (!drm->parent) {
present_flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
}
struct wlr_output_event_present present_event = {
/* The DRM backend guarantees that the presentation event will be for
* the last submitted frame. */

View file

@ -25,8 +25,7 @@ static void handle_add_drm_card(struct wl_listener *listener, void *data) {
}
wlr_log(WLR_DEBUG, "Creating DRM backend for %s after hotplug", event->path);
struct wlr_backend *child_drm = wlr_drm_backend_create(backend_monitor->session,
dev, backend_monitor->primary_drm);
struct wlr_backend *child_drm = wlr_drm_backend_create(backend_monitor->session, dev);
if (!child_drm) {
wlr_log(WLR_ERROR, "Failed to create DRM backend after hotplug");
return;

View file

@ -13,35 +13,6 @@
#include "render/pixel_format.h"
#include "render/wlr_renderer.h"
bool init_drm_renderer(struct wlr_drm_backend *drm,
struct wlr_drm_renderer *renderer) {
renderer->wlr_rend = renderer_autocreate_with_drm_fd(drm->fd);
if (!renderer->wlr_rend) {
wlr_log(WLR_ERROR, "Failed to create renderer");
return false;
}
uint32_t backend_caps = backend_get_buffer_caps(&drm->backend);
renderer->allocator = allocator_autocreate_with_drm_fd(backend_caps,
renderer->wlr_rend, drm->fd);
if (renderer->allocator == NULL) {
wlr_log(WLR_ERROR, "Failed to create allocator");
wlr_renderer_destroy(renderer->wlr_rend);
return false;
}
return true;
}
void finish_drm_renderer(struct wlr_drm_renderer *renderer) {
if (!renderer) {
return;
}
wlr_allocator_destroy(renderer->allocator);
wlr_renderer_destroy(renderer->wlr_rend);
}
void finish_drm_surface(struct wlr_drm_surface *surf) {
if (!surf || !surf->renderer) {
return;
@ -85,62 +56,6 @@ bool init_drm_surface(struct wlr_drm_surface *surf,
return true;
}
struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
struct wlr_buffer *buffer,
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
struct wlr_renderer *renderer = surf->renderer->wlr_rend;
if (surf->swapchain->width != buffer->width ||
surf->swapchain->height != buffer->height) {
wlr_log(WLR_ERROR, "Surface size doesn't match buffer size");
return NULL;
}
struct wlr_texture *tex = wlr_texture_from_buffer(renderer, buffer);
if (tex == NULL) {
wlr_log(WLR_ERROR, "Failed to import source buffer into multi-GPU renderer");
return NULL;
}
struct wlr_buffer *dst = wlr_swapchain_acquire(surf->swapchain);
if (!dst) {
wlr_log(WLR_ERROR, "Failed to acquire multi-GPU swapchain buffer");
goto error_tex;
}
surf->point++;
const struct wlr_buffer_pass_options pass_options = {
.signal_timeline = surf->timeline,
.signal_point = surf->point,
};
struct wlr_render_pass *pass = wlr_renderer_begin_buffer_pass(renderer, dst, &pass_options);
if (pass == NULL) {
wlr_log(WLR_ERROR, "Failed to begin render pass with multi-GPU destination buffer");
goto error_dst;
}
wlr_render_pass_add_texture(pass, &(struct wlr_render_texture_options){
.texture = tex,
.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
.wait_timeline = wait_timeline,
.wait_point = wait_point,
});
if (!wlr_render_pass_submit(pass)) {
wlr_log(WLR_ERROR, "Failed to submit multi-GPU render pass");
goto error_dst;
}
wlr_texture_destroy(tex);
return dst;
error_dst:
wlr_buffer_unlock(dst);
error_tex:
wlr_texture_destroy(tex);
return NULL;
}
bool drm_plane_pick_render_format(struct wlr_drm_plane *plane,
struct wlr_drm_format *fmt, struct wlr_drm_renderer *renderer) {
const struct wlr_drm_format_set *render_formats =

View file

@ -19,9 +19,6 @@ struct wlr_drm_plane {
uint32_t type;
uint32_t id;
/* Only initialized on multi-GPU setups */
struct wlr_drm_surface mgpu_surf;
/* Buffer submitted to the kernel, will be presented on next vblank */
struct wlr_drm_fb *queued_fb;
/* Buffer currently displayed on screen */
@ -80,7 +77,6 @@ struct wlr_drm_crtc {
struct wlr_drm_backend {
struct wlr_backend backend;
struct wlr_drm_backend *parent;
const struct wlr_drm_interface *iface;
bool addfb2_modifiers;
@ -99,7 +95,6 @@ struct wlr_drm_backend {
struct wl_listener session_destroy;
struct wl_listener session_active;
struct wl_listener parent_destroy;
struct wl_listener dev_change;
struct wl_listener dev_remove;
@ -108,15 +103,10 @@ struct wlr_drm_backend {
struct wl_list page_flips; // wlr_drm_page_flip.link
/* Only initialized on multi-GPU setups */
struct wlr_drm_renderer mgpu_renderer;
struct wlr_session *session;
uint64_t cursor_width, cursor_height;
struct wlr_drm_format_set mgpu_formats;
bool supports_tearing_page_flips;
};

View file

@ -25,19 +25,11 @@ struct wlr_drm_surface {
uint64_t point;
};
bool init_drm_renderer(struct wlr_drm_backend *drm,
struct wlr_drm_renderer *renderer);
void finish_drm_renderer(struct wlr_drm_renderer *renderer);
bool init_drm_surface(struct wlr_drm_surface *surf,
struct wlr_drm_renderer *renderer, int width, int height,
const struct wlr_drm_format *drm_format);
void finish_drm_surface(struct wlr_drm_surface *surf);
struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
struct wlr_buffer *buffer,
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point);
bool drm_plane_pick_render_format(struct wlr_drm_plane *plane,
struct wlr_drm_format *fmt, struct wlr_drm_renderer *renderer);

View file

@ -32,21 +32,12 @@ struct wlr_drm_lease {
/**
* Creates a DRM backend using the specified GPU file descriptor (typically from
* a device node in /dev/dri).
*
* To slave this to another DRM backend, pass it as the parent (which _must_ be
* a DRM backend, other kinds of backends raise SIGABRT).
*/
struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
struct wlr_device *dev, struct wlr_backend *parent);
struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session, struct wlr_device *dev);
bool wlr_backend_is_drm(struct wlr_backend *backend);
bool wlr_output_is_drm(struct wlr_output *output);
/**
* Get the parent DRM backend, if any.
*/
struct wlr_backend *wlr_drm_backend_get_parent(struct wlr_backend *backend);
/**
* Get the KMS connector object ID.
*/

View file

@ -1070,15 +1070,6 @@ static bool devid_from_fd(int fd, dev_t *devid) {
return true;
}
static bool is_secondary_drm_backend(struct wlr_backend *backend) {
#if WLR_HAS_DRM_BACKEND
return wlr_backend_is_drm(backend) &&
wlr_drm_backend_get_parent(backend) != NULL;
#else
return false;
#endif
}
bool wlr_linux_dmabuf_feedback_v1_init_with_options(struct wlr_linux_dmabuf_feedback_v1 *feedback,
const struct wlr_linux_dmabuf_feedback_v1_init_options *options) {
assert(options->main_renderer != NULL);
@ -1121,8 +1112,7 @@ bool wlr_linux_dmabuf_feedback_v1_init_with_options(struct wlr_linux_dmabuf_feed
wlr_log(WLR_ERROR, "Failed to intersect renderer and scanout formats");
goto error;
}
} else if (options->scanout_primary_output != NULL &&
!is_secondary_drm_backend(options->scanout_primary_output->backend)) {
} else if (options->scanout_primary_output != NULL) {
int backend_drm_fd = wlr_backend_get_drm_fd(options->scanout_primary_output->backend);
if (backend_drm_fd < 0) {
wlr_log(WLR_ERROR, "Failed to get backend DRM FD");