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