Add mip support to GrAHardwareBufferImageGenerator

Bug: skia:
Change-Id: I482d8f9937c86ed441016afef2d8f924282dd17a
Reviewed-on: https://skia-review.googlesource.com/63861
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/gm/image_pict.cpp b/gm/image_pict.cpp
index 0e39d3b..bf1c651 100644
--- a/gm/image_pict.cpp
+++ b/gm/image_pict.cpp
@@ -186,8 +186,11 @@
         desc.fHeight = info.height();
         desc.fConfig = fProxy->config();
 
+        GrMipMapped mipMapped = willBeMipped ? GrMipMapped::kYes : GrMipMapped::kNo;
+
         sk_sp<GrSurfaceContext> dstContext(fCtx->contextPriv().makeDeferredSurfaceContext(
                                                                             desc,
+                                                                            mipMapped,
                                                                             SkBackingFit::kExact,
                                                                             SkBudgeted::kYes));
         if (!dstContext) {
diff --git a/include/private/GrSurfaceProxy.h b/include/private/GrSurfaceProxy.h
index 2bbf02a..0eccdce 100644
--- a/include/private/GrSurfaceProxy.h
+++ b/include/private/GrSurfaceProxy.h
@@ -326,12 +326,12 @@
     // Helper function that creates a temporary SurfaceContext to perform the copy
     // It always returns a kExact-backed proxy bc it is used when converting an SkSpecialImage
     // to an SkImage. The copy is is not a render target and not multisampled.
-    static sk_sp<GrTextureProxy> Copy(GrContext*, GrSurfaceProxy* src,
+    static sk_sp<GrTextureProxy> Copy(GrContext*, GrSurfaceProxy* src, GrMipMapped,
                                       SkIRect srcRect, SkBudgeted);
 
     // Copy the entire 'src'
     // It always returns a kExact-backed proxy bc it is used in SkGpuDevice::snapSpecial
-    static sk_sp<GrTextureProxy> Copy(GrContext* context, GrSurfaceProxy* src,
+    static sk_sp<GrTextureProxy> Copy(GrContext* context, GrSurfaceProxy* src, GrMipMapped,
                                       SkBudgeted budgeted);
 
     // Test-only entry point - should decrease in use as proxies propagate
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp
index db4fadc..df56afd 100644
--- a/src/core/SkSpecialImage.cpp
+++ b/src/core/SkSpecialImage.cpp
@@ -464,7 +464,8 @@
             }
 
             sk_sp<GrTextureProxy> subsetProxy(GrSurfaceProxy::Copy(fContext, fTextureProxy.get(),
-                                                                   *subset, SkBudgeted::kYes));
+                                                                   GrMipMapped::kNo, *subset,
+                                                                   SkBudgeted::kYes));
             if (!subsetProxy) {
                 return nullptr;
             }
diff --git a/src/gpu/GrAHardwareBufferImageGenerator.cpp b/src/gpu/GrAHardwareBufferImageGenerator.cpp
index 164e3d6..bdfdbd0 100644
--- a/src/gpu/GrAHardwareBufferImageGenerator.cpp
+++ b/src/gpu/GrAHardwareBufferImageGenerator.cpp
@@ -104,17 +104,44 @@
         return nullptr;
     }
 
+    bool makingASubset = true;
     if (0 == origin.fX && 0 == origin.fY &&
             info.width() == getInfo().width() && info.height() == getInfo().height()) {
-        // If the caller wants the entire texture, we're done
-        return proxy;
-    } else {
-        // Otherwise, make a copy of the requested subset.
-        return GrSurfaceProxy::Copy(context, proxy.get(),
-                                    SkIRect::MakeXYWH(origin.fX, origin.fY, info.width(),
-                                                      info.height()),
-                                    SkBudgeted::kYes);
+        makingASubset = false;
+        if (!willNeedMipMaps || GrMipMapped::kYes == proxy->mipMapped()) {
+            // If the caller wants the full texture and we have the correct mip support, we're done
+            return proxy;
+        }
     }
+    // Otherwise, make a copy for the requested subset or for mip maps.
+    SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, info.width(), info.height());
+
+    GrMipMapped mipMapped = willNeedMipMaps ? GrMipMapped::kYes : GrMipMapped::kNo;
+
+    sk_sp<GrTextureProxy> texProxy = GrSurfaceProxy::Copy(context, proxy.get(), mipMapped,
+                                                          subset, SkBudgeted::kYes);
+    if (!makingASubset && texProxy) {
+        // We are in this case if we wanted the full texture, but we will be mip mapping the
+        // texture. Therefore we want to update the cached texture so that we point to the
+        // mipped version instead of the old one.
+        SkASSERT(willNeedMipMaps);
+        SkASSERT(GrMipMapped::kYes == texProxy->mipMapped());
+
+        // The only way we should get into here is if we just made a new texture in makeProxy or
+        // we found a cached texture in the same context. Thus the current and cached contexts
+        // should match.
+        SkASSERT(context->uniqueID() == fOwningContextID);
+
+        // Clear out the old cached texture.
+        this->clear();
+
+        // We need to get the actual GrTexture so force instantiation of the GrTextureProxy
+        texProxy->instantiate(context->resourceProvider());
+        GrTexture* texture = texProxy->priv().peekTexture();
+        SkASSERT(texture);
+        fOriginalTexture = texture;
+    }
+    return texProxy;
 }
 #endif
 
diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp
index 68fd9f3..9760205d 100644
--- a/src/gpu/GrBlurUtils.cpp
+++ b/src/gpu/GrBlurUtils.cpp
@@ -85,6 +85,7 @@
 
     sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeDeferredSurfaceContext(
                                                         desc,
+                                                        GrMipMapped::kNo,
                                                         SkBackingFit::kApprox,
                                                         SkBudgeted::kYes);
     if (!sContext) {
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index f4f1d6c..605fe2e 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -750,11 +750,19 @@
 }
 
 sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc,
+                                                                  GrMipMapped mipMapped,
                                                                   SkBackingFit fit,
                                                                   SkBudgeted isDstBudgeted) {
 
-    sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(),
-                                                               dstDesc, fit, isDstBudgeted);
+    sk_sp<GrTextureProxy> proxy;
+    if (GrMipMapped::kNo == mipMapped) {
+        proxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(), dstDesc, fit,
+                                             isDstBudgeted);
+    } else {
+        SkASSERT(SkBackingFit::kExact == fit);
+        proxy = GrSurfaceProxy::MakeDeferredMipMap(fContext->resourceProvider(), dstDesc,
+                                                   isDstBudgeted);
+    }
     if (!proxy) {
         return nullptr;
     }
diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h
index e1773c8..cdd04b4 100644
--- a/src/gpu/GrContextPriv.h
+++ b/src/gpu/GrContextPriv.h
@@ -27,6 +27,7 @@
     sk_sp<GrSurfaceContext> makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy>, sk_sp<SkColorSpace>);
 
     sk_sp<GrSurfaceContext> makeDeferredSurfaceContext(const GrSurfaceDesc&,
+                                                       GrMipMapped,
                                                        SkBackingFit,
                                                        SkBudgeted);
 
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 5f071e8..44550e1 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -1890,6 +1890,7 @@
 
     sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeDeferredSurfaceContext(
                                                                                 desc,
+                                                                                GrMipMapped::kNo,
                                                                                 fit,
                                                                                 SkBudgeted::kYes);
     if (!sContext) {
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index d45847a..1005758 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -100,6 +100,7 @@
 
     sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeDeferredSurfaceContext(
                                                                                 desc,
+                                                                                GrMipMapped::kNo,
                                                                                 fit,
                                                                                 SkBudgeted::kYes);
     if (!sContext || !sContext->asTextureProxy()) {
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index da5bb17..3e188b8 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -411,6 +411,7 @@
 
 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context,
                                            GrSurfaceProxy* src,
+                                           GrMipMapped mipMapped,
                                            SkIRect srcRect,
                                            SkBudgeted budgeted) {
     if (!srcRect.intersect(SkIRect::MakeWH(src->width(), src->height()))) {
@@ -425,6 +426,7 @@
 
     sk_sp<GrSurfaceContext> dstContext(context->contextPriv().makeDeferredSurfaceContext(
                                                                             dstDesc,
+                                                                            mipMapped,
                                                                             SkBackingFit::kExact,
                                                                             budgeted));
     if (!dstContext) {
@@ -439,8 +441,8 @@
 }
 
 sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context, GrSurfaceProxy* src,
-                                           SkBudgeted budgeted) {
-    return Copy(context, src, SkIRect::MakeWH(src->width(), src->height()), budgeted);
+                                           GrMipMapped mipMapped, SkBudgeted budgeted) {
+    return Copy(context, src, mipMapped, SkIRect::MakeWH(src->width(), src->height()), budgeted);
 }
 
 sk_sp<GrSurfaceContext> GrSurfaceProxy::TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc,
@@ -448,6 +450,7 @@
 
     sk_sp<GrSurfaceContext> dstContext(context->contextPriv().makeDeferredSurfaceContext(
                                                                             dstDesc,
+                                                                            GrMipMapped::kNo,
                                                                             SkBackingFit::kExact,
                                                                             SkBudgeted::kYes));
     if (!dstContext) {
diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp
index 085e5be..d6a5666 100644
--- a/src/gpu/GrYUVProvider.cpp
+++ b/src/gpu/GrYUVProvider.cpp
@@ -109,7 +109,9 @@
                 (yuvDesc.fHeight != yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight)
                     ? SkBackingFit::kExact : SkBackingFit::kApprox;
 
-        yuvTextureContexts[i] = ctx->contextPriv().makeDeferredSurfaceContext(yuvDesc, fit,
+        yuvTextureContexts[i] = ctx->contextPriv().makeDeferredSurfaceContext(yuvDesc,
+                                                                              GrMipMapped::kNo,
+                                                                              fit,
                                                                               SkBudgeted::kYes);
         if (!yuvTextureContexts[i]) {
             return nullptr;
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 93414ed..fe1f6ae 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1238,6 +1238,7 @@
         // filter
         proxy = GrSurfaceProxy::Copy(fContext.get(),
                                      this->accessRenderTargetContext()->asSurfaceProxy(),
+                                     GrMipMapped::kNo,
                                      SkBudgeted::kYes);
         if (!proxy) {
             return nullptr;
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 9f1586c..e89af42 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -249,6 +249,7 @@
 
     sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
                                                                         desc,
+                                                                        GrMipMapped::kNo,
                                                                         SkBackingFit::kExact,
                                                                         fBudgeted));
     if (!sContext) {
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 6e9bc3f..8b7a065 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -110,7 +110,9 @@
     if (!srcProxy || rtc->priv().refsWrappedObjects()) {
         SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin());
 
-        srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), budgeted);
+        // TODO: We should look at the rtc to see if it is mipped and if so create the copy as well
+        // with mips.
+        srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), GrMipMapped::kNo, budgeted);
     }
 
     const SkImageInfo info = fDevice->imageInfo();
diff --git a/tests/GrSurfaceTest.cpp b/tests/GrSurfaceTest.cpp
index e5dc6ae..eff8c25 100644
--- a/tests/GrSurfaceTest.cpp
+++ b/tests/GrSurfaceTest.cpp
@@ -212,7 +212,8 @@
                     // Try creating the texture as a deferred proxy.
                     for (int i = 0; i < 2; ++i) {
                         auto surfCtx = context->contextPriv().makeDeferredSurfaceContext(
-                                desc, approx ? SkBackingFit::kApprox : SkBackingFit::kExact,
+                                desc, GrMipMapped::kNo,
+                                approx ? SkBackingFit::kApprox : SkBackingFit::kExact,
                                 SkBudgeted::kYes);
                         if (!surfCtx) {
                             continue;
diff --git a/tests/SRGBReadWritePixelsTest.cpp b/tests/SRGBReadWritePixelsTest.cpp
index a52e961..6ebdcf7 100644
--- a/tests/SRGBReadWritePixelsTest.cpp
+++ b/tests/SRGBReadWritePixelsTest.cpp
@@ -176,8 +176,9 @@
         context->caps()->isConfigTexturable(desc.fConfig)) {
 
         sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeDeferredSurfaceContext(
-                                                                    desc, SkBackingFit::kExact,
-                                                                    SkBudgeted::kNo);
+                                                                             desc, GrMipMapped::kNo,
+                                                                             SkBackingFit::kExact,
+                                                                             SkBudgeted::kNo);
         if (!sContext) {
             ERRORF(reporter, "Could not create SRGBA surface context.");
             return;
@@ -215,7 +216,9 @@
         }
 
         desc.fConfig = kRGBA_8888_GrPixelConfig;
-        sContext = context->contextPriv().makeDeferredSurfaceContext(desc, SkBackingFit::kExact,
+        sContext = context->contextPriv().makeDeferredSurfaceContext(desc,
+                                                                     GrMipMapped::kNo,
+                                                                     SkBackingFit::kExact,
                                                                      SkBudgeted::kNo);
         if (!sContext) {
             ERRORF(reporter, "Could not create RGBA surface context.");