Caches.cpp revision 96a5c4c7bab6718524de7253da8309143ab48bef
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 : patchCache(renderState) 52 , mRenderState(&renderState) 53 , mExtensions(Extensions::getInstance()) 54 , mInitialized(false) { 55 INIT_LOGD("Creating OpenGL renderer caches"); 56 init(); 57 initFont(); 58 initConstraints(); 59 initProperties(); 60 initStaticProperties(); 61 initExtensions(); 62 initTempProperties(); 63 64 mDebugLevel = readDebugLevel(); 65 ALOGD_IF(mDebugLevel != kDebugDisabled, 66 "Enabling debug mode %d", mDebugLevel); 67} 68 69bool Caches::init() { 70 if (mInitialized) return false; 71 72 ATRACE_NAME("Caches::init"); 73 74 glActiveTexture(gTextureUnits[0]); 75 mTextureUnit = 0; 76 77 mRegionMesh = nullptr; 78 blend = false; 79 lastSrcMode = GL_ZERO; 80 lastDstMode = GL_ZERO; 81 currentProgram = nullptr; 82 83 mFunctorsCount = 0; 84 85 debugLayersUpdates = false; 86 debugOverdraw = false; 87 debugStencilClip = kStencilHide; 88 89 patchCache.init(); 90 91 mInitialized = true; 92 93 resetBoundTextures(); 94 mPixelBufferState.reset(new PixelBufferState()); 95 96 return true; 97} 98 99void Caches::initFont() { 100 fontRenderer = GammaFontRenderer::createRenderer(); 101} 102 103void Caches::initExtensions() { 104 if (mExtensions.hasDebugMarker()) { 105 eventMark = glInsertEventMarkerEXT; 106 107 startMark = glPushGroupMarkerEXT; 108 endMark = glPopGroupMarkerEXT; 109 } else { 110 eventMark = eventMarkNull; 111 startMark = startMarkNull; 112 endMark = endMarkNull; 113 } 114 115 if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) { 116 setLabel = glLabelObjectEXT; 117 getLabel = glGetObjectLabelEXT; 118 } else { 119 setLabel = setLabelNull; 120 getLabel = getLabelNull; 121 } 122} 123 124void Caches::initConstraints() { 125 GLint maxTextureUnits; 126 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); 127 if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) { 128 ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT); 129 } 130 131 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); 132} 133 134void Caches::initStaticProperties() { 135 gpuPixelBuffersEnabled = false; 136 137 // OpenGL ES 3.0+ specific features 138 if (mExtensions.hasPixelBufferObjects()) { 139 char property[PROPERTY_VALUE_MAX]; 140 if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "true") > 0) { 141 gpuPixelBuffersEnabled = !strcmp(property, "true"); 142 } 143 } 144} 145 146bool Caches::initProperties() { 147 bool prevDebugLayersUpdates = debugLayersUpdates; 148 bool prevDebugOverdraw = debugOverdraw; 149 StencilClipDebug prevDebugStencilClip = debugStencilClip; 150 151 char property[PROPERTY_VALUE_MAX]; 152 if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, nullptr) > 0) { 153 INIT_LOGD(" Layers updates debug enabled: %s", property); 154 debugLayersUpdates = !strcmp(property, "true"); 155 } else { 156 debugLayersUpdates = false; 157 } 158 159 debugOverdraw = false; 160 if (property_get(PROPERTY_DEBUG_OVERDRAW, property, nullptr) > 0) { 161 INIT_LOGD(" Overdraw debug enabled: %s", property); 162 if (!strcmp(property, "show")) { 163 debugOverdraw = true; 164 mOverdrawDebugColorSet = kColorSet_Default; 165 } else if (!strcmp(property, "show_deuteranomaly")) { 166 debugOverdraw = true; 167 mOverdrawDebugColorSet = kColorSet_Deuteranomaly; 168 } 169 } 170 171 // See Properties.h for valid values 172 if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, nullptr) > 0) { 173 INIT_LOGD(" Stencil clip debug enabled: %s", property); 174 if (!strcmp(property, "hide")) { 175 debugStencilClip = kStencilHide; 176 } else if (!strcmp(property, "highlight")) { 177 debugStencilClip = kStencilShowHighlight; 178 } else if (!strcmp(property, "region")) { 179 debugStencilClip = kStencilShowRegion; 180 } 181 } else { 182 debugStencilClip = kStencilHide; 183 } 184 185 if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) { 186 drawDeferDisabled = !strcasecmp(property, "true"); 187 INIT_LOGD(" Draw defer %s", drawDeferDisabled ? "disabled" : "enabled"); 188 } else { 189 drawDeferDisabled = false; 190 INIT_LOGD(" Draw defer enabled"); 191 } 192 193 if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) { 194 drawReorderDisabled = !strcasecmp(property, "true"); 195 INIT_LOGD(" Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled"); 196 } else { 197 drawReorderDisabled = false; 198 INIT_LOGD(" Draw reorder enabled"); 199 } 200 201 return (prevDebugLayersUpdates != debugLayersUpdates) || 202 (prevDebugOverdraw != debugOverdraw) || 203 (prevDebugStencilClip != debugStencilClip); 204} 205 206void Caches::terminate() { 207 if (!mInitialized) return; 208 mRegionMesh.release(); 209 210 fboCache.clear(); 211 212 programCache.clear(); 213 currentProgram = nullptr; 214 215 patchCache.clear(); 216 217 clearGarbage(); 218 219 mPixelBufferState.release(); 220 221 mInitialized = false; 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<const 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// Textures 352/////////////////////////////////////////////////////////////////////////////// 353 354void Caches::activeTexture(GLuint textureUnit) { 355 if (mTextureUnit != textureUnit) { 356 glActiveTexture(gTextureUnits[textureUnit]); 357 mTextureUnit = textureUnit; 358 } 359} 360 361void Caches::resetActiveTexture() { 362 mTextureUnit = -1; 363} 364 365void Caches::bindTexture(GLuint texture) { 366 if (mBoundTextures[mTextureUnit] != texture) { 367 glBindTexture(GL_TEXTURE_2D, texture); 368 mBoundTextures[mTextureUnit] = texture; 369 } 370} 371 372void Caches::bindTexture(GLenum target, GLuint texture) { 373 if (target == GL_TEXTURE_2D) { 374 bindTexture(texture); 375 } else { 376 // GLConsumer directly calls glBindTexture() with 377 // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target 378 // since the cached state could be stale 379 glBindTexture(target, texture); 380 } 381} 382 383void Caches::deleteTexture(GLuint texture) { 384 // When glDeleteTextures() is called on a currently bound texture, 385 // OpenGL ES specifies that the texture is then considered unbound 386 // Consider the following series of calls: 387 // 388 // glGenTextures -> creates texture name 2 389 // glBindTexture(2) 390 // glDeleteTextures(2) -> 2 is now unbound 391 // glGenTextures -> can return 2 again 392 // 393 // If we don't call glBindTexture(2) after the second glGenTextures 394 // call, any texture operation will be performed on the default 395 // texture (name=0) 396 397 unbindTexture(texture); 398 399 glDeleteTextures(1, &texture); 400} 401 402void Caches::resetBoundTextures() { 403 memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint)); 404} 405 406void Caches::unbindTexture(GLuint texture) { 407 for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) { 408 if (mBoundTextures[i] == texture) { 409 mBoundTextures[i] = 0; 410 } 411 } 412} 413 414/////////////////////////////////////////////////////////////////////////////// 415// Tiling 416/////////////////////////////////////////////////////////////////////////////// 417 418void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard) { 419 if (mExtensions.hasTiledRendering() && !debugOverdraw) { 420 glStartTilingQCOM(x, y, width, height, (discard ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM)); 421 } 422} 423 424void Caches::endTiling() { 425 if (mExtensions.hasTiledRendering() && !debugOverdraw) { 426 glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM); 427 } 428} 429 430bool Caches::hasRegisteredFunctors() { 431 return mFunctorsCount > 0; 432} 433 434void Caches::registerFunctors(uint32_t functorCount) { 435 mFunctorsCount += functorCount; 436} 437 438void Caches::unregisterFunctors(uint32_t functorCount) { 439 if (functorCount > mFunctorsCount) { 440 mFunctorsCount = 0; 441 } else { 442 mFunctorsCount -= functorCount; 443 } 444} 445 446/////////////////////////////////////////////////////////////////////////////// 447// Regions 448/////////////////////////////////////////////////////////////////////////////// 449 450TextureVertex* Caches::getRegionMesh() { 451 // Create the mesh, 2 triangles and 4 vertices per rectangle in the region 452 if (!mRegionMesh) { 453 mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]); 454 } 455 456 return mRegionMesh.get(); 457} 458 459/////////////////////////////////////////////////////////////////////////////// 460// Temporary Properties 461/////////////////////////////////////////////////////////////////////////////// 462 463void Caches::initTempProperties() { 464 propertyLightDiameter = -1.0f; 465 propertyLightPosY = -1.0f; 466 propertyLightPosZ = -1.0f; 467 propertyAmbientRatio = -1.0f; 468 propertyAmbientShadowStrength = -1; 469 propertySpotShadowStrength = -1; 470} 471 472void Caches::setTempProperty(const char* name, const char* value) { 473 ALOGD("setting property %s to %s", name, value); 474 if (!strcmp(name, "ambientRatio")) { 475 propertyAmbientRatio = fmin(fmax(atof(value), 0.0), 10.0); 476 ALOGD("ambientRatio = %.2f", propertyAmbientRatio); 477 return; 478 } else if (!strcmp(name, "lightDiameter")) { 479 propertyLightDiameter = fmin(fmax(atof(value), 0.0), 3000.0); 480 ALOGD("lightDiameter = %.2f", propertyLightDiameter); 481 return; 482 } else if (!strcmp(name, "lightPosY")) { 483 propertyLightPosY = fmin(fmax(atof(value), 0.0), 3000.0); 484 ALOGD("lightPos Y = %.2f", propertyLightPosY); 485 return; 486 } else if (!strcmp(name, "lightPosZ")) { 487 propertyLightPosZ = fmin(fmax(atof(value), 0.0), 3000.0); 488 ALOGD("lightPos Z = %.2f", propertyLightPosZ); 489 return; 490 } else if (!strcmp(name, "ambientShadowStrength")) { 491 propertyAmbientShadowStrength = atoi(value); 492 ALOGD("ambient shadow strength = 0x%x out of 0xff", propertyAmbientShadowStrength); 493 return; 494 } else if (!strcmp(name, "spotShadowStrength")) { 495 propertySpotShadowStrength = atoi(value); 496 ALOGD("spot shadow strength = 0x%x out of 0xff", propertySpotShadowStrength); 497 return; 498 } 499 ALOGD(" failed"); 500} 501 502}; // namespace uirenderer 503}; // namespace android 504