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