Add option to create a deferred render target context with mips

We need this since we have texture generators that draw the base level
but nothing more. Thus we want them to be able to directly draw into
a pre allocated mipped target instead of doing a copy later.

TBR: bsalomon@google.com
Bug: skia:
Change-Id: I1dfae0da7153b21b30fdfa51a7061fc255739a1e
Reviewed-on: https://skia-review.googlesource.com/54100
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/core/SkColorSpaceXformImageGenerator.cpp b/src/core/SkColorSpaceXformImageGenerator.cpp
index bf1275e..ea277fe 100644
--- a/src/core/SkColorSpaceXformImageGenerator.cpp
+++ b/src/core/SkColorSpaceXformImageGenerator.cpp
@@ -87,7 +87,7 @@
 
     sk_sp<GrRenderTargetContext> renderTargetContext = ctx->makeDeferredRenderTargetContext(
             SkBackingFit::kExact, info.width(), info.height(), kRGBA_8888_GrPixelConfig, nullptr,
-            0, kTopLeft_GrSurfaceOrigin);
+            0, false, kTopLeft_GrSurfaceOrigin);
     if (!renderTargetContext) {
         return nullptr;
     }
diff --git a/src/gpu/GrBitmapTextureMaker.cpp b/src/gpu/GrBitmapTextureMaker.cpp
index efb9e20..b92ffda 100644
--- a/src/gpu/GrBitmapTextureMaker.cpp
+++ b/src/gpu/GrBitmapTextureMaker.cpp
@@ -77,8 +77,7 @@
         // We need a mipped proxy, but we either found a proxy earlier that wasn't mipped or
         // generated a non mipped proxy. Thus we generate a new mipped surface and copy the original
         // proxy into the base layer. We will then let the gpu generate the rest of the mips.
-        if (auto mippedProxy = GrCopyBaseMipMapToTextureProxy(this->context(), proxy.get(),
-                                                              dstColorSpace)) {
+        if (auto mippedProxy = GrCopyBaseMipMapToTextureProxy(this->context(), proxy.get())) {
             SkASSERT(mippedProxy->origin() == kTopLeft_GrSurfaceOrigin);
             if (fOriginalKey.isValid()) {
                 // In this case we are stealing the key from the original proxy which should only
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 9abf953..d346a2a 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -614,6 +614,7 @@
                                                            tempDrawInfo.fTempSurfaceDesc.fConfig,
                                                            nullptr,
                                                            tempDrawInfo.fTempSurfaceDesc.fSampleCnt,
+                                                           false,
                                                            tempDrawInfo.fTempSurfaceDesc.fOrigin);
         if (tempRTC) {
             SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top));
@@ -873,6 +874,7 @@
                                                                  GrPixelConfig config,
                                                                  sk_sp<SkColorSpace> colorSpace,
                                                                  int sampleCnt,
+                                                                 bool willNeedMipMaps,
                                                                  GrSurfaceOrigin origin,
                                                                  const SkSurfaceProps* surfaceProps,
                                                                  SkBudgeted budgeted) {
@@ -881,7 +883,8 @@
     }
 
     return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace),
-                                                 sampleCnt, origin, surfaceProps, budgeted);
+                                                 sampleCnt, willNeedMipMaps, origin, surfaceProps,
+                                                 budgeted);
 }
 
 sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext(
@@ -890,6 +893,7 @@
                                                         GrPixelConfig config,
                                                         sk_sp<SkColorSpace> colorSpace,
                                                         int sampleCnt,
+                                                        bool willNeedMipMaps,
                                                         GrSurfaceOrigin origin,
                                                         const SkSurfaceProps* surfaceProps,
                                                         SkBudgeted budgeted) {
@@ -905,8 +909,12 @@
     desc.fConfig = config;
     desc.fSampleCnt = sampleCnt;
 
-    sk_sp<GrTextureProxy> rtp = GrSurfaceProxy::MakeDeferred(this->resourceProvider(),
-                                                             desc, fit, budgeted);
+    sk_sp<GrTextureProxy> rtp;
+    if (!willNeedMipMaps) {
+        rtp = GrSurfaceProxy::MakeDeferred(this->resourceProvider(), desc, fit, budgeted);
+    } else {
+        rtp = GrSurfaceProxy::MakeDeferredMipMap(this->resourceProvider(), desc, budgeted);
+    }
     if (!rtp) {
         return nullptr;
     }
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index 0cc3621..803c0eb 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -19,6 +19,7 @@
 #include "GrTextureRenderTargetProxy.h"
 
 #include "SkMathPriv.h"
+#include "SkMipMap.h"
 
 GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface, GrSurfaceOrigin origin, SkBackingFit fit)
         : INHERITED(std::move(surface))
