blob: 69d3edfc2459f0b61daacc1fdbe0f4fd70411aa8 [file] [log] [blame]
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/ganesh/GrStencilSettings.h"
#include "src/gpu/ganesh/mtl/GrMtlDepthStencil.h"
#include "src/gpu/ganesh/mtl/GrMtlGpu.h"
#if !__has_feature(objc_arc)
#error This file must be compiled with Arc. Use -fobjc-arc flag
#endif
GR_NORETAIN_BEGIN
MTLStencilOperation skia_stencil_op_to_mtl(GrStencilOp op) {
switch (op) {
case GrStencilOp::kKeep:
return MTLStencilOperationKeep;
case GrStencilOp::kZero:
return MTLStencilOperationZero;
case GrStencilOp::kReplace:
return MTLStencilOperationReplace;
case GrStencilOp::kInvert:
return MTLStencilOperationInvert;
case GrStencilOp::kIncWrap:
return MTLStencilOperationIncrementWrap;
case GrStencilOp::kDecWrap:
return MTLStencilOperationDecrementWrap;
case GrStencilOp::kIncClamp:
return MTLStencilOperationIncrementClamp;
case GrStencilOp::kDecClamp:
return MTLStencilOperationDecrementClamp;
}
}
MTLStencilDescriptor* skia_stencil_to_mtl(GrStencilSettings::Face face) {
MTLStencilDescriptor* result = [[MTLStencilDescriptor alloc] init];
switch (face.fTest) {
case GrStencilTest::kAlways:
result.stencilCompareFunction = MTLCompareFunctionAlways;
break;
case GrStencilTest::kNever:
result.stencilCompareFunction = MTLCompareFunctionNever;
break;
case GrStencilTest::kGreater:
result.stencilCompareFunction = MTLCompareFunctionGreater;
break;
case GrStencilTest::kGEqual:
result.stencilCompareFunction = MTLCompareFunctionGreaterEqual;
break;
case GrStencilTest::kLess:
result.stencilCompareFunction = MTLCompareFunctionLess;
break;
case GrStencilTest::kLEqual:
result.stencilCompareFunction = MTLCompareFunctionLessEqual;
break;
case GrStencilTest::kEqual:
result.stencilCompareFunction = MTLCompareFunctionEqual;
break;
case GrStencilTest::kNotEqual:
result.stencilCompareFunction = MTLCompareFunctionNotEqual;
break;
}
result.readMask = face.fTestMask;
result.writeMask = face.fWriteMask;
result.depthStencilPassOperation = skia_stencil_op_to_mtl(face.fPassOp);
result.stencilFailureOperation = skia_stencil_op_to_mtl(face.fFailOp);
return result;
}
GrMtlDepthStencil* GrMtlDepthStencil::Create(const GrMtlGpu* gpu,
const GrStencilSettings& stencil,
GrSurfaceOrigin origin) {
MTLDepthStencilDescriptor* desc = [[MTLDepthStencilDescriptor alloc] init];
if (!stencil.isDisabled()) {
if (stencil.isTwoSided()) {
desc.frontFaceStencil = skia_stencil_to_mtl(stencil.postOriginCCWFace(origin));
desc.backFaceStencil = skia_stencil_to_mtl(stencil.postOriginCWFace(origin));
}
else {
desc.frontFaceStencil = skia_stencil_to_mtl(stencil.singleSidedFace());
desc.backFaceStencil = desc.frontFaceStencil;
}
}
return new GrMtlDepthStencil([gpu->device() newDepthStencilStateWithDescriptor: desc],
GenerateKey(stencil, origin));
}
void skia_stencil_to_key(GrStencilSettings::Face face, GrMtlDepthStencil::Key::Face* faceKey) {
const int kPassOpShift = 3;
const int kFailOpShift = 6;
faceKey->fReadMask = face.fTestMask;
faceKey->fWriteMask = face.fWriteMask;
SkASSERT(static_cast<int>(face.fTest) <= 7);
faceKey->fOps = static_cast<uint32_t>(face.fTest);
SkASSERT(static_cast<int>(face.fPassOp) <= 7);
faceKey->fOps |= (static_cast<uint32_t>(face.fPassOp) << kPassOpShift);
SkASSERT(static_cast<int>(face.fFailOp) <= 7);
faceKey->fOps |= (static_cast<uint32_t>(face.fFailOp) << kFailOpShift);
}
GrMtlDepthStencil::Key GrMtlDepthStencil::GenerateKey(const GrStencilSettings& stencil,
GrSurfaceOrigin origin) {
Key depthStencilKey;
if (stencil.isDisabled()) {
memset(&depthStencilKey, 0, sizeof(Key));
} else {
if (stencil.isTwoSided()) {
skia_stencil_to_key(stencil.postOriginCCWFace(origin), &depthStencilKey.fFront);
skia_stencil_to_key(stencil.postOriginCWFace(origin), &depthStencilKey.fBack);
}
else {
skia_stencil_to_key(stencil.singleSidedFace(), &depthStencilKey.fFront);
memcpy(&depthStencilKey.fBack, &depthStencilKey.fFront, sizeof(Key::Face));
}
}
return depthStencilKey;
}
GR_NORETAIN_END