FBFetch refactor + arm support

BUG=skia:
R=krajcevski@google.com, bsalomon@google.com

Author: joshualitt@chromium.org

Review URL: https://codereview.chromium.org/433603002
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 7dee3de..f128711 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -22,7 +22,6 @@
     fStencilFormats.reset();
     fStencilVerifiedColorConfigs.reset();
     fMSFBOType = kNone_MSFBOType;
-    fFBFetchType = kNone_FBFetchType;
     fInvalidateFBType = kNone_InvalidateFBType;
     fLATCAlias = kLATC_LATCAlias;
     fMapBufferType = kNone_MapBufferType;
@@ -48,6 +47,9 @@
     fIsCoreProfile = false;
     fFullClearIsFree = false;
     fDropsTileOnZeroDivide = false;
+    fFBFetchSupport = false;
+    fFBFetchColorName = NULL;
+    fFBFetchExtensionString = NULL;
 }
 
 GrGLCaps::GrGLCaps(const GrGLCaps& caps) : GrDrawTargetCaps() {
@@ -65,7 +67,6 @@
     fMaxFragmentTextureUnits = caps.fMaxFragmentTextureUnits;
     fMaxFixedFunctionTextureCoords = caps.fMaxFixedFunctionTextureCoords;
     fMSFBOType = caps.fMSFBOType;
-    fFBFetchType = caps.fFBFetchType;
     fInvalidateFBType = caps.fInvalidateFBType;
     fMapBufferType = caps.fMapBufferType;
     fRGBA8RenderbufferSupport = caps.fRGBA8RenderbufferSupport;
@@ -86,6 +87,9 @@
     fIsCoreProfile = caps.fIsCoreProfile;
     fFullClearIsFree = caps.fFullClearIsFree;
     fDropsTileOnZeroDivide = caps.fDropsTileOnZeroDivide;
+    fFBFetchSupport = caps.fFBFetchSupport;
+    fFBFetchColorName = caps.fFBFetchColorName;
+    fFBFetchExtensionString = caps.fFBFetchExtensionString;
 
     return *this;
 }
@@ -233,9 +237,19 @@
 
     if (kGLES_GrGLStandard == standard) {
         if (ctxInfo.hasExtension("GL_EXT_shader_framebuffer_fetch")) {
-            fFBFetchType = kEXT_FBFetchType;
+            fFBFetchSupport = true;
+            fFBFetchColorName = "gl_LastFragData[0]";
+            fFBFetchExtensionString = "GL_EXT_shader_framebuffer_fetch";
         } else if (ctxInfo.hasExtension("GL_NV_shader_framebuffer_fetch")) {
-            fFBFetchType = kNV_FBFetchType;
+            fFBFetchSupport = true;
+            fFBFetchColorName = "gl_LastFragData[0]";
+            fFBFetchExtensionString = "GL_NV_shader_framebuffer_fetch";
+        } else if (ctxInfo.hasExtension("GL_ARM_shader_framebuffer_fetch")) {
+            // The arm extension also requires an additional flag which we will set onResetContext
+            // This is all temporary.
+            fFBFetchSupport = true;
+            fFBFetchColorName = "gl_LastFragColorARM";
+            fFBFetchExtensionString = "GL_ARM_shader_framebuffer_fetch";
         }
     }
 
@@ -335,7 +349,8 @@
 
     fGpuTracingSupport = ctxInfo.hasExtension("GL_EXT_debug_marker");
 
-    fDstReadInShaderSupport = kNone_FBFetchType != fFBFetchType;
+    // For now these two are equivalent but we could have dst read in shader via some other method
+    fDstReadInShaderSupport = fFBFetchSupport;
 
     // Disable scratch texture reuse on Mali and Adreno devices
     fReuseScratchTextures = kARM_GrGLVendor != ctxInfo.vendor() &&
@@ -777,16 +792,6 @@
     GR_STATIC_ASSERT(6 == kES_EXT_MsToTexture_MSFBOType);
     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kMSFBOExtStr) == kLast_MSFBOType + 1);
 
