Add caps overrides to GMs

Review URL: https://codereview.chromium.org/1158963002
diff --git a/dm/DMGpuSupport.h b/dm/DMGpuSupport.h
index 65fbc53..f147248 100644
--- a/dm/DMGpuSupport.h
+++ b/dm/DMGpuSupport.h
@@ -55,8 +55,13 @@
     void dumpGpuStats(SkString*) const {}
 };
 
+struct GrContextOptions {};
+
 class GrContextFactory {
 public:
+    GrContextFactory() {};
+    explicit GrContextFactory(const GrContextOptions&) {}
+
     typedef int GLContextType;
 
     static const GLContextType kANGLE_GLContextType  = 0,
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index a838511..0a90e03 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -57,6 +57,11 @@
     return gm->getName();
 }
 
+void GMSrc::modifyGrContextOptions(GrContextOptions* options) const {
+    SkAutoTDelete<skiagm::GM> gm(fFactory(NULL));
+    gm->modifyGrContextOptions(options);
+}
+
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
 CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType)
@@ -434,7 +439,10 @@
 void PreAbandonGpuContextErrorHandler(SkError, void*) {}
 
 Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
-    GrContextFactory factory;
+    GrContextOptions options;
+    src.modifyGrContextOptions(&options);
+
+    GrContextFactory factory(options);
     const SkISize size = src.size();
     const SkImageInfo info =
         SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType);
diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h
index 85877df..bd8c41e 100644
--- a/dm/DMSrcSink.h
+++ b/dm/DMSrcSink.h
@@ -59,6 +59,7 @@
     virtual Error SK_WARN_UNUSED_RESULT draw(SkCanvas*) const = 0;
     virtual SkISize size() const = 0;
     virtual Name name() const = 0;
+    virtual void modifyGrContextOptions(GrContextOptions* options) const {}
 };
 
 struct Sink {
@@ -85,6 +86,8 @@
     Error draw(SkCanvas*) const override;
     SkISize size() const override;
     Name name() const override;
+    void modifyGrContextOptions(GrContextOptions* options) const override;
+
 private:
     skiagm::GMRegistry::Factory fFactory;
 };
diff --git a/gm/bleed.cpp b/gm/bleed.cpp
index 75cf8ca..a96917b 100644
--- a/gm/bleed.cpp
+++ b/gm/bleed.cpp
@@ -12,6 +12,7 @@
 
 #if SK_SUPPORT_GPU
 #include "GrContext.h"
+#include "GrContextOptions.h"
 #endif
 
 // Create a black&white checked texture with 2 1-pixel rings
@@ -188,67 +189,52 @@
                 canvas->scale(0.71f, 1.22f);
             }
 
-            // First draw a column with no bleeding, tiling, or filtering
+            // First draw a column with no bleeding and no filtering
             this->drawCase1(canvas, kCol0X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, kNone_SkFilterQuality);
             this->drawCase2(canvas, kCol0X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, kNone_SkFilterQuality);
             this->drawCase3(canvas, kCol0X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, kNone_SkFilterQuality);
             this->drawCase4(canvas, kCol0X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, kNone_SkFilterQuality);
 
-            // Then draw a column with no bleeding or tiling but with low filtering
+            // Then draw a column with no bleeding and low filtering
             this->drawCase1(canvas, kCol1X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, kLow_SkFilterQuality);
             this->drawCase2(canvas, kCol1X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, kLow_SkFilterQuality);
             this->drawCase3(canvas, kCol1X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, kLow_SkFilterQuality);
             this->drawCase4(canvas, kCol1X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, kLow_SkFilterQuality);
 
-            // Then draw a column with no bleeding or tiling but with high filtering
+            // Then draw a column with no bleeding and high filtering
             this->drawCase1(canvas, kCol2X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, kHigh_SkFilterQuality);
             this->drawCase2(canvas, kCol2X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, kHigh_SkFilterQuality);
             this->drawCase3(canvas, kCol2X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, kHigh_SkFilterQuality);
             this->drawCase4(canvas, kCol2X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, kHigh_SkFilterQuality);
 
