| /* | |
| * Copyright 2022 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "src/gpu/graphite/mtl/MtlSampler.h" | |
| #include "include/core/SkSamplingOptions.h" | |
| #include "src/gpu/graphite/mtl/MtlCaps.h" | |
| #include "src/gpu/graphite/mtl/MtlSharedContext.h" | |
| namespace skgpu::graphite { | |
| MtlSampler::MtlSampler(const MtlSharedContext* sharedContext, | |
| sk_cfp<id<MTLSamplerState>> samplerState) | |
| : Sampler(sharedContext) | |
| , fSamplerState(std::move(samplerState)) {} | |
| static inline MTLSamplerAddressMode tile_mode_to_mtl_sampler_address(SkTileMode tileMode, | |
| const Caps& caps) { | |
| switch (tileMode) { | |
| case SkTileMode::kClamp: | |
| return MTLSamplerAddressModeClampToEdge; | |
| case SkTileMode::kRepeat: | |
| return MTLSamplerAddressModeRepeat; | |
| case SkTileMode::kMirror: | |
| return MTLSamplerAddressModeMirrorRepeat; | |
| case SkTileMode::kDecal: | |
| // For this tilemode, we should have checked that clamp-to-border support exists. | |
| // If it doesn't we should have fallen back to a shader instead. | |
| // TODO: for textures with alpha, we could use ClampToZero if there's no | |
| // ClampToBorderColor as they'll clamp to (0,0,0,0). | |
| // Unfortunately textures without alpha end up clamping to (0,0,0,1). | |
| if (@available(macOS 10.12, iOS 14.0, tvOS 14.0, *)) { | |
| SkASSERT(caps.clampToBorderSupport()); | |
| return MTLSamplerAddressModeClampToBorderColor; | |
| } else { | |
| SkASSERT(false); | |
| return MTLSamplerAddressModeClampToZero; | |
| } | |
| } | |
| SkUNREACHABLE; | |
| } | |
| sk_sp<MtlSampler> MtlSampler::Make(const MtlSharedContext* sharedContext, | |
| const SkSamplingOptions& samplingOptions, | |
| SkTileMode xTileMode, | |
| SkTileMode yTileMode) { | |
| sk_cfp<MTLSamplerDescriptor*> desc([[MTLSamplerDescriptor alloc] init]); | |
| MTLSamplerMinMagFilter minMagFilter = [&] { | |
| switch (samplingOptions.filter) { | |
| case SkFilterMode::kNearest: return MTLSamplerMinMagFilterNearest; | |
| case SkFilterMode::kLinear: return MTLSamplerMinMagFilterLinear; | |
| } | |
| SkUNREACHABLE; | |
| }(); | |
| MTLSamplerMipFilter mipFilter = [&] { | |
| switch (samplingOptions.mipmap) { | |
| case SkMipmapMode::kNone: return MTLSamplerMipFilterNotMipmapped; | |
| case SkMipmapMode::kNearest: return MTLSamplerMipFilterNearest; | |
| case SkMipmapMode::kLinear: return MTLSamplerMipFilterLinear; | |
| } | |
| SkUNREACHABLE; | |
| }(); | |
| (*desc).rAddressMode = MTLSamplerAddressModeClampToEdge; | |
| (*desc).sAddressMode = tile_mode_to_mtl_sampler_address(xTileMode, sharedContext->mtlCaps()); | |
| (*desc).tAddressMode = tile_mode_to_mtl_sampler_address(yTileMode, sharedContext->mtlCaps()); | |
| (*desc).magFilter = minMagFilter; | |
| (*desc).minFilter = minMagFilter; | |
| (*desc).mipFilter = mipFilter; | |
| (*desc).lodMinClamp = 0.0f; | |
| (*desc).lodMaxClamp = FLT_MAX; // default value according to docs. | |
| (*desc).maxAnisotropy = 1; // TODO: if we start using aniso, need to add to key | |
| (*desc).normalizedCoordinates = true; | |
| if (@available(macOS 10.11, iOS 9.0, tvOS 9.0, *)) { | |
| (*desc).compareFunction = MTLCompareFunctionNever; | |
| } | |
| #ifdef SK_ENABLE_MTL_DEBUG_INFO | |
| NSString* tileModeLabels[] = { | |
| @"Clamp", | |
| @"Repeat", | |
| @"Mirror", | |
| @"Decal" | |
| }; | |
| NSString* minMagFilterLabels[] = { | |
| @"Nearest", | |
| @"Linear" | |
| }; | |
| NSString* mipFilterLabels[] = { | |
| @"MipNone", | |
| @"MipNearest", | |
| @"MipLinear" | |
| }; | |
| (*desc).label = [NSString stringWithFormat:@"X%@Y%@%@%@", | |
| tileModeLabels[(int)xTileMode], | |
| tileModeLabels[(int)yTileMode], | |
| minMagFilterLabels[(int)samplingOptions.filter], | |
| mipFilterLabels[(int)samplingOptions.mipmap]]; | |
| #endif | |
| sk_cfp<id<MTLSamplerState>> sampler( | |
| [sharedContext->device() newSamplerStateWithDescriptor:desc.get()]); | |
| if (!sampler) { | |
| return nullptr; | |
| } | |
| return sk_sp<MtlSampler>(new MtlSampler(sharedContext, std::move(sampler))); | |
| } | |
| void MtlSampler::freeGpuData() { | |
| fSamplerState.reset(); | |
| } | |
| } // namespace skgpu::graphite | |