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