1/* 2 * Copyright 2022 Google LLC 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "experimental/graphite/src/mtl/MtlSampler.h" 9 10#include "experimental/graphite/src/mtl/MtlCaps.h" 11#include "experimental/graphite/src/mtl/MtlGpu.h" 12#include "include/core/SkSamplingOptions.h" 13 14namespace skgpu::mtl { 15 16Sampler::Sampler(const Gpu* gpu, 17 sk_cfp<id<MTLSamplerState>> samplerState) 18 : skgpu::Sampler(gpu) 19 , fSamplerState(std::move(samplerState)) {} 20 21static inline MTLSamplerAddressMode tile_mode_to_mtl_sampler_address(SkTileMode tileMode, 22 const Caps& caps) { 23 switch (tileMode) { 24 case SkTileMode::kClamp: 25 return MTLSamplerAddressModeClampToEdge; 26 case SkTileMode::kRepeat: 27 return MTLSamplerAddressModeRepeat; 28 case SkTileMode::kMirror: 29 return MTLSamplerAddressModeMirrorRepeat; 30 case SkTileMode::kDecal: 31 // For this tilemode, we should have checked that clamp-to-border support exists. 32 // If it doesn't we should have fallen back to a shader instead. 33 // TODO: for textures with alpha, we could use ClampToZero if there's no 34 // ClampToBorderColor as they'll clamp to (0,0,0,0). 35 // Unfortunately textures without alpha end up clamping to (0,0,0,1). 36 if (@available(macOS 10.12, iOS 14.0, *)) { 37 SkASSERT(caps.clampToBorderSupport()); 38 return MTLSamplerAddressModeClampToBorderColor; 39 } else { 40 SkASSERT(false); 41 return MTLSamplerAddressModeClampToZero; 42 } 43 } 44 SkUNREACHABLE; 45} 46 47sk_sp<Sampler> Sampler::Make(const Gpu* gpu, 48 const SkSamplingOptions& samplingOptions, 49 SkTileMode xTileMode, 50 SkTileMode yTileMode) { 51 sk_cfp<MTLSamplerDescriptor*> desc([[MTLSamplerDescriptor alloc] init]); 52 53 MTLSamplerMinMagFilter minMagFilter = [&] { 54 switch (samplingOptions.filter) { 55 case SkFilterMode::kNearest: return MTLSamplerMinMagFilterNearest; 56 case SkFilterMode::kLinear: return MTLSamplerMinMagFilterLinear; 57 } 58 SkUNREACHABLE; 59 }(); 60 61 MTLSamplerMipFilter mipFilter = [&] { 62 switch (samplingOptions.mipmap) { 63 case SkMipmapMode::kNone: return MTLSamplerMipFilterNotMipmapped; 64 case SkMipmapMode::kNearest: return MTLSamplerMipFilterNearest; 65 case SkMipmapMode::kLinear: return MTLSamplerMipFilterLinear; 66 } 67 SkUNREACHABLE; 68 }(); 69 70 auto samplerDesc = [[MTLSamplerDescriptor alloc] init]; 71 samplerDesc.rAddressMode = MTLSamplerAddressModeClampToEdge; 72 samplerDesc.sAddressMode = tile_mode_to_mtl_sampler_address(xTileMode, gpu->mtlCaps()); 73 samplerDesc.tAddressMode = tile_mode_to_mtl_sampler_address(yTileMode, gpu->mtlCaps()); 74 samplerDesc.magFilter = minMagFilter; 75 samplerDesc.minFilter = minMagFilter; 76 samplerDesc.mipFilter = mipFilter; 77 samplerDesc.lodMinClamp = 0.0f; 78 samplerDesc.lodMaxClamp = FLT_MAX; // default value according to docs. 79 samplerDesc.maxAnisotropy = 1.0f; 80 samplerDesc.normalizedCoordinates = true; 81 if (@available(macOS 10.11, iOS 9.0, *)) { 82 samplerDesc.compareFunction = MTLCompareFunctionNever; 83 } 84#ifdef SK_ENABLE_MTL_DEBUG_INFO 85 // TODO: add label? 86#endif 87 88 sk_cfp<id<MTLSamplerState>> sampler([gpu->device() newSamplerStateWithDescriptor:desc.get()]); 89 if (!sampler) { 90 return nullptr; 91 } 92 return sk_sp<Sampler>(new Sampler(gpu, std::move(sampler))); 93} 94 95void Sampler::onFreeGpuData() { 96 fSamplerState.reset(); 97} 98 99} // namespace skgpu::mtl 100 101