1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16#include "renderstate/TextureState.h" 17 18#include "Caches.h" 19#include "utils/TraceUtils.h" 20 21#include <GLES3/gl3.h> 22#include <SkBitmap.h> 23#include <SkCanvas.h> 24#include <memory> 25 26namespace android { 27namespace uirenderer { 28 29// Width of mShadowLutTexture, defines how accurate the shadow alpha lookup table is 30static const int SHADOW_LUT_SIZE = 128; 31 32// Must define as many texture units as specified by kTextureUnitsCount 33const GLenum kTextureUnits[] = {GL_TEXTURE0, GL_TEXTURE1, GL_TEXTURE2, GL_TEXTURE3}; 34 35TextureState::TextureState() : mTextureUnit(0) { 36 glActiveTexture(kTextureUnits[0]); 37 resetBoundTextures(); 38 39 GLint maxTextureUnits; 40 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); 41 LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount, 42 "At least %d texture units are required!", kTextureUnitsCount); 43 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 44} 45 46TextureState::~TextureState() { 47 if (mShadowLutTexture != nullptr) { 48 mShadowLutTexture->deleteTexture(); 49 } 50} 51 52/** 53 * Maps shadow geometry 'alpha' varying (1 for darkest, 0 for transparent) to 54 * darkness at that spot. Input values of 0->1 should be mapped within the same 55 * range, but can affect the curve for a different visual falloff. 56 * 57 * This is used to populate the shadow LUT texture for quick lookup in the 58 * shadow shader. 59 */ 60static float computeShadowOpacity(float ratio) { 61 // exponential falloff function provided by UX 62 float val = 1 - ratio; 63 return exp(-val * val * 4.0) - 0.018; 64} 65 66void TextureState::constructTexture(Caches& caches) { 67 if (mShadowLutTexture == nullptr) { 68 mShadowLutTexture.reset(new Texture(caches)); 69 70 unsigned char bytes[SHADOW_LUT_SIZE]; 71 for (int i = 0; i < SHADOW_LUT_SIZE; i++) { 72 float inputRatio = i / (SHADOW_LUT_SIZE - 1.0f); 73 bytes[i] = computeShadowOpacity(inputRatio) * 255; 74 } 75 mShadowLutTexture->upload(GL_ALPHA, SHADOW_LUT_SIZE, 1, GL_ALPHA, GL_UNSIGNED_BYTE, &bytes); 76 mShadowLutTexture->setFilter(GL_LINEAR); 77 mShadowLutTexture->setWrap(GL_CLAMP_TO_EDGE); 78 } 79} 80 81void TextureState::activateTexture(GLuint textureUnit) { 82 LOG_ALWAYS_FATAL_IF(textureUnit >= kTextureUnitsCount, 83 "Tried to use texture unit index %d, only %d exist", textureUnit, 84 kTextureUnitsCount); 85 if (mTextureUnit != textureUnit) { 86 glActiveTexture(kTextureUnits[textureUnit]); 87 mTextureUnit = textureUnit; 88 } 89} 90 91void TextureState::resetActiveTexture() { 92 mTextureUnit = -1; 93} 94 95void TextureState::bindTexture(GLuint texture) { 96 if (mBoundTextures[mTextureUnit] != texture) { 97 glBindTexture(GL_TEXTURE_2D, texture); 98 mBoundTextures[mTextureUnit] = texture; 99 } 100} 101 102void TextureState::bindTexture(GLenum target, GLuint texture) { 103 if (target == GL_TEXTURE_2D) { 104 bindTexture(texture); 105 } else { 106 // GLConsumer directly calls glBindTexture() with 107 // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target 108 // since the cached state could be stale 109 glBindTexture(target, texture); 110 } 111} 112 113void TextureState::deleteTexture(GLuint texture) { 114 // When glDeleteTextures() is called on a currently bound texture, 115 // OpenGL ES specifies that the texture is then considered unbound 116 // Consider the following series of calls: 117 // 118 // glGenTextures -> creates texture name 2 119 // glBindTexture(2) 120 // glDeleteTextures(2) -> 2 is now unbound 121 // glGenTextures -> can return 2 again 122 // 123 // If we don't call glBindTexture(2) after the second glGenTextures 124 // call, any texture operation will be performed on the default 125 // texture (name=0) 126 127 unbindTexture(texture); 128 129 glDeleteTextures(1, &texture); 130} 131 132void TextureState::resetBoundTextures() { 133 for (int i = 0; i < kTextureUnitsCount; i++) { 134 mBoundTextures[i] = 0; 135 } 136} 137 138void TextureState::unbindTexture(GLuint texture) { 139 for (int i = 0; i < kTextureUnitsCount; i++) { 140 if (mBoundTextures[i] == texture) { 141 mBoundTextures[i] = 0; 142 } 143 } 144} 145 146} /* namespace uirenderer */ 147} /* namespace android */ 148