added TextureRenderTarget to Metal gpu backend

Bug: skia:
Change-Id: I5cacdb832deefe0f8d8460ff10b2216d5dec1ed7
Reviewed-on: https://skia-review.googlesource.com/137890
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Timothy Liang <timliang@google.com>
diff --git a/src/gpu/mtl/GrMtlRenderTarget.mm b/src/gpu/mtl/GrMtlRenderTarget.mm
index c102e6d..32d6128 100644
--- a/src/gpu/mtl/GrMtlRenderTarget.mm
+++ b/src/gpu/mtl/GrMtlRenderTarget.mm
@@ -10,6 +10,28 @@
 #include "GrMtlGpu.h"
 #include "GrMtlUtil.h"
 
+GrMtlRenderTarget::GrMtlRenderTarget(GrMtlGpu* gpu,
+                                     const GrSurfaceDesc& desc,
+                                     SkBudgeted budgeted,
+                                     id<MTLTexture> renderTexture)
+        : GrSurface(gpu, desc)
+        , GrRenderTarget(gpu, desc)
+        , fRenderTexture(renderTexture)
+        , fResolveTexture(nil) {
+    SkASSERT(1 == desc.fSampleCnt);
+    this->registerWithCache(budgeted);
+}
+
+GrMtlRenderTarget::GrMtlRenderTarget(GrMtlGpu* gpu,
+                                     const GrSurfaceDesc& desc,
+                                     id<MTLTexture> renderTexture)
+        : GrSurface(gpu, desc)
+        , GrRenderTarget(gpu, desc)
+        , fRenderTexture(renderTexture)
+        , fResolveTexture(nil) {
+    SkASSERT(1 == desc.fSampleCnt);
+}
+
 sk_sp<GrMtlRenderTarget> GrMtlRenderTarget::CreateNewRenderTarget(GrMtlGpu* gpu,
                                                                   const GrSurfaceDesc& desc,
                                                                   SkBudgeted budgeted) {
@@ -43,16 +65,6 @@
     return sk_sp<GrMtlRenderTarget>(new GrMtlRenderTarget(gpu, desc, budgeted, texture));
 }
 
-GrMtlRenderTarget::GrMtlRenderTarget(GrMtlGpu* gpu,
-                                     const GrSurfaceDesc& desc,
-                                     SkBudgeted budgeted,
-                                     id<MTLTexture> renderTexture)
-        : GrSurface(gpu, desc)
-        , GrRenderTarget(gpu, desc)
-        , fRenderTexture(renderTexture)
-        , fResolveTexture(nil) {
-}
-
 GrMtlRenderTarget::~GrMtlRenderTarget() {
     SkASSERT(nil == fRenderTexture);
     SkASSERT(nil == fResolveTexture);
@@ -73,7 +85,7 @@
     fResolveTexture = nil;
 }
 
-bool completeStencilAttachment() {
+bool GrMtlRenderTarget::completeStencilAttachment() {
     // TODO: fill this out
     return true;
 }
diff --git a/src/gpu/mtl/GrMtlTexture.h b/src/gpu/mtl/GrMtlTexture.h
index f750832..57a7ee5 100644
--- a/src/gpu/mtl/GrMtlTexture.h
+++ b/src/gpu/mtl/GrMtlTexture.h
@@ -40,7 +40,7 @@
     }
 
 protected:
-    GrMtlTexture(GrMtlGpu*, const GrSurfaceDesc&);
+    GrMtlTexture(GrMtlGpu*, const GrSurfaceDesc&, id<MTLTexture>, GrMipMapsStatus);
 
     GrMtlGpu* getMtlGpu() const;
 
diff --git a/src/gpu/mtl/GrMtlTexture.mm b/src/gpu/mtl/GrMtlTexture.mm
index ac4e735..90bfcb3 100644
--- a/src/gpu/mtl/GrMtlTexture.mm
+++ b/src/gpu/mtl/GrMtlTexture.mm
@@ -11,6 +11,35 @@
 #include "GrMtlUtil.h"
 #include "GrTexturePriv.h"
 