@@ -313,6 +314,23 @@
     return GrSurfaceProxy::MakeDeferred(resourceProvider, desc, SkBackingFit::kExact, budgeted);
 }
 
+sk_sp<GrTextureProxy> GrSurfaceProxy::MakeDeferredMipMap(GrResourceProvider* resourceProvider,
+                                                         const GrSurfaceDesc& desc,
+                                                         SkBudgeted budgeted) {
+    // SkMipMap doesn't include the base level in the level count so we have to add 1
+    int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1;
+
+    std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipCount]);
+
+    // We don't want to upload any texel data
+    for (int i = 0; i < mipCount; i++) {
+        texels[i].fPixels = nullptr;
+        texels[i].fRowBytes = 0;
+    }
+
+    return MakeDeferredMipMap(resourceProvider, desc, budgeted, texels.get(), mipCount);
+}
+
 sk_sp<GrTextureProxy> GrSurfaceProxy::MakeDeferredMipMap(
                                                     GrResourceProvider* resourceProvider,
                                                     const GrSurfaceDesc& desc,
diff --git a/src/gpu/GrTextureAdjuster.cpp b/src/gpu/GrTextureAdjuster.cpp
index e42be3f..da31758 100644
--- a/src/gpu/GrTextureAdjuster.cpp
+++ b/src/gpu/GrTextureAdjuster.cpp
@@ -42,7 +42,8 @@
     // We don't currently have a mechanism for notifications on Images!
 }
 
-sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxyCopy(const CopyParams& copyParams) {
+sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxyCopy(const CopyParams& copyParams,
+                                                             bool willBeMipped) {
     GrUniqueKey key;
     this->makeCopyKey(copyParams, &key, nullptr);
     if (key.isValid()) {
@@ -57,7 +58,8 @@
     sk_sp<GrTextureProxy> proxy = this->originalProxyRef();
     const SkIRect* contentArea = this->contentAreaOrNull();
 
-    sk_sp<GrTextureProxy> copy = CopyOnGpu(fContext, std::move(proxy), contentArea, copyParams);
+    sk_sp<GrTextureProxy> copy = CopyOnGpu(fContext, std::move(proxy), contentArea, copyParams,
+                                           willBeMipped);
     if (copy) {
         if (key.isValid()) {
             SkASSERT(copy->origin() == this->originalProxy()->origin());
@@ -79,7 +81,8 @@
         return nullptr;
     }
 
-    if (contentArea && GrSamplerState::Filter::kMipMap == params.filter()) {
+    bool willBeMipped = GrSamplerState::Filter::kMipMap == params.filter();
+    if (contentArea && willBeMipped) {
         // If we generate a MIP chain for texture it will read pixel values from outside the content
         // area.
         copyParams.fWidth = contentArea->width();
@@ -90,7 +93,7 @@
         return proxy;
     }
 
-    return this->refTextureProxyCopy(copyParams);
+    return this->refTextureProxyCopy(copyParams, willBeMipped);
 }
 
 std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
diff --git a/src/gpu/GrTextureAdjuster.h b/src/gpu/GrTextureAdjuster.h
index 5ee6edc..ca5b0e9 100644
--- a/src/gpu/GrTextureAdjuster.h
+++ b/src/gpu/GrTextureAdjuster.h
@@ -58,7 +58,7 @@
     SkColorSpace*         fColorSpace;
     uint32_t              fUniqueID;
 
-    sk_sp<GrTextureProxy> refTextureProxyCopy(const CopyParams &copyParams);
+    sk_sp<GrTextureProxy> refTextureProxyCopy(const CopyParams &copyParams, bool willBeMipped);
 
     typedef GrTextureProducer INHERITED;
 };
diff --git a/src/gpu/GrTextureMaker.cpp b/src/gpu/GrTextureMaker.cpp
index db0f421..8183188 100644
--- a/src/gpu/GrTextureMaker.cpp
+++ b/src/gpu/GrTextureMaker.cpp
@@ -59,7 +59,7 @@
 
     sk_sp<GrTextureProxy> result;
     if (original) {
-        result = CopyOnGpu(fContext, std::move(original), nullptr, copyParams);
+        result = CopyOnGpu(fContext, std::move(original), nullptr, copyParams, willBeMipped);
     } else {
         result = this->generateTextureProxyForParams(copyParams, willBeMipped, dstColorSpace);
     }
@@ -134,5 +134,5 @@
         return nullptr;
     }
 
-    return CopyOnGpu(fContext, std::move(original), nullptr, copyParams);
+    return CopyOnGpu(fContext, std::move(original), nullptr, copyParams, willBeMipped);
 }
diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp
index 91e196d..2b9679a 100644
--- a/src/gpu/GrTextureProducer.cpp
+++ b/src/gpu/GrTextureProducer.cpp
@@ -17,7 +17,8 @@
 sk_sp<GrTextureProxy> GrTextureProducer::CopyOnGpu(GrContext* context,
                                                    sk_sp<GrTextureProxy> inputProxy,
                                                    const SkIRect* subset,
-                                                   const CopyParams& copyParams) {
+                                                   const CopyParams& copyParams,
+                                                   bool dstWillRequireMipMaps) {
     SkASSERT(!subset || !subset->isEmpty());
     SkASSERT(context);
 
@@ -25,7 +26,7 @@
 
     sk_sp<GrRenderTargetContext> copyRTC = context->makeDeferredRenderTargetContextWithFallback(
         SkBackingFit::kExact, dstRect.width(), dstRect.height(), inputProxy->config(), nullptr,
-        0, inputProxy->origin());
+        0, dstWillRequireMipMaps, inputProxy->origin());
     if (!copyRTC) {
         return nullptr;
     }
diff --git a/src/gpu/GrTextureProducer.h b/src/gpu/GrTextureProducer.h
index 7d05664..24b23b6 100644
--- a/src/gpu/GrTextureProducer.h
+++ b/src/gpu/GrTextureProducer.h
@@ -125,7 +125,8 @@
     };
 
     static sk_sp<GrTextureProxy> CopyOnGpu(GrContext*, sk_sp<GrTextureProxy> inputProxy,
-                                           const SkIRect* subset, const CopyParams& copyParams);
+                                           const SkIRect* subset, const CopyParams& copyParams,
+                                           bool dstWillRequireMipMaps);
 
     static DomainMode DetermineDomainMode(const SkRect& constraintRect,
                                           FilterConstraint filterConstraint,
diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp
index 6b58d42..085e5be 100644
--- a/src/gpu/GrYUVProvider.cpp
+++ b/src/gpu/GrYUVProvider.cpp
@@ -123,11 +123,13 @@
     }
 
     // We never want to perform color-space conversion during the decode
