Revert "Revert "Revert "Revert "Revert "Revert "Redefine the meaning of sample counts in GPU backend.""""""

This reverts commit 3a2cc2c2ec124de36d2544b2a523ef1dd317ca32.

Fix code with samplecnt=0 that slipped in between trybots/CQ and landing of previous version

Change-Id: Iab19f2e8d1e9901601c8c76244d7a88c5d707fab
Reviewed-on: https://skia-review.googlesource.com/103181
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
index b9ecfa7..f7f0bff 100644
--- a/bench/nanobench.cpp
+++ b/bench/nanobench.cpp
@@ -428,7 +428,8 @@
         if (const GrContext* ctx = factory.get(ctxType, ctxOverrides)) {
             GrPixelConfig grPixConfig = SkImageInfo2GrPixelConfig(colorType, colorSpace,
                                                                   *ctx->caps());
-            int supportedSampleCount = ctx->caps()->getSampleCount(sampleCount, grPixConfig);
+            int supportedSampleCount =
+                    ctx->caps()->getRenderTargetSampleCount(sampleCount, grPixConfig);
             if (sampleCount != supportedSampleCount) {
                 SkDebugf("Configuration '%s' sample count %d is not a supported sample count.\n",
                          config->getTag().c_str(), sampleCount);
diff --git a/debugger/QT/SkGLWidget.cpp b/debugger/QT/SkGLWidget.cpp
index baee2bb..44a15dc 100644
--- a/debugger/QT/SkGLWidget.cpp
+++ b/debugger/QT/SkGLWidget.cpp
@@ -20,7 +20,7 @@
 
 void SkGLWidget::setSampleCount(int sampleCount) {
     QGLFormat currentFormat = format();
-    currentFormat.setSampleBuffers(sampleCount > 0);
+    currentFormat.setSampleBuffers(sampleCount > 1);
     currentFormat.setSamples(sampleCount);
     setFormat(currentFormat);
 }
@@ -89,6 +89,7 @@
     int sampleCnt;
     GR_GL_GetIntegerv(fCurIntf.get(), GR_GL_FRAMEBUFFER_BINDING, &info.fFBOID);
     GR_GL_GetIntegerv(fCurIntf.get(), GR_GL_SAMPLES, &sampleCnt);
+    sampleCnt = SkTMax(sampleCnt, 1);
     GR_GL_GetIntegerv(fCurIntf.get(), GR_GL_STENCIL_BITS, &stencilBits);
     // We are on desktop so we assume the internal config is RGBA
     info.fFormat = GR_GL_RGBA8;
diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h
index db1e064..157a484 100644
--- a/dm/DMSrcSink.h
+++ b/dm/DMSrcSink.h
@@ -350,7 +350,7 @@
     bool serial() const override { return !fThreaded; }
     const char* fileExtension() const override { return "png"; }
     SinkFlags flags() const override {
-        SinkFlags::Multisampled ms = fSampleCount > 0 ? SinkFlags::kMultisampled
+        SinkFlags::Multisampled ms = fSampleCount > 1 ? SinkFlags::kMultisampled
                                                       : SinkFlags::kNotMultisampled;
         return SinkFlags{ SinkFlags::kGPU, SinkFlags::kDirect, ms };
     }
diff --git a/example/HelloWorld.cpp b/example/HelloWorld.cpp
index 5954e71..b20d30a 100644
--- a/example/HelloWorld.cpp
+++ b/example/HelloWorld.cpp
@@ -38,7 +38,7 @@
 }
 
 void HelloWorld::updateTitle() {
-    if (!fWindow || fWindow->sampleCount() < 0) {
+    if (!fWindow || fWindow->sampleCount() <= 1) {
         return;
     }
 
diff --git a/include/core/SkSurface.h b/include/core/SkSurface.h
index 1f2c4b7..d621fdf 100644
--- a/include/core/SkSurface.h
+++ b/include/core/SkSurface.h
@@ -90,7 +90,7 @@
     /**
      *  Used to wrap a pre-existing backend 3D API texture as a SkSurface. Skia will not assume
      *  ownership of the texture and the client must ensure the texture is valid for the lifetime
-     *  of the SkSurface. If sampleCnt > 0, then we will create an intermediate mssa surface which
+     *  of the SkSurface. If sampleCnt > 1, then we will create an intermediate mssa surface which
      *  we will use for rendering. We then resolve into the passed in texture.
      */
     static sk_sp<SkSurface> MakeFromBackendTexture(GrContext* context,
@@ -102,13 +102,13 @@
     /**
      *  Used to wrap a pre-existing backend 3D API texture as a SkSurface. Skia will not assume
      *  ownership of the texture and the client must ensure the texture is valid for the lifetime
-     *  of the SkSurface. If sampleCnt > 0, then we will create an intermediate mssa surface which
+     *  of the SkSurface. If sampleCnt > 1, then we will create an intermediate mssa surface which
      *  we will use for rendering. We then resolve into the passed in texture.
      *
      *  The GrBackendTexture must have a valid backend format supplied (GrGLTextureInfo::fFormat,
      *  GrVkImageInfo::fFormat, etc.) in it. The passed in SkColorType informs skia how it should
      *  interpret the backend format supplied by the GrBackendTexture. If the format in the
-     *  GrBackendTexture is not compitable with the sampleCnt, SkColorType, and SkColorSpace we
+     *  GrBackendTexture is not compatible with the sampleCnt, SkColorType, and SkColorSpace we
      *  will return nullptr.
      */
     static sk_sp<SkSurface> MakeFromBackendTexture(GrContext* context,
@@ -128,7 +128,7 @@
      *  The GrBackendRenderTarget must have a valid backend format set (GrGLTextureInfo::fFormat,
      *  GrVkImageInfo::fFormat, etc.) in it. The passed in SkColorType informs skia how it should
      *  interpret the backend format supplied by the GrBackendRenderTarget. If the format in the
-     *  GrBackendRenderTarget is not compitable with the sampleCnt, SkColorType, and SkColorSpace
+     *  GrBackendRenderTarget is not compatible with the sampleCnt, SkColorType, and SkColorSpace
      *  we will return nullptr.
      */
     static sk_sp<SkSurface> MakeFromBackendRenderTarget(GrContext* context,
@@ -162,7 +162,7 @@
      *  The GrBackendTexture must have a valid backend format supplied (GrGLTextureInfo::fFormat,
      *  GrVkImageInfo::fFormat, etc.) in it. The passed in SkColorType informs skia how it should
      *  interpret the backend format supplied by the GrBackendTexture. If the format in the
-     *  GrBackendTexture is not compitable with the sampleCnt, SkColorType, and SkColorSpace we
+     *  GrBackendTexture is not compatible with the sampleCnt, SkColorType, and SkColorSpace we
      *  will return nullptr.
      */
     static sk_sp<SkSurface> MakeFromBackendTextureAsRenderTarget(GrContext* context,
diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h
index f4d6e06..0f03f16 100644
--- a/include/gpu/GrCaps.h
+++ b/include/gpu/GrCaps.h
@@ -134,10 +134,6 @@
 
     int maxRasterSamples() const { return fMaxRasterSamples; }
 
-    // Find a sample count greater than or equal to the requested count which is supported for a
-    // color buffer of the given config. If MSAA is not support for the config we will return 0.
-    virtual int getSampleCount(int requestedCount, GrPixelConfig config) const = 0;
-
     int maxWindowRectangles() const { return fMaxWindowRectangles; }
 
     // A tuned, platform-specific value for the maximum number of analytic fragment processors we
@@ -145,9 +141,32 @@
     int maxClipAnalyticFPs() const { return fMaxClipAnalyticFPs; }
 
     virtual bool isConfigTexturable(GrPixelConfig) const = 0;
-    virtual bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const = 0;
+
     // Returns whether a texture of the given config can be copied to a texture of the same config.
-    virtual bool isConfigCopyable(GrPixelConfig config) const = 0;
+    virtual bool isConfigCopyable(GrPixelConfig) const = 0;
+
+    // Returns the maximum supported sample count for a config. 0 means the config is not renderable
+    // 1 means the config is renderable but doesn't support MSAA.
+    virtual int maxRenderTargetSampleCount(GrPixelConfig) const = 0;
+
+    bool isConfigRenderable(GrPixelConfig config) const {
+        return this->maxRenderTargetSampleCount(config) > 0;
+    }
+
+    // TODO: Remove this after Flutter updated to no longer use it.
+    bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const {
+        return this->maxRenderTargetSampleCount(config) > (withMSAA ? 1 : 0);
+    }
+
+    // Find a sample count greater than or equal to the requested count which is supported for a
+    // color buffer of the given config or 0 if no such sample count is supported. If the requested
+    // sample count is 1 then 1 will be returned if non-MSAA rendering is supported, otherwise 0.
+    // For historical reasons requestedCount==0 is handled identically to requestedCount==1.
+    virtual int getRenderTargetSampleCount(int requestedCount, GrPixelConfig) const = 0;
+    // TODO: Remove. Legacy name used by Chrome.
+    int getSampleCount(int requestedCount, GrPixelConfig config) const {
+        return this->getRenderTargetSampleCount(requestedCount, config);
+    }
 
     bool suppressPrints() const { return fSuppressPrints; }
 
@@ -178,6 +197,8 @@
     virtual bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
                                     bool* rectsMustMatch, bool* disallowSubrect) const = 0;
 
+    bool validateSurfaceDesc(const GrSurfaceDesc&, GrMipMapped) const;
+
     /**
      * Returns true if the GrBackendTexutre can we used with the supplied SkColorType. If it is
      * compatible, the passed in GrPixelConfig will be set to a config that matches the backend
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index f85efc4..d0ca90e 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -216,6 +216,26 @@
     /** Access the context capabilities */
     const GrCaps* caps() const { return fCaps.get(); }
 
+    /**
+     * Can a SkImage be created with the given color type.
+     */
+    bool colorTypeSupportedAsImage(SkColorType) const;
+
+    /**
+     * Can a SkSurface be created with the given color type. To check whether MSAA is supported
+     * use maxSurfaceSampleCountForColorType().
+     */
+    bool colorTypeSupportedAsSurface(SkColorType colorType) const {
+        return this->maxSurfaceSampleCountForColorType(colorType) > 0;
+    }
+
+    /**
+     * Gets the maximum supported sample count for a color type. 1 is returned if only non-MSAA
+     * rendering is supported for the color type. 0 is returned if rendering to this color type
+     * is not supported at all.
+     */
+    int maxSurfaceSampleCountForColorType(SkColorType) const;
+
     /*
      * Create a new render target context backed by a deferred-style
      * GrRenderTargetProxy. We guarantee that "asTextureProxy" will succeed for
@@ -226,7 +246,7 @@
                                                  int width, int height,
                                                  GrPixelConfig config,
                                                  sk_sp<SkColorSpace> colorSpace,
-                                                 int sampleCnt = 0,
+                                                 int sampleCnt = 1,
                                                  GrMipMapped = GrMipMapped::kNo,
                                                  GrSurfaceOrigin origin = kBottomLeft_GrSurfaceOrigin,
                                                  const SkSurfaceProps* surfaceProps = nullptr,
@@ -242,7 +262,7 @@
                                                  int width, int height,
                                                  GrPixelConfig config,
                                                  sk_sp<SkColorSpace> colorSpace,
-                                                 int sampleCnt = 0,
+                                                 int sampleCnt = 1,
                                                  GrMipMapped = GrMipMapped::kNo,
                                                  GrSurfaceOrigin origin = kBottomLeft_GrSurfaceOrigin,
                                                  const SkSurfaceProps* surfaceProps = nullptr,
diff --git a/include/gpu/GrRenderTarget.h b/include/gpu/GrRenderTarget.h
index 4eee7f6..0aad636 100644
--- a/include/gpu/GrRenderTarget.h
+++ b/include/gpu/GrRenderTarget.h
@@ -33,10 +33,11 @@
     const GrRenderTarget* asRenderTarget() const  override { return this; }
 
     // GrRenderTarget
-    bool isStencilBufferMultisampled() const { return fSampleCnt > 0; }
+    bool isStencilBufferMultisampled() const { return fSampleCnt > 1; }
 
     GrFSAAType fsaaType() const {
-        if (!fSampleCnt) {
+        SkASSERT(fSampleCnt >= 1);
+        if (fSampleCnt <= 1) {
             SkASSERT(!(fFlags & GrRenderTargetFlags::kMixedSampled));
             return GrFSAAType::kNone;
         }
@@ -45,15 +46,15 @@
     }
 
     /**
-     * Returns the number of samples/pixel in the stencil buffer (Zero if non-MSAA).
+     * Returns the number of samples/pixel in the stencil buffer (One if non-MSAA).
      */
     int numStencilSamples() const { return fSampleCnt; }
 
     /**
-     * Returns the number of samples/pixel in the color buffer (Zero if non-MSAA or mixed sampled).
+     * Returns the number of samples/pixel in the color buffer (One if non-MSAA or mixed sampled).
      */
     int numColorSamples() const {
-        return GrFSAAType::kMixedSamples == this->fsaaType() ? 0 : fSampleCnt;
+        return GrFSAAType::kMixedSamples == this->fsaaType() ? 1 : fSampleCnt;
     }
 
     /**
diff --git a/include/gpu/GrTypes.h b/include/gpu/GrTypes.h
index 3081543..ab21fba 100644
--- a/include/gpu/GrTypes.h
+++ b/include/gpu/GrTypes.h
@@ -402,13 +402,12 @@
  */
 struct GrSurfaceDesc {
     GrSurfaceDesc()
-        : fFlags(kNone_GrSurfaceFlags)
-        , fOrigin(kTopLeft_GrSurfaceOrigin)
-        , fWidth(0)
-        , fHeight(0)
-        , fConfig(kUnknown_GrPixelConfig)
-        , fSampleCnt(0) {
-    }
+            : fFlags(kNone_GrSurfaceFlags)
+            , fOrigin(kTopLeft_GrSurfaceOrigin)
+            , fWidth(0)
+            , fHeight(0)
+            , fConfig(kUnknown_GrPixelConfig)
+            , fSampleCnt(1) {}
 
     GrSurfaceFlags         fFlags;  //!< bitfield of TextureFlags
     GrSurfaceOrigin        fOrigin; //!< origin of the texture
@@ -422,11 +421,11 @@
     GrPixelConfig          fConfig;
 
     /**
-     * The number of samples per pixel or 0 to disable full scene AA. This only
+     * The number of samples per pixel. Zero is treated equivalently to 1. This only
      * applies if the kRenderTarget_GrSurfaceFlag is set. The actual number
      * of samples may not exactly match the request. The request will be rounded
-     * up to the next supported sample count, or down if it is larger than the
-     * max supported count.
+     * up to the next supported sample count. A value larger than the largest
+     * supported sample count will fail.
      */
     int                    fSampleCnt;
 };
diff --git a/include/gpu/mock/GrMockTypes.h b/include/gpu/mock/GrMockTypes.h
index cf30a33..0954c5e 100644
--- a/include/gpu/mock/GrMockTypes.h
+++ b/include/gpu/mock/GrMockTypes.h
@@ -22,8 +22,9 @@
  */
 struct GrMockOptions {
     GrMockOptions() {
+        using Renderability = ConfigOptions::Renderability;
         // By default RGBA_8888 is textureable and renderable and A8 and RGB565 are texturable.
-        fConfigOptions[kRGBA_8888_GrPixelConfig].fRenderable[0] = true;
+        fConfigOptions[kRGBA_8888_GrPixelConfig].fRenderability = Renderability::kNonMSAA;
         fConfigOptions[kRGBA_8888_GrPixelConfig].fTexturable = true;
         fConfigOptions[kAlpha_8_GrPixelConfig].fTexturable = true;
         fConfigOptions[kAlpha_8_as_Alpha_GrPixelConfig].fTexturable = true;
@@ -32,8 +33,8 @@
     }
 
     struct ConfigOptions {
-        /** The first value is for non-MSAA rendering, the second for MSAA. */
-        bool fRenderable[2] = {false, false};
+        enum Renderability { kNo, kNonMSAA, kMSAA };
+        Renderability fRenderability;
         bool fTexturable = false;
     };
 
diff --git a/include/private/GrRenderTargetProxy.h b/include/private/GrRenderTargetProxy.h
index 1cd3d5d..efe2823 100644
--- a/include/private/GrRenderTargetProxy.h
+++ b/include/private/GrRenderTargetProxy.h
@@ -26,7 +26,7 @@
     bool instantiate(GrResourceProvider*) override;
 
     GrFSAAType fsaaType() const {
-        if (!fSampleCnt) {
+        if (fSampleCnt <= 1) {
             SkASSERT(!(fRenderTargetFlags & GrRenderTargetFlags::kMixedSampled));
             return GrFSAAType::kNone;
         }
@@ -42,15 +42,15 @@
     bool needsStencil() const { return fNeedsStencil; }
 
     /**
-     * Returns the number of samples/pixel in the stencil buffer (Zero if non-MSAA).
+     * Returns the number of samples/pixel in the stencil buffer (One if non-MSAA).
      */
     int numStencilSamples() const { return fSampleCnt; }
 
     /**
-     * Returns the number of samples/pixel in the color buffer (Zero if non-MSAA or mixed sampled).
+     * Returns the number of samples/pixel in the color buffer (One if non-MSAA or mixed sampled).
      */
     int numColorSamples() const {
-        return GrFSAAType::kMixedSamples == this->fsaaType() ? 0 : fSampleCnt;
+        return GrFSAAType::kMixedSamples == this->fsaaType() ? 1 : fSampleCnt;
     }
 
     int maxWindowRectangles(const GrCaps& caps) const;
diff --git a/src/gpu/GrBackendSurface.cpp b/src/gpu/GrBackendSurface.cpp
index 406cb22..16fa793 100644
--- a/src/gpu/GrBackendSurface.cpp
+++ b/src/gpu/GrBackendSurface.cpp
@@ -106,7 +106,7 @@
                                              const GrVkImageInfo& vkInfo)
         : fWidth(width)
         , fHeight(height)
-        , fSampleCnt(sampleCnt)
+        , fSampleCnt(SkTMax(1, sampleCnt))
         , fStencilBits(stencilBits)
         , fConfig(GrVkFormatToPixelConfig(vkInfo.fFormat))
         , fBackend(kVulkan_GrBackend)
@@ -121,7 +121,7 @@
                                              const GrGLFramebufferInfo& glInfo)
         : fWidth(width)
         , fHeight(height)
-        , fSampleCnt(sampleCnt)
+        , fSampleCnt(SkTMax(1, sampleCnt))
         , fStencilBits(stencilBits)
         , fConfig(config)
         , fBackend(kOpenGL_GrBackend)
@@ -134,7 +134,7 @@
                                              const GrGLFramebufferInfo& glInfo)
         : fWidth(width)
         , fHeight(height)
-        , fSampleCnt(sampleCnt)
+        , fSampleCnt(SkTMax(1, sampleCnt))
         , fStencilBits(stencilBits)
         , fConfig(GrGLSizedFormatToPixelConfig(glInfo.fFormat))
         , fBackend(kOpenGL_GrBackend)
diff --git a/src/gpu/GrBackendTextureImageGenerator.cpp b/src/gpu/GrBackendTextureImageGenerator.cpp
index ae27912..af28409 100644
--- a/src/gpu/GrBackendTextureImageGenerator.cpp
+++ b/src/gpu/GrBackendTextureImageGenerator.cpp
@@ -186,8 +186,8 @@
         GrMipMapped mipMapped = willNeedMipMaps ? GrMipMapped::kYes : GrMipMapped::kNo;
 
         sk_sp<GrRenderTargetContext> rtContext(context->makeDeferredRenderTargetContext(
-                SkBackingFit::kExact, info.width(), info.height(), proxy->config(), nullptr,
-                0, mipMapped, proxy->origin(), nullptr, SkBudgeted::kYes));
+                SkBackingFit::kExact, info.width(), info.height(), proxy->config(), nullptr, 1,
+                mipMapped, proxy->origin(), nullptr, SkBudgeted::kYes));
 
         if (!rtContext) {
             return nullptr;
diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp
index b79a38a..b6e3092 100644
--- a/src/gpu/GrBlurUtils.cpp
+++ b/src/gpu/GrBlurUtils.cpp
@@ -110,7 +110,7 @@
                                              int sampleCnt) {
     if (GrAA::kNo == aa) {
         // Don't need MSAA if mask isn't AA
-        sampleCnt = 0;
+        sampleCnt = 1;
     }
 
     sk_sp<GrRenderTargetContext> rtContext(context->makeDeferredRenderTargetContextWithFallback(
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp
index 427b204..dd589b4 100644
--- a/src/gpu/GrCaps.cpp
+++ b/src/gpu/GrCaps.cpp
@@ -196,8 +196,7 @@
                          kBlendEquationSupportNames[fBlendEquationSupport]);
     writer->appendString("Map Buffer Support", map_flags_to_string(fMapBufferFlags).c_str());
 
-    SkASSERT(!this->isConfigRenderable(kUnknown_GrPixelConfig, false));
-    SkASSERT(!this->isConfigRenderable(kUnknown_GrPixelConfig, true));
+    SkASSERT(!this->isConfigRenderable(kUnknown_GrPixelConfig));
     SkASSERT(!this->isConfigTexturable(kUnknown_GrPixelConfig));
 
     writer->beginArray("configs");
@@ -206,8 +205,7 @@
         GrPixelConfig config = static_cast<GrPixelConfig>(i);
         writer->beginObject(nullptr, false);
         writer->appendString("name", pixel_config_name(config));
-        writer->appendBool("renderable", this->isConfigRenderable(config, false));
-        writer->appendBool("renderableMSAA", this->isConfigRenderable(config, true));
+        writer->appendS32("max sample count", this->maxRenderTargetSampleCount(config));
         writer->appendBool("texturable", this->isConfigTexturable(config));
         writer->endObject();
     }
@@ -222,3 +220,39 @@
     writer->endObject();
 }
 
+bool GrCaps::validateSurfaceDesc(const GrSurfaceDesc& desc, GrMipMapped mipped) const {
+    if (!this->isConfigTexturable(desc.fConfig)) {
+        return false;
+    }
+
+    if (GrMipMapped::kYes == mipped) {
+        if (GrPixelConfigIsSint(desc.fConfig) || !this->mipMapSupport()) {
+            return false;
+        }
+    }
+
+    if (desc.fWidth < 1 || desc.fHeight < 1) {
+        return false;
+    }
+
+    if (SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag)) {
+        if (0 == this->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig)) {
+            return false;
+        }
+        int maxRTSize = this->maxRenderTargetSize();
+        if (desc.fWidth > maxRTSize || desc.fHeight > maxRTSize) {
+            return false;
+        }
+    } else {
+        // We currently do not support multisampled textures
+        if (desc.fSampleCnt > 1) {
+            return false;
+        }
+        int maxSize = this->maxTextureSize();
+        if (desc.fWidth > maxSize || desc.fHeight > maxSize) {
+            return false;
+        }
+    }
+
+    return true;
+}
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index 8f82ea1..24c813e 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -198,7 +198,7 @@
         // With mixed samples (non-msaa color buffer), any coverage info is lost from color once it
         // hits the color buffer anyway, so we may as well use coverage AA if nothing else in the
         // pipe is multisampled.
-        if (renderTargetContext->numColorSamples() > 0 || useHWAA || hasUserStencilSettings) {
+        if (renderTargetContext->numColorSamples() > 1 || useHWAA || hasUserStencilSettings) {
             maxAnalyticFPs = 0;
         }
         SkASSERT(!context->caps()->avoidStencilBuffers()); // We disable MSAA when avoiding stencil.
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index b427e70..05908f4 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -420,6 +420,18 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const {
+    GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps());
+    return this->caps()->isConfigTexturable(config);
+}
+
+int GrContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const {
+    GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps());
+    return this->caps()->maxRenderTargetSampleCount(config);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 void GrContext::TextBlobCacheOverBudgetCB(void* data) {
     SkASSERT(data);
     // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on
@@ -862,6 +874,7 @@
                                                                    sk_sp<SkColorSpace> colorSpace,
                                                                    const SkSurfaceProps* props) {
     ASSERT_SINGLE_OWNER_PRIV
+    SkASSERT(sampleCnt > 0);
 
     sk_sp<GrTextureProxy> proxy(this->proxyProvider()->createWrappedTextureProxy(tex, origin,
                                                                                  sampleCnt));
@@ -898,7 +911,7 @@
                                                      sk_sp<SkColorSpace> colorSpace,
                                                      const SkSurfaceProps* props) {
     ASSERT_SINGLE_OWNER_PRIV
-
+    SkASSERT(sampleCnt > 0);
     sk_sp<GrSurfaceProxy> proxy(this->proxyProvider()->createWrappedRenderTargetProxy(tex, origin,
                                                                                       sampleCnt));
     if (!proxy) {
@@ -949,7 +962,8 @@
                                                                  GrSurfaceOrigin origin,
                                                                  const SkSurfaceProps* surfaceProps,
                                                                  SkBudgeted budgeted) {
-    if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) {
+    SkASSERT(sampleCnt > 0);
+    if (0 == this->caps()->getRenderTargetSampleCount(sampleCnt, config)) {
         config = GrPixelConfigFallback(config);
     }
 
@@ -968,6 +982,7 @@
                                                         GrSurfaceOrigin origin,
                                                         const SkSurfaceProps* surfaceProps,
                                                         SkBudgeted budgeted) {
+    SkASSERT(sampleCnt > 0);
     if (this->abandoned()) {
         return nullptr;
     }
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index eb005d1..955d57d 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -72,68 +72,22 @@
     return false;
 }
 
-/**
- * Prior to creating a texture, make sure the type of texture being created is
- * supported by calling check_texture_creation_params.
- *
- * @param caps          The capabilities of the GL device.
- * @param desc          The descriptor of the texture to create.
- * @param isRT          Indicates if the texture can be a render target.
- * @param texels        The texel data for the mipmap levels
- * @param mipLevelCount The number of GrMipLevels in 'texels'
- */
-static bool check_texture_creation_params(const GrCaps& caps, const GrSurfaceDesc& desc,
-                                          bool* isRT,
-                                          const GrMipLevel texels[], int mipLevelCount) {
-    if (!caps.isConfigTexturable(desc.fConfig)) {
-        return false;
-    }
-
-    if (GrPixelConfigIsSint(desc.fConfig) && mipLevelCount > 1) {
-        return false;
-    }
-
-    *isRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
-    if (*isRT && !caps.isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
-        return false;
-    }
-
-    // We currently do not support multisampled textures
-    if (!*isRT && desc.fSampleCnt > 0) {
-        return false;
-    }
-
-    if (*isRT) {
-        int maxRTSize = caps.maxRenderTargetSize();
-        if (desc.fWidth > maxRTSize || desc.fHeight > maxRTSize) {
-            return false;
-        }
-    } else {
-        int maxSize = caps.maxTextureSize();
-        if (desc.fWidth > maxSize || desc.fHeight > maxSize) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budgeted,
                                       const GrMipLevel texels[], int mipLevelCount) {
     GR_CREATE_TRACE_MARKER_CONTEXT("GrGpu", "createTexture", fContext);
     GrSurfaceDesc desc = origDesc;
 
-    const GrCaps* caps = this->caps();
-    bool isRT = false;
-    bool textureCreationParamsValid = check_texture_creation_params(*caps, desc, &isRT,
-                                                                    texels, mipLevelCount);
-    if (!textureCreationParamsValid) {
+    GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
+    if (!this->caps()->validateSurfaceDesc(desc, mipMapped)) {
         return nullptr;
     }
 
-    desc.fSampleCnt = caps->getSampleCount(desc.fSampleCnt, desc.fConfig);
+    bool isRT = desc.fFlags & kRenderTarget_GrSurfaceFlag;
+    if (isRT) {
+        desc.fSampleCnt = this->caps()->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig);
+    }
     // Attempt to catch un- or wrongly initialized sample counts.
-    SkASSERT(desc.fSampleCnt >= 0 && desc.fSampleCnt <= 64);
+    SkASSERT(desc.fSampleCnt > 0 && desc.fSampleCnt <= 64);
 
     if (mipLevelCount && (desc.fFlags & kPerformInitialClear_GrSurfaceFlag)) {
         return nullptr;
@@ -142,7 +96,7 @@
     this->handleDirtyContext();
     sk_sp<GrTexture> tex = this->onCreateTexture(desc, budgeted, texels, mipLevelCount);
     if (tex) {
-        if (!caps->reuseScratchTextures() && !isRT) {
+        if (!this->caps()->reuseScratchTextures() && !isRT) {
             tex->resourcePriv().removeScratchKey();
         }
         fStats.incTextureCreates();
@@ -179,8 +133,11 @@
 sk_sp<GrTexture> GrGpu::wrapRenderableBackendTexture(const GrBackendTexture& backendTex,
                                                      int sampleCnt, GrWrapOwnership ownership) {
     this->handleDirtyContext();
+    if (sampleCnt < 1) {
+        return nullptr;
+    }
     if (!this->caps()->isConfigTexturable(backendTex.config()) ||
-        !this->caps()->isConfigRenderable(backendTex.config(), sampleCnt > 0)) {
+        !this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config())) {
         return nullptr;
     }
 
@@ -197,7 +154,7 @@
 }
 
 sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) {
-    if (!this->caps()->isConfigRenderable(backendRT.config(), backendRT.sampleCnt() > 0)) {
+    if (0 == this->caps()->getRenderTargetSampleCount(backendRT.sampleCnt(), backendRT.config())) {
         return nullptr;
     }
     this->handleDirtyContext();
@@ -206,14 +163,14 @@
 
 sk_sp<GrRenderTarget> GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
                                                               int sampleCnt) {
-    this->handleDirtyContext();
-    if (!this->caps()->isConfigRenderable(tex.config(), sampleCnt > 0)) {
+    if (0 == this->caps()->getRenderTargetSampleCount(sampleCnt, tex.config())) {
         return nullptr;
     }
     int maxSize = this->caps()->maxTextureSize();
     if (tex.width() > maxSize || tex.height() > maxSize) {
         return nullptr;
     }
+    this->handleDirtyContext();
     return this->onWrapBackendTextureAsRenderTarget(tex, sampleCnt);
 }
 
@@ -262,7 +219,7 @@
 
     // Check to see if we're going to request that the caller draw when drawing is not possible.
     if (!srcSurface->asTexture() ||
-        !this->caps()->isConfigRenderable(tempDrawInfo->fTempSurfaceDesc.fConfig, false)) {
+        !this->caps()->isConfigRenderable(tempDrawInfo->fTempSurfaceDesc.fConfig)) {
         // If we don't have a fallback to a straight read then fail.
         if (kRequireDraw_DrawPreference == *drawPreference) {
             return false;
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 2f12073..6527064 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -455,6 +455,10 @@
     /** Creates a texture directly in the backend API without wrapping it in a GrTexture. This is
         only to be used for testing (particularly for testing the methods that import an externally
         created texture into Skia. Must be matched with a call to deleteTestingOnlyTexture(). */
+    GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h, SkColorType,
+                                                     bool isRenderTarget, GrMipMapped);
+
+    /** Older version based on GrPixelConfig. Currently the preferred one above devolves to this. */
     virtual GrBackendTexture createTestingOnlyBackendTexture(
                                                       void* pixels, int w, int h,
                                                       GrPixelConfig config,
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index e453246..6641bcf 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -315,37 +315,14 @@
                                                    uint32_t flags) {
     SkASSERT(0 == flags || GrResourceProvider::kNoPendingIO_Flag == flags);
 
-    const GrCaps* caps = this->caps();
-
-    // TODO: move this logic into GrResourceProvider!
-    // TODO: share this testing code with check_texture_creation_params
-    if (!caps->isConfigTexturable(desc.fConfig)) {
+    if (!this->caps()->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
         return nullptr;
     }
-
-    bool willBeRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
-    if (willBeRT && !caps->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
-        return nullptr;
-    }
-
-    // We currently do not support multisampled textures
-    if (!willBeRT && desc.fSampleCnt > 0) {
-        return nullptr;
-    }
-
-    int maxSize;
-    if (willBeRT) {
-        maxSize = caps->maxRenderTargetSize();
-    } else {
-        maxSize = caps->maxTextureSize();
-    }
-
-    if (desc.fWidth > maxSize || desc.fHeight > maxSize || desc.fWidth <= 0 || desc.fHeight <= 0) {
-        return nullptr;
-    }
-
     GrSurfaceDesc copyDesc = desc;
-    copyDesc.fSampleCnt = caps->getSampleCount(desc.fSampleCnt, desc.fConfig);
+    if (desc.fFlags & kRenderTarget_GrSurfaceFlag) {
+        copyDesc.fSampleCnt =
+                this->caps()->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig);
+    }
 
 #ifdef SK_DISABLE_DEFERRED_PROXIES
     // Temporarily force instantiation for crbug.com/769760 and crbug.com/769898
@@ -363,11 +340,11 @@
 
     return GrSurfaceProxy::MakeWrapped(std::move(tex), copyDesc.fOrigin);
 #else
-    if (willBeRT) {
+    if (copyDesc.fFlags & kRenderTarget_GrSurfaceFlag) {
         // We know anything we instantiate later from this deferred path will be
         // both texturable and renderable
-        return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*caps, copyDesc, fit,
-                                                                    budgeted, flags));
+        return sk_sp<GrTextureProxy>(
+                new GrTextureRenderTargetProxy(*this->caps(), copyDesc, fit, budgeted, flags));
     }
 
     return sk_sp<GrTextureProxy>(new GrTextureProxy(copyDesc, fit, budgeted, nullptr, 0, flags));
@@ -507,7 +484,7 @@
     desc.fWidth = -1;
     desc.fHeight = -1;
     desc.fConfig = config;
-    desc.fSampleCnt = 0;
+    desc.fSampleCnt = 1;
 
     return this->createLazyProxy(std::move(callback), desc, GrMipMapped::kNo,
                                  SkBackingFit::kApprox, SkBudgeted::kYes);
diff --git a/src/gpu/GrRenderTarget.cpp b/src/gpu/GrRenderTarget.cpp
index 3090219..36fa4dd 100644
--- a/src/gpu/GrRenderTarget.cpp
+++ b/src/gpu/GrRenderTarget.cpp
@@ -27,7 +27,7 @@
         , fMultisampleSpecsID(0)
         , fFlags(flags) {
     SkASSERT(desc.fFlags & kRenderTarget_GrSurfaceFlag);
-    SkASSERT(!(fFlags & GrRenderTargetFlags::kMixedSampled) || fSampleCnt > 0);
+    SkASSERT(!(fFlags & GrRenderTargetFlags::kMixedSampled) || fSampleCnt > 1);
     SkASSERT(!(fFlags & GrRenderTargetFlags::kWindowRectsSupport) ||
              gpu->caps()->maxWindowRectangles() > 0);
     fResolveRect = SkRectPriv::MakeILargestInverted();
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp
index 9eb37a0..841d4b1 100644
--- a/src/gpu/GrRenderTargetProxy.cpp
+++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -26,7 +26,7 @@
         , fRenderTargetFlags(GrRenderTargetFlags::kNone) {
     // Since we know the newly created render target will be internal, we are able to precompute
     // what the flags will ultimately end up being.
-    if (caps.usesMixedSamples() && fSampleCnt > 0) {
+    if (caps.usesMixedSamples() && fSampleCnt > 1) {
         fRenderTargetFlags |= GrRenderTargetFlags::kMixedSampled;
     }
     if (caps.maxWindowRectangles() > 0) {
@@ -97,7 +97,11 @@
 }
 
 size_t GrRenderTargetProxy::onUninstantiatedGpuMemorySize() const {
-    int colorSamplesPerPixel = this->numColorSamples() + 1;
+    int colorSamplesPerPixel = this->numColorSamples();
+    if (colorSamplesPerPixel > 1) {
+        // Add one for the resolve buffer.
+        ++colorSamplesPerPixel;
+    }
 
     // TODO: do we have enough information to improve this worst case estimate?
     return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 3800383..ec94968 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -46,28 +46,6 @@
     fQuadIndexBufferKey = gQuadIndexBufferKey;
 }
 
-bool validate_desc(const GrSurfaceDesc& desc, const GrCaps& caps, int levelCount = 0) {
-    if (desc.fWidth <= 0 || desc.fHeight <= 0) {
-        return false;
-    }
-    if (!caps.isConfigTexturable(desc.fConfig)) {
-        return false;
-    }
-    if (desc.fFlags & kRenderTarget_GrSurfaceFlag) {
-        if (!caps.isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
-            return false;
-        }
-    } else {
-        if (desc.fSampleCnt) {
-            return false;
-        }
-    }
-    if (levelCount > 1 && (GrPixelConfigIsSint(desc.fConfig) || !caps.mipMapSupport())) {
-        return false;
-    }
-    return true;
-}
-
 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
                                                    const GrMipLevel texels[], int mipLevelCount,
                                                    SkDestinationSurfaceColorMode mipColorMode) {
@@ -79,7 +57,8 @@
         return nullptr;
     }
 
-    if (!validate_desc(desc, *fCaps, mipLevelCount)) {
+    GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
+    if (!fCaps->validateSurfaceDesc(desc, mipMapped)) {
         return nullptr;
     }
 
@@ -125,7 +104,7 @@
         return nullptr;
     }
 
-    if (!validate_desc(desc, *fCaps)) {
+    if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
         return nullptr;
     }
 
@@ -157,12 +136,11 @@
 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
                                                    uint32_t flags) {
     ASSERT_SINGLE_OWNER
-
     if (this->isAbandoned()) {
         return nullptr;
     }
 
-    if (!validate_desc(desc, *fCaps)) {
+    if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
         return nullptr;
     }
 
@@ -183,7 +161,7 @@
         return nullptr;
     }
 
-    if (!validate_desc(desc, *fCaps)) {
+    if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
         return nullptr;
     }
 
@@ -212,7 +190,7 @@
                                                        uint32_t flags) {
     ASSERT_SINGLE_OWNER
     SkASSERT(!this->isAbandoned());
-    SkASSERT(validate_desc(desc, *fCaps));
+    SkASSERT(fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo));
 
     // We could make initial clears work with scratch textures but it is a rare case so we just opt
     // to fall back to making a new texture.
diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h
index 0092430..385282d 100644
--- a/src/gpu/GrResourceProvider.h
+++ b/src/gpu/GrResourceProvider.h
@@ -89,7 +89,7 @@
                                         GrWrapOwnership = kBorrow_GrWrapOwnership);
 
     /**
-     * This makes the backend texture be renderable. If sampleCnt is > 0 and the underlying API
+     * This makes the backend texture be renderable. If sampleCnt is > 1 and the underlying API
      * uses separate MSAA render buffers then a MSAA render buffer is created that resolves
      * to the texture.
      */
diff --git a/src/gpu/GrSurface.cpp b/src/gpu/GrSurface.cpp
index ec503d7..b35683c 100644
--- a/src/gpu/GrSurface.cpp
+++ b/src/gpu/GrSurface.cpp
@@ -29,8 +29,9 @@
     bool isRenderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
     if (isRenderTarget) {
         // We own one color value for each MSAA sample.
-        int colorValuesPerPixel = SkTMax(1, desc.fSampleCnt);
-        if (desc.fSampleCnt) {
+        SkASSERT(desc.fSampleCnt >= 1);
+        int colorValuesPerPixel = desc.fSampleCnt;
+        if (desc.fSampleCnt > 1) {
             // Worse case, we own the resolve buffer so that is one more sample per pixel.
             colorValuesPerPixel += 1;
         }
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index 64c47b5..4020758 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -26,7 +26,7 @@
     return desc.fWidth <= 0 &&
            desc.fHeight <= 0 &&
            desc.fConfig != kUnknown_GrPixelConfig &&
-           desc.fSampleCnt == 0 &&
+           desc.fSampleCnt == 1 &&
            SkBackingFit::kApprox == fit;
 }
 
@@ -190,7 +190,7 @@
 void GrSurfaceProxy::computeScratchKey(GrScratchKey* key) const {
     SkASSERT(LazyState::kFully != this->lazyInstantiationState());
     const GrRenderTargetProxy* rtp = this->asRenderTargetProxy();
-    int sampleCount = 0;
+    int sampleCount = 1;
     if (rtp) {
         sampleCount = rtp->numStencilSamples();
     }
diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp
index b4cefb0..dd06317 100644
--- a/src/gpu/GrTexture.cpp
+++ b/src/gpu/GrTexture.cpp
@@ -78,7 +78,7 @@
 
 void GrTexture::computeScratchKey(GrScratchKey* key) const {
     const GrRenderTarget* rt = this->asRenderTarget();
-    int sampleCount = 0;
+    int sampleCount = 1;
     if (rt) {
         sampleCount = rt->numStencilSamples();
     }
@@ -92,8 +92,10 @@
                                       GrMipMapped mipMapped, GrScratchKey* key) {
     static const GrScratchKey::ResourceType kType = GrScratchKey::GenerateResourceType();
     uint32_t flags = isRenderTarget;
-
-    SkASSERT(0 == sampleCnt || isRenderTarget);
+    SkASSERT(width > 0);
+    SkASSERT(height > 0);
+    SkASSERT(sampleCnt > 0);
+    SkASSERT(1 == sampleCnt || isRenderTarget);
 
     // make sure desc.fConfig fits in 5 bits
     SkASSERT(sk_float_log2(kLast_GrPixelConfig) <= 5);
diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp
index 9593cb6..9b344cb 100644
--- a/src/gpu/GrTextureProducer.cpp
+++ b/src/gpu/GrTextureProducer.cpp
@@ -25,8 +25,8 @@
     GrMipMapped mipMapped = dstWillRequireMipMaps ? GrMipMapped::kYes : GrMipMapped::kNo;
 
     sk_sp<GrRenderTargetContext> copyRTC = context->makeDeferredRenderTargetContextWithFallback(
-        SkBackingFit::kExact, dstRect.width(), dstRect.height(), inputProxy->config(), nullptr,
-        0, mipMapped, inputProxy->origin());
+            SkBackingFit::kExact, dstRect.width(), dstRect.height(), inputProxy->config(), nullptr,
+            1, mipMapped, inputProxy->origin());
     if (!copyRTC) {
         return nullptr;
     }
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index 8e6afbf..54d0769 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -64,7 +64,7 @@
     if (LazyState::kNot != this->lazyInstantiationState()) {
         return false;
     }
-    if (!this->instantiateImpl(resourceProvider, 0, /* needsStencil = */ false,
+    if (!this->instantiateImpl(resourceProvider, 1, /* needsStencil = */ false,
                                kNone_GrSurfaceFlags, fMipMapped, fMipColorMode,
                                fUniqueKey.isValid() ? &fUniqueKey : nullptr)) {
         return false;
@@ -76,7 +76,7 @@
 }
 
 sk_sp<GrSurface> GrTextureProxy::createSurface(GrResourceProvider* resourceProvider) const {
-    sk_sp<GrSurface> surface= this->createSurfaceImpl(resourceProvider, 0,
+    sk_sp<GrSurface> surface= this->createSurfaceImpl(resourceProvider, 1,
                                                       /* needsStencil = */ false,
                                                       kNone_GrSurfaceFlags,
                                                       fMipMapped, fMipColorMode);
diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp
index da8e483..843524c 100644
--- a/src/gpu/GrTextureRenderTargetProxy.cpp
+++ b/src/gpu/GrTextureRenderTargetProxy.cpp
@@ -53,7 +53,11 @@
 }
 
 size_t GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize() const {
-    int colorSamplesPerPixel = this->numColorSamples() + 1;
+    int colorSamplesPerPixel = this->numColorSamples();
+    if (colorSamplesPerPixel > 1) {
+        // Add one to account for the resolve buffer.
+        ++colorSamplesPerPixel += 1;
+    }
 
     // TODO: do we have enough information to improve this worst case estimate?
     return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp
index 62ff0d0..47d27c4 100644
--- a/src/gpu/GrYUVProvider.cpp
+++ b/src/gpu/GrYUVProvider.cpp
@@ -106,7 +106,7 @@
         auto proxyProvider = ctx->contextPriv().proxyProvider();
         yuvTextureProxies[i] = proxyProvider->createTextureProxy(yuvImage, kNone_GrSurfaceFlags,
                                                                  kTopLeft_GrSurfaceOrigin,
-                                                                 0, SkBudgeted::kYes, fit);
+                                                                 1, SkBudgeted::kYes, fit);
     }
 
     // We never want to perform color-space conversion during the decode
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 3d951c4..29a8943 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -48,7 +48,7 @@
     desc.fWidth = info.width();
     desc.fHeight = info.height();
     desc.fConfig = SkImageInfo2GrPixelConfig(info, caps);
-    desc.fSampleCnt = 0;
+    desc.fSampleCnt = 1;
     return desc;
 }
 
@@ -170,7 +170,7 @@
     desc.fWidth = baseProxy->width();
     desc.fHeight = baseProxy->height();
     desc.fConfig = baseProxy->config();
-    desc.fSampleCnt = 0;
+    desc.fSampleCnt = 1;
 
     sk_sp<GrTextureProxy> proxy = proxyProvider->createMipMapProxy(desc, SkBudgeted::kYes);
     if (!proxy) {
@@ -268,7 +268,7 @@
     }
     if (!proxy) {
         proxy = proxyProvider->createTextureProxy(std::move(srcImage), kNone_GrSurfaceFlags,
-                                                  kTopLeft_GrSurfaceOrigin, 0, SkBudgeted::kYes,
+                                                  kTopLeft_GrSurfaceOrigin, 1, SkBudgeted::kYes,
                                                   SkBackingFit::kExact);
         if (proxy && originalKey.isValid()) {
             proxyProvider->assignUniqueKeyToProxy(originalKey, proxy.get());
diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
index abe8880..da69917 100644
--- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
+++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
@@ -42,7 +42,7 @@
     return shaderCaps.integerSupport() && shaderCaps.flatInterpolationSupport() &&
            caps.instanceAttribSupport() && GrCaps::kNone_MapFlags != caps.mapBufferFlags() &&
            caps.isConfigTexturable(kAlpha_half_GrPixelConfig) &&
-           caps.isConfigRenderable(kAlpha_half_GrPixelConfig, /*withMSAA=*/false) &&
+           caps.isConfigRenderable(kAlpha_half_GrPixelConfig) &&
            !caps.blacklistCoverageCounting();
 }
 
diff --git a/src/gpu/ddl/GrDDLGpu.h b/src/gpu/ddl/GrDDLGpu.h
index 16deab0..e1f463f 100644
--- a/src/gpu/ddl/GrDDLGpu.h
+++ b/src/gpu/ddl/GrDDLGpu.h
@@ -46,7 +46,7 @@
     void onQueryMultisampleSpecs(GrRenderTarget* rt, GrSurfaceOrigin, const GrStencilSettings&,
                                  int* effectiveSampleCnt, SamplePattern*) override {
         SkASSERT(0);
-        *effectiveSampleCnt = 0; // ??
+        *effectiveSampleCnt = 1;  // ??
     }
 
     GrGpuRTCommandBuffer* createCommandBuffer(
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 3b90676..99f5656 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -1958,6 +1958,8 @@
 
     for (int i = 0; i < kGrPixelConfigCnt; ++i) {
         if (ConfigInfo::kRenderableWithMSAA_Flag & fConfigTable[i].fFlags) {
+            // We assume that MSAA rendering is supported only if we support non-MSAA rendering.
+            SkASSERT(ConfigInfo::kRenderable_Flag & fConfigTable[i].fFlags);
             if ((kGL_GrGLStandard == ctxInfo.standard() &&
                  (ctxInfo.version() >= GR_GL_VER(4,2) ||
                   ctxInfo.hasExtension("GL_ARB_internalformat_query"))) ||
@@ -1970,10 +1972,15 @@
                     int* temp = new int[count];
                     GR_GL_GetInternalformativ(gli, GR_GL_RENDERBUFFER, format, GR_GL_SAMPLES, count,
                                               temp);
+                    // GL has a concept of MSAA rasterization with a single sample but we do not.
+                    if (count && temp[count - 1] == 1) {
+                        --count;
+                        SkASSERT(!count || temp[count -1] > 1);
+                    }
                     fConfigTable[i].fColorSampleCounts.setCount(count+1);
-                    // We initialize our supported values with 0 (no msaa) and reverse the order
+                    // We initialize our supported values with 1 (no msaa) and reverse the order
                     // returned by GL so that the array is ascending.
-                    fConfigTable[i].fColorSampleCounts[0] = 0;
+                    fConfigTable[i].fColorSampleCounts[0] = 1;
                     for (int j = 0; j < count; ++j) {
                         fConfigTable[i].fColorSampleCounts[j+1] = temp[count - j - 1];
                     }
@@ -1982,14 +1989,16 @@
             } else {
                 // Fake out the table using some semi-standard counts up to the max allowed sample
                 // count.
-                int maxSampleCnt = 0;
+                int maxSampleCnt = 1;
                 if (GrGLCaps::kES_IMG_MsToTexture_MSFBOType == fMSFBOType) {
                     GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES_IMG, &maxSampleCnt);
                 } else if (GrGLCaps::kNone_MSFBOType != fMSFBOType) {
                     GR_GL_GetIntegerv(gli, GR_GL_MAX_SAMPLES, &maxSampleCnt);
                 }
+                // Chrome has a mock GL implementation that returns 0.
+                maxSampleCnt = SkTMax(1, maxSampleCnt);
 
-                static constexpr int kDefaultSamples[] = {0, 1, 2, 4, 8};
+                static constexpr int kDefaultSamples[] = {1, 2, 4, 8};
                 int count = SK_ARRAY_COUNT(kDefaultSamples);
                 for (; count > 0; --count) {
                     if (kDefaultSamples[count - 1] <= maxSampleCnt) {
@@ -2000,6 +2009,9 @@
                     fConfigTable[i].fColorSampleCounts.append(count, kDefaultSamples);
                 }
             }
+        } else if (ConfigInfo::kRenderable_Flag & fConfigTable[i].fFlags) {
+            fConfigTable[i].fColorSampleCounts.setCount(1);
+            fConfigTable[i].fColorSampleCounts[0] = 1;
         }
     }
 
@@ -2034,7 +2046,7 @@
 
     // If the src is a texture, we can implement the blit as a draw assuming the config is
     // renderable.
-    if (src->asTextureProxy() && this->isConfigRenderable(src->config(), false)) {
+    if (src->asTextureProxy() && !this->isConfigRenderable(src->config())) {
         desc->fOrigin = kBottomLeft_GrSurfaceOrigin;
         desc->fFlags = kRenderTarget_GrSurfaceFlag;
         desc->fConfig = src->config();
@@ -2059,14 +2071,14 @@
     GrSurfaceOrigin originForBlitFramebuffer = kTopLeft_GrSurfaceOrigin;
     bool rectsMustMatchForBlitFramebuffer = false;
     bool disallowSubrectForBlitFramebuffer = false;
-    if (src->numColorSamples() &&
+    if (src->numColorSamples() > 1 &&
         (this->blitFramebufferSupportFlags() & kResolveMustBeFull_BlitFrambufferFlag)) {
         rectsMustMatchForBlitFramebuffer = true;
         disallowSubrectForBlitFramebuffer = true;
         // Mirroring causes rects to mismatch later, don't allow it.
         originForBlitFramebuffer = src->origin();
-    } else if (src->numColorSamples() && (this->blitFramebufferSupportFlags() &
-                                          kRectsMustMatchForMSAASrc_BlitFramebufferFlag)) {
+    } else if (src->numColorSamples() > 1 && (this->blitFramebufferSupportFlags() &
+                                              kRectsMustMatchForMSAASrc_BlitFramebufferFlag)) {
         rectsMustMatchForBlitFramebuffer = true;
         // Mirroring causes rects to mismatch later, don't allow it.
         originForBlitFramebuffer = src->origin();
@@ -2456,18 +2468,31 @@
     }
 }
 
-int GrGLCaps::getSampleCount(int requestedCount, GrPixelConfig config) const {
+int GrGLCaps::getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const {
+    requestedCount = SkTMax(1, requestedCount);
     int count = fConfigTable[config].fColorSampleCounts.count();
-    if (!count || !this->isConfigRenderable(config, true)) {
+    if (!count) {
         return 0;
     }
 
+    if (1 == requestedCount) {
+        return fConfigTable[config].fColorSampleCounts[0] == 1 ? 1 : 0;
+    }
+
     for (int i = 0; i < count; ++i) {
         if (fConfigTable[config].fColorSampleCounts[i] >= requestedCount) {
             return fConfigTable[config].fColorSampleCounts[i];
         }
     }
-    return fConfigTable[config].fColorSampleCounts[count-1];
+    return 0;
+}
+
+int GrGLCaps::maxRenderTargetSampleCount(GrPixelConfig config) const {
+    const auto& table = fConfigTable[config].fColorSampleCounts;
+    if (!table.count()) {
+        return 0;
+    }
+    return table[table.count() - 1];
 }
 
 bool validate_sized_format(GrGLenum format, SkColorType ct, GrPixelConfig* config,
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index fd49a65..7a443e4 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -112,19 +112,12 @@
     GrGLCaps(const GrContextOptions& contextOptions, const GrGLContextInfo& ctxInfo,
              const GrGLInterface* glInterface);
 
-    int getSampleCount(int requestedCount, GrPixelConfig config) const override;
-
     bool isConfigTexturable(GrPixelConfig config) const override {
         return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kTextureable_Flag);
     }
 
-    bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override {
-        if (withMSAA) {
-            return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderableWithMSAA_Flag);
-        } else {
-            return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag);
-        }
-    }
+    int getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const override;
+    int maxRenderTargetSampleCount(GrPixelConfig config) const override;
 
     bool isConfigCopyable(GrPixelConfig config) const override {
         // In GL we have three ways to be able to copy. CopyTexImage, blit, and draw. CopyTexImage
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index ae31495..b4a0341 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -545,7 +545,7 @@
     surfDesc.fWidth = backendTex.width();
     surfDesc.fHeight = backendTex.height();
     surfDesc.fConfig = backendTex.config();
-    surfDesc.fSampleCnt = 0;
+    surfDesc.fSampleCnt = 1;
 
     GrMipMapsStatus mipMapsStatus = backendTex.hasMipMaps() ? GrMipMapsStatus::kValid
                                                             : GrMipMapsStatus::kNotAllocated;
@@ -581,7 +581,10 @@
     surfDesc.fWidth = backendTex.width();
     surfDesc.fHeight = backendTex.height();
     surfDesc.fConfig = backendTex.config();
-    surfDesc.fSampleCnt = this->caps()->getSampleCount(sampleCnt, backendTex.config());
+    surfDesc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config());
+    if (surfDesc.fSampleCnt < 1) {
+        return nullptr;
+    }
 
     GrGLRenderTarget::IDDesc rtIDDesc;
     if (!this->createRenderTargetObjects(surfDesc, idDesc.fInfo, &rtIDDesc)) {
@@ -616,7 +619,8 @@
     desc.fWidth = backendRT.width();
     desc.fHeight = backendRT.height();
     desc.fConfig = backendRT.config();
-    desc.fSampleCnt = this->caps()->getSampleCount(backendRT.sampleCnt(), backendRT.config());
+    desc.fSampleCnt =
+            this->caps()->getRenderTargetSampleCount(backendRT.sampleCnt(), backendRT.config());
 
     return GrGLRenderTarget::MakeWrapped(this, desc, idDesc, backendRT.stencilBits());
 }
@@ -645,7 +649,7 @@
     surfDesc.fWidth = tex.width();
     surfDesc.fHeight = tex.height();
     surfDesc.fConfig = tex.config();
-    surfDesc.fSampleCnt = this->caps()->getSampleCount(sampleCnt, tex.config());
+    surfDesc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, tex.config());
 
     GrGLRenderTarget::IDDesc rtIDDesc;
     if (!this->createRenderTargetObjects(surfDesc, texInfo, &rtIDDesc)) {
@@ -686,7 +690,7 @@
     }
 
     // If the dst is MSAA, we have to draw, or we'll just be writing to the resolve target.
-    if (dstSurface->asRenderTarget() && dstSurface->asRenderTarget()->numColorSamples() > 0) {
+    if (dstSurface->asRenderTarget() && dstSurface->asRenderTarget()->numColorSamples() > 1) {
         ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
     }
 
@@ -704,7 +708,7 @@
     tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig;
     tempDrawInfo->fTempSurfaceDesc.fWidth = width;
     tempDrawInfo->fTempSurfaceDesc.fHeight = height;
-    tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 0;
+    tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1;
     tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin; // no CPU y-flip for TL.
 
     bool configsAreRBSwaps = GrPixelConfigSwapRAndB(srcConfig) == dstSurface->config();
@@ -1277,13 +1281,13 @@
     idDesc->fTexFBOID = 0;
     SkASSERT((GrGLCaps::kMixedSamples_MSFBOType == this->glCaps().msFBOType()) ==
              this->caps()->usesMixedSamples());
-    idDesc->fIsMixedSampled = desc.fSampleCnt > 0 && this->caps()->usesMixedSamples();
+    idDesc->fIsMixedSampled = desc.fSampleCnt > 1 && this->caps()->usesMixedSamples();
 
     GrGLenum status;
 
     GrGLenum colorRenderbufferFormat = 0; // suppress warning
 
-    if (desc.fSampleCnt > 0 && GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) {
+    if (desc.fSampleCnt > 1 && GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) {
         goto FAILED;
     }
 
@@ -1296,7 +1300,7 @@
     // 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 && this->glCaps().usesMSAARenderBuffers()) {
+    if (desc.fSampleCnt > 1 && this->glCaps().usesMSAARenderBuffers()) {
         GL_CALL(GenFramebuffers(1, &idDesc->fRTFBOID));
         GL_CALL(GenRenderbuffers(1, &idDesc->fMSColorRenderbufferID));
         if (!idDesc->fRTFBOID ||
@@ -1313,7 +1317,7 @@
     // below here we may bind the FBO
     fHWBoundRenderTargetUniqueID.makeInvalid();
     if (idDesc->fRTFBOID != idDesc->fTexFBOID) {
-        SkASSERT(desc.fSampleCnt > 0);
+        SkASSERT(desc.fSampleCnt > 1);
         GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbufferID));
         if (!renderbuffer_storage_msaa(*fGLContext,
                                        desc.fSampleCnt,
@@ -1338,7 +1342,7 @@
     fStats.incRenderTargetBinds();
     GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, idDesc->fTexFBOID));
 
-    if (this->glCaps().usesImplicitMSAAResolve() && desc.fSampleCnt > 0) {
+    if (this->glCaps().usesImplicitMSAAResolve() && desc.fSampleCnt > 1) {
         GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER,
                                                 GR_GL_COLOR_ATTACHMENT0,
                                                 texInfo.fTarget,
@@ -1415,7 +1419,7 @@
                                           const GrMipLevel texels[],
                                           int mipLevelCount) {
     // We fail if the MSAA was requested and is not available.
-    if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType() && desc.fSampleCnt) {
+    if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType() && desc.fSampleCnt > 1) {
         //SkDebugf("MSAA RT requested but not supported on this platform.");
         return return_null_texture();
     }
@@ -1524,7 +1528,7 @@
 
 int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) {
     static const int kSize = 16;
-    SkASSERT(this->caps()->isConfigRenderable(config, false));
+    SkASSERT(this->caps()->isConfigRenderable(config));
     if (!this->glCaps().hasStencilFormatBeenDeterminedForConfig(config)) {
         // Default to unsupported, set this if we find a stencil format that works.
         int firstWorkingStencilFormatIndex = -1;
@@ -1694,7 +1698,7 @@
     CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
     // we do this "if" so that we don't call the multisample
     // version on a GL that doesn't have an MSAA extension.
-    if (samples > 0) {
+    if (samples > 1) {
         SkAssertResult(renderbuffer_storage_msaa(*fGLContext,
                                                  samples,
                                                  sFmt.fInternalFormat,
@@ -2133,7 +2137,7 @@
         GrSurfaceDesc desc;
         desc.fConfig = rtConfig;
         desc.fWidth = desc.fHeight = 16;
-        if (this->glCaps().isConfigRenderable(rtConfig, false)) {
+        if (this->glCaps().isConfigRenderable(rtConfig)) {
             desc.fFlags = kRenderTarget_GrSurfaceFlag;
             desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
             temp = this->createTexture(desc, SkBudgeted::kNo);
@@ -2194,7 +2198,7 @@
     tempDrawInfo->fTempSurfaceDesc.fFlags = kRenderTarget_GrSurfaceFlag;
     tempDrawInfo->fTempSurfaceDesc.fWidth = width;
     tempDrawInfo->fTempSurfaceDesc.fHeight = height;
-    tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 0;
+    tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1;
     tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin; // no CPU y-flip for TL.
     tempDrawInfo->fTempSurfaceFit = this->glCaps().partialFBOReadIsSlow() ? SkBackingFit::kExact
                                                                           : SkBackingFit::kApprox;
@@ -2872,10 +2876,13 @@
                 GL_CALL(Enable(GR_GL_RASTER_MULTISAMPLE));
                 fHWRasterMultisampleEnabled = kYes_TriState;
             }
-            if (rt->numStencilSamples() != fHWNumRasterSamples) {
-                SkASSERT(rt->numStencilSamples() <= this->caps()->maxRasterSamples());
-                GL_CALL(RasterSamples(rt->numStencilSamples(), GR_GL_TRUE));
-                fHWNumRasterSamples = rt->numStencilSamples();
+            int numStencilSamples = rt->numStencilSamples();
+            // convert to GL's understanding of sample counts where 0 means nonMSAA.
+            numStencilSamples = 1 == numStencilSamples ? 0 : numStencilSamples;
+            if (numStencilSamples != fHWNumRasterSamples) {
+                SkASSERT(numStencilSamples <= this->caps()->maxRasterSamples());
+                GL_CALL(RasterSamples(numStencilSamples, GR_GL_TRUE));
+                fHWNumRasterSamples = numStencilSamples;
             }
         } else {
             if (kNo_TriState != fHWRasterMultisampleEnabled) {
@@ -3334,8 +3341,8 @@
         }
     }
     if (GrGLCaps::kResolveMustBeFull_BlitFrambufferFlag & blitFramebufferFlags) {
-        if (srcRT && srcRT->numColorSamples()) {
-            if (dstRT && !dstRT->numColorSamples()) {
+        if (srcRT && srcRT->numColorSamples() > 1) {
+            if (dstRT && 1 == dstRT->numColorSamples()) {
                 return false;
             }
             if (SkRect::Make(srcRect) != srcRT->getBoundsRect()) {
@@ -3344,7 +3351,7 @@
         }
     }
     if (GrGLCaps::kNoMSAADst_BlitFramebufferFlag & blitFramebufferFlags) {
-        if (dstRT && dstRT->numColorSamples() > 0) {
+        if (dstRT && dstRT->numColorSamples() > 1) {
             return false;
         }
     }
@@ -3354,12 +3361,12 @@
         }
     } else if (GrGLCaps::kNoFormatConversionForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) {
         const GrRenderTarget* srcRT = src->asRenderTarget();
-        if (srcRT && srcRT->numColorSamples() && dst->config() != src->config()) {
+        if (srcRT && srcRT->numColorSamples() > 1 && dst->config() != src->config()) {
             return false;
         }
     }
     if (GrGLCaps::kRectsMustMatchForMSAASrc_BlitFramebufferFlag & blitFramebufferFlags) {
-        if (srcRT && srcRT->numColorSamples()) {
+        if (srcRT && srcRT->numColorSamples() > 1) {
             if (dstPoint.fX != srcRect.fLeft || dstPoint.fY != srcRect.fTop) {
                 return false;
             }
@@ -3376,7 +3383,7 @@
     // 1) It's multisampled
     // 2) We're using an extension with separate MSAA renderbuffers
     // 3) It's not FBO 0, which is special and always auto-resolves
-    return rt->numColorSamples() > 0 && glCaps.usesMSAARenderBuffers() && rt->renderFBOID() != 0;
+    return rt->numColorSamples() > 1 && glCaps.usesMSAARenderBuffers() && rt->renderFBOID() != 0;
 }
 
 static inline bool can_copy_texsubimage(const GrSurface* dst, GrSurfaceOrigin dstOrigin,
diff --git a/src/gpu/gl/GrGLRenderTarget.cpp b/src/gpu/gl/GrGLRenderTarget.cpp
index 443128d..6f3714c 100644
--- a/src/gpu/gl/GrGLRenderTarget.cpp
+++ b/src/gpu/gl/GrGLRenderTarget.cpp
@@ -224,7 +224,7 @@
     if (fTexFBOID == kUnresolvableFBOID || fTexFBOID != fRTFBOID) {
         // If the render target's FBO is external (fTexFBOID == kUnresolvableFBOID), or if we own
         // the render target's FBO (fTexFBOID == fRTFBOID) then we use the provided sample count.
-        return SkTMax(1, this->numStencilSamples());
+        return this->numStencilSamples();
     }
 
     // When fTexFBOID == fRTFBOID, we either are not using MSAA, or MSAA is auto resolving, so use
diff --git a/src/gpu/gl/GrGLStencilAttachment.cpp b/src/gpu/gl/GrGLStencilAttachment.cpp
index aa813ed..5c07a7d 100644
--- a/src/gpu/gl/GrGLStencilAttachment.cpp
+++ b/src/gpu/gl/GrGLStencilAttachment.cpp
@@ -14,7 +14,7 @@
     uint64_t size = this->width();
     size *= this->height();
     size *= fFormat.fTotalBits;
-    size *= SkTMax(1,this->numSamples());
+    size *= this->numSamples();
     return static_cast<size_t>(size / 8);
 }
 
diff --git a/src/gpu/mock/GrMockCaps.h b/src/gpu/mock/GrMockCaps.h
index edec556..1e44851 100644
--- a/src/gpu/mock/GrMockCaps.h
+++ b/src/gpu/mock/GrMockCaps.h
@@ -33,19 +33,39 @@
 
         this->applyOptionsOverrides(contextOptions);
     }
-    int getSampleCount(int /*requestCount*/, GrPixelConfig /*config*/) const override {
-        return 0;
-    }
     bool isConfigTexturable(GrPixelConfig config) const override {
         return fOptions.fConfigOptions[config].fTexturable;
     }
-    bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override {
-        return fOptions.fConfigOptions[config].fRenderable[withMSAA];
-    }
+
     bool isConfigCopyable(GrPixelConfig config) const override {
         return false;
     }
 
+    int getRenderTargetSampleCount(int requestCount, GrPixelConfig config) const override {
+        requestCount = SkTMax(requestCount, 1);
+        switch (fOptions.fConfigOptions[config].fRenderability) {
+            case GrMockOptions::ConfigOptions::Renderability::kNo:
+                return 0;
+            case GrMockOptions::ConfigOptions::Renderability::kNonMSAA:
+                return requestCount > 1 ? 0 : 1;
+            case GrMockOptions::ConfigOptions::Renderability::kMSAA:
+                return requestCount > kMaxSampleCnt ? 0 : GrNextPow2(requestCount);
+        }
+        return 0;
+    }
+
+    int maxRenderTargetSampleCount(GrPixelConfig config) const override {
+        switch (fOptions.fConfigOptions[config].fRenderability) {
+            case GrMockOptions::ConfigOptions::Renderability::kNo:
+                return 0;
+            case GrMockOptions::ConfigOptions::Renderability::kNonMSAA:
+                return 1;
+            case GrMockOptions::ConfigOptions::Renderability::kMSAA:
+                return kMaxSampleCnt;
+        }
+        return 0;
+    }
+
     bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
                             bool* rectsMustMatch, bool* disallowSubrect) const override {
         return false;
@@ -62,6 +82,8 @@
     }
 
 private:
+    static const int kMaxSampleCnt = 16;
+
     GrMockOptions fOptions;
     typedef GrCaps INHERITED;
 };
diff --git a/src/gpu/mock/GrMockTexture.h b/src/gpu/mock/GrMockTexture.h
index 9b6501a..b5cc4a2 100644
--- a/src/gpu/mock/GrMockTexture.h
+++ b/src/gpu/mock/GrMockTexture.h
@@ -90,8 +90,11 @@
     }
 
     size_t onGpuMemorySize() const override {
-        // The plus 1 is to account for the resolve texture.
-        int numColorSamples = this->numColorSamples() + 1;
+        int numColorSamples = this->numColorSamples();
+        if (numColorSamples > 1) {
+            // Add one to account for the resolve buffer.
+            ++numColorSamples;
+        }
         return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
                                       numColorSamples,
                                       this->texturePriv().mipMapped());
diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h
index 6204eaa..935cb07 100644
--- a/src/gpu/mtl/GrMtlCaps.h
+++ b/src/gpu/mtl/GrMtlCaps.h
@@ -24,20 +24,12 @@
     GrMtlCaps(const GrContextOptions& contextOptions, id<MTLDevice> device,
               MTLFeatureSet featureSet);
 
-    int getSampleCount(int requestedCount, GrPixelConfig config) const override;
-
     bool isConfigTexturable(GrPixelConfig config) const override {
         return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kTextureable_Flag);
     }
 
-    bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override {
-        if (withMSAA) {
-            return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag) &&
-                   SkToBool(fConfigTable[config].fFlags & ConfigInfo::kMSAA_Flag);
-        } else {
-            return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag);
-        }
-    }
+    int getRenderTargetSampleCount(int requestedCount, GrPixelConfig) const override;
+    int maxRenderTargetSampleCount(GrPixelConfig) const override;
 
     bool isConfigCopyable(GrPixelConfig config) const override {
         return true;
diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm
index 2bce74a..0bb7530 100644
--- a/src/gpu/mtl/GrMtlCaps.mm
+++ b/src/gpu/mtl/GrMtlCaps.mm
@@ -121,7 +121,7 @@
     fMaxTextureSize = fMaxRenderTargetSize;
 
     // Init sample counts. All devices support 1 (i.e. 0 in skia).
-    fSampleCounts.push(0);
+    fSampleCounts.push(1);
     for (auto sampleCnt : {2, 4, 8}) {
         if ([device supportsTextureSampleCount:sampleCnt]) {
             fSampleCounts.push(sampleCnt);
@@ -164,19 +164,29 @@
     fCrossContextTextureSupport = false;
 }
 
-int GrMtlCaps::getSampleCount(int requestedCount, GrPixelConfig config) const {
-    int count = fSampleCounts.count();
-    SkASSERT(count > 0); // We always add 0 as a valid sample count
-    if (!this->isConfigRenderable(config, true)) {
-        return 0;
-    }
 
-    for (int i = 0; i < count; ++i) {
-        if (fSampleCounts[i] >= requestedCount) {
-            return fSampleCounts[i];
-        }
+int GrMtlCaps::maxRenderTargetSampleCount(GrPixelConfig config) const {
+    if (fConfigTable[config].fFlags & ConfigInfo::kMSAA_Flag) {
+        return fSampleCounts[fSampleCounts.count() - 1];
+    } else if (fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag) {
+        return 1;
     }
-    return fSampleCounts[count-1];
+    return 0;
+}
+
+int GrMtlCaps::getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const {
+    requestedCount = SkTMax(requestedCount, 1);
+    if (fConfigTable[config].fFlags & ConfigInfo::kMSAA_Flag) {
+        int count = fSampleCounts.count();
+        for (int i = 0; i < count; ++i) {
+            if (fSampleCounts[i] >= requestedCount) {
+                return fSampleCounts[i];
+            }
+        }
+    } else if (fConfigTable[config].fFlags & ConfigInfo::kRenderable_Flag) {
+        return 1 == requestedCount ? 1 : 0;
+    }
+    return 0;
 }
 
 void GrMtlCaps::initShaderCaps() {
diff --git a/src/gpu/mtl/GrMtlRenderTarget.h b/src/gpu/mtl/GrMtlRenderTarget.h
index 4dac306..83e7d3c 100644
--- a/src/gpu/mtl/GrMtlRenderTarget.h
+++ b/src/gpu/mtl/GrMtlRenderTarget.h
@@ -63,8 +63,11 @@
 
     // This accounts for the texture's memory and any MSAA renderbuffer's memory.
     size_t onGpuMemorySize() const override {
+        int numColorSamples = this->numColorSamples();
         // The plus 1 is to account for the resolve texture or if not using msaa the RT itself
-        int numColorSamples = this->numColorSamples() + 1;
+        if (numColorSamples > 1) {
+            ++numColorSamples;
+        }
         return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
                                       numColorSamples, GrMipMapped::kNo);
     }
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 0ae7c00..8af8119 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -346,7 +346,7 @@
                                                                  &properties));
     VkSampleCountFlags flags = properties.sampleCounts;
     if (flags & VK_SAMPLE_COUNT_1_BIT) {
-        fColorSampleCounts.push(0);
+        fColorSampleCounts.push(1);
     }
     if (kImagination_VkVendor == physProps.vendorID) {
         // MSAA does not work on imagination
@@ -386,18 +386,34 @@
     }
 }
 
-int GrVkCaps::getSampleCount(int requestedCount, GrPixelConfig config) const {
+int GrVkCaps::getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const {
+    requestedCount = SkTMax(1, requestedCount);
     int count = fConfigTable[config].fColorSampleCounts.count();
-    if (!count || !this->isConfigRenderable(config, true)) {
+
+    if (!count) {
         return 0;
     }
 
+    if (1 == requestedCount) {
+        SkASSERT(fConfigTable[config].fColorSampleCounts.count() &&
+                 fConfigTable[config].fColorSampleCounts[0] == 1);
+        return 1;
+    }
+
     for (int i = 0; i < count; ++i) {
         if (fConfigTable[config].fColorSampleCounts[i] >= requestedCount) {
             return fConfigTable[config].fColorSampleCounts[i];
         }
     }
-    return fConfigTable[config].fColorSampleCounts[count-1];
+    return 0;
+}
+
+int GrVkCaps::maxRenderTargetSampleCount(GrPixelConfig config) const {
+    const auto& table = fConfigTable[config].fColorSampleCounts;
+    if (!table.count()) {
+        return 0;
+    }
+    return table[table.count() - 1];
 }
 
 bool validate_image_info(const GrVkImageInfo* imageInfo, SkColorType ct, GrPixelConfig* config) {
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index d63c2ba..3449dd2 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -29,20 +29,17 @@
     GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
              VkPhysicalDevice device, uint32_t featureFlags, uint32_t extensionFlags);
 
-    int getSampleCount(int requestedCount, GrPixelConfig config) const override;
-
     bool isConfigTexturable(GrPixelConfig config) const override {
         return SkToBool(ConfigInfo::kTextureable_Flag & fConfigTable[config].fOptimalFlags);
     }
 
-    bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override {
-        return SkToBool(ConfigInfo::kRenderable_Flag & fConfigTable[config].fOptimalFlags);
-    }
-
     bool isConfigCopyable(GrPixelConfig config) const override {
         return true;
     }
 
+    int getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const override;
+    int maxRenderTargetSampleCount(GrPixelConfig config) const override;
+
     bool isConfigTexturableLinearly(GrPixelConfig config) const {
         return SkToBool(ConfigInfo::kTextureable_Flag & fConfigTable[config].fLinearFlags);
     }
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index f7e3d47..362ac1f 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -352,7 +352,7 @@
     tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig;
     tempDrawInfo->fTempSurfaceDesc.fWidth = width;
     tempDrawInfo->fTempSurfaceDesc.fHeight = height;
-    tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 0;
+    tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1;
     tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
 
     if (dstSurface->config() == srcConfig) {
@@ -777,17 +777,7 @@
     bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
 
     VkFormat pixelFormat;
-    if (!GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat)) {
-        return nullptr;
-    }
-
-    if (!fVkCaps->isConfigTexturable(desc.fConfig)) {
-        return nullptr;
-    }
-
-    if (renderTarget && !fVkCaps->isConfigRenderable(desc.fConfig, false)) {
-        return nullptr;
-    }
+    SkAssertResult(GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat));
 
     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
     if (renderTarget) {
@@ -914,7 +904,7 @@
     surfDesc.fWidth = backendTex.width();
     surfDesc.fHeight = backendTex.height();
     surfDesc.fConfig = backendTex.config();
-    surfDesc.fSampleCnt = 0;
+    surfDesc.fSampleCnt = 1;
 
     return GrVkTexture::MakeWrappedTexture(this, surfDesc, ownership, backendTex.getVkImageInfo());
 }
@@ -932,7 +922,7 @@
     surfDesc.fWidth = backendTex.width();
     surfDesc.fHeight = backendTex.height();
     surfDesc.fConfig = backendTex.config();
-    surfDesc.fSampleCnt = this->caps()->getSampleCount(sampleCnt, backendTex.config());
+    surfDesc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config());
 
     return GrVkTextureRenderTarget::MakeWrappedTextureRenderTarget(this, surfDesc, ownership,
                                                                    backendTex.getVkImageInfo());
@@ -943,7 +933,7 @@
     // general this is not an issue since swapchain images in vulkan are never multisampled. Thus if
     // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
     // creating and owning the MSAA images.
-    if (backendRT.sampleCnt()) {
+    if (backendRT.sampleCnt() > 1) {
         return nullptr;
     }
 
@@ -961,7 +951,7 @@
     desc.fWidth = backendRT.width();
     desc.fHeight = backendRT.height();
     desc.fConfig = backendRT.config();
-    desc.fSampleCnt = 0;
+    desc.fSampleCnt = 1;
 
     sk_sp<GrVkRenderTarget> tgt = GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, info);
     if (tgt && backendRT.stencilBits()) {
@@ -989,7 +979,10 @@
     desc.fWidth = tex.width();
     desc.fHeight = tex.height();
     desc.fConfig = tex.config();
-    desc.fSampleCnt = this->caps()->getSampleCount(sampleCnt, tex.config());
+    desc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, tex.config());
+    if (!desc.fSampleCnt) {
+        return nullptr;
+    }
 
     sk_sp<GrVkRenderTarget> tgt = GrVkRenderTarget::MakeWrappedRenderTarget(this, desc, info);
     return tgt;
@@ -1188,7 +1181,7 @@
         return GrBackendTexture(); // invalid
     }
 
-    if (isRenderTarget && !fVkCaps->isConfigRenderable(config, false)) {
+    if (isRenderTarget && !fVkCaps->isConfigRenderable(config)) {
         return GrBackendTexture(); // invalid
     }
 
@@ -1796,7 +1789,7 @@
                                 const GrSurface* src, GrSurfaceOrigin srcOrigin,
                                 const GrVkGpu* gpu) {
     // Our src must be a multisampled render target
-    if (!src->asRenderTarget() || src->asRenderTarget()->numColorSamples() <= 1) {
+    if (!src->asRenderTarget() || 1 == src->asRenderTarget()->numColorSamples()) {
         return false;
     }
 
@@ -1894,7 +1887,7 @@
     tempDrawInfo->fTempSurfaceDesc.fFlags = kRenderTarget_GrSurfaceFlag;
     tempDrawInfo->fTempSurfaceDesc.fWidth = width;
     tempDrawInfo->fTempSurfaceDesc.fHeight = height;
-    tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 0;
+    tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1;
     tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin; // no CPU y-flip for TL.
     tempDrawInfo->fTempSurfaceFit = SkBackingFit::kApprox;
 
diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp
index c5a8628..2a745ed 100644
--- a/src/gpu/vk/GrVkRenderTarget.cpp
+++ b/src/gpu/vk/GrVkRenderTarget.cpp
@@ -39,7 +39,7 @@
     , fResolveAttachmentView(resolveAttachmentView)
     , fFramebuffer(nullptr)
     , fCachedSimpleRenderPass(nullptr) {
-    SkASSERT(desc.fSampleCnt);
+    SkASSERT(desc.fSampleCnt > 1);
     this->createFramebuffer(gpu);
     this->registerWithCache(budgeted);
 }
@@ -62,7 +62,7 @@
     , fResolveAttachmentView(resolveAttachmentView)
     , fFramebuffer(nullptr)
     , fCachedSimpleRenderPass(nullptr) {
-    SkASSERT(desc.fSampleCnt);
+    SkASSERT(desc.fSampleCnt > 1);
     this->createFramebuffer(gpu);
 }
 
@@ -82,7 +82,7 @@
     , fResolveAttachmentView(nullptr)
     , fFramebuffer(nullptr)
     , fCachedSimpleRenderPass(nullptr) {
-    SkASSERT(!desc.fSampleCnt);
+    SkASSERT(1 == desc.fSampleCnt);
     this->createFramebuffer(gpu);
     this->registerWithCache(budgeted);
 }
@@ -102,7 +102,7 @@
     , fResolveAttachmentView(nullptr)
     , fFramebuffer(nullptr)
     , fCachedSimpleRenderPass(nullptr) {
-    SkASSERT(!desc.fSampleCnt);
+    SkASSERT(1 == desc.fSampleCnt);
     this->createFramebuffer(gpu);
 }
 
@@ -121,7 +121,7 @@
     // create msaa surface if necessary
     GrVkImageInfo msInfo;
     const GrVkImageView* resolveAttachmentView = nullptr;
-    if (desc.fSampleCnt) {
+    if (desc.fSampleCnt > 1) {
         GrVkImage::ImageDesc msImageDesc;
         msImageDesc.fImageType = VK_IMAGE_TYPE_2D;
         msImageDesc.fFormat = pixelFormat;
@@ -158,7 +158,7 @@
     const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat,
                                                                      GrVkImageView::kColor_Type, 1);
     if (!colorAttachmentView) {
-        if (desc.fSampleCnt) {
+        if (desc.fSampleCnt > 1) {
             resolveAttachmentView->unref(gpu);
             GrVkImage::DestroyImageInfo(gpu, &msInfo);
         }
@@ -166,7 +166,7 @@
     }
 
     GrVkRenderTarget* texRT;
-    if (desc.fSampleCnt) {
+    if (desc.fSampleCnt > 1) {
         texRT = new GrVkRenderTarget(gpu, budgeted, desc, info, msInfo,
                                      colorAttachmentView, resolveAttachmentView, ownership);
     } else {
@@ -237,11 +237,10 @@
 void GrVkRenderTarget::getAttachmentsDescriptor(
                                            GrVkRenderPass::AttachmentsDescriptor* desc,
                                            GrVkRenderPass::AttachmentFlags* attachmentFlags) const {
-    int colorSamples = this->numColorSamples();
     VkFormat colorFormat;
     GrPixelConfigToVkFormat(this->config(), &colorFormat);
     desc->fColor.fFormat = colorFormat;
-    desc->fColor.fSamples = colorSamples ? colorSamples : 1;
+    desc->fColor.fSamples = this->numColorSamples();
     *attachmentFlags = GrVkRenderPass::kColor_AttachmentFlag;
     uint32_t attachmentCount = 1;
 
@@ -249,7 +248,7 @@
     if (stencil) {
         const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
         desc->fStencil.fFormat = vkStencil->vkFormat();
-        desc->fStencil.fSamples = vkStencil->numSamples() ? vkStencil->numSamples() : 1;
+        desc->fStencil.fSamples = vkStencil->numSamples();
         // Currently in vulkan stencil and color attachments must all have same number of samples
         SkASSERT(desc->fColor.fSamples == desc->fStencil.fSamples);
         *attachmentFlags |= GrVkRenderPass::kStencil_AttachmentFlag;
diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h
index eb297a8..02d4add 100644
--- a/src/gpu/vk/GrVkRenderTarget.h
+++ b/src/gpu/vk/GrVkRenderTarget.h
@@ -99,8 +99,11 @@
 
     // This accounts for the texture's memory and any MSAA renderbuffer's memory.
     size_t onGpuMemorySize() const override {
-        // The plus 1 is to account for the resolve texture or if not using msaa the RT itself
-        int numColorSamples = this->numColorSamples() + 1;
+        int numColorSamples = this->numColorSamples();
+        if (numColorSamples > 1) {
+            // Add one to account for the resolved VkImage.
+            numColorSamples += 1;
+        }
         return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
                                       numColorSamples, GrMipMapped::kNo);
     }
diff --git a/src/gpu/vk/GrVkStencilAttachment.cpp b/src/gpu/vk/GrVkStencilAttachment.cpp
index 5348885..139c00f 100644
--- a/src/gpu/vk/GrVkStencilAttachment.cpp
+++ b/src/gpu/vk/GrVkStencilAttachment.cpp
@@ -72,7 +72,7 @@
     uint64_t size = this->width();
     size *= this->height();
     size *= fFormat.fTotalBits;
-    size *= SkTMax(1,this->numSamples());
+    size *= this->numSamples();
     return static_cast<size_t>(size / 8);
 }
 
diff --git a/src/gpu/vk/GrVkTextureRenderTarget.cpp b/src/gpu/vk/GrVkTextureRenderTarget.cpp
index 9a211e2..ee31f23 100644
--- a/src/gpu/vk/GrVkTextureRenderTarget.cpp
+++ b/src/gpu/vk/GrVkTextureRenderTarget.cpp
@@ -106,7 +106,7 @@
     // create msaa surface if necessary
     GrVkImageInfo msInfo;
     const GrVkImageView* resolveAttachmentView = nullptr;
-    if (desc.fSampleCnt) {
+    if (desc.fSampleCnt > 1) {
         GrVkImage::ImageDesc msImageDesc;
         msImageDesc.fImageType = VK_IMAGE_TYPE_2D;
         msImageDesc.fFormat = pixelFormat;
@@ -145,7 +145,7 @@
     const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat,
                                                                      GrVkImageView::kColor_Type, 1);
     if (!colorAttachmentView) {
-        if (desc.fSampleCnt) {
+        if (desc.fSampleCnt > 1) {
             resolveAttachmentView->unref(gpu);
             GrVkImage::DestroyImageInfo(gpu, &msInfo);
         }
@@ -154,7 +154,7 @@
     }
 
     sk_sp<GrVkTextureRenderTarget> texRT;
-    if (desc.fSampleCnt) {
+    if (desc.fSampleCnt > 1) {
         if (!isWrapped) {
             texRT = sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget(
                                                       gpu, budgeted, desc,
@@ -232,7 +232,7 @@
 bool GrVkTextureRenderTarget::updateForMipmap(GrVkGpu* gpu, const GrVkImageInfo& newInfo) {
     VkFormat pixelFormat;
     GrPixelConfigToVkFormat(this->config(), &pixelFormat);
-    if (this->numStencilSamples()) {
+    if (this->numStencilSamples() > 1) {
         const GrVkImageView* resolveAttachmentView =
                 GrVkImageView::Create(gpu,
                                       newInfo.fImage,
@@ -262,8 +262,11 @@
 }
 
 size_t GrVkTextureRenderTarget::onGpuMemorySize() const {
-    // The plus 1 is to account for the resolve texture.
-    int numColorSamples = this->numColorSamples() + 1;
+    int numColorSamples = this->numColorSamples();
+    if (numColorSamples > 1) {
+        // Add one to account for the resolve VkImage.
+        ++numColorSamples;
+    }
     return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
                                   numColorSamples,  // TODO: this still correct?
                                   this->texturePriv().mipMapped());
diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp
index cb0046e..12db4c1 100644
--- a/src/gpu/vk/GrVkUtil.cpp
+++ b/src/gpu/vk/GrVkUtil.cpp
@@ -263,8 +263,8 @@
 }
 
 bool GrSampleCountToVkSampleCount(uint32_t samples, VkSampleCountFlagBits* vkSamples) {
+    SkASSERT(samples >= 1);
     switch (samples) {
-        case 0: // fall through
         case 1:
             *vkSamples = VK_SAMPLE_COUNT_1_BIT;
             return true;
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index c00c50d..a136c7b 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -438,13 +438,8 @@
 
     // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
     sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext(
-                                                                         SkBackingFit::kExact,
-                                                                         width, height,
-                                                                         kRGBA_8888_GrPixelConfig,
-                                                                         std::move(imageColorSpace),
-                                                                         0,
-                                                                         GrMipMapped::kNo,
-                                                                         origin));
+            SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig,
+            std::move(imageColorSpace), 1, GrMipMapped::kNo, origin));
     if (!renderTargetContext) {
         return nullptr;
     }
diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp
index ed46835..92d3a2f 100644
--- a/src/image/SkImage_Lazy.cpp
+++ b/src/image/SkImage_Lazy.cpp
@@ -267,9 +267,8 @@
 
 #if SK_SUPPORT_GPU
     bool supportsHalfFloat() const {
-        return !fCaps ||
-            (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) &&
-             fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig, false));
+        return !fCaps || (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) &&
+                          fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig));
     }
 
     bool supportsSRGB() const {
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index 0a684cc..ef6d809 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -247,8 +247,8 @@
 
 #if !SK_SUPPORT_GPU
 
-sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext*, SkBudgeted, const SkImageInfo&,
-                                             int, GrSurfaceOrigin, const SkSurfaceProps*, bool) {
+sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext*, SkBudgeted, const SkImageInfo&, int,
+                                             GrSurfaceOrigin, const SkSurfaceProps*, bool) {
     return nullptr;
 }
 
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 9f7ec3b..ff66844 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -256,7 +256,7 @@
     if (!SkSurface_Gpu::Valid(info)) {
         return nullptr;
     }
-
+    sampleCount = SkTMax(1, sampleCount);
     GrMipMapped mipMapped = shouldCreateWithMips ? GrMipMapped::kYes : GrMipMapped::kNo;
 
     if (!ctx->caps()->mipMapSupport()) {
@@ -299,6 +299,7 @@
     if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) {
         return nullptr;
     }
+    sampleCnt = SkTMax(1, sampleCnt);
 
     sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeBackendTextureRenderTargetContext(
                                                                     tex,
@@ -333,11 +334,9 @@
         return false;
     }
 
-    if (!ctx->caps()->isConfigRenderable(*config, sampleCnt > 0)) {
-        return false;
-    }
-
-    if (ctx->caps()->getSampleCount(sampleCnt, *config) != sampleCnt) {
+    // We don't require that the client gave us an exact valid sample cnt. However, it must be
+    // less than the max supported sample count and 1 if MSAA is unsupported for the color type.
+    if (!ctx->caps()->getRenderTargetSampleCount(sampleCnt, *config)) {
         return false;
     }
 
@@ -355,6 +354,7 @@
     if (!context) {
         return nullptr;
     }
+    sampleCnt = SkTMax(1, sampleCnt);
     GrBackendTexture texCopy = tex;
     if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
                                   sampleCnt, colorType, colorSpace, true)) {
@@ -409,7 +409,11 @@
         return false;
     }
 
-    if (!ctx->caps()->isConfigRenderable(*config, false)) {
+    if (rt.sampleCnt() > 1) {
+        if (ctx->caps()->maxRenderTargetSampleCount(*config) <= 1) {
+            return false;
+        }
+    } else if (!ctx->caps()->isConfigRenderable(*config)) {
         return false;
     }
 
@@ -445,6 +449,7 @@
     if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) {
         return nullptr;
     }
+    sampleCnt = SkTMax(1, sampleCnt);
 
     sk_sp<GrRenderTargetContext> rtc(
         context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext(
@@ -475,6 +480,7 @@
     if (!context) {
         return nullptr;
     }
+    sampleCnt = SkTMax(1, sampleCnt);
     GrBackendTexture texCopy = tex;
     if (!validate_backend_texture(context, texCopy, &texCopy.fConfig,
                                   sampleCnt, colorType, colorSpace, false)) {
diff --git a/src/utils/win/SkWGL.h b/src/utils/win/SkWGL.h
index c6c9479..cd19f2e 100644
--- a/src/utils/win/SkWGL.h
+++ b/src/utils/win/SkWGL.h
@@ -83,7 +83,8 @@
      * priority are:
      *     * Choose formats with the smallest sample count that is >=
      *       desiredSampleCount (or the largest sample count if all formats have
-     *       fewer samples than desiredSampleCount.)
+     *       fewer samples than desiredSampleCount.) If desiredSampleCount is 1 then
+     *       all msaa formats are excluded from consideration.
      *     * Choose formats with the fewest color samples when coverage sampling
      *       is available.
      *     * If the above rules leave multiple formats, choose the one that
@@ -130,8 +131,9 @@
 /**
  * Helper to create an OpenGL context for a DC using WGL. Configs with a sample count >= to
  * msaaSampleCount are preferred but if none is available then a context with a lower sample count
- * (including non-MSAA) will be created. If preferCoreProfile is true but a core profile cannot be
- * created then a compatible profile context will be created.
+ * (including non-MSAA) will be created. If msaaSampleCount is 1 then this will fail if a non-msaa
+ * context cannot be created. If preferCoreProfile is true but a core profile cannot be created
+ * then a compatible profile context will be created.
  */
 HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor, SkWGLContextRequest context,
                          HGLRC shareContext = nullptr);
diff --git a/src/utils/win/SkWGL_win.cpp b/src/utils/win/SkWGL_win.cpp
index b7c8994..441d7a4 100644
--- a/src/utils/win/SkWGL_win.cpp
+++ b/src/utils/win/SkWGL_win.cpp
@@ -126,6 +126,7 @@
                                   int formatCount,
                                   HDC dc,
                                   int desiredSampleCount) const {
+    SkASSERT(desiredSampleCount >= 1);
     if (formatCount <= 0) {
         return -1;
     }
@@ -146,7 +147,7 @@
                                      &kQueryAttr,
                                      &numSamples);
         rankedFormats[i].fFormat =  formats[i];
-        rankedFormats[i].fSampleCnt = numSamples;
+        rankedFormats[i].fSampleCnt = SkTMax(1, numSamples);
         rankedFormats[i].fChoosePixelFormatRank = i;
     }
     SkTQSort(rankedFormats.begin(),
@@ -159,6 +160,10 @@
     if (idx < 0) {
         idx = ~idx;
     }
+    // If the caller asked for non-MSAA fail if the closest format has MSAA.
+    if (desiredSampleCount == 1 && rankedFormats[idx].fSampleCnt != 1) {
+        return -1;
+    }
     return rankedFormats[idx].fFormat;
 }
 
diff --git a/tests/BlendTest.cpp b/tests/BlendTest.cpp
index b17b9f1..3ac7e3c 100644
--- a/tests/BlendTest.cpp
+++ b/tests/BlendTest.cpp
@@ -140,7 +140,7 @@
     std::vector<TestCase> testCases;
 
     for (auto origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
-        for (int sampleCnt : {0, 4}) {
+        for (int sampleCnt : {1, 4}) {
             for (auto rectAndPoints : allRectsAndPoints) {
                 for (auto clip : {SkRect::MakeXYWH(0, 0, 10, 10), SkRect::MakeXYWH(1, 1, 8, 8)}) {
                     testCases.push_back({rectAndPoints, clip, sampleCnt, origin});
@@ -162,7 +162,7 @@
         sk_sp<SkSurface> surface = create_gpu_surface_backend_texture_as_render_target(
                 context, sampleCnt, kWidth, kHeight, kColorType, kConfig, origin, &backingSurface);
 
-        if (!surface && sampleCnt > 0) {
+        if (!surface && sampleCnt > 1) {
             // Some platforms don't support MSAA.
             continue;
         }
diff --git a/tests/DeferredDisplayListTest.cpp b/tests/DeferredDisplayListTest.cpp
index 049b971..b3637cb 100644
--- a/tests/DeferredDisplayListTest.cpp
+++ b/tests/DeferredDisplayListTest.cpp
@@ -31,9 +31,8 @@
             , fOrigin(kTopLeft_GrSurfaceOrigin)
             , fColorType(kRGBA_8888_SkColorType)
             , fColorSpace(SkColorSpace::MakeSRGB())
-            , fSampleCount(0)
-            , fSurfaceProps(0x0, kUnknown_SkPixelGeometry) {
-    }
+            , fSampleCount(1)
+            , fSurfaceProps(0x0, kUnknown_SkPixelGeometry) {}
 
     int sampleCount() const { return fSampleCount; }
 
@@ -138,10 +137,10 @@
         if (SurfaceParameters::kSampleCount == i) {
             SkSurface_Gpu* gpuSurf = static_cast<SkSurface_Gpu*>(s.get());
 
-            int supportedSampleCount = context->caps()->getSampleCount(
+            int supportedSampleCount = context->caps()->getRenderTargetSampleCount(
                 params.sampleCount(),
                 gpuSurf->getDevice()->accessRenderTargetContext()->asRenderTargetProxy()->config());
-            if (0 == supportedSampleCount) {
+            if (1 == supportedSampleCount) {
                 // If changing the sample count won't result in a different
                 // surface characterization, skip this step
                 continue;
diff --git a/tests/DeviceTest.cpp b/tests/DeviceTest.cpp
index 64b83fc..58369cc 100644
--- a/tests/DeviceTest.cpp
+++ b/tests/DeviceTest.cpp
@@ -81,7 +81,7 @@
     SkImageInfo ii = SkImageInfo::MakeN32Premul(2*kWidth, 2*kHeight);
 
     sk_sp<SkBaseDevice> gpuDev(SkGpuDevice::Make(context, SkBudgeted::kNo, ii,
-                                                 0, kBottomLeft_GrSurfaceOrigin, nullptr,
+                                                 1, kBottomLeft_GrSurfaceOrigin, nullptr,
                                                  GrMipMapped::kNo,
                                                  SkGpuDevice::kClear_InitContents));
 
diff --git a/tests/EGLImageTest.cpp b/tests/EGLImageTest.cpp
index dac78a8..b0631d0 100644
--- a/tests/EGLImageTest.cpp
+++ b/tests/EGLImageTest.cpp
@@ -163,7 +163,7 @@
     {
         sk_sp<GrRenderTargetContext> temp =
                 context0->contextPriv().makeBackendTextureRenderTargetContext(
-                        backendTex, kBottomLeft_GrSurfaceOrigin, 0, nullptr);
+                        backendTex, kBottomLeft_GrSurfaceOrigin, 1, nullptr);
         if (temp) {
             ERRORF(reporter, "Should not be able to wrap an EXTERNAL texture as a RT.");
         }
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index 6c2e8d2..f625a77 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -150,7 +150,10 @@
                                                                  const GrCaps* caps) {
     GrSurfaceOrigin origin = random->nextBool() ? kTopLeft_GrSurfaceOrigin
                                                 : kBottomLeft_GrSurfaceOrigin;
-    int sampleCnt = random->nextBool() ? caps->getSampleCount(4, kRGBA_8888_GrPixelConfig) : 0;
+    int sampleCnt =
+            random->nextBool() ? caps->getRenderTargetSampleCount(2, kRGBA_8888_GrPixelConfig) : 1;
+    // Above could be 0 if msaa isn't supported.
+    sampleCnt = SkTMax(1, sampleCnt);
 
     sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext(
                                                                            SkBackingFit::kExact,
diff --git a/tests/GpuDrawPathTest.cpp b/tests/GpuDrawPathTest.cpp
index 012dc61..79afa63 100644
--- a/tests/GpuDrawPathTest.cpp
+++ b/tests/GpuDrawPathTest.cpp
@@ -78,7 +78,7 @@
 
 DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(GpuDrawPath, reporter, ctxInfo) {
     for (auto& test_func : { &test_drawPathEmpty, &test_drawSameRectOvals }) {
-        for (auto& sampleCount : {0, 4, 16}) {
+        for (auto& sampleCount : {1, 4, 16}) {
             SkImageInfo info = SkImageInfo::MakeN32Premul(255, 255);
             auto surface(
                 SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kNo, info,
diff --git a/tests/GpuSampleLocationsTest.cpp b/tests/GpuSampleLocationsTest.cpp
index de15e03..56764cf 100644
--- a/tests/GpuSampleLocationsTest.cpp
+++ b/tests/GpuSampleLocationsTest.cpp
@@ -109,22 +109,36 @@
     }
 }
 
+static int pick_random_sample_count(int testPatternSize, SkRandom* rand, const GrCaps* caps) {
+    GrAlwaysAssert(testPatternSize > 1 && SkIsPow2(testPatternSize));
+    int randSampCnt = rand->nextRangeU(1 + testPatternSize / 2, testPatternSize);
+    do {
+        int cnt = caps->getRenderTargetSampleCount(randSampCnt, kRGBA_8888_GrPixelConfig);
+        if (cnt) {
+            return cnt;
+        }
+        --randSampCnt;
+    } while (randSampCnt);
+    // This test assumes an MSAA kRGBA_8888 RTC can be created.
+    GrAlwaysAssert(false);
+    return 0;
+}
+
 void test_sampleLocations(skiatest::Reporter* reporter, TestSampleLocationsInterface* testInterface,
                           GrContext* ctx) {
     SkRandom rand;
     sk_sp<GrRenderTargetContext> bottomUps[numTestPatterns];
     sk_sp<GrRenderTargetContext> topDowns[numTestPatterns];
     for (int i = 0; i < numTestPatterns; ++i) {
-        int numSamples = (int)kTestPatterns[i].size();
-        GrAlwaysAssert(numSamples > 1 && SkIsPow2(numSamples));
+        int patternSize = (int)kTestPatterns[i].size();
+        int randNumSamples = pick_random_sample_count(patternSize, &rand, ctx->caps());
         bottomUps[i] = ctx->makeDeferredRenderTargetContext(
-                           SkBackingFit::kExact, 100, 100, kRGBA_8888_GrPixelConfig, nullptr,
-                           rand.nextRangeU(1 + numSamples / 2, numSamples), GrMipMapped::kNo,
-                           kBottomLeft_GrSurfaceOrigin);
+                SkBackingFit::kExact, 100, 100, kRGBA_8888_GrPixelConfig, nullptr, randNumSamples,
+                GrMipMapped::kNo, kBottomLeft_GrSurfaceOrigin);
+        randNumSamples = pick_random_sample_count(patternSize, &rand, ctx->caps());
         topDowns[i] = ctx->makeDeferredRenderTargetContext(
-                          SkBackingFit::kExact, 100, 100, kRGBA_8888_GrPixelConfig, nullptr,
-                          rand.nextRangeU(1 + numSamples / 2, numSamples), GrMipMapped::kNo,
-                          kTopLeft_GrSurfaceOrigin);
+                SkBackingFit::kExact, 100, 100, kRGBA_8888_GrPixelConfig, nullptr, randNumSamples,
+                GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
     }
 
     // Ensure all sample locations get queried and/or cached properly.
@@ -189,7 +203,7 @@
     sk_sp<GrContext> ctx(GrContext::MakeGL(testInterface));
 
     // This test relies on at least 2 samples.
-    int supportedSample = ctx->caps()->getSampleCount(2, kRGBA_8888_GrPixelConfig);
+    int supportedSample = ctx->caps()->getRenderTargetSampleCount(2, kRGBA_8888_GrPixelConfig);
     if (supportedSample < 2) {
         return;
     }
diff --git a/tests/GrCCPRTest.cpp b/tests/GrCCPRTest.cpp
index 9f770d6..cba94b4 100644
--- a/tests/GrCCPRTest.cpp
+++ b/tests/GrCCPRTest.cpp
@@ -119,7 +119,8 @@
         GrMockOptions mockOptions;
         mockOptions.fInstanceAttribSupport = true;
         mockOptions.fMapBufferFlags = GrCaps::kCanMap_MapFlag;
-        mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderable[0] = true;
+        mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderability =
+                GrMockOptions::ConfigOptions::Renderability::kNonMSAA;
         mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fTexturable = true;
         mockOptions.fGeometryShaderSupport = true;
         mockOptions.fIntegerSupport = true;
diff --git a/tests/GrSurfaceTest.cpp b/tests/GrSurfaceTest.cpp
index 3e246cc..32ac0c7 100644
--- a/tests/GrSurfaceTest.cpp
+++ b/tests/GrSurfaceTest.cpp
@@ -33,7 +33,7 @@
     desc.fWidth = 256;
     desc.fHeight = 256;
     desc.fConfig = kRGBA_8888_GrPixelConfig;
-    desc.fSampleCnt = 0;
+    desc.fSampleCnt = 1;
     sk_sp<GrSurface> texRT1 = resourceProvider->createTexture(desc, SkBudgeted::kNo);
 
     REPORTER_ASSERT(reporter, texRT1.get() == texRT1->asRenderTarget());
@@ -55,8 +55,8 @@
     GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
         nullptr, 256, 256, kRGBA_8888_GrPixelConfig, false, GrMipMapped::kNo);
 
-    sk_sp<GrSurface> texRT2 = resourceProvider->wrapRenderableBackendTexture(
-                                                    backendTex, 0, kBorrow_GrWrapOwnership);
+    sk_sp<GrSurface> texRT2 =
+            resourceProvider->wrapRenderableBackendTexture(backendTex, 1, kBorrow_GrWrapOwnership);
 
     REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asRenderTarget());
     REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asTexture());
@@ -120,7 +120,7 @@
             desc.fFlags = kNone_GrSurfaceFlags;
             desc.fOrigin = origin;
             desc.fConfig = config;
-            desc.fSampleCnt = 0;
+            desc.fSampleCnt = 1;
 
             sk_sp<GrSurface> tex = resourceProvider->createTexture(desc, SkBudgeted::kNo);
             bool ict = caps->isConfigTexturable(desc.fConfig);
@@ -143,17 +143,17 @@
 
             desc.fFlags = kRenderTarget_GrSurfaceFlag;
             tex = resourceProvider->createTexture(desc, SkBudgeted::kNo);
-            bool icr = caps->isConfigRenderable(config, false);
-            REPORTER_ASSERT(reporter, SkToBool(tex) == icr,
-                            "config:%d, tex:%d, isConfigRenderable(false):%d", config,
-                            SkToBool(tex), icr);
+            bool isRenderable = caps->isConfigRenderable(config);
+            REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
+                            "config:%d, tex:%d, isRenderable:%d", config, SkToBool(tex),
+                            isRenderable);
 
-            desc.fSampleCnt = 4;
+            desc.fSampleCnt = 2;
             tex = resourceProvider->createTexture(desc, SkBudgeted::kNo);
-            icr = caps->isConfigRenderable(config, true);
-            REPORTER_ASSERT(reporter, SkToBool(tex) == icr,
-                            "config:%d, tex:%d, isConfigRenderable(true):%d", config, SkToBool(tex),
-                            icr);
+            isRenderable = SkToBool(caps->getRenderTargetSampleCount(2, config));
+            REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
+                            "config:%d, tex:%d, isRenderable:%d", config, SkToBool(tex),
+                            isRenderable);
         }
     }
 }
@@ -178,7 +178,7 @@
         }
         desc.fFlags = kPerformInitialClear_GrSurfaceFlag;
         for (bool rt : {false, true}) {
-            if (rt && !context->caps()->isConfigRenderable(desc.fConfig, false)) {
+            if (rt && !context->caps()->isConfigRenderable(desc.fConfig)) {
                 continue;
             }
             desc.fFlags |= rt ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp
index a1472d4..9a89000 100644
--- a/tests/ImageTest.cpp
+++ b/tests/ImageTest.cpp
@@ -38,6 +38,7 @@
 #include "GrResourceCache.h"
 #include "GrTest.h"
 #include "GrTexture.h"
+#include "SkGr.h"
 #endif
 
 using namespace sk_gpu_test;
@@ -486,6 +487,29 @@
     surface->getCanvas()->drawImage(image, 0, 0);
 }
 
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrContext_colorTypeSupportedAsImage, reporter, ctxInfo) {
+    for (int ct = 0; ct < kLastEnum_SkColorType; ++ct) {
+        static constexpr int kSize = 10;
+        SkColorType colorType = static_cast<SkColorType>(ct);
+        bool can = ctxInfo.grContext()->colorTypeSupportedAsImage(colorType);
+        auto* gpu = ctxInfo.grContext()->contextPriv().getGpu();
+        GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
+                nullptr, kSize, kSize, colorType, false, GrMipMapped::kNo);
+        auto img =
+                SkImage::MakeFromTexture(ctxInfo.grContext(), backendTex, kTopLeft_GrSurfaceOrigin,
+                                         colorType, kOpaque_SkAlphaType, nullptr);
+        REPORTER_ASSERT(reporter, can == SkToBool(img),
+                        "%d, colorTypeSupportedAsImage:%d, actual:%d, ct:%d", can, SkToBool(img),
+                        colorType);
+
+        img.reset();
+        ctxInfo.grContext()->flush();
+        if (backendTex.isValid()) {
+            gpu->deleteTestingOnlyBackendTexture(&backendTex);
+        }
+    }
+}
+
 #endif
 
 class EmptyGenerator : public SkImageGenerator {
diff --git a/tests/LazyProxyTest.cpp b/tests/LazyProxyTest.cpp
index f1bffa5..5c05327 100644
--- a/tests/LazyProxyTest.cpp
+++ b/tests/LazyProxyTest.cpp
@@ -179,7 +179,8 @@
 
 DEF_GPUTEST(LazyProxyTest, reporter, /* options */) {
     GrMockOptions mockOptions;
-    mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderable[0] = true;
+    mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderability =
+            GrMockOptions::ConfigOptions::Renderability::kNonMSAA;
     mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fTexturable = true;
     sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
diff --git a/tests/PathRendererCacheTests.cpp b/tests/PathRendererCacheTests.cpp
index 15b1faa..19197b0 100644
--- a/tests/PathRendererCacheTests.cpp
+++ b/tests/PathRendererCacheTests.cpp
@@ -80,8 +80,8 @@
     GrResourceCache* cache = ctx->contextPriv().getResourceCache();
 
     sk_sp<GrRenderTargetContext> rtc(ctx->makeDeferredRenderTargetContext(
-            SkBackingFit::kApprox, 800, 800, kRGBA_8888_GrPixelConfig, nullptr, 0,
-            GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin));
+            SkBackingFit::kApprox, 800, 800, kRGBA_8888_GrPixelConfig, nullptr, 1, GrMipMapped::kNo,
+            kTopLeft_GrSurfaceOrigin));
     if (!rtc) {
         return;
     }
diff --git a/tests/ProxyTest.cpp b/tests/ProxyTest.cpp
index 0636ed4..dff230c 100644
--- a/tests/ProxyTest.cpp
+++ b/tests/ProxyTest.cpp
@@ -118,7 +118,7 @@
                                  kRGBA_8888_GrPixelConfig }) {
                 for (auto fit : { SkBackingFit::kExact, SkBackingFit::kApprox }) {
                     for (auto budgeted : { SkBudgeted::kYes, SkBudgeted::kNo }) {
-                        for (auto numSamples : { 0, 4, 16, 128 }) {
+                        for (auto numSamples : {1, 4, 16, 128}) {
                             GrSurfaceDesc desc;
                             desc.fFlags = kRenderTarget_GrSurfaceFlag;
                             desc.fOrigin = origin;
@@ -149,7 +149,8 @@
 
                                     check_surface(reporter, proxy.get(), origin,
                                                   widthHeight, widthHeight, config, budgeted);
-                                    int supportedSamples = caps.getSampleCount(numSamples, config);
+                                    int supportedSamples =
+                                            caps.getRenderTargetSampleCount(numSamples, config);
                                     check_rendertarget(reporter, caps, resourceProvider,
                                                        proxy->asRenderTargetProxy(),
                                                        supportedSamples,
@@ -204,10 +205,8 @@
     for (auto origin : { kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin }) {
         for (auto config : { kAlpha_8_GrPixelConfig, kRGBA_8888_GrPixelConfig }) {
             for (auto budgeted : { SkBudgeted::kYes, SkBudgeted::kNo }) {
-                for (auto numSamples: { 0, 4}) {
-                    int supportedNumSamples = caps.getSampleCount(numSamples, config);
-
-                    bool renderable = caps.isConfigRenderable(config, numSamples > 0);
+                for (auto numSamples : {1, 4}) {
+                    int supportedNumSamples = caps.getRenderTargetSampleCount(numSamples, config);
 
                     GrSurfaceDesc desc;
                     desc.fOrigin = origin;
@@ -217,7 +216,7 @@
                     desc.fSampleCnt = supportedNumSamples;
 
                     // External on-screen render target.
-                    if (renderable && kOpenGL_GrBackend == ctxInfo.backend()) {
+                    if (supportedNumSamples && kOpenGL_GrBackend == ctxInfo.backend()) {
                         GrGLFramebufferInfo fboInfo;
                         fboInfo.fFBOID = 0;
                         GrBackendRenderTarget backendRT(kWidthHeight, kWidthHeight, numSamples, 8,
@@ -232,7 +231,7 @@
                                            supportedNumSamples, SkBackingFit::kExact, 0, true);
                     }
 
-                    if (renderable) {
+                    if (supportedNumSamples) {
                         // Internal offscreen render target.
                         desc.fFlags = kRenderTarget_GrSurfaceFlag;
 
@@ -251,7 +250,7 @@
                     } else {
                         // Internal offscreen texture
                         SkASSERT(kNone_GrSurfaceFlags == desc.fFlags );
-                        desc.fSampleCnt = 0;
+                        desc.fSampleCnt = 1;
 
                         sk_sp<GrSurfaceProxy> sProxy = proxyProvider->createInstantiatedProxy(
                                                           desc, SkBackingFit::kExact, budgeted);
@@ -287,7 +286,7 @@
                     desc.fWidth = width;
                     desc.fHeight = height;
                     desc.fConfig = kRGBA_8888_GrPixelConfig;
-                    desc.fSampleCnt = 0;
+                    desc.fSampleCnt = 1;
 
                     sk_sp<GrTextureProxy> proxy = provider->createProxy(desc, fit, SkBudgeted::kNo);
                     REPORTER_ASSERT(reporter, !proxy);
diff --git a/tests/ResourceAllocatorTest.cpp b/tests/ResourceAllocatorTest.cpp
index 7dcb0ee..173696b 100644
--- a/tests/ResourceAllocatorTest.cpp
+++ b/tests/ResourceAllocatorTest.cpp
@@ -148,8 +148,8 @@
                      std::move(p1), std::move(p2), test.fExpectation);
     }
 
-    int k2 = ctxInfo.grContext()->caps()->getSampleCount(2, kRGBA);
-    int k4 = ctxInfo.grContext()->caps()->getSampleCount(4, kRGBA);
+    int k2 = ctxInfo.grContext()->caps()->getRenderTargetSampleCount(2, kRGBA);
+    int k4 = ctxInfo.grContext()->caps()->getRenderTargetSampleCount(4, kRGBA);
 
     //--------------------------------------------------------------------------------------------
     TestCase gNonOverlappingTests[] = {
diff --git a/tests/ResourceCacheTest.cpp b/tests/ResourceCacheTest.cpp
index 34ed4f7..3bd6c4b 100644
--- a/tests/ResourceCacheTest.cpp
+++ b/tests/ResourceCacheTest.cpp
@@ -129,21 +129,20 @@
 
     GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider();
 
-    sk_sp<GrRenderTarget> smallRT0 = create_RT_with_SB(resourceProvider, 4, 0, SkBudgeted::kYes);
+    sk_sp<GrRenderTarget> smallRT0 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kYes);
     REPORTER_ASSERT(reporter, smallRT0);
 
     {
        // Two budgeted RTs with the same desc should share a stencil buffer.
-        sk_sp<GrRenderTarget> smallRT1 = create_RT_with_SB(resourceProvider, 4, 0,
-                                                           SkBudgeted::kYes);
-        REPORTER_ASSERT(reporter, smallRT1);
+       sk_sp<GrRenderTarget> smallRT1 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kYes);
+       REPORTER_ASSERT(reporter, smallRT1);
 
-        REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) == get_SB(smallRT1.get()));
+       REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) == get_SB(smallRT1.get()));
     }
 
     {
         // An unbudgeted RT with the same desc should also share.
-        sk_sp<GrRenderTarget> smallRT2 = create_RT_with_SB(resourceProvider, 4, 0, SkBudgeted::kNo);
+        sk_sp<GrRenderTarget> smallRT2 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kNo);
         REPORTER_ASSERT(reporter, smallRT2);
 
         REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) == get_SB(smallRT2.get()));
@@ -151,14 +150,14 @@
 
     {
         // An RT with a much larger size should not share.
-        sk_sp<GrRenderTarget> bigRT = create_RT_with_SB(resourceProvider, 400, 0, SkBudgeted::kNo);
+        sk_sp<GrRenderTarget> bigRT = create_RT_with_SB(resourceProvider, 400, 1, SkBudgeted::kNo);
         REPORTER_ASSERT(reporter, bigRT);
 
         REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) != get_SB(bigRT.get()));
     }
 
-    int smallSampleCount = context->caps()->getSampleCount(4, kRGBA_8888_GrPixelConfig);
-    if (smallSampleCount > 0) {
+    int smallSampleCount = context->caps()->getRenderTargetSampleCount(2, kRGBA_8888_GrPixelConfig);
+    if (smallSampleCount > 1) {
         // An RT with a different sample count should not share.
         sk_sp<GrRenderTarget> smallMSAART0 = create_RT_with_SB(resourceProvider, 4,
                                                                smallSampleCount, SkBudgeted::kNo);
@@ -183,10 +182,11 @@
             REPORTER_ASSERT(reporter, get_SB(smallMSAART0.get()) == get_SB(smallMSAART1.get()));
         }
 
-        // But not one with a larger sample count should not. (Also check that the request for 4
-        // samples didn't get rounded up to >= 8 or else they could share.).
-        int bigSampleCount = context->caps()->getSampleCount(8, kRGBA_8888_GrPixelConfig);
-        if (bigSampleCount != smallSampleCount) {
+        // But one with a larger sample count should not. (Also check that the two requests didn't
+        // rounded up to the same actual sample count or else they could share.).
+        int bigSampleCount =
+                context->caps()->getRenderTargetSampleCount(5, kRGBA_8888_GrPixelConfig);
+        if (bigSampleCount > 0 && bigSampleCount != smallSampleCount) {
             sk_sp<GrRenderTarget> smallMSAART2 = create_RT_with_SB(resourceProvider, 4,
                                                                    bigSampleCount,
                                                                    SkBudgeted::kNo);
@@ -1707,11 +1707,12 @@
     {
         sk_sp<GrTexture> tex;
 
-        tex = make_normal_texture(resourceProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize, 0);
+        tex = make_normal_texture(resourceProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize, 1);
         size_t size = tex->gpuMemorySize();
         REPORTER_ASSERT(reporter, kSize*kSize*4 == size);
 
-        size_t sampleCount = (size_t)context->caps()->getSampleCount(4, kRGBA_8888_GrPixelConfig);
+        size_t sampleCount =
+                (size_t)context->caps()->getRenderTargetSampleCount(4, kRGBA_8888_GrPixelConfig);
         if (sampleCount >= 4) {
             tex = make_normal_texture(resourceProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize,
                                       sampleCount);
@@ -1722,7 +1723,7 @@
                             kSize*kSize*4*(sampleCount+1) == size);   // explicit resolve buffer
         }
 
-        tex = make_normal_texture(resourceProvider, kNone_GrSurfaceFlags, kSize, kSize, 0);
+        tex = make_normal_texture(resourceProvider, kNone_GrSurfaceFlags, kSize, kSize, 1);
         size = tex->gpuMemorySize();
         REPORTER_ASSERT(reporter, kSize*kSize*4 == size);
     }
@@ -1732,11 +1733,12 @@
     if (context->caps()->mipMapSupport()) {
         sk_sp<GrTextureProxy> proxy;
 
-        proxy = make_mipmap_proxy(proxyProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize, 0);
+        proxy = make_mipmap_proxy(proxyProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize, 1);
         size_t size = proxy->gpuMemorySize();
         REPORTER_ASSERT(reporter, kSize*kSize*4+(kSize*kSize*4)/3 == size);
 
-        size_t sampleCount = (size_t)context->caps()->getSampleCount(4, kRGBA_8888_GrPixelConfig);
+        size_t sampleCount =
+                (size_t)context->caps()->getRenderTargetSampleCount(4, kRGBA_8888_GrPixelConfig);
         if (sampleCount >= 4) {
             proxy = make_mipmap_proxy(proxyProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize,
                                       sampleCount);
@@ -1747,7 +1749,7 @@
                kSize*kSize*4*(sampleCount+1)+(kSize*kSize*4)/3 == size);  // explicit resolve buffer
         }
 
-        proxy = make_mipmap_proxy(proxyProvider, kNone_GrSurfaceFlags, kSize, kSize, 0);
+        proxy = make_mipmap_proxy(proxyProvider, kNone_GrSurfaceFlags, kSize, kSize, 1);
         size = proxy->gpuMemorySize();
         REPORTER_ASSERT(reporter, kSize*kSize*4+(kSize*kSize*4)/3 == size);
     }
diff --git a/tests/SRGBReadWritePixelsTest.cpp b/tests/SRGBReadWritePixelsTest.cpp
index 7013971..bb7b77c 100644
--- a/tests/SRGBReadWritePixelsTest.cpp
+++ b/tests/SRGBReadWritePixelsTest.cpp
@@ -172,7 +172,7 @@
     desc.fWidth = kW;
     desc.fHeight = kH;
     desc.fConfig = kSRGBA_8888_GrPixelConfig;
-    if (context->caps()->isConfigRenderable(desc.fConfig, false) &&
+    if (context->caps()->isConfigRenderable(desc.fConfig) &&
         context->caps()->isConfigTexturable(desc.fConfig)) {
 
         sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeDeferredSurfaceContext(
diff --git a/tests/SkpSkGrTest.cpp b/tests/SkpSkGrTest.cpp
index 24d1b9c..898faf0 100644
--- a/tests/SkpSkGrTest.cpp
+++ b/tests/SkpSkGrTest.cpp
@@ -442,7 +442,7 @@
         desc.fFlags = kRenderTarget_GrTextureFlagBit;
         desc.fWidth = dim.fX;
         desc.fHeight = dim.fY;
-        desc.fSampleCnt = 0;
+        desc.fSampleCnt = 1;
         sk_sp<GrTexture> texture(context->createUncachedTexture(desc, nullptr, 0));
         if (!texture) {
             SkDebugf("unable to allocate texture for %s (w=%d h=%d)\n", fFilename,
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index 471953b..de1cd9a 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -19,13 +19,17 @@
 #include "Test.h"
 
 #if SK_SUPPORT_GPU
+#include <vector>
 #include "GrContext.h"
 #include "GrContextPriv.h"
-#include "GrRenderTargetContext.h"
 #include "GrGpu.h"
+#include "GrGpuResourcePriv.h"
+#include "GrRenderTargetContext.h"
 #include "GrResourceProvider.h"
 #include "GrTest.h"
-#include <vector>
+#include "SkGpuDevice.h"
+#include "SkImage_Gpu.h"
+#include "SkSurface_Gpu.h"
 #endif
 
 #include <initializer_list>
@@ -88,6 +92,121 @@
 }
 #endif
 
+#if SK_SUPPORT_GPU
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrContext_colorTypeSupportedAsSurface, reporter, ctxInfo) {
+    for (int ct = 0; ct < kLastEnum_SkColorType; ++ct) {
+        static constexpr int kSize = 10;
+
+        SkColorType colorType = static_cast<SkColorType>(ct);
+        auto info = SkImageInfo::Make(kSize, kSize, colorType, kOpaque_SkAlphaType, nullptr);
+        bool can = ctxInfo.grContext()->colorTypeSupportedAsSurface(colorType);
+        auto surf = SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kYes, info, 1,
+                                                nullptr);
+        REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d",
+                        colorType, can, SkToBool(surf));
+
+        auto* gpu = ctxInfo.grContext()->contextPriv().getGpu();
+        GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
+                nullptr, kSize, kSize, colorType, true, GrMipMapped::kNo);
+        surf = SkSurface::MakeFromBackendTexture(ctxInfo.grContext(), backendTex,
+                                                 kTopLeft_GrSurfaceOrigin, 0, colorType, nullptr,
+                                                 nullptr);
+        REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d",
+                        colorType, can, SkToBool(surf));
+
+        surf = SkSurface::MakeFromBackendTextureAsRenderTarget(ctxInfo.grContext(), backendTex,
+                                                               kTopLeft_GrSurfaceOrigin, 1,
+                                                               colorType, nullptr, nullptr);
+        REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d",
+                        colorType, can, SkToBool(surf));
+
+        surf.reset();
+        ctxInfo.grContext()->flush();
+        if (backendTex.isValid()) {
+            gpu->deleteTestingOnlyBackendTexture(&backendTex);
+        }
+
+        static constexpr int kSampleCnt = 2;
+
+        can = ctxInfo.grContext()->maxSurfaceSampleCountForColorType(colorType) >= kSampleCnt;
+        surf = SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kYes, info, kSampleCnt,
+                                           nullptr);
+        REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d",
+                        colorType, can, SkToBool(surf));
+
+        backendTex = gpu->createTestingOnlyBackendTexture(nullptr, kSize, kSize, colorType, true,
+                                                          GrMipMapped::kNo);
+        surf = SkSurface::MakeFromBackendTexture(ctxInfo.grContext(), backendTex,
+                                                 kTopLeft_GrSurfaceOrigin, kSampleCnt, colorType,
+                                                 nullptr, nullptr);
+        REPORTER_ASSERT(reporter, can == SkToBool(surf),
+                        "colorTypeSupportedAsSurface:%d, surf:%d, ct:%d", can, SkToBool(surf),
+                        colorType);
+        // Ensure that the sample count stored on the resulting SkSurface is a valid value.
+        if (surf) {
+            auto* rtc = ((SkSurface_Gpu*)(surf.get()))->getDevice()->accessRenderTargetContext();
+            int storedCnt = rtc->numStencilSamples();
+            int allowedCnt = ctxInfo.grContext()->caps()->getSampleCount(
+                    storedCnt, rtc->asSurfaceProxy()->config());
+            REPORTER_ASSERT(reporter, storedCnt == allowedCnt,
+                            "Should store an allowed sample count (%d vs %d)", allowedCnt,
+                            storedCnt);
+        }
+
+        surf = SkSurface::MakeFromBackendTextureAsRenderTarget(ctxInfo.grContext(), backendTex,
+                                                               kTopLeft_GrSurfaceOrigin, kSampleCnt,
+                                                               colorType, nullptr, nullptr);
+        REPORTER_ASSERT(reporter, can == SkToBool(surf),
+                        "colorTypeSupportedAsSurface:%d, surf:%d, ct:%d", can, SkToBool(surf),
+                        colorType);
+        if (surf) {
+            auto* rtc = ((SkSurface_Gpu*)(surf.get()))->getDevice()->accessRenderTargetContext();
+            int storedCnt = rtc->numStencilSamples();
+            int allowedCnt = ctxInfo.grContext()->caps()->getSampleCount(
+                    storedCnt, rtc->asSurfaceProxy()->config());
+            REPORTER_ASSERT(reporter, storedCnt == allowedCnt,
+                            "Should store an allowed sample count (%d vs %d)", allowedCnt,
+                            storedCnt);
+        }
+
+        surf.reset();
+        ctxInfo.grContext()->flush();
+        if (backendTex.isValid()) {
+            gpu->deleteTestingOnlyBackendTexture(&backendTex);
+        }
+    }
+}
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrContext_maxSurfaceSamplesForColorType, reporter, ctxInfo) {
+    for (int ct = 0; ct < kLastEnum_SkColorType; ++ct) {
+        static constexpr int kSize = 10;
+
+        SkColorType colorType = static_cast<SkColorType>(ct);
+        int max = ctxInfo.grContext()->maxSurfaceSampleCountForColorType(colorType);
+        if (!max) {
+            continue;
+        }
+        auto* gpu = ctxInfo.grContext()->contextPriv().getGpu();
+        GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
+                nullptr, kSize, kSize, colorType, true, GrMipMapped::kNo);
+
+        auto info = SkImageInfo::Make(kSize, kSize, colorType, kOpaque_SkAlphaType, nullptr);
+        auto surf = SkSurface::MakeFromBackendTexture(ctxInfo.grContext(), backendTex,
+                                                      kTopLeft_GrSurfaceOrigin, max,
+                                                      colorType, nullptr, nullptr);
+        REPORTER_ASSERT(reporter, surf);
+        if (!surf) {
+            continue;
+        }
+        int sampleCnt = ((SkSurface_Gpu*)(surf.get()))
+                                ->getDevice()
+                                ->accessRenderTargetContext()
+                                ->numStencilSamples();
+        REPORTER_ASSERT(reporter, sampleCnt == max, "Exected: %d, actual: %d", max, sampleCnt);
+    }
+}
+#endif
+
 static void test_canvas_peek(skiatest::Reporter* reporter,
                              sk_sp<SkSurface>& surface,
                              const SkImageInfo& requestInfo,
@@ -437,10 +556,6 @@
 #endif
 
 #if SK_SUPPORT_GPU
-#include "GrGpuResourcePriv.h"
-#include "SkGpuDevice.h"
-#include "SkImage_Gpu.h"
-#include "SkSurface_Gpu.h"
 
 static SkBudgeted is_budgeted(const sk_sp<SkSurface>& surf) {
     SkSurface_Gpu* gsurf = (SkSurface_Gpu*)surf.get();
@@ -704,7 +819,7 @@
         for (auto& surfaceFunc : {&create_gpu_surface_backend_texture,
                                   &create_gpu_surface_backend_texture_as_render_target}) {
             GrBackendTexture backendTex;
-            auto surface = surfaceFunc(context, 0, kOrigColor, &backendTex);
+            auto surface = surfaceFunc(context, 1, kOrigColor, &backendTex);
             test_surface_clear(reporter, surface, grSurfaceGetter, kOrigColor);
             surface.reset();
             gpu->deleteTestingOnlyBackendTexture(&backendTex);
@@ -767,7 +882,7 @@
         // preserved in pixels that aren't rendered to via the surface.
         // This works only for non-multisampled case.
         GrBackendTexture backendTex;
-        auto surface = surfaceFunc(ctxInfo.grContext(), 0, kOrigColor, &backendTex);
+        auto surface = surfaceFunc(ctxInfo.grContext(), 1, kOrigColor, &backendTex);
         if (surface) {
             test_surface_draw_partially(reporter, surface, kOrigColor);
             surface.reset();
@@ -791,11 +906,11 @@
 
     for (auto& surfaceFunc : {&create_gpu_surface_backend_texture,
                               &create_gpu_surface_backend_texture_as_render_target}) {
-        for (int sampleCnt : {0, 4, 8}) {
+        for (int sampleCnt : {1, 4, 8}) {
             GrBackendTexture backendTex;
             auto surface = surfaceFunc(ctxInfo.grContext(), sampleCnt, kOrigColor, &backendTex);
 
-            if (!surface && sampleCnt > 0) {
+            if (!surface && sampleCnt > 1) {
                 // Certain platforms don't support MSAA, skip these.
                 continue;
             }
@@ -880,7 +995,7 @@
 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCreationWithColorSpace_Gpu, reporter, ctxInfo) {
     GrContext* context = ctxInfo.grContext();
 
-    bool f16Support = context->caps()->isConfigRenderable(kRGBA_half_GrPixelConfig, false);
+    bool f16Support = context->caps()->isConfigRenderable(kRGBA_half_GrPixelConfig);
     auto surfaceMaker = [context](const SkImageInfo& info) {
         return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
     };
diff --git a/tests/TessellatingPathRendererTests.cpp b/tests/TessellatingPathRendererTests.cpp
index 1eb055f..e24bf7a 100644
--- a/tests/TessellatingPathRendererTests.cpp
+++ b/tests/TessellatingPathRendererTests.cpp
@@ -486,13 +486,8 @@
 DEF_GPUTEST_FOR_ALL_CONTEXTS(TessellatingPathRendererTests, reporter, ctxInfo) {
     GrContext* ctx = ctxInfo.grContext();
     sk_sp<GrRenderTargetContext> rtc(ctx->makeDeferredRenderTargetContext(
-                                                                  SkBackingFit::kApprox,
-                                                                  800, 800,
-                                                                  kRGBA_8888_GrPixelConfig,
-                                                                  nullptr,
-                                                                  0,
-                                                                  GrMipMapped::kNo,
-                                                                  kTopLeft_GrSurfaceOrigin));
+            SkBackingFit::kApprox, 800, 800, kRGBA_8888_GrPixelConfig, nullptr, 1, GrMipMapped::kNo,
+            kTopLeft_GrSurfaceOrigin));
     if (!rtc) {
         return;
     }
diff --git a/tests/TestConfigParsing.cpp b/tests/TestConfigParsing.cpp
index aa95ff7..7e90730 100644
--- a/tests/TestConfigParsing.cpp
+++ b/tests/TestConfigParsing.cpp
@@ -45,7 +45,7 @@
                     == GrContextFactory::kGL_ContextType);
     REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getUseNVPR() == false);
     REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getUseDIText() == false);
-    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getSamples() == 0);
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getSamples() == 1);
     REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getColorType() == kRGBA_8888_SkColorType);
     REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getColorSpace() == nullptr);
 #endif
@@ -240,7 +240,7 @@
                     GrContextFactory::kGL_ContextType);
     REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getUseNVPR());
     REPORTER_ASSERT(reporter, !configs[0]->asConfigGpu()->getUseDIText());
-    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getSamples() == 0);
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getSamples() == 1);
     REPORTER_ASSERT(reporter, configs[1]->asConfigGpu()->getContextType() ==
                     GrContextFactory::kANGLE_D3D9_ES2_ContextType);
     REPORTER_ASSERT(reporter, configs[1]->asConfigGpu());
@@ -254,18 +254,18 @@
                     GrContextFactory::kGLES_ContextType);
     REPORTER_ASSERT(reporter, !configs[5]->asConfigGpu()->getUseNVPR());
     REPORTER_ASSERT(reporter, !configs[5]->asConfigGpu()->getUseDIText());
-    REPORTER_ASSERT(reporter, configs[5]->asConfigGpu()->getSamples() == 0);
+    REPORTER_ASSERT(reporter, configs[5]->asConfigGpu()->getSamples() == 1);
     REPORTER_ASSERT(reporter, configs[6]->asConfigGpu()->getContextType() ==
                               GrContextFactory::kGL_ContextType);
     REPORTER_ASSERT(reporter, !configs[6]->asConfigGpu()->getUseNVPR());
     REPORTER_ASSERT(reporter, !configs[6]->asConfigGpu()->getUseDIText());
-    REPORTER_ASSERT(reporter, configs[6]->asConfigGpu()->getSamples() == 0);
+    REPORTER_ASSERT(reporter, configs[6]->asConfigGpu()->getSamples() == 1);
 #ifdef SK_VULKAN
     REPORTER_ASSERT(reporter, configs[7]->asConfigGpu()->getContextType() ==
                               GrContextFactory::kVulkan_ContextType);
     REPORTER_ASSERT(reporter, !configs[7]->asConfigGpu()->getUseNVPR());
     REPORTER_ASSERT(reporter, !configs[7]->asConfigGpu()->getUseDIText());
-    REPORTER_ASSERT(reporter, configs[7]->asConfigGpu()->getSamples() == 0);
+    REPORTER_ASSERT(reporter, configs[7]->asConfigGpu()->getSamples() == 1);
 #endif
 #ifdef SK_METAL
     REPORTER_ASSERT(reporter, configs[8]->asConfigGpu()->getContextType() ==
diff --git a/tests/TextureProxyTest.cpp b/tests/TextureProxyTest.cpp
index d422b07..0591130 100644
--- a/tests/TextureProxyTest.cpp
+++ b/tests/TextureProxyTest.cpp
@@ -34,7 +34,7 @@
     desc.fWidth = 64;
     desc.fHeight = 64;
     desc.fConfig = kRGBA_8888_GrPixelConfig;
-    desc.fSampleCnt = 0;
+    desc.fSampleCnt = 1;
 
     return desc;
 }
diff --git a/tests/TransferPixelsTest.cpp b/tests/TransferPixelsTest.cpp
index ce8d1ed..8f71528 100755
--- a/tests/TransferPixelsTest.cpp
+++ b/tests/TransferPixelsTest.cpp
@@ -104,7 +104,7 @@
     desc.fWidth = kTextureWidth;
     desc.fHeight = kTextureHeight;
     desc.fConfig = config;
-    desc.fSampleCnt = 0;
+    desc.fSampleCnt = 1;
     sk_sp<GrTexture> tex = resourceProvider->createTexture(desc, SkBudgeted::kNo);
 
     //////////////////////////
diff --git a/tests/VkClearTests.cpp b/tests/VkClearTests.cpp
index c797ef2..0dcb446 100644
--- a/tests/VkClearTests.cpp
+++ b/tests/VkClearTests.cpp
@@ -58,7 +58,7 @@
     surfDesc.fWidth = 5;
     surfDesc.fHeight = 5;
     surfDesc.fConfig = config;
-    surfDesc.fSampleCnt = 0;
+    surfDesc.fSampleCnt = 1;
     GrTexture* tex = gpu->createTexture(surfDesc, SkBudgeted::kNo);
     SkASSERT(tex);
     SkASSERT(tex->asRenderTarget());
@@ -114,7 +114,7 @@
     surfDesc.fWidth = width;
     surfDesc.fHeight = height;
     surfDesc.fConfig = config;
-    surfDesc.fSampleCnt = 0;
+    surfDesc.fSampleCnt = 1;
     GrTexture* tex = gpu->createTexture(surfDesc, SkBudgeted::kNo);
     SkASSERT(tex);
     SkASSERT(tex->asRenderTarget());
diff --git a/tests/VkUploadPixelsTests.cpp b/tests/VkUploadPixelsTests.cpp
index 3b3feca..f35480a 100644
--- a/tests/VkUploadPixelsTests.cpp
+++ b/tests/VkUploadPixelsTests.cpp
@@ -69,7 +69,7 @@
     surfDesc.fWidth = kWidth;
     surfDesc.fHeight = kHeight;
     surfDesc.fConfig = config;
-    surfDesc.fSampleCnt = 0;
+    surfDesc.fSampleCnt = 1;
 
     SkColorType ct;
     SkAssertResult(GrPixelConfigToColorType(config, &ct));
diff --git a/tests/VkWrapTests.cpp b/tests/VkWrapTests.cpp
index 6cfbba6..9723d57 100644
--- a/tests/VkWrapTests.cpp
+++ b/tests/VkWrapTests.cpp
@@ -83,7 +83,7 @@
                                                                            GrMipMapped::kNo);
     const GrVkImageInfo* imageInfo = origBackendTex.getVkImageInfo();
 
-    GrBackendRenderTarget origBackendRT(kW, kH, 0, 0, *imageInfo);
+    GrBackendRenderTarget origBackendRT(kW, kH, 1, 0, *imageInfo);
 
     sk_sp<GrRenderTarget> rt = gpu->wrapBackendRenderTarget(origBackendRT);
     REPORTER_ASSERT(reporter, rt);
@@ -92,7 +92,7 @@
     {
         GrVkImageInfo backendCopy = *imageInfo;
         backendCopy.fImage = VK_NULL_HANDLE;
-        GrBackendRenderTarget backendRT(kW, kH, 0, 0, backendCopy);
+        GrBackendRenderTarget backendRT(kW, kH, 1, 0, backendCopy);
         rt = gpu->wrapBackendRenderTarget(backendRT);
         REPORTER_ASSERT(reporter, !rt);
     }
@@ -102,7 +102,7 @@
         GrVkImageInfo backendCopy = *imageInfo;
         backendCopy.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
         // can wrap null alloc
-        GrBackendRenderTarget backendRT(kW, kH, 0, 0, backendCopy);
+        GrBackendRenderTarget backendRT(kW, kH, 1, 0, backendCopy);
         rt = gpu->wrapBackendRenderTarget(backendRT);
         REPORTER_ASSERT(reporter, rt);
     }
@@ -120,8 +120,8 @@
                                                                            GrMipMapped::kNo);
     const GrVkImageInfo* imageInfo = origBackendTex.getVkImageInfo();
 
-    sk_sp<GrTexture> tex = gpu->wrapRenderableBackendTexture(origBackendTex, 0,
-                                                             kBorrow_GrWrapOwnership);
+    sk_sp<GrTexture> tex =
+            gpu->wrapRenderableBackendTexture(origBackendTex, 1, kBorrow_GrWrapOwnership);
     REPORTER_ASSERT(reporter, tex);
 
     // image is null
@@ -129,9 +129,9 @@
         GrVkImageInfo backendCopy = *imageInfo;
         backendCopy.fImage = VK_NULL_HANDLE;
         GrBackendTexture backendTex = GrBackendTexture(kW, kH, backendCopy);
-        tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kBorrow_GrWrapOwnership);
+        tex = gpu->wrapRenderableBackendTexture(backendTex, 1, kBorrow_GrWrapOwnership);
         REPORTER_ASSERT(reporter, !tex);
-        tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kAdopt_GrWrapOwnership);
+        tex = gpu->wrapRenderableBackendTexture(backendTex, 1, kAdopt_GrWrapOwnership);
         REPORTER_ASSERT(reporter, !tex);
     }
 
@@ -140,9 +140,9 @@
         GrVkImageInfo backendCopy = *imageInfo;
         backendCopy.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
         GrBackendTexture backendTex = GrBackendTexture(kW, kH, backendCopy);
-        tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kBorrow_GrWrapOwnership);
+        tex = gpu->wrapRenderableBackendTexture(backendTex, 1, kBorrow_GrWrapOwnership);
         REPORTER_ASSERT(reporter, !tex);
-        tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kAdopt_GrWrapOwnership);
+        tex = gpu->wrapRenderableBackendTexture(backendTex, 1, kAdopt_GrWrapOwnership);
         REPORTER_ASSERT(reporter, !tex);
     }
 
@@ -150,7 +150,7 @@
     {
         GrVkImageInfo backendCopy = *imageInfo;
         GrBackendTexture backendTex = GrBackendTexture(kW, kH, backendCopy);
-        tex = gpu->wrapRenderableBackendTexture(backendTex, 0, kAdopt_GrWrapOwnership);
+        tex = gpu->wrapRenderableBackendTexture(backendTex, 1, kAdopt_GrWrapOwnership);
         REPORTER_ASSERT(reporter, tex);
     }
 
diff --git a/tests/WritePixelsTest.cpp b/tests/WritePixelsTest.cpp
index a16752f..2a2ee39 100644
--- a/tests/WritePixelsTest.cpp
+++ b/tests/WritePixelsTest.cpp
@@ -412,11 +412,11 @@
     const SkImageInfo ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
 
     for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
-        for (int sampleCnt : {0, 4}) {
+        for (int sampleCnt : {1, 4}) {
             sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
                                                                  SkBudgeted::kNo, ii, sampleCnt,
                                                                  origin, nullptr));
-            if (!surface && sampleCnt > 0) {
+            if (!surface && sampleCnt > 1) {
                 // Some platforms don't support MSAA
                 continue;
             }
@@ -430,7 +430,7 @@
     GrGpu* gpu = context->contextPriv().getGpu();
 
     for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
-        for (int sampleCnt : {0, 4}) {
+        for (int sampleCnt : {1, 4}) {
             GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
                     nullptr, DEV_W, DEV_H, kSkia8888_GrPixelConfig, true, GrMipMapped::kNo);
             SkColorType colorType;
diff --git a/tools/fiddle/fiddle_main.cpp b/tools/fiddle/fiddle_main.cpp
index 4ba84f3..684bc2a 100644
--- a/tools/fiddle/fiddle_main.cpp
+++ b/tools/fiddle/fiddle_main.cpp
@@ -133,7 +133,7 @@
     backingDesc.fHeight = bm.height();
     // This config must match the SkColorType used in draw.cpp in the SkImage and Surface factories
     backingDesc.fConfig = kRGBA_8888_GrPixelConfig;
-    backingDesc.fSampleCnt = 0;
+    backingDesc.fSampleCnt = 1;
 
     if (!bm.empty()) {
         SkPixmap originalPixmap;
diff --git a/tools/flags/SkCommonFlagsConfig.cpp b/tools/flags/SkCommonFlagsConfig.cpp
index d38d70a..9d1c2dd 100644
--- a/tools/flags/SkCommonFlagsConfig.cpp
+++ b/tools/flags/SkCommonFlagsConfig.cpp
@@ -391,7 +391,7 @@
     bool seenUseDIText =false;
     bool useDIText = false;
     bool seenSamples = false;
-    int samples = 0;
+    int samples = 1;
     bool seenColor = false;
     SkColorType colorType = kRGBA_8888_SkColorType;
     SkAlphaType alphaType = kPremul_SkAlphaType;
diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp
index 829ddcb..06d9b83 100644
--- a/tools/gpu/GrTest.cpp
+++ b/tools/gpu/GrTest.cpp
@@ -182,6 +182,13 @@
 
 #endif
 
+GrBackendTexture GrGpu::createTestingOnlyBackendTexture(void* pixels, int w, int h,
+                                                        SkColorType colorType, bool isRenderTarget,
+                                                        GrMipMapped mipMapped) {
+    GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps());
+    return this->createTestingOnlyBackendTexture(pixels, w, h, config, isRenderTarget, mipMapped);
+}
+
 #if GR_CACHE_STATS
 void GrResourceCache::getStats(Stats* stats) const {
     stats->reset();
diff --git a/tools/sk_app/DisplayParams.h b/tools/sk_app/DisplayParams.h
index 959735e..203e8bd 100644
--- a/tools/sk_app/DisplayParams.h
+++ b/tools/sk_app/DisplayParams.h
@@ -13,10 +13,7 @@
 namespace sk_app {
 
 struct DisplayParams {
-    DisplayParams()
-        : fColorType(kN32_SkColorType)
-        , fColorSpace(nullptr)
-        , fMSAASampleCount(0) {}
+    DisplayParams() : fColorType(kN32_SkColorType), fColorSpace(nullptr), fMSAASampleCount(1) {}
 
     SkColorType         fColorType;
     sk_sp<SkColorSpace> fColorSpace;
diff --git a/tools/sk_app/GLWindowContext.cpp b/tools/sk_app/GLWindowContext.cpp
index 9ef5141..9d042cf 100644
--- a/tools/sk_app/GLWindowContext.cpp
+++ b/tools/sk_app/GLWindowContext.cpp
@@ -24,9 +24,7 @@
     : WindowContext(params)
     , fBackendContext(nullptr)
     , fSurface(nullptr) {
-    fDisplayParams.fMSAASampleCount = fDisplayParams.fMSAASampleCount ?
-                                      GrNextPow2(fDisplayParams.fMSAASampleCount) :
-                                      0;
+    fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount);
 }
 
 void GLWindowContext::initializeContext() {
@@ -34,7 +32,7 @@
 
     fBackendContext = this->onInitializeContext();
     fContext = GrContext::MakeGL(fBackendContext, fDisplayParams.fGrContextOptions);
-    if (!fContext && fDisplayParams.fMSAASampleCount) {
+    if (!fContext && fDisplayParams.fMSAASampleCount > 1) {
         fDisplayParams.fMSAASampleCount /= 2;
         this->initializeContext();
         return;
diff --git a/tools/sk_app/Window.cpp b/tools/sk_app/Window.cpp
index 29e4864..1694bea 100644
--- a/tools/sk_app/Window.cpp
+++ b/tools/sk_app/Window.cpp
@@ -117,7 +117,7 @@
 
 int Window::sampleCount() const {
     if (!fWindowContext) {
-        return -1;
+        return 0;
     }
     return fWindowContext->sampleCount();
 }
diff --git a/tools/sk_app/WindowContext.h b/tools/sk_app/WindowContext.h
index 5e7d76d..71c21ac 100644
--- a/tools/sk_app/WindowContext.h
+++ b/tools/sk_app/WindowContext.h
@@ -21,11 +21,11 @@
 class WindowContext {
 public:
     WindowContext(const DisplayParams& params)
-        : fContext(nullptr)
-        , fDisplayParams(params)
-        , fSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)
-        , fSampleCount(0)
-        , fStencilBits(0) {}
+            : fContext(nullptr)
+            , fDisplayParams(params)
+            , fSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)
+            , fSampleCount(1)
+            , fStencilBits(0) {}
 
     virtual ~WindowContext() {}
 
diff --git a/tools/sk_app/android/GLWindowContext_android.cpp b/tools/sk_app/android/GLWindowContext_android.cpp
index acdb587..5111114 100644
--- a/tools/sk_app/android/GLWindowContext_android.cpp
+++ b/tools/sk_app/android/GLWindowContext_android.cpp
@@ -70,6 +70,8 @@
     SkAssertResult(eglBindAPI(EGL_OPENGL_ES_API));
 
     EGLint numConfigs = 0;
+    EGLint eglSampleCnt = fDisplayParams.fMSAASampleCount > 1 ? fDisplayParams.fMSAASampleCount > 1
+                                                              : 0;
     const EGLint configAttribs[] = {
         EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
@@ -78,8 +80,8 @@
         EGL_BLUE_SIZE, 8,
         EGL_ALPHA_SIZE, 8,
         EGL_STENCIL_SIZE, 8,
-        EGL_SAMPLE_BUFFERS, fDisplayParams.fMSAASampleCount ? 1 : 0,
-        EGL_SAMPLES, fDisplayParams.fMSAASampleCount,
+        EGL_SAMPLE_BUFFERS, eglSampleCnt ? 1 : 0,
+        EGL_SAMPLES, eglSampleCnt,
         EGL_NONE
     };
 
@@ -131,6 +133,7 @@
 
     eglGetConfigAttrib(fDisplay, surfaceConfig, EGL_STENCIL_SIZE, &fStencilBits);
     eglGetConfigAttrib(fDisplay, surfaceConfig, EGL_SAMPLES, &fSampleCount);
+    fSampleCount = SkTMax(fSampleCount, 1);
 
     return GrGLMakeNativeInterface();
 }
diff --git a/tools/sk_app/ios/GLWindowContext_ios.cpp b/tools/sk_app/ios/GLWindowContext_ios.cpp
index f4c0d6b..2a57b33 100644
--- a/tools/sk_app/ios/GLWindowContext_ios.cpp
+++ b/tools/sk_app/ios/GLWindowContext_ios.cpp
@@ -67,6 +67,7 @@
 
         SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &fStencilBits);
         SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &fSampleCount);
+        fSampleCount = SkTMax(fSampleCount, 1);
 
         SDL_GL_GetDrawableSize(fWindow, &fWidth, &fHeight);
         glViewport(0, 0, fWidth, fHeight);
diff --git a/tools/sk_app/ios/RasterWindowContext_ios.cpp b/tools/sk_app/ios/RasterWindowContext_ios.cpp
index cae5774..53d7c1a 100644
--- a/tools/sk_app/ios/RasterWindowContext_ios.cpp
+++ b/tools/sk_app/ios/RasterWindowContext_ios.cpp
@@ -79,6 +79,7 @@
 
         SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &fStencilBits);
         SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &fSampleCount);
+        fSampleCount = SkTMax(fSampleCount, 1);
 
         SDL_GL_GetDrawableSize(fWindow, &fWidth, &fHeight);
         glViewport(0, 0, fWidth, fHeight);
diff --git a/tools/sk_app/ios/Window_ios.cpp b/tools/sk_app/ios/Window_ios.cpp
index c1bdeae..ac0ad0c 100644
--- a/tools/sk_app/ios/Window_ios.cpp
+++ b/tools/sk_app/ios/Window_ios.cpp
@@ -49,7 +49,7 @@
 
     SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
 
-    if (fRequestedDisplayParams.fMSAASampleCount > 0) {
+    if (fRequestedDisplayParams.fMSAASampleCount > 1) {
         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fRequestedDisplayParams.fMSAASampleCount);
     } else {
diff --git a/tools/sk_app/ios/Window_ios.h b/tools/sk_app/ios/Window_ios.h
index 667fa74..a0fed90 100644
--- a/tools/sk_app/ios/Window_ios.h
+++ b/tools/sk_app/ios/Window_ios.h
@@ -18,11 +18,7 @@
 
 class Window_ios : public Window {
 public:
-    Window_ios()
-        : INHERITED()
-        , fWindow(nullptr)
-        , fWindowID(0)
-        , fMSAASampleCount(0) {}
+    Window_ios() : INHERITED(), fWindow(nullptr), fWindowID(0), fMSAASampleCount(1) {}
     ~Window_ios() override { this->closeWindow(); }
 
     bool initWindow();
diff --git a/tools/sk_app/mac/GLWindowContext_mac.cpp b/tools/sk_app/mac/GLWindowContext_mac.cpp
index 005fc07..67fb853 100644
--- a/tools/sk_app/mac/GLWindowContext_mac.cpp
+++ b/tools/sk_app/mac/GLWindowContext_mac.cpp
@@ -67,6 +67,7 @@
 
         SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &fStencilBits);
         SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &fSampleCount);
+        fSampleCount = SkTMax(fSampleCount, 1);
 
         SDL_GetWindowSize(fWindow, &fWidth, &fHeight);
         glViewport(0, 0, fWidth, fHeight);
diff --git a/tools/sk_app/mac/RasterWindowContext_mac.cpp b/tools/sk_app/mac/RasterWindowContext_mac.cpp
index 67022af..fbe9837 100644
--- a/tools/sk_app/mac/RasterWindowContext_mac.cpp
+++ b/tools/sk_app/mac/RasterWindowContext_mac.cpp
@@ -79,6 +79,7 @@
 
         SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &fStencilBits);
         SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &fSampleCount);
+        fSampleCount = SkTMax(fSampleCount, 1);
 
         SDL_GetWindowSize(fWindow, &fWidth, &fHeight);
         glViewport(0, 0, fWidth, fHeight);
diff --git a/tools/sk_app/mac/Window_mac.cpp b/tools/sk_app/mac/Window_mac.cpp
index 8de5b10..f262051 100644
--- a/tools/sk_app/mac/Window_mac.cpp
+++ b/tools/sk_app/mac/Window_mac.cpp
@@ -49,7 +49,7 @@
 
     SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
 
-    if (fRequestedDisplayParams.fMSAASampleCount > 0) {
+    if (fRequestedDisplayParams.fMSAASampleCount > 1) {
         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fRequestedDisplayParams.fMSAASampleCount);
     } else {
diff --git a/tools/sk_app/mac/Window_mac.h b/tools/sk_app/mac/Window_mac.h
index aa5c8df..35cba09 100644
--- a/tools/sk_app/mac/Window_mac.h
+++ b/tools/sk_app/mac/Window_mac.h
@@ -18,11 +18,7 @@
 
 class Window_mac : public Window {
 public:
-    Window_mac()
-        : INHERITED()
-        , fWindow(nullptr)
-        , fWindowID(0)
-        , fMSAASampleCount(0) {}
+    Window_mac() : INHERITED(), fWindow(nullptr), fWindowID(0), fMSAASampleCount(1) {}
     ~Window_mac() override { this->closeWindow(); }
 
     bool initWindow();
diff --git a/tools/sk_app/unix/GLWindowContext_unix.cpp b/tools/sk_app/unix/GLWindowContext_unix.cpp
index 25ec95c..3a3a4b1 100644
--- a/tools/sk_app/unix/GLWindowContext_unix.cpp
+++ b/tools/sk_app/unix/GLWindowContext_unix.cpp
@@ -99,6 +99,7 @@
 
     glXGetConfig(fDisplay, fVisualInfo, GLX_STENCIL_SIZE, &fStencilBits);
     glXGetConfig(fDisplay, fVisualInfo, GLX_SAMPLES_ARB, &fSampleCount);
+    fSampleCount = SkTMax(fSampleCount, 1);
 
     XWindow root;
     int x, y;
diff --git a/tools/sk_app/unix/Window_unix.cpp b/tools/sk_app/unix/Window_unix.cpp
index f5ca5ee..745b4dd 100644
--- a/tools/sk_app/unix/Window_unix.cpp
+++ b/tools/sk_app/unix/Window_unix.cpp
@@ -72,7 +72,7 @@
         None
     };
     SkASSERT(nullptr == fVisualInfo);
-    if (fRequestedDisplayParams.fMSAASampleCount > 0) {
+    if (fRequestedDisplayParams.fMSAASampleCount > 1) {
         static const GLint kChooseFBConifgAttCnt = SK_ARRAY_COUNT(kChooseFBConfigAtt);
         GLint msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 4];
         memcpy(msaaChooseFBConfigAtt, kChooseFBConfigAtt, sizeof(kChooseFBConfigAtt));
diff --git a/tools/sk_app/unix/Window_unix.h b/tools/sk_app/unix/Window_unix.h
index b59f502..62a2795 100644
--- a/tools/sk_app/unix/Window_unix.h
+++ b/tools/sk_app/unix/Window_unix.h
@@ -20,13 +20,14 @@
 
 class Window_unix : public Window {
 public:
-    Window_unix() : Window()
-                  , fDisplay(nullptr)
-                  , fWindow(0)
-                  , fGC(nullptr)
-                  , fFBConfig(nullptr)
-                  , fVisualInfo(nullptr)
-                  , fMSAASampleCount(0) {}
+    Window_unix()
+            : Window()
+            , fDisplay(nullptr)
+            , fWindow(0)
+            , fGC(nullptr)
+            , fFBConfig(nullptr)
+            , fVisualInfo(nullptr)
+            , fMSAASampleCount(1) {}
     ~Window_unix() override { this->closeWindow(); }
 
     bool initWindow(Display* display);
diff --git a/tools/sk_app/win/ANGLEWindowContext_win.cpp b/tools/sk_app/win/ANGLEWindowContext_win.cpp
index 649528d..452b462 100644
--- a/tools/sk_app/win/ANGLEWindowContext_win.cpp
+++ b/tools/sk_app/win/ANGLEWindowContext_win.cpp
@@ -76,7 +76,8 @@
     }
     EGLint numConfigs;
     fSampleCount = this->getDisplayParams().fMSAASampleCount;
-    const int sampleBuffers = fSampleCount > 0 ? 1 : 0;
+    const int sampleBuffers = fSampleCount > 1 ? 1 : 0;
+    const int eglSampleCnt = fSampleCount > 1 ? fSampleCount : 0;
     const EGLint configAttribs[] = {EGL_RENDERABLE_TYPE,
                                     // We currently only support ES3.
                                     EGL_OPENGL_ES3_BIT,
@@ -91,7 +92,7 @@
                                     EGL_SAMPLE_BUFFERS,
                                     sampleBuffers,
                                     EGL_SAMPLES,
-                                    fSampleCount,
+                                    eglSampleCnt,
                                     EGL_NONE};
 
     EGLConfig surfaceConfig;
diff --git a/tools/sk_app/win/GLWindowContext_win.cpp b/tools/sk_app/win/GLWindowContext_win.cpp
index 7e43d2b..1c583cb 100644
--- a/tools/sk_app/win/GLWindowContext_win.cpp
+++ b/tools/sk_app/win/GLWindowContext_win.cpp
@@ -96,8 +96,9 @@
                                               1,
                                               &kSampleCountAttr,
                                               &fSampleCount);
+            fSampleCount = SkTMax(fSampleCount, 1);
         } else {
-            fSampleCount = 0;
+            fSampleCount = 1;
         }
 
         RECT rect;
diff --git a/tools/skpbench/skpbench.cpp b/tools/skpbench/skpbench.cpp
index fcab2d3..6b89bc2 100644
--- a/tools/skpbench/skpbench.cpp
+++ b/tools/skpbench/skpbench.cpp
@@ -292,7 +292,8 @@
     GrPixelConfig grPixConfig = SkImageInfo2GrPixelConfig(config->getColorType(),
                                                           config->getColorSpace(),
                                                           *ctx->caps());
-    int supportedSampleCount = ctx->caps()->getSampleCount(config->getSamples(), grPixConfig);
+    int supportedSampleCount =
+            ctx->caps()->getRenderTargetSampleCount(config->getSamples(), grPixConfig);
     if (supportedSampleCount != config->getSamples()) {
         exitf(ExitErr::kUnavailable, "sample count %i not supported by platform",
                                      config->getSamples());
diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp
index 198f9ba..35b0e14 100644
--- a/tools/viewer/Viewer.cpp
+++ b/tools/viewer/Viewer.cpp
@@ -78,7 +78,7 @@
 
 static DEFINE_string2(backend, b, "sw", "Backend to use. Allowed values are " BACKENDS_STR ".");
 
-static DEFINE_int32(msaa, 0, "Number of subpixel samples. 0 for no HW antialiasing.");
+static DEFINE_int32(msaa, 1, "Number of subpixel samples. 0 for no HW antialiasing.");
 
 DECLARE_int32(threads)
 
@@ -501,7 +501,7 @@
     if (!fWindow) {
         return;
     }
-    if (fWindow->sampleCount() < 0) {
+    if (fWindow->sampleCount() < 1) {
         return; // Surface hasn't been created yet.
     }
 
@@ -561,7 +561,8 @@
 
     title.append(" [");
     title.append(kBackendTypeStrings[fBackendType]);
-    if (int msaa = fWindow->sampleCount()) {
+    int msaa = fWindow->sampleCount();
+    if (msaa > 1) {
         title.appendf(" MSAA: %i", msaa);
     }
     title.append("]");
@@ -994,7 +995,7 @@
                 if (ctx) {
                     int sampleCount = fWindow->sampleCount();
                     ImGui::Text("MSAA: "); ImGui::SameLine();
-                    ImGui::RadioButton("0", &sampleCount, 0); ImGui::SameLine();
+                    ImGui::RadioButton("1", &sampleCount, 1); ImGui::SameLine();
                     ImGui::RadioButton("4", &sampleCount, 4); ImGui::SameLine();
                     ImGui::RadioButton("8", &sampleCount, 8); ImGui::SameLine();
                     ImGui::RadioButton("16", &sampleCount, 16);
@@ -1018,7 +1019,7 @@
 
                     if (!ctx) {
                         ImGui::RadioButton("Software", true);
-                    } else if (fWindow->sampleCount()) {
+                    } else if (fWindow->sampleCount() > 1) {
                         prButton(GpuPathRenderers::kDefault);
                         prButton(GpuPathRenderers::kAll);
                         if (ctx->caps()->shaderCaps()->pathRenderingSupport()) {
@@ -1198,7 +1199,7 @@
     if (!fWindow) {
         return;
     }
-    if (fWindow->sampleCount() < 0) {
+    if (fWindow->sampleCount() < 1) {
         return; // Surface hasn't been created yet.
     }
 
@@ -1244,7 +1245,7 @@
     const GrContext* ctx = fWindow->getGrContext();
     if (!ctx) {
         prState[kOptions].append("Software");
-    } else if (fWindow->sampleCount()) {
+    } else if (fWindow->sampleCount() > 1) {
         prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kDefault]);
         prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kAll]);
         if (ctx->caps()->shaderCaps()->pathRenderingSupport()) {