• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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