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 "src/gpu/graphite/mtl/MtlSampler.h" 9 10#include "include/core/SkSamplingOptions.h" 11#include "src/gpu/graphite/mtl/MtlCaps.h" 12#include "src/gpu/graphite/mtl/MtlSharedContext.h" 13 14namespace skgpu::graphite { 15 16MtlSampler::MtlSampler(const MtlSharedContext* sharedContext, 17 sk_cfp<id<MTLSamplerState>> samplerState) 18 : Sampler(sharedContext) 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, tvOS 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<MtlSampler> MtlSampler::Make(const MtlSharedContext* sharedContext, 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 (*desc).rAddressMode = MTLSamplerAddressModeClampToEdge; 71 (*desc).sAddressMode = tile_mode_to_mtl_sampler_address(xTileMode, sharedContext->mtlCaps()); 72 (*desc).tAddressMode = tile_mode_to_mtl_sampler_address(yTileMode, sharedContext->mtlCaps()); 73 (*desc).magFilter = minMagFilter; 74 (*desc).minFilter = minMagFilter; 75 (*desc).mipFilter = mipFilter; 76 (*desc).lodMinClamp = 0.0f; 77 (*desc).lodMaxClamp = FLT_MAX; // default value according to docs. 78 (*desc).maxAnisotropy = 1; // TODO: if we start using aniso, need to add to key 79 (*desc).normalizedCoordinates = true; 80 if (@available(macOS 10.11, iOS 9.0, tvOS 9.0, *)) { 81 (*desc).compareFunction = MTLCompareFunctionNever; 82 } 83#ifdef SK_ENABLE_MTL_DEBUG_INFO 84 NSString* tileModeLabels[] = { 85 @"Clamp", 86 @"Repeat", 87 @"Mirror", 88 @"Decal" 89 }; 90 NSString* minMagFilterLabels[] = { 91 @"Nearest", 92 @"Linear" 93 }; 94 NSString* mipFilterLabels[] = { 95 @"MipNone", 96 @"MipNearest", 97 @"MipLinear" 98 }; 99 100 (*desc).label = [NSString stringWithFormat:@"X%@Y%@%@%@", 101 tileModeLabels[(int)xTileMode], 102 tileModeLabels[(int)yTileMode], 103 minMagFilterLabels[(int)samplingOptions.filter], 104 mipFilterLabels[(int)samplingOptions.mipmap]]; 105#endif 106 107 sk_cfp<id<MTLSamplerState>> sampler( 108 [sharedContext->device() newSamplerStateWithDescriptor:desc.get()]); 109 if (!sampler) { 110 return nullptr; 111 } 112 return sk_sp<MtlSampler>(new MtlSampler(sharedContext, std::move(sampler))); 113} 114 115void MtlSampler::freeGpuData() { 116 fSamplerState.reset(); 117} 118 119} // namespace skgpu::graphite 120 121