[3/3] gl: add support for OpenGL ES 3.0

Submitted by Bryce Harrington on Dec. 7, 2016, 11:46 p.m.

Details

Message ID 1481154412-16053-4-git-send-email-bryce@osg.samsung.com
State New
Headers show
Series "Enable GLES v3 support" ( rev: 1 ) in Cairo

Not browsing as part of any series.

Commit Message

Bryce Harrington Dec. 7, 2016, 11:46 p.m.
Extract and rebase Henry Song's GLESv3 patch from his cairogles fork to
current Cairo trunk.

Original commit message follows:

"""
configure with --enable-glesv3=yes to enable glesv3 supports.

There is a pecularity of OpenGL ES 3.0:  glesv3 supports creating
multi-sampled renderbuffer and supports blitting from multisampled
renderbuffer to single sample texture only (not other way around).

In this implementation, glesv3 backends always create a renderbuffer.
This renderbuffer can be single sample (if num of samples <= 1) or
multisampled renderbuffers.  All renderings are always on this
renderbuffer.  Only when the surface is used as source or mask, then the
renderbuffer content is blitted to the texture.

When an image is uploaded to a texture, it stays in the texture, until
when the surface is used as rendering target, at which time, the texture
is painted to the renderbuffer.

I know this is a little inefficient for drivers that only can have
single-sampled renderbuffer, but this makes the implementation much
simpler.

GLESv3 also supports PBO, like PBO in GL, we have not implemented PBO
for image uploading.
"""

Signed-off-by: Bryce Harrington <bryce@osg.samsung.com>
---
 boilerplate/Makefile.win32.features |  12 +++++
 boilerplate/cairo-boilerplate-egl.c |   8 ++-
 build/Makefile.win32.features       |   1 +
 build/Makefile.win32.features-h     |   3 ++
 build/configure.ac.features         |   1 +
 cairo-glesv3-uninstall.pc           |   7 +++
 configure.ac                        |  18 +++++++
 src/Makefile.sources                |   4 ++
 src/Makefile.win32.features         |  16 ++++++
 src/cairo-gl-composite.c            | 101 +++++++++++++++++++++++++++++++++++-
 src/cairo-gl-device.c               |  93 +++++++++++++++++++++++++++------
 src/cairo-gl-dispatch.c             |  12 +++++
 src/cairo-gl-gradient-private.h     |   3 ++
 src/cairo-gl-gradient.c             |   3 +-
 src/cairo-gl-info.c                 |   8 +++
 src/cairo-gl-msaa-compositor.c      |   9 +++-
 src/cairo-gl-operand.c              |   3 +-
 src/cairo-gl-private.h              |  12 ++++-
 src/cairo-gl-shaders.c              |  15 ++++--
 src/cairo-gl-surface.c              |  54 ++++++++++++++++---
 src/cairo-gl.h                      |   2 +-
 21 files changed, 345 insertions(+), 40 deletions(-)
 create mode 100644 cairo-glesv3-uninstall.pc

Patch hide | download patch | download mbox

diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index e60a95b..abb198d 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -247,6 +247,18 @@  enabled_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_glesv2_cxx_sources)
 enabled_cairo_boilerplate_sources += $(cairo_boilerplate_glesv2_sources)
 endif
 
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_glesv3_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_glesv3_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_glesv3_private)
+all_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_glesv3_cxx_sources)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_glesv3_sources)
+ifeq ($(CAIRO_HAS_GLESV3_SURFACE),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_glesv3_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_glesv3_private)
+enabled_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_glesv3_cxx_sources)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_glesv3_sources)
+endif
+
 unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_cogl_headers)
 all_cairo_boilerplate_headers += $(cairo_boilerplate_cogl_headers)
 all_cairo_boilerplate_private += $(cairo_boilerplate_cogl_private)
diff --git a/boilerplate/cairo-boilerplate-egl.c b/boilerplate/cairo-boilerplate-egl.c
index 99bee64..162d921 100644
--- a/boilerplate/cairo-boilerplate-egl.c
+++ b/boilerplate/cairo-boilerplate-egl.c
@@ -37,6 +37,8 @@ 
 #include <GL/gl.h>
 #elif CAIRO_HAS_GLESV2_SURFACE
 #include <GLES2/gl2.h>
+#elif CAIRO_HAS_GLESV3_SURFACE
+#include <GLES3/gl3.h>
 #endif
 
 static const cairo_user_data_key_t gl_closure_key;
@@ -87,7 +89,7 @@  _cairo_boilerplate_egl_create_surface (const char		 *name,
 	EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
 #if CAIRO_HAS_GL_SURFACE
 	EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
-#elif CAIRO_HAS_GLESV2_SURFACE
+#elif CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_GLESV3_SURFACE
 	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
 #endif
 	EGL_NONE
@@ -95,6 +97,8 @@  _cairo_boilerplate_egl_create_surface (const char		 *name,
     const EGLint ctx_attribs[] = {
 #if CAIRO_HAS_GLESV2_SURFACE
 	EGL_CONTEXT_CLIENT_VERSION, 2,
+#elif CAIRO_HAS_GLESV3_SURFACE
+	EGL_CONTEXT_CLIENT_VERSION, 3,
 #endif
 	EGL_NONE
     };
@@ -117,7 +121,7 @@  _cairo_boilerplate_egl_create_surface (const char		 *name,
 
 #if CAIRO_HAS_GL_SURFACE
     eglBindAPI (EGL_OPENGL_API);
-#elif CAIRO_HAS_GLESV2_SURFACE
+#elif CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_GLESV3_SURFACE
     eglBindAPI (EGL_OPENGL_ES_API);
 #endif
 
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
index 8cb155d..7f62d97 100644
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@ -19,6 +19,7 @@  CAIRO_HAS_GALLIUM_SURFACE=0
 CAIRO_HAS_PNG_FUNCTIONS=1
 CAIRO_HAS_GL_SURFACE=0
 CAIRO_HAS_GLESV2_SURFACE=0
+CAIRO_HAS_GLESV3_SURFACE=0
 CAIRO_HAS_COGL_SURFACE=0
 CAIRO_HAS_DIRECTFB_SURFACE=0
 CAIRO_HAS_VG_SURFACE=0
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index 13904cf..2825f0c 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -62,6 +62,9 @@  endif
 ifeq ($(CAIRO_HAS_GLESV2_SURFACE),1)
 	@echo "#define CAIRO_HAS_GLESV2_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
 endif
+ifeq ($(CAIRO_HAS_GLESV3_SURFACE),1)
+	@echo "#define CAIRO_HAS_GLESV3_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
+endif
 ifeq ($(CAIRO_HAS_COGL_SURFACE),1)
 	@echo "#define CAIRO_HAS_COGL_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
 endif
diff --git a/build/configure.ac.features b/build/configure.ac.features
index 77f2035..aa48652 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -384,6 +384,7 @@  AC_DEFUN([CAIRO_REPORT],
 	echo "  SVG:           $use_svg"
 	echo "  OpenGL:        $use_gl"
 	echo "  OpenGL ES 2.0: $use_glesv2"
+	echo "  OpenGL ES 3.0: $use_glesv3"
 	echo "  BeOS:          $use_beos"
 	echo "  DirectFB:      $use_directfb"
 	echo "  OpenVG:        $use_vg"
diff --git a/cairo-glesv3-uninstall.pc b/cairo-glesv3-uninstall.pc
new file mode 100644
index 0000000..00ea39a
--- /dev/null
+++ b/cairo-glesv3-uninstall.pc
@@ -0,0 +1,7 @@ 
+Name: cairo-glesv3
+Description: OpenGLESv3 surface backend for cairo graphics library
+Version: 1.12.14
+
+Requires: cairo glesv3
+Libs:
+Cflags: -I${pc_top_builddir}/${pcfiledir}/./src
diff --git a/configure.ac b/configure.ac
index 93953a7..ea71ad6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -386,6 +386,24 @@  CAIRO_ENABLE_SURFACE_BACKEND(glesv2, OpenGLESv2, no, [
 ])
 
 dnl ===========================================================================
+CAIRO_ENABLE_SURFACE_BACKEND(glesv3, OpenGLESv3, no, [
+  glesv3_REQUIRES="glesv2"
+  PKG_CHECK_MODULES(glesv3, $glesv3_REQUIRES,, [
+	 dnl Fallback to searching for headers
+	 AC_CHECK_HEADER(GLES3/gl3.h,, [use_glesv3="no (glesv2.pc nor OpenGL ES 3.0 headers not found)"])
+	 if test "x$use_glesv3" = "xyes"; then
+	     glesv3_NONPKGCONFIG_CFLAGS=
+	     glesv3_NONPKGCONFIG_LIBS="-lGLESv2"
+	 fi])
+
+  if test "x$have_dl" = "xyes" -a "x$have_dlsym" = "xyes"; then
+    glesv3_LIBS="$glesv3_LIBS -ldl"
+  fi
+
+  need_egl_functions=yes
+])
+
+dnl ===========================================================================
 CAIRO_ENABLE_SURFACE_BACKEND(cogl, Cogl, no, [
   cogl_REQUIRES="cogl-2.0-experimental"
   PKG_CHECK_MODULES(cogl, $cogl_REQUIRES,, [use_cogl="no"])
diff --git a/src/Makefile.sources b/src/Makefile.sources
index b368f27..eb0c5a6 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -407,6 +407,10 @@  cairo_glesv2_headers = $(cairo_gl_headers)
 cairo_glesv2_private = $(cairo_gl_private)
 cairo_glesv2_sources = $(cairo_gl_sources)
 
+cairo_glesv3_headers = $(cairo_gl_headers)
+cairo_glesv3_private = $(cairo_gl_private)
+cairo_glesv3_sources = $(cairo_gl_sources)
+
 cairo_egl_sources += cairo-egl-context.c
 cairo_glx_sources += cairo-glx-context.c
 cairo_wgl_sources += cairo-wgl-context.c
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index 2274f4a..e8be9f7 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -325,6 +325,22 @@  ifeq ($(CAIRO_HAS_GLESV2_SURFACE),1)
 enabled_cairo_pkgconf += cairo-glesv2.pc
 endif
 
+unsupported_cairo_headers += $(cairo_glesv3_headers)
+all_cairo_headers += $(cairo_glesv3_headers)
+all_cairo_private += $(cairo_glesv3_private)
+all_cairo_cxx_sources += $(cairo_glesv3_cxx_sources)
+all_cairo_sources += $(cairo_glesv3_sources)
+ifeq ($(CAIRO_HAS_GLESV3_SURFACE),1)
+enabled_cairo_headers += $(cairo_glesv3_headers)
+enabled_cairo_private += $(cairo_glesv3_private)
+enabled_cairo_cxx_sources += $(cairo_glesv3_cxx_sources)
+enabled_cairo_sources += $(cairo_glesv3_sources)
+endif
+all_cairo_pkgconf += cairo-glesv3.pc
+ifeq ($(CAIRO_HAS_GLESV3_SURFACE),1)
+enabled_cairo_pkgconf += cairo-glesv3.pc
+endif
+
 unsupported_cairo_headers += $(cairo_cogl_headers)
 all_cairo_headers += $(cairo_cogl_headers)
 all_cairo_private += $(cairo_cogl_private)
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index a95712e..76bc1ef 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -52,6 +52,91 @@ 
 #include "cairo-error-private.h"
 #include "cairo-image-surface-private.h"
 
+/* FIXME: Copy of same routine in cairo-gl-msaa-compositor.c */
+static cairo_int_status_t
+_draw_int_rect (cairo_gl_context_t      *ctx,
+		cairo_gl_composite_t    *setup,
+		cairo_rectangle_int_t   *rect)
+{
+    cairo_box_t box;
+    cairo_point_t quad[4];
+
+    _cairo_box_from_rectangle (&box, rect);
+    quad[0].x = box.p1.x;
+    quad[0].y = box.p1.y;
+    quad[1].x = box.p1.x;
+    quad[1].y = box.p2.y;
+    quad[2].x = box.p2.x;
+    quad[2].y = box.p2.y;
+    quad[3].x = box.p2.x;
+    quad[3].y = box.p1.y;
+
+    return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
+}
+
+static cairo_int_status_t
+_blit_texture_to_renderbuffer (cairo_gl_surface_t *surface)
+{
+    cairo_gl_context_t *ctx = NULL;
+    cairo_gl_composite_t setup;
+    cairo_surface_pattern_t pattern;
+    cairo_rectangle_int_t extents;
+    cairo_int_status_t status;
+
+    /* FIXME: we need to take care of certain glesv2 extension too */
+    if (((cairo_gl_context_t *)surface->base.device)->gl_flavor != CAIRO_GL_FLAVOR_ES3)
+	return CAIRO_INT_STATUS_SUCCESS;
+
+    if (! surface->content_in_texture)
+	return CAIRO_INT_STATUS_SUCCESS;
+
+    memset (&setup, 0, sizeof (cairo_gl_composite_t));
+
+    status = _cairo_gl_composite_set_operator (&setup,
+					       CAIRO_OPERATOR_SOURCE,
+					       FALSE);
+
+    if (status)
+	return status;
+
+    setup.dst = surface;
+    setup.clip_region = surface->clip_region;
+
+    _cairo_pattern_init_for_surface (&pattern, &surface->base);
+    status = _cairo_gl_composite_set_source (&setup, &pattern.base,
+					     NULL, NULL, FALSE);
+    _cairo_pattern_fini (&pattern.base);
+
+    if (unlikely (status))
+	goto FAIL;
+
+    _cairo_gl_composite_set_multisample (&setup);
+
+    status = _cairo_gl_composite_begin (&setup, &ctx);
+
+    if (unlikely (status))
+	goto FAIL;
+
+    extents.x = extents.y = 0;
+    extents.width = surface->width;
+    extents.height = surface->height;
+
+    status = _draw_int_rect (ctx, &setup, &extents);
+
+    if (status == CAIRO_INT_STATUS_SUCCESS)
+	surface->content_in_texture = FALSE;
+
+FAIL:
+    _cairo_gl_composite_fini (&setup);
+
+    if (ctx) {
+	_cairo_gl_composite_flush (ctx);
+	status = _cairo_gl_context_release (ctx, status);
+    }
+
+    return status;
+}
+
 cairo_int_status_t
 _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
 			        const cairo_pattern_t *pattern,
@@ -68,8 +153,13 @@  void
 _cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
 					const cairo_gl_operand_t *source)
 {
+    cairo_int_status_t status;
+
     _cairo_gl_operand_destroy (&setup->src);
     _cairo_gl_operand_copy (&setup->src, source);
+
+    if (source->type == CAIRO_GL_OPERAND_TEXTURE)
+	status = _cairo_gl_surface_resolve_multisampling (source->texture.surface);
 }
 
 void
@@ -99,9 +189,13 @@  void
 _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
 				      const cairo_gl_operand_t *mask)
 {
+    cairo_int_status_t status;
     _cairo_gl_operand_destroy (&setup->mask);
-    if (mask)
+    if (mask) {
 	_cairo_gl_operand_copy (&setup->mask, mask);
+	if (mask->type == CAIRO_GL_OPERAND_TEXTURE)
+	    status = _cairo_gl_surface_resolve_multisampling (mask->texture.surface);
+    }
 }
 
 void
@@ -174,7 +268,8 @@  _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
 
     switch (extend) {
     case CAIRO_EXTEND_NONE:
-	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2)
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
+	    ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
 	    wrap_mode = GL_CLAMP_TO_EDGE;
 	else
 	    wrap_mode = GL_CLAMP_TO_BORDER;
@@ -1178,6 +1273,8 @@  _cairo_gl_composite_init (cairo_gl_composite_t *setup,
 {
     cairo_status_t status;
 
+    status = _blit_texture_to_renderbuffer (dst);
+
     memset (setup, 0, sizeof (cairo_gl_composite_t));
 
     status = _cairo_gl_composite_set_operator (setup, op,
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 2f56a5f..62d8a62 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -171,7 +171,8 @@  test_can_read_bgra (cairo_gl_flavor_t gl_flavor)
     if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
 	return TRUE;
 
-    assert (gl_flavor == CAIRO_GL_FLAVOR_ES2);
+    assert (gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
+	    gl_flavor == CAIRO_GL_FLAVOR_ES3);
 
    /* For OpenGL ES we have to look for the specific extension and BGRA only
     * matches cairo's integer packed bytes on little-endian machines. */
@@ -190,7 +191,8 @@  _cairo_gl_context_init (cairo_gl_context_t *ctx)
     int n;
 
     cairo_bool_t is_desktop = gl_flavor == CAIRO_GL_FLAVOR_DESKTOP;
-    cairo_bool_t is_gles = gl_flavor == CAIRO_GL_FLAVOR_ES2;
+    cairo_bool_t is_gles = (gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
+			    gl_flavor == CAIRO_GL_FLAVOR_ES3);
 
     _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
 
@@ -277,11 +279,20 @@  _cairo_gl_context_init (cairo_gl_context_t *ctx)
     }
 #endif
 
-    ctx->supports_msaa = ctx->num_samples > 1;
+#if CAIRO_HAS_GLESV3_SURFACE
+    if (is_gles && ctx->has_packed_depth_stencil) {
+	glGetIntegerv(GL_MAX_SAMPLES, &ctx->num_samples);
+    }
+#endif
+
+    /* we always use renderbuffer for rendering in glesv3 */
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
+	ctx->supports_msaa = TRUE;
+    else
+	ctx->supports_msaa = ctx->num_samples > 1;
     if (ctx->num_samples > MAX_MSAA_SAMPLES)
 	ctx->num_samples = MAX_MSAA_SAMPLES;
 
-
     ctx->current_operator = -1;
     ctx->gl_flavor = gl_flavor;
 
@@ -358,6 +369,8 @@  _get_depth_stencil_format (cairo_gl_context_t *ctx)
     return GL_DEPTH_STENCIL;
 #elif CAIRO_HAS_GLESV2_SURFACE
     return GL_DEPTH24_STENCIL8_OES;
+#elif CAIRO_HAS_GLESV3_SURFACE
+    return GL_DEPTH24_STENCIL8;
 #endif
 }
 
@@ -387,6 +400,9 @@  _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
 {
     GLenum status;
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+#if CAIRO_HAS_GLESV3_SURFACE
+    GLenum buf;
+#endif
 
     if (likely (surface->fb))
         return;
@@ -415,6 +431,10 @@  _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
 #if CAIRO_HAS_GL_SURFACE
     glDrawBuffer (GL_COLOR_ATTACHMENT0);
     glReadBuffer (GL_COLOR_ATTACHMENT0);
+#elif CAIRO_HAS_GLESV3_SURFACE
+    buf = GL_COLOR_ATTACHMENT0;
+    glDrawBuffers (1, &buf);
+    glReadBuffer (GL_COLOR_ATTACHMENT0);
 #endif
 
     status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
@@ -436,13 +456,14 @@  _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
 		 str, status);
     }
 }
-#if CAIRO_HAS_GL_SURFACE
+#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
 static void
 _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
 				cairo_gl_surface_t *surface)
 {
     assert (surface->supports_msaa);
-    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
+    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
+	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3);
 
     if (surface->msaa_fb)
 	return;
@@ -460,7 +481,11 @@  _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
        this information. */
     ctx->dispatch.RenderbufferStorageMultisample (GL_RENDERBUFFER,
 						  ctx->num_samples,
+#if CAIRO_HAS_GLESV3_SURFACE
+						  GL_RGBA8,
+#else
 						  GL_RGBA,
+#endif
 						  surface->width,
 						  surface->height);
     ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER,
@@ -472,6 +497,11 @@  _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
     glDisable (GL_SCISSOR_TEST);
     glClearColor (0, 0, 0, 0);
     glClear (GL_COLOR_BUFFER_BIT);
+
+    /* for glesv3 with multisample renderbuffer, we always render to
+       this renderbuffer */
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
+	surface->msaa_active = TRUE;
 }
 #endif
 
@@ -484,8 +514,9 @@  _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
 	return TRUE;
 
     _cairo_gl_ensure_framebuffer (ctx, surface);
-#if CAIRO_HAS_GL_SURFACE
-    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
+	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
 	_cairo_gl_ensure_multisampling (ctx, surface);
 #endif
 
@@ -499,8 +530,9 @@  _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
 					      surface->width,
 					      surface->height);
 
-#if CAIRO_HAS_GL_SURFACE
-    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
+#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
+	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) {
 	dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
 					   GL_DEPTH_STENCIL_ATTACHMENT,
 					   GL_RENDERBUFFER,
@@ -615,7 +647,7 @@  _gl_identity_ortho (GLfloat *m,
 #undef M
 }
 
-#if CAIRO_HAS_GL_SURFACE
+#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
 static void
 bind_multisample_framebuffer (cairo_gl_context_t *ctx,
 			       cairo_gl_surface_t *surface)
@@ -624,14 +656,19 @@  bind_multisample_framebuffer (cairo_gl_context_t *ctx,
     cairo_bool_t scissor_test_enabled;
 
     assert (surface->supports_msaa);
-    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
+    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
+	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3);
 
     _cairo_gl_ensure_framebuffer (ctx, surface);
     _cairo_gl_ensure_multisampling (ctx, surface);
 
     if (surface->msaa_active) {
+#if CAIRO_HAS_GL_SURFACE
 	glEnable (GL_MULTISAMPLE);
+#endif
 	ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
+	    surface->content_in_texture = FALSE;
 	return;
     }
 
@@ -642,7 +679,9 @@  bind_multisample_framebuffer (cairo_gl_context_t *ctx,
     glDisable (GL_STENCIL_TEST);
     glDisable (GL_SCISSOR_TEST);
 
+#if CAIRO_HAS_GL_SURFACE
     glEnable (GL_MULTISAMPLE);
+#endif
 
     /* The last time we drew to the surface, we were not using multisampling,
        so we need to blit from the non-multisampling framebuffer into the
@@ -658,10 +697,12 @@  bind_multisample_framebuffer (cairo_gl_context_t *ctx,
 	glEnable (GL_STENCIL_TEST);
     if (scissor_test_enabled)
 	glEnable (GL_SCISSOR_TEST);
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
+	surface->content_in_texture = FALSE;
 }
 #endif
 
-#if CAIRO_HAS_GL_SURFACE
+#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
 static void
 bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
 			       cairo_gl_surface_t *surface)
@@ -669,11 +710,15 @@  bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
     cairo_bool_t stencil_test_enabled;
     cairo_bool_t scissor_test_enabled;
 
-    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
+    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
+	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3);
     _cairo_gl_ensure_framebuffer (ctx, surface);
 
     if (! surface->msaa_active) {
+#if CAIRO_HAS_GL_SURFACE
 	glDisable (GL_MULTISAMPLE);
+#endif
+
 	ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
 	return;
     }
@@ -685,7 +730,9 @@  bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
     glDisable (GL_STENCIL_TEST);
     glDisable (GL_SCISSOR_TEST);
 
+#if CAIRO_HAS_GL_SURFACE
     glDisable (GL_MULTISAMPLE);
+#endif
 
     /* The last time we drew to the surface, we were using multisampling,
        so we need to blit from the multisampling framebuffer into the
@@ -718,7 +765,7 @@  _cairo_gl_context_bind_framebuffer (cairo_gl_context_t *ctx,
 	    return;
 	}
 
-#if CAIRO_HAS_GL_SURFACE
+#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
 	if (multisampling)
 	    bind_multisample_framebuffer (ctx, surface);
 	else
@@ -737,7 +784,8 @@  _cairo_gl_context_bind_framebuffer (cairo_gl_context_t *ctx,
 #endif
     }
 
-    surface->msaa_active = multisampling;
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+	surface->msaa_active = multisampling;
 }
 
 void
@@ -746,14 +794,21 @@  _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
                                    cairo_bool_t multisampling)
 {
     cairo_bool_t changing_surface, changing_sampling;
+#if CAIRO_HAS_GLESV3_SURFACE
+    GLenum buf;
+#endif
 
     /* The decision whether or not to use multisampling happens when
      * we create an OpenGL ES surface, so we can never switch modes. */
     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2)
 	multisampling = surface->msaa_active;
+    /* For GLESV3, we always use renderbuffer for drawing */
+    else if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
+	multisampling = TRUE;
 
     changing_surface = ctx->current_target != surface || surface->needs_update;
-    changing_sampling = surface->msaa_active != multisampling;
+    changing_sampling = (surface->msaa_active != multisampling ||
+			 surface->content_in_texture);
     if (! changing_surface && ! changing_sampling)
 	return;
 
@@ -778,6 +833,10 @@  _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
 #if CAIRO_HAS_GL_SURFACE
 	glDrawBuffer (GL_BACK_LEFT);
 	glReadBuffer (GL_BACK_LEFT);
+#elif CAIRO_HAS_GLESV3_SURFACE
+	buf = GL_BACK;
+	glDrawBuffers (1, &buf);
+	glReadBuffer (GL_BACK);
 #endif
     }
 
diff --git a/src/cairo-gl-dispatch.c b/src/cairo-gl-dispatch.c
index 3e37219..a49199d 100644
--- a/src/cairo-gl-dispatch.c
+++ b/src/cairo-gl-dispatch.c
@@ -124,6 +124,10 @@  _cairo_gl_dispatch_init_buffers (cairo_gl_dispatch_t *dispatch,
 	else
 	    return CAIRO_STATUS_DEVICE_ERROR;
     }
+    else if (gl_flavor == CAIRO_GL_FLAVOR_ES3)
+    {
+	dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
+    }
     else if (gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
 	     gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
     {
@@ -156,6 +160,10 @@  _cairo_gl_dispatch_init_shaders (cairo_gl_dispatch_t *dispatch,
 	else
 	    return CAIRO_STATUS_DEVICE_ERROR;
     }
+    else if (gl_flavor == CAIRO_GL_FLAVOR_ES3)
+    {
+	dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
+    }
     else if (gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
 	     gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
     {
@@ -189,6 +197,10 @@  _cairo_gl_dispatch_init_fbo (cairo_gl_dispatch_t *dispatch,
 	else
 	    return CAIRO_STATUS_DEVICE_ERROR;
     }
+    else if (gl_flavor == CAIRO_GL_FLAVOR_ES3)
+    {
+	dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
+    }
     else if (gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
 	     gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
     {
diff --git a/src/cairo-gl-gradient-private.h b/src/cairo-gl-gradient-private.h
index 77f9bbd..e7b97a1 100644
--- a/src/cairo-gl-gradient-private.h
+++ b/src/cairo-gl-gradient-private.h
@@ -57,6 +57,9 @@ 
 #elif CAIRO_HAS_GLESV2_SURFACE
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#elif CAIRO_HAS_GLESV3_SURFACE
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
 #endif
 
 #define CAIRO_GL_GRADIENT_CACHE_SIZE 4096
diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c
index db82c23..cfdf946 100644
--- a/src/cairo-gl-gradient.c
+++ b/src/cairo-gl-gradient.c
@@ -282,7 +282,8 @@  _cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
      * In OpenGL ES 2.0 no format conversion is allowed i.e. 'internalFormat'
      * must match 'format' in glTexImage2D.
      */
-    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2)
+    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2 ||
+	_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES3)
 	internal_format = GL_BGRA;
     else
 	internal_format = GL_RGBA;
diff --git a/src/cairo-gl-info.c b/src/cairo-gl-info.c
index 39541aa..29b8768 100644
--- a/src/cairo-gl-info.c
+++ b/src/cairo-gl-info.c
@@ -67,6 +67,14 @@  _cairo_gl_get_flavor (void)
 	flavor = CAIRO_GL_FLAVOR_NONE;
     else if (strstr (version, "OpenGL ES 2") != NULL)
 	flavor = CAIRO_GL_FLAVOR_ES2;
+    else if (strstr (version, "OpenGL ES 3") != NULL)
+#if CAIRO_HAS_GLESV3_SURFACE
+	flavor = CAIRO_GL_FLAVOR_ES3;
+#elif CAIRO_HAS_GLESV2_SURFACE
+	flavor = CAIRO_GL_FLAVOR_ES2;
+#else
+	flavor = CAIRO_GL_FLAVOR_NONE;
+#endif
     else
 	flavor = CAIRO_GL_FLAVOR_DESKTOP;
 
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 507459d..fcd4144 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -280,8 +280,10 @@  can_use_msaa_compositor (cairo_gl_surface_t *surface,
     /* Multisampling OpenGL ES surfaces only maintain one multisampling
        framebuffer and thus must use the spans compositor to do non-antialiased
        rendering. */
-    if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES2
+    if ((((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
+	 ((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES3)
 	 && surface->supports_msaa
+	 && surface->num_samples > 1
 	 && antialias == CAIRO_ANTIALIAS_NONE)
 	return FALSE;
 
@@ -378,6 +380,9 @@  _cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compos
 					   FALSE);
     if (unlikely (status))
 	goto finish;
+
+    _cairo_gl_context_set_destination (ctx, dst, setup.multisample);
+
     status = _cairo_gl_set_operands_and_operator (&setup, ctx);
     if (unlikely (status))
 	goto finish;
@@ -623,6 +628,7 @@  query_surface_capabilities (cairo_gl_surface_t *surface)
     surface->stencil_and_msaa_caps_initialized = TRUE;
     surface->supports_stencil = FALSE;
     surface->supports_msaa = FALSE;
+    surface->num_samples = samples;
 
     status = _cairo_gl_context_acquire (surface->base.device, &ctx);
     if (unlikely (status))
@@ -634,6 +640,7 @@  query_surface_capabilities (cairo_gl_surface_t *surface)
     glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
     surface->supports_stencil = stencil_bits > 0;
     surface->supports_msaa = samples > 1;
+    surface->num_samples = samples;
 
     status = _cairo_gl_context_release (ctx, status);
 }
diff --git a/src/cairo-gl-operand.c b/src/cairo-gl-operand.c
index ca1fa4b..8136646 100644
--- a/src/cairo-gl-operand.c
+++ b/src/cairo-gl-operand.c
@@ -658,7 +658,8 @@  _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
 	 * with CAIRO_EXTEND_NONE). When bilinear filtering is enabled,
 	 * these shaders need the texture dimensions for their calculations.
 	 */
-	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
+	if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
+	     ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) &&
 	    _cairo_gl_operand_get_extend (operand) == CAIRO_EXTEND_NONE &&
 	    _cairo_gl_operand_get_gl_filter (operand) == GL_LINEAR)
 	{
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 7d5d7b4..15096c7 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -66,6 +66,9 @@ 
 #elif CAIRO_HAS_GLESV2_SURFACE
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#elif CAIRO_HAS_GLESV3_SURFACE
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
 #endif
 
 #include "cairo-gl-ext-def-private.h"
@@ -103,7 +106,8 @@  typedef struct _cairo_gl_surface cairo_gl_surface_t;
 typedef enum cairo_gl_flavor {
     CAIRO_GL_FLAVOR_NONE = 0,
     CAIRO_GL_FLAVOR_DESKTOP = 1,
-    CAIRO_GL_FLAVOR_ES2 = 2
+    CAIRO_GL_FLAVOR_ES2 = 2,
+    CAIRO_GL_FLAVOR_ES3 = 3
 } cairo_gl_flavor_t;
 
 /* Indices for vertex attributes used by BindAttribLocation etc */
@@ -169,7 +173,7 @@  struct _cairo_gl_surface {
     GLuint fb; /* GL framebuffer object wrapping our data. */
     GLuint depth_stencil; /* GL renderbuffer object for holding stencil buffer clip. */
 
-#if CAIRO_HAS_GL_SURFACE
+#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
     GLuint msaa_rb; /* The ARB MSAA path uses a renderbuffer. */
     GLuint msaa_fb;
 #endif
@@ -178,8 +182,12 @@  struct _cairo_gl_surface {
     cairo_bool_t stencil_and_msaa_caps_initialized;
     cairo_bool_t supports_stencil; /* Stencil support for for non-texture surfaces. */
     cairo_bool_t supports_msaa;
+    cairo_bool_t num_samples;
     cairo_bool_t msaa_active; /* Whether the multisampling
 			         framebuffer is active or not. */
+    cairo_bool_t content_in_texture; /* whether we just uploaded image
+					to texture, used for certain
+					gles2 extensions and glesv3 */
     cairo_clip_t *clip_on_stencil_buffer;
 
     int owns_tex;
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index aceb5d2..5d8becd 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -398,7 +398,8 @@  cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 	     "vec4 get_%s()\n"
 	     "{\n",
 	     rectstr, namestr, namestr, namestr, namestr);
-	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
+	if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
+	     ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) &&
 	    _cairo_gl_shader_needs_border_fade (op))
 	{
 	    _cairo_output_stream_printf (stream,
@@ -425,7 +426,8 @@  cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 	    "vec4 get_%s()\n"
 	    "{\n",
 	    namestr, namestr, rectstr, namestr, namestr);
-	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
+	if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
+	     ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) &&
 	    _cairo_gl_shader_needs_border_fade (op))
 	{
 	    _cairo_output_stream_printf (stream,
@@ -462,7 +464,8 @@  cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 	    "    float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n",
 	    namestr, namestr, rectstr, namestr, namestr, namestr, namestr,
 	    namestr, namestr, namestr, namestr, namestr);
-	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
+	if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
+	     ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) &&
 	    _cairo_gl_shader_needs_border_fade (op))
 	{
 	    _cairo_output_stream_printf (stream,
@@ -507,7 +510,8 @@  cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 	    "    float upper_t = mix (t.y, t.x, is_valid.x);\n",
 	    namestr, namestr, rectstr, namestr, namestr, namestr, namestr,
 	    namestr, namestr, namestr, namestr, namestr, namestr);
-	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
+	if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
+	     ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) &&
 	    _cairo_gl_shader_needs_border_fade (op))
 	{
 	    _cairo_output_stream_printf (stream,
@@ -674,7 +678,8 @@  cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
     _cairo_gl_shader_emit_wrap (ctx, stream, src, CAIRO_GL_TEX_SOURCE);
     _cairo_gl_shader_emit_wrap (ctx, stream, mask, CAIRO_GL_TEX_MASK);
 
-    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) {
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
+	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) {
 	if (_cairo_gl_shader_needs_border_fade (src))
 	    _cairo_gl_shader_emit_border_fade (stream, src, CAIRO_GL_TEX_SOURCE);
 	if (_cairo_gl_shader_needs_border_fade (mask))
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 8ecc3a9..3d34faf 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -395,6 +395,7 @@  _cairo_gl_surface_init (cairo_device_t *device,
     surface->width = width;
     surface->height = height;
     surface->needs_update = FALSE;
+    surface->content_in_texture = FALSE;
 
     _cairo_gl_surface_embedded_operand_init (surface);
 }
@@ -433,6 +434,7 @@  _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t   *ctx,
     _cairo_gl_surface_init (&ctx->base, surface, content, width, height);
 
     surface->supports_msaa = ctx->supports_msaa;
+    surface->num_samples = ctx->num_samples;
     surface->supports_stencil = TRUE;
 
     /* Create the texture used to store the surface's data. */
@@ -875,7 +877,8 @@  _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
     if (unlikely (status))
 	return status;
 
-    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2) {
+    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2 ||
+	_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES3) {
 	pixman_format_code_t pixman_format;
 	cairo_surface_pattern_t pattern;
 	cairo_bool_t require_conversion = FALSE;
@@ -980,10 +983,17 @@  _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	else
 	{
 	    glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-	    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+	    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
+		ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
 		glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
 	}
 
+	/* we must resolve the renderbuffer to texture before we
+	   upload image */
+	status = _cairo_gl_surface_resolve_multisampling (dst);
+	if (unlikely (status))
+	    goto FAIL;
+
         _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
 	glBindTexture (ctx->tex_target, dst->tex);
 	glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -1003,6 +1013,8 @@  _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 						  dst_x, dst_y,
 						  width, height);
 	}
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
+	    dst->content_in_texture = TRUE;
     } else {
         cairo_surface_t *tmp;
 
@@ -1042,6 +1054,8 @@  _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
         }
 
         cairo_surface_destroy (tmp);
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
+	    dst->content_in_texture = TRUE;
     }
 
 FAIL:
@@ -1092,7 +1106,7 @@  _cairo_gl_surface_finish (void *abstract_surface)
     if (surface->msaa_depth_stencil)
 	ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
 
-#if CAIRO_HAS_GL_SURFACE
+#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
     if (surface->msaa_fb)
 	ctx->dispatch.DeleteFramebuffers (1, &surface->msaa_fb);
     if (surface->msaa_rb)
@@ -1144,7 +1158,8 @@  _cairo_gl_surface_map_to_image (void      *abstract_surface,
 	return NULL;
     }
 
-    if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES2) {
+    if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES2 ||
+	_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES3) {
 	/* If only RGBA is supported, we must download data in a compatible
 	 * format. This means that pixman will convert the data on the CPU when
 	 * interacting with other image surfaces. For ALPHA, GLES2 does not
@@ -1193,13 +1208,29 @@  _cairo_gl_surface_map_to_image (void      *abstract_surface,
      * fall back instead.
      */
     _cairo_gl_composite_flush (ctx);
-    _cairo_gl_context_set_destination (ctx, surface, FALSE);
+
+    if (ctx->gl_flavor != CAIRO_GL_FLAVOR_ES3) {
+	_cairo_gl_context_set_destination (ctx, surface, FALSE);
+    } else {
+	if (surface->content_in_texture) {
+	    _cairo_gl_ensure_framebuffer (ctx, surface);
+	    ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
+	} else {
+	    status = _cairo_gl_surface_resolve_multisampling (surface);
+	    if (unlikely (status)) {
+		status = _cairo_gl_context_release (ctx, status);
+		cairo_surface_destroy (&image->base);
+		return _cairo_image_surface_create_in_error (status);
+	    }
+	}
+    }
 
     flipped = ! _cairo_gl_surface_is_texture (surface);
     mesa_invert = flipped && ctx->has_mesa_pack_invert;
 
     glPixelStorei (GL_PACK_ALIGNMENT, 4);
-    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
+	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
 	glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
     if (mesa_invert)
 	glPixelStorei (GL_PACK_INVERT_MESA, 1);
@@ -1366,6 +1397,9 @@  _cairo_gl_surface_resolve_multisampling (cairo_gl_surface_t *surface)
     /* GLES surfaces do not need explicit resolution. */
     if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES2)
 	return CAIRO_INT_STATUS_SUCCESS;
+    else if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES3 &&
+	     surface->content_in_texture)
+	return CAIRO_INT_STATUS_SUCCESS;
 
     if (! _cairo_gl_surface_is_texture (surface))
 	return CAIRO_INT_STATUS_SUCCESS;
@@ -1374,10 +1408,14 @@  _cairo_gl_surface_resolve_multisampling (cairo_gl_surface_t *surface)
     if (unlikely (status))
 	return status;
 
-    ctx->current_target = surface;
+    _cairo_gl_composite_flush (ctx);
+
+    ctx->current_target = NULL;
 
-#if CAIRO_HAS_GL_SURFACE
+#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
     _cairo_gl_context_bind_framebuffer (ctx, surface, FALSE);
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
+	surface->content_in_texture = TRUE;
 #endif
 
     status = _cairo_gl_context_release (ctx, status);
diff --git a/src/cairo-gl.h b/src/cairo-gl.h
index 9fd7608..7cd869c 100644
--- a/src/cairo-gl.h
+++ b/src/cairo-gl.h
@@ -62,7 +62,7 @@ 
 
 #include "cairo.h"
 
-#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV2_SURFACE
+#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_GLESV3_SURFACE
 
 CAIRO_BEGIN_DECLS
 

Comments

Again, I don't know OpenGL, so feel free to ignore anything stupid that
I say.

On 08.12.2016 00:46, Bryce Harrington wrote:
> @@ -87,7 +89,7 @@ _cairo_boilerplate_egl_create_surface (const char		 *name,
>  	EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
>  #if CAIRO_HAS_GL_SURFACE
>  	EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
> -#elif CAIRO_HAS_GLESV2_SURFACE
> +#elif CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_GLESV3_SURFACE
>  	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
>  #endif
>  	EGL_NONE

Why ES2_BIT instead of ES3_BIT?

[...]
> diff --git a/cairo-glesv3-uninstall.pc b/cairo-glesv3-uninstall.pc
> new file mode 100644
> index 0000000..00ea39a
> --- /dev/null
> +++ b/cairo-glesv3-uninstall.pc
> @@ -0,0 +1,7 @@
> +Name: cairo-glesv3
> +Description: OpenGLESv3 surface backend for cairo graphics library
> +Version: 1.12.14
> +
> +Requires: cairo glesv3
> +Libs:
> +Cflags: -I${pc_top_builddir}/${pcfiledir}/./src

What's up with this file? There are no other such files in git (but
build/configure.ac.features generates such files at configure-time) and
the file name is wrong (it would need to be "uninstalled" instead of
"uninstall" so that pkg-config picks it up).

Giving the above, I'd say this file can just be dropped.

> diff --git a/configure.ac b/configure.ac
> index 93953a7..ea71ad6 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -386,6 +386,24 @@ CAIRO_ENABLE_SURFACE_BACKEND(glesv2, OpenGLESv2, no, [
>  ])
>  
>  dnl ===========================================================================
> +CAIRO_ENABLE_SURFACE_BACKEND(glesv3, OpenGLESv3, no, [
> +  glesv3_REQUIRES="glesv2"
> +  PKG_CHECK_MODULES(glesv3, $glesv3_REQUIRES,, [
> +	 dnl Fallback to searching for headers
> +	 AC_CHECK_HEADER(GLES3/gl3.h,, [use_glesv3="no (glesv2.pc nor OpenGL ES 3.0 headers not found)"])
> +	 if test "x$use_glesv3" = "xyes"; then
> +	     glesv3_NONPKGCONFIG_CFLAGS=
> +	     glesv3_NONPKGCONFIG_LIBS="-lGLESv2"
> +	 fi])

Really? The pkg-config file for glesv3 is calles glesv2 and the library
is called libGLESv2? Shouldn't there be more "3"s in there?

[...]
> diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
> index a95712e..76bc1ef 100644
> --- a/src/cairo-gl-composite.c
> +++ b/src/cairo-gl-composite.c
> @@ -52,6 +52,91 @@
[...]
> +static cairo_int_status_t
> +_blit_texture_to_renderbuffer (cairo_gl_surface_t *surface)
> +{
> +    cairo_gl_context_t *ctx = NULL;
> +    cairo_gl_composite_t setup;
> +    cairo_surface_pattern_t pattern;
> +    cairo_rectangle_int_t extents;
> +    cairo_int_status_t status;
> +
> +    /* FIXME: we need to take care of certain glesv2 extension too */

That FIXME is quite vague to me. Could something like "for example FOO"
be added, or anything to make this more precise?

[...]
> @@ -624,14 +656,19 @@ bind_multisample_framebuffer (cairo_gl_context_t *ctx,
>      cairo_bool_t scissor_test_enabled;
>  
>      assert (surface->supports_msaa);
> -    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
> +    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
> +	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3);
>  
>      _cairo_gl_ensure_framebuffer (ctx, surface);
>      _cairo_gl_ensure_multisampling (ctx, surface);
>  
>      if (surface->msaa_active) {
> +#if CAIRO_HAS_GL_SURFACE
>  	glEnable (GL_MULTISAMPLE);
> +#endif

This seems fishy to me. Shouldn't there be something like ctx->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP around this call to glEnable()? Otherwise it
will be done with GLESv3 if and only if the "desktop gl" stuff was enabled.

>  	ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
> +	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
> +	    surface->content_in_texture = FALSE;
>  	return;
>      }
>  
> @@ -642,7 +679,9 @@ bind_multisample_framebuffer (cairo_gl_context_t *ctx,
>      glDisable (GL_STENCIL_TEST);
>      glDisable (GL_SCISSOR_TEST);
>  
> +#if CAIRO_HAS_GL_SURFACE
>      glEnable (GL_MULTISAMPLE);
> +#endif

Same as above.
[...]
> @@ -669,11 +710,15 @@ bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
>      cairo_bool_t stencil_test_enabled;
>      cairo_bool_t scissor_test_enabled;
>  
> -    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
> +    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
> +	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3);
>      _cairo_gl_ensure_framebuffer (ctx, surface);
>  
>      if (! surface->msaa_active) {
> +#if CAIRO_HAS_GL_SURFACE
>  	glDisable (GL_MULTISAMPLE);
> +#endif
> +

Same.

>  	ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
>  	return;
>      }
> @@ -685,7 +730,9 @@ bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
>      glDisable (GL_STENCIL_TEST);
>      glDisable (GL_SCISSOR_TEST);
>  
> +#if CAIRO_HAS_GL_SURFACE
>      glDisable (GL_MULTISAMPLE);
> +#endif

Same.

[...]
> diff --git a/src/cairo-gl-info.c b/src/cairo-gl-info.c
> index 39541aa..29b8768 100644
> --- a/src/cairo-gl-info.c
> +++ b/src/cairo-gl-info.c
> @@ -67,6 +67,14 @@ _cairo_gl_get_flavor (void)
>  	flavor = CAIRO_GL_FLAVOR_NONE;
>      else if (strstr (version, "OpenGL ES 2") != NULL)
>  	flavor = CAIRO_GL_FLAVOR_ES2;
> +    else if (strstr (version, "OpenGL ES 3") != NULL)
> +#if CAIRO_HAS_GLESV3_SURFACE
> +	flavor = CAIRO_GL_FLAVOR_ES3;
> +#elif CAIRO_HAS_GLESV2_SURFACE
> +	flavor = CAIRO_GL_FLAVOR_ES2;
> +#else
> +	flavor = CAIRO_GL_FLAVOR_NONE;
> +#endif
>      else
>  	flavor = CAIRO_GL_FLAVOR_DESKTOP;

This patch is about adding support for OpenGL ES 3. But the above
changes the behaviour for GLES 2 if the new GLES 3 support is disabled.
Is that intended?

>  
> diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
> index 507459d..fcd4144 100644
> --- a/src/cairo-gl-msaa-compositor.c
> +++ b/src/cairo-gl-msaa-compositor.c
> @@ -280,8 +280,10 @@ can_use_msaa_compositor (cairo_gl_surface_t *surface,
>      /* Multisampling OpenGL ES surfaces only maintain one multisampling
>         framebuffer and thus must use the spans compositor to do non-antialiased
>         rendering. */
> -    if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES2
> +    if ((((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
> +	 ((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES3)
>  	 && surface->supports_msaa
> +	 && surface->num_samples > 1
>  	 && antialias == CAIRO_ANTIALIAS_NONE)
>  	return FALSE;

The above also changes things even if ES3 is disabled, doesn't it?

[...]
> @@ -1374,10 +1408,14 @@ _cairo_gl_surface_resolve_multisampling (cairo_gl_surface_t *surface)
>      if (unlikely (status))
>  	return status;
>  
> -    ctx->current_target = surface;
> +    _cairo_gl_composite_flush (ctx);
> +
> +    ctx->current_target = NULL;
[...]

Things like this look weird to me since the code will behave differently
even if GLES3 is not enabled. This is the only such place I mention,
because I do not know the code to say more about it...

Hopefully something from this was useful.

Uli
On Sat, Dec 10, 2016 at 04:22:05PM +0100, Uli Schlachter wrote:
> Again, I don't know OpenGL, so feel free to ignore anything stupid that
> I say.

Hi Uli, thanks I appreciate the review.  This is an area I'm not super
deep in myself so value the second set of eyes.
 
> On 08.12.2016 00:46, Bryce Harrington wrote:
> > @@ -87,7 +89,7 @@ _cairo_boilerplate_egl_create_surface (const char		 *name,
> >  	EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
> >  #if CAIRO_HAS_GL_SURFACE
> >  	EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
> > -#elif CAIRO_HAS_GLESV2_SURFACE
> > +#elif CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_GLESV3_SURFACE
> >  	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
> >  #endif
> >  	EGL_NONE
> 
> Why ES2_BIT instead of ES3_BIT?

It looks like there is not an EGL_OPENGL_ES2_BIT defined anywhere.  The
docs don't mention it:

  https://www.khronos.org/registry/egl/sdk/docs/man/html/eglChooseConfig.xhtml

I do see there is a EGL_OPENGL_ES3_BIT_KHR defined in the headers
(eglext.h).  This is described here:

  https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_create_context.txt

Offhand, it looks like EGL_OPENGL_ES3_BIT_KHR was added late in the
GLESv3 definition, and some GLESv3 implementations might not have had it
in the past.  I might guess that at the time Henry implemented the
patchset it was not available on the systems he was testing on; there's
no mention of it in his cairoglesv3 tree.

From the second kronos link (see Issue 8) it sounds like a proper
implementation would try to create the context with
EGL_OPENGL_ES3_BIT_KHR and then if it fails with a EGL_BAD_ATTIBUTE
error, we should re-try with ES2_BIT.

I think you're probably right that ES3_BIT would be more proper, but
I'll do a bit more investigation first.

> [...]
> > diff --git a/cairo-glesv3-uninstall.pc b/cairo-glesv3-uninstall.pc
> > new file mode 100644
> > index 0000000..00ea39a
> > --- /dev/null
> > +++ b/cairo-glesv3-uninstall.pc
> > @@ -0,0 +1,7 @@
> > +Name: cairo-glesv3
> > +Description: OpenGLESv3 surface backend for cairo graphics library
> > +Version: 1.12.14
> > +
> > +Requires: cairo glesv3
> > +Libs:
> > +Cflags: -I${pc_top_builddir}/${pcfiledir}/./src
> 
> What's up with this file? There are no other such files in git (but
> build/configure.ac.features generates such files at configure-time) and
> the file name is wrong (it would need to be "uninstalled" instead of
> "uninstall" so that pkg-config picks it up).
> 
> Giving the above, I'd say this file can just be dropped.

Ok.
 
> > diff --git a/configure.ac b/configure.ac
> > index 93953a7..ea71ad6 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -386,6 +386,24 @@ CAIRO_ENABLE_SURFACE_BACKEND(glesv2, OpenGLESv2, no, [
> >  ])
> >  
> >  dnl ===========================================================================
> > +CAIRO_ENABLE_SURFACE_BACKEND(glesv3, OpenGLESv3, no, [
> > +  glesv3_REQUIRES="glesv2"
> > +  PKG_CHECK_MODULES(glesv3, $glesv3_REQUIRES,, [
> > +	 dnl Fallback to searching for headers
> > +	 AC_CHECK_HEADER(GLES3/gl3.h,, [use_glesv3="no (glesv2.pc nor OpenGL ES 3.0 headers not found)"])
> > +	 if test "x$use_glesv3" = "xyes"; then
> > +	     glesv3_NONPKGCONFIG_CFLAGS=
> > +	     glesv3_NONPKGCONFIG_LIBS="-lGLESv2"
> > +	 fi])
> 
> Really? The pkg-config file for glesv3 is calles glesv2 and the library
> is called libGLESv2? Shouldn't there be more "3"s in there?

Yeah, that does look odd.  Maybe it's attempting to fallback to v2 if
the v3 stuff is missing?  But this isn't the right way to do that.  I'll
rework this.
 
> [...]
> > diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
> > index a95712e..76bc1ef 100644
> > --- a/src/cairo-gl-composite.c
> > +++ b/src/cairo-gl-composite.c
> > @@ -52,6 +52,91 @@
> [...]
> > +static cairo_int_status_t
> > +_blit_texture_to_renderbuffer (cairo_gl_surface_t *surface)
> > +{
> > +    cairo_gl_context_t *ctx = NULL;
> > +    cairo_gl_composite_t setup;
> > +    cairo_surface_pattern_t pattern;
> > +    cairo_rectangle_int_t extents;
> > +    cairo_int_status_t status;
> > +
> > +    /* FIXME: we need to take care of certain glesv2 extension too */
> 
> That FIXME is quite vague to me. Could something like "for example FOO"
> be added, or anything to make this more precise?

Yes, I can fix that.  There's actually a subsequent patch that fills
this in, but it's mixed in with some work adding an ANGLE feature.  I'll
see if I can extract the fix for this, or if not at least improve the
comment.

> [...]
> > @@ -624,14 +656,19 @@ bind_multisample_framebuffer (cairo_gl_context_t *ctx,
> >      cairo_bool_t scissor_test_enabled;
> >  
> >      assert (surface->supports_msaa);
> > -    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
> > +    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
> > +	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3);
> >  
> >      _cairo_gl_ensure_framebuffer (ctx, surface);
> >      _cairo_gl_ensure_multisampling (ctx, surface);
> >  
> >      if (surface->msaa_active) {
> > +#if CAIRO_HAS_GL_SURFACE
> >  	glEnable (GL_MULTISAMPLE);
> > +#endif
> 
> This seems fishy to me. Shouldn't there be something like ctx->gl_flavor
> == CAIRO_GL_FLAVOR_DESKTOP around this call to glEnable()? Otherwise it
> will be done with GLESv3 if and only if the "desktop gl" stuff was enabled.

That could be; I gather that GLESv3 automatically enables multisampling
so the glEnable call isn't necessary there.  So perhaps testing for
CAIRO_GL_FLAVOR_DESKTOP would be more proper here.  The ANGLE patch I
mentioned earlier tweaks this logic a bit, so perhaps I need to tease
some of that out and squash it here.

> >  	ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
> > +	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
> > +	    surface->content_in_texture = FALSE;
> >  	return;
> >      }
> >  
> > @@ -642,7 +679,9 @@ bind_multisample_framebuffer (cairo_gl_context_t *ctx,
> >      glDisable (GL_STENCIL_TEST);
> >      glDisable (GL_SCISSOR_TEST);
> >  
> > +#if CAIRO_HAS_GL_SURFACE
> >      glEnable (GL_MULTISAMPLE);
> > +#endif
> 
> Same as above.
> [...]
> > @@ -669,11 +710,15 @@ bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
> >      cairo_bool_t stencil_test_enabled;
> >      cairo_bool_t scissor_test_enabled;
> >  
> > -    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
> > +    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
> > +	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3);
> >      _cairo_gl_ensure_framebuffer (ctx, surface);
> >  
> >      if (! surface->msaa_active) {
> > +#if CAIRO_HAS_GL_SURFACE
> >  	glDisable (GL_MULTISAMPLE);
> > +#endif
> > +
> 
> Same.
> 
> >  	ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
> >  	return;
> >      }
> > @@ -685,7 +730,9 @@ bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
> >      glDisable (GL_STENCIL_TEST);
> >      glDisable (GL_SCISSOR_TEST);
> >  
> > +#if CAIRO_HAS_GL_SURFACE
> >      glDisable (GL_MULTISAMPLE);
> > +#endif
> 
> Same.
> 
> [...]
> > diff --git a/src/cairo-gl-info.c b/src/cairo-gl-info.c
> > index 39541aa..29b8768 100644
> > --- a/src/cairo-gl-info.c
> > +++ b/src/cairo-gl-info.c
> > @@ -67,6 +67,14 @@ _cairo_gl_get_flavor (void)
> >  	flavor = CAIRO_GL_FLAVOR_NONE;
> >      else if (strstr (version, "OpenGL ES 2") != NULL)
> >  	flavor = CAIRO_GL_FLAVOR_ES2;
> > +    else if (strstr (version, "OpenGL ES 3") != NULL)
> > +#if CAIRO_HAS_GLESV3_SURFACE
> > +	flavor = CAIRO_GL_FLAVOR_ES3;
> > +#elif CAIRO_HAS_GLESV2_SURFACE
> > +	flavor = CAIRO_GL_FLAVOR_ES2;
> > +#else
> > +	flavor = CAIRO_GL_FLAVOR_NONE;
> > +#endif
> >      else
> >  	flavor = CAIRO_GL_FLAVOR_DESKTOP;
> 
> This patch is about adding support for OpenGL ES 3. But the above
> changes the behaviour for GLES 2 if the new GLES 3 support is disabled.
> Is that intended?

Guessing it probably has no effect in practice, but you're right, the
fallback for undefined CAIRO_HAS_GLESV2_SURFACE should be the same
regardless of whether the system's ES support is version 2 or 3.
I'll fix this and look at the following.

> > diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
> > index 507459d..fcd4144 100644
> > --- a/src/cairo-gl-msaa-compositor.c
> > +++ b/src/cairo-gl-msaa-compositor.c
> > @@ -280,8 +280,10 @@ can_use_msaa_compositor (cairo_gl_surface_t *surface,
> >      /* Multisampling OpenGL ES surfaces only maintain one multisampling
> >         framebuffer and thus must use the spans compositor to do non-antialiased
> >         rendering. */
> > -    if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES2
> > +    if ((((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
> > +	 ((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES3)
> >  	 && surface->supports_msaa
> > +	 && surface->num_samples > 1
> >  	 && antialias == CAIRO_ANTIALIAS_NONE)
> >  	return FALSE;
> 
> The above also changes things even if ES3 is disabled, doesn't it?
> 
> [...]
> > @@ -1374,10 +1408,14 @@ _cairo_gl_surface_resolve_multisampling (cairo_gl_surface_t *surface)
> >      if (unlikely (status))
> >  	return status;
> >  
> > -    ctx->current_target = surface;
> > +    _cairo_gl_composite_flush (ctx);
> > +
> > +    ctx->current_target = NULL;
> [...]
> 
> Things like this look weird to me since the code will behave differently
> even if GLES3 is not enabled. This is the only such place I mention,
> because I do not know the code to say more about it...

I'll comb through and try and remove more of these, and if the change
seems justifyable will submit as a discrete patch.
 
> Hopefully something from this was useful.

Definitely, thanks again!

Bryce

> Uli
> -- 
> Happiness can't be found -- it finds you.
>  - Majic