[PATCH v2] egl: Adds EGL_EXT_swap_buffers_with_damage implementation

Robert Bragg robert at sixbynine.org
Sat Feb 11 08:56:43 PST 2012


This adds an implementation of EGL_EXT_swap_buffers_with_damage which
provides an alternative for eglSwapBuffers called
eglSwapBuffersWithDamageEXT that has identical semantics except that it
takes a list of damage rectangles that may be passed to a compositor
when running as a client in a compositing environment. The compositor
can optionally use this region to optimize how much of the screen it
redraws in response to the clients new front buffer.

Currently this is only supported by the wayland EGL platform.

Signed-off-by: Robert Bragg <robert at sixbynine.org>
---
 docs/EXT_swap_buffers_with_damage.txt   |  138 +++++++++++++++++++++++++++++++
 include/EGL/eglext.h                    |    8 ++
 src/egl/drivers/dri2/platform_wayland.c |   25 +++++-
 src/egl/main/eglapi.c                   |   28 ++++++
 src/egl/main/eglapi.h                   |    8 ++
 src/egl/main/egldisplay.h               |    2 +
 src/egl/main/eglmisc.c                  |    2 +
 7 files changed, 208 insertions(+), 3 deletions(-)
 create mode 100644 docs/EXT_swap_buffers_with_damage.txt

diff --git a/docs/EXT_swap_buffers_with_damage.txt b/docs/EXT_swap_buffers_with_damage.txt
new file mode 100644
index 0000000..605338f
--- /dev/null
+++ b/docs/EXT_swap_buffers_with_damage.txt
@@ -0,0 +1,138 @@
+EGL_EXT_swap_buffers_with_damage
+
+    EXT_swap_buffers_with_damage
+
+Name Strings
+
+    EGL_EXT_swap_buffers_with_damage
+
+Notice
+
+    Copyright 2011 Intel Cooperation. All rights reserved.
+
+Contributors
+
+    Robert Bragg
+    Tapani Pälli
+    Kristian Høgsberg
+
+Contacts
+
+    Robert Bragg, Intel (robert.bragg 'at' intel.com)
+
+Status
+
+    Draft
+
+Version
+
+    4 - Feb 11, 2012
+
+Number
+
+    TBD
+
+Dependencies
+
+    Requires EGL 1.4
+
+    This extension is written against the wording of the EGL 1.4
+    Specification.
+
+Overview
+
+    This extension provides a means to issue a swap buffers request to
+    display the contents of the current back buffer and also specify a
+    list of damage rectangles that can be passed to a system
+    compositor so it can minimize how it has to recompose.
+
+    This should be used in situations where an application is only
+    animating a small portion of a surface since it enables the
+    compositor to avoid wasting time recomposing parts of the surface
+    that haven't changed.
+
+New Procedures and Functions
+
+    EGLBoolean eglSwapBuffersWithDamageEXT (
+	EGLDisplay dpy,
+	EGLSurface surface,
+	EGLint *rects,
+	EGLint n_rects);
+
+New Tokens
+
+    None
+
+Additions to Section 3.9 of the EGL 1.4 Specification (Posting the
+Color Buffer)
+
+    Add the following text to the end of subsection 3.9.1 titled
+    "Posting to a Window"
+
+	As an alternative to eglSwapBuffers use:
+
+	EGLBoolean eglSwapBuffersWithDamageEXT (
+	    EGLDisplay dpy,
+	    EGLSurface surface,
+	    EGLint *rects,
+	    EGLint n_rects);
+
+	to do the same thing as eglSwapBuffers but additionally report
+	a list of rectangles that defines the region that has truly
+	changed since the last frame. To be clear; the entire contents
+	of the back buffer will still be swapped to the front so
+	applications using this API must still ensure that the entire
+	back buffer is consistent. The rectangles are only a hint for
+	the system compositor so it can avoid recomposing parts of the
+	surface that haven't really changed.
+	    <rects> points to a list of integers in groups of four that
+	each describe a rectangle in screen coordinates in this
+	layout: {x, y, width, height}. The rectangles are specified
+	relative to the top-left of the surface and the x and y
+	components of each rectangle specify the top-left position of
+	that rectangle. <n_rects> determines how many groups of 4
+	integers can be read from <rects>.  It is not necessary to
+	avoid overlaps of the specified rectangles.
+	    In addition to the error conditions checked for by the
+	eglSwapBuffers api an EGL_BAD_PARAMETER error is generated if
+	<rects> is NULL and <n_rects> is greater than 0.
+
+Dependencies on OpenGL ES
+
+    None
+
+Dependencies on OpenVG
+
+    None
+
+Issues
+
+1)  Do applications have to make sure the rectangles don't overlap?
+
+    RESOLVED: No, that would be inconvenient for applications and we
+    see no difficulty for implementations to supporting overlapping
+    rectangles.
+
+2)  Would it be valid for an implementation to discard the list of
+    rectangles internally and work just in terms of the
+    eglSwapBuffers api?
+
+    Yes the rectangles are only there for optimization purposes so
+    although it wouldn't be beneficial to applications if it was
+    convenient at times then it would be compliant for an
+    implementation to discard the rectangles and just call
+    eglSwapBuffers instead. The error conditions that should be
+    checked for are compatible with the requirements for
+    eglSwapBuffers.
+
+Revision History
+
+    Version 1, 29/07/2011
+      - First draft
+    Version 2, 03/08/2011
+      - Clarify that the rectangles passed may overlap
+    Version 3, 01/09/2011
+      - Fix a missing '*' in prototype to make rects a pointer
+    Version 4, 11,02,2012
+      - Clarify that implementing in terms of eglSwapBuffers would be
+	compliant.
diff --git a/include/EGL/eglext.h b/include/EGL/eglext.h
index a40165e..75b28e4 100644
--- a/include/EGL/eglext.h
+++ b/include/EGL/eglext.h
@@ -340,6 +340,14 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLDISPATCHEVENTSINTELPROC) (EGLDisplay dpy)
 typedef EGLBoolean (EGLAPIENTRYP PFNEGLFORWARDEVENTINTELPROC) (EGLDisplay dpy, EGLNativeEventTypeINTEL event);
 #endif /* EGL_INTEL_native_event_objects */
 
