diff --git a/cogl/cogl-onscreen.c b/cogl/cogl-onscreen.c index 6b3cea1b3..ab898fbed 100644 --- a/cogl/cogl-onscreen.c +++ b/cogl/cogl-onscreen.c @@ -165,7 +165,9 @@ _cogl_onscreen_queue_event (CoglOnscreen *onscreen, } void -cogl_onscreen_swap_buffers (CoglOnscreen *onscreen) +cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); const CoglWinsysVtable *winsys; @@ -181,7 +183,8 @@ cogl_onscreen_swap_buffers (CoglOnscreen *onscreen) cogl_flush (); winsys = _cogl_framebuffer_get_winsys (framebuffer); - winsys->onscreen_swap_buffers (COGL_ONSCREEN (framebuffer)); + winsys->onscreen_swap_buffers_with_damage (onscreen, + rectangles, n_rectangles); cogl_framebuffer_discard_buffers (framebuffer, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH | @@ -204,6 +207,12 @@ cogl_onscreen_swap_buffers (CoglOnscreen *onscreen) onscreen->frame_counter++; } +void +cogl_onscreen_swap_buffers (CoglOnscreen *onscreen) +{ + cogl_onscreen_swap_buffers_with_damage (onscreen, NULL, 0); +} + void cogl_onscreen_swap_region (CoglOnscreen *onscreen, const int *rectangles, diff --git a/cogl/cogl-onscreen.h b/cogl/cogl-onscreen.h index 4389a43a3..9e58a3b85 100644 --- a/cogl/cogl-onscreen.h +++ b/cogl/cogl-onscreen.h @@ -322,6 +322,12 @@ cogl_onscreen_hide (CoglOnscreen *onscreen); * start a new frame that incrementally builds on the contents of the previous * frame. * + * It is highly recommended that applications use + * cogl_onscreen_swap_buffers_with_damage() instead whenever possible + * and also use the cogl_onscreen_get_buffer_age() api so they can + * perform incremental updates to older buffers instead of having to + * render a full buffer for every frame. + * * Since: 1.10 * Stability: unstable */ @@ -376,6 +382,59 @@ cogl_onscreen_swap_buffers (CoglOnscreen *onscreen); int cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen); +/** + * cogl_onscreen_swap_buffers_with_damage: + * @onscreen: A #CoglOnscreen framebuffer + * @rectangles: An array of integer 4-tuples representing damaged + * rectangles as (x, y, width, height) tuples. + * @n_rectangles: The number of 4-tuples to be read from @rectangles + * + * Swaps the current back buffer being rendered too, to the front for + * display and provides information to any system compositor about + * what regions of the buffer have changed (damage) with respect to + * the last swapped buffer. + * + * This function has the same semantics as + * cogl_framebuffer_swap_buffers() except that it additionally allows + * applications to pass a list of damaged rectangles which may be + * passed on to a compositor so that it can minimize how much of the + * screen is redrawn in response to this applications newly swapped + * front buffer. + * + * For example if your application is only animating a small object in + * the corner of the screen and everything else is remaining static + * then it can help the compositor to know that only the bottom right + * corner of your newly swapped buffer has really changed with respect + * to your previously swapped front buffer. + * + * If @n_rectangles is 0 then the whole buffer will implicitly be + * reported as damaged as if cogl_onscreen_swap_buffers() had been + * called. + * + * This function also implicitly discards the contents of the color, + * depth and stencil buffers as if cogl_framebuffer_discard_buffers() + * were used. The significance of the discard is that you should not + * expect to be able to start a new frame that incrementally builds on + * the contents of the previous frame. If you want to perform + * incremental updates to older back buffers then please refer to the + * cogl_onscreen_get_buffer_age() api. + * + * Whenever possible it is recommended that applications use this + * function instead of cogl_onscreen_swap_buffers() to improve + * performance when running under a compositor. + * + * It is highly recommended to use this API in conjunction with + * the cogl_onscreen_get_buffer_age() api so that your application can + * perform incremental rendering based on old back buffers. + * + * Since: 1.16 + * Stability: unstable + */ +void +cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles); + /** * cogl_onscreen_swap_region: * @onscreen: A #CoglOnscreen framebuffer diff --git a/cogl/winsys/cogl-winsys-egl-feature-functions.h b/cogl/winsys/cogl-winsys-egl-feature-functions.h index 5068090a2..24cc80522 100644 --- a/cogl/winsys/cogl-winsys-egl-feature-functions.h +++ b/cogl/winsys/cogl-winsys-egl-feature-functions.h @@ -101,3 +101,14 @@ COGL_WINSYS_FEATURE_BEGIN (buffer_age, COGL_WINSYS_FEATURE_END () #endif + +COGL_WINSYS_FEATURE_BEGIN (swap_buffers_with_damage, + "EXT\0", + "swap_buffers_with_damage\0", + 0) +COGL_WINSYS_FEATURE_FUNCTION (EGLBoolean, eglSwapBuffersWithDamage, + (EGLDisplay dpy, + EGLSurface surface, + const EGLint *rects, + EGLint n_rects)) +COGL_WINSYS_FEATURE_END () diff --git a/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/winsys/cogl-winsys-egl-kms.c index a2ec7b988..d24ef243a 100644 --- a/cogl/winsys/cogl-winsys-egl-kms.c +++ b/cogl/winsys/cogl-winsys-egl-kms.c @@ -719,7 +719,9 @@ _cogl_winsys_egl_cleanup_context (CoglDisplay *display) } static void -_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) +_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles) { CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglDisplayEGL *egl_display = context->display->winsys; @@ -737,8 +739,9 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) while (kms_onscreen->next_fb_id != 0) handle_drm_event (kms_renderer); - /* First chain-up. This will call eglSwapBuffers */ - parent_vtable->onscreen_swap_buffers (onscreen); + parent_vtable->onscreen_swap_buffers_with_damage (onscreen, + rectangles, + n_rectangles); /* Now we need to set the CRTC to whatever is the front buffer */ kms_onscreen->next_bo = gbm_surface_lock_front_buffer (kms_onscreen->surface); @@ -963,7 +966,8 @@ _cogl_winsys_egl_kms_get_vtable (void) /* The KMS winsys doesn't support swap region */ vtable.onscreen_swap_region = NULL; - vtable.onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers; + vtable.onscreen_swap_buffers_with_damage = + _cogl_winsys_onscreen_swap_buffers_with_damage; vtable_inited = TRUE; } diff --git a/cogl/winsys/cogl-winsys-egl-wayland.c b/cogl/winsys/cogl-winsys-egl-wayland.c index 4fc6b8888..4b7c8c154 100644 --- a/cogl/winsys/cogl-winsys-egl-wayland.c +++ b/cogl/winsys/cogl-winsys-egl-wayland.c @@ -418,7 +418,9 @@ _cogl_winsys_egl_onscreen_deinit (CoglOnscreen *onscreen) } static void -_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) +_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles) { CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen); CoglContext *context = fb->context; @@ -442,8 +444,9 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) wayland_onscreen->has_pending = FALSE; } - /* chain-up */ - parent_vtable->onscreen_swap_buffers (onscreen); + parent_vtable->onscreen_swap_buffers_with_damage (onscreen, + rectangles, + n_rectangles); /* * The implementation of eglSwapBuffers may do a flush however the semantics @@ -648,7 +651,8 @@ _cogl_winsys_egl_wayland_get_vtable (void) vtable.renderer_connect = _cogl_winsys_renderer_connect; vtable.renderer_disconnect = _cogl_winsys_renderer_disconnect; - vtable.onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers; + vtable.onscreen_swap_buffers_with_damage = + _cogl_winsys_onscreen_swap_buffers_with_damage; vtable_inited = TRUE; } diff --git a/cogl/winsys/cogl-winsys-egl.c b/cogl/winsys/cogl-winsys-egl.c index 99476523b..c81790ca7 100644 --- a/cogl/winsys/cogl-winsys-egl.c +++ b/cogl/winsys/cogl-winsys-egl.c @@ -784,7 +784,9 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, } static void -_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) +_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles) { CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; CoglRenderer *renderer = context->display->renderer; @@ -800,7 +802,29 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) COGL_FRAMEBUFFER (onscreen), COGL_FRAMEBUFFER_STATE_BIND); - eglSwapBuffers (egl_renderer->edpy, egl_onscreen->egl_surface); + if (n_rectangles && egl_renderer->pf_eglSwapBuffersWithDamage) + { + CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen); + size_t size = n_rectangles * sizeof (int) * 4; + int *flipped = alloca (size); + int i; + + memcpy (flipped, rectangles, size); + for (i = 0; i < n_rectangles; i++) + { + const int *rect = rectangles + 4 * i; + int *flip_rect = flipped + 4 * i; + flip_rect[1] = fb->height - rect[1] - rect[3]; + } + + if (egl_renderer->pf_eglSwapBuffersWithDamage (egl_renderer->edpy, + egl_onscreen->egl_surface, + flipped, + n_rectangles) == EGL_FALSE) + g_warning ("Error reported by eglSwapBuffersWithDamage"); + } + else + eglSwapBuffers (egl_renderer->edpy, egl_onscreen->egl_surface); } static void @@ -901,7 +925,8 @@ static CoglWinsysVtable _cogl_winsys_vtable = .onscreen_init = _cogl_winsys_onscreen_init, .onscreen_deinit = _cogl_winsys_onscreen_deinit, .onscreen_bind = _cogl_winsys_onscreen_bind, - .onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers, + .onscreen_swap_buffers_with_damage = + _cogl_winsys_onscreen_swap_buffers_with_damage, .onscreen_swap_region = _cogl_winsys_onscreen_swap_region, .onscreen_get_buffer_age = _cogl_winsys_onscreen_get_buffer_age, .onscreen_update_swap_throttled = diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c index eb4aff6fb..e0e2b0c88 100644 --- a/cogl/winsys/cogl-winsys-glx.c +++ b/cogl/winsys/cogl-winsys-glx.c @@ -1869,7 +1869,9 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen, } static void -_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) +_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles) { CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); CoglContext *context = framebuffer->context; @@ -2623,7 +2625,8 @@ static CoglWinsysVtable _cogl_winsys_vtable = .onscreen_init = _cogl_winsys_onscreen_init, .onscreen_deinit = _cogl_winsys_onscreen_deinit, .onscreen_bind = _cogl_winsys_onscreen_bind, - .onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers, + .onscreen_swap_buffers_with_damage = + _cogl_winsys_onscreen_swap_buffers_with_damage, .onscreen_swap_region = _cogl_winsys_onscreen_swap_region, .onscreen_get_buffer_age = _cogl_winsys_onscreen_get_buffer_age, .onscreen_update_swap_throttled = diff --git a/cogl/winsys/cogl-winsys-private.h b/cogl/winsys/cogl-winsys-private.h index b7c727ee4..ac67deea6 100644 --- a/cogl/winsys/cogl-winsys-private.h +++ b/cogl/winsys/cogl-winsys-private.h @@ -111,7 +111,9 @@ typedef struct _CoglWinsysVtable (*onscreen_bind) (CoglOnscreen *onscreen); void - (*onscreen_swap_buffers) (CoglOnscreen *onscreen); + (*onscreen_swap_buffers_with_damage) (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles); void (*onscreen_update_swap_throttled) (CoglOnscreen *onscreen); diff --git a/cogl/winsys/cogl-winsys-sdl.c b/cogl/winsys/cogl-winsys-sdl.c index 6cb246ec0..ed8212e3a 100644 --- a/cogl/winsys/cogl-winsys-sdl.c +++ b/cogl/winsys/cogl-winsys-sdl.c @@ -362,7 +362,9 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, } static void -_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) +_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles) { SDL_GL_SwapBuffers (); } @@ -430,7 +432,8 @@ _cogl_winsys_sdl_get_vtable (void) vtable.onscreen_init = _cogl_winsys_onscreen_init; vtable.onscreen_deinit = _cogl_winsys_onscreen_deinit; vtable.onscreen_bind = _cogl_winsys_onscreen_bind; - vtable.onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers; + vtable.onscreen_swap_buffers_with_damage = + _cogl_winsys_onscreen_swap_buffers_with_damage; vtable.onscreen_update_swap_throttled = _cogl_winsys_onscreen_update_swap_throttled; vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility; diff --git a/cogl/winsys/cogl-winsys-sdl2.c b/cogl/winsys/cogl-winsys-sdl2.c index dc0fad5f1..5595f461f 100644 --- a/cogl/winsys/cogl-winsys-sdl2.c +++ b/cogl/winsys/cogl-winsys-sdl2.c @@ -497,7 +497,9 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, } static void -_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) +_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles) { CoglOnscreenSdl2 *sdl_onscreen = onscreen->winsys; @@ -572,7 +574,8 @@ _cogl_winsys_sdl_get_vtable (void) vtable.onscreen_init = _cogl_winsys_onscreen_init; vtable.onscreen_deinit = _cogl_winsys_onscreen_deinit; vtable.onscreen_bind = _cogl_winsys_onscreen_bind; - vtable.onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers; + vtable.onscreen_swap_buffers_with_damage = + _cogl_winsys_onscreen_swap_buffers_with_damage; vtable.onscreen_update_swap_throttled = _cogl_winsys_onscreen_update_swap_throttled; vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility; diff --git a/cogl/winsys/cogl-winsys-stub.c b/cogl/winsys/cogl-winsys-stub.c index aee70a91d..55ae3e268 100644 --- a/cogl/winsys/cogl-winsys-stub.c +++ b/cogl/winsys/cogl-winsys-stub.c @@ -133,7 +133,9 @@ _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen) } static void -_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) +_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles) { } @@ -176,7 +178,8 @@ _cogl_winsys_stub_get_vtable (void) vtable.onscreen_init = _cogl_winsys_onscreen_init; vtable.onscreen_deinit = _cogl_winsys_onscreen_deinit; vtable.onscreen_bind = _cogl_winsys_onscreen_bind; - vtable.onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers; + vtable.onscreen_swap_buffers_with_damage = + _cogl_winsys_onscreen_swap_buffers_with_damage; vtable.onscreen_update_swap_throttled = _cogl_winsys_onscreen_update_swap_throttled; vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility; diff --git a/cogl/winsys/cogl-winsys-wgl.c b/cogl/winsys/cogl-winsys-wgl.c index 33e7ad2f2..ce2e97c36 100644 --- a/cogl/winsys/cogl-winsys-wgl.c +++ b/cogl/winsys/cogl-winsys-wgl.c @@ -836,7 +836,9 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, } static void -_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) +_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen, + const int *rectangles, + int n_rectangles) { CoglOnscreenWgl *wgl_onscreen = onscreen->winsys; @@ -901,7 +903,8 @@ _cogl_winsys_wgl_get_vtable (void) vtable.onscreen_init = _cogl_winsys_onscreen_init; vtable.onscreen_deinit = _cogl_winsys_onscreen_deinit; vtable.onscreen_bind = _cogl_winsys_onscreen_bind; - vtable.onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers; + vtable.onscreen_swap_buffers_with_damage = + _cogl_winsys_onscreen_swap_buffers_with_damage; vtable.onscreen_update_swap_throttled = _cogl_winsys_onscreen_update_swap_throttled; vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility; diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt index 006de1e71..247516095 100644 --- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt +++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt @@ -618,6 +618,7 @@ cogl_onscreen_remove_resize_callback cogl_onscreen_swap_buffers +cogl_onscreen_swap_buffers_with_damage cogl_onscreen_swap_region cogl_onscreen_set_swap_throttled CoglSwapBuffersNotify