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