Add detection of image load/store to caps

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4861

Change-Id: Ibf70cce9f61553e830b62339551c1541dc054e8b
Reviewed-on: https://skia-review.googlesource.com/4861
Reviewed-by: Chris Dalton <csmartdalton@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h
index 204cfc9..c44f6c1 100644
--- a/include/gpu/GrCaps.h
+++ b/include/gpu/GrCaps.h
@@ -64,6 +64,7 @@
     bool dualSourceBlendingSupport() const { return fDualSourceBlendingSupport; }
     bool integerSupport() const { return fIntegerSupport; }
     bool texelBufferSupport() const { return fTexelBufferSupport; }
+    int imageLoadStoreSupport() const { return fImageLoadStoreSupport; }
 
     /**
     * Get the precision info for a variable of type kFloat_GrSLType, kVec2f_GrSLType, etc in a
@@ -106,18 +107,18 @@
         the client. Note that overrides will only reduce the caps never expand them. */
     void applyOptionsOverrides(const GrContextOptions& options);
 
-    bool fShaderDerivativeSupport : 1;
-    bool fGeometryShaderSupport : 1;
-    bool fPathRenderingSupport : 1;
-    bool fDstReadInShaderSupport : 1;
+    bool fShaderDerivativeSupport   : 1;
+    bool fGeometryShaderSupport     : 1;
+    bool fPathRenderingSupport      : 1;
+    bool fDstReadInShaderSupport    : 1;
     bool fDualSourceBlendingSupport : 1;
-    bool fIntegerSupport : 1;
-    bool fTexelBufferSupport : 1;
-
-    bool fShaderPrecisionVaries;
+    bool fIntegerSupport            : 1;
+    bool fTexelBufferSupport        : 1;
+    bool fImageLoadStoreSupport     : 1;
+    bool fPLSPathRenderingSupport   : 1;
+    bool fShaderPrecisionVaries     : 1;
     PrecisionInfo fFloatPrecisions[kGrShaderTypeCount][kGrSLPrecisionCount];
     int fPixelLocalStorageSize;
-    bool fPLSPathRenderingSupport;
 
 private:
     virtual void onApplyOptionsOverrides(const GrContextOptions&) {}
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp
index a41be0e..7b09214 100644
--- a/src/gpu/GrCaps.cpp
+++ b/src/gpu/GrCaps.cpp
@@ -17,7 +17,10 @@
     fDualSourceBlendingSupport = false;
     fIntegerSupport = false;
     fTexelBufferSupport = false;
+    fImageLoadStoreSupport = false;
     fShaderPrecisionVaries = false;
+    fPLSPathRenderingSupport = false;
+    fPixelLocalStorageSize = 0;
 }
 
 static const char* shader_type_to_string(GrShaderType type) {
@@ -54,6 +57,7 @@
     r.appendf("Dual Source Blending Support       : %s\n", gNY[fDualSourceBlendingSupport]);
     r.appendf("Integer Support                    : %s\n", gNY[fIntegerSupport]);
     r.appendf("Texel Buffer Support               : %s\n", gNY[fTexelBufferSupport]);
+    r.appendf("Image Load Store Support           : %s\n", gNY[fImageLoadStoreSupport]);
 
     r.appendf("Shader Float Precisions (varies: %s):\n", gNY[fShaderPrecisionVaries]);
 
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index d1c1162..5d943c7 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -309,6 +309,33 @@
     GR_GL_GetIntegerv(gli, GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxSamplers);
     glslCaps->fMaxCombinedSamplers = SkTMin<GrGLint>(kMaxSaneSamplers, maxSamplers);
 
+    if (kGL_GrGLStandard == standard) {
+        glslCaps->fImageLoadStoreSupport = ctxInfo.version() >= GR_GL_VER(4, 2);
+        if (!glslCaps->fImageLoadStoreSupport &&
+            ctxInfo.hasExtension("GL_ARB_shader_image_load_store")) {
+            glslCaps->fImageLoadStoreSupport = true;
+            glslCaps->fImageLoadStoreExtensionString = "GL_ARB_shader_image_load_store";
+        }
+    } else {
+        glslCaps->fImageLoadStoreSupport = ctxInfo.version() >= GR_GL_VER(3, 1);
+    }
+    if (glslCaps->fImageLoadStoreSupport) {
+        // Protect ourselves against tracking huge amounts of image state.
+        static constexpr int kMaxSaneImages = 4;
+        GrGLint maxUnits;
+        GR_GL_GetIntegerv(gli, GR_GL_MAX_IMAGE_UNITS, &maxUnits);
+        GR_GL_GetIntegerv(gli, GR_GL_MAX_VERTEX_IMAGE_UNIFORMS, &glslCaps->fMaxVertexImages);
+        GR_GL_GetIntegerv(gli, GR_GL_MAX_GEOMETRY_IMAGE_UNIFORMS, &glslCaps->fMaxGeometryImages);
+        GR_GL_GetIntegerv(gli, GR_GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &glslCaps->fMaxFragmentImages);
+        GR_GL_GetIntegerv(gli, GR_GL_MAX_COMBINED_IMAGE_UNIFORMS, &glslCaps->fMaxCombinedImages);
+        // We use one unit for every image uniform
+        glslCaps->fMaxCombinedImages = SkTMin(SkTMin(glslCaps->fMaxCombinedImages, maxUnits),
+                                                     kMaxSaneImages);
+        glslCaps->fMaxVertexImages = SkTMin(maxUnits, glslCaps->fMaxVertexImages);
+        glslCaps->fMaxGeometryImages = SkTMin(maxUnits, glslCaps->fMaxGeometryImages);
+        glslCaps->fMaxFragmentImages =  SkTMin(maxUnits, glslCaps->fMaxFragmentImages);
+    }
+
     /**************************************************************************
      * GrCaps fields
      **************************************************************************/
diff --git a/src/gpu/glsl/GrGLSLCaps.cpp b/src/gpu/glsl/GrGLSLCaps.cpp
index 8e464b0..5bb22b3 100644
--- a/src/gpu/glsl/GrGLSLCaps.cpp
+++ b/src/gpu/glsl/GrGLSLCaps.cpp
@@ -42,10 +42,15 @@
     fSampleVariablesExtensionString = nullptr;
     fFBFetchColorName = nullptr;
     fFBFetchExtensionString = nullptr;
+    fImageLoadStoreExtensionString = nullptr;
     fMaxVertexSamplers = 0;
     fMaxGeometrySamplers = 0;
     fMaxFragmentSamplers = 0;
     fMaxCombinedSamplers = 0;
+    fMaxVertexImages = 0;
+    fMaxGeometryImages = 0;
+    fMaxFragmentImages = 0;
+    fMaxCombinedImages   = 0;
     fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
 }
 
@@ -90,6 +95,10 @@
     r.appendf("Max GS Samplers: %d\n", fMaxGeometrySamplers);
     r.appendf("Max FS Samplers: %d\n", fMaxFragmentSamplers);
     r.appendf("Max Combined Samplers: %d\n", fMaxFragmentSamplers);
+    r.appendf("Max VS Images: %d\n", fMaxVertexImages);
+    r.appendf("Max GS Images: %d\n", fMaxGeometryImages);
+    r.appendf("Max FS Images: %d\n", fMaxFragmentImages);
+    r.appendf("Max Combined Images: %d\n", fMaxFragmentImages);
     r.appendf("Advanced blend equation interaction: %s\n",
               kAdvBlendEqInteractionStr[fAdvBlendEqInteraction]);
     return r;
diff --git a/src/gpu/glsl/GrGLSLCaps.h b/src/gpu/glsl/GrGLSLCaps.h
index 137c9b7..4c53ad0 100644
--- a/src/gpu/glsl/GrGLSLCaps.h
+++ b/src/gpu/glsl/GrGLSLCaps.h
@@ -144,6 +144,11 @@
         return fSampleVariablesExtensionString;
     }
 
+    const char* imageLoadStoreExtensionString() const {
+        SkASSERT(this->imageLoadStoreSupport());
+        return fImageLoadStoreExtensionString;
+    }
+
     int maxVertexSamplers() const { return fMaxVertexSamplers; }
 
     int maxGeometrySamplers() const { return fMaxGeometrySamplers; }
@@ -152,6 +157,14 @@
 
     int maxCombinedSamplers() const { return fMaxCombinedSamplers; }
 
+    int maxVertexImages() const { return fMaxVertexImages; }
+
+    int maxGeometryImages() const { return fMaxGeometryImages; }
+
+    int maxFragmentImages() const { return fMaxFragmentImages; }
+
+    int maxCombinedImages() const { return fMaxCombinedImages; }
+
     /**
      * Given a texture's config, this determines what swizzle must be appended to accesses to the
      * texture in generated shader code. Swizzling may be implemented in texture parameters or a
@@ -215,6 +228,7 @@
     const char* fNoPerspectiveInterpolationExtensionString;
     const char* fMultisampleInterpolationExtensionString;
     const char* fSampleVariablesExtensionString;
+    const char* fImageLoadStoreExtensionString;
 
     const char* fFBFetchColorName;
     const char* fFBFetchExtensionString;
@@ -224,6 +238,11 @@
     int fMaxFragmentSamplers;
     int fMaxCombinedSamplers;
 
+    int fMaxVertexImages;
+    int fMaxGeometryImages;
+    int fMaxFragmentImages;
+    int fMaxCombinedImages;
+
     AdvBlendEqInteraction fAdvBlendEqInteraction;
 
     GrSwizzle fConfigTextureSwizzle[kGrPixelConfigCnt];