Caches.cpp revision 0f6675332c04c74909425d1d328f02b32c0ff40e
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 <utils/Log.h> 20#include <utils/String8.h> 21 22#include "Caches.h" 23#include "DisplayListRenderer.h" 24#include "Properties.h" 25#include "LayerRenderer.h" 26 27namespace android { 28 29#ifdef USE_OPENGL_RENDERER 30using namespace uirenderer; 31ANDROID_SINGLETON_STATIC_INSTANCE(Caches); 32#endif 33 34namespace uirenderer { 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(): Singleton<Caches>(), mExtensions(Extensions::getInstance()), mInitialized(false) { 51 init(); 52 initFont(); 53 initConstraints(); 54 initProperties(); 55 initExtensions(); 56 57 mDebugLevel = readDebugLevel(); 58 ALOGD("Enabling debug mode %d", mDebugLevel); 59} 60 61void Caches::init() { 62 if (mInitialized) return; 63 64 glGenBuffers(1, &meshBuffer); 65 glBindBuffer(GL_ARRAY_BUFFER, meshBuffer); 66 glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW); 67 68 mCurrentBuffer = meshBuffer; 69 mCurrentIndicesBuffer = 0; 70 mCurrentPositionPointer = this; 71 mCurrentPositionStride = 0; 72 mCurrentTexCoordsPointer = this; 73 74 mTexCoordsArrayEnabled = false; 75 76 glDisable(GL_SCISSOR_TEST); 77 scissorEnabled = false; 78 mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0; 79 80 glActiveTexture(gTextureUnits[0]); 81 mTextureUnit = 0; 82 83 mRegionMesh = NULL; 84 85 blend = false; 86 lastSrcMode = GL_ZERO; 87 lastDstMode = GL_ZERO; 88 currentProgram = NULL; 89 90 mFunctorsCount = 0; 91 92 debugLayersUpdates = false; 93 debugOverdraw = false; 94 debugStencilClip = kStencilHide; 95 96 mInitialized = true; 97} 98 99void Caches::initFont() { 100 fontRenderer = GammaFontRenderer::createRenderer(); 101} 102 103void Caches::initExtensions() { 104 if (mExtensions.hasDebugMarker()) { 105 eventMark = glInsertEventMarkerEXT; 106 if ((drawDeferDisabled || drawReorderDisabled)) { 107 startMark = glPushGroupMarkerEXT; 108 endMark = glPopGroupMarkerEXT; 109 } else { 110 startMark = startMarkNull; 111 endMark = endMarkNull; 112 } 113 114 } else { 115 eventMark = eventMarkNull; 116 startMark = startMarkNull; 117 endMark = endMarkNull; 118 } 119 120 if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) { 121 setLabel = glLabelObjectEXT; 122 getLabel = glGetObjectLabelEXT; 123 } else { 124 setLabel = setLabelNull; 125 getLabel = getLabelNull; 126 } 127} 128 129void Caches::initConstraints() { 130 GLint maxTextureUnits; 131 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); 132 if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) { 133 ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT); 134 } 135 136 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); 137} 138 139bool Caches::initProperties() { 140 bool prevDebugLayersUpdates = debugLayersUpdates; 141 bool prevDebugOverdraw = debugOverdraw; 142 StencilClipDebug prevDebugStencilClip = debugStencilClip; 143 144 char property[PROPERTY_VALUE_MAX]; 145 if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, NULL) > 0) { 146 INIT_LOGD(" Layers updates debug enabled: %s", property); 147 debugLayersUpdates = !strcmp(property, "true"); 148 } else { 149 debugLayersUpdates = false; 150 } 151 152 if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) { 153 INIT_LOGD(" Overdraw debug enabled: %s", property); 154 debugOverdraw = !strcmp(property, "true"); 155 } else { 156 debugOverdraw = false; 157 } 158 159 // See Properties.h for valid values 160 if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, NULL) > 0) { 161 INIT_LOGD(" Stencil clip debug enabled: %s", property); 162 if (!strcmp(property, "hide")) { 163 debugStencilClip = kStencilHide; 164 } else if (!strcmp(property, "highlight")) { 165 debugStencilClip = kStencilShowHighlight; 166 } else if (!strcmp(property, "region")) { 167 debugStencilClip = kStencilShowRegion; 168 } 169 } else { 170 debugStencilClip = kStencilHide; 171 } 172 173 if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) { 174 drawDeferDisabled = !strcasecmp(property, "true"); 175 INIT_LOGD(" Draw defer %s", drawDeferDisabled ? "disabled" : "enabled"); 176 } else { 177 INIT_LOGD(" Draw defer enabled"); 178 } 179 180 if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) { 181 drawReorderDisabled = !strcasecmp(property, "true"); 182 INIT_LOGD(" Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled"); 183 } else { 184 INIT_LOGD(" Draw reorder enabled"); 185 } 186 187 return (prevDebugLayersUpdates != debugLayersUpdates) || 188 (prevDebugOverdraw != debugOverdraw) || 189 (prevDebugStencilClip != debugStencilClip); 190} 191 192void Caches::terminate() { 193 if (!mInitialized) return; 194 195 glDeleteBuffers(1, &meshBuffer); 196 mCurrentBuffer = 0; 197 198 glDeleteBuffers(1, &mRegionMeshIndices); 199 delete[] mRegionMesh; 200 mRegionMesh = NULL; 201 202 fboCache.clear(); 203 204 programCache.clear(); 205 currentProgram = NULL; 206 207 mInitialized = false; 208} 209 210/////////////////////////////////////////////////////////////////////////////// 211// Debug 212/////////////////////////////////////////////////////////////////////////////// 213 214void Caches::dumpMemoryUsage() { 215 String8 stringLog; 216 dumpMemoryUsage(stringLog); 217 ALOGD("%s", stringLog.string()); 218} 219 220void Caches::dumpMemoryUsage(String8 &log) { 221 log.appendFormat("Current memory usage / total memory usage (bytes):\n"); 222 log.appendFormat(" TextureCache %8d / %8d\n", 223 textureCache.getSize(), textureCache.getMaxSize()); 224 log.appendFormat(" LayerCache %8d / %8d\n", 225 layerCache.getSize(), layerCache.getMaxSize()); 226 log.appendFormat(" RenderBufferCache %8d / %8d\n", 227 renderBufferCache.getSize(), renderBufferCache.getMaxSize()); 228 log.appendFormat(" GradientCache %8d / %8d\n", 229 gradientCache.getSize(), gradientCache.getMaxSize()); 230 log.appendFormat(" PathCache %8d / %8d\n", 231 pathCache.getSize(), pathCache.getMaxSize()); 232 log.appendFormat(" CircleShapeCache %8d / %8d\n", 233 circleShapeCache.getSize(), circleShapeCache.getMaxSize()); 234 log.appendFormat(" OvalShapeCache %8d / %8d\n", 235 ovalShapeCache.getSize(), ovalShapeCache.getMaxSize()); 236 log.appendFormat(" RoundRectShapeCache %8d / %8d\n", 237 roundRectShapeCache.getSize(), roundRectShapeCache.getMaxSize()); 238 log.appendFormat(" RectShapeCache %8d / %8d\n", 239 rectShapeCache.getSize(), rectShapeCache.getMaxSize()); 240 log.appendFormat(" ArcShapeCache %8d / %8d\n", 241 arcShapeCache.getSize(), arcShapeCache.getMaxSize()); 242 log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(), 243 dropShadowCache.getMaxSize()); 244 for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) { 245 const uint32_t size = fontRenderer->getFontRendererSize(i); 246 log.appendFormat(" FontRenderer %d %8d / %8d\n", i, size, size); 247 } 248 log.appendFormat("Other:\n"); 249 log.appendFormat(" FboCache %8d / %8d\n", 250 fboCache.getSize(), fboCache.getMaxSize()); 251 log.appendFormat(" PatchCache %8d / %8d\n", 252 patchCache.getSize(), patchCache.getMaxSize()); 253 254 uint32_t total = 0; 255 total += textureCache.getSize(); 256 total += layerCache.getSize(); 257 total += renderBufferCache.getSize(); 258 total += gradientCache.getSize(); 259 total += pathCache.getSize(); 260 total += dropShadowCache.getSize(); 261 total += roundRectShapeCache.getSize(); 262 total += circleShapeCache.getSize(); 263 total += ovalShapeCache.getSize(); 264 total += rectShapeCache.getSize(); 265 total += arcShapeCache.getSize(); 266 for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) { 267 total += fontRenderer->getFontRendererSize(i); 268 } 269 270 log.appendFormat("Total memory usage:\n"); 271 log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f); 272} 273 274/////////////////////////////////////////////////////////////////////////////// 275// Memory management 276/////////////////////////////////////////////////////////////////////////////// 277 278void Caches::clearGarbage() { 279 textureCache.clearGarbage(); 280 pathCache.clearGarbage(); 281 282 Vector<DisplayList*> displayLists; 283 Vector<Layer*> layers; 284 285 { // scope for the lock 286 Mutex::Autolock _l(mGarbageLock); 287 displayLists = mDisplayListGarbage; 288 layers = mLayerGarbage; 289 mDisplayListGarbage.clear(); 290 mLayerGarbage.clear(); 291 } 292 293 size_t count = displayLists.size(); 294 for (size_t i = 0; i < count; i++) { 295 DisplayList* displayList = displayLists.itemAt(i); 296 delete displayList; 297 } 298 299 count = layers.size(); 300 for (size_t i = 0; i < count; i++) { 301 Layer* layer = layers.itemAt(i); 302 delete layer; 303 } 304 layers.clear(); 305} 306 307void Caches::deleteLayerDeferred(Layer* layer) { 308 Mutex::Autolock _l(mGarbageLock); 309 mLayerGarbage.push(layer); 310} 311 312void Caches::deleteDisplayListDeferred(DisplayList* displayList) { 313 Mutex::Autolock _l(mGarbageLock); 314 mDisplayListGarbage.push(displayList); 315} 316 317void Caches::flush(FlushMode mode) { 318 FLUSH_LOGD("Flushing caches (mode %d)", mode); 319 320 switch (mode) { 321 case kFlushMode_Full: 322 textureCache.clear(); 323 patchCache.clear(); 324 dropShadowCache.clear(); 325 gradientCache.clear(); 326 fontRenderer->clear(); 327 dither.clear(); 328 // fall through 329 case kFlushMode_Moderate: 330 fontRenderer->flush(); 331 textureCache.flush(); 332 pathCache.clear(); 333 roundRectShapeCache.clear(); 334 circleShapeCache.clear(); 335 ovalShapeCache.clear(); 336 rectShapeCache.clear(); 337 arcShapeCache.clear(); 338 // fall through 339 case kFlushMode_Layers: 340 layerCache.clear(); 341 renderBufferCache.clear(); 342 break; 343 } 344 345 clearGarbage(); 346} 347 348/////////////////////////////////////////////////////////////////////////////// 349// VBO 350/////////////////////////////////////////////////////////////////////////////// 351 352bool Caches::bindMeshBuffer() { 353 return bindMeshBuffer(meshBuffer); 354} 355 356bool Caches::bindMeshBuffer(const GLuint buffer) { 357 if (mCurrentBuffer != buffer) { 358 glBindBuffer(GL_ARRAY_BUFFER, buffer); 359 mCurrentBuffer = buffer; 360 return true; 361 } 362 return false; 363} 364 365bool Caches::unbindMeshBuffer() { 366 if (mCurrentBuffer) { 367 glBindBuffer(GL_ARRAY_BUFFER, 0); 368 mCurrentBuffer = 0; 369 return true; 370 } 371 return false; 372} 373 374bool Caches::bindIndicesBuffer(const GLuint buffer) { 375 if (mCurrentIndicesBuffer != buffer) { 376 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); 377 mCurrentIndicesBuffer = buffer; 378 return true; 379 } 380 return false; 381} 382 383bool Caches::unbindIndicesBuffer() { 384 if (mCurrentIndicesBuffer) { 385 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 386 mCurrentIndicesBuffer = 0; 387 return true; 388 } 389 return false; 390} 391 392/////////////////////////////////////////////////////////////////////////////// 393// Meshes and textures 394/////////////////////////////////////////////////////////////////////////////// 395 396void Caches::bindPositionVertexPointer(bool force, GLvoid* vertices, GLsizei stride) { 397 if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) { 398 GLuint slot = currentProgram->position; 399 glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices); 400 mCurrentPositionPointer = vertices; 401 mCurrentPositionStride = stride; 402 } 403} 404 405void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride) { 406 if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) { 407 GLuint slot = currentProgram->texCoords; 408 glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices); 409 mCurrentTexCoordsPointer = vertices; 410 mCurrentTexCoordsStride = stride; 411 } 412} 413 414void Caches::resetVertexPointers() { 415 mCurrentPositionPointer = this; 416 mCurrentTexCoordsPointer = this; 417} 418 419void Caches::resetTexCoordsVertexPointer() { 420 mCurrentTexCoordsPointer = this; 421} 422 423void Caches::enableTexCoordsVertexArray() { 424 if (!mTexCoordsArrayEnabled) { 425 glEnableVertexAttribArray(Program::kBindingTexCoords); 426 mCurrentTexCoordsPointer = this; 427 mTexCoordsArrayEnabled = true; 428 } 429} 430 431void Caches::disableTexCoordsVertexArray() { 432 if (mTexCoordsArrayEnabled) { 433 glDisableVertexAttribArray(Program::kBindingTexCoords); 434 mTexCoordsArrayEnabled = false; 435 } 436} 437 438void Caches::activeTexture(GLuint textureUnit) { 439 if (mTextureUnit != textureUnit) { 440 glActiveTexture(gTextureUnits[textureUnit]); 441 mTextureUnit = textureUnit; 442 } 443} 444 445/////////////////////////////////////////////////////////////////////////////// 446// Scissor 447/////////////////////////////////////////////////////////////////////////////// 448 449bool Caches::setScissor(GLint x, GLint y, GLint width, GLint height) { 450 if (scissorEnabled && (x != mScissorX || y != mScissorY || 451 width != mScissorWidth || height != mScissorHeight)) { 452 453 if (x < 0) { 454 width += x; 455 x = 0; 456 } 457 if (y < 0) { 458 height += y; 459 y = 0; 460 } 461 if (width < 0) { 462 width = 0; 463 } 464 if (height < 0) { 465 height = 0; 466 } 467 glScissor(x, y, width, height); 468 469 mScissorX = x; 470 mScissorY = y; 471 mScissorWidth = width; 472 mScissorHeight = height; 473 474 return true; 475 } 476 return false; 477} 478 479bool Caches::enableScissor() { 480 if (!scissorEnabled) { 481 glEnable(GL_SCISSOR_TEST); 482 scissorEnabled = true; 483 resetScissor(); 484 return true; 485 } 486 return false; 487} 488 489bool Caches::disableScissor() { 490 if (scissorEnabled) { 491 glDisable(GL_SCISSOR_TEST); 492 scissorEnabled = false; 493 return true; 494 } 495 return false; 496} 497 498void Caches::setScissorEnabled(bool enabled) { 499 if (scissorEnabled != enabled) { 500 if (enabled) glEnable(GL_SCISSOR_TEST); 501 else glDisable(GL_SCISSOR_TEST); 502 scissorEnabled = enabled; 503 } 504} 505 506void Caches::resetScissor() { 507 mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0; 508} 509 510/////////////////////////////////////////////////////////////////////////////// 511// Tiling 512/////////////////////////////////////////////////////////////////////////////// 513 514void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard) { 515 if (mExtensions.hasTiledRendering() && !debugOverdraw) { 516 glStartTilingQCOM(x, y, width, height, (discard ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM)); 517 } 518} 519 520void Caches::endTiling() { 521 if (mExtensions.hasTiledRendering() && !debugOverdraw) { 522 glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM); 523 } 524} 525 526bool Caches::hasRegisteredFunctors() { 527 return mFunctorsCount > 0; 528} 529 530void Caches::registerFunctors(uint32_t functorCount) { 531 mFunctorsCount += functorCount; 532} 533 534void Caches::unregisterFunctors(uint32_t functorCount) { 535 if (functorCount > mFunctorsCount) { 536 mFunctorsCount = 0; 537 } else { 538 mFunctorsCount -= functorCount; 539 } 540} 541 542/////////////////////////////////////////////////////////////////////////////// 543// Regions 544/////////////////////////////////////////////////////////////////////////////// 545 546TextureVertex* Caches::getRegionMesh() { 547 // Create the mesh, 2 triangles and 4 vertices per rectangle in the region 548 if (!mRegionMesh) { 549 mRegionMesh = new TextureVertex[REGION_MESH_QUAD_COUNT * 4]; 550 551 uint16_t* regionIndices = new uint16_t[REGION_MESH_QUAD_COUNT * 6]; 552 for (int i = 0; i < REGION_MESH_QUAD_COUNT; i++) { 553 uint16_t quad = i * 4; 554 int index = i * 6; 555 regionIndices[index ] = quad; // top-left 556 regionIndices[index + 1] = quad + 1; // top-right 557 regionIndices[index + 2] = quad + 2; // bottom-left 558 regionIndices[index + 3] = quad + 2; // bottom-left 559 regionIndices[index + 4] = quad + 1; // top-right 560 regionIndices[index + 5] = quad + 3; // bottom-right 561 } 562 563 glGenBuffers(1, &mRegionMeshIndices); 564 bindIndicesBuffer(mRegionMeshIndices); 565 glBufferData(GL_ELEMENT_ARRAY_BUFFER, REGION_MESH_QUAD_COUNT * 6 * sizeof(uint16_t), 566 regionIndices, GL_STATIC_DRAW); 567 568 delete[] regionIndices; 569 } else { 570 bindIndicesBuffer(mRegionMeshIndices); 571 } 572 573 return mRegionMesh; 574} 575 576}; // namespace uirenderer 577}; // namespace android 578