-#if SK_SUPPORT_GPU
-            GrContext* ctx = canvas->getGrContext();
-            int oldMaxTextureSize = 0;
-            if (ctx) {
-                // shrink the max texture size so all our textures can be reasonably sized
-                oldMaxTextureSize = ctx->getMaxTextureSize();
-                ctx->setMaxTextureSizeOverride(kMaxTextureSize);
-            }
-#endif
+            // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
+            this->drawCase1(canvas, kCol3X, kRow0Y, SkCanvas::kBleed_DrawBitmapRectFlag, kNone_SkFilterQuality);
+            this->drawCase2(canvas, kCol3X, kRow1Y, SkCanvas::kBleed_DrawBitmapRectFlag, kNone_SkFilterQuality);
+            this->drawCase3(canvas, kCol3X, kRow2Y, SkCanvas::kBleed_DrawBitmapRectFlag, kNone_SkFilterQuality);
+            this->drawCase4(canvas, kCol3X, kRow3Y, SkCanvas::kBleed_DrawBitmapRectFlag, kNone_SkFilterQuality);
 
-            // Then draw a column with no bleeding but with tiling and low filtering
-            this->drawCase1(canvas, kCol3X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, kLow_SkFilterQuality);
-            this->drawCase2(canvas, kCol3X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, kLow_SkFilterQuality);
-            this->drawCase3(canvas, kCol3X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, kLow_SkFilterQuality);
-            this->drawCase4(canvas, kCol3X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, kLow_SkFilterQuality);
+            // Then draw a column with bleeding and low filtering
+            this->drawCase1(canvas, kCol4X, kRow0Y, SkCanvas::kBleed_DrawBitmapRectFlag, kLow_SkFilterQuality);
+            this->drawCase2(canvas, kCol4X, kRow1Y, SkCanvas::kBleed_DrawBitmapRectFlag, kLow_SkFilterQuality);
+            this->drawCase3(canvas, kCol4X, kRow2Y, SkCanvas::kBleed_DrawBitmapRectFlag, kLow_SkFilterQuality);
+            this->drawCase4(canvas, kCol4X, kRow3Y, SkCanvas::kBleed_DrawBitmapRectFlag, kLow_SkFilterQuality);
 
-            // Then draw a column with no bleeding but with tiling and high filtering
-            this->drawCase1(canvas, kCol4X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, kHigh_SkFilterQuality);
-            this->drawCase2(canvas, kCol4X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, kHigh_SkFilterQuality);
-            this->drawCase3(canvas, kCol4X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, kHigh_SkFilterQuality);
-            this->drawCase4(canvas, kCol4X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, kHigh_SkFilterQuality);
+            // Finally draw a column with bleeding and high filtering
+            this->drawCase1(canvas, kCol5X, kRow0Y, SkCanvas::kBleed_DrawBitmapRectFlag, kHigh_SkFilterQuality);
+            this->drawCase2(canvas, kCol5X, kRow1Y, SkCanvas::kBleed_DrawBitmapRectFlag, kHigh_SkFilterQuality);
+            this->drawCase3(canvas, kCol5X, kRow2Y, SkCanvas::kBleed_DrawBitmapRectFlag, kHigh_SkFilterQuality);
+            this->drawCase4(canvas, kCol5X, kRow3Y, SkCanvas::kBleed_DrawBitmapRectFlag, kHigh_SkFilterQuality);
 
-            // Then draw a column with bleeding, tiling, and low filtering
-            this->drawCase1(canvas, kCol5X, kRow0Y, SkCanvas::kBleed_DrawBitmapRectFlag, kLow_SkFilterQuality);
-            this->drawCase2(canvas, kCol5X, kRow1Y, SkCanvas::kBleed_DrawBitmapRectFlag, kLow_SkFilterQuality);
-            this->drawCase3(canvas, kCol5X, kRow2Y, SkCanvas::kBleed_DrawBitmapRectFlag, kLow_SkFilterQuality);
-            this->drawCase4(canvas, kCol5X, kRow3Y, SkCanvas::kBleed_DrawBitmapRectFlag, kLow_SkFilterQuality);
-
-            // Finally draw a column with bleeding, tiling, and high filtering
-            this->drawCase1(canvas, kCol6X, kRow0Y, SkCanvas::kBleed_DrawBitmapRectFlag, kHigh_SkFilterQuality);
-            this->drawCase2(canvas, kCol6X, kRow1Y, SkCanvas::kBleed_DrawBitmapRectFlag, kHigh_SkFilterQuality);
-            this->drawCase3(canvas, kCol6X, kRow2Y, SkCanvas::kBleed_DrawBitmapRectFlag, kHigh_SkFilterQuality);
-            this->drawCase4(canvas, kCol6X, kRow3Y, SkCanvas::kBleed_DrawBitmapRectFlag, kHigh_SkFilterQuality);
-
-#if SK_SUPPORT_GPU
-            if (ctx) {
-                ctx->setMaxTextureSizeOverride(oldMaxTextureSize);
-            }
-#endif
             canvas->restore();
         }
     }
 
+#if SK_SUPPORT_GPU
+    void modifyGrContextOptions(GrContextOptions* options) override {
+        options->fMaxTextureSizeOverride = kMaxTextureSize;
+    }
+#endif
+
 private:
     static const int kBlockSize = 70;
     static const int kBlockSpacing = 5;
@@ -259,8 +245,7 @@
     static const int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
     static const int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
     static const int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
-    static const int kCol6X = 7*kBlockSpacing + 6*kBlockSize;
-    static const int kWidth = 8*kBlockSpacing + 7*kBlockSize;
+    static const int kWidth = 7*kBlockSpacing + 6*kBlockSize;
 
     static const int kRow0Y = kBlockSpacing;
     static const int kRow1Y = 2*kBlockSpacing + kBlockSize;
diff --git a/gm/discard.cpp b/gm/discard.cpp
index a762288..106a6be 100644
--- a/gm/discard.cpp
+++ b/gm/discard.cpp
@@ -9,6 +9,7 @@
 #include "SkCanvas.h"
 #include "SkColorShader.h"
 #include "SkPaint.h"
+#include "SkRandom.h"
 #include "SkSurface.h"
 
 #if SK_SUPPORT_GPU
diff --git a/gm/gm.h b/gm/gm.h
index 87ad927..24c6100 100644
--- a/gm/gm.h
+++ b/gm/gm.h
@@ -17,10 +17,7 @@
 #include "sk_tool_utils.h"
 
 class SkAnimTimer;
-
-#if SK_SUPPORT_GPU
-#include "GrContext.h"
-#endif
+struct GrContextOptions;
 
 #define DEF_GM(code) \
     static skiagm::GM*          SK_MACRO_APPEND_LINE(F_)(void*) { code; } \
@@ -96,6 +93,8 @@
 
         bool animate(const SkAnimTimer&);
 
+        virtual void modifyGrContextOptions(GrContextOptions* options) {}
+
     protected:
         /** draws a standard message that the GM is only intended to be used with the GPU.*/
         void drawGpuOnlyMessage(SkCanvas*);
diff --git a/gm/textblobuseaftergpufree.cpp b/gm/textblobuseaftergpufree.cpp
index 127e436..070c9ef 100644
--- a/gm/textblobuseaftergpufree.cpp
+++ b/gm/textblobuseaftergpufree.cpp
@@ -12,6 +12,7 @@
 #include "SkCanvas.h"
 #include "SkSurface.h"
 #include "SkTextBlob.h"
+#include "GrContext.h"
 
 // This tests that we correctly regenerate textblobs after freeing all gpu resources crbug/491350
 namespace skiagm {
diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h
index be62d8a..e083042 100644
--- a/include/gpu/GrCaps.h
+++ b/include/gpu/GrCaps.h
@@ -84,6 +84,11 @@
     bool floatPrecisionVaries() const { return fShaderPrecisionVaries; }
 
 protected:
+    /** Subclasses must call this at the end of their constructors in order to apply caps
+        overrides requested by 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;
@@ -194,6 +199,11 @@
         return fDrawPathMasksToCompressedTextureSupport; }
 
 protected:
+    /** Subclasses must call this at the end of their constructors in order to apply caps
+        overrides requested by the client. Note that overrides will only reduce the caps never
+        expand them. */
+    void applyOptionsOverrides(const GrContextOptions& options);
+
     SkAutoTUnref<GrShaderCaps>    fShaderCaps;
 
     bool fNPOTTextureTileSupport        : 1;
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 56ba262..8c5f09f 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -179,15 +179,6 @@
     int getMaxTextureSize() const;
 
     /**
-     *  Temporarily override the true max texture size. Note: an override
-     *  larger then the true max texture size will have no effect.
-     *  This entry point is mainly meant for testing texture size dependent
-     *  features and is only available if defined outside of Skia (see
-     *  bleed GM.
-     */
-    void setMaxTextureSizeOverride(int maxTextureSizeOverride);
-
-    /**
      * Can the provided configuration act as a color render target?
      */
     bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const;
@@ -429,8 +420,6 @@
 
     SkTDArray<CleanUpData>          fCleanUpData;
 
-    int                             fMaxTextureSizeOverride;
-
     const uint32_t                  fUniqueID;
 
     GrContext(); // init must be called after the constructor.
diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h
index d78ac6c..686d6a9 100644
--- a/include/gpu/GrContextOptions.h
+++ b/include/gpu/GrContextOptions.h
@@ -11,14 +11,24 @@
 #include "SkTypes.h"
 
 struct GrContextOptions {
-    GrContextOptions() : fDrawPathToCompressedTexture(false), fSuppressPrints(false) {}
+    GrContextOptions()
+        : fDrawPathToCompressedTexture(false)
+        , fSuppressPrints(false)
+        , fMaxTextureSizeOverride(SK_MaxS32) {}
 
     // EXPERIMENTAL
     // May be removed in the future, or may become standard depending
     // on the outcomes of a variety of internal tests.
     bool fDrawPathToCompressedTexture;
+
     // Suppress prints for the GrContext.
     bool fSuppressPrints;
+
+    /** Overrides: These options override feature detection using backend API queries. These
+        overrides can only reduce the feature set or limits, never increase them beyond the
+        detected values. */
+
+    int fMaxTextureSizeOverride;
 };
 
 #endif
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp
index eb2cf7d..625bd90 100644
--- a/src/gpu/GrCaps.cpp
+++ b/src/gpu/GrCaps.cpp
@@ -73,6 +73,10 @@
     return r;
 }
 
