[PATCH] egl: Adds EGL_EXT_swap_buffers_with_damage implementation

Robert Bragg robert at sixbynine.org
Fri Feb 10 09:11:14 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   |  127 +++++++++++++++++++++++++++++++
 include/EGL/eglext.h                    |    8 ++
 src/egl/drivers/dri2/platform_wayland.c |   25 ++++++-
 src/egl/main/eglapi.c                   |   25 ++++++
 src/egl/main/eglapi.h                   |    8 ++
 src/egl/main/egldisplay.h               |    2 +
 src/egl/main/eglmisc.c                  |    2 +
 7 files changed, 194 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..d7a6131
--- /dev/null
+++ b/docs/EXT_swap_buffers_with_damage.txt
@@ -0,0 +1,127 @@
+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
+
+    3 - Sept 1, 2011
+
+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.
+
+	On success, EGL_TRUE is returned. In addition to the arguments
+	passed to eglSwapBuffers, <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.
+	    On failure, EGL_FALSE is returned. An EGL_NOT_INITIALIZED
+	error is generated if EGL is not initialized on <dpy>. An
+	EGL_BAD_PARAMETER error is generated if <surface> doesn't
+	refer to a valid EGLSurface. 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
+
+    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.
+
+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
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..baacebc 100644
--- a/src/egl/main/eglapi.c
+++ b/src/egl/main/eglapi.c
@@ -754,6 +754,28 @@ 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);
+
+   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 +1012,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