mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2026-05-08 17:09:41 +02:00
drm-backend: Reuse prior state where possible
If we're in a steady state, doing nothing but flipping buffers, we can try to avoid going through our full routine of brute-forcing an acceptable plane state, by instead just reusing the old state and changing only the FB it refers to. Signed-off-by: Daniel Stone <daniels@collabora.com> Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
This commit is contained in:
parent
e2cda4570e
commit
119ce40714
3 changed files with 140 additions and 7 deletions
|
|
@ -342,6 +342,7 @@ enum drm_output_propose_state_mode {
|
|||
DRM_OUTPUT_PROPOSE_STATE_RENDERER_AND_CURSOR, /**< only assign to renderer & cursor plane */
|
||||
DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY, /**< only assign to renderer */
|
||||
DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY, /**< no renderer use, only planes */
|
||||
DRM_OUTPUT_PROPOSE_STATE_REUSE = 128, /**< bit indicates reuse prior state with new buffers */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -407,6 +407,9 @@ drm_output_state_duplicate(struct drm_output_state *src,
|
|||
|
||||
assert(dst);
|
||||
|
||||
/* The reuse bit isn't stored in the state */
|
||||
assert(!(src->mode & DRM_OUTPUT_PROPOSE_STATE_REUSE));
|
||||
|
||||
/* Copy the whole structure, then individually modify the
|
||||
* pending_state, as well as the list link into our pending
|
||||
* state. */
|
||||
|
|
|
|||
|
|
@ -53,13 +53,27 @@ static const char *const drm_output_propose_state_mode_as_string[] = {
|
|||
[DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY] = "plane-only state"
|
||||
};
|
||||
|
||||
static const char *const drm_output_propose_reused_state_mode_as_string[] = {
|
||||
[DRM_OUTPUT_PROPOSE_STATE_INVALID] = "reused invalid(uninitialized) state",
|
||||
[DRM_OUTPUT_PROPOSE_STATE_MIXED] = "reused mixed state",
|
||||
[DRM_OUTPUT_PROPOSE_STATE_RENDERER_AND_CURSOR] = "reused renderer-and-cursor state",
|
||||
[DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY] = "reused renderer-only state",
|
||||
[DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY] = "reused plane-only state",
|
||||
};
|
||||
|
||||
static const char *
|
||||
drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode)
|
||||
{
|
||||
bool reuse = mode & DRM_OUTPUT_PROPOSE_STATE_REUSE;
|
||||
|
||||
mode &= ~DRM_OUTPUT_PROPOSE_STATE_REUSE;
|
||||
if (mode < 0 || mode >= ARRAY_LENGTH(drm_output_propose_state_mode_as_string))
|
||||
return " unknown compositing mode";
|
||||
|
||||
return drm_output_propose_state_mode_as_string[mode];
|
||||
if (reuse)
|
||||
return drm_output_propose_reused_state_mode_as_string[mode];
|
||||
else
|
||||
return drm_output_propose_state_mode_as_string[mode];
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -889,13 +903,118 @@ drm_output_propose_state(struct weston_output *output_base,
|
|||
pixman_region32_t renderer_region;
|
||||
pixman_region32_t background_region;
|
||||
|
||||
bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
|
||||
int ret;
|
||||
/* Record the current lowest zpos of the overlay planes */
|
||||
uint64_t current_lowest_zpos_overlay = DRM_PLANE_ZPOS_INVALID_PLANE;
|
||||
/* Record the current lowest zpos of the underlay plane */
|
||||
uint64_t current_lowest_zpos_underlay = DRM_PLANE_ZPOS_INVALID_PLANE;
|
||||
|
||||
if (mode & DRM_OUTPUT_PROPOSE_STATE_REUSE) {
|
||||
struct weston_paint_node *pnode;
|
||||
bool found_primary = false;
|
||||
|
||||
if (output->state_cur->mode == DRM_OUTPUT_PROPOSE_STATE_INVALID) {
|
||||
debug_propose_fail(output, mode, "no previous state");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (output_base->paint_node_changes & ~WESTON_PAINT_NODE_BUFFER_DIRTY) {
|
||||
debug_propose_fail(output, mode, "state is outdated");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = drm_output_state_duplicate(output->state_cur,
|
||||
pending_state,
|
||||
DRM_OUTPUT_STATE_PRESERVE_PLANES);
|
||||
if (!state) {
|
||||
debug_propose_fail(output, mode, "could not clone prior state");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (state->planes_enabled != !output_base->disable_planes) {
|
||||
debug_propose_fail(output, mode, "planes_enabled changed");
|
||||
drm_output_state_free(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_list_for_each(pnode, &output_base->paint_node_z_order_list,
|
||||
z_order_link) {
|
||||
enum try_view_on_plane_failure_reasons reasons;
|
||||
struct drm_plane_state *pstate;
|
||||
struct drm_plane *plane;
|
||||
struct drm_fb *fb;
|
||||
|
||||
drm_debug(b, "\t\t[reuse] have seen pnode %p (view %p)\n", pnode, pnode->view);
|
||||
|
||||
/* we don't care about renderer views */
|
||||
if (pnode->plane == &output_base->primary_plane) {
|
||||
drm_debug(b, "\t\t[reuse] ignoring view %p on renderer plane\n", pnode->view);
|
||||
continue;
|
||||
}
|
||||
plane = (struct drm_plane *) pnode->plane;
|
||||
pstate = drm_output_state_get_existing_plane(state, plane);
|
||||
assert(pstate);
|
||||
pstate->ev = pnode->view;
|
||||
|
||||
/* cursor is handled out of band */
|
||||
if (plane->type == WDRM_PLANE_TYPE_CURSOR) {
|
||||
drm_debug(b, "\t\t[reuse] ignoring cursor plane for view %p\n", pnode->view);
|
||||
continue;
|
||||
}
|
||||
|
||||
drm_debug(b, "\t\t[reuse] view %p has plane %d\n", pnode->view, plane->plane_id);
|
||||
|
||||
if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
|
||||
found_primary = true;
|
||||
|
||||
fb = drm_fb_get_from_paint_node(state, pnode, &reasons);
|
||||
if (!fb) {
|
||||
char *fr_str = bits_to_str(pnode->try_view_on_plane_failure_reasons,
|
||||
weston_plane_failure_reasons_to_str);
|
||||
char *msg;
|
||||
|
||||
str_printf(&msg, "couldn't get new FB: %s", fr_str);
|
||||
debug_propose_fail(output, mode, msg);
|
||||
free(msg);
|
||||
free(fr_str);
|
||||
drm_output_state_free(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drm_fb_unref(pstate->fb);
|
||||
pstate->fb = fb;
|
||||
|
||||
pstate->in_fence_fd = pnode->surface->acquire_fence_fd;
|
||||
drm_debug(b, "\t\t[reuse] successfully stole away pnode %p to reused plane\n", pnode);
|
||||
/* XXX: When we set non-default color states in DRM, make sure they match */
|
||||
weston_buffer_reference(&pstate->fb_ref.buffer,
|
||||
pnode->surface->buffer_ref.buffer,
|
||||
BUFFER_MAY_BE_ACCESSED);
|
||||
weston_buffer_release_reference(&pstate->fb_ref.release,
|
||||
pnode->surface->buffer_release_ref.buffer_release);
|
||||
}
|
||||
|
||||
if (drm_pending_state_test(pending_state) != 0) {
|
||||
debug_propose_fail(output, mode, "atomic test not OK");
|
||||
drm_output_state_free(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!found_primary) {
|
||||
struct drm_plane_state *pstate =
|
||||
drm_output_state_get_existing_plane(state, output->scanout_plane);
|
||||
/* drm_output_repaint expects to see this */
|
||||
drm_debug(b, "\t\t[reuse] dropped reference on renderer fb %p\n", pstate->fb);
|
||||
assert(pstate->fb->type == BUFFER_GBM_SURFACE ||
|
||||
pstate->fb->type == BUFFER_PIXMAN_DUMB ||
|
||||
pstate->fb->type == BUFFER_DMABUF_BACKEND);
|
||||
drm_fb_unref(pstate->fb);
|
||||
pstate->fb = NULL;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
assert(!output->state_last);
|
||||
state = drm_output_state_duplicate(output->state_cur,
|
||||
pending_state,
|
||||
|
|
@ -1036,6 +1155,7 @@ drm_output_propose_state(struct weston_output *output_base,
|
|||
struct drm_plane_state *ps = NULL;
|
||||
bool need_underlay = false;
|
||||
pixman_region32_t tmp;
|
||||
bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
|
||||
|
||||
drm_debug(b, "\t\t\t[view] evaluating view %p for plane "
|
||||
"assignment on output %s (%lu)\n",
|
||||
|
|
@ -1196,21 +1316,30 @@ drm_assign_planes(struct weston_output *output_base)
|
|||
struct drm_device *device = output->device;
|
||||
struct drm_backend *b = device->backend;
|
||||
struct drm_pending_state *pending_state = device->repaint_data;
|
||||
struct drm_output_state *state = NULL;
|
||||
struct drm_output_state *state;
|
||||
struct drm_plane_state *plane_state;
|
||||
struct drm_writeback_state *wb_state = output->wb_state;
|
||||
struct weston_paint_node *pnode;
|
||||
struct weston_plane *primary = &output_base->primary_plane;
|
||||
enum drm_output_propose_state_mode mode = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY;
|
||||
enum drm_output_propose_state_mode mode;
|
||||
|
||||
assert(output);
|
||||
|
||||
drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n",
|
||||
output_base->name, (unsigned long) output_base->id);
|
||||
|
||||
if (!device->sprites_are_broken && !output_base->disable_planes &&
|
||||
!output->is_virtual && b->gbm) {
|
||||
drm_debug(b, "\t[repaint] trying to reuse prior %s\n",
|
||||
drm_propose_state_mode_to_string(output->state_cur->mode));
|
||||
|
||||
mode = DRM_OUTPUT_PROPOSE_STATE_REUSE | output->state_cur->mode;
|
||||
state = drm_output_propose_state(output_base, pending_state, mode);
|
||||
if (!state)
|
||||
drm_debug(b, "\t[repaint] could not reuse prior state\n");
|
||||
|
||||
if (!state && !device->sprites_are_broken &&
|
||||
!output_base->disable_planes && !output->is_virtual && b->gbm) {
|
||||
drm_debug(b, "\t[repaint] trying planes-only build state\n");
|
||||
mode = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY;
|
||||
state = drm_output_propose_state(output_base, pending_state, mode);
|
||||
if (!state) {
|
||||
drm_debug(b, "\t[repaint] could not build planes-only "
|
||||
|
|
@ -1220,7 +1349,7 @@ drm_assign_planes(struct weston_output *output_base)
|
|||
pending_state,
|
||||
mode);
|
||||
}
|
||||
} else {
|
||||
} else if (!state) {
|
||||
drm_debug(b, "\t[state] no overlay plane support\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue