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 #include "ShadowTessellator.h"
     27 #include "RenderState.h"
     28 
     29 namespace android {
     30 
     31 #ifdef USE_OPENGL_RENDERER
     32 using namespace uirenderer;
     33 ANDROID_SINGLETON_STATIC_INSTANCE(Caches);
     34 #endif
     35 
     36 namespace uirenderer {
     37 
     38 ///////////////////////////////////////////////////////////////////////////////
     39 // Macros
     40 ///////////////////////////////////////////////////////////////////////////////
     41 
     42 #if DEBUG_CACHE_FLUSH
     43     #define FLUSH_LOGD(...) ALOGD(__VA_ARGS__)
     44 #else
     45     #define FLUSH_LOGD(...)
     46 #endif
     47 
     48 ///////////////////////////////////////////////////////////////////////////////
     49 // Constructors/destructor
     50 ///////////////////////////////////////////////////////////////////////////////
     51 
     52 Caches::Caches(): Singleton<Caches>(),
     53         mExtensions(Extensions::getInstance()), mInitialized(false), mRenderState(NULL) {
     54     init();
     55     initFont();
     56     initConstraints();
     57     initProperties();
     58     initStaticProperties();
     59     initExtensions();
     60     initTempProperties();
     61 
     62     mDebugLevel = readDebugLevel();
     63     ALOGD("Enabling debug mode %d", mDebugLevel);
     64 }
     65 
     66 bool Caches::init() {
     67     if (mInitialized) return false;
     68 
     69     ATRACE_NAME("Caches::init");
     70 
     71     glGenBuffers(1, &meshBuffer);
     72     glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
     73     glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
     74 
     75     mCurrentBuffer = meshBuffer;
     76     mCurrentIndicesBuffer = 0;
     77     mCurrentPositionPointer = this;
     78     mCurrentPositionStride = 0;
     79     mCurrentTexCoordsPointer = this;
     80     mCurrentPixelBuffer = 0;
     81 
     82     mTexCoordsArrayEnabled = false;
     83 
     84     glDisable(GL_SCISSOR_TEST);
     85     scissorEnabled = false;
     86     mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
     87 
     88     glActiveTexture(gTextureUnits[0]);
     89     mTextureUnit = 0;
     90 
     91     mRegionMesh = NULL;
     92     mMeshIndices = 0;
     93     mShadowStripsIndices = 0;
     94     blend = false;
     95     lastSrcMode = GL_ZERO;
     96     lastDstMode = GL_ZERO;
     97     currentProgram = NULL;
     98 
     99     mFunctorsCount = 0;
    100 
    101     debugLayersUpdates = false;
    102     debugOverdraw = false;
    103     debugStencilClip = kStencilHide;
    104 
    105     patchCache.init(*this);
    106 
    107     mInitialized = true;
    108 
    109     resetBoundTextures();
    110 
    111     return true;
    112 }
    113 
    114 void Caches::initFont() {
    115     fontRenderer = GammaFontRenderer::createRenderer();
    116 }
    117 
    118 void Caches::initExtensions() {
    119     if (mExtensions.hasDebugMarker()) {
    120         eventMark = glInsertEventMarkerEXT;
    121 
    122         startMark = glPushGroupMarkerEXT;
    123         endMark = glPopGroupMarkerEXT;
    124     } else {
    125         eventMark = eventMarkNull;
    126         startMark = startMarkNull;
    127         endMark = endMarkNull;
    128     }
    129 
    130     if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) {
    131         setLabel = glLabelObjectEXT;
    132         getLabel = glGetObjectLabelEXT;
    133     } else {
    134         setLabel = setLabelNull;
    135         getLabel = getLabelNull;
    136     }
    137 }
    138 
    139 void Caches::initConstraints() {
    140     GLint maxTextureUnits;
    141     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
    142     if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
    143         ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
    144     }
    145 
    146     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
    147 }
    148 
    149 void Caches::initStaticProperties() {
    150     gpuPixelBuffersEnabled = false;
    151 
    152     // OpenGL ES 3.0+ specific features
    153     if (mExtensions.hasPixelBufferObjects()) {
    154         char property[PROPERTY_VALUE_MAX];
    155         if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "true") > 0) {
    156             gpuPixelBuffersEnabled = !strcmp(property, "true");
    157         }
    158     }
    159 }
    160 
    161 bool Caches::initProperties() {
    162     bool prevDebugLayersUpdates = debugLayersUpdates;
    163     bool prevDebugOverdraw = debugOverdraw;
    164     StencilClipDebug prevDebugStencilClip = debugStencilClip;
    165 
    166     char property[PROPERTY_VALUE_MAX];
    167     if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, NULL) > 0) {
    168         INIT_LOGD("  Layers updates debug enabled: %s", property);
    169         debugLayersUpdates = !strcmp(property, "true");
    170     } else {
    171         debugLayersUpdates = false;
    172     }
    173 
    174     debugOverdraw = false;
    175     if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) {
    176         INIT_LOGD("  Overdraw debug enabled: %s", property);
    177         if (!strcmp(property, "show")) {
    178             debugOverdraw = true;
    179             mOverdrawDebugColorSet = kColorSet_Default;
    180         } else if (!strcmp(property, "show_deuteranomaly")) {
    181             debugOverdraw = true;
    182             mOverdrawDebugColorSet = kColorSet_Deuteranomaly;
    183         }
    184     }
    185 
    186     // See Properties.h for valid values
    187     if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, NULL) > 0) {
    188         INIT_LOGD("  Stencil clip debug enabled: %s", property);
    189         if (!strcmp(property, "hide")) {
    190             debugStencilClip = kStencilHide;
    191         } else if (!strcmp(property, "highlight")) {
    192             debugStencilClip = kStencilShowHighlight;
    193         } else if (!strcmp(property, "region")) {
    194             debugStencilClip = kStencilShowRegion;
    195         }
    196     } else {
    197         debugStencilClip = kStencilHide;
    198     }
    199 
    200     if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) {
    201         drawDeferDisabled = !strcasecmp(property, "true");
    202         INIT_LOGD("  Draw defer %s", drawDeferDisabled ? "disabled" : "enabled");
    203     } else {
    204         drawDeferDisabled = false;
    205         INIT_LOGD("  Draw defer enabled");
    206     }
    207 
    208     if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) {
    209         drawReorderDisabled = !strcasecmp(property, "true");
    210         INIT_LOGD("  Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled");
    211     } else {
    212         drawReorderDisabled = false;
    213         INIT_LOGD("  Draw reorder enabled");
    214     }
    215 
    216     return (prevDebugLayersUpdates != debugLayersUpdates) ||
    217             (prevDebugOverdraw != debugOverdraw) ||
    218             (prevDebugStencilClip != debugStencilClip);
    219 }
    220 
    221 void Caches::terminate() {
    222     if (!mInitialized) return;
    223 
    224     glDeleteBuffers(1, &meshBuffer);
    225     mCurrentBuffer = 0;
    226 
    227     glDeleteBuffers(1, &mMeshIndices);
    228     delete[] mRegionMesh;
    229     mMeshIndices = 0;
    230     mRegionMesh = NULL;
    231 
    232     glDeleteBuffers(1, &mShadowStripsIndices);
    233     mShadowStripsIndices = 0;
    234 
    235     fboCache.clear();
    236 
    237     programCache.clear();
    238     currentProgram = NULL;
    239 
    240     patchCache.clear();
    241 
    242     clearGarbage();
    243 
    244     mInitialized = false;
    245 }
    246 
    247 ///////////////////////////////////////////////////////////////////////////////
    248 // Debug
    249 ///////////////////////////////////////////////////////////////////////////////
    250 
    251 uint32_t Caches::getOverdrawColor(uint32_t amount) const {
    252     static uint32_t sOverdrawColors[2][4] = {
    253             { 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 },
    254             { 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 }
    255     };
    256     if (amount < 1) amount = 1;
    257     if (amount > 4) amount = 4;
    258     return sOverdrawColors[mOverdrawDebugColorSet][amount - 1];
    259 }
    260 
    261 void Caches::dumpMemoryUsage() {
    262     String8 stringLog;
    263     dumpMemoryUsage(stringLog);
    264     ALOGD("%s", stringLog.string());
    265 }
    266 
    267 void Caches::dumpMemoryUsage(String8 &log) {
    268     uint32_t total = 0;
    269     log.appendFormat("Current memory usage / total memory usage (bytes):\n");
    270     log.appendFormat("  TextureCache         %8d / %8d\n",
    271             textureCache.getSize(), textureCache.getMaxSize());
    272     log.appendFormat("  LayerCache           %8d / %8d (numLayers = %zu)\n",
    273             layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount());
    274     if (mRenderState) {
    275         int memused = 0;
    276         for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
    277                 it != mRenderState->mActiveLayers.end(); it++) {
    278             const Layer* layer = *it;
    279             log.appendFormat("    Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n",
    280                     layer->getWidth(), layer->getHeight(),
    281                     layer->isTextureLayer(), layer->getTexture(),
    282                     layer->getFbo(), layer->getStrongCount());
    283             memused += layer->getWidth() * layer->getHeight() * 4;
    284         }
    285         log.appendFormat("  Layers total   %8d (numLayers = %zu)\n",
    286                 memused, mRenderState->mActiveLayers.size());
    287         total += memused;
    288     }
    289     log.appendFormat("  RenderBufferCache    %8d / %8d\n",
    290             renderBufferCache.getSize(), renderBufferCache.getMaxSize());
    291     log.appendFormat("  GradientCache        %8d / %8d\n",
    292             gradientCache.getSize(), gradientCache.getMaxSize());
    293     log.appendFormat("  PathCache            %8d / %8d\n",
    294             pathCache.getSize(), pathCache.getMaxSize());
    295     log.appendFormat("  TessellationCache    %8d / %8d\n",
    296             tessellationCache.getSize(), tessellationCache.getMaxSize());
    297     log.appendFormat("  TextDropShadowCache  %8d / %8d\n", dropShadowCache.getSize(),
    298             dropShadowCache.getMaxSize());
    299     log.appendFormat("  PatchCache           %8d / %8d\n",
    300             patchCache.getSize(), patchCache.getMaxSize());
    301     for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
    302         const uint32_t sizeA8 = fontRenderer->getFontRendererSize(i, GL_ALPHA);
    303         const uint32_t sizeRGBA = fontRenderer->getFontRendererSize(i, GL_RGBA);
    304         log.appendFormat("  FontRenderer %d A8    %8d / %8d\n", i, sizeA8, sizeA8);
    305         log.appendFormat("  FontRenderer %d RGBA  %8d / %8d\n", i, sizeRGBA, sizeRGBA);
    306         log.appendFormat("  FontRenderer %d total %8d / %8d\n", i, sizeA8 + sizeRGBA,
    307                 sizeA8 + sizeRGBA);
    308     }
    309     log.appendFormat("Other:\n");
    310     log.appendFormat("  FboCache             %8d / %8d\n",
    311             fboCache.getSize(), fboCache.getMaxSize());
    312 
    313     total += textureCache.getSize();
    314     total += renderBufferCache.getSize();
    315     total += gradientCache.getSize();
    316     total += pathCache.getSize();
    317     total += tessellationCache.getSize();
    318     total += dropShadowCache.getSize();
    319     total += patchCache.getSize();
    320     for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
    321         total += fontRenderer->getFontRendererSize(i, GL_ALPHA);
    322         total += fontRenderer->getFontRendererSize(i, GL_RGBA);
    323     }
    324 
    325     log.appendFormat("Total memory usage:\n");
    326     log.appendFormat("  %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
    327 }
    328 
    329 ///////////////////////////////////////////////////////////////////////////////
    330 // Memory management
    331 ///////////////////////////////////////////////////////////////////////////////
    332 
    333 void Caches::clearGarbage() {
    334     textureCache.clearGarbage();
    335     pathCache.clearGarbage();
    336     patchCache.clearGarbage();
    337 }
    338 
    339 void Caches::flush(FlushMode mode) {
    340     FLUSH_LOGD("Flushing caches (mode %d)", mode);
    341 
    342     // We must stop tasks before clearing caches
    343     if (mode > kFlushMode_Layers) {
    344         tasks.stop();
    345     }
    346 
    347     switch (mode) {
    348         case kFlushMode_Full:
    349             textureCache.clear();
    350             patchCache.clear();
    351             dropShadowCache.clear();
    352             gradientCache.clear();
    353             fontRenderer->clear();
    354             fboCache.clear();
    355             dither.clear();
    356             // fall through
    357         case kFlushMode_Moderate:
    358             fontRenderer->flush();
    359             textureCache.flush();
    360             pathCache.clear();
    361             tessellationCache.clear();
    362             // fall through
    363         case kFlushMode_Layers:
    364             layerCache.clear();
    365             renderBufferCache.clear();
    366             break;
    367     }
    368 
    369     clearGarbage();
    370     glFinish();
    371 }
    372 
    373 ///////////////////////////////////////////////////////////////////////////////
    374 // VBO
    375 ///////////////////////////////////////////////////////////////////////////////
    376 
    377 bool Caches::bindMeshBuffer() {
    378     return bindMeshBuffer(meshBuffer);
    379 }
    380 
    381 bool Caches::bindMeshBuffer(const GLuint buffer) {
    382     if (mCurrentBuffer != buffer) {
    383         glBindBuffer(GL_ARRAY_BUFFER, buffer);
    384         mCurrentBuffer = buffer;
    385         return true;
    386     }
    387     return false;
    388 }
    389 
    390 bool Caches::unbindMeshBuffer() {
    391     if (mCurrentBuffer) {
    392         glBindBuffer(GL_ARRAY_BUFFER, 0);
    393         mCurrentBuffer = 0;
    394         return true;
    395     }
    396     return false;
    397 }
    398 
    399 bool Caches::bindIndicesBufferInternal(const GLuint buffer) {
    400     if (mCurrentIndicesBuffer != buffer) {
    401         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
    402         mCurrentIndicesBuffer = buffer;
    403         return true;
    404     }
    405     return false;
    406 }
    407 
    408 bool Caches::bindQuadIndicesBuffer() {
    409     if (!mMeshIndices) {
    410         uint16_t* regionIndices = new uint16_t[gMaxNumberOfQuads * 6];
    411         for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
    412             uint16_t quad = i * 4;
    413             int index = i * 6;
    414             regionIndices[index    ] = quad;       // top-left
    415             regionIndices[index + 1] = quad + 1;   // top-right
    416             regionIndices[index + 2] = quad + 2;   // bottom-left
    417             regionIndices[index + 3] = quad + 2;   // bottom-left
    418             regionIndices[index + 4] = quad + 1;   // top-right
    419             regionIndices[index + 5] = quad + 3;   // bottom-right
    420         }
    421 
    422         glGenBuffers(1, &mMeshIndices);
    423         bool force = bindIndicesBufferInternal(mMeshIndices);
    424         glBufferData(GL_ELEMENT_ARRAY_BUFFER, gMaxNumberOfQuads * 6 * sizeof(uint16_t),
    425                 regionIndices, GL_STATIC_DRAW);
    426 
    427         delete[] regionIndices;
    428         return force;
    429     }
    430 
    431     return bindIndicesBufferInternal(mMeshIndices);
    432 }
    433 
    434 bool Caches::bindShadowIndicesBuffer() {
    435     if (!mShadowStripsIndices) {
    436         uint16_t* shadowIndices = new uint16_t[MAX_SHADOW_INDEX_COUNT];
    437         ShadowTessellator::generateShadowIndices(shadowIndices);
    438         glGenBuffers(1, &mShadowStripsIndices);
    439         bool force = bindIndicesBufferInternal(mShadowStripsIndices);
    440         glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_SHADOW_INDEX_COUNT * sizeof(uint16_t),
    441             shadowIndices, GL_STATIC_DRAW);
    442 
    443         delete[] shadowIndices;
    444         return force;
    445     }
    446 
    447     return bindIndicesBufferInternal(mShadowStripsIndices);
    448 }
    449 
    450 bool Caches::unbindIndicesBuffer() {
    451     if (mCurrentIndicesBuffer) {
    452         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    453         mCurrentIndicesBuffer = 0;
    454         return true;
    455     }
    456     return false;
    457 }
    458 
    459 ///////////////////////////////////////////////////////////////////////////////
    460 // PBO
    461 ///////////////////////////////////////////////////////////////////////////////
    462 
    463 bool Caches::bindPixelBuffer(const GLuint buffer) {
    464     if (mCurrentPixelBuffer != buffer) {
    465         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
    466         mCurrentPixelBuffer = buffer;
    467         return true;
    468     }
    469     return false;
    470 }
    471 
    472 bool Caches::unbindPixelBuffer() {
    473     if (mCurrentPixelBuffer) {
    474         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
    475         mCurrentPixelBuffer = 0;
    476         return true;
    477     }
    478     return false;
    479 }
    480 
    481 ///////////////////////////////////////////////////////////////////////////////
    482 // Meshes and textures
    483 ///////////////////////////////////////////////////////////////////////////////
    484 
    485 void Caches::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
    486     if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
    487         GLuint slot = currentProgram->position;
    488         glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
    489         mCurrentPositionPointer = vertices;
    490         mCurrentPositionStride = stride;
    491     }
    492 }
    493 
    494 void Caches::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
    495     if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
    496         GLuint slot = currentProgram->texCoords;
    497         glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
    498         mCurrentTexCoordsPointer = vertices;
    499         mCurrentTexCoordsStride = stride;
    500     }
    501 }
    502 
    503 void Caches::resetVertexPointers() {
    504     mCurrentPositionPointer = this;
    505     mCurrentTexCoordsPointer = this;
    506 }
    507 
    508 void Caches::resetTexCoordsVertexPointer() {
    509     mCurrentTexCoordsPointer = this;
    510 }
    511 
    512 void Caches::enableTexCoordsVertexArray() {
    513     if (!mTexCoordsArrayEnabled) {
    514         glEnableVertexAttribArray(Program::kBindingTexCoords);
    515         mCurrentTexCoordsPointer = this;
    516         mTexCoordsArrayEnabled = true;
    517     }
    518 }
    519 
    520 void Caches::disableTexCoordsVertexArray() {
    521     if (mTexCoordsArrayEnabled) {
    522         glDisableVertexAttribArray(Program::kBindingTexCoords);
    523         mTexCoordsArrayEnabled = false;
    524     }
    525 }
    526 
    527 void Caches::activeTexture(GLuint textureUnit) {
    528     if (mTextureUnit != textureUnit) {
    529         glActiveTexture(gTextureUnits[textureUnit]);
    530         mTextureUnit = textureUnit;
    531     }
    532 }
    533 
    534 void Caches::resetActiveTexture() {
    535     mTextureUnit = -1;
    536 }
    537 
    538 void Caches::bindTexture(GLuint texture) {
    539     if (mBoundTextures[mTextureUnit] != texture) {
    540         glBindTexture(GL_TEXTURE_2D, texture);
    541         mBoundTextures[mTextureUnit] = texture;
    542     }
    543 }
    544 
    545 void Caches::bindTexture(GLenum target, GLuint texture) {
    546     if (target == GL_TEXTURE_2D) {
    547         bindTexture(texture);
    548     } else {
    549         // GLConsumer directly calls glBindTexture() with
    550         // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
    551         // since the cached state could be stale
    552         glBindTexture(target, texture);
    553     }
    554 }
    555 
    556 void Caches::deleteTexture(GLuint texture) {
    557     // When glDeleteTextures() is called on a currently bound texture,
    558     // OpenGL ES specifies that the texture is then considered unbound
    559     // Consider the following series of calls:
    560     //
    561     // glGenTextures -> creates texture name 2
    562     // glBindTexture(2)
    563     // glDeleteTextures(2) -> 2 is now unbound
    564     // glGenTextures -> can return 2 again
    565     //
    566     // If we don't call glBindTexture(2) after the second glGenTextures
    567     // call, any texture operation will be performed on the default
    568     // texture (name=0)
    569 
    570     unbindTexture(texture);
    571 
    572     glDeleteTextures(1, &texture);
    573 }
    574 
    575 void Caches::resetBoundTextures() {
    576     memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
    577 }
    578 
    579 void Caches::unbindTexture(GLuint texture) {
    580     for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
    581         if (mBoundTextures[i] == texture) {
    582             mBoundTextures[i] = 0;
    583         }
    584     }
    585 }
    586 
    587 ///////////////////////////////////////////////////////////////////////////////
    588 // Scissor
    589 ///////////////////////////////////////////////////////////////////////////////
    590 
    591 bool Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
    592     if (scissorEnabled && (x != mScissorX || y != mScissorY ||
    593             width != mScissorWidth || height != mScissorHeight)) {
    594 
    595         if (x < 0) {
    596             width += x;
    597             x = 0;
    598         }
    599         if (y < 0) {
    600             height += y;
    601             y = 0;
    602         }
    603         if (width < 0) {
    604             width = 0;
    605         }
    606         if (height < 0) {
    607             height = 0;
    608         }
    609         glScissor(x, y, width, height);
    610 
    611         mScissorX = x;
    612         mScissorY = y;
    613         mScissorWidth = width;
    614         mScissorHeight = height;
    615 
    616         return true;
    617     }
    618     return false;
    619 }
    620 
    621 bool Caches::enableScissor() {
    622     if (!scissorEnabled) {
    623         glEnable(GL_SCISSOR_TEST);
    624         scissorEnabled = true;
    625         resetScissor();
    626         return true;
    627     }
    628     return false;
    629 }
    630 
    631 bool Caches::disableScissor() {
    632     if (scissorEnabled) {
    633         glDisable(GL_SCISSOR_TEST);
    634         scissorEnabled = false;
    635         return true;
    636     }
    637     return false;
    638 }
    639 
    640 void Caches::setScissorEnabled(bool enabled) {
    641     if (scissorEnabled != enabled) {
    642         if (enabled) glEnable(GL_SCISSOR_TEST);
    643         else glDisable(GL_SCISSOR_TEST);
    644         scissorEnabled = enabled;
    645     }
    646 }
    647 
    648 void Caches::resetScissor() {
    649     mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
    650 }
    651 
    652 ///////////////////////////////////////////////////////////////////////////////
    653 // Tiling
    654 ///////////////////////////////////////////////////////////////////////////////
    655 
    656 void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard) {
    657     if (mExtensions.hasTiledRendering() && !debugOverdraw) {
    658         glStartTilingQCOM(x, y, width, height, (discard ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM));
    659     }
    660 }
    661 
    662 void Caches::endTiling() {
    663     if (mExtensions.hasTiledRendering() && !debugOverdraw) {
    664         glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
    665     }
    666 }
    667 
    668 bool Caches::hasRegisteredFunctors() {
    669     return mFunctorsCount > 0;
    670 }
    671 
    672 void Caches::registerFunctors(uint32_t functorCount) {
    673     mFunctorsCount += functorCount;
    674 }
    675 
    676 void Caches::unregisterFunctors(uint32_t functorCount) {
    677     if (functorCount > mFunctorsCount) {
    678         mFunctorsCount = 0;
    679     } else {
    680         mFunctorsCount -= functorCount;
    681     }
    682 }
    683 
    684 ///////////////////////////////////////////////////////////////////////////////
    685 // Regions
    686 ///////////////////////////////////////////////////////////////////////////////
    687 
    688 TextureVertex* Caches::getRegionMesh() {
    689     // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
    690     if (!mRegionMesh) {
    691         mRegionMesh = new TextureVertex[gMaxNumberOfQuads * 4];
    692     }
    693 
    694     return mRegionMesh;
    695 }
    696 
    697 ///////////////////////////////////////////////////////////////////////////////
    698 // Temporary Properties
    699 ///////////////////////////////////////////////////////////////////////////////
    700 
    701 void Caches::initTempProperties() {
    702     propertyLightDiameter = -1.0f;
    703     propertyLightPosY = -1.0f;
    704     propertyLightPosZ = -1.0f;
    705     propertyAmbientRatio = -1.0f;
    706     propertyAmbientShadowStrength = -1;
    707     propertySpotShadowStrength = -1;
    708 }
    709 
    710 void Caches::setTempProperty(const char* name, const char* value) {
    711     ALOGD("setting property %s to %s", name, value);
    712     if (!strcmp(name, "ambientRatio")) {
    713         propertyAmbientRatio = fmin(fmax(atof(value), 0.0), 10.0);
    714         ALOGD("ambientRatio = %.2f", propertyAmbientRatio);
    715         return;
    716     } else if (!strcmp(name, "lightDiameter")) {
    717         propertyLightDiameter = fmin(fmax(atof(value), 0.0), 3000.0);
    718         ALOGD("lightDiameter = %.2f", propertyLightDiameter);
    719         return;
    720     } else if (!strcmp(name, "lightPosY")) {
    721         propertyLightPosY = fmin(fmax(atof(value), 0.0), 3000.0);
    722         ALOGD("lightPos Y = %.2f", propertyLightPosY);
    723         return;
    724     } else if (!strcmp(name, "lightPosZ")) {
    725         propertyLightPosZ = fmin(fmax(atof(value), 0.0), 3000.0);
    726         ALOGD("lightPos Z = %.2f", propertyLightPosZ);
    727         return;
    728     } else if (!strcmp(name, "ambientShadowStrength")) {
    729         propertyAmbientShadowStrength = atoi(value);
    730         ALOGD("ambient shadow strength = 0x%x out of 0xff", propertyAmbientShadowStrength);
    731         return;
    732     } else if (!strcmp(name, "spotShadowStrength")) {
    733         propertySpotShadowStrength = atoi(value);
    734         ALOGD("spot shadow strength = 0x%x out of 0xff", propertySpotShadowStrength);
    735         return;
    736     }
    737     ALOGD("    failed");
    738 }
    739 
    740 }; // namespace uirenderer
    741 }; // namespace android
    742