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