Round stencil buffers dims up to next pow2 when allowed

Review URL: https://codereview.chromium.org/937303002
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 7ccdce5..ffdd4dc 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -1080,6 +1080,7 @@
     fReuseScratchTextures = true;
     fGpuTracingSupport = false;
     fCompressedTexSubImageSupport = false;
+    fOversizedStencilSupport = false;
 
     fUseDrawInsteadOfClear = false;
 
@@ -1110,6 +1111,7 @@
     fReuseScratchTextures = other.fReuseScratchTextures;
     fGpuTracingSupport = other.fGpuTracingSupport;
     fCompressedTexSubImageSupport = other.fCompressedTexSubImageSupport;
+    fOversizedStencilSupport = other.fOversizedStencilSupport;
 
     fUseDrawInsteadOfClear = other.fUseDrawInsteadOfClear;
 
@@ -1192,7 +1194,7 @@
     r.appendf("Reuse Scratch Textures             : %s\n", gNY[fReuseScratchTextures]);
     r.appendf("Gpu Tracing Support                : %s\n", gNY[fGpuTracingSupport]);
     r.appendf("Compressed Update Support          : %s\n", gNY[fCompressedTexSubImageSupport]);
-
+    r.appendf("Oversized Stencil Support          : %s\n", gNY[fOversizedStencilSupport]);
     r.appendf("Draw Instead of Clear [workaround] : %s\n", gNY[fUseDrawInsteadOfClear]);
 
     r.appendf("Max Texture Size                   : %d\n", fMaxTextureSize);
diff --git a/src/gpu/GrDrawTargetCaps.h b/src/gpu/GrDrawTargetCaps.h
index 1bd18b0..61ec3b2 100644
--- a/src/gpu/GrDrawTargetCaps.h
+++ b/src/gpu/GrDrawTargetCaps.h
@@ -82,6 +82,7 @@
     bool discardRenderTargetSupport() const { return fDiscardRenderTargetSupport; }
     bool gpuTracingSupport() const { return fGpuTracingSupport; }
     bool compressedTexSubImageSupport() const { return fCompressedTexSubImageSupport; }
+    bool oversizedStencilSupport() const { return fOversizedStencilSupport; }
 
     bool useDrawInsteadOfClear() const { return fUseDrawInsteadOfClear; }
 
@@ -146,23 +147,23 @@
     uint32_t getUniqueID() const { return fUniqueID; }
 
 protected:
-    bool fNPOTTextureTileSupport    : 1;
-    bool fMipMapSupport             : 1;
-    bool fTwoSidedStencilSupport    : 1;
-    bool fStencilWrapOpsSupport     : 1;
-    bool fHWAALineSupport           : 1;
-    bool fShaderDerivativeSupport   : 1;
-    bool fGeometryShaderSupport     : 1;
-    bool fDualSourceBlendingSupport : 1;
-    bool fPathRenderingSupport      : 1;
-    bool fDstReadInShaderSupport    : 1;
-    bool fDiscardRenderTargetSupport: 1;
-    bool fReuseScratchTextures      : 1;
-    bool fGpuTracingSupport         : 1;
-    bool fCompressedTexSubImageSupport : 1;
-
+    bool fNPOTTextureTileSupport        : 1;
+    bool fMipMapSupport                 : 1;
+    bool fTwoSidedStencilSupport        : 1;
+    bool fStencilWrapOpsSupport         : 1;
+    bool fHWAALineSupport               : 1;
+    bool fShaderDerivativeSupport       : 1;
+    bool fGeometryShaderSupport         : 1;
+    bool fDualSourceBlendingSupport     : 1;
+    bool fPathRenderingSupport          : 1;
+    bool fDstReadInShaderSupport        : 1;
+    bool fDiscardRenderTargetSupport    : 1;
+    bool fReuseScratchTextures          : 1;
+    bool fGpuTracingSupport             : 1;
+    bool fCompressedTexSubImageSupport  : 1;
+    bool fOversizedStencilSupport       : 1;
     // Driver workaround
-    bool fUseDrawInsteadOfClear     : 1;
+    bool fUseDrawInsteadOfClear         : 1;
 
     uint32_t fMapBufferFlags;
 
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 27fed3c..d22399f 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -87,8 +87,15 @@
 bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
     SkASSERT(NULL == rt->getStencilBuffer());
     GrUniqueKey sbKey;
-    GrStencilBuffer::ComputeSharedStencilBufferKey(rt->width(), rt->height(), rt->numSamples(),
-                                                   &sbKey);
+
+    int width = rt->width();
+    int height = rt->height();
+    if (this->caps()->oversizedStencilSupport()) {
+        width  = SkNextPow2(width);
+        height = SkNextPow2(height);
+    }
+
+    GrStencilBuffer::ComputeSharedStencilBufferKey(width, height, rt->numSamples(), &sbKey);
     SkAutoTUnref<GrStencilBuffer> sb(static_cast<GrStencilBuffer*>(
         this->getContext()->getResourceCache()->findAndRefUniqueResource(sbKey)));
     if (sb) {
@@ -99,7 +106,7 @@
         }
         return attached;
     }
-    if (this->createStencilBufferForRenderTarget(rt, rt->width(), rt->height())) {
+    if (this->createStencilBufferForRenderTarget(rt, width, height)) {
         // Right now we're clearing the stencil buffer here after it is
         // attached to an RT for the first time. When we start matching
         // stencil buffers with smaller color targets this will no longer
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 6d8b4ba..1f50f8d 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -407,6 +407,19 @@
         fUseDrawInsteadOfClear = true;
     }
 
+    if (kGL_GrGLStandard == standard) {
+        // ARB allows mixed size FBO attachments, EXT does not.
+        if (ctxInfo.version() >= GR_GL_VER(3, 0) ||
+            ctxInfo.hasExtension("GL_ARB_framebuffer_object")) {
+            fOversizedStencilSupport = true;
+        } else {
+            SkASSERT(ctxInfo.hasExtension("GL_EXT_framebuffer_object"));
+        }
+    } else {
+        // ES 3.0 supports mixed size FBO attachments, 2.0 does not.
+        fOversizedStencilSupport = ctxInfo.version() >= GR_GL_VER(3, 0);
+    }
+
     this->initConfigTexturableTable(ctxInfo, gli);
     this->initConfigRenderableTable(ctxInfo);