1/* 2 * Copyright 2018 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "src/gpu/GrStencilSettings.h" 9#include "src/gpu/mtl/GrMtlDepthStencil.h" 10#include "src/gpu/mtl/GrMtlGpu.h" 11 12#if !__has_feature(objc_arc) 13#error This file must be compiled with Arc. Use -fobjc-arc flag 14#endif 15 16MTLStencilOperation skia_stencil_op_to_mtl(GrStencilOp op) { 17 switch (op) { 18 case GrStencilOp::kKeep: 19 return MTLStencilOperationKeep; 20 case GrStencilOp::kZero: 21 return MTLStencilOperationZero; 22 case GrStencilOp::kReplace: 23 return MTLStencilOperationReplace; 24 case GrStencilOp::kInvert: 25 return MTLStencilOperationInvert; 26 case GrStencilOp::kIncWrap: 27 return MTLStencilOperationIncrementWrap; 28 case GrStencilOp::kDecWrap: 29 return MTLStencilOperationDecrementWrap; 30 case GrStencilOp::kIncClamp: 31 return MTLStencilOperationIncrementClamp; 32 case GrStencilOp::kDecClamp: 33 return MTLStencilOperationDecrementClamp; 34 } 35} 36 37MTLStencilDescriptor* skia_stencil_to_mtl(GrStencilSettings::Face face) { 38 MTLStencilDescriptor* result = [[MTLStencilDescriptor alloc] init]; 39 switch (face.fTest) { 40 case GrStencilTest::kAlways: 41 result.stencilCompareFunction = MTLCompareFunctionAlways; 42 break; 43 case GrStencilTest::kNever: 44 result.stencilCompareFunction = MTLCompareFunctionNever; 45 break; 46 case GrStencilTest::kGreater: 47 result.stencilCompareFunction = MTLCompareFunctionGreater; 48 break; 49 case GrStencilTest::kGEqual: 50 result.stencilCompareFunction = MTLCompareFunctionGreaterEqual; 51 break; 52 case GrStencilTest::kLess: 53 result.stencilCompareFunction = MTLCompareFunctionLess; 54 break; 55 case GrStencilTest::kLEqual: 56 result.stencilCompareFunction = MTLCompareFunctionLessEqual; 57 break; 58 case GrStencilTest::kEqual: 59 result.stencilCompareFunction = MTLCompareFunctionEqual; 60 break; 61 case GrStencilTest::kNotEqual: 62 result.stencilCompareFunction = MTLCompareFunctionNotEqual; 63 break; 64 } 65 result.readMask = face.fTestMask; 66 result.writeMask = face.fWriteMask; 67 result.depthStencilPassOperation = skia_stencil_op_to_mtl(face.fPassOp); 68 result.stencilFailureOperation = skia_stencil_op_to_mtl(face.fFailOp); 69 return result; 70} 71 72GrMtlDepthStencil* GrMtlDepthStencil::Create(const GrMtlGpu* gpu, 73 const GrStencilSettings& stencil, 74 GrSurfaceOrigin origin) { 75 MTLDepthStencilDescriptor* desc = [[MTLDepthStencilDescriptor alloc] init]; 76 if (!stencil.isDisabled()) { 77 if (stencil.isTwoSided()) { 78 desc.frontFaceStencil = skia_stencil_to_mtl(stencil.front(origin)); 79 desc.backFaceStencil = skia_stencil_to_mtl(stencil.back(origin)); 80 } 81 else { 82 desc.frontFaceStencil = skia_stencil_to_mtl(stencil.frontAndBack()); 83 desc.backFaceStencil = desc.frontFaceStencil; 84 } 85 } 86 87 return new GrMtlDepthStencil([gpu->device() newDepthStencilStateWithDescriptor: desc], 88 GenerateKey(stencil, origin)); 89} 90 91void skia_stencil_to_key(GrStencilSettings::Face face, GrMtlDepthStencil::Key::Face* faceKey) { 92 const int kPassOpShift = 3; 93 const int kFailOpShift = 6; 94 95 faceKey->fReadMask = face.fTestMask; 96 faceKey->fWriteMask = face.fWriteMask; 97 98 SkASSERT(static_cast<int>(face.fTest) <= 7); 99 faceKey->fOps = static_cast<uint32_t>(face.fTest); 100 101 SkASSERT(static_cast<int>(face.fPassOp) <= 7); 102 faceKey->fOps |= (static_cast<uint32_t>(face.fPassOp) << kPassOpShift); 103 104 SkASSERT(static_cast<int>(face.fFailOp) <= 7); 105 faceKey->fOps |= (static_cast<uint32_t>(face.fFailOp) << kFailOpShift); 106} 107 108GrMtlDepthStencil::Key GrMtlDepthStencil::GenerateKey(const GrStencilSettings& stencil, 109 GrSurfaceOrigin origin) { 110 Key depthStencilKey; 111 112 if (stencil.isDisabled()) { 113 memset(&depthStencilKey, 0, sizeof(Key)); 114 } else { 115 if (stencil.isTwoSided()) { 116 skia_stencil_to_key(stencil.front(origin), &depthStencilKey.fFront); 117 skia_stencil_to_key(stencil.back(origin), &depthStencilKey.fBack); 118 } 119 else { 120 skia_stencil_to_key(stencil.frontAndBack(), &depthStencilKey.fFront); 121 memcpy(&depthStencilKey.fBack, &depthStencilKey.fFront, sizeof(Key::Face)); 122 } 123 } 124 125 return depthStencilKey; 126} 127