Add support for ES3 MSAA.

R=robertphillips@google.com, jvanverth@google.com

Author: bsalomon@google.com

Review URL: https://chromiumcodereview.appspot.com/23404002

git-svn-id: http://skia.googlecode.com/svn/trunk/src@11124 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/gl/GrGLCaps.cpp b/gpu/gl/GrGLCaps.cpp
index 382bfba..1488e75 100644
--- a/gpu/gl/GrGLCaps.cpp
+++ b/gpu/gl/GrGLCaps.cpp
@@ -386,17 +386,21 @@
 
     fMSFBOType = kNone_MSFBOType;
     if (kDesktop_GrGLBinding != ctxInfo.binding()) {
-       if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample")) {
-           // chrome's extension is equivalent to the EXT msaa
-           // and fbo_blit extensions.
-           fMSFBOType = kDesktop_EXT_MSFBOType;
-       } else if (ctxInfo.hasExtension("GL_APPLE_framebuffer_multisample")) {
-           fMSFBOType = kES_Apple_MSFBOType;
-       } else if (ctxInfo.hasExtension("GL_EXT_multisampled_render_to_texture")) {
-           fMSFBOType = kES_EXT_MsToTexture_MSFBOType;
-       } else if (ctxInfo.hasExtension("GL_IMG_multisampled_render_to_texture")) {
-           fMSFBOType = kES_IMG_MsToTexture_MSFBOType;
-       }
+        // We prefer the EXT/IMG extension over ES3 MSAA because we've observed
+        // ES3 driver bugs on at least one device with a tiled GPU (N10).
+        if (ctxInfo.hasExtension("GL_EXT_multisampled_render_to_texture")) {
+            fMSFBOType = kES_EXT_MsToTexture_MSFBOType;
+        } else if (ctxInfo.hasExtension("GL_IMG_multisampled_render_to_texture")) {
+            fMSFBOType = kES_IMG_MsToTexture_MSFBOType;
+        } else if (!GR_GL_IGNORE_ES3_MSAA && ctxInfo.version() >= GR_GL_VER(3,0)) {
+            fMSFBOType = GrGLCaps::kES_3_0_MSFBOType;
+        } else if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample")) {
+            // chrome's extension is equivalent to the EXT msaa
+            // and fbo_blit extensions.
+            fMSFBOType = kDesktop_EXT_MSFBOType;
+        } else if (ctxInfo.hasExtension("GL_APPLE_framebuffer_multisample")) {
+            fMSFBOType = kES_Apple_MSFBOType;
+        }
     } else {
         if ((ctxInfo.version() >= GR_GL_VER(3,0)) ||
             ctxInfo.hasExtension("GL_ARB_framebuffer_object")) {
@@ -569,6 +573,7 @@
         "None",
         "ARB",
         "EXT",
+        "ES 3.0",
         "Apple",
         "IMG MS To Texture",
         "EXT MS To Texture",
@@ -576,9 +581,10 @@
     GR_STATIC_ASSERT(0 == kNone_MSFBOType);
     GR_STATIC_ASSERT(1 == kDesktop_ARB_MSFBOType);
     GR_STATIC_ASSERT(2 == kDesktop_EXT_MSFBOType);
-    GR_STATIC_ASSERT(3 == kES_Apple_MSFBOType);
-    GR_STATIC_ASSERT(4 == kES_IMG_MsToTexture_MSFBOType);
-    GR_STATIC_ASSERT(5 == kES_EXT_MsToTexture_MSFBOType);
+    GR_STATIC_ASSERT(3 == kES_3_0_MSFBOType);
+    GR_STATIC_ASSERT(4 == kES_Apple_MSFBOType);
+    GR_STATIC_ASSERT(5 == kES_IMG_MsToTexture_MSFBOType);
+    GR_STATIC_ASSERT(6 == kES_EXT_MsToTexture_MSFBOType);
     GR_STATIC_ASSERT(GR_ARRAY_COUNT(kMSFBOExtStr) == kLast_MSFBOType + 1);
 
     static const char* kFBFetchTypeStr[] = {
diff --git a/gpu/gl/GrGLCaps.h b/gpu/gl/GrGLCaps.h
index a4d5673..a05d2b6 100644
--- a/gpu/gl/GrGLCaps.h
+++ b/gpu/gl/GrGLCaps.h
@@ -54,7 +54,7 @@
          */
         kNone_MSFBOType = 0,
         /**
-         * GL3.0-style MSAA FBO (GL_ARB_framebuffer_object)
+         * GL3.0-style MSAA FBO (GL_ARB_framebuffer_object). 
          */
         kDesktop_ARB_MSFBOType,
         /**
@@ -62,6 +62,10 @@
          */
         kDesktop_EXT_MSFBOType,
         /**
+         * Similar to kDesktop_ARB but with additional restrictions on glBlitFramebuffer.
+         */
+        kES_3_0_MSFBOType,
+        /**
          * GL_APPLE_framebuffer_multisample ES extension
          */
         kES_Apple_MSFBOType,
diff --git a/gpu/gl/GrGLInterface.cpp b/gpu/gl/GrGLInterface.cpp
index d15b4cc..7e557da 100644
--- a/gpu/gl/GrGLInterface.cpp
+++ b/gpu/gl/GrGLInterface.cpp
@@ -336,25 +336,45 @@
             }
         }
     } else {
+#if GR_GL_IGNORE_ES3_MSAA
         if (extensions.has("GL_CHROMIUM_framebuffer_multisample")) {
             if (NULL == fRenderbufferStorageMultisample ||
                 NULL == fBlitFramebuffer) {
                 return false;
             }
+        } else if (extensions.has("GL_APPLE_framebuffer_multisample")) {
+            if (NULL == fRenderbufferStorageMultisample ||
+                NULL == fResolveMultisampleFramebuffer) {
+                return false;
+            }
+        } else if (extensions.has("GL_IMG_multisampled_render_to_texture") ||
+                   extensions.has("GL_EXT_multisampled_render_to_texture")) {
+            if (NULL == fRenderbufferStorageMultisample ||
+                NULL == fFramebufferTexture2DMultisample) {
+                return false;
+            }
+        }
+#else
+        if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_CHROMIUM_framebuffer_multisample")) {
+            if (NULL == fRenderbufferStorageMultisample ||
+                NULL == fBlitFramebuffer) {
+                return false;
+            }
         }
         if (extensions.has("GL_APPLE_framebuffer_multisample")) {
-            if (NULL == fRenderbufferStorageMultisample ||
+            if (NULL == fRenderbufferStorageMultisampleES2APPLE ||
                 NULL == fResolveMultisampleFramebuffer) {
                 return false;
             }
         }
         if (extensions.has("GL_IMG_multisampled_render_to_texture") ||
             extensions.has("GL_EXT_multisampled_render_to_texture")) {
-            if (NULL == fRenderbufferStorageMultisample ||
+            if (NULL == fRenderbufferStorageMultisampleES2EXT ||
                 NULL == fFramebufferTexture2DMultisample) {
                 return false;
             }
         }
+#endif
     }
 
     // On ES buffer mapping is an extension. On Desktop
diff --git a/gpu/gl/GrGpuGL.cpp b/gpu/gl/GrGpuGL.cpp
index a9fd41e..75b4191 100644
--- a/gpu/gl/GrGpuGL.cpp
+++ b/gpu/gl/GrGpuGL.cpp
@@ -789,11 +789,43 @@
         created = (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(ctx.interface()));
     }
     if (!created) {
+#if GR_GL_IGNORE_ES3_MSAA
         GL_ALLOC_CALL(ctx.interface(),
                       RenderbufferStorageMultisample(GR_GL_RENDERBUFFER,
                                                      sampleCount,
                                                      format,
                                                      width, height));
+#else
+        switch (ctx.info().caps()->msFBOType()) {
+            case GrGLCaps::kDesktop_ARB_MSFBOType:
+            case GrGLCaps::kDesktop_EXT_MSFBOType:
+            case GrGLCaps::kES_3_0_MSFBOType:
+                GL_ALLOC_CALL(ctx.interface(),
+                              RenderbufferStorageMultisample(GR_GL_RENDERBUFFER,
+                                                             sampleCount,
+                                                             format,
+                                                             width, height));
+                break;
+            case GrGLCaps::kES_Apple_MSFBOType:
+                GL_ALLOC_CALL(ctx.interface(),
+                              RenderbufferStorageMultisampleES2APPLE(GR_GL_RENDERBUFFER,
+                                                                     sampleCount,
+                                                                     format,
+                                                                     width, height));
+                break;
+            case GrGLCaps::kES_EXT_MsToTexture_MSFBOType:
+            case GrGLCaps::kES_IMG_MsToTexture_MSFBOType:
+                GL_ALLOC_CALL(ctx.interface(),
+                              RenderbufferStorageMultisampleES2EXT(GR_GL_RENDERBUFFER,
+                                                                   sampleCount,
+                                                                   format,
+                                                                   width, height));
+                break;
+            case GrGLCaps::kNone_MSFBOType:
+                GrCrash("Shouldn't be here if we don't support multisampled renderbuffers.");
+                break;
+        }
+#endif
         created = (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(ctx.interface()));
     }
     return created;
