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