mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-17 06:46:39 -04:00
Perform direct scanout on secondary GPUs
This change attempts to import the buffer directly into the target DRM context, and only performs drm_surface_blit if that doesn't work. Also advertise all scanout mods instead of only the ones compatible with the main dev, since we can now scan them out.
This commit is contained in:
parent
0925a529ab
commit
eb812f34f0
4 changed files with 66 additions and 33 deletions
|
|
@ -562,6 +562,7 @@ static void drm_connector_state_finish(struct wlr_drm_connector_state *state) {
|
|||
|
||||
static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn,
|
||||
struct wlr_drm_connector_state *state) {
|
||||
bool ok;
|
||||
struct wlr_drm_backend *drm = conn->backend;
|
||||
|
||||
assert(state->base->committed & WLR_OUTPUT_STATE_BUFFER);
|
||||
|
|
@ -571,34 +572,63 @@ 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_buffer *local_buf = wlr_buffer_lock(source_buf);
|
||||
|
||||
struct wlr_buffer *local_buf;
|
||||
if (drm->parent) {
|
||||
/*
|
||||
* First try to import the buffer. We can have a decent degree of
|
||||
* confidence this will work for a couple reasons:
|
||||
* 1. Apps running on the dGPU in PRIME setups will be submitting
|
||||
* buffers with linear modifiers, so that they can be imported
|
||||
* on the primary GPU. This means they are directly imporatable
|
||||
* here as well. This gives a nice FPS boost.
|
||||
* 2. When the dGPU app supports reacting to dmabuf feedback it will
|
||||
* be using dGPU modifiers, again meaning it can be imported into
|
||||
* the dGPU directly for an additional nice perf boost.
|
||||
*
|
||||
* The fallback drm_surface_blit path will only be hit when the
|
||||
* app is running fullscreen with dGPU (non-linear) modifiers and
|
||||
* we start using rendered composition again. For a frame we will
|
||||
* do the fallback before the app reallocs its buffers back to
|
||||
* linear to be compatible with the primary GPU.
|
||||
*/
|
||||
ok = drm_fb_import(&state->primary_fb, drm, local_buf,
|
||||
&crtc->primary->formats);
|
||||
|
||||
/*
|
||||
* If trying to import this buffer directly didn't work then try
|
||||
* to perform a blit to a mgpu drm surface and import that instead.
|
||||
*/
|
||||
if (!ok && 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;
|
||||
ok = false;
|
||||
goto release_buf;
|
||||
}
|
||||
|
||||
// TODO: fallback to modifier-less buffer allocation
|
||||
bool ok = init_drm_surface(&plane->mgpu_surf, &drm->mgpu_renderer,
|
||||
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;
|
||||
ok = false;
|
||||
goto release_buf;
|
||||
}
|
||||
|
||||
local_buf = drm_surface_blit(&plane->mgpu_surf, source_buf);
|
||||
if (local_buf == NULL) {
|
||||
return false;
|
||||
struct wlr_buffer *drm_buf = drm_surface_blit(&plane->mgpu_surf,
|
||||
&drm->parent->mgpu_renderer, source_buf);
|
||||
if (drm_buf == NULL) {
|
||||
ok = false;
|
||||
goto release_buf;
|
||||
}
|
||||
} else {
|
||||
local_buf = wlr_buffer_lock(source_buf);
|
||||
ok = drm_fb_import(&state->primary_fb, drm, drm_buf,
|
||||
&plane->formats);
|
||||
wlr_buffer_unlock(drm_buf);
|
||||
}
|
||||
|
||||
bool ok = drm_fb_import(&state->primary_fb, drm, local_buf,
|
||||
&plane->formats);
|
||||
release_buf:
|
||||
wlr_buffer_unlock(local_buf);
|
||||
|
||||
if (!ok) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Failed to import buffer for scan-out");
|
||||
|
|
@ -1012,7 +1042,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
|
|||
return false;
|
||||
}
|
||||
|
||||
local_buf = drm_surface_blit(&plane->mgpu_surf, buffer);
|
||||
local_buf = drm_surface_blit(&plane->mgpu_surf, &drm->parent->mgpu_renderer, buffer);
|
||||
if (local_buf == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ bool init_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_renderer *parent_renderer, struct wlr_buffer *buffer) {
|
||||
struct wlr_renderer *renderer = surf->renderer->wlr_rend;
|
||||
|
||||
if (surf->swapchain->width != buffer->width ||
|
||||
|
|
@ -84,11 +84,23 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
|
|||
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");
|
||||
struct wlr_texture_set *set = wlr_texture_set_create(renderer, NULL);
|
||||
if (set == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to import source buffer multi-GPU texture set");
|
||||
return NULL;
|
||||
}
|
||||
/* Add the parent renderer so the texture set can use it for copies */
|
||||
wlr_texture_set_add_renderer(set, parent_renderer->wlr_rend, parent_renderer->allocator);
|
||||
if (!wlr_texture_set_import_buffer(set, buffer)) {
|
||||
wlr_log(WLR_ERROR, "Failed to import source buffer multi-GPU texture set");
|
||||
goto error_tex;
|
||||
}
|
||||
|
||||
struct wlr_texture *tex = wlr_texture_set_get_tex_for_renderer(set, renderer);
|
||||
if (tex == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to export source buffer for multi-GPU renderer");
|
||||
goto error_tex;
|
||||
}
|
||||
|
||||
struct wlr_buffer *dst = wlr_swapchain_acquire(surf->swapchain, NULL);
|
||||
if (!dst) {
|
||||
|
|
@ -111,14 +123,14 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
|
|||
goto error_dst;
|
||||
}
|
||||
|
||||
wlr_texture_destroy(tex);
|
||||
wlr_texture_set_destroy(set);
|
||||
|
||||
return dst;
|
||||
|
||||
error_dst:
|
||||
wlr_buffer_unlock(dst);
|
||||
error_tex:
|
||||
wlr_texture_destroy(tex);
|
||||
wlr_texture_set_destroy(set);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ bool init_drm_surface(struct wlr_drm_surface *surf,
|
|||
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_renderer *parent_renderer, struct wlr_buffer *buffer);
|
||||
|
||||
bool drm_plane_pick_render_format(struct wlr_drm_plane *plane,
|
||||
struct wlr_drm_format *fmt, struct wlr_drm_renderer *renderer);
|
||||
|
|
|
|||
|
|
@ -1096,15 +1096,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);
|
||||
|
|
@ -1147,8 +1138,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");
|
||||
|
|
@ -1174,8 +1164,9 @@ bool wlr_linux_dmabuf_feedback_v1_init_with_options(struct wlr_linux_dmabuf_feed
|
|||
|
||||
tranche->target_device = backend_dev;
|
||||
tranche->flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT;
|
||||
if (!wlr_drm_format_set_intersect(&tranche->formats, scanout_formats, renderer_formats)) {
|
||||
wlr_log(WLR_ERROR, "Failed to intersect renderer and scanout formats");
|
||||
// Copy our scanout formats to the scanout tranche
|
||||
if (!wlr_drm_format_set_copy(&tranche->formats, scanout_formats)) {
|
||||
wlr_log(WLR_ERROR, "Failed to copy scanout formats");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue