Caches.cpp revision db663fe83f976107fd8fd9307d871b37d9e47370
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 "Caches.h" 20 21#include "GammaFontRenderer.h" 22#include "LayerRenderer.h" 23#include "Properties.h" 24#include "renderstate/RenderState.h" 25#include "ShadowTessellator.h" 26 27#include <utils/Log.h> 28#include <utils/String8.h> 29 30namespace android { 31namespace uirenderer { 32 33Caches* Caches::sInstance = nullptr; 34 35/////////////////////////////////////////////////////////////////////////////// 36// Macros 37/////////////////////////////////////////////////////////////////////////////// 38 39#if DEBUG_CACHE_FLUSH 40 #define FLUSH_LOGD(...) ALOGD(__VA_ARGS__) 41#else 42 #define FLUSH_LOGD(...) 43#endif 44 45/////////////////////////////////////////////////////////////////////////////// 46// Constructors/destructor 47/////////////////////////////////////////////////////////////////////////////// 48 49Caches::Caches(RenderState& renderState) 50 : gradientCache(mExtensions) 51 , patchCache(renderState) 52 , programCache(mExtensions) 53 , dither(*this) 54 , mRenderState(&renderState) 55 , mInitialized(false) { 56 INIT_LOGD("Creating OpenGL renderer caches"); 57 init(); 58 initFont(); 59 initConstraints(); 60 initProperties(); 61 initStaticProperties(); 62 initExtensions(); 63 initTempProperties(); 64 65 mDebugLevel = readDebugLevel(); 66 ALOGD_IF(mDebugLevel != kDebugDisabled, 67 "Enabling debug mode %d", mDebugLevel); 68} 69 70bool Caches::init() { 71 if (mInitialized) return false; 72 73 ATRACE_NAME("Caches::init"); 74 75 mRegionMesh = nullptr; 76 mProgram = nullptr; 77 78 mFunctorsCount = 0; 79 80 debugLayersUpdates = false; 81 debugOverdraw = false; 82 debugStencilClip = kStencilHide; 83 84 patchCache.init(); 85 86 mInitialized = true; 87 88 mPixelBufferState = new PixelBufferState(); 89 mTextureState = new TextureState(); 90 91 return true; 92} 93 94void Caches::initFont() { 95 fontRenderer = GammaFontRenderer::createRenderer(); 96} 97 98void Caches::initExtensions() { 99 if (mExtensions.hasDebugMarker()) { 100 eventMark = glInsertEventMarkerEXT; 101 102 startMark = glPushGroupMarkerEXT; 103 endMark = glPopGroupMarkerEXT; 104 } else { 105 eventMark = eventMarkNull; 106 startMark = startMarkNull; 107 endMark = endMarkNull; 108 } 109} 110 111void Caches::initConstraints() { 112 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); 113} 114 115void Caches::initStaticProperties() { 116 gpuPixelBuffersEnabled = false; 117 118 // OpenGL ES 3.0+ specific features 119 if (mExtensions.hasPixelBufferObjects()) { 120 char property[PROPERTY_VALUE_MAX]; 121 if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "true") > 0) { 122 gpuPixelBuffersEnabled = !strcmp(property, "true"); 123 } 124 } 125} 126 127bool Caches::initProperties() { 128 bool prevDebugLayersUpdates = debugLayersUpdates; 129 bool prevDebugOverdraw = debugOverdraw; 130 StencilClipDebug prevDebugStencilClip = debugStencilClip; 131 132 char property[PROPERTY_VALUE_MAX]; 133 if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, nullptr) > 0) { 134 INIT_LOGD(" Layers updates debug enabled: %s", property); 135 debugLayersUpdates = !strcmp(property, "true"); 136 } else { 137 debugLayersUpdates = false; 138 } 139 140 debugOverdraw = false; 141 if (property_get(PROPERTY_DEBUG_OVERDRAW, property, nullptr) > 0) { 142 INIT_LOGD(" Overdraw debug enabled: %s", property); 143 if (!strcmp(property, "show")) { 144 debugOverdraw = true; 145 mOverdrawDebugColorSet = kColorSet_Default; 146 } else if (!strcmp(property, "show_deuteranomaly")) { 147 debugOverdraw = true; 148 mOverdrawDebugColorSet = kColorSet_Deuteranomaly; 149 } 150 } 151 152 // See Properties.h for valid values 153 if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, nullptr) > 0) { 154 INIT_LOGD(" Stencil clip debug enabled: %s", property); 155 if (!strcmp(property, "hide")) { 156 debugStencilClip = kStencilHide; 157 } else if (!strcmp(property, "highlight")) { 158 debugStencilClip = kStencilShowHighlight; 159 } else if (!strcmp(property, "region")) { 160 debugStencilClip = kStencilShowRegion; 161 } 162 } else { 163 debugStencilClip = kStencilHide; 164 } 165 166 if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) { 167 drawDeferDisabled = !strcasecmp(property, "true"); 168 INIT_LOGD(" Draw defer %s", drawDeferDisabled ? "disabled" : "enabled"); 169 } else { 170 drawDeferDisabled = false; 171 INIT_LOGD(" Draw defer enabled"); 172 } 173 174 if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) { 175 drawReorderDisabled = !strcasecmp(property, "true"); 176 INIT_LOGD(" Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled"); 177 } else { 178 drawReorderDisabled = false; 179 INIT_LOGD(" Draw reorder enabled"); 180 } 181 182 return (prevDebugLayersUpdates != debugLayersUpdates) 183 || (prevDebugOverdraw != debugOverdraw) 184 || (prevDebugStencilClip != debugStencilClip); 185} 186 187void Caches::terminate() { 188 if (!mInitialized) return; 189 mRegionMesh.release(); 190 191 fboCache.clear(); 192 193 programCache.clear(); 194 mProgram = nullptr; 195 196 patchCache.clear(); 197 198 clearGarbage(); 199 200 delete mPixelBufferState; 201 mPixelBufferState = nullptr; 202 delete mTextureState; 203 mTextureState = nullptr; 204 mInitialized = false; 205} 206 207void Caches::setProgram(const ProgramDescription& description) { 208 setProgram(programCache.get(description)); 209} 210 211void Caches::setProgram(Program* program) { 212 if (!program || !program->isInUse()) { 213 if (mProgram) { 214 mProgram->remove(); 215 } 216 if (program) { 217 program->use(); 218 } 219 mProgram = program; 220 } 221} 222 223/////////////////////////////////////////////////////////////////////////////// 224// Debug 225/////////////////////////////////////////////////////////////////////////////// 226 227uint32_t Caches::getOverdrawColor(uint32_t amount) const { 228 static uint32_t sOverdrawColors[2][4] = { 229 { 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 }, 230 { 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 } 231 }; 232 if (amount < 1) amount = 1; 233 if (amount > 4) amount = 4; 234 return sOverdrawColors[mOverdrawDebugColorSet][amount - 1]; 235} 236 237void Caches::dumpMemoryUsage() { 238 String8 stringLog; 239 dumpMemoryUsage(stringLog); 240 ALOGD("%s", stringLog.string()); 241} 242 243void Caches::dumpMemoryUsage(String8 &log) { 244 uint32_t total = 0; 245 log.appendFormat("Current memory usage / total memory usage (bytes):\n"); 246 log.appendFormat(" TextureCache %8d / %8d\n", 247 textureCache.getSize(), textureCache.getMaxSize()); 248 log.appendFormat(" LayerCache %8d / %8d (numLayers = %zu)\n", 249 layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount()); 250 if (mRenderState) { 251 int memused = 0; 252 for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin(); 253 it != mRenderState->mActiveLayers.end(); it++) { 254 const Layer* layer = *it; 255 log.appendFormat(" Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n", 256 layer->getWidth(), layer->getHeight(), 257 layer->isTextureLayer(), layer->getTextureId(), 258 layer->getFbo(), layer->getStrongCount()); 259 memused += layer->getWidth() * layer->getHeight() * 4; 260 } 261 log.appendFormat(" Layers total %8d (numLayers = %zu)\n", 262 memused, mRenderState->mActiveLayers.size()); 263 total += memused; 264 } 265 log.appendFormat(" RenderBufferCache %8d / %8d\n", 266 renderBufferCache.getSize(), renderBufferCache.getMaxSize()); 267 log.appendFormat(" GradientCache %8d / %8d\n", 268 gradientCache.getSize(), gradientCache.getMaxSize()); 269 log.appendFormat(" PathCache %8d / %8d\n", 270 pathCache.getSize(), pathCache.getMaxSize()); 271 log.appendFormat(" TessellationCache %8d / %8d\n", 272 tessellationCache.getSize(), tessellationCache.getMaxSize()); 273 log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(), 274 dropShadowCache.getMaxSize()); 275 log.appendFormat(" PatchCache %8d / %8d\n", 276 patchCache.getSize(), patchCache.getMaxSize()); 277 for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) { 278 const uint32_t sizeA8 = fontRenderer->getFontRendererSize(i, GL_ALPHA); 279 const uint32_t sizeRGBA = fontRenderer->getFontRendererSize(i, GL_RGBA); 280 log.appendFormat(" FontRenderer %d A8 %8d / %8d\n", i, sizeA8, sizeA8); 281 log.appendFormat(" FontRenderer %d RGBA %8d / %8d\n", i, sizeRGBA, sizeRGBA); 282 log.appendFormat(" FontRenderer %d total %8d / %8d\n", i, sizeA8 + sizeRGBA, 283 sizeA8 + sizeRGBA); 284 } 285 log.appendFormat("Other:\n"); 286 log.appendFormat(" FboCache %8d / %8d\n", 287 fboCache.getSize(), fboCache.getMaxSize()); 288 289 total += textureCache.getSize(); 290 total += renderBufferCache.getSize(); 291 total += gradientCache.getSize(); 292 total += pathCache.getSize(); 293 total += tessellationCache.getSize(); 294 total += dropShadowCache.getSize(); 295 total += patchCache.getSize(); 296 for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) { 297 total += fontRenderer->getFontRendererSize(i, GL_ALPHA); 298 total += fontRenderer->getFontRendererSize(i, GL_RGBA); 299 } 300 301 log.appendFormat("Total memory usage:\n"); 302 log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f); 303} 304 305/////////////////////////////////////////////////////////////////////////////// 306// Memory management 307/////////////////////////////////////////////////////////////////////////////// 308 309void Caches::clearGarbage() { 310 textureCache.clearGarbage(); 311 pathCache.clearGarbage(); 312 patchCache.clearGarbage(); 313} 314 315void Caches::flush(FlushMode mode) { 316 FLUSH_LOGD("Flushing caches (mode %d)", mode); 317 318 // We must stop tasks before clearing caches 319 if (mode > kFlushMode_Layers) { 320 tasks.stop(); 321 } 322 323 switch (mode) { 324 case kFlushMode_Full: 325 textureCache.clear(); 326 patchCache.clear(); 327 dropShadowCache.clear(); 328 gradientCache.clear(); 329 fontRenderer->clear(); 330 fboCache.clear(); 331 dither.clear(); 332 // fall through 333 case kFlushMode_Moderate: 334 fontRenderer->flush(); 335 textureCache.flush(); 336 pathCache.clear(); 337 tessellationCache.clear(); 338 // fall through 339 case kFlushMode_Layers: 340 layerCache.clear(); 341 renderBufferCache.clear(); 342 break; 343 } 344 345 clearGarbage(); 346 glFinish(); 347} 348 349/////////////////////////////////////////////////////////////////////////////// 350// Tiling 351/////////////////////////////////////////////////////////////////////////////// 352 353void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard) { 354 if (mExtensions.hasTiledRendering() && !debugOverdraw) { 355 glStartTilingQCOM(x, y, width, height, (discard ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM)); 356 } 357} 358 359void Caches::endTiling() { 360 if (mExtensions.hasTiledRendering() && !debugOverdraw) { 361 glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM); 362 } 363} 364 365bool Caches::hasRegisteredFunctors() { 366 return mFunctorsCount > 0; 367} 368 369void Caches::registerFunctors(uint32_t functorCount) { 370 mFunctorsCount += functorCount; 371} 372 373void Caches::unregisterFunctors(uint32_t functorCount) { 374 if (functorCount > mFunctorsCount) { 375 mFunctorsCount = 0; 376 } else { 377 mFunctorsCount -= functorCount; 378 } 379} 380 381/////////////////////////////////////////////////////////////////////////////// 382// Regions 383/////////////////////////////////////////////////////////////////////////////// 384 385TextureVertex* Caches::getRegionMesh() { 386 // Create the mesh, 2 triangles and 4 vertices per rectangle in the region 387 if (!mRegionMesh) { 388 mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]); 389 } 390 391 return mRegionMesh.get(); 392} 393 394/////////////////////////////////////////////////////////////////////////////// 395// Temporary Properties 396/////////////////////////////////////////////////////////////////////////////// 397 398void Caches::initTempProperties() { 399 propertyLightRadius = -1.0f; 400 propertyLightPosY = -1.0f; 401 propertyLightPosZ = -1.0f; 402 propertyAmbientRatio = -1.0f; 403 propertyAmbientShadowStrength = -1; 404 propertySpotShadowStrength = -1; 405} 406 407void Caches::setTempProperty(const char* name, const char* value) { 408 ALOGD("setting property %s to %s", name, value); 409 if (!strcmp(name, "ambientRatio")) { 410 propertyAmbientRatio = fmin(fmax(atof(value), 0.0), 10.0); 411 ALOGD("ambientRatio = %.2f", propertyAmbientRatio); 412 return; 413 } else if (!strcmp(name, "lightRadius")) { 414 propertyLightRadius = fmin(fmax(atof(value), 0.0), 3000.0); 415 ALOGD("lightRadius = %.2f", propertyLightRadius); 416 return; 417 } else if (!strcmp(name, "lightPosY")) { 418 propertyLightPosY = fmin(fmax(atof(value), 0.0), 3000.0); 419 ALOGD("lightPos Y = %.2f", propertyLightPosY); 420 return; 421 } else if (!strcmp(name, "lightPosZ")) { 422 propertyLightPosZ = fmin(fmax(atof(value), 0.0), 3000.0); 423 ALOGD("lightPos Z = %.2f", propertyLightPosZ); 424 return; 425 } else if (!strcmp(name, "ambientShadowStrength")) { 426 propertyAmbientShadowStrength = atoi(value); 427 ALOGD("ambient shadow strength = 0x%x out of 0xff", propertyAmbientShadowStrength); 428 return; 429 } else if (!strcmp(name, "spotShadowStrength")) { 430 propertySpotShadowStrength = atoi(value); 431 ALOGD("spot shadow strength = 0x%x out of 0xff", propertySpotShadowStrength); 432 return; 433 } 434 ALOGD(" failed"); 435} 436 437}; // namespace uirenderer 438}; // namespace android 439