+// This method parallels GrTextureProxy::highestFilterMode
+static inline GrSamplerState::Filter highest_filter_mode(GrPixelConfig config) {
+    return GrSamplerState::Filter::kMipMap;
+}
+
+GrMtlTexture::GrMtlTexture(GrMtlGpu* gpu,
+                           SkBudgeted budgeted,
+                           const GrSurfaceDesc& desc,
+                           id<MTLTexture> texture,
+                           GrMipMapsStatus mipMapsStatus)
+        : GrSurface(gpu, desc)
+        , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig),
+                    mipMapsStatus)
+        , fTexture(texture) {
+    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == texture.mipmapLevelCount));
+    this->registerWithCache(budgeted);
+}
+
+GrMtlTexture::GrMtlTexture(GrMtlGpu* gpu,
+                           const GrSurfaceDesc& desc,
+                           id<MTLTexture> texture,
+                           GrMipMapsStatus mipMapsStatus)
+        : GrSurface(gpu, desc)
+        , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig),
+                    mipMapsStatus)
+        , fTexture(texture) {
+    SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == texture.mipmapLevelCount));
+}
+
 sk_sp<GrMtlTexture> GrMtlTexture::CreateNewTexture(GrMtlGpu* gpu, SkBudgeted budgeted,
                                                    const GrSurfaceDesc& desc, int mipLevels) {
     MTLPixelFormat format;
@@ -41,22 +70,6 @@
     return sk_sp<GrMtlTexture>(new GrMtlTexture(gpu, budgeted, desc, texture, mipMapsStatus));
 }
 
-// This method parallels GrTextureProxy::highestFilterMode
-static inline GrSamplerState::Filter highest_filter_mode(GrPixelConfig config) {
-    return GrSamplerState::Filter::kMipMap;
-}
-
-GrMtlTexture::GrMtlTexture(GrMtlGpu* gpu,
-                           SkBudgeted budgeted,
-                           const GrSurfaceDesc& desc,
-                           id<MTLTexture> texture,
-                           GrMipMapsStatus mipMapsStatus)
-        : GrSurface(gpu, desc)
-        , INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig),
-                    mipMapsStatus)
-        , fTexture(texture) {
-}
-
 GrMtlTexture::~GrMtlTexture() {
     SkASSERT(nil == fTexture);
 }
diff --git a/src/gpu/mtl/GrMtlTextureRenderTarget.h b/src/gpu/mtl/GrMtlTextureRenderTarget.h
new file mode 100644
index 0000000..5137dd0
--- /dev/null
+++ b/src/gpu/mtl/GrMtlTextureRenderTarget.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrMtlTextureRenderTarget_DEFINED
+#define GrMtlTextureRenderTarget_DEFINED
+
+#include "GrMtlRenderTarget.h"
+#include "GrMtlTexture.h"
+
+class GrMtlTextureRenderTarget: public GrMtlTexture, public GrMtlRenderTarget {
+public:
+    static sk_sp<GrMtlTextureRenderTarget> CreateNewTextureRenderTarget(GrMtlGpu*,
+                                                                        SkBudgeted,
+                                                                        const GrSurfaceDesc&,
+                                                                        int mipLevels);
+
+    static sk_sp<GrMtlTextureRenderTarget> MakeWrappedTextureRenderTarget(GrMtlGpu*,
+                                                                          const GrSurfaceDesc&,
+                                                                          GrWrapOwnership);
+
+protected:
+    void onAbandon() override {
+        GrMtlRenderTarget::onAbandon();
+        GrMtlTexture::onAbandon();
+    }
+
+    void onRelease() override {
+        GrMtlRenderTarget::onRelease();
+        GrMtlTexture::onRelease();
+    }
+
+private:
+    GrMtlTextureRenderTarget(GrMtlGpu* gpu,
+                             SkBudgeted budgeted,
+                             const GrSurfaceDesc& desc,
+                             id<MTLTexture> renderTexture,
+                             id<MTLTexture> resolveTexture,
+                             GrMipMapsStatus);
+
+    GrMtlTextureRenderTarget(GrMtlGpu* gpu,
+                             SkBudgeted budgeted,
+                             const GrSurfaceDesc& desc,
+                             id<MTLTexture> renderTexture,
+                             GrMipMapsStatus);
+
+    GrMtlTextureRenderTarget(GrMtlGpu* gpu,
+                             const GrSurfaceDesc& desc,
+                             id<MTLTexture> renderTexture,
+                             id<MTLTexture> resolveTexture,
+                             GrMipMapsStatus);
+
+    GrMtlTextureRenderTarget(GrMtlGpu* gpu,
+                             const GrSurfaceDesc& desc,
+                             id<MTLTexture> renderTexture,
+                             GrMipMapsStatus);
+
+    static sk_sp<GrMtlTextureRenderTarget> Make(GrMtlGpu*,
+                                                const GrSurfaceDesc&,
+                                                id<MTLTexture> resolveTexture,
+                                                int mipLevels,
+                                                SkBudgeted budgeted,
+                                                bool isWrapped);
+
+    size_t onGpuMemorySize() const override {
+        // TODO: When used as render targets certain formats may actually have a larger size than
+        // the base format size. Check to make sure we are reporting the correct value here.
+        // The plus 1 is to account for the resolve texture or if not using msaa the RT itself
+        int numColorSamples = this->numColorSamples();
+        if (numColorSamples > 1) {
+            ++numColorSamples;
+        }
+        return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
+                                      numColorSamples, GrMipMapped::kNo, false);
+    }
+};
+
+#endif
diff --git a/src/gpu/mtl/GrMtlTextureRenderTarget.mm b/src/gpu/mtl/GrMtlTextureRenderTarget.mm
new file mode 100644
index 0000000..99d1c9e
--- /dev/null
+++ b/src/gpu/mtl/GrMtlTextureRenderTarget.mm
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrMtlTextureRenderTarget.h"
+#include "GrMtlGpu.h"
+#include "GrMtlUtil.h"
+
+GrMtlTextureRenderTarget::GrMtlTextureRenderTarget(GrMtlGpu* gpu,
+                                                   SkBudgeted budgeted,
+                                                   const GrSurfaceDesc& desc,
+                                                   id<MTLTexture> renderTexture,
+                                                   GrMipMapsStatus mipMapsStatus)
+        : GrSurface(gpu, desc)
+        , GrMtlTexture(gpu, desc, renderTexture, mipMapsStatus)
+        , GrMtlRenderTarget(gpu, desc, renderTexture) {
+    this->registerWithCache(budgeted);
+}
+
+sk_sp<GrMtlTextureRenderTarget>
+GrMtlTextureRenderTarget::Make(GrMtlGpu* gpu,
+                               const GrSurfaceDesc& desc,
+                               id<MTLTexture> renderTexture,
+                               int mipLevels,
+                               SkBudgeted budgeted,
+                               bool isWrapped) {
+    SkASSERT(nil != renderTexture);
+    if (desc.fSampleCnt > 1) {
+        SkASSERT(false); // Currently don't support MSAA
+        return nullptr;
+    }
+    GrMipMapsStatus mipMapsStatus = mipLevels > 1 ? GrMipMapsStatus::kValid
+                                                  : GrMipMapsStatus::kNotAllocated;
+    if (!isWrapped) {
+        return sk_sp<GrMtlTextureRenderTarget>(new GrMtlTextureRenderTarget(gpu,
+                                                                            budgeted,
+                                                                            desc,
+                                                                            renderTexture,
+                                                                            mipMapsStatus));
+    } else {
+        return nullptr; // Currently don't support wrapped TextureRenderTargets
+    }
+}
+
+
+sk_sp<GrMtlTextureRenderTarget>
+GrMtlTextureRenderTarget::CreateNewTextureRenderTarget(GrMtlGpu* gpu,
+                                                       SkBudgeted budgeted,
+                                                       const GrSurfaceDesc& desc,
+                                                       int mipLevels) {
+    MTLPixelFormat format;
+    if (!GrPixelConfigToMTLFormat(desc.fConfig, &format)) {
+        return nullptr;
+    }
+
+    MTLTextureDescriptor* descriptor = [[MTLTextureDescriptor alloc] init];
+    descriptor.textureType = MTLTextureType2D;
+    descriptor.pixelFormat = format;
+    descriptor.width = desc.fWidth;
+    descriptor.height = desc.fHeight;
+    descriptor.depth = 1;
+    descriptor.mipmapLevelCount = mipLevels;
+    descriptor.sampleCount = 1;
+    descriptor.arrayLength = 1;
+    // descriptor.resourceOptions This looks to be set by setting cpuCacheMode and storageModes
+    descriptor.cpuCacheMode = MTLCPUCacheModeWriteCombined;
+    // RenderTargets never need to be mapped so their storage mode is set to private
+    descriptor.storageMode = MTLStorageModePrivate;
+
+    descriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
+
+    id<MTLTexture> texture = [gpu->device() newTextureWithDescriptor:descriptor];
+
+    return Make(gpu, desc, texture, mipLevels, budgeted, false);
+}
+
+sk_sp<GrMtlTextureRenderTarget>
+GrMtlTextureRenderTarget::MakeWrappedTextureRenderTarget(GrMtlGpu* gpu,
+                                                         const GrSurfaceDesc& desc,
+                                                         GrWrapOwnership wrapOwnership) {
+    return nullptr;
+}