Add support for IMG's MSAA extension.
Review URL: https://codereview.chromium.org/12875005

git-svn-id: http://skia.googlecode.com/svn/trunk@8241 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 04c2c3c..a115b5d 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -251,6 +251,8 @@
            fMSFBOType = kDesktopEXT_MSFBOType;
        } else if (ctxInfo.hasExtension("GL_APPLE_framebuffer_multisample")) {
            fMSFBOType = kAppleES_MSFBOType;
+       } else if (ctxInfo.hasExtension("GL_IMG_multisampled_render_to_texture")) {
+           fMSFBOType = kImaginationES_MSFBOType;
        }
     } else {
         if ((ctxInfo.version() >= GR_GL_VER(3,0)) ||
@@ -420,11 +422,13 @@
     GR_STATIC_ASSERT(1 == kDesktopARB_MSFBOType);
     GR_STATIC_ASSERT(2 == kDesktopEXT_MSFBOType);
     GR_STATIC_ASSERT(3 == kAppleES_MSFBOType);
+    GR_STATIC_ASSERT(4 == kImaginationES_MSFBOType);
     static const char* gMSFBOExtStr[] = {
         "None",
         "ARB",
         "EXT",
         "Apple",
+        "IMG",
     };
     GrPrintf("MSAA Type: %s\n", gMSFBOExtStr[fMSFBOType]);
     GrPrintf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors);
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 2ecfb85..83f4650 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -62,6 +62,10 @@
          * GL_APPLE_framebuffer_multisample ES extension
          */
         kAppleES_MSFBOType,
+        /**
+         * GL_IMG_multisampled_render_to_texture
+         */
+        kImaginationES_MSFBOType,
     };
 
     enum CoverageAAType {
diff --git a/src/gpu/gl/GrGLDefines.h b/src/gpu/gl/GrGLDefines.h
index e0e8398..2ab9570 100644
--- a/src/gpu/gl/GrGLDefines.h
+++ b/src/gpu/gl/GrGLDefines.h
@@ -658,6 +658,8 @@
 #define GR_GL_DEPTH24_STENCIL8               0x88F0
 
 #define GR_GL_MAX_SAMPLES                    0x8D57
+// GL_IMG_multisampled_render_to_texture uses a different value for GL_MAX_SAMPLES
+#define GR_GL_MAX_SAMPLES_IMG                0x9135
 
 #define GR_GL_RENDERBUFFER_WIDTH             0x8D42
 #define GR_GL_RENDERBUFFER_HEIGHT            0x8D43
diff --git a/src/gpu/gl/GrGLInterface.cpp b/src/gpu/gl/GrGLInterface.cpp
index 0119a1e..0c6bd86 100644
--- a/src/gpu/gl/GrGLInterface.cpp
+++ b/src/gpu/gl/GrGLInterface.cpp
@@ -323,6 +323,12 @@
                 return false;
             }
         }
+        if (extensions.has("GL_IMG_multisampled_render_to_texture")) {
+            if (NULL == fRenderbufferStorageMultisample ||
+                NULL == fFramebufferTexture2DMultisample) {
+                return false;
+            }
+        }
     }
 
     // On ES buffer mapping is an extension. On Desktop
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 8882934..e202a14 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -285,11 +285,12 @@
         caps->fGeometryShaderSupport = this->glVersion() >= GR_GL_VER(3,2) &&
                                        this->glslGeneration() >= k150_GrGLSLGeneration;
     } else {
-        caps->fShaderDerivativeSupport =
-                            this->hasExtension("GL_OES_standard_derivatives");
+        caps->fShaderDerivativeSupport = this->hasExtension("GL_OES_standard_derivatives");
     }
 
-    if (GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType()) {
+    if (GrGLCaps::kImaginationES_MSFBOType == this->glCaps().msFBOType()) {
+        GR_GL_GetIntegerv(this->glInterface(), GR_GL_MAX_SAMPLES_IMG, &caps->fMaxSampleCount);
+    } else if (GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType()) {
         GR_GL_GetIntegerv(this->glInterface(), GR_GL_MAX_SAMPLES, &caps->fMaxSampleCount);
     }
 }
@@ -879,9 +880,11 @@
     }
 
 