+#ifndef EGL_EXT_swap_buffers_with_damage
+#define EGL_EXT_swap_buffers_with_damage 1
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageEXT(EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects);
+#endif
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects);
+#endif /* EGL_EXT_swap_buffers_with_damage */
+
 #include <EGL/eglmesaext.h>
 
 #ifdef __cplusplus
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index b2981a0..93a7090 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -564,7 +564,11 @@ static const struct wl_callback_listener frame_listener = {
  * Called via eglSwapBuffers(), drv->API.SwapBuffers().
  */
 static EGLBoolean
-dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
+dri2_swap_buffers_with_damage(_EGLDriver *drv,
+                              _EGLDisplay *disp,
+                              _EGLSurface *draw,
+                              const EGLint *rects,
+                              EGLint n_rects)
 {
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
@@ -582,6 +586,7 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
    wl_callback_add_listener(callback, &frame_listener, dri2_surf);
 
    if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
+      int i;
       pointer_swap(
 	    (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT],
 	    (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
@@ -611,8 +616,11 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
       dri2_surf->dx = 0;
       dri2_surf->dy = 0;
 
-      wl_surface_damage(dri2_surf->wl_win->surface, 0, 0,
-	    dri2_surf->base.Width, dri2_surf->base.Height);
+      for (i = 0; i < n_rects; i++) {
+         int *rect = &rects[i * 4];
+         wl_surface_damage(dri2_surf->wl_win->surface, rect[0], rect[1],
+               rect[2], rect[3]);
+      }
    }
 
    _EGLContext *ctx;
@@ -628,6 +636,14 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
    return EGL_TRUE;
 }
 
+static EGLBoolean
+dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
+{
+   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
+   EGLint damage[4] = { 0, 0, dri2_surf->base.Width, dri2_surf->base.Height };
+   return dri2_swap_buffers_with_damage (drv, disp, draw, damage, 1);
+}
+
 /**
  * Called via eglCreateImageKHR(), drv->API.CreateImageKHR().
  */
@@ -803,6 +819,7 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
    drv->API.CreatePixmapSurface = dri2_create_pixmap_surface;
    drv->API.DestroySurface = dri2_destroy_surface;
    drv->API.SwapBuffers = dri2_swap_buffers;
+   drv->API.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage;
    drv->API.CreateImageKHR = dri2_wayland_create_image_khr;
    drv->API.Terminate = dri2_terminate;
 
@@ -878,6 +895,8 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
    disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
    dri2_dpy->authenticate = dri2_wayland_authenticate;
 
+   disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
+
    /* we're supporting EGL 1.4 */
    disp->VersionMajor = 1;
    disp->VersionMinor = 4;
diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
index 082a557..f8bc670 100644
--- a/src/egl/main/eglapi.c
+++ b/src/egl/main/eglapi.c
@@ -754,6 +754,31 @@ eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
 
 
 EGLBoolean EGLAPIENTRY
+eglSwapBuffersWithDamageEXT(EGLDisplay dpy, EGLSurface surface,
+                            const EGLint *rects, EGLint n_rects)
+{
+   _EGLContext *ctx = _eglGetCurrentContext();
+   _EGLDisplay *disp = _eglLockDisplay(dpy);
+   _EGLSurface *surf = _eglLookupSurface(surface, disp);
+   _EGLDriver *drv;
+   EGLBoolean ret;
+
+   _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv);
+
+   /* surface must be bound to current context in EGL 1.4 */
+   if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
+       surf != ctx->DrawSurface)
+      RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE);
+
+   if (rects == NULL && n_rects != 0)
+      RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_FALSE);
+
+   ret = drv->API.SwapBuffersWithDamageEXT(drv, disp, surf, rects, n_rects);
+
+   RETURN_EGL_EVAL(disp, ret);
+}
+
+EGLBoolean EGLAPIENTRY
 eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
 {
    _EGLDisplay *disp = _eglLockDisplay(dpy);
@@ -990,6 +1015,9 @@ eglGetProcAddress(const char *procname)
       { "eglUnbindWaylandDisplayWL", (_EGLProc) eglUnbindWaylandDisplayWL },
 #endif
       { "eglPostSubBufferNV", (_EGLProc) eglPostSubBufferNV },
+#ifdef EGL_EXT_swap_buffers_with_damage
+      { "eglSwapBuffersWithDamageEXT", (_EGLProc) eglSwapBuffersWithDamageEXT },
+#endif
       { NULL, NULL }
    };
    EGLint i;
diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h
index 056da7b..bbcc337 100644
--- a/src/egl/main/eglapi.h
+++ b/src/egl/main/eglapi.h
@@ -133,6 +133,10 @@ typedef EGLBoolean (*DispatchEventsINTEL_t) (_EGLDriver *drv, _EGLDisplay *dpy);
 typedef EGLBoolean (*ForwardEventINTEL_t) (_EGLDriver *drv, _EGLDisplay *dpy, EGLNativeEventTypeINTEL event);
 #endif /* EGL_INTEL_native_event_objects */
 
+#ifdef EGL_EXT_swap_buffers_with_damage
+typedef EGLBoolean (*SwapBuffersWithDamageEXT_t) (_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface, const EGLint *rects, EGLint n_rects);
+#endif /* EGL_INTEL_native_event_objects */
+
 /**
  * The API dispatcher jumps through these functions
  */
@@ -213,6 +217,10 @@ struct _egl_api
    ForwardEventINTEL_t ForwardEventINTEL;
 #endif /* EGL_INTEL_native_event_objects */
 
+#ifdef EGL_EXT_swap_buffers_with_damage
+   SwapBuffersWithDamageEXT_t SwapBuffersWithDamageEXT;
+#endif /* EGL_EXT_swap_buffers_with_damage */
+
    PostSubBufferNV_t PostSubBufferNV;
 };
 
diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h
index 905c7a4..148a533 100644
--- a/src/egl/main/egldisplay.h
+++ b/src/egl/main/egldisplay.h
@@ -113,6 +113,8 @@ struct _egl_extensions
    EGLBoolean ANDROID_image_native_buffer;
 
    EGLBoolean NV_post_sub_buffer;
+
+   EGLBoolean EXT_swap_buffers_with_damage;
 };
 
 
diff --git a/src/egl/main/eglmisc.c b/src/egl/main/eglmisc.c
index 9d534f0..65ee228 100644
--- a/src/egl/main/eglmisc.c
+++ b/src/egl/main/eglmisc.c
@@ -117,6 +117,8 @@ _eglUpdateExtensionsString(_EGLDisplay *dpy)
    _EGL_CHECK_EXTENSION(ANDROID_image_native_buffer);
 
    _EGL_CHECK_EXTENSION(NV_post_sub_buffer);
+
+   _EGL_CHECK_EXTENSION(EXT_swap_buffers_with_damage);
 #undef _EGL_CHECK_EXTENSION
 }
 
-- 
1.7.7.5



More information about the wayland-devel mailing list