[Cogl] [PATCH 2/2] wayland: Don't delay resize if nothing is drawn since last swap
Robert Bragg
robert at sixbynine.org
Wed May 29 10:46:55 PDT 2013
Cool, thanks for all the updates, this looks good to land to me:
Reviewed-by: Robert Bragg <robert at linux.intel.com>
thanks,
- Robert
On Wed, May 29, 2013 at 5:44 PM, Neil Roberts <neil at linux.intel.com> wrote:
> After discussing with Kristian Høgsberg it seems that the semantics of
> wl_egl_window_resize is meant to be that if nothing has been drawn to
> the framebuffer since the last swap then the resize will take effect
> immediately. Cogl was previously always delaying the call to
> wl_egl_window_resize until the next swap. That meant that if you
> wanted to resize the surface you would have to call
> cogl_wayland_onscreen_resize and then redundantly draw a frame at the
> old size so that you can swap to get the resize to occur before
> drawing again at the right size. Typically an application would decide
> to resize at the start of its paint sequence so it should be able to
> just resize immediately.
>
> In current Mesa master it seems that there is a bug which means that
> it won't actually delay a resize that is done mid-scene and instead it
> will just discard what came before. To get consistent behaviour in
> Cogl, the code to delay the call to wl_egl_window_resize is still used
> if it determines that the buffer is dirty. There is an existing
> _cogl_framebuffer_mark_mid_scene call which was being used to track
> when the framebuffer becomes dirty since the last clear. This function
> is now also used to track a new flag to track whether something has
> been drawn since the last swap. It is called ‘mid_scene’ under the
> assumption that this may also be useful for other things later.
>
> cogl_framebuffer_clear has been slightly altered to always call
> _cogl_framebuffer_mark_mid_scene even if it determines that it doesn't
> need to clear because the framebuffer should still be considered to be
> in the middle of a scene. Adding a quad to the journal now also begins
> the scene.
>
> This also fixes a potential bug where it looks like pending_dx/dy were
> never cleared so they would always be accumulated even after the
> resize is flushed.
> ---
> cogl/cogl-framebuffer-private.h | 4 ++++
> cogl/cogl-framebuffer.c | 5 +++--
> cogl/cogl-journal.c | 6 ++++++
> cogl/cogl-onscreen.c | 2 ++
> cogl/cogl-onscreen.h | 21 ++++++++++++--------
> cogl/winsys/cogl-winsys-egl-wayland.c | 37 ++++++++++++++++++++++++++---------
> 6 files changed, 56 insertions(+), 19 deletions(-)
>
> diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h
> index bc1b4c9..2dfcb6e 100644
> --- a/cogl/cogl-framebuffer-private.h
> +++ b/cogl/cogl-framebuffer-private.h
> @@ -170,6 +170,10 @@ struct _CoglFramebuffer
> int clear_clip_y1;
> CoglBool clear_clip_dirty;
>
> + /* Whether something has been drawn to the buffer since the last
> + * swap buffers or swap region. */
> + CoglBool mid_scene;
> +
> /* driver specific */
> CoglBool dirty_bitmasks;
> CoglFramebufferBits bits;
> diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
> index a6a9a8d..4faad61 100644
> --- a/cogl/cogl-framebuffer.c
> +++ b/cogl/cogl-framebuffer.c
> @@ -228,6 +228,7 @@ void
> _cogl_framebuffer_mark_mid_scene (CoglFramebuffer *framebuffer)
> {
> framebuffer->clear_clip_dirty = TRUE;
> + framebuffer->mid_scene = TRUE;
> }
>
> void
> @@ -353,6 +354,8 @@ cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
>
> cleared:
>
> + _cogl_framebuffer_mark_mid_scene (framebuffer);
> +
> if (buffers & COGL_BUFFER_BIT_COLOR && buffers & COGL_BUFFER_BIT_DEPTH)
> {
> /* For our fast-path for reading back a single pixel of simple
> @@ -380,8 +383,6 @@ cleared:
> /* FIXME: set degenerate clip */
> }
> }
> - else
> - _cogl_framebuffer_mark_mid_scene (framebuffer);
> }
>
> /* Note: the 'buffers' and 'color' arguments were switched around on
> diff --git a/cogl/cogl-journal.c b/cogl/cogl-journal.c
> index f651a55..518a797 100644
> --- a/cogl/cogl-journal.c
> +++ b/cogl/cogl-journal.c
> @@ -1445,6 +1445,12 @@ _cogl_journal_log_quad (CoglJournal *journal,
>
> COGL_TIMER_START (_cogl_uprof_context, log_timer);
>
> + /* Adding something to the journal should mean that we are in the
> + * middle of the scene. Although this will also end up being set
> + * when the journal is actually flushed, we set it here explicitly
> + * so that we will know sooner */
> + _cogl_framebuffer_mark_mid_scene (framebuffer);
> +
> /* If the framebuffer was previously empty then we'll take a
> reference to the current framebuffer. This reference will be
> removed when the journal is flushed */
> diff --git a/cogl/cogl-onscreen.c b/cogl/cogl-onscreen.c
> index 03c4849..9f4a215 100644
> --- a/cogl/cogl-onscreen.c
> +++ b/cogl/cogl-onscreen.c
> @@ -172,6 +172,7 @@ cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
> }
>
> onscreen->frame_counter++;
> + framebuffer->mid_scene = FALSE;
> }
>
> void
> @@ -227,6 +228,7 @@ cogl_onscreen_swap_region (CoglOnscreen *onscreen,
> }
>
> onscreen->frame_counter++;
> + framebuffer->mid_scene = FALSE;
> }
>
> int
> diff --git a/cogl/cogl-onscreen.h b/cogl/cogl-onscreen.h
> index 2bce1c4..2646d40 100644
> --- a/cogl/cogl-onscreen.h
> +++ b/cogl/cogl-onscreen.h
> @@ -212,12 +212,12 @@ cogl_wayland_onscreen_set_foreign_surface (CoglOnscreen *onscreen,
> * @width: The desired width of the framebuffer
> * @height: The desired height of the framebuffer
> * @offset_x: A relative x offset for the new framebuffer
> - * @offset_y: A relative x offset for the new framebuffer
> + * @offset_y: A relative y offset for the new framebuffer
> *
> - * Queues a resize of the given @onscreen framebuffer which will be applied
> - * during the next swap buffers request. Since a buffer is usually conceptually
> - * scaled with a center point the @offset_x and @offset_y arguments allow the
> - * newly allocated buffer to be positioned relative to the old buffer size.
> + * Resizes the backbuffer of the given @onscreen framebuffer to the
> + * given size. Since a buffer is usually conceptually scaled with a
> + * center point the @offset_x and @offset_y arguments allow the newly
> + * allocated buffer to be positioned relative to the old buffer size.
> *
> * For example a buffer that is being resized by moving the bottom right
> * corner, and the top left corner is remaining static would use x and y
> @@ -228,9 +228,14 @@ cogl_wayland_onscreen_set_foreign_surface (CoglOnscreen *onscreen,
> * x/y_size_increase is how many pixels bigger the buffer is on the x and y
> * axis.
> *
> - * If cogl_wayland_onscreen_resize() is called multiple times before the next
> - * swap buffers request then the relative x and y offsets accumulate instead of
> - * being replaced. The @width and @height values superseed the old values.
> + * Note that if some drawing commands have been applied to the
> + * framebuffer since the last swap buffers then the resize will be
> + * queued and will only take effect in the next swap buffers.
> + *
> + * If multiple calls to cogl_wayland_onscreen_resize() get queued
> + * before the next swap buffers request then the relative x and y
> + * offsets accumulate instead of being replaced. The @width and
> + * @height values superseed the old values.
> *
> * Since: 1.10
> * Stability: unstable
> diff --git a/cogl/winsys/cogl-winsys-egl-wayland.c b/cogl/winsys/cogl-winsys-egl-wayland.c
> index 95f3008..6732547 100644
> --- a/cogl/winsys/cogl-winsys-egl-wayland.c
> +++ b/cogl/winsys/cogl-winsys-egl-wayland.c
> @@ -419,15 +419,8 @@ _cogl_winsys_egl_onscreen_deinit (CoglOnscreen *onscreen)
> }
>
> static void
> -_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
> - const int *rectangles,
> - int n_rectangles)
> +flush_pending_resize (CoglOnscreen *onscreen)
> {
> - CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
> - CoglContext *context = fb->context;
> - CoglRenderer *renderer = context->display->renderer;
> - CoglRendererEGL *egl_renderer = renderer->winsys;
> - CoglRendererWayland *wayland_renderer = egl_renderer->platform;
> CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
> CoglOnscreenWayland *wayland_onscreen = egl_onscreen->platform;
>
> @@ -439,11 +432,28 @@ _cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
> wayland_onscreen->pending_dx,
> wayland_onscreen->pending_dy);
>
> - _cogl_framebuffer_winsys_update_size (fb,
> + _cogl_framebuffer_winsys_update_size (COGL_FRAMEBUFFER (onscreen),
> wayland_onscreen->pending_width,
> wayland_onscreen->pending_height);
> +
> + wayland_onscreen->pending_dx = 0;
> + wayland_onscreen->pending_dy = 0;
> wayland_onscreen->has_pending = FALSE;
> }
> +}
> +
> +static void
> +_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
> + const int *rectangles,
> + int n_rectangles)
> +{
> + CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
> + CoglContext *context = fb->context;
> + CoglRenderer *renderer = context->display->renderer;
> + CoglRendererEGL *egl_renderer = renderer->winsys;
> + CoglRendererWayland *wayland_renderer = egl_renderer->platform;
> +
> + flush_pending_resize (onscreen);
>
> parent_vtable->onscreen_swap_buffers_with_damage (onscreen,
> rectangles,
> @@ -640,6 +650,15 @@ cogl_wayland_onscreen_resize (CoglOnscreen *onscreen,
> wayland_onscreen->pending_dx += offset_x;
> wayland_onscreen->pending_dy += offset_y;
> wayland_onscreen->has_pending = TRUE;
> +
> + /* If nothing has been drawn to the framebuffer since the
> + * last swap then wl_egl_window_resize will take effect
> + * immediately. Otherwise it might not take effect until the
> + * next swap, depending on the version of Mesa. To keep
> + * consistent behaviour we'll delay the resize until the
> + * next swap unless we're sure nothing has been drawn */
> + if (!fb->mid_scene)
> + flush_pending_resize (onscreen);
> }
> }
> else
> --
> 1.7.11.3.g3c3efa5
>
> _______________________________________________
> Cogl mailing list
> Cogl at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/cogl
More information about the Cogl
mailing list