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