1 /* 2 * Copyright (C) 2010 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 17 #define LOG_TAG "OpenGLRenderer" 18 19 #include "Debug.h" 20 #include "GammaFontRenderer.h" 21 #include "Properties.h" 22 23 namespace android { 24 namespace uirenderer { 25 26 /////////////////////////////////////////////////////////////////////////////// 27 // Utils 28 /////////////////////////////////////////////////////////////////////////////// 29 30 static int luminance(const SkPaint* paint) { 31 uint32_t c = paint->getColor(); 32 const int r = (c >> 16) & 0xFF; 33 const int g = (c >> 8) & 0xFF; 34 const int b = (c ) & 0xFF; 35 return (r * 2 + g * 5 + b) >> 3; 36 } 37 38 /////////////////////////////////////////////////////////////////////////////// 39 // Base class GammaFontRenderer 40 /////////////////////////////////////////////////////////////////////////////// 41 42 GammaFontRenderer* GammaFontRenderer::createRenderer() { 43 // Choose the best renderer 44 char property[PROPERTY_VALUE_MAX]; 45 if (property_get(PROPERTY_TEXT_GAMMA_METHOD, property, DEFAULT_TEXT_GAMMA_METHOD) > 0) { 46 if (!strcasecmp(property, "lookup")) { 47 return new LookupGammaFontRenderer(); 48 } else if (!strcasecmp(property, "shader")) { 49 return new ShaderGammaFontRenderer(false); 50 } else if (!strcasecmp(property, "shader3")) { 51 return new ShaderGammaFontRenderer(true); 52 } 53 } 54 55 return new Lookup3GammaFontRenderer(); 56 } 57 58 GammaFontRenderer::GammaFontRenderer() { 59 // Get the renderer properties 60 char property[PROPERTY_VALUE_MAX]; 61 62 // Get the gamma 63 mGamma = DEFAULT_TEXT_GAMMA; 64 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) { 65 INIT_LOGD(" Setting text gamma to %s", property); 66 mGamma = atof(property); 67 } else { 68 INIT_LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA); 69 } 70 71 // Get the black gamma threshold 72 mBlackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD; 73 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) { 74 INIT_LOGD(" Setting text black gamma threshold to %s", property); 75 mBlackThreshold = atoi(property); 76 } else { 77 INIT_LOGD(" Using default text black gamma threshold of %d", 78 DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD); 79 } 80 81 // Get the white gamma threshold 82 mWhiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD; 83 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) { 84 INIT_LOGD(" Setting text white gamma threshold to %s", property); 85 mWhiteThreshold = atoi(property); 86 } else { 87 INIT_LOGD(" Using default white black gamma threshold of %d", 88 DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD); 89 } 90 } 91 92 GammaFontRenderer::~GammaFontRenderer() { 93 } 94 95 /////////////////////////////////////////////////////////////////////////////// 96 // Shader-based renderer 97 /////////////////////////////////////////////////////////////////////////////// 98 99 ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma): GammaFontRenderer() { 100 INIT_LOGD("Creating shader gamma font renderer"); 101 mRenderer = NULL; 102 mMultiGamma = multiGamma; 103 } 104 105 void ShaderGammaFontRenderer::describe(ProgramDescription& description, 106 const SkPaint* paint) const { 107 if (paint->getShader() == NULL) { 108 if (mMultiGamma) { 109 const int l = luminance(paint); 110 111 if (l <= mBlackThreshold) { 112 description.hasGammaCorrection = true; 113 description.gamma = mGamma; 114 } else if (l >= mWhiteThreshold) { 115 description.hasGammaCorrection = true; 116 description.gamma = 1.0f / mGamma; 117 } 118 } else { 119 description.hasGammaCorrection = true; 120 description.gamma = 1.0f / mGamma; 121 } 122 } 123 } 124 125 void ShaderGammaFontRenderer::setupProgram(ProgramDescription& description, 126 Program* program) const { 127 if (description.hasGammaCorrection) { 128 glUniform1f(program->getUniform("gamma"), description.gamma); 129 } 130 } 131 132 void ShaderGammaFontRenderer::endPrecaching() { 133 if (mRenderer) { 134 mRenderer->endPrecaching(); 135 } 136 } 137 138 /////////////////////////////////////////////////////////////////////////////// 139 // Lookup-based renderer 140 /////////////////////////////////////////////////////////////////////////////// 141 142 LookupGammaFontRenderer::LookupGammaFontRenderer(): GammaFontRenderer() { 143 INIT_LOGD("Creating lookup gamma font renderer"); 144 145 // Compute the gamma tables 146 const float gamma = 1.0f / mGamma; 147 148 for (uint32_t i = 0; i <= 255; i++) { 149 mGammaTable[i] = uint8_t((float)::floor(pow(i / 255.0f, gamma) * 255.0f + 0.5f)); 150 } 151 152 mRenderer = NULL; 153 } 154 155 void LookupGammaFontRenderer::endPrecaching() { 156 if (mRenderer) { 157 mRenderer->endPrecaching(); 158 } 159 } 160 161 /////////////////////////////////////////////////////////////////////////////// 162 // Lookup-based renderer, using 3 different correction tables 163 /////////////////////////////////////////////////////////////////////////////// 164 165 Lookup3GammaFontRenderer::Lookup3GammaFontRenderer(): GammaFontRenderer() { 166 INIT_LOGD("Creating lookup3 gamma font renderer"); 167 168 // Compute the gamma tables 169 const float blackGamma = mGamma; 170 const float whiteGamma = 1.0f / mGamma; 171 172 for (uint32_t i = 0; i <= 255; i++) { 173 const float v = i / 255.0f; 174 const float black = pow(v, blackGamma); 175 const float white = pow(v, whiteGamma); 176 177 mGammaTable[i] = i; 178 mGammaTable[256 + i] = uint8_t((float)::floor(black * 255.0f + 0.5f)); 179 mGammaTable[512 + i] = uint8_t((float)::floor(white * 255.0f + 0.5f)); 180 } 181 182 memset(mRenderers, 0, sizeof(FontRenderer*) * kGammaCount); 183 memset(mRenderersUsageCount, 0, sizeof(uint32_t) * kGammaCount); 184 } 185 186 Lookup3GammaFontRenderer::~Lookup3GammaFontRenderer() { 187 for (int i = 0; i < kGammaCount; i++) { 188 delete mRenderers[i]; 189 } 190 } 191 192 void Lookup3GammaFontRenderer::endPrecaching() { 193 for (int i = 0; i < kGammaCount; i++) { 194 if (mRenderers[i]) { 195 mRenderers[i]->endPrecaching(); 196 } 197 } 198 } 199 200 void Lookup3GammaFontRenderer::clear() { 201 for (int i = 0; i < kGammaCount; i++) { 202 delete mRenderers[i]; 203 mRenderers[i] = NULL; 204 } 205 } 206 207 void Lookup3GammaFontRenderer::flush() { 208 int count = 0; 209 int min = -1; 210 uint32_t minCount = UINT_MAX; 211 212 for (int i = 0; i < kGammaCount; i++) { 213 if (mRenderers[i]) { 214 count++; 215 if (mRenderersUsageCount[i] < minCount) { 216 minCount = mRenderersUsageCount[i]; 217 min = i; 218 } 219 } 220 } 221 222 if (count <= 1 || min < 0) return; 223 224 delete mRenderers[min]; 225 mRenderers[min] = NULL; 226 227 // Also eliminate the caches for large glyphs, as they consume significant memory 228 for (int i = 0; i < kGammaCount; ++i) { 229 if (mRenderers[i]) { 230 mRenderers[i]->flushLargeCaches(); 231 } 232 } 233 } 234 235 FontRenderer* Lookup3GammaFontRenderer::getRenderer(Gamma gamma) { 236 FontRenderer* renderer = mRenderers[gamma]; 237 if (!renderer) { 238 renderer = new FontRenderer(); 239 mRenderers[gamma] = renderer; 240 renderer->setGammaTable(&mGammaTable[gamma * 256]); 241 } 242 mRenderersUsageCount[gamma]++; 243 return renderer; 244 } 245 246 FontRenderer& Lookup3GammaFontRenderer::getFontRenderer(const SkPaint* paint) { 247 if (paint->getShader() == NULL) { 248 const int l = luminance(paint); 249 250 if (l <= mBlackThreshold) { 251 return *getRenderer(kGammaBlack); 252 } else if (l >= mWhiteThreshold) { 253 return *getRenderer(kGammaWhite); 254 } 255 } 256 return *getRenderer(kGammaDefault); 257 } 258 259 }; // namespace uirenderer 260 }; // namespace android 261