implemented GrMtlSampler for metal gpu backend

Bug: skia:
Change-Id: I936e5510e5ee146c0fc6bdbc0d5f5352359fbe7d
Reviewed-on: https://skia-review.googlesource.com/145893
Commit-Queue: Timothy Liang <timliang@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 4139c4c..1d41773 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -645,6 +645,8 @@
   "$_src/gpu/mtl/GrMtlRenderTarget.mm",
   "$_src/gpu/mtl/GrMtlResourceProvider.h",
   "$_src/gpu/mtl/GrMtlResourceProvider.mm",
+  "$_src/gpu/mtl/GrMtlSampler.h",
+  "$_src/gpu/mtl/GrMtlSampler.mm",
   "$_src/gpu/mtl/GrMtlTexture.h",
   "$_src/gpu/mtl/GrMtlTexture.mm",
   "$_src/gpu/mtl/GrMtlTextureRenderTarget.h",
diff --git a/src/gpu/mtl/GrMtlSampler.h b/src/gpu/mtl/GrMtlSampler.h
new file mode 100644
index 0000000..8a24b9a
--- /dev/null
+++ b/src/gpu/mtl/GrMtlSampler.h
@@ -0,0 +1,30 @@
+/*
+ * 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 GrMtlSampler_DEFINED
+#define GrMtlSampler_DEFINED
+
+#import <metal/metal.h>
+
+class GrSamplerState;
+class GrMtlGpu;
+
+// This class only acts as a wrapper for a MTLSamplerState object for now, but will be more useful
+// once we start caching sampler states.
+class GrMtlSampler {
+public:
+    static GrMtlSampler* Create(const GrMtlGpu* gpu, const GrSamplerState&, uint32_t maxMipLevel);
+
+    id<MTLSamplerState> mtlSamplerState() const { return fMtlSamplerState; }
+
+private:
+    GrMtlSampler(id<MTLSamplerState> mtlSamplerState) : fMtlSamplerState(mtlSamplerState) {}
+
+    id<MTLSamplerState> fMtlSamplerState;
+};
+
+#endif
diff --git a/src/gpu/mtl/GrMtlSampler.mm b/src/gpu/mtl/GrMtlSampler.mm
new file mode 100644
index 0000000..54145fc
--- /dev/null
+++ b/src/gpu/mtl/GrMtlSampler.mm
@@ -0,0 +1,54 @@
+/*
+ * 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 "GrMtlSampler.h"
+
+#include "GrMtlGpu.h"
+
+static inline MTLSamplerAddressMode wrap_mode_to_mtl_sampler_address(
+        GrSamplerState::WrapMode wrapMode) {
+    switch (wrapMode) {
+        case GrSamplerState::WrapMode::kClamp:
+            return MTLSamplerAddressModeClampToEdge;
+        case GrSamplerState::WrapMode::kRepeat:
+            return MTLSamplerAddressModeRepeat;
+        case GrSamplerState::WrapMode::kMirrorRepeat:
+            return MTLSamplerAddressModeMirrorRepeat;
+    }
+    SK_ABORT("Unknown wrap mode.");
+    return MTLSamplerAddressModeClampToEdge;
+}
+
+GrMtlSampler* GrMtlSampler::Create(const GrMtlGpu* gpu, const GrSamplerState& samplerState,
+                                   uint32_t maxMipLevel) {
+    static MTLSamplerMinMagFilter mtlMinMagFilterModes[] = {
+        MTLSamplerMinMagFilterNearest,
+        MTLSamplerMinMagFilterLinear,
+        MTLSamplerMinMagFilterLinear
+    };
+
+    GR_STATIC_ASSERT((int)GrSamplerState::Filter::kNearest == 0);
+    GR_STATIC_ASSERT((int)GrSamplerState::Filter::kBilerp == 1);
+    GR_STATIC_ASSERT((int)GrSamplerState::Filter::kMipMap == 2);
+
+    auto samplerDesc = [[MTLSamplerDescriptor alloc] init];
+    samplerDesc.rAddressMode = MTLSamplerAddressModeClampToEdge;
+    samplerDesc.sAddressMode = wrap_mode_to_mtl_sampler_address(samplerState.wrapModeX());
+    samplerDesc.tAddressMode = wrap_mode_to_mtl_sampler_address(samplerState.wrapModeY());
+    samplerDesc.magFilter = mtlMinMagFilterModes[static_cast<int>(samplerState.filter())];
+    samplerDesc.minFilter = mtlMinMagFilterModes[static_cast<int>(samplerState.filter())];
+    samplerDesc.mipFilter = MTLSamplerMipFilterLinear;
+    samplerDesc.lodMinClamp = 0.0f;
+    bool useMipMaps = GrSamplerState::Filter::kMipMap == samplerState.filter() && maxMipLevel > 0;
+    samplerDesc.lodMaxClamp = !useMipMaps ? 0.0f : (float)(maxMipLevel);
+    samplerDesc.maxAnisotropy = 1.0f;
+    samplerDesc.normalizedCoordinates = true;
+    samplerDesc.compareFunction = MTLCompareFunctionNever;
+    samplerDesc.borderColor = MTLSamplerBorderColorTransparentBlack;
+
+    return new GrMtlSampler([gpu->device() newSamplerStateWithDescriptor: samplerDesc]);
+}