/* * 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 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() { glStencilMask(0xff); glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); if (mState == StencilState::Test) { // reset to test state, with immutable stencil glStencilMask(0); } } void Stencil::enableTest(int incrementThreshold) { if (mState != StencilState::Test) { 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 = StencilState::Test; } } void Stencil::enableWrite(int incrementThreshold) { if (mState != StencilState::Write) { 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 = StencilState::Write; } } 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 = StencilState::Test; glStencilMask(0); } void Stencil::enableDebugWrite() { 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 = StencilState::Write; glStencilMask(0xff); } void Stencil::enable() { if (mState == StencilState::Disabled) { glEnable(GL_STENCIL_TEST); } } void Stencil::disable() { if (mState != StencilState::Disabled) { glDisable(GL_STENCIL_TEST); mState = StencilState::Disabled; } } void Stencil::dump() { ALOGD("Stencil: state %d", mState); } }; // namespace uirenderer }; // namespace android