-    static const char* kFBFetchTypeStr[] = {
-        "None",
-        "EXT",
-        "NV",
-    };
-    GR_STATIC_ASSERT(0 == kNone_FBFetchType);
-    GR_STATIC_ASSERT(1 == kEXT_FBFetchType);
-    GR_STATIC_ASSERT(2 == kNV_FBFetchType);
-    GR_STATIC_ASSERT(SK_ARRAY_COUNT(kFBFetchTypeStr) == kLast_FBFetchType + 1);
-
     static const char* kInvalidateFBTypeStr[] = {
         "None",
         "Discard",
@@ -811,7 +816,7 @@
 
     r.appendf("Core Profile: %s\n", (fIsCoreProfile ? "YES" : "NO"));
     r.appendf("MSAA Type: %s\n", kMSFBOExtStr[fMSFBOType]);
-    r.appendf("FB Fetch Type: %s\n", kFBFetchTypeStr[fFBFetchType]);
+    r.appendf("FB Fetch Support: %s\n", (fFBFetchSupport ? "YES" : "NO"));
     r.appendf("Invalidate FB Type: %s\n", kInvalidateFBTypeStr[fInvalidateFBType]);
     r.appendf("Map Buffer Type: %s\n", kMapBufferTypeStr[fMapBufferType]);
     r.appendf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors);
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index ccf04fd..887e2e9 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -68,16 +68,6 @@
         kLast_MSFBOType = kES_EXT_MsToTexture_MSFBOType
     };
 
-    enum FBFetchType {
-        kNone_FBFetchType,
-        /** GL_EXT_shader_framebuffer_fetch */
-        kEXT_FBFetchType,
-        /** GL_NV_shader_framebuffer_fetch */
-        kNV_FBFetchType,
-
-        kLast_FBFetchType = kNV_FBFetchType
-    };
-
     enum InvalidateFBType {
         kNone_InvalidateFBType,
         kDiscard_InvalidateFBType,       //<! glDiscardFramebuffer()
@@ -174,7 +164,16 @@
                kES_EXT_MsToTexture_MSFBOType == fMSFBOType;
     }
 
-    FBFetchType fbFetchType() const { return fFBFetchType; }
+    /**
+     * Some helper functions for encapsulating various extensions to read FB Buffer on openglES
+     *
+     * TODO On desktop opengl 4.2+ we can achieve something similar to this effect
+     */
+    bool fbFetchSupport() const { return fFBFetchSupport; }
+
+    const char* fbFetchColorName() const { return fFBFetchColorName; }
+
+    const char* fbFetchExtensionString() const { return fFBFetchExtensionString; }
 
     InvalidateFBType invalidateFBType() const { return fInvalidateFBType; }
 
@@ -340,7 +339,6 @@
     int fMaxFixedFunctionTextureCoords;
 
     MSFBOType           fMSFBOType;
-    FBFetchType         fFBFetchType;
     InvalidateFBType    fInvalidateFBType;
     MapBufferType       fMapBufferType;
     LATCAlias           fLATCAlias;
@@ -363,6 +361,10 @@
     bool fIsCoreProfile : 1;
     bool fFullClearIsFree : 1;
     bool fDropsTileOnZeroDivide : 1;
+    bool fFBFetchSupport : 1;
+
+    const char* fFBFetchColorName;
+    const char* fFBFetchExtensionString;
 
     typedef GrDrawTargetCaps INHERITED;
 };
diff --git a/src/gpu/gl/GrGLDefines.h b/src/gpu/gl/GrGLDefines.h
index 77b7a15..06dd99d 100644
--- a/src/gpu/gl/GrGLDefines.h
+++ b/src/gpu/gl/GrGLDefines.h
@@ -900,4 +900,8 @@
 // shader stage of <program> (if a fragment stage exists).
 #define GR_GL_FRAGMENT_INPUT                                0x936D
 
+/*  ARM specific define for MSAA support on framebuffer fetch */
+#define GR_GL_FETCH_PER_SAMPLE_ARM                          0x8F65
+
+
 #endif
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 561acd5..d6679dc 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -114,8 +114,7 @@
 
     ///////////////////////////////////////////////////////////////////////////
     // emit code to read the dst copy texture, if necessary
-    if (kNoDstRead_DstReadKey != header.fDstReadKey &&
-        GrGLCaps::kNone_FBFetchType == fGpu->glCaps().fbFetchType()) {
+    if (kNoDstRead_DstReadKey != header.fDstReadKey && !fGpu->glCaps().fbFetchSupport()) {
         bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey);
         const char* dstCopyTopLeftName;
         const char* dstCopyCoordScaleName;
@@ -280,37 +279,6 @@
     }
 }
 
-bool GrGLShaderBuilder::enablePrivateFeature(GLSLPrivateFeature feature) {
-    switch (feature) {
-        case kFragCoordConventions_GLSLPrivateFeature:
-            if (!fGpu->glCaps().fragCoordConventionsSupport()) {
-                return false;
-            }
-            if (fGpu->glslGeneration() < k150_GrGLSLGeneration) {
-                this->addFSFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
-                                   "GL_ARB_fragment_coord_conventions");
-            }
-            return true;
-        case kEXTShaderFramebufferFetch_GLSLPrivateFeature:
-            if (GrGLCaps::kEXT_FBFetchType != fGpu->glCaps().fbFetchType()) {
-                return false;
-            }
-            this->addFSFeature(1 << kEXTShaderFramebufferFetch_GLSLPrivateFeature,
-                               "GL_EXT_shader_framebuffer_fetch");
-            return true;
-        case kNVShaderFramebufferFetch_GLSLPrivateFeature:
-            if (GrGLCaps::kNV_FBFetchType != fGpu->glCaps().fbFetchType()) {
-                return false;
-            }
-            this->addFSFeature(1 << kNVShaderFramebufferFetch_GLSLPrivateFeature,
-                               "GL_NV_shader_framebuffer_fetch");
-            return true;
-        default:
-            SkFAIL("Unexpected GLSLPrivateFeature requested.");
-            return false;
-    }
-}
-
 void GrGLShaderBuilder::addFSFeature(uint32_t featureBit, const char* extensionName) {
     if (!(featureBit & fFSFeaturesAddedMask)) {
         fFSExtensions.appendf("#extension %s: require\n", extensionName);
@@ -342,14 +310,11 @@
             return "";
         }
     }
-    static const char kFBFetchColorName[] = "gl_LastFragData[0]";
-    GrGLCaps::FBFetchType fetchType = fGpu->glCaps().fbFetchType();
-    if (GrGLCaps::kEXT_FBFetchType == fetchType) {
-        SkAssertResult(this->enablePrivateFeature(kEXTShaderFramebufferFetch_GLSLPrivateFeature));
-        return kFBFetchColorName;
-    } else if (GrGLCaps::kNV_FBFetchType == fetchType) {
-        SkAssertResult(this->enablePrivateFeature(kNVShaderFramebufferFetch_GLSLPrivateFeature));
-        return kFBFetchColorName;
+
+    if (fGpu->glCaps().fbFetchSupport()) {
+        this->addFSFeature(1 << (kLastGLSLPrivateFeature + 1),
+                           fGpu->glCaps().fbFetchExtensionString());
+        return fGpu->glCaps().fbFetchColorName();
     } else if (fOutput.fUniformHandles.fDstCopySamplerUni.isValid()) {
         return kDstCopyColorName;
     } else {
@@ -389,7 +354,7 @@
 GrGLShaderBuilder::DstReadKey GrGLShaderBuilder::KeyForDstRead(const GrTexture* dstCopy,
                                                                const GrGLCaps& caps) {
     uint32_t key = kYesDstRead_DstReadKeyBit;
-    if (GrGLCaps::kNone_FBFetchType != caps.fbFetchType()) {
+    if (caps.fbFetchSupport()) {
         return key;
     }
     SkASSERT(NULL != dstCopy);
@@ -500,7 +465,10 @@
         return "gl_FragCoord";
     } else if (fGpu->glCaps().fragCoordConventionsSupport()) {
         if (!fSetupFragPosition) {
-            SkAssertResult(this->enablePrivateFeature(kFragCoordConventions_GLSLPrivateFeature));
+            if (fGpu->glslGeneration() < k150_GrGLSLGeneration) {
+                this->addFSFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
+                                   "GL_ARB_fragment_coord_conventions");
+            }
             fFSInputs.push_back().set(kVec4f_GrSLType,
                                       GrGLShaderVar::kIn_TypeModifier,
                                       "gl_FragCoord",
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 15e9ad8..9b74b47 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -371,8 +371,7 @@
      */
     enum GLSLPrivateFeature {
         kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1,
-        kEXTShaderFramebufferFetch_GLSLPrivateFeature,
-        kNVShaderFramebufferFetch_GLSLPrivateFeature,
+        kLastGLSLPrivateFeature = kFragCoordConventions_GLSLPrivateFeature
     };
     bool enablePrivateFeature(GLSLPrivateFeature);
 
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 404e7ab..8982785 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -275,6 +275,13 @@
             // currently part of our gl interface. There are probably others as
             // well.
         }
+
+        if (kGLES_GrGLStandard == this->glStandard() &&
+                fGLContext.hasExtension("GL_ARM_shader_framebuffer_fetch")) {
+            // The arm extension requires specifically enabling MSAA fetching per sample.
+            // On some devices this may have a perf hit.  Also multiple render targets are disabled
+            GL_CALL(Enable(GR_GL_FETCH_PER_SAMPLE_ARM));
+        }
         fHWWriteToColor = kUnknown_TriState;
         // we only ever use lines in hairline mode
         GL_CALL(LineWidth(1));
@@ -1490,7 +1497,7 @@
         GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, glRT->renderFBOID()));
     }
     switch (this->glCaps().invalidateFBType()) {
-        case GrGLCaps::kNone_FBFetchType:
+        case GrGLCaps::kNone_InvalidateFBType:
             SkFAIL("Should never get here.");
             break;
         case GrGLCaps::kInvalidate_InvalidateFBType: