| /* |
| * 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 |