@@ -2313,6 +2345,12 @@
     if (gpu->isConfigRenderable(dst->config()) &&
         gpu->isConfigRenderable(src->config()) &&
         gpu->glCaps().usesMSAARenderBuffers()) {
+        // ES3 doesn't allow framebuffer blits when the src has MSAA and the configs don't match
+        // or the rects are not the same (not just the same size but have the same edges).
+        if (GrGLCaps::kES_3_0_MSFBOType == gpu->glCaps().msFBOType() &&
+            (src->desc().fSampleCnt > 0 || src->config() != dst->config())) {
+           return false;
+        }
         if (NULL != wouldNeedTempFBO) {
             *wouldNeedTempFBO = NULL == dst->asRenderTarget() || NULL == src->asRenderTarget();
         }
diff --git a/gpu/gl/android/GrGLCreateNativeInterface_android.cpp b/gpu/gl/android/GrGLCreateNativeInterface_android.cpp
index 881a46b..5e5411e 100644
--- a/gpu/gl/android/GrGLCreateNativeInterface_android.cpp
+++ b/gpu/gl/android/GrGLCreateNativeInterface_android.cpp
@@ -147,6 +147,8 @@
     interface->fDeleteRenderbuffers = glDeleteRenderbuffers;
     interface->fFramebufferRenderbuffer = glFramebufferRenderbuffer;
     interface->fFramebufferTexture2D = glFramebufferTexture2D;
+#if GR_GL_IGNORE_ES3_MSAA
+
     if (extensions.has("GL_EXT_multisampled_render_to_texture")) {
 #if GL_EXT_multisampled_render_to_texture
         interface->fFramebufferTexture2DMultisample = glFramebufferTexture2DMultisampleEXT;
@@ -164,6 +166,37 @@
         interface->fRenderbufferStorageMultisample = (GrGLRenderbufferStorageMultisampleProc) eglGetProcAddress("glRenderbufferStorageMultisampleIMG");
 #endif
     }
+
+#else // GR_GL_IGNORE_ES3_MSAA
+
+        if (version >= GR_GL_VER(3,0)) {
+#if GL_ES_VERSION_3_0
+            interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisample;
+            interface->fBlitFramebuffer = glBlitFramebuffer;
+#else
+            interface->fRenderbufferStorageMultisample = (GrGLRenderbufferStorageMultisampleProc) eglGetProcAddress("glRenderbufferStorageMultisample");
+            interface->fBlitFramebuffer = (GrGLBlitFramebufferProc) eglGetProcAddress("glBlitFramebuffer");
+#endif
+        }
+        if (extensions.has("GL_EXT_multisampled_render_to_texture")) {
+#if GL_EXT_multisampled_render_to_texture
+            interface->fFramebufferTexture2DMultisample = glFramebufferTexture2DMultisampleEXT;
+            interface->fRenderbufferStorageMultisampleES2EXT = glRenderbufferStorageMultisampleEXT;
+#else
+            interface->fFramebufferTexture2DMultisample = (GrGLFramebufferTexture2DMultisampleProc) eglGetProcAddress("glFramebufferTexture2DMultisampleEXT");
+            interface->fRenderbufferStorageMultisampleES2EXT = (GrGLRenderbufferStorageMultisampleProc) eglGetProcAddress("glRenderbufferStorageMultisampleEXT");
+#endif
+        } else if (extensions.has("GL_IMG_multisampled_render_to_texture")) {
+#if GL_IMG_multisampled_render_to_texture
+            interface->fFramebufferTexture2DMultisample = glFramebufferTexture2DMultisampleIMG;
+            interface->fRenderbufferStorageMultisampleES2EXT = glRenderbufferStorageMultisampleIMG;
+#else
+            interface->fFramebufferTexture2DMultisample = (GrGLFramebufferTexture2DMultisampleProc) eglGetProcAddress("glFramebufferTexture2DMultisampleIMG");
+            interface->fRenderbufferStorageMultisampleES2EXT = (GrGLRenderbufferStorageMultisampleProc) eglGetProcAddress("glRenderbufferStorageMultisampleIMG");
+#endif
+        }
+
+#endif // GR_GL_IGNORE_ES3_MSAA
     interface->fGenFramebuffers = glGenFramebuffers;
     interface->fGenRenderbuffers = glGenRenderbuffers;
     interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv;