Add support for ES3 MSAA.
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 5 Sep 2013 23:44:09 +0000 (23:44 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 5 Sep 2013 23:44:09 +0000 (23:44 +0000)
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@11124 2bbb7eff-a529-9590-31e7-b0007b416f81

include/gpu/gl/GrGLConfig.h
include/gpu/gl/GrGLConfig_chrome.h
include/gpu/gl/GrGLInterface.h
src/gpu/gl/GrGLCaps.cpp
src/gpu/gl/GrGLCaps.h
src/gpu/gl/GrGLInterface.cpp
src/gpu/gl/GrGpuGL.cpp
src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp

index 1f7c9e29f5ec160ce67d16316a5f9d6e64c57bfd..0da2c0bf2c6fcb09d179311681127f3f06793c04 100644 (file)
     #define GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE       0
 #endif
 
+// We now have a separate GrGLInterface function pointer entry for the IMG/EXT version of
+// glRenderbufferStorageMultisampled. However, Chrome is setting the one we now use for
+// ES3 MSAA to point to the IMG/EXT function. This macro exists to make Skia ignore the
+// ES3 MSAA and instead use the IMG/EXT version with the old function pointer entry. It will
+// be removed as soon as Chrome is updated to set the new function pointer.
+#if !defined(GR_GL_IGNORE_ES3_MSAA)
+    #define GR_GL_IGNORE_ES3_MSAA 0
+#endif
+
 /**
  * There is a strange bug that occurs on Macs with NVIDIA GPUs. We don't
  * fully understand it. When (element) array buffers are continually
index e08692fb61f9a2b1f67ae7283e30e90988b2c9e4..fe3578339c8b00d0b3bce7aff96e0c7aa4350414 100644 (file)
@@ -41,4 +41,8 @@
 // (const char* const instead of char**).
 #define GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE       1
 
+#if !defined(GR_GL_IGNORE_ES3_MSAA)
+    #define GR_GL_IGNORE_ES3_MSAA 1
+#endif
+
 #endif
index 67d6840e423e4dab45213040e243057cf450dff6..de1b29143faa58daa9b85127a47ff8e246797f58 100644 (file)
@@ -229,7 +229,31 @@ public:
     GLPtr<GrGLReadBufferProc> fReadBuffer;
     GLPtr<GrGLReadPixelsProc> fReadPixels;
     GLPtr<GrGLRenderbufferStorageProc> fRenderbufferStorage;
+
+#if !GR_GL_IGNORE_ES3_MSAA
+    //  On OpenGL ES there are multiple incompatible extensions that add support for MSAA
+    //  and ES3 adds MSAA support to the standard. On an ES3 driver we may still use the
+    //  older extensions for performance reasons or due to ES3 driver bugs. We want the function
+    //  that creates the GrGLInterface to provide all available functions and internally
+    //  we will select among them. They all have a method called glRenderbufferStorageMultisample*.
+    //  So we have separate function pointers for GL_IMG/EXT_multisampled_to_texture,
+    //  GL_CHROMIUM/ANGLE_framebuffer_multisample/ES3, and GL_APPLE_framebuffer_multisample
+    //  variations.
+    //
+    //  If a driver supports multiple GL_ARB_framebuffer_multisample-style extensions then we will
+    //  assume the function pointers for the standard (or equivalent GL_ARB) version have
+    //  been preferred over GL_EXT, GL_CHROMIUM, or GL_ANGLE variations that have reduced
+    //  functionality.
+
+    //  GL_EXT_multisampled_render_to_texture (preferred) or GL_IMG_multisampled_render_to_texture
+    GLPtr<GrGLRenderbufferStorageMultisampleProc> fRenderbufferStorageMultisampleES2EXT;
+    //  GL_APPLE_framebuffer_multisample
+    GLPtr<GrGLRenderbufferStorageMultisampleProc> fRenderbufferStorageMultisampleES2APPLE;
+#endif
+    //  This is used to store the pointer for GL_ARB/EXT/ANGLE/CHROMIUM_framebuffer_multisample or
+    //  the standard function in ES3+ or GL 3.0+.
     GLPtr<GrGLRenderbufferStorageMultisampleProc> fRenderbufferStorageMultisample;
+
     GLPtr<GrGLRenderbufferStorageMultisampleCoverageProc> fRenderbufferStorageMultisampleCoverage;
     GLPtr<GrGLResolveMultisampleFramebufferProc> fResolveMultisampleFramebuffer;
     GLPtr<GrGLScissorProc> fScissor;
index 382bfba68daf67831f9f120be0c358e5b2f0a54b..1488e75c293c4af9f1f8032ad9d75e6bb0d65157 100644 (file)
@@ -386,17 +386,21 @@ void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterfa
 
     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 @@ void GrGLCaps::print() const {
         "None",
         "ARB",
         "EXT",
+        "ES 3.0",
         "Apple",
         "IMG MS To Texture",
         "EXT MS To Texture",
@@ -576,9 +581,10 @@ void GrGLCaps::print() const {
     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[] = {
index a4d567351e635166b8668dd9d251656f6530c025..a05d2b6faa33d6ecdc638818df8288c724b612b1 100644 (file)
@@ -54,13 +54,17 @@ public:
          */
         kNone_MSFBOType = 0,
         /**
-         * GL3.0-style MSAA FBO (GL_ARB_framebuffer_object)
+         * GL3.0-style MSAA FBO (GL_ARB_framebuffer_object)
          */
         kDesktop_ARB_MSFBOType,
         /**
          * earlier GL_EXT_framebuffer* extensions
          */
         kDesktop_EXT_MSFBOType,
+        /**
+         * Similar to kDesktop_ARB but with additional restrictions on glBlitFramebuffer.
+         */
+        kES_3_0_MSFBOType,
         /**
          * GL_APPLE_framebuffer_multisample ES extension
          */
index d15b4cc48bf5530672d49a9b3c3a51243aa46d12..7e557da4f5f98853ccf7a1ac5f7b269ef10c9894 100644 (file)
@@ -336,25 +336,45 @@ bool GrGLInterface::validate(GrGLBinding binding) const {
             }
         }
     } 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;
+            }
         }
-        if (extensions.has("GL_APPLE_framebuffer_multisample")) {
+#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 == 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
index a9fd41ed5ad95a1fe252c49515b92c4184e2c865..75b41913663bedfa932ca498a2e661dd6392beb0 100644 (file)
@@ -789,11 +789,43 @@ bool renderbuffer_storage_msaa(GrGLContext& ctx,
         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 @@ inline bool can_blit_framebuffer(const GrSurface* dst,
     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();
         }
index 881a46b476a4b884e5a8b1c1835cf20f537740d0..5e5411e54efb4a767d1d3774ed9670cf534cf2e0 100644 (file)
@@ -147,6 +147,8 @@ static const GrGLInterface* create_es_interface(GrGLVersion version,
     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 @@ static const GrGLInterface* create_es_interface(GrGLVersion version,
         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;