[cairo-commit] 3 commits - boilerplate/cairo-boilerplate-egl.c boilerplate/Makefile.win32.features build/configure.ac.features build/Makefile.win32.features build/Makefile.win32.features-h configure.ac src/cairo-gl-composite.c src/cairo-gl-device.c src/cairo-gl-dispatch.c src/cairo-gl-gradient.c src/cairo-gl-gradient-private.h src/cairo-gl.h src/cairo-gl-info.c src/cairo-gl-msaa-compositor.c src/cairo-gl-operand.c src/cairo-gl-private.h src/cairo-gl-shaders.c src/cairo-gl-surface.c src/cairo-gl-traps-compositor.c src/Makefile.sources src/Makefile.win32.features

Bryce Harrington bryce at kemper.freedesktop.org
Wed Sep 13 22:21:59 UTC 2017


 boilerplate/Makefile.win32.features |   12 ++++
 boilerplate/cairo-boilerplate-egl.c |   30 +++++++---
 build/Makefile.win32.features       |    1 
 build/Makefile.win32.features-h     |    3 +
 build/configure.ac.features         |    1 
 configure.ac                        |   23 +++++++
 src/Makefile.sources                |    4 +
 src/Makefile.win32.features         |   16 +++++
 src/cairo-gl-composite.c            |  103 ++++++++++++++++++++++++++++++++++-
 src/cairo-gl-device.c               |   93 ++++++++++++++++++++++++--------
 src/cairo-gl-dispatch.c             |   12 ++++
 src/cairo-gl-gradient-private.h     |    9 ++-
 src/cairo-gl-gradient.c             |    3 -
 src/cairo-gl-info.c                 |    4 +
 src/cairo-gl-msaa-compositor.c      |   10 +++
 src/cairo-gl-operand.c              |    3 -
 src/cairo-gl-private.h              |   24 ++++++--
 src/cairo-gl-shaders.c              |   15 +++--
 src/cairo-gl-surface.c              |  104 +++++++++++++++++++++++++++++++++---
 src/cairo-gl-traps-compositor.c     |   30 ----------
 src/cairo-gl.h                      |    2 
 21 files changed, 413 insertions(+), 89 deletions(-)

New commits:
commit 8ff3019f51bd40c23d8a0dd5e51ce3fab6442d6e
Author: Bryce Harrington <bryce at osg.samsung.com>
Date:   Wed Sep 13 12:35:27 2017 -0700

    gl: Add support for OpenGL ES 3.0
    
    This improves the OpenGL ES support to extend it to version 3.0.
    A number of new features are available in glesv3 including creation of
    multi-sampled renderbuffers.  These renderbuffers can be blitted to
    single sample textures (but not the other way around).  Other features
    such as PBO for image uploading, are left as followon work.
    
    For this preliminary implementation, glesv3 backends always create
    renderbuffers, which can be set as single sample or multisample.  The
    renderbuffer's content is blitted to the texture only when used as a
    source or a mask.
    
    Images uploaded to a texture stay there until the surface is used as a
    rendering target, at which point its painted to the renderbuffer.
    
    This patch is heavily based off of Henry Song's initial GLESv3 patch
    6f7f3795 from his cairogles fork of Cairo, and incorporates subsequent
    fixes and pertinent refactorings from his trunk and review feedback from
    Uli.
    
    This implements the *functional* support for glesv3, excluding the
    various optimization work to utilize its features.  Rendering and
    performance should not be expected to improve notably from pure glesv2.
    As the GL backend for Cairo remains "experimental", these changes should
    likewise be considered as such.
    
    Signed-off-by: Bryce Harrington <bryce at osg.samsung.com>

diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index e60a95ba..abb198de 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 99bee64c..c44441cc 100644
--- a/boilerplate/cairo-boilerplate-egl.c
+++ b/boilerplate/cairo-boilerplate-egl.c
@@ -33,10 +33,13 @@
 #include "cairo-boilerplate-private.h"
 
 #include <cairo-gl.h>
-#if CAIRO_HAS_GL_SURFACE
-#include <GL/gl.h>
+#if CAIRO_HAS_GLESV3_SURFACE
+#include <GLES3/gl3.h>
+#include <EGL/eglext.h>
 #elif CAIRO_HAS_GLESV2_SURFACE
 #include <GLES2/gl2.h>
+#elif CAIRO_HAS_GL_SURFACE
+#include <GL/gl.h>
 #endif
 
 static const cairo_user_data_key_t gl_closure_key;
