summaryrefslogtreecommitdiffstats
path: root/libs/hwui/renderstate/Stencil.cpp
blob: 92a057d92c5dbc3b8f61af88f4539c8634e59074 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "renderstate/Stencil.h"

#include "Caches.h"
#include "Debug.h"
#include "Extensions.h"
#include "Properties.h"

#include <GLES2/gl2ext.h>

namespace android {
namespace uirenderer {

#if DEBUG_STENCIL
#define STENCIL_WRITE_VALUE 0xff
#define STENCIL_MASK_VALUE 0xff
#else
#define STENCIL_WRITE_VALUE 0x1
#define STENCIL_MASK_VALUE 0x1
#endif

Stencil::Stencil()
        : mState(kDisabled) {
}

uint8_t Stencil::getStencilSize() {
    return STENCIL_BUFFER_SIZE;
}

/**
 * This method will return either GL_STENCIL_INDEX4_OES if supported,
 * GL_STENCIL_INDEX8 if not.
 *
 * Layers can't use a single bit stencil because multi-rect ClipArea needs a high enough
 * stencil resolution to represent the summation of multiple intersecting rect geometries.
 */
GLenum Stencil::getLayerStencilFormat() {
#if !DEBUG_STENCIL
    const Extensions& extensions = Caches::getInstance().extensions();
    if (extensions.has4BitStencil()) {
        return GL_STENCIL_INDEX4_OES;
    }
#endif
    return GL_STENCIL_INDEX8;
}

void Stencil::clear() {
    glClearStencil(0);
    glClear(GL_STENCIL_BUFFER_BIT);
}

void Stencil::enableTest(int incrementThreshold) {
    if (mState != kTest) {
        enable();
        if (incrementThreshold > 0) {
            glStencilFunc(GL_EQUAL, incrementThreshold, 0xff);
        } else {
            glStencilFunc(GL_EQUAL, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE);
        }
        // We only want to test, let's keep everything
        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
        glStencilMask(0);
        mState = kTest;
    }
}

void Stencil::enableWrite(int incrementThreshold) {
    if (mState != kWrite) {
        enable();
        if (incrementThreshold > 0) {
            glStencilFunc(GL_ALWAYS, 1, 0xff);
            // The test always passes so the first two values are meaningless
            glStencilOp(GL_INCR, GL_INCR, GL_INCR);
        } else {
            glStencilFunc(GL_ALWAYS, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE);
            // The test always passes so the first two values are meaningless
            glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
        }
        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
        glStencilMask(0xff);
        mState = kWrite;
    }
}

void Stencil::enableDebugTest(GLint value, bool greater) {
    enable();
    glStencilFunc(greater ? GL_LESS : GL_EQUAL, value, 0xffffffff);
    // We only want to test, let's keep everything
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    mState = kTest;
}

void Stencil::enableDebugWrite() {
    if (mState != kWrite) {
        enable();
        glStencilFunc(GL_ALWAYS, 0x1, 0xffffffff);
        // The test always passes so the first two values are meaningless
        glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
        mState = kWrite;
    }
}

void Stencil::enable() {
    if (mState == kDisabled) {
        glEnable(GL_STENCIL_TEST);
    }
}

void Stencil::disable() {
    if (mState != kDisabled) {
        glDisable(GL_STENCIL_TEST);
        mState = kDisabled;
    }
}

void Stencil::dump() {
    ALOGD("Stencil: state %d", mState);
}

}; // namespace uirenderer
}; // namespace android