Hi Daniel
On 09/12/16 20:58, Daniel Stone wrote: > Generate an output state in two stages. Firstly, attempt to run through > and generate a configuration with all views in planes. If this succeeds, > we can bypass the renderer completely. > > If this fails, we know we need to have the renderer output used as a > base on the scanout plane, and can incrementally attempt to construct a > working state, by trying the combination of our old renderer state with > planes added one-by-one. If they pass the test commit stage, we can use > it, so we stash that state and continue on. > > Signed-off-by: Daniel Stone <dani...@collabora.com> > > Differential Revision: https://phabricator.freedesktop.org/D1535 > --- > libweston/compositor-drm.c | 135 > +++++++++++++++++++++++++++++++++------------ > 1 file changed, 101 insertions(+), 34 deletions(-) > > diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c > index e51a5b2..7c8b5d9 100644 > --- a/libweston/compositor-drm.c > +++ b/libweston/compositor-drm.c > @@ -1669,12 +1669,15 @@ enum drm_output_propose_state_mode { > > static struct drm_plane_state * > drm_output_prepare_scanout_view(struct drm_output_state *output_state, > - struct weston_view *ev) > + struct weston_view *ev, > + enum drm_output_propose_state_mode mode) > { > struct drm_output *output = output_state->output; > struct drm_plane *scanout_plane = output->scanout_plane; > struct drm_plane_state *state; > + struct drm_plane_state *state_old = NULL; > struct drm_fb *fb; > + int ret; > > fb = drm_fb_get_from_view(output_state, ev); > if (!fb) > @@ -1687,7 +1690,16 @@ drm_output_prepare_scanout_view(struct > drm_output_state *output_state, > } > > state = drm_output_state_get_plane(output_state, scanout_plane); > - if (state->fb) { > + > + /* Check if we've already placed a buffer on this plane; if there's a > + * buffer there but it comes from GBM, then it's the result of > + * drm_output_propose_state placing it here for testing purposes. */ > + if (state->fb && > + (state->fb->type == BUFFER_GBM_SURFACE || > + state->fb->type == BUFFER_PIXMAN_DUMB)) { > + state_old = calloc(1, sizeof(*state_old)); > + memcpy(state_old, state, sizeof(*state_old)); > + } else if (state->fb) { > drm_fb_unref(fb); > return NULL; > } > @@ -1706,10 +1718,21 @@ drm_output_prepare_scanout_view(struct > drm_output_state *output_state, > state->dest_h != (unsigned) output->base.current_mode->height) > goto err; > > + if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) > + return state; > + > + ret = drm_output_apply_state(output_state, mode); "mode" is not the correct parameter (it is an 'enum drm_output_propose_state_mode' and drm_output_apply_state expects an 'enum drm_output_apply_state_mode mode'). Use DRM_OUTPUT_APPLY_STATE_TEST instead of mode > + if (ret != 0) > + goto err; > + > return state; > > err: > - drm_plane_state_put_back(state); > + drm_plane_state_free(state, false); > + if (state_old) { > + wl_list_insert(&output_state->plane_list, &state_old->link); > + state_old->output_state = output_state; > + } > return NULL; > } > > @@ -1780,7 +1803,9 @@ drm_output_render(struct drm_output *output, > pixman_region32_t *damage) > * want to render. */ > scanout_state = drm_output_state_get_plane(output->state_pending, > output->scanout_plane); > - if (scanout_state->fb) > + if (scanout_state->fb && > + scanout_state->fb->type != BUFFER_GBM_SURFACE && > + scanout_state->fb->type != BUFFER_PIXMAN_DUMB) > return; > > if (!pixman_region32_not_empty(damage) && > @@ -1803,6 +1828,7 @@ drm_output_render(struct drm_output *output, > pixman_region32_t *damage) > return; > } > > + drm_fb_unref(scanout_state->fb); > scanout_state->fb = fb; > scanout_state->output = output; > > @@ -2401,24 +2427,24 @@ atomic_flip_handler(int fd, unsigned int frame, > > static struct drm_plane_state * > drm_output_prepare_overlay_view(struct drm_output_state *output_state, > - struct weston_view *ev) > + struct weston_view *ev, > + enum drm_output_propose_state_mode mode) > { > struct drm_output *output = output_state->output; > struct weston_compositor *ec = output->base.compositor; > struct drm_backend *b = to_drm_backend(ec); > struct drm_plane *p; > - struct drm_plane_state *state = NULL; > struct drm_fb *fb; > unsigned int i; > - > - if (b->sprites_are_broken) > - return NULL; > + int ret; > > fb = drm_fb_get_from_view(output_state, ev); > if (!fb) > return NULL; > > wl_list_for_each(p, &b->plane_list, link) { > + struct drm_plane_state *state = NULL; > + > if (p->type != WDRM_PLANE_TYPE_OVERLAY) > continue; > > @@ -2444,28 +2470,30 @@ drm_output_prepare_overlay_view(struct > drm_output_state *output_state, > continue; > } > > - break; > - } > + state->fb = fb; > + state->ev = ev; > + state->output = output; > > - /* No sprites available */ > - if (!state) { > - drm_fb_unref(fb); > - return NULL; > - } > + drm_plane_state_coords_for_view(state, ev); > + if (state->src_w != state->dest_w << 16 || > + state->src_h != state->dest_h << 16) { > + drm_plane_state_put_back(state); > + continue; > + } > > - state->fb = fb; > - state->ev = ev; > - state->output = output; > + /* In planes-only mode, we don't have an incremental state to > + * test against, so we just hope it'll work. */ > + if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) > + return state; > > - drm_plane_state_coords_for_view(state, ev); > - if (state->src_w != state->dest_w << 16 || > - state->src_h != state->dest_h << 16) > - goto err; > + ret = drm_output_apply_state(output_state, mode); Same remark here > + if (ret == 0) > + return state; > > - return state; > + drm_plane_state_put_back(state); > + } > > -err: > - drm_plane_state_put_back(state); > + drm_fb_unref(fb); > return NULL; > } > > @@ -2665,12 +2693,42 @@ drm_output_propose_state(struct weston_output > *output_base, > struct weston_view *ev; > pixman_region32_t surface_overlap, renderer_region, occluded_region; > bool renderer_ok = (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY); > - bool planes_ok = !b->sprites_are_broken; > + bool planes_ok = false; > + bool duplicate_renderer = false; > + int ret; > + > + /* We can only propose planes if we're in plane-only mode (i.e. just > + * get as much as possible into planes and test at the end), or mixed > + * mode, where we have our previous renderer buffer (and it's broadly > + * compatible) to test with. If we don't have these things, then we > + * don't know whether or not the planes will work, so we conservatively > + * fall back to just using the renderer. */ > + if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) { > + if (b->sprites_are_broken) > + return NULL; > + planes_ok = true; > + } else if (output->scanout_plane->state_cur->fb) { > + struct drm_fb *scanout_fb = > + output->scanout_plane->state_cur->fb; > + if ((scanout_fb->type == BUFFER_GBM_SURFACE || > + scanout_fb->type == BUFFER_PIXMAN_DUMB) && > + scanout_fb->width == output_base->current_mode->width && > + scanout_fb->height == output_base->current_mode->height) { > + planes_ok = true; > + duplicate_renderer = true; > + } > + } > > assert(!output->state_last); > assert(!output->state_pending); > state = drm_output_state_duplicate(output->state_cur, > DRM_OUTPUT_STATE_CLEAR_PLANES); > + if (!planes_ok) > + return state; > + > + if (duplicate_renderer) > + drm_plane_state_duplicate(state, > + output->scanout_plane->state_cur); > > /* > * Find a surface for each sprite in the output using some heuristics: > @@ -2704,6 +2762,9 @@ drm_output_propose_state(struct weston_output > *output_base, > if (ev->output_mask != (1u << output->base.id)) > force_renderer = true; > > + if (!ev->surface->buffer_ref.buffer) > + force_renderer = true; > + > /* Ignore views we know to be totally occluded. */ > pixman_region32_init(&surface_overlap); > pixman_region32_subtract(&surface_overlap, > @@ -2737,17 +2798,13 @@ drm_output_propose_state(struct weston_output > *output_base, > * cursors_are_broken flag. */ > if (!force_renderer && !b->cursors_are_broken) > ps = drm_output_prepare_cursor_view(state, ev); > - if (!planes_ok) > - force_renderer = true; > if (!force_renderer && !ps) > - ps = drm_output_prepare_scanout_view(state, ev); > + ps = drm_output_prepare_scanout_view(state, ev, mode); > if (!force_renderer && !ps) > - ps = drm_output_prepare_overlay_view(state, ev); > + ps = drm_output_prepare_overlay_view(state, ev, mode); > > if (ps) > continue; > - if (!renderer_ok) > - goto err; > > pixman_region32_union(&renderer_region, > &renderer_region, > @@ -2756,6 +2813,11 @@ drm_output_propose_state(struct weston_output > *output_base, > pixman_region32_fini(&renderer_region); > pixman_region32_fini(&occluded_region); > > + /* Check to see if this state will actually work. */ > + ret = drm_output_apply_state(state, DRM_OUTPUT_APPLY_STATE_TEST); > + if (ret != 0) > + goto err; > + > return state; > > err: > @@ -2776,7 +2838,12 @@ drm_assign_planes(struct weston_output *output_base) > struct weston_plane *primary = &output_base->compositor->primary_plane; > > state = drm_output_propose_state(output_base, > - DRM_OUTPUT_PROPOSE_STATE_MIXED); > + DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY); > + if (!state) > + state = drm_output_propose_state(output_base, > + > DRM_OUTPUT_PROPOSE_STATE_MIXED); > + > + assert(state); > > wl_list_for_each(ev, &output_base->compositor->view_list, link) { > struct drm_plane *target_plane = NULL; Fabien BR _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel