blob: 89f52a262abd22fa4e491f65aac0a164b1364ccb [file] [log] [blame]
/*
* Copyright 2021 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/MtlSharedContext.h"
#include "include/gpu/graphite/BackendTexture.h"
#include "include/gpu/graphite/ContextOptions.h"
#include "include/gpu/graphite/TextureInfo.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/GlobalCache.h"
#include "src/gpu/graphite/Log.h"
#include "src/gpu/graphite/mtl/MtlCommandBuffer.h"
#include "src/gpu/graphite/mtl/MtlResourceProvider.h"
#include "src/gpu/graphite/mtl/MtlTexture.h"
#include "src/gpu/graphite/render/CommonDepthStencilSettings.h"
#include "src/gpu/mtl/MtlMemoryAllocatorImpl.h"
namespace skgpu::graphite {
sk_sp<SharedContext> MtlSharedContext::Make(const MtlBackendContext& context,
const ContextOptions& options) {
if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
// no warning needed
} else {
SKGPU_LOG_E("Skia's Graphite backend no longer supports this OS version.");
#ifdef SK_BUILD_FOR_IOS
SKGPU_LOG_E("Minimum supported version is iOS/tvOS 13.0.");
#else
SKGPU_LOG_E("Minimum supported version is MacOS 10.15.");
#endif
return nullptr;
}
sk_cfp<id<MTLDevice>> device = sk_ret_cfp((id<MTLDevice>)(context.fDevice.get()));
std::unique_ptr<const MtlCaps> caps(new MtlCaps(device.get(), options));
// TODO: Add memory allocator to context once we figure out synchronization
sk_sp<MtlMemoryAllocator> memoryAllocator = skgpu::MtlMemoryAllocatorImpl::Make(device.get());
if (!memoryAllocator) {
SkDEBUGFAIL("No supplied Metal memory allocator and unable to create one internally.");
return nullptr;
}
return sk_sp<SharedContext>(new MtlSharedContext(std::move(device),
std::move(memoryAllocator),
std::move(caps),
options.fExecutor,
options.fUserDefinedKnownRuntimeEffects));
}
MtlSharedContext::MtlSharedContext(sk_cfp<id<MTLDevice>> device,
sk_sp<skgpu::MtlMemoryAllocator> memoryAllocator,
std::unique_ptr<const MtlCaps> caps,
SkExecutor* executor,
SkSpan<sk_sp<SkRuntimeEffect>> userDefinedKnownRuntimeEffects)
: SharedContext(std::move(caps),
BackendApi::kMetal,
executor,
userDefinedKnownRuntimeEffects)
, fMemoryAllocator(std::move(memoryAllocator))
, fDevice(std::move(device)) {
static constexpr DepthStencilSettings kIgnoreDSS;
for (const DepthStencilSettings& dss : { kDirectDepthLessPass,
kDirectDepthLEqualPass,
kWindingStencilPass,
kEvenOddStencilPass,
kRegularCoverPass,
kInverseCoverPass,
kIgnoreDSS }) {
this->createCompatibleDepthStencilState(dss);
}
}
MtlSharedContext::~MtlSharedContext() {
// need to clear out resources before the allocator (if any) is removed
this->globalCache()->deleteResources();
}
std::unique_ptr<ResourceProvider> MtlSharedContext::makeResourceProvider(
SingleOwner* singleOwner,
uint32_t recorderID,
size_t resourceBudget) {
return std::unique_ptr<ResourceProvider>(new MtlResourceProvider(this,
singleOwner,
recorderID,
resourceBudget));
}
namespace {
MTLCompareFunction compare_op_to_mtl(CompareOp op) {
switch (op) {
case CompareOp::kAlways:
return MTLCompareFunctionAlways;
case CompareOp::kNever:
return MTLCompareFunctionNever;
case CompareOp::kGreater:
return MTLCompareFunctionGreater;
case CompareOp::kGEqual:
return MTLCompareFunctionGreaterEqual;
case CompareOp::kLess:
return MTLCompareFunctionLess;
case CompareOp::kLEqual:
return MTLCompareFunctionLessEqual;
case CompareOp::kEqual:
return MTLCompareFunctionEqual;
case CompareOp::kNotEqual:
return MTLCompareFunctionNotEqual;
}
}
MTLStencilOperation stencil_op_to_mtl(StencilOp op) {
switch (op) {
case StencilOp::kKeep:
return MTLStencilOperationKeep;
case StencilOp::kZero:
return MTLStencilOperationZero;
case StencilOp::kReplace:
return MTLStencilOperationReplace;
case StencilOp::kInvert:
return MTLStencilOperationInvert;
case StencilOp::kIncWrap:
return MTLStencilOperationIncrementWrap;
case StencilOp::kDecWrap:
return MTLStencilOperationDecrementWrap;
case StencilOp::kIncClamp:
return MTLStencilOperationIncrementClamp;
case StencilOp::kDecClamp:
return MTLStencilOperationDecrementClamp;
}
}
MTLStencilDescriptor* stencil_face_to_mtl(DepthStencilSettings::Face face) {
MTLStencilDescriptor* result = [[MTLStencilDescriptor alloc] init];
result.stencilCompareFunction = compare_op_to_mtl(face.fCompareOp);
result.readMask = face.fReadMask;
result.writeMask = face.fWriteMask;
result.depthStencilPassOperation = stencil_op_to_mtl(face.fDepthStencilPassOp);
result.stencilFailureOperation = stencil_op_to_mtl(face.fStencilFailOp);
return result;
}
} // anonymous namespace
sk_cfp<id<MTLDepthStencilState>> MtlSharedContext::getCompatibleDepthStencilState(
const DepthStencilSettings& depthStencilSettings) const {
sk_cfp<id<MTLDepthStencilState>>* depthStencilState;
depthStencilState = fDepthStencilStates.find(depthStencilSettings);
// We've explicitly initialized fDepthStencilStates with all the common depth stencil settings
// in the ctor - since there are so few of them. This frees us from concurrency concerns (i.e.,
// if we were to lazily create them and store them in a map). However, if a new one is
// encountered we will need to either add its initialization to the ctor or reconsider this
// approach.
SkAssertResult(depthStencilState);
return *depthStencilState;
}
void MtlSharedContext::createCompatibleDepthStencilState(
const DepthStencilSettings& depthStencilSettings) {
MTLDepthStencilDescriptor* desc = [[MTLDepthStencilDescriptor alloc] init];
SkASSERT(depthStencilSettings.fDepthTestEnabled ||
depthStencilSettings.fDepthCompareOp == CompareOp::kAlways);
desc.depthCompareFunction = compare_op_to_mtl(depthStencilSettings.fDepthCompareOp);
if (depthStencilSettings.fDepthTestEnabled) {
desc.depthWriteEnabled = depthStencilSettings.fDepthWriteEnabled;
}
if (depthStencilSettings.fStencilTestEnabled) {
desc.frontFaceStencil = stencil_face_to_mtl(depthStencilSettings.fFrontStencil);
desc.backFaceStencil = stencil_face_to_mtl(depthStencilSettings.fBackStencil);
}
sk_cfp<id<MTLDepthStencilState>> dss(
[this->device() newDepthStencilStateWithDescriptor: desc]);
fDepthStencilStates.set(depthStencilSettings, std::move(dss));
}
} // namespace skgpu::graphite