blob: e8924a6c07a18123e4744dc3682cf505cd37ff73 [file] [log] [blame]
/*
* 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, *)) {
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, *)) {
(*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