+void GrShaderCaps::applyOptionsOverrides(const GrContextOptions&) {
+    // Currently no overrides apply to shader caps.
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 GrCaps::GrCaps(const GrContextOptions& options) {
@@ -103,6 +107,10 @@
     fDrawPathMasksToCompressedTextureSupport = options.fDrawPathToCompressedTexture;
 }
 
+void GrCaps::applyOptionsOverrides(const GrContextOptions& options) {
+    fMaxTextureSize = SkTMin(fMaxTextureSize, options.fMaxTextureSizeOverride);
+}
+
 static SkString map_flags_to_string(uint32_t flags) {
     SkString str;
     if (GrCaps::kNone_MapFlags == flags) {
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index cc7e6c2..5baf722 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -144,7 +144,6 @@
     fSoftwarePathRenderer = NULL;
     fBatchFontCache = NULL;
     fFlushToReduceCacheSize = false;
-    fMaxTextureSizeOverride = 1 << 20;
 }
 
 bool GrContext::init(GrBackend backend, GrBackendContext backendContext,
@@ -292,7 +291,7 @@
 }
 
 int GrContext::getMaxTextureSize() const {
-    return SkTMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride);
+    return fGpu->caps()->maxTextureSize();
 }
 
 int GrContext::getMaxRenderTargetSize() const {
diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp
index 8546cf1..37a0feb 100644
--- a/src/gpu/GrTest.cpp
+++ b/src/gpu/GrTest.cpp
@@ -32,10 +32,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrContext::setMaxTextureSizeOverride(int maxTextureSizeOverride) {
-    fMaxTextureSizeOverride = maxTextureSizeOverride;
-}
-
 void GrContext::purgeAllUnlockedResources() {
     fResourceCache->purgeAllUnlocked();
 }
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 6f272b7..13ce507 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -49,7 +49,10 @@
 
     this->init(ctxInfo, glInterface);
 
-    fShaderCaps.reset(SkNEW_ARGS(GrGLSLCaps, (ctxInfo, glInterface, *this)));
+    fShaderCaps.reset(SkNEW_ARGS(GrGLSLCaps, (contextOptions,
+        ctxInfo, glInterface, *this)));
+
+    this->applyOptionsOverrides(contextOptions);
 }
 
 void GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
@@ -893,7 +896,8 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////
 
-GrGLSLCaps::GrGLSLCaps(const GrGLContextInfo& ctxInfo,
+GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options,
+                       const GrGLContextInfo& ctxInfo,
                        const GrGLInterface* gli,
                        const GrGLCaps& glCaps) {
     fDropsTileOnZeroDivide = false;
@@ -903,6 +907,7 @@
     fFBFetchColorName = NULL;
     fFBFetchExtensionString = NULL;
     this->init(ctxInfo, gli, glCaps);
+    this->applyOptionsOverrides(options);
 }
 
 void GrGLSLCaps::init(const GrGLContextInfo& ctxInfo,
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 9d38c82..87fc1f4 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -388,7 +388,8 @@
      * Initializes the GrGLSLCaps to the set of features supported in the current
      * OpenGL context accessible via ctxInfo.
      */
-    GrGLSLCaps(const GrGLContextInfo&, const GrGLInterface*, const GrGLCaps&);
+    GrGLSLCaps(const GrContextOptions&, const GrGLContextInfo&, const GrGLInterface*,
+               const GrGLCaps&);
 
     /**
      * Some helper functions for encapsulating various extensions to read FB Buffer on openglES