@@ -85,15 +88,19 @@ _cairo_boilerplate_egl_create_surface (const char		 *name,
 	EGL_BLUE_SIZE, 8,
 	EGL_ALPHA_SIZE, 8,
 	EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
-#if CAIRO_HAS_GL_SURFACE
-	EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+#if CAIRO_HAS_GLESV3_SURFACE
+	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
 #elif CAIRO_HAS_GLESV2_SURFACE
 	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+#elif CAIRO_HAS_GL_SURFACE
+	EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
 #endif
 	EGL_NONE
     };
     const EGLint ctx_attribs[] = {
-#if CAIRO_HAS_GLESV2_SURFACE
+#if CAIRO_HAS_GLESV3_SURFACE
+	EGL_CONTEXT_CLIENT_VERSION, 3,
+#elif CAIRO_HAS_GLESV2_SURFACE
 	EGL_CONTEXT_CLIENT_VERSION, 2,
 #endif
 	EGL_NONE
@@ -110,15 +117,22 @@ _cairo_boilerplate_egl_create_surface (const char		 *name,
     }
 
     eglChooseConfig (gltc->dpy, config_attribs, &config, 1, &numConfigs);
+#if CAIRO_HAS_GLESV3_SURFACE && CAIRO_HAS_GLESV2_SURFACE
+    if (numConfigs == 0) {
+        /* retry with ES2_BIT */
+        config_attribs[11] = ES2_BIT;  /* FIXME: Ick */
+        eglChooseConfig (gltc->dpy, config_attribs, &config, 1, &numConfigs);
+    }
+#endif
     if (numConfigs == 0) {
 	free (gltc);
 	return NULL;
     }
 
-#if CAIRO_HAS_GL_SURFACE
-    eglBindAPI (EGL_OPENGL_API);
-#elif CAIRO_HAS_GLESV2_SURFACE
+#if CAIRO_HAS_GLESV3_SURFACE || CAIRO_HAS_GLESV2_SURFACE
     eglBindAPI (EGL_OPENGL_ES_API);
+#elif CAIRO_HAS_GL_SURFACE
+    eglBindAPI (EGL_OPENGL_API);
 #endif
 
     gltc->ctx = eglCreateContext (gltc->dpy, config, EGL_NO_CONTEXT,
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
index 8cb155dc..7f62d975 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 13904cfa..2825f0c3 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 77f20358..aa48652f 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/configure.ac b/configure.ac
index 93953a7f..264623d8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -386,6 +386,29 @@ CAIRO_ENABLE_SURFACE_BACKEND(glesv2, OpenGLESv2, no, [
 ])
 
 dnl ===========================================================================
+CAIRO_ENABLE_SURFACE_BACKEND(glesv3, OpenGLESv3, no, [
+  glesv3_REQUIRES="glesv3"
+  PKG_CHECK_MODULES(glesv3, $glesv3_REQUIRES,, [
+	 dnl Fallback to searching for headers
+	 AC_CHECK_HEADER(GLES3/gl3.h,, [use_glesv3="no (glesv3.pc nor OpenGL ES 3.0 headers not found)"])
+	 if test "x$use_glesv3" = "xyes"; then
+	     glesv3_NONPKGCONFIG_CFLAGS=
+	     dnl glesv3 is provided by the libGLESv2 library (there is no separate libGLESv3)
+	     glesv3_NONPKGCONFIG_LIBS="-lGLESv2"
+	 fi])
+
+  if test "x$have_dl" = "xyes" -a "x$have_dlsym" = "xyes"; then
+    glesv3_LIBS="$glesv3_LIBS -ldl"
+  fi
+
+  if test "x$use_glesv3" = "xyes" -a "x$use_gl" = "xyes"; then
+      AC_MSG_ERROR([use either --enable-gl=yes or --enable-glesv3=yes. Not both at the same time.])
+  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 b1e3eb13..89417ac8 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 2274f4ad..e8be9f74 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 a95712e1..ecf03a55 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -52,6 +52,93 @@
 #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: This only permits blit when glesv3 is enabled.  But note that
+       glesv2 with the ANGLE extension should also be able to support this feature,
+       so once the ANGLE support code is in place this check can be relaxed. */
+    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 +155,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 +191,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 +270,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_ES3 ||
+	    ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2)
 	    wrap_mode = GL_CLAMP_TO_EDGE;
 	else
 	    wrap_mode = GL_CLAMP_TO_BORDER;
@@ -1178,6 +1275,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 2f56a5fd..38582fd2 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_ES3 ||
+	    gl_flavor == CAIRO_GL_FLAVOR_ES2);
 
    /* 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_ES3 ||
+			    gl_flavor == CAIRO_GL_FLAVOR_ES2);
 
     _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
 
@@ -263,25 +265,31 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     }
 #endif
 
-#if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_EXT)
+#if CAIRO_HAS_GLESV3_SURFACE
+    if (is_gles && ctx->has_packed_depth_stencil) {
+	glGetIntegerv(GL_MAX_SAMPLES, &ctx->num_samples);
+    }
+
+#elif CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_EXT)
     if (is_gles && ctx->has_packed_depth_stencil &&
 	_cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture")) {
 	glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
     }
-#endif
 
-#if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_IMG)
     if (is_gles && ctx->has_packed_depth_stencil &&
 	_cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture")) {
 	glGetIntegerv(GL_MAX_SAMPLES_IMG, &ctx->num_samples);
     }
 #endif
 
-    ctx->supports_msaa = ctx->num_samples > 1;
+    /* 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;
 
@@ -349,13 +357,15 @@ _get_depth_stencil_format (cairo_gl_context_t *ctx)
 	return GL_DEPTH_STENCIL;
 #endif
 
-#if CAIRO_HAS_GLESV2_SURFACE
+#if CAIRO_HAS_GLESV2_SURFACE && !CAIRO_HAS_GLESV3_SURFACE
     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
 	return GL_DEPTH24_STENCIL8_OES;
 #endif
 
 #if CAIRO_HAS_GL_SURFACE
     return GL_DEPTH_STENCIL;
+#elif CAIRO_HAS_GLESV3_SURFACE
+    return GL_DEPTH24_STENCIL8;
 #elif CAIRO_HAS_GLESV2_SURFACE
     return GL_DEPTH24_STENCIL8_OES;
 #endif
@@ -436,13 +446,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 +471,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 +487,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 +504,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 +520,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 +637,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 +646,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 +669,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
@@ -651,17 +680,24 @@ bind_multisample_framebuffer (cairo_gl_context_t *ctx,
     ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->fb);
     ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
 				   0, 0, surface->width, surface->height,
-				   GL_COLOR_BUFFER_BIT, GL_NEAREST);
+				   GL_COLOR_BUFFER_BIT
+#if CAIRO_HAS_GL_SURFACE
+				   | GL_STENCIL_BUFFER_BIT
+#endif
+				   ,
+				   GL_NEAREST);
     ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
 
     if (stencil_test_enabled)
 	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 +705,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 +725,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 +760,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 +779,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
@@ -751,9 +794,13 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
      * 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;
 
diff --git a/src/cairo-gl-dispatch.c b/src/cairo-gl-dispatch.c
index 3e372192..a49199db 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 77f9bbdc..0d9f41f5 100644
--- a/src/cairo-gl-gradient-private.h
+++ b/src/cairo-gl-gradient-private.h
@@ -51,12 +51,15 @@
 
 #include "cairo-gl.h"
 
-#if CAIRO_HAS_GL_SURFACE
-#include <GL/gl.h>
-#include <GL/glext.h>
+#if CAIRO_HAS_GLESV3_SURFACE
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
 #elif CAIRO_HAS_GLESV2_SURFACE
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#elif CAIRO_HAS_GL_SURFACE
+#include <GL/gl.h>
+#include <GL/glext.h>
 #endif
 
 #define CAIRO_GL_GRADIENT_CACHE_SIZE 4096
diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c
index db82c23d..0ab01ac3 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_ES3 ||
+	_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2)
 	internal_format = GL_BGRA;
     else
 	internal_format = GL_RGBA;
diff --git a/src/cairo-gl-info.c b/src/cairo-gl-info.c
index a4b42715..032e2568 100644
--- a/src/cairo-gl-info.c
+++ b/src/cairo-gl-info.c
@@ -65,7 +65,9 @@ _cairo_gl_get_flavor (void)
 
     if (version == NULL)
 	flavor = CAIRO_GL_FLAVOR_NONE;
-    else if (strstr (version, "OpenGL ES") != NULL)
+    else if (strstr (version, "OpenGL ES 3") != NULL)
+	flavor = CAIRO_GL_FLAVOR_ES3;
+    else if (strstr (version, "OpenGL ES 2") != NULL)
 	flavor = CAIRO_GL_FLAVOR_ES2;
     else
 	flavor = CAIRO_GL_FLAVOR_DESKTOP;
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 507459de..f9cd7c29 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -273,6 +273,8 @@ static cairo_bool_t
 can_use_msaa_compositor (cairo_gl_surface_t *surface,
 			 cairo_antialias_t antialias)
 {
+    cairo_gl_flavor_t gl_flavor = ((cairo_gl_context_t *) surface->base.device)->gl_flavor;
+
     query_surface_capabilities (surface);
     if (! surface->supports_stencil)
 	return FALSE;
@@ -280,8 +282,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 ((gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
+	 gl_flavor == CAIRO_GL_FLAVOR_ES2)
 	 && surface->supports_msaa
+	 && surface->num_samples > 1
 	 && antialias == CAIRO_ANTIALIAS_NONE)
 	return FALSE;
 
@@ -378,6 +382,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;
@@ -634,6 +641,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 ca1fa4b6..8626329e 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_ES3 ||
+	     ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) &&
 	    _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 b2d8545c..f02a5876 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -60,12 +60,15 @@
 
 #include <assert.h>
 
-#if CAIRO_HAS_GL_SURFACE
-#include <GL/gl.h>
-#include <GL/glext.h>
+#if CAIRO_HAS_GLESV3_SURFACE
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
 #elif CAIRO_HAS_GLESV2_SURFACE
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#elif CAIRO_HAS_GL_SURFACE
+#include <GL/gl.h>
+#include <GL/glext.h>
 #endif
 
 #include "cairo-gl-ext-def-private.h"
@@ -99,11 +102,12 @@
 
 typedef struct _cairo_gl_surface cairo_gl_surface_t;
 
-/* GL flavor */
+/* GL flavor is the type of GL supported by the underlying platform. */
 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;
+    GLint        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 aceb5d25..7d4fefbb 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_ES3 ||
+	     ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) &&
 	    _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_ES3 ||
+	     ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) &&
 	    _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_ES3 ||
+	     ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) &&
 	    _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_ES3 ||
+	     ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) &&
 	    _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_ES3 ||
+	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) {
 	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 8ecc3a92..6be6d986 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_ES3 ||
+	_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2) {
 	pixman_format_code_t pixman_format;
 	cairo_surface_pattern_t pattern;
 	cairo_bool_t require_conversion = FALSE;
@@ -885,13 +888,12 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	    if (src->pixman_format != pixman_format)
 		require_conversion = TRUE;
 	}
-	else if (dst->base.content != CAIRO_CONTENT_ALPHA)
+	else if (dst->base.content != CAIRO_CONTENT_ALPHA) {
+	    require_conversion = TRUE;
+	}
+	else if (src->pixman_format != PIXMAN_a8) {
+	    pixman_format = PIXMAN_a8;
 	    require_conversion = TRUE;
-	else {
-	    if (src->pixman_format == PIXMAN_a1) {
-		pixman_format = PIXMAN_a8;
-		require_conversion = TRUE;
-	    }
 	}
 
 	if (require_conversion) {
@@ -980,10 +982,19 @@ _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)) {
+	    free (data_start_gles2);
+	    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 +1014,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 +1055,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 +1107,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 +1159,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_ES3 ||
+	_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES2) {
 	/* 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 +1209,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 +1398,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 +1409,20 @@ _cairo_gl_surface_resolve_multisampling (cairo_gl_surface_t *surface)
     if (unlikely (status))
 	return status;
 
-    ctx->current_target = surface;
+#if CAIRO_HAS_GLESV3_SURFACE
+    _cairo_gl_composite_flush (ctx);
+    ctx->current_target = NULL;
+    _cairo_gl_context_bind_framebuffer (ctx, surface, FALSE);
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
+	surface->content_in_texture = TRUE;
 
-#if CAIRO_HAS_GL_SURFACE
+#elif CAIRO_HAS_GL_SURFACE
+    ctx->current_target = surface;
     _cairo_gl_context_bind_framebuffer (ctx, surface, FALSE);
+
+#else
+    ctx->current_target = surface;
+
 #endif
 
     status = _cairo_gl_context_release (ctx, status);
diff --git a/src/cairo-gl.h b/src/cairo-gl.h
index 9fd7608f..7cd869c7 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
 
commit d1f941d7ee06340c155158b32bec28fc2e1a4264
Author: Bryce Harrington <bryce at osg.samsung.com>
Date:   Thu Oct 20 16:37:28 2016 -0700

    gl: Make _cairo_gl_ensure_framebuffer a private shared routine
    
    Signed-off-by: Bryce Harrington <bryce at osg.samsung.com>

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index c6aba430..2f56a5fd 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -381,7 +381,7 @@ _cairo_gl_ensure_msaa_gles_framebuffer (cairo_gl_context_t *ctx,
 }
 #endif
 
-static void
+void
 _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
                               cairo_gl_surface_t *surface)
 {
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index b6d236c5..b2d8545c 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -801,6 +801,10 @@ _cairo_gl_composite_glyphs_with_clip (void			    *_dst,
 				      cairo_composite_glyphs_info_t *info,
 				      cairo_clip_t		    *clip);
 
+cairo_private void
+_cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
+                              cairo_gl_surface_t *surface);
+
 cairo_private cairo_surface_t *
 _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
 				  cairo_content_t	content,
commit 4b164bc89872f0cf4e123e1358cc83be8e83a4d3
Author: Bryce Harrington <bryce at osg.samsung.com>
Date:   Fri Oct 7 15:26:25 2016 -0700

    gl: Convert images to rgba or a8 formats when uploading with GLESv2
    
    The GLESv2 backend supports only GL_RGBA and GL_ALPHA as supported
    texture formats.  So, make _cairo_gl_get_image_format_and_type_gles2
    force conversion of other image formats to either of these two as
    appropriate when uploading images.
    
    Patch originally from Henry Song <henry.song at samsung.com>
    
    Bryce Harrington <bryce at osg.samsung.com>
    
    Signed-off-by: Bryce Harrington <bryce at osg.samsung.com>

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index e5e8205d..8ecc3a92 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -868,12 +868,54 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
     cairo_image_surface_t *clone = NULL;
     cairo_gl_context_t *ctx;
     int cpp;
+    cairo_image_surface_t *rgba_clone = NULL;
     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
 
     status = _cairo_gl_context_acquire (dst->base.device, &ctx);
     if (unlikely (status))
 	return status;
 
+    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2) {
+	pixman_format_code_t pixman_format;
+	cairo_surface_pattern_t pattern;
+	cairo_bool_t require_conversion = FALSE;
+	pixman_format = _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8;
+
+	if (src->base.content != CAIRO_CONTENT_ALPHA) {
+	    if (src->pixman_format != pixman_format)
+		require_conversion = TRUE;
+	}
+	else if (dst->base.content != CAIRO_CONTENT_ALPHA)
+	    require_conversion = TRUE;
+	else {
+	    if (src->pixman_format == PIXMAN_a1) {
+		pixman_format = PIXMAN_a8;
+		require_conversion = TRUE;
+	    }
+	}
+
+	if (require_conversion) {
+	    rgba_clone = (cairo_image_surface_t *)
+		_cairo_image_surface_create_with_pixman_format (NULL,
+								pixman_format,
+								src->width,
+								src->height,
+								0);
+	    if (unlikely (rgba_clone->base.status))
+		goto FAIL;
+
+	    _cairo_pattern_init_for_surface (&pattern, &src->base);
+	    status = _cairo_surface_paint (&rgba_clone->base,
+					   CAIRO_OPERATOR_SOURCE,
+					   &pattern.base, NULL);
+	    _cairo_pattern_fini (&pattern.base);
+	    if (unlikely (status))
+		goto FAIL;
+
+	    src = rgba_clone;
+	}
+    }
+
     if (! _cairo_gl_get_image_format_and_type (ctx->gl_flavor,
 					       src->pixman_format,
 					       &internal_format,
@@ -1008,6 +1050,9 @@ FAIL:
     if (clone)
         cairo_surface_destroy (&clone->base);
 
+    if (rgba_clone)
+	cairo_surface_destroy (&rgba_clone->base);
+
     return status;
 }
 
diff --git a/src/cairo-gl-traps-compositor.c b/src/cairo-gl-traps-compositor.c
index 664a27a4..1e11006e 100644
--- a/src/cairo-gl-traps-compositor.c
+++ b/src/cairo-gl-traps-compositor.c
@@ -303,36 +303,6 @@ traps_to_operand (void *_dst,
 	return image->status;
     }
 
-    /* GLES2 only supports RGB/RGBA when uploading */
-    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2) {
-	cairo_surface_pattern_t pattern;
-	cairo_surface_t *rgba_image;
-
-	/* XXX perform this fixup inside _cairo_gl_draw_image() */
-
-	rgba_image =
-	    _cairo_image_surface_create_with_pixman_format (NULL,
-							    _cairo_is_little_endian () ?  PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8,
-							    extents->width,
-							    extents->height,
-							    0);
-	if (unlikely (rgba_image->status))
-	    return rgba_image->status;
-
-	_cairo_pattern_init_for_surface (&pattern, image);
-	status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE,
-				       &pattern.base, NULL);
-	_cairo_pattern_fini (&pattern.base);
-
-	cairo_surface_destroy (image);
-	image = rgba_image;
-
-	if (unlikely (status)) {
-	    cairo_surface_destroy (image);
-	    return status;
-	}
-    }
-
     mask = _cairo_surface_create_scratch (_dst,
 					  CAIRO_CONTENT_COLOR_ALPHA,
 					  extents->width,


More information about the cairo-commit mailing list