+    // TODO: investigate preallocating mip maps here
     sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext(
                                                                     SkBackingFit::kExact,
                                                                     desc.fWidth, desc.fHeight,
                                                                     desc.fConfig, nullptr,
                                                                     desc.fSampleCnt,
+                                                                    false, // always non mipped
                                                                     kTopLeft_GrSurfaceOrigin));
     if (!renderTargetContext) {
         return nullptr;
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 3f0bdce..bbc23c2 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -162,7 +162,7 @@
                                     SkBackingFit::kExact,
                                     origInfo.width(), origInfo.height(),
                                     config, origInfo.refColorSpace(), sampleCount,
-                                    origin, surfaceProps, budgeted);
+                                    false, origin, surfaceProps, budgeted);
 }
 
 sk_sp<SkSpecialImage> SkGpuDevice::filterTexture(SkSpecialImage* srcImg,
@@ -1702,6 +1702,7 @@
                                                    fRenderTargetContext->config(),
                                                    fRenderTargetContext->refColorSpace(),
                                                    fRenderTargetContext->numStencilSamples(),
+                                                   false,
                                                    kBottomLeft_GrSurfaceOrigin,
                                                    &props));
     if (!rtc) {
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 8035027..0c065f9 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -219,29 +219,13 @@
 }
 
 sk_sp<GrTextureProxy> GrCopyBaseMipMapToTextureProxy(GrContext* ctx,
-                                                     GrTextureProxy* baseProxy,
-                                                     SkColorSpace* dstColorSpace) {
+                                                     GrTextureProxy* baseProxy) {
     SkASSERT(baseProxy);
 
     if (!ctx->caps()->isConfigCopyable(baseProxy->config())) {
         return nullptr;
     }
 
-    SkDestinationSurfaceColorMode colorMode = dstColorSpace
-        ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware
-        : SkDestinationSurfaceColorMode::kLegacy;
-
-    // SkMipMap doesn't include the base level in the level count so we have to add 1
-    int mipLevelCount = SkMipMap::ComputeLevelCount(baseProxy->width(), baseProxy->height()) + 1;
-
-    std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
-
-    // We don't want to upload any texel data
-    for (int i = 0; i < mipLevelCount; i++) {
-        texels[i].fPixels = nullptr;
-        texels[i].fRowBytes = 0;
-    }
-
     GrSurfaceDesc desc;
     desc.fFlags = kNone_GrSurfaceFlags;
     desc.fOrigin = baseProxy->origin();
@@ -252,8 +236,7 @@
 
     sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeDeferredMipMap(ctx->resourceProvider(),
                                                                      desc,
-                                                                     SkBudgeted::kYes, texels.get(),
-                                                                     mipLevelCount, colorMode);
+                                                                     SkBudgeted::kYes);
     if (!proxy) {
         return nullptr;
     }
diff --git a/src/gpu/SkGr.h b/src/gpu/SkGr.h
index 20110a5..f4f4d07 100644
--- a/src/gpu/SkGr.h
+++ b/src/gpu/SkGr.h
@@ -228,8 +228,7 @@
  * Creates a new texture with mipmap levels and copies the baseProxy into the base layer.
  */
 sk_sp<GrTextureProxy> GrCopyBaseMipMapToTextureProxy(GrContext*,
-                                                     GrTextureProxy* baseProxy,
-                                                     SkColorSpace* dstColorSpace);
+                                                     GrTextureProxy* baseProxy);
 
 /**
  * Creates a new texture populated with the mipmap levels.
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index e477a5e..2f7d663 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -387,6 +387,7 @@
                                                                          kRGBA_8888_GrPixelConfig,
                                                                          std::move(imageColorSpace),
                                                                          0,
+                                                                         false,
                                                                          origin));
     if (!renderTargetContext) {
         return nullptr;
diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp
index 26a1ef9..5e3c037 100644
--- a/src/image/SkImage_Lazy.cpp
+++ b/src/image/SkImage_Lazy.cpp
@@ -850,7 +850,7 @@
         // generate the rest of the mips.
         SkASSERT(willBeMipped);
         SkASSERT(!proxy->isMipMapped());
-        if (auto mippedProxy = GrCopyBaseMipMapToTextureProxy(ctx, proxy.get(), dstColorSpace)) {
+        if (auto mippedProxy = GrCopyBaseMipMapToTextureProxy(ctx, proxy.get())) {
             set_key_on_proxy(ctx->resourceProvider(), mippedProxy.get(), proxy.get(), key);
             return mippedProxy;
         }