-    // If we are using multisampling we will create two FBOS. We render
-    // to one and then resolve to the texture bound to the other.
-    if (desc->fSampleCnt > 0) {
+    // If we are using multisampling we will create two FBOS. We render to one and then resolve to
+    // the texture bound to the other. The exception is the IMG multisample extension. With this
+    // extension the texture is multisampled when rendered to and then auto-resolves it when it is
+    // rendered from.
+    if (desc->fSampleCnt > 0 && GrGLCaps::kImaginationES_MSFBOType != this->glCaps().msFBOType()) {
         if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) {
             goto FAILED;
         }
@@ -921,16 +924,22 @@
             if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
                 goto FAILED;
             }
-            fGLContext.info().caps().markConfigAsValidColorAttachment(
-                                                                desc->fConfig);
+            fGLContext.info().caps().markConfigAsValidColorAttachment(desc->fConfig);
         }
     }
     GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fTexFBOID));
 
-    GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
-                                 GR_GL_COLOR_ATTACHMENT0,
-                                 GR_GL_TEXTURE_2D,
-                                 texID, 0));
+    if (GrGLCaps::kImaginationES_MSFBOType == this->glCaps().msFBOType() && desc->fSampleCnt > 0) {
+        GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER,
+                                                GR_GL_COLOR_ATTACHMENT0,
+                                                GR_GL_TEXTURE_2D,
+                                                texID, 0, desc->fSampleCnt));
+    } else {
+        GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
+                                     GR_GL_COLOR_ATTACHMENT0,
+                                     GR_GL_TEXTURE_2D,
+                                     texID, 0));
+    }
     if (!this->glCaps().isConfigVerifiedColorAttachment(desc->fConfig)) {
         GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
         if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
@@ -1172,8 +1181,7 @@
     return false;
 }
 
-bool GrGpuGL::attachStencilBufferToRenderTarget(GrStencilBuffer* sb,
-                                                GrRenderTarget* rt) {
+bool GrGpuGL::attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTarget* rt) {
     GrGLRenderTarget* glrt = (GrGLRenderTarget*) rt;
 
     GrGLuint fbo = glrt->renderFBOID();
@@ -1181,11 +1189,11 @@
     if (NULL == sb) {
         if (NULL != rt->getStencilBuffer()) {
             GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                          GR_GL_STENCIL_ATTACHMENT,
-                                          GR_GL_RENDERBUFFER, 0));
+                                            GR_GL_STENCIL_ATTACHMENT,
+                                            GR_GL_RENDERBUFFER, 0));
             GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                          GR_GL_DEPTH_ATTACHMENT,
-                                          GR_GL_RENDERBUFFER, 0));
+                                            GR_GL_DEPTH_ATTACHMENT,
+                                            GR_GL_RENDERBUFFER, 0));
 #if GR_DEBUG
             GrGLenum status;
             GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
@@ -1194,27 +1202,26 @@
         }
         return true;
     } else {
-        GrGLStencilBuffer* glsb = (GrGLStencilBuffer*) sb;
+        GrGLStencilBuffer* glsb = static_cast<GrGLStencilBuffer*>(sb);
         GrGLuint rb = glsb->renderbufferID();
 
         fHWBoundRenderTarget = NULL;
         GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo));
         GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                      GR_GL_STENCIL_ATTACHMENT,
-                                      GR_GL_RENDERBUFFER, rb));
+                                        GR_GL_STENCIL_ATTACHMENT,
+                                        GR_GL_RENDERBUFFER, rb));
         if (glsb->format().fPacked) {
             GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                          GR_GL_DEPTH_ATTACHMENT,
-                                          GR_GL_RENDERBUFFER, rb));
+                                            GR_GL_DEPTH_ATTACHMENT,
+                                            GR_GL_RENDERBUFFER, rb));
         } else {
             GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                          GR_GL_DEPTH_ATTACHMENT,
-                                          GR_GL_RENDERBUFFER, 0));
+                                            GR_GL_DEPTH_ATTACHMENT,
+                                            GR_GL_RENDERBUFFER, 0));
         }
 
         GrGLenum status;
-        if (!this->glCaps().isColorConfigAndStencilFormatVerified(rt->config(),
-                                                           glsb->format())) {
+        if (!this->glCaps().isColorConfigAndStencilFormatVerified(rt->config(), glsb->format())) {
             GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
             if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
                 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
@@ -1767,47 +1774,45 @@
 }
 
 void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) {
-
     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target);
-
     if (rt->needsResolve()) {
-        GrAssert(GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType());
-        GrAssert(rt->textureFBOID() != rt->renderFBOID());
-        GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER,
-                                rt->renderFBOID()));
-        GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER,
-                                rt->textureFBOID()));
-        // make sure we go through flushRenderTarget() since we've modified
-        // the bound DRAW FBO ID.
-        fHWBoundRenderTarget = NULL;
-        const GrGLIRect& vp = rt->getViewport();
-        const GrIRect dirtyRect = rt->getResolveRect();
-        GrGLIRect r;
-        r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop,
-                        dirtyRect.width(), dirtyRect.height(), target->origin());
+        // The IMG extension automatically resolves the texture when it is read.
+        if (GrGLCaps::kImaginationES_MSFBOType != this->glCaps().msFBOType()) {
+            GrAssert(GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType());
+            GrAssert(rt->textureFBOID() != rt->renderFBOID());
+            GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, rt->renderFBOID()));
+            GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->textureFBOID()));
+            // make sure we go through flushRenderTarget() since we've modified
+            // the bound DRAW FBO ID.
+            fHWBoundRenderTarget = NULL;
+            const GrGLIRect& vp = rt->getViewport();
+            const GrIRect dirtyRect = rt->getResolveRect();
+            GrGLIRect r;
+            r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop,
+                            dirtyRect.width(), dirtyRect.height(), target->origin());
 
-        GrAutoTRestore<ScissorState> asr;
-        if (GrGLCaps::kAppleES_MSFBOType == this->glCaps().msFBOType()) {
-            // Apple's extension uses the scissor as the blit bounds.
-            asr.reset(&fScissorState);
-            fScissorState.fEnabled = true;
-            fScissorState.fRect = dirtyRect;
-            this->flushScissor();
-            GL_CALL(ResolveMultisampleFramebuffer());
-        } else {
-            if (GrGLCaps::kDesktopARB_MSFBOType != this->glCaps().msFBOType()) {
-                // this respects the scissor during the blit, so disable it.
-                GrAssert(GrGLCaps::kDesktopEXT_MSFBOType ==
-                         this->glCaps().msFBOType());
+            GrAutoTRestore<ScissorState> asr;
+            if (GrGLCaps::kAppleES_MSFBOType == this->glCaps().msFBOType()) {
+                // Apple's extension uses the scissor as the blit bounds.
                 asr.reset(&fScissorState);
-                fScissorState.fEnabled = false;
+                fScissorState.fEnabled = true;
+                fScissorState.fRect = dirtyRect;
                 this->flushScissor();
+                GL_CALL(ResolveMultisampleFramebuffer());
+            } else {
+                if (GrGLCaps::kDesktopARB_MSFBOType != this->glCaps().msFBOType()) {
+                    // this respects the scissor during the blit, so disable it.
+                    GrAssert(GrGLCaps::kDesktopEXT_MSFBOType == this->glCaps().msFBOType());
+                    asr.reset(&fScissorState);
+                    fScissorState.fEnabled = false;
+                    this->flushScissor();
+                }
+                int right = r.fLeft + r.fWidth;
+                int top = r.fBottom + r.fHeight;
+                GL_CALL(BlitFramebuffer(r.fLeft, r.fBottom, right, top,
+                                        r.fLeft, r.fBottom, right, top,
+                                        GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
             }
-            int right = r.fLeft + r.fWidth;
-            int top = r.fBottom + r.fHeight;
-            GL_CALL(BlitFramebuffer(r.fLeft, r.fBottom, right, top,
-                                    r.fLeft, r.fBottom, right, top,
-                                    GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
         }
         rt->flagAsResolved();
     }
diff --git a/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp b/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp
index 6fa9053..6f81cab 100644
--- a/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp
+++ b/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp
@@ -124,6 +124,10 @@
         interface->fDeleteRenderbuffers = glDeleteRenderbuffers;
         interface->fFramebufferRenderbuffer = glFramebufferRenderbuffer;
         interface->fFramebufferTexture2D = glFramebufferTexture2D;
+#if GL_IMG_multisampled_render_to_texture
+        interface->fFramebufferTexture2DMultisample = glFramebufferTexture2DMultisampleIMG;
+        interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisampleIMG;
+#endif
         interface->fGenFramebuffers = glGenFramebuffers;
         interface->fGenRenderbuffers = glGenRenderbuffers;
         interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv;