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 <stdlib.h>
     20 #include <stdint.h>
     21 #include <sys/types.h>
     22 
     23 #include <SkCanvas.h>
     24 #include <SkTypeface.h>
     25 
     26 #include <utils/Log.h>
     27 #include <utils/StopWatch.h>
     28 
     29 #include <private/hwui/DrawGlInfo.h>
     30 
     31 #include <ui/Rect.h>
     32 
     33 #include "OpenGLRenderer.h"
     34 #include "DeferredDisplayList.h"
     35 #include "DisplayListRenderer.h"
     36 #include "Fence.h"
     37 #include "PathTessellator.h"
     38 #include "Properties.h"
     39 #include "Vector.h"
     40 
     41 namespace android {
     42 namespace uirenderer {
     43 
     44 ///////////////////////////////////////////////////////////////////////////////
     45 // Defines
     46 ///////////////////////////////////////////////////////////////////////////////
     47 
     48 #define RAD_TO_DEG (180.0f / 3.14159265f)
     49 #define MIN_ANGLE 0.001f
     50 
     51 #define ALPHA_THRESHOLD 0
     52 
     53 #define FILTER(paint) (!paint || paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST)
     54 
     55 ///////////////////////////////////////////////////////////////////////////////
     56 // Globals
     57 ///////////////////////////////////////////////////////////////////////////////
     58 
     59 /**
     60  * Structure mapping Skia xfermodes to OpenGL blending factors.
     61  */
     62 struct Blender {
     63     SkXfermode::Mode mode;
     64     GLenum src;
     65     GLenum dst;
     66 }; // struct Blender
     67 
     68 // In this array, the index of each Blender equals the value of the first
     69 // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
     70 static const Blender gBlends[] = {
     71     { SkXfermode::kClear_Mode,    GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
     72     { SkXfermode::kSrc_Mode,      GL_ONE,                 GL_ZERO },
     73     { SkXfermode::kDst_Mode,      GL_ZERO,                GL_ONE },
     74     { SkXfermode::kSrcOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
     75     { SkXfermode::kDstOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
     76     { SkXfermode::kSrcIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
     77     { SkXfermode::kDstIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
     78     { SkXfermode::kSrcOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
     79     { SkXfermode::kDstOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
     80     { SkXfermode::kSrcATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
     81     { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
     82     { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
     83     { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
     84     { SkXfermode::kModulate_Mode, GL_ZERO,                GL_SRC_COLOR },
     85     { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
     86 };
     87 
     88 // This array contains the swapped version of each SkXfermode. For instance
     89 // this array's SrcOver blending mode is actually DstOver. You can refer to
     90 // createLayer() for more information on the purpose of this array.
     91 static const Blender gBlendsSwap[] = {
     92     { SkXfermode::kClear_Mode,    GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
     93     { SkXfermode::kSrc_Mode,      GL_ZERO,                GL_ONE },
     94     { SkXfermode::kDst_Mode,      GL_ONE,                 GL_ZERO },
     95     { SkXfermode::kSrcOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
     96     { SkXfermode::kDstOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
     97     { SkXfermode::kSrcIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
     98     { SkXfermode::kDstIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
     99     { SkXfermode::kSrcOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
    100     { SkXfermode::kDstOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
    101     { SkXfermode::kSrcATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
    102     { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
    103     { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
    104     { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
    105     { SkXfermode::kModulate_Mode, GL_DST_COLOR,           GL_ZERO },
    106     { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
    107 };
    108 
    109 ///////////////////////////////////////////////////////////////////////////////
    110 // Functions
    111 ///////////////////////////////////////////////////////////////////////////////
    112 
    113 template<typename T>
    114 static inline T min(T a, T b) {
    115     return a < b ? a : b;
    116 }
    117 
    118 ///////////////////////////////////////////////////////////////////////////////
    119 // Constructors/destructor
    120 ///////////////////////////////////////////////////////////////////////////////
    121 
    122 OpenGLRenderer::OpenGLRenderer():
    123         mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) {
    124     // *set* draw modifiers to be 0
    125     memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
    126     mDrawModifiers.mOverrideLayerAlpha = 1.0f;
    127 
    128     memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
    129 
    130     mFirstSnapshot = new Snapshot;
    131     mFrameStarted = false;
    132     mCountOverdraw = false;
    133 
    134     mScissorOptimizationDisabled = false;
    135 }
    136 
    137 OpenGLRenderer::~OpenGLRenderer() {
    138     // The context has already been destroyed at this point, do not call
    139     // GL APIs. All GL state should be kept in Caches.h
    140 }
    141 
    142 void OpenGLRenderer::initProperties() {
    143     char property[PROPERTY_VALUE_MAX];
    144     if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) {
    145         mScissorOptimizationDisabled = !strcasecmp(property, "true");
    146         INIT_LOGD("  Scissor optimization %s",
    147                 mScissorOptimizationDisabled ? "disabled" : "enabled");
    148     } else {
    149         INIT_LOGD("  Scissor optimization enabled");
    150     }
    151 }
    152 
    153 ///////////////////////////////////////////////////////////////////////////////
    154 // Setup
    155 ///////////////////////////////////////////////////////////////////////////////
    156 
    157 void OpenGLRenderer::setName(const char* name) {
    158     if (name) {
    159         mName.setTo(name);
    160     } else {
    161         mName.clear();
    162     }
    163 }
    164 
    165 const char* OpenGLRenderer::getName() const {
    166     return mName.string();
    167 }
    168 
    169 bool OpenGLRenderer::isDeferred() {
    170     return false;
    171 }
    172 
    173 void OpenGLRenderer::setViewport(int width, int height) {
    174     initViewport(width, height);
    175 
    176     glDisable(GL_DITHER);
    177     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    178 
    179     glEnableVertexAttribArray(Program::kBindingPosition);
    180 }
    181 
    182 void OpenGLRenderer::initViewport(int width, int height) {
    183     mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
    184 
    185     mWidth = width;
    186     mHeight = height;
    187 
    188     mFirstSnapshot->height = height;
    189     mFirstSnapshot->viewport.set(0, 0, width, height);
    190 }
    191 
    192 void OpenGLRenderer::setupFrameState(float left, float top,
    193         float right, float bottom, bool opaque) {
    194     mCaches.clearGarbage();
    195 
    196     mOpaque = opaque;
    197     mSnapshot = new Snapshot(mFirstSnapshot,
    198             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
    199     mSnapshot->fbo = getTargetFbo();
    200     mSaveCount = 1;
    201 
    202     mSnapshot->setClip(left, top, right, bottom);
    203     mTilingClip.set(left, top, right, bottom);
    204 }
    205 
    206 status_t OpenGLRenderer::startFrame() {
    207     if (mFrameStarted) return DrawGlInfo::kStatusDone;
    208     mFrameStarted = true;
    209 
    210     mDirtyClip = true;
    211 
    212     discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
    213 
    214     glViewport(0, 0, mWidth, mHeight);
    215 
    216     // Functors break the tiling extension in pretty spectacular ways
    217     // This ensures we don't use tiling when a functor is going to be
    218     // invoked during the frame
    219     mSuppressTiling = mCaches.hasRegisteredFunctors();
    220 
    221     startTiling(mSnapshot, true);
    222 
    223     debugOverdraw(true, true);
    224 
    225     return clear(mTilingClip.left, mTilingClip.top,
    226             mTilingClip.right, mTilingClip.bottom, mOpaque);
    227 }
    228 
    229 status_t OpenGLRenderer::prepare(bool opaque) {
    230     return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
    231 }
    232 
    233 status_t OpenGLRenderer::prepareDirty(float left, float top,
    234         float right, float bottom, bool opaque) {
    235 
    236     setupFrameState(left, top, right, bottom, opaque);
    237 
    238     // Layer renderers will start the frame immediately
    239     // The framebuffer renderer will first defer the display list
    240     // for each layer and wait until the first drawing command
    241     // to start the frame
    242     if (mSnapshot->fbo == 0) {
    243         syncState();
    244         updateLayers();
    245     } else {
    246         return startFrame();
    247     }
    248 
    249     return DrawGlInfo::kStatusDone;
    250 }
    251 
    252 void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
    253     // If we know that we are going to redraw the entire framebuffer,
    254     // perform a discard to let the driver know we don't need to preserve
    255     // the back buffer for this frame.
    256     if (mExtensions.hasDiscardFramebuffer() &&
    257             left <= 0.0f && top <= 0.0f && right >= mWidth && bottom >= mHeight) {
    258         const bool isFbo = getTargetFbo() == 0;
    259         const GLenum attachments[] = {
    260                 isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
    261                 isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT };
    262         glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
    263     }
    264 }
    265 
    266 status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
    267     if (!opaque || mCountOverdraw) {
    268         mCaches.enableScissor();
    269         mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
    270         glClear(GL_COLOR_BUFFER_BIT);
    271         return DrawGlInfo::kStatusDrew;
    272     }
    273 
    274     mCaches.resetScissor();
    275     return DrawGlInfo::kStatusDone;
    276 }
    277 
    278 void OpenGLRenderer::syncState() {
    279     if (mCaches.blend) {
    280         glEnable(GL_BLEND);
    281     } else {
    282         glDisable(GL_BLEND);
    283     }
    284 }
    285 
    286 void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) {
    287     if (!mSuppressTiling) {
    288         Rect* clip = &mTilingClip;
    289         if (s->flags & Snapshot::kFlagFboTarget) {
    290             clip = &(s->layer->clipRect);
    291         }
    292 
    293         startTiling(*clip, s->height, opaque);
    294     }
    295 }
    296 
    297 void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque) {
    298     if (!mSuppressTiling) {
    299         mCaches.startTiling(clip.left, windowHeight - clip.bottom,
    300                 clip.right - clip.left, clip.bottom - clip.top, opaque);
    301     }
    302 }
    303 
    304 void OpenGLRenderer::endTiling() {
    305     if (!mSuppressTiling) mCaches.endTiling();
    306 }
    307 
    308 void OpenGLRenderer::finish() {
    309     renderOverdraw();
    310     endTiling();
    311 
    312     // When finish() is invoked on FBO 0 we've reached the end
    313     // of the current frame
    314     if (getTargetFbo() == 0) {
    315         mCaches.pathCache.trim();
    316     }
    317 
    318     if (!suppressErrorChecks()) {
    319 #if DEBUG_OPENGL
    320         GLenum status = GL_NO_ERROR;
    321         while ((status = glGetError()) != GL_NO_ERROR) {
    322             ALOGD("GL error from OpenGLRenderer: 0x%x", status);
    323             switch (status) {
    324                 case GL_INVALID_ENUM:
    325                     ALOGE("  GL_INVALID_ENUM");
    326                     break;
    327                 case GL_INVALID_VALUE:
    328                     ALOGE("  GL_INVALID_VALUE");
    329                     break;
    330                 case GL_INVALID_OPERATION:
    331                     ALOGE("  GL_INVALID_OPERATION");
    332                     break;
    333                 case GL_OUT_OF_MEMORY:
    334                     ALOGE("  Out of memory!");
    335                     break;
    336             }
    337         }
    338 #endif
    339 
    340 #if DEBUG_MEMORY_USAGE
    341         mCaches.dumpMemoryUsage();
    342 #else
    343         if (mCaches.getDebugLevel() & kDebugMemory) {
    344             mCaches.dumpMemoryUsage();
    345         }
    346 #endif
    347     }
    348 
    349     if (mCountOverdraw) {
    350         countOverdraw();
    351     }
    352 
    353     mFrameStarted = false;
    354 }
    355 
    356 void OpenGLRenderer::interrupt() {
    357     if (mCaches.currentProgram) {
    358         if (mCaches.currentProgram->isInUse()) {
    359             mCaches.currentProgram->remove();
    360             mCaches.currentProgram = NULL;
    361         }
    362     }
    363     mCaches.resetActiveTexture();
    364     mCaches.unbindMeshBuffer();
    365     mCaches.unbindIndicesBuffer();
    366     mCaches.resetVertexPointers();
    367     mCaches.disableTexCoordsVertexArray();
    368     debugOverdraw(false, false);
    369 }
    370 
    371 void OpenGLRenderer::resume() {
    372     sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
    373     glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
    374     glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
    375     debugOverdraw(true, false);
    376 
    377     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    378 
    379     mCaches.scissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
    380     mCaches.enableScissor();
    381     mCaches.resetScissor();
    382     dirtyClip();
    383 
    384     mCaches.activeTexture(0);
    385     mCaches.resetBoundTextures();
    386 
    387     mCaches.blend = true;
    388     glEnable(GL_BLEND);
    389     glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode);
    390     glBlendEquation(GL_FUNC_ADD);
    391 }
    392 
    393 void OpenGLRenderer::resumeAfterLayer() {
    394     sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
    395     glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
    396     glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
    397     debugOverdraw(true, false);
    398 
    399     mCaches.resetScissor();
    400     dirtyClip();
    401 }
    402 
    403 void OpenGLRenderer::detachFunctor(Functor* functor) {
    404     mFunctors.remove(functor);
    405 }
    406 
    407 void OpenGLRenderer::attachFunctor(Functor* functor) {
    408     mFunctors.add(functor);
    409 }
    410 
    411 status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
    412     status_t result = DrawGlInfo::kStatusDone;
    413     size_t count = mFunctors.size();
    414 
    415     if (count > 0) {
    416         interrupt();
    417         SortedVector<Functor*> functors(mFunctors);
    418         mFunctors.clear();
    419 
    420         DrawGlInfo info;
    421         info.clipLeft = 0;
    422         info.clipTop = 0;
    423         info.clipRight = 0;
    424         info.clipBottom = 0;
    425         info.isLayer = false;
    426         info.width = 0;
    427         info.height = 0;
    428         memset(info.transform, 0, sizeof(float) * 16);
    429 
    430         for (size_t i = 0; i < count; i++) {
    431             Functor* f = functors.itemAt(i);
    432             result |= (*f)(DrawGlInfo::kModeProcess, &info);
    433 
    434             if (result & DrawGlInfo::kStatusDraw) {
    435                 Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
    436                 dirty.unionWith(localDirty);
    437             }
    438 
    439             if (result & DrawGlInfo::kStatusInvoke) {
    440                 mFunctors.add(f);
    441             }
    442         }
    443         resume();
    444     }
    445 
    446     return result;
    447 }
    448 
    449 status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
    450     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
    451 
    452     detachFunctor(functor);
    453 
    454 
    455     Rect clip(*mSnapshot->clipRect);
    456     clip.snapToPixelBoundaries();
    457 
    458     // Since we don't know what the functor will draw, let's dirty
    459     // tne entire clip region
    460     if (hasLayer()) {
    461         dirtyLayerUnchecked(clip, getRegion());
    462     }
    463 
    464     DrawGlInfo info;
    465     info.clipLeft = clip.left;
    466     info.clipTop = clip.top;
    467     info.clipRight = clip.right;
    468     info.clipBottom = clip.bottom;
    469     info.isLayer = hasLayer();
    470     info.width = getSnapshot()->viewport.getWidth();
    471     info.height = getSnapshot()->height;
    472     getSnapshot()->transform->copyTo(&info.transform[0]);
    473 
    474     bool dirtyClip = mDirtyClip;
    475     // setup GL state for functor
    476     if (mDirtyClip) {
    477         setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
    478     }
    479     if (mCaches.enableScissor() || dirtyClip) {
    480         setScissorFromClip();
    481     }
    482     interrupt();
    483 
    484     // call functor immediately after GL state setup
    485     status_t result = (*functor)(DrawGlInfo::kModeDraw, &info);
    486 
    487     if (result != DrawGlInfo::kStatusDone) {
    488         Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
    489         dirty.unionWith(localDirty);
    490 
    491         if (result & DrawGlInfo::kStatusInvoke) {
    492             mFunctors.add(functor);
    493         }
    494     }
    495 
    496     resume();
    497     return result | DrawGlInfo::kStatusDrew;
    498 }
    499 
    500 ///////////////////////////////////////////////////////////////////////////////
    501 // Debug
    502 ///////////////////////////////////////////////////////////////////////////////
    503 
    504 void OpenGLRenderer::eventMark(const char* name) const {
    505     mCaches.eventMark(0, name);
    506 }
    507 
    508 void OpenGLRenderer::startMark(const char* name) const {
    509     mCaches.startMark(0, name);
    510 }
    511 
    512 void OpenGLRenderer::endMark() const {
    513     mCaches.endMark();
    514 }
    515 
    516 void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
    517     if (mCaches.debugOverdraw && getTargetFbo() == 0) {
    518         if (clear) {
    519             mCaches.disableScissor();
    520             mCaches.stencil.clear();
    521         }
    522         if (enable) {
    523             mCaches.stencil.enableDebugWrite();
    524         } else {
    525             mCaches.stencil.disable();
    526         }
    527     }
    528 }
    529 
    530 void OpenGLRenderer::renderOverdraw() {
    531     if (mCaches.debugOverdraw && getTargetFbo() == 0) {
    532         const Rect* clip = &mTilingClip;
    533 
    534         mCaches.enableScissor();
    535         mCaches.setScissor(clip->left, mFirstSnapshot->height - clip->bottom,
    536                 clip->right - clip->left, clip->bottom - clip->top);
    537 
    538         // 1x overdraw
    539         mCaches.stencil.enableDebugTest(2);
    540         drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
    541 
    542         // 2x overdraw
    543         mCaches.stencil.enableDebugTest(3);
    544         drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
    545 
    546         // 3x overdraw
    547         mCaches.stencil.enableDebugTest(4);
    548         drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
    549 
    550         // 4x overdraw and higher
    551         mCaches.stencil.enableDebugTest(4, true);
    552         drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
    553 
    554         mCaches.stencil.disable();
    555     }
    556 }
    557 
    558 void OpenGLRenderer::countOverdraw() {
    559     size_t count = mWidth * mHeight;
    560     uint32_t* buffer = new uint32_t[count];
    561     glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
    562 
    563     size_t total = 0;
    564     for (size_t i = 0; i < count; i++) {
    565         total += buffer[i] & 0xff;
    566     }
    567 
    568     mOverdraw = total / float(count);
    569 
    570     delete[] buffer;
    571 }
    572 
    573 ///////////////////////////////////////////////////////////////////////////////
    574 // Layers
    575 ///////////////////////////////////////////////////////////////////////////////
    576 
    577 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
    578     if (layer->deferredUpdateScheduled && layer->renderer &&
    579             layer->displayList && layer->displayList->isRenderable()) {
    580         ATRACE_CALL();
    581 
    582         Rect& dirty = layer->dirtyRect;
    583 
    584         if (inFrame) {
    585             endTiling();
    586             debugOverdraw(false, false);
    587         }
    588 
    589         if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
    590             layer->render();
    591         } else {
    592             layer->defer();
    593         }
    594 
    595         if (inFrame) {
    596             resumeAfterLayer();
    597             startTiling(mSnapshot);
    598         }
    599 
    600         layer->debugDrawUpdate = mCaches.debugLayersUpdates;
    601         layer->hasDrawnSinceUpdate = false;
    602 
    603         return true;
    604     }
    605 
    606     return false;
    607 }
    608 
    609 void OpenGLRenderer::updateLayers() {
    610     // If draw deferring is enabled this method will simply defer
    611     // the display list of each individual layer. The layers remain
    612     // in the layer updates list which will be cleared by flushLayers().
    613     int count = mLayerUpdates.size();
    614     if (count > 0) {
    615         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
    616             startMark("Layer Updates");
    617         } else {
    618             startMark("Defer Layer Updates");
    619         }
    620 
    621         // Note: it is very important to update the layers in order
    622         for (int i = 0; i < count; i++) {
    623             Layer* layer = mLayerUpdates.itemAt(i);
    624             updateLayer(layer, false);
    625             if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
    626                 mCaches.resourceCache.decrementRefcount(layer);
    627             }
    628         }
    629 
    630         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
    631             mLayerUpdates.clear();
    632             glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
    633         }
    634         endMark();
    635     }
    636 }
    637 
    638 void OpenGLRenderer::flushLayers() {
    639     int count = mLayerUpdates.size();
    640     if (count > 0) {
    641         startMark("Apply Layer Updates");
    642         char layerName[12];
    643 
    644         // Note: it is very important to update the layers in order
    645         for (int i = 0; i < count; i++) {
    646             sprintf(layerName, "Layer #%d", i);
    647             startMark(layerName);
    648 
    649             ATRACE_BEGIN("flushLayer");
    650             Layer* layer = mLayerUpdates.itemAt(i);
    651             layer->flush();
    652             ATRACE_END();
    653 
    654             mCaches.resourceCache.decrementRefcount(layer);
    655 
    656             endMark();
    657         }
    658 
    659         mLayerUpdates.clear();
    660         glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
    661 
    662         endMark();
    663     }
    664 }
    665 
    666 void OpenGLRenderer::pushLayerUpdate(Layer* layer) {
    667     if (layer) {
    668         // Make sure we don't introduce duplicates.
    669         // SortedVector would do this automatically but we need to respect
    670         // the insertion order. The linear search is not an issue since
    671         // this list is usually very short (typically one item, at most a few)
    672         for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
    673             if (mLayerUpdates.itemAt(i) == layer) {
    674                 return;
    675             }
    676         }
    677         mLayerUpdates.push_back(layer);
    678         mCaches.resourceCache.incrementRefcount(layer);
    679     }
    680 }
    681 
    682 void OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
    683     if (layer) {
    684         for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
    685             if (mLayerUpdates.itemAt(i) == layer) {
    686                 mLayerUpdates.removeAt(i);
    687                 mCaches.resourceCache.decrementRefcount(layer);
    688                 break;
    689             }
    690         }
    691     }
    692 }
    693 
    694 void OpenGLRenderer::clearLayerUpdates() {
    695     size_t count = mLayerUpdates.size();
    696     if (count > 0) {
    697         mCaches.resourceCache.lock();
    698         for (size_t i = 0; i < count; i++) {
    699             mCaches.resourceCache.decrementRefcountLocked(mLayerUpdates.itemAt(i));
    700         }
    701         mCaches.resourceCache.unlock();
    702         mLayerUpdates.clear();
    703     }
    704 }
    705 
    706 void OpenGLRenderer::flushLayerUpdates() {
    707     syncState();
    708     updateLayers();
    709     flushLayers();
    710     // Wait for all the layer updates to be executed
    711     AutoFence fence;
    712 }
    713 
    714 ///////////////////////////////////////////////////////////////////////////////
    715 // State management
    716 ///////////////////////////////////////////////////////////////////////////////
    717 
    718 int OpenGLRenderer::getSaveCount() const {
    719     return mSaveCount;
    720 }
    721 
    722 int OpenGLRenderer::save(int flags) {
    723     return saveSnapshot(flags);
    724 }
    725 
    726 void OpenGLRenderer::restore() {
    727     if (mSaveCount > 1) {
    728         restoreSnapshot();
    729     }
    730 }
    731 
    732 void OpenGLRenderer::restoreToCount(int saveCount) {
    733     if (saveCount < 1) saveCount = 1;
    734 
    735     while (mSaveCount > saveCount) {
    736         restoreSnapshot();
    737     }
    738 }
    739 
    740 int OpenGLRenderer::saveSnapshot(int flags) {
    741     mSnapshot = new Snapshot(mSnapshot, flags);
    742     return mSaveCount++;
    743 }
    744 
    745 bool OpenGLRenderer::restoreSnapshot() {
    746     bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
    747     bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
    748     bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho;
    749 
    750     sp<Snapshot> current = mSnapshot;
    751     sp<Snapshot> previous = mSnapshot->previous;
    752 
    753     if (restoreOrtho) {
    754         Rect& r = previous->viewport;
    755         glViewport(r.left, r.top, r.right, r.bottom);
    756         mOrthoMatrix.load(current->orthoMatrix);
    757     }
    758 
    759     mSaveCount--;
    760     mSnapshot = previous;
    761 
    762     if (restoreClip) {
    763         dirtyClip();
    764     }
    765 
    766     if (restoreLayer) {
    767         endMark(); // Savelayer
    768         startMark("ComposeLayer");
    769         composeLayer(current, previous);
    770         endMark();
    771     }
    772 
    773     return restoreClip;
    774 }
    775 
    776 ///////////////////////////////////////////////////////////////////////////////
    777 // Layers
    778 ///////////////////////////////////////////////////////////////////////////////
    779 
    780 int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
    781         int alpha, SkXfermode::Mode mode, int flags) {
    782     const GLuint previousFbo = mSnapshot->fbo;
    783     const int count = saveSnapshot(flags);
    784 
    785     if (!mSnapshot->isIgnored()) {
    786         createLayer(left, top, right, bottom, alpha, mode, flags, previousFbo);
    787     }
    788 
    789     return count;
    790 }
    791 
    792 void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) {
    793     const Rect untransformedBounds(bounds);
    794 
    795     currentTransform().mapRect(bounds);
    796 
    797     // Layers only make sense if they are in the framebuffer's bounds
    798     if (bounds.intersect(*mSnapshot->clipRect)) {
    799         // We cannot work with sub-pixels in this case
    800         bounds.snapToPixelBoundaries();
    801 
    802         // When the layer is not an FBO, we may use glCopyTexImage so we
    803         // need to make sure the layer does not extend outside the bounds
    804         // of the framebuffer
    805         if (!bounds.intersect(mSnapshot->previous->viewport)) {
    806             bounds.setEmpty();
    807         } else if (fboLayer) {
    808             clip.set(bounds);
    809             mat4 inverse;
    810             inverse.loadInverse(currentTransform());
    811             inverse.mapRect(clip);
    812             clip.snapToPixelBoundaries();
    813             if (clip.intersect(untransformedBounds)) {
    814                 clip.translate(-untransformedBounds.left, -untransformedBounds.top);
    815                 bounds.set(untransformedBounds);
    816             } else {
    817                 clip.setEmpty();
    818             }
    819         }
    820     } else {
    821         bounds.setEmpty();
    822     }
    823 }
    824 
    825 void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip,
    826         bool fboLayer, int alpha) {
    827     if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
    828             bounds.getHeight() > mCaches.maxTextureSize ||
    829             (fboLayer && clip.isEmpty())) {
    830         mSnapshot->empty = fboLayer;
    831     } else {
    832         mSnapshot->invisible = mSnapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer);
    833     }
    834 }
    835 
    836 int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
    837         int alpha, SkXfermode::Mode mode, int flags) {
    838     const GLuint previousFbo = mSnapshot->fbo;
    839     const int count = saveSnapshot(flags);
    840 
    841     if (!mSnapshot->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
    842         // initialize the snapshot as though it almost represents an FBO layer so deferred draw
    843         // operations will be able to store and restore the current clip and transform info, and
    844         // quick rejection will be correct (for display lists)
    845 
    846         Rect bounds(left, top, right, bottom);
    847         Rect clip;
    848         calculateLayerBoundsAndClip(bounds, clip, true);
    849         updateSnapshotIgnoreForLayer(bounds, clip, true, alpha);
    850 
    851         if (!mSnapshot->isIgnored()) {
    852             mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
    853             mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
    854             mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
    855         }
    856     }
    857 
    858     return count;
    859 }
    860 
    861 
    862 /**
    863  * Layers are viewed by Skia are slightly different than layers in image editing
    864  * programs (for instance.) When a layer is created, previously created layers
    865  * and the frame buffer still receive every drawing command. For instance, if a
    866  * layer is created and a shape intersecting the bounds of the layers and the
    867  * framebuffer is draw, the shape will be drawn on both (unless the layer was
    868  * created with the SkCanvas::kClipToLayer_SaveFlag flag.)
    869  *
    870  * A way to implement layers is to create an FBO for each layer, backed by an RGBA
    871  * texture. Unfortunately, this is inefficient as it requires every primitive to
    872  * be drawn n + 1 times, where n is the number of active layers. In practice this
    873  * means, for every primitive:
    874  *   - Switch active frame buffer
    875  *   - Change viewport, clip and projection matrix
    876  *   - Issue the drawing
    877  *
    878  * Switching rendering target n + 1 times per drawn primitive is extremely costly.
    879  * To avoid this, layers are implemented in a different way here, at least in the
    880  * general case. FBOs are used, as an optimization, when the "clip to layer" flag
    881  * is set. When this flag is set we can redirect all drawing operations into a
    882  * single FBO.
    883  *
    884  * This implementation relies on the frame buffer being at least RGBA 8888. When
    885  * a layer is created, only a texture is created, not an FBO. The content of the
    886  * frame buffer contained within the layer's bounds is copied into this texture
    887  * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
    888  * buffer and drawing continues as normal. This technique therefore treats the
    889  * frame buffer as a scratch buffer for the layers.
    890  *
    891  * To compose the layers back onto the frame buffer, each layer texture
    892  * (containing the original frame buffer data) is drawn as a simple quad over
    893  * the frame buffer. The trick is that the quad is set as the composition
    894  * destination in the blending equation, and the frame buffer becomes the source
    895  * of the composition.
    896  *
    897  * Drawing layers with an alpha value requires an extra step before composition.
    898  * An empty quad is drawn over the layer's region in the frame buffer. This quad
    899  * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
    900  * quad is used to multiply the colors in the frame buffer. This is achieved by
    901  * changing the GL blend functions for the GL_FUNC_ADD blend equation to
    902  * GL_ZERO, GL_SRC_ALPHA.
    903  *
    904  * Because glCopyTexImage2D() can be slow, an alternative implementation might
    905  * be use to draw a single clipped layer. The implementation described above
    906  * is correct in every case.
    907  *
    908  * (1) The frame buffer is actually not cleared right away. To allow the GPU
    909  *     to potentially optimize series of calls to glCopyTexImage2D, the frame
    910  *     buffer is left untouched until the first drawing operation. Only when
    911  *     something actually gets drawn are the layers regions cleared.
    912  */
    913 bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
    914         int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo) {
    915     LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
    916     LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
    917 
    918     const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
    919 
    920     // Window coordinates of the layer
    921     Rect clip;
    922     Rect bounds(left, top, right, bottom);
    923     calculateLayerBoundsAndClip(bounds, clip, fboLayer);
    924     updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, alpha);
    925 
    926     // Bail out if we won't draw in this snapshot
    927     if (mSnapshot->isIgnored()) {
    928         return false;
    929     }
    930 
    931     mCaches.activeTexture(0);
    932     Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
    933     if (!layer) {
    934         return false;
    935     }
    936 
    937     layer->setAlpha(alpha, mode);
    938     layer->layer.set(bounds);
    939     layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
    940             bounds.getWidth() / float(layer->getWidth()), 0.0f);
    941     layer->setColorFilter(mDrawModifiers.mColorFilter);
    942     layer->setBlend(true);
    943     layer->setDirty(false);
    944 
    945     // Save the layer in the snapshot
    946     mSnapshot->flags |= Snapshot::kFlagIsLayer;
    947     mSnapshot->layer = layer;
    948 
    949     startMark("SaveLayer");
    950     if (fboLayer) {
    951         return createFboLayer(layer, bounds, clip, previousFbo);
    952     } else {
    953         // Copy the framebuffer into the layer
    954         layer->bindTexture();
    955         if (!bounds.isEmpty()) {
    956             if (layer->isEmpty()) {
    957                 // Workaround for some GL drivers. When reading pixels lying outside
    958                 // of the window we should get undefined values for those pixels.
    959                 // Unfortunately some drivers will turn the entire target texture black
    960                 // when reading outside of the window.
    961                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(),
    962                         0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    963                 layer->setEmpty(false);
    964             }
    965 
    966             glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
    967                     mSnapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
    968 
    969             // Enqueue the buffer coordinates to clear the corresponding region later
    970             mLayers.push(new Rect(bounds));
    971         }
    972     }
    973 
    974     return true;
    975 }
    976 
    977 bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLuint previousFbo) {
    978     layer->clipRect.set(clip);
    979     layer->setFbo(mCaches.fboCache.get());
    980 
    981     mSnapshot->region = &mSnapshot->layer->region;
    982     mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer |
    983             Snapshot::kFlagDirtyOrtho;
    984     mSnapshot->fbo = layer->getFbo();
    985     mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
    986     mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
    987     mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
    988     mSnapshot->height = bounds.getHeight();
    989     mSnapshot->orthoMatrix.load(mOrthoMatrix);
    990 
    991     endTiling();
    992     debugOverdraw(false, false);
    993     // Bind texture to FBO
    994     glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
    995     layer->bindTexture();
    996 
    997     // Initialize the texture if needed
    998     if (layer->isEmpty()) {
    999         layer->allocateTexture();
   1000         layer->setEmpty(false);
   1001     }
   1002 
   1003     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
   1004             layer->getTexture(), 0);
   1005 
   1006     startTiling(mSnapshot, true);
   1007 
   1008     // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
   1009     mCaches.enableScissor();
   1010     mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
   1011             clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
   1012     glClear(GL_COLOR_BUFFER_BIT);
   1013 
   1014     dirtyClip();
   1015 
   1016     // Change the ortho projection
   1017     glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
   1018     mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
   1019 
   1020     return true;
   1021 }
   1022 
   1023 /**
   1024  * Read the documentation of createLayer() before doing anything in this method.
   1025  */
   1026 void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
   1027     if (!current->layer) {
   1028         ALOGE("Attempting to compose a layer that does not exist");
   1029         return;
   1030     }
   1031 
   1032     Layer* layer = current->layer;
   1033     const Rect& rect = layer->layer;
   1034     const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
   1035 
   1036     bool clipRequired = false;
   1037     quickRejectNoScissor(rect, &clipRequired); // safely ignore return, should never be rejected
   1038     mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
   1039 
   1040     if (fboLayer) {
   1041         endTiling();
   1042 
   1043         // Detach the texture from the FBO
   1044         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
   1045 
   1046         layer->removeFbo(false);
   1047 
   1048         // Unbind current FBO and restore previous one
   1049         glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
   1050         debugOverdraw(true, false);
   1051 
   1052         startTiling(previous);
   1053     }
   1054 
   1055     if (!fboLayer && layer->getAlpha() < 255) {
   1056         drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
   1057                 layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true);
   1058         // Required below, composeLayerRect() will divide by 255
   1059         layer->setAlpha(255);
   1060     }
   1061 
   1062     mCaches.unbindMeshBuffer();
   1063 
   1064     mCaches.activeTexture(0);
   1065 
   1066     // When the layer is stored in an FBO, we can save a bit of fillrate by
   1067     // drawing only the dirty region
   1068     if (fboLayer) {
   1069         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
   1070         if (layer->getColorFilter()) {
   1071             setupColorFilter(layer->getColorFilter());
   1072         }
   1073         composeLayerRegion(layer, rect);
   1074         if (layer->getColorFilter()) {
   1075             resetColorFilter();
   1076         }
   1077     } else if (!rect.isEmpty()) {
   1078         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
   1079         composeLayerRect(layer, rect, true);
   1080     }
   1081 
   1082     dirtyClip();
   1083 
   1084     // Failing to add the layer to the cache should happen only if the layer is too large
   1085     if (!mCaches.layerCache.put(layer)) {
   1086         LAYER_LOGD("Deleting layer");
   1087         Caches::getInstance().resourceCache.decrementRefcount(layer);
   1088     }
   1089 }
   1090 
   1091 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
   1092     float alpha = getLayerAlpha(layer);
   1093 
   1094     setupDraw();
   1095     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
   1096         setupDrawWithTexture();
   1097     } else {
   1098         setupDrawWithExternalTexture();
   1099     }
   1100     setupDrawTextureTransform();
   1101     setupDrawColor(alpha, alpha, alpha, alpha);
   1102     setupDrawColorFilter();
   1103     setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode());
   1104     setupDrawProgram();
   1105     setupDrawPureColorUniforms();
   1106     setupDrawColorFilterUniforms();
   1107     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
   1108         setupDrawTexture(layer->getTexture());
   1109     } else {
   1110         setupDrawExternalTexture(layer->getTexture());
   1111     }
   1112     if (currentTransform().isPureTranslate() &&
   1113             layer->getWidth() == (uint32_t) rect.getWidth() &&
   1114             layer->getHeight() == (uint32_t) rect.getHeight()) {
   1115         const float x = (int) floorf(rect.left + currentTransform().getTranslateX() + 0.5f);
   1116         const float y = (int) floorf(rect.top + currentTransform().getTranslateY() + 0.5f);
   1117 
   1118         layer->setFilter(GL_NEAREST);
   1119         setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
   1120     } else {
   1121         layer->setFilter(GL_LINEAR);
   1122         setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
   1123     }
   1124     setupDrawTextureTransformUniforms(layer->getTexTransform());
   1125     setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
   1126 
   1127     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
   1128 }
   1129 
   1130 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
   1131     if (!layer->isTextureLayer()) {
   1132         const Rect& texCoords = layer->texCoords;
   1133         resetDrawTextureTexCoords(texCoords.left, texCoords.top,
   1134                 texCoords.right, texCoords.bottom);
   1135 
   1136         float x = rect.left;
   1137         float y = rect.top;
   1138         bool simpleTransform = currentTransform().isPureTranslate() &&
   1139                 layer->getWidth() == (uint32_t) rect.getWidth() &&
   1140                 layer->getHeight() == (uint32_t) rect.getHeight();
   1141 
   1142         if (simpleTransform) {
   1143             // When we're swapping, the layer is already in screen coordinates
   1144             if (!swap) {
   1145                 x = (int) floorf(rect.left + currentTransform().getTranslateX() + 0.5f);
   1146                 y = (int) floorf(rect.top + currentTransform().getTranslateY() + 0.5f);
   1147             }
   1148 
   1149             layer->setFilter(GL_NEAREST, true);
   1150         } else {
   1151             layer->setFilter(GL_LINEAR, true);
   1152         }
   1153 
   1154         float alpha = getLayerAlpha(layer);
   1155         bool blend = layer->isBlend() || alpha < 1.0f;
   1156         drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
   1157                 layer->getTexture(), alpha, layer->getMode(), blend,
   1158                 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
   1159                 GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
   1160 
   1161         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
   1162     } else {
   1163         resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
   1164         drawTextureLayer(layer, rect);
   1165         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
   1166     }
   1167 }
   1168 
   1169 /**
   1170  * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
   1171  * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
   1172  * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
   1173  * by saveLayer's restore
   1174  */
   1175 #define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) {                             \
   1176         DRAW_COMMAND;                                                            \
   1177         if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
   1178             glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);                 \
   1179             DRAW_COMMAND;                                                        \
   1180             glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                     \
   1181         }                                                                        \
   1182     }
   1183 
   1184 #define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
   1185 
   1186 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
   1187     if (layer->region.isRect()) {
   1188         layer->setRegionAsRect();
   1189 
   1190         DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
   1191 
   1192         layer->region.clear();
   1193         return;
   1194     }
   1195 
   1196     if (CC_LIKELY(!layer->region.isEmpty())) {
   1197         size_t count;
   1198         const android::Rect* rects;
   1199         Region safeRegion;
   1200         if (CC_LIKELY(hasRectToRectTransform())) {
   1201             rects = layer->region.getArray(&count);
   1202         } else {
   1203             safeRegion = Region::createTJunctionFreeRegion(layer->region);
   1204             rects = safeRegion.getArray(&count);
   1205         }
   1206 
   1207         const float alpha = getLayerAlpha(layer);
   1208         const float texX = 1.0f / float(layer->getWidth());
   1209         const float texY = 1.0f / float(layer->getHeight());
   1210         const float height = rect.getHeight();
   1211 
   1212         setupDraw();
   1213 
   1214         // We must get (and therefore bind) the region mesh buffer
   1215         // after we setup drawing in case we need to mess with the
   1216         // stencil buffer in setupDraw()
   1217         TextureVertex* mesh = mCaches.getRegionMesh();
   1218         uint32_t numQuads = 0;
   1219 
   1220         setupDrawWithTexture();
   1221         setupDrawColor(alpha, alpha, alpha, alpha);
   1222         setupDrawColorFilter();
   1223         setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false);
   1224         setupDrawProgram();
   1225         setupDrawDirtyRegionsDisabled();
   1226         setupDrawPureColorUniforms();
   1227         setupDrawColorFilterUniforms();
   1228         setupDrawTexture(layer->getTexture());
   1229         if (currentTransform().isPureTranslate()) {
   1230             const float x = (int) floorf(rect.left + currentTransform().getTranslateX() + 0.5f);
   1231             const float y = (int) floorf(rect.top + currentTransform().getTranslateY() + 0.5f);
   1232 
   1233             layer->setFilter(GL_NEAREST);
   1234             setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
   1235         } else {
   1236             layer->setFilter(GL_LINEAR);
   1237             setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
   1238         }
   1239         setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]);
   1240 
   1241         for (size_t i = 0; i < count; i++) {
   1242             const android::Rect* r = &rects[i];
   1243 
   1244             const float u1 = r->left * texX;
   1245             const float v1 = (height - r->top) * texY;
   1246             const float u2 = r->right * texX;
   1247             const float v2 = (height - r->bottom) * texY;
   1248 
   1249             // TODO: Reject quads outside of the clip
   1250             TextureVertex::set(mesh++, r->left, r->top, u1, v1);
   1251             TextureVertex::set(mesh++, r->right, r->top, u2, v1);
   1252             TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
   1253             TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
   1254 
   1255             numQuads++;
   1256 
   1257             if (numQuads >= gMaxNumberOfQuads) {
   1258                 DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
   1259                                 GL_UNSIGNED_SHORT, NULL));
   1260                 numQuads = 0;
   1261                 mesh = mCaches.getRegionMesh();
   1262             }
   1263         }
   1264 
   1265         if (numQuads > 0) {
   1266             DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
   1267                             GL_UNSIGNED_SHORT, NULL));
   1268         }
   1269 
   1270 #if DEBUG_LAYERS_AS_REGIONS
   1271         drawRegionRects(layer->region);
   1272 #endif
   1273 
   1274         layer->region.clear();
   1275     }
   1276 }
   1277 
   1278 void OpenGLRenderer::drawRegionRects(const Region& region) {
   1279 #if DEBUG_LAYERS_AS_REGIONS
   1280     size_t count;
   1281     const android::Rect* rects = region.getArray(&count);
   1282 
   1283     uint32_t colors[] = {
   1284             0x7fff0000, 0x7f00ff00,
   1285             0x7f0000ff, 0x7fff00ff,
   1286     };
   1287 
   1288     int offset = 0;
   1289     int32_t top = rects[0].top;
   1290 
   1291     for (size_t i = 0; i < count; i++) {
   1292         if (top != rects[i].top) {
   1293             offset ^= 0x2;
   1294             top = rects[i].top;
   1295         }
   1296 
   1297         Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
   1298         drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)],
   1299                 SkXfermode::kSrcOver_Mode);
   1300     }
   1301 #endif
   1302 }
   1303 
   1304 void OpenGLRenderer::drawRegionRects(const SkRegion& region, int color,
   1305         SkXfermode::Mode mode, bool dirty) {
   1306     Vector<float> rects;
   1307 
   1308     SkRegion::Iterator it(region);
   1309     while (!it.done()) {
   1310         const SkIRect& r = it.rect();
   1311         rects.push(r.fLeft);
   1312         rects.push(r.fTop);
   1313         rects.push(r.fRight);
   1314         rects.push(r.fBottom);
   1315         it.next();
   1316     }
   1317 
   1318     drawColorRects(rects.array(), rects.size(), color, mode, true, dirty, false);
   1319 }
   1320 
   1321 void OpenGLRenderer::dirtyLayer(const float left, const float top,
   1322         const float right, const float bottom, const mat4 transform) {
   1323     if (hasLayer()) {
   1324         Rect bounds(left, top, right, bottom);
   1325         transform.mapRect(bounds);
   1326         dirtyLayerUnchecked(bounds, getRegion());
   1327     }
   1328 }
   1329 
   1330 void OpenGLRenderer::dirtyLayer(const float left, const float top,
   1331         const float right, const float bottom) {
   1332     if (hasLayer()) {
   1333         Rect bounds(left, top, right, bottom);
   1334         dirtyLayerUnchecked(bounds, getRegion());
   1335     }
   1336 }
   1337 
   1338 void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
   1339     if (bounds.intersect(*mSnapshot->clipRect)) {
   1340         bounds.snapToPixelBoundaries();
   1341         android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
   1342         if (!dirty.isEmpty()) {
   1343             region->orSelf(dirty);
   1344         }
   1345     }
   1346 }
   1347 
   1348 void OpenGLRenderer::drawIndexedQuads(Vertex* mesh, GLsizei quadsCount) {
   1349     GLsizei elementsCount = quadsCount * 6;
   1350     while (elementsCount > 0) {
   1351         GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
   1352 
   1353         setupDrawIndexedVertices(&mesh[0].position[0]);
   1354         glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL);
   1355 
   1356         elementsCount -= drawCount;
   1357         // Though there are 4 vertices in a quad, we use 6 indices per
   1358         // quad to draw with GL_TRIANGLES
   1359         mesh += (drawCount / 6) * 4;
   1360     }
   1361 }
   1362 
   1363 void OpenGLRenderer::clearLayerRegions() {
   1364     const size_t count = mLayers.size();
   1365     if (count == 0) return;
   1366 
   1367     if (!mSnapshot->isIgnored()) {
   1368         // Doing several glScissor/glClear here can negatively impact
   1369         // GPUs with a tiler architecture, instead we draw quads with
   1370         // the Clear blending mode
   1371 
   1372         // The list contains bounds that have already been clipped
   1373         // against their initial clip rect, and the current clip
   1374         // is likely different so we need to disable clipping here
   1375         bool scissorChanged = mCaches.disableScissor();
   1376 
   1377         Vertex mesh[count * 4];
   1378         Vertex* vertex = mesh;
   1379 
   1380         for (uint32_t i = 0; i < count; i++) {
   1381             Rect* bounds = mLayers.itemAt(i);
   1382 
   1383             Vertex::set(vertex++, bounds->left, bounds->top);
   1384             Vertex::set(vertex++, bounds->right, bounds->top);
   1385             Vertex::set(vertex++, bounds->left, bounds->bottom);
   1386             Vertex::set(vertex++, bounds->right, bounds->bottom);
   1387 
   1388             delete bounds;
   1389         }
   1390         // We must clear the list of dirty rects before we
   1391         // call setupDraw() to prevent stencil setup to do
   1392         // the same thing again
   1393         mLayers.clear();
   1394 
   1395         setupDraw(false);
   1396         setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
   1397         setupDrawBlending(true, SkXfermode::kClear_Mode);
   1398         setupDrawProgram();
   1399         setupDrawPureColorUniforms();
   1400         setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
   1401 
   1402         drawIndexedQuads(&mesh[0], count);
   1403 
   1404         if (scissorChanged) mCaches.enableScissor();
   1405     } else {
   1406         for (uint32_t i = 0; i < count; i++) {
   1407             delete mLayers.itemAt(i);
   1408         }
   1409         mLayers.clear();
   1410     }
   1411 }
   1412 
   1413 ///////////////////////////////////////////////////////////////////////////////
   1414 // State Deferral
   1415 ///////////////////////////////////////////////////////////////////////////////
   1416 
   1417 bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
   1418     const Rect& currentClip = *(mSnapshot->clipRect);
   1419     const mat4& currentMatrix = *(mSnapshot->transform);
   1420 
   1421     if (stateDeferFlags & kStateDeferFlag_Draw) {
   1422         // state has bounds initialized in local coordinates
   1423         if (!state.mBounds.isEmpty()) {
   1424             currentMatrix.mapRect(state.mBounds);
   1425             Rect clippedBounds(state.mBounds);
   1426             // NOTE: if we ever want to use this clipping info to drive whether the scissor
   1427             // is used, it should more closely duplicate the quickReject logic (in how it uses
   1428             // snapToPixelBoundaries)
   1429 
   1430             if(!clippedBounds.intersect(currentClip)) {
   1431                 // quick rejected
   1432                 return true;
   1433             }
   1434 
   1435             state.mClipSideFlags = kClipSide_None;
   1436             if (!currentClip.contains(state.mBounds)) {
   1437                 int& flags = state.mClipSideFlags;
   1438                 // op partially clipped, so record which sides are clipped for clip-aware merging
   1439                 if (currentClip.left > state.mBounds.left) flags |= kClipSide_Left;
   1440                 if (currentClip.top > state.mBounds.top) flags |= kClipSide_Top;
   1441                 if (currentClip.right < state.mBounds.right) flags |= kClipSide_Right;
   1442                 if (currentClip.bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
   1443             }
   1444             state.mBounds.set(clippedBounds);
   1445         } else {
   1446             // Empty bounds implies size unknown. Label op as conservatively clipped to disable
   1447             // overdraw avoidance (since we don't know what it overlaps)
   1448             state.mClipSideFlags = kClipSide_ConservativeFull;
   1449             state.mBounds.set(currentClip);
   1450         }
   1451     }
   1452 
   1453     state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
   1454     if (state.mClipValid) {
   1455         state.mClip.set(currentClip);
   1456     }
   1457 
   1458     // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
   1459     // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
   1460     state.mMatrix.load(currentMatrix);
   1461     state.mDrawModifiers = mDrawModifiers;
   1462     state.mAlpha = mSnapshot->alpha;
   1463     return false;
   1464 }
   1465 
   1466 void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
   1467     currentTransform().load(state.mMatrix);
   1468     mDrawModifiers = state.mDrawModifiers;
   1469     mSnapshot->alpha = state.mAlpha;
   1470 
   1471     if (state.mClipValid && !skipClipRestore) {
   1472         mSnapshot->setClip(state.mClip.left, state.mClip.top,
   1473                 state.mClip.right, state.mClip.bottom);
   1474         dirtyClip();
   1475     }
   1476 }
   1477 
   1478 /**
   1479  * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done
   1480  * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at
   1481  * least one op is clipped), or disabled entirely (because no merged op is clipped)
   1482  *
   1483  * This method should be called when restoreDisplayState() won't be restoring the clip
   1484  */
   1485 void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
   1486     if (clipRect != NULL) {
   1487         mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
   1488     } else {
   1489         mSnapshot->setClip(0, 0, mWidth, mHeight);
   1490     }
   1491     dirtyClip();
   1492     mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);
   1493 }
   1494 
   1495 ///////////////////////////////////////////////////////////////////////////////
   1496 // Transforms
   1497 ///////////////////////////////////////////////////////////////////////////////
   1498 
   1499 void OpenGLRenderer::translate(float dx, float dy) {
   1500     currentTransform().translate(dx, dy);
   1501 }
   1502 
   1503 void OpenGLRenderer::rotate(float degrees) {
   1504     currentTransform().rotate(degrees, 0.0f, 0.0f, 1.0f);
   1505 }
   1506 
   1507 void OpenGLRenderer::scale(float sx, float sy) {
   1508     currentTransform().scale(sx, sy, 1.0f);
   1509 }
   1510 
   1511 void OpenGLRenderer::skew(float sx, float sy) {
   1512     currentTransform().skew(sx, sy);
   1513 }
   1514 
   1515 void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
   1516     if (matrix) {
   1517         currentTransform().load(*matrix);
   1518     } else {
   1519         currentTransform().loadIdentity();
   1520     }
   1521 }
   1522 
   1523 bool OpenGLRenderer::hasRectToRectTransform() {
   1524     return CC_LIKELY(currentTransform().rectToRect());
   1525 }
   1526 
   1527 void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
   1528     currentTransform().copyTo(*matrix);
   1529 }
   1530 
   1531 void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
   1532     SkMatrix transform;
   1533     currentTransform().copyTo(transform);
   1534     transform.preConcat(*matrix);
   1535     currentTransform().load(transform);
   1536 }
   1537 
   1538 ///////////////////////////////////////////////////////////////////////////////
   1539 // Clipping
   1540 ///////////////////////////////////////////////////////////////////////////////
   1541 
   1542 void OpenGLRenderer::setScissorFromClip() {
   1543     Rect clip(*mSnapshot->clipRect);
   1544     clip.snapToPixelBoundaries();
   1545 
   1546     if (mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom,
   1547             clip.getWidth(), clip.getHeight())) {
   1548         mDirtyClip = false;
   1549     }
   1550 }
   1551 
   1552 void OpenGLRenderer::ensureStencilBuffer() {
   1553     // Thanks to the mismatch between EGL and OpenGL ES FBO we
   1554     // cannot attach a stencil buffer to fbo0 dynamically. Let's
   1555     // just hope we have one when hasLayer() returns false.
   1556     if (hasLayer()) {
   1557         attachStencilBufferToLayer(mSnapshot->layer);
   1558     }
   1559 }
   1560 
   1561 void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
   1562     // The layer's FBO is already bound when we reach this stage
   1563     if (!layer->getStencilRenderBuffer()) {
   1564         // GL_QCOM_tiled_rendering doesn't like it if a renderbuffer
   1565         // is attached after we initiated tiling. We must turn it off,
   1566         // attach the new render buffer then turn tiling back on
   1567         endTiling();
   1568 
   1569         RenderBuffer* buffer = mCaches.renderBufferCache.get(
   1570                 Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
   1571         layer->setStencilRenderBuffer(buffer);
   1572 
   1573         startTiling(layer->clipRect, layer->layer.getHeight());
   1574     }
   1575 }
   1576 
   1577 void OpenGLRenderer::setStencilFromClip() {
   1578     if (!mCaches.debugOverdraw) {
   1579         if (!mSnapshot->clipRegion->isEmpty()) {
   1580             // NOTE: The order here is important, we must set dirtyClip to false
   1581             //       before any draw call to avoid calling back into this method
   1582             mDirtyClip = false;
   1583 
   1584             ensureStencilBuffer();
   1585 
   1586             mCaches.stencil.enableWrite();
   1587 
   1588             // Clear the stencil but first make sure we restrict drawing
   1589             // to the region's bounds
   1590             bool resetScissor = mCaches.enableScissor();
   1591             if (resetScissor) {
   1592                 // The scissor was not set so we now need to update it
   1593                 setScissorFromClip();
   1594             }
   1595             mCaches.stencil.clear();
   1596             if (resetScissor) mCaches.disableScissor();
   1597 
   1598             // NOTE: We could use the region contour path to generate a smaller mesh
   1599             //       Since we are using the stencil we could use the red book path
   1600             //       drawing technique. It might increase bandwidth usage though.
   1601 
   1602             // The last parameter is important: we are not drawing in the color buffer
   1603             // so we don't want to dirty the current layer, if any
   1604             drawRegionRects(*mSnapshot->clipRegion, 0xff000000, SkXfermode::kSrc_Mode, false);
   1605 
   1606             mCaches.stencil.enableTest();
   1607 
   1608             // Draw the region used to generate the stencil if the appropriate debug
   1609             // mode is enabled
   1610             if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
   1611                 drawRegionRects(*mSnapshot->clipRegion, 0x7f0000ff, SkXfermode::kSrcOver_Mode);
   1612             }
   1613         } else {
   1614             mCaches.stencil.disable();
   1615         }
   1616     }
   1617 }
   1618 
   1619 const Rect& OpenGLRenderer::getClipBounds() {
   1620     return mSnapshot->getLocalClip();
   1621 }
   1622 
   1623 bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
   1624         bool snapOut, bool* clipRequired) {
   1625     if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
   1626         return true;
   1627     }
   1628 
   1629     Rect r(left, top, right, bottom);
   1630     currentTransform().mapRect(r);
   1631     r.snapGeometryToPixelBoundaries(snapOut);
   1632 
   1633     Rect clipRect(*mSnapshot->clipRect);
   1634     clipRect.snapToPixelBoundaries();
   1635 
   1636     if (!clipRect.intersects(r)) return true;
   1637 
   1638     if (clipRequired) *clipRequired = !clipRect.contains(r);
   1639     return false;
   1640 }
   1641 
   1642 bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom,
   1643         SkPaint* paint) {
   1644     // AA geometry will likely have a ramp around it (not accounted for in local bounds). Snap out
   1645     // the final mapped rect to ensure correct clipping behavior for the ramp.
   1646     bool snapOut = paint->isAntiAlias();
   1647 
   1648     if (paint->getStyle() != SkPaint::kFill_Style) {
   1649         float outset = paint->getStrokeWidth() * 0.5f;
   1650         return quickReject(left - outset, top - outset, right + outset, bottom + outset, snapOut);
   1651     } else {
   1652         return quickReject(left, top, right, bottom, snapOut);
   1653     }
   1654 }
   1655 
   1656 bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom, bool snapOut) {
   1657     bool clipRequired = false;
   1658     if (quickRejectNoScissor(left, top, right, bottom, snapOut, &clipRequired)) {
   1659         return true;
   1660     }
   1661 
   1662     if (!isDeferred()) {
   1663         mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
   1664     }
   1665     return false;
   1666 }
   1667 
   1668 void OpenGLRenderer::debugClip() {
   1669 #if DEBUG_CLIP_REGIONS
   1670     if (!isDeferred() && !mSnapshot->clipRegion->isEmpty()) {
   1671         drawRegionRects(*mSnapshot->clipRegion, 0x7f00ff00, SkXfermode::kSrcOver_Mode);
   1672     }
   1673 #endif
   1674 }
   1675 
   1676 bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
   1677     if (CC_LIKELY(currentTransform().rectToRect())) {
   1678         bool clipped = mSnapshot->clip(left, top, right, bottom, op);
   1679         if (clipped) {
   1680             dirtyClip();
   1681         }
   1682         return !mSnapshot->clipRect->isEmpty();
   1683     }
   1684 
   1685     SkPath path;
   1686     path.addRect(left, top, right, bottom);
   1687 
   1688     return OpenGLRenderer::clipPath(&path, op);
   1689 }
   1690 
   1691 bool OpenGLRenderer::clipPath(SkPath* path, SkRegion::Op op) {
   1692     SkMatrix transform;
   1693     currentTransform().copyTo(transform);
   1694 
   1695     SkPath transformed;
   1696     path->transform(transform, &transformed);
   1697 
   1698     SkRegion clip;
   1699     if (!mSnapshot->previous->clipRegion->isEmpty()) {
   1700         clip.setRegion(*mSnapshot->previous->clipRegion);
   1701     } else {
   1702         if (mSnapshot->previous == mFirstSnapshot) {
   1703             clip.setRect(0, 0, mWidth, mHeight);
   1704         } else {
   1705             Rect* bounds = mSnapshot->previous->clipRect;
   1706             clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
   1707         }
   1708     }
   1709 
   1710     SkRegion region;
   1711     region.setPath(transformed, clip);
   1712 
   1713     bool clipped = mSnapshot->clipRegionTransformed(region, op);
   1714     if (clipped) {
   1715         dirtyClip();
   1716     }
   1717     return !mSnapshot->clipRect->isEmpty();
   1718 }
   1719 
   1720 bool OpenGLRenderer::clipRegion(SkRegion* region, SkRegion::Op op) {
   1721     bool clipped = mSnapshot->clipRegionTransformed(*region, op);
   1722     if (clipped) {
   1723         dirtyClip();
   1724     }
   1725     return !mSnapshot->clipRect->isEmpty();
   1726 }
   1727 
   1728 Rect* OpenGLRenderer::getClipRect() {
   1729     return mSnapshot->clipRect;
   1730 }
   1731 
   1732 ///////////////////////////////////////////////////////////////////////////////
   1733 // Drawing commands
   1734 ///////////////////////////////////////////////////////////////////////////////
   1735 
   1736 void OpenGLRenderer::setupDraw(bool clear) {
   1737     // TODO: It would be best if we could do this before quickReject()
   1738     //       changes the scissor test state
   1739     if (clear) clearLayerRegions();
   1740     // Make sure setScissor & setStencil happen at the beginning of
   1741     // this method
   1742     if (mDirtyClip) {
   1743         if (mCaches.scissorEnabled) {
   1744             setScissorFromClip();
   1745         }
   1746         setStencilFromClip();
   1747     }
   1748 
   1749     mDescription.reset();
   1750 
   1751     mSetShaderColor = false;
   1752     mColorSet = false;
   1753     mColorA = mColorR = mColorG = mColorB = 0.0f;
   1754     mTextureUnit = 0;
   1755     mTrackDirtyRegions = true;
   1756 
   1757     // Enable debug highlight when what we're about to draw is tested against
   1758     // the stencil buffer and if stencil highlight debugging is on
   1759     mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
   1760             mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
   1761             mCaches.stencil.isTestEnabled();
   1762 
   1763     mDescription.emulateStencil = mCountOverdraw;
   1764 }
   1765 
   1766 void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
   1767     mDescription.hasTexture = true;
   1768     mDescription.hasAlpha8Texture = isAlpha8;
   1769 }
   1770 
   1771 void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
   1772     mDescription.hasTexture = true;
   1773     mDescription.hasColors = true;
   1774     mDescription.hasAlpha8Texture = isAlpha8;
   1775 }
   1776 
   1777 void OpenGLRenderer::setupDrawWithExternalTexture() {
   1778     mDescription.hasExternalTexture = true;
   1779 }
   1780 
   1781 void OpenGLRenderer::setupDrawNoTexture() {
   1782     mCaches.disableTexCoordsVertexArray();
   1783 }
   1784 
   1785 void OpenGLRenderer::setupDrawAA() {
   1786     mDescription.isAA = true;
   1787 }
   1788 
   1789 void OpenGLRenderer::setupDrawColor(int color, int alpha) {
   1790     mColorA = alpha / 255.0f;
   1791     mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
   1792     mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
   1793     mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
   1794     mColorSet = true;
   1795     mSetShaderColor = mDescription.setColor(mColorR, mColorG, mColorB, mColorA);
   1796 }
   1797 
   1798 void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
   1799     mColorA = alpha / 255.0f;
   1800     mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
   1801     mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
   1802     mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
   1803     mColorSet = true;
   1804     mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA);
   1805 }
   1806 
   1807 void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
   1808     mCaches.fontRenderer->describe(mDescription, paint);
   1809 }
   1810 
   1811 void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
   1812     mColorA = a;
   1813     mColorR = r;
   1814     mColorG = g;
   1815     mColorB = b;
   1816     mColorSet = true;
   1817     mSetShaderColor = mDescription.setColor(r, g, b, a);
   1818 }
   1819 
   1820 void OpenGLRenderer::setupDrawShader() {
   1821     if (mDrawModifiers.mShader) {
   1822         mDrawModifiers.mShader->describe(mDescription, mExtensions);
   1823     }
   1824 }
   1825 
   1826 void OpenGLRenderer::setupDrawColorFilter() {
   1827     if (mDrawModifiers.mColorFilter) {
   1828         mDrawModifiers.mColorFilter->describe(mDescription, mExtensions);
   1829     }
   1830 }
   1831 
   1832 void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
   1833     if (mColorSet && mode == SkXfermode::kClear_Mode) {
   1834         mColorA = 1.0f;
   1835         mColorR = mColorG = mColorB = 0.0f;
   1836         mSetShaderColor = mDescription.modulate = true;
   1837     }
   1838 }
   1839 
   1840 void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) {
   1841     // When the blending mode is kClear_Mode, we need to use a modulate color
   1842     // argb=1,0,0,0
   1843     accountForClear(mode);
   1844     bool blend = (mColorSet && mColorA < 1.0f) ||
   1845             (mDrawModifiers.mShader && mDrawModifiers.mShader->blend());
   1846     chooseBlending(blend, mode, mDescription, swapSrcDst);
   1847 }
   1848 
   1849 void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) {
   1850     // When the blending mode is kClear_Mode, we need to use a modulate color
   1851     // argb=1,0,0,0
   1852     accountForClear(mode);
   1853     blend |= (mColorSet && mColorA < 1.0f) ||
   1854             (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
   1855             (mDrawModifiers.mColorFilter && mDrawModifiers.mColorFilter->blend());
   1856     chooseBlending(blend, mode, mDescription, swapSrcDst);
   1857 }
   1858 
   1859 void OpenGLRenderer::setupDrawProgram() {
   1860     useProgram(mCaches.programCache.get(mDescription));
   1861 }
   1862 
   1863 void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
   1864     mTrackDirtyRegions = false;
   1865 }
   1866 
   1867 void OpenGLRenderer::setupDrawModelViewTranslate(float left, float top, float right, float bottom,
   1868         bool ignoreTransform) {
   1869     mModelView.loadTranslate(left, top, 0.0f);
   1870     if (!ignoreTransform) {
   1871         mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform());
   1872         if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, currentTransform());
   1873     } else {
   1874         mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity());
   1875         if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
   1876     }
   1877 }
   1878 
   1879 void OpenGLRenderer::setupDrawModelViewIdentity(bool offset) {
   1880     mCaches.currentProgram->set(mOrthoMatrix, mat4::identity(), currentTransform(), offset);
   1881 }
   1882 
   1883 void OpenGLRenderer::setupDrawModelView(float left, float top, float right, float bottom,
   1884         bool ignoreTransform, bool ignoreModelView) {
   1885     if (!ignoreModelView) {
   1886         mModelView.loadTranslate(left, top, 0.0f);
   1887         mModelView.scale(right - left, bottom - top, 1.0f);
   1888     } else {
   1889         mModelView.loadIdentity();
   1890     }
   1891     bool dirty = right - left > 0.0f && bottom - top > 0.0f;
   1892     if (!ignoreTransform) {
   1893         mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform());
   1894         if (mTrackDirtyRegions && dirty) {
   1895             dirtyLayer(left, top, right, bottom, currentTransform());
   1896         }
   1897     } else {
   1898         mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity());
   1899         if (mTrackDirtyRegions && dirty) dirtyLayer(left, top, right, bottom);
   1900     }
   1901 }
   1902 
   1903 void OpenGLRenderer::setupDrawColorUniforms() {
   1904     if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) {
   1905         mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
   1906     }
   1907 }
   1908 
   1909 void OpenGLRenderer::setupDrawPureColorUniforms() {
   1910     if (mSetShaderColor) {
   1911         mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
   1912     }
   1913 }
   1914 
   1915 void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) {
   1916     if (mDrawModifiers.mShader) {
   1917         if (ignoreTransform) {
   1918             mModelView.loadInverse(currentTransform());
   1919         }
   1920         mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
   1921                 mModelView, *mSnapshot, &mTextureUnit);
   1922     }
   1923 }
   1924 
   1925 void OpenGLRenderer::setupDrawShaderIdentityUniforms() {
   1926     if (mDrawModifiers.mShader) {
   1927         mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
   1928                 mat4::identity(), *mSnapshot, &mTextureUnit);
   1929     }
   1930 }
   1931 
   1932 void OpenGLRenderer::setupDrawColorFilterUniforms() {
   1933     if (mDrawModifiers.mColorFilter) {
   1934         mDrawModifiers.mColorFilter->setupProgram(mCaches.currentProgram);
   1935     }
   1936 }
   1937 
   1938 void OpenGLRenderer::setupDrawTextGammaUniforms() {
   1939     mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram);
   1940 }
   1941 
   1942 void OpenGLRenderer::setupDrawSimpleMesh() {
   1943     bool force = mCaches.bindMeshBuffer();
   1944     mCaches.bindPositionVertexPointer(force, 0);
   1945     mCaches.unbindIndicesBuffer();
   1946 }
   1947 
   1948 void OpenGLRenderer::setupDrawTexture(GLuint texture) {
   1949     if (texture) bindTexture(texture);
   1950     mTextureUnit++;
   1951     mCaches.enableTexCoordsVertexArray();
   1952 }
   1953 
   1954 void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
   1955     bindExternalTexture(texture);
   1956     mTextureUnit++;
   1957     mCaches.enableTexCoordsVertexArray();
   1958 }
   1959 
   1960 void OpenGLRenderer::setupDrawTextureTransform() {
   1961     mDescription.hasTextureTransform = true;
   1962 }
   1963 
   1964 void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
   1965     glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
   1966             GL_FALSE, &transform.data[0]);
   1967 }
   1968 
   1969 void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
   1970     bool force = false;
   1971     if (!vertices || vbo) {
   1972         force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
   1973     } else {
   1974         force = mCaches.unbindMeshBuffer();
   1975     }
   1976 
   1977     mCaches.bindPositionVertexPointer(force, vertices);
   1978     if (mCaches.currentProgram->texCoords >= 0) {
   1979         mCaches.bindTexCoordsVertexPointer(force, texCoords);
   1980     }
   1981 
   1982     mCaches.unbindIndicesBuffer();
   1983 }
   1984 
   1985 void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors) {
   1986     bool force = mCaches.unbindMeshBuffer();
   1987     GLsizei stride = sizeof(ColorTextureVertex);
   1988 
   1989     mCaches.bindPositionVertexPointer(force, vertices, stride);
   1990     if (mCaches.currentProgram->texCoords >= 0) {
   1991         mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
   1992     }
   1993     int slot = mCaches.currentProgram->getAttrib("colors");
   1994     if (slot >= 0) {
   1995         glEnableVertexAttribArray(slot);
   1996         glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
   1997     }
   1998 
   1999     mCaches.unbindIndicesBuffer();
   2000 }
   2001 
   2002 void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
   2003     bool force = false;
   2004     // If vbo is != 0 we want to treat the vertices parameter as an offset inside
   2005     // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
   2006     // use the default VBO found in Caches
   2007     if (!vertices || vbo) {
   2008         force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
   2009     } else {
   2010         force = mCaches.unbindMeshBuffer();
   2011     }
   2012     mCaches.bindIndicesBuffer();
   2013 
   2014     mCaches.bindPositionVertexPointer(force, vertices);
   2015     if (mCaches.currentProgram->texCoords >= 0) {
   2016         mCaches.bindTexCoordsVertexPointer(force, texCoords);
   2017     }
   2018 }
   2019 
   2020 void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
   2021     bool force = mCaches.unbindMeshBuffer();
   2022     mCaches.bindIndicesBuffer();
   2023     mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
   2024 }
   2025 
   2026 ///////////////////////////////////////////////////////////////////////////////
   2027 // Drawing
   2028 ///////////////////////////////////////////////////////////////////////////////
   2029 
   2030 status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
   2031         int32_t replayFlags) {
   2032     status_t status;
   2033     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
   2034     // will be performed by the display list itself
   2035     if (displayList && displayList->isRenderable()) {
   2036         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
   2037             status = startFrame();
   2038             ReplayStateStruct replayStruct(*this, dirty, replayFlags);
   2039             displayList->replay(replayStruct, 0);
   2040             return status | replayStruct.mDrawGlStatus;
   2041         }
   2042 
   2043         bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs!
   2044         DeferredDisplayList deferredList(*(mSnapshot->clipRect), avoidOverdraw);
   2045         DeferStateStruct deferStruct(deferredList, *this, replayFlags);
   2046         displayList->defer(deferStruct, 0);
   2047 
   2048         flushLayers();
   2049         status = startFrame();
   2050 
   2051         return status | deferredList.flush(*this, dirty);
   2052     }
   2053 
   2054     return DrawGlInfo::kStatusDone;
   2055 }
   2056 
   2057 void OpenGLRenderer::outputDisplayList(DisplayList* displayList) {
   2058     if (displayList) {
   2059         displayList->output(1);
   2060     }
   2061 }
   2062 
   2063 void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) {
   2064     int alpha;
   2065     SkXfermode::Mode mode;
   2066     getAlphaAndMode(paint, &alpha, &mode);
   2067 
   2068     int color = paint != NULL ? paint->getColor() : 0;
   2069 
   2070     float x = left;
   2071     float y = top;
   2072 
   2073     texture->setWrap(GL_CLAMP_TO_EDGE, true);
   2074 
   2075     bool ignoreTransform = false;
   2076     if (currentTransform().isPureTranslate()) {
   2077         x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f);
   2078         y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f);
   2079         ignoreTransform = true;
   2080 
   2081         texture->setFilter(GL_NEAREST, true);
   2082     } else {
   2083         texture->setFilter(FILTER(paint), true);
   2084     }
   2085 
   2086     // No need to check for a UV mapper on the texture object, only ARGB_8888
   2087     // bitmaps get packed in the atlas
   2088     drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
   2089             paint != NULL, color, alpha, mode, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
   2090             GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
   2091 }
   2092 
   2093 /**
   2094  * Important note: this method is intended to draw batches of bitmaps and
   2095  * will not set the scissor enable or dirty the current layer, if any.
   2096  * The caller is responsible for properly dirtying the current layer.
   2097  */
   2098 status_t OpenGLRenderer::drawBitmaps(SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
   2099         TextureVertex* vertices, bool pureTranslate, const Rect& bounds, SkPaint* paint) {
   2100     mCaches.activeTexture(0);
   2101     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
   2102     if (!texture) return DrawGlInfo::kStatusDone;
   2103 
   2104     const AutoTexture autoCleanup(texture);
   2105 
   2106     int alpha;
   2107     SkXfermode::Mode mode;
   2108     getAlphaAndMode(paint, &alpha, &mode);
   2109 
   2110     texture->setWrap(GL_CLAMP_TO_EDGE, true);
   2111     texture->setFilter(pureTranslate ? GL_NEAREST : FILTER(paint), true);
   2112 
   2113     const float x = (int) floorf(bounds.left + 0.5f);
   2114     const float y = (int) floorf(bounds.top + 0.5f);
   2115     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
   2116         int color = paint != NULL ? paint->getColor() : 0;
   2117         drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
   2118                 texture->id, paint != NULL, color, alpha, mode,
   2119                 &vertices[0].position[0], &vertices[0].texture[0],
   2120                 GL_TRIANGLES, bitmapCount * 6, true, true, false);
   2121     } else {
   2122         drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
   2123                 texture->id, alpha / 255.0f, mode, texture->blend,
   2124                 &vertices[0].position[0], &vertices[0].texture[0],
   2125                 GL_TRIANGLES, bitmapCount * 6, false, true, 0, true, false);
   2126     }
   2127 
   2128     return DrawGlInfo::kStatusDrew;
   2129 }
   2130 
   2131 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
   2132     const float right = left + bitmap->width();
   2133     const float bottom = top + bitmap->height();
   2134 
   2135     if (quickReject(left, top, right, bottom)) {
   2136         return DrawGlInfo::kStatusDone;
   2137     }
   2138 
   2139     mCaches.activeTexture(0);
   2140     Texture* texture = getTexture(bitmap);
   2141     if (!texture) return DrawGlInfo::kStatusDone;
   2142     const AutoTexture autoCleanup(texture);
   2143 
   2144     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
   2145         drawAlphaBitmap(texture, left, top, paint);
   2146     } else {
   2147         drawTextureRect(left, top, right, bottom, texture, paint);
   2148     }
   2149 
   2150     return DrawGlInfo::kStatusDrew;
   2151 }
   2152 
   2153 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
   2154     Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
   2155     const mat4 transform(*matrix);
   2156     transform.mapRect(r);
   2157 
   2158     if (quickReject(r.left, r.top, r.right, r.bottom)) {
   2159         return DrawGlInfo::kStatusDone;
   2160     }
   2161 
   2162     mCaches.activeTexture(0);
   2163     Texture* texture = getTexture(bitmap);
   2164     if (!texture) return DrawGlInfo::kStatusDone;
   2165     const AutoTexture autoCleanup(texture);
   2166 
   2167     // This could be done in a cheaper way, all we need is pass the matrix
   2168     // to the vertex shader. The save/restore is a bit overkill.
   2169     save(SkCanvas::kMatrix_SaveFlag);
   2170     concatMatrix(matrix);
   2171     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
   2172         drawAlphaBitmap(texture, 0.0f, 0.0f, paint);
   2173     } else {
   2174         drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
   2175     }
   2176     restore();
   2177 
   2178     return DrawGlInfo::kStatusDrew;
   2179 }
   2180 
   2181 status_t OpenGLRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
   2182     const float right = left + bitmap->width();
   2183     const float bottom = top + bitmap->height();
   2184 
   2185     if (quickReject(left, top, right, bottom)) {
   2186         return DrawGlInfo::kStatusDone;
   2187     }
   2188 
   2189     mCaches.activeTexture(0);
   2190     Texture* texture = mCaches.textureCache.getTransient(bitmap);
   2191     const AutoTexture autoCleanup(texture);
   2192 
   2193     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
   2194         drawAlphaBitmap(texture, left, top, paint);
   2195     } else {
   2196         drawTextureRect(left, top, right, bottom, texture, paint);
   2197     }
   2198 
   2199     return DrawGlInfo::kStatusDrew;
   2200 }
   2201 
   2202 status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
   2203         float* vertices, int* colors, SkPaint* paint) {
   2204     if (!vertices || mSnapshot->isIgnored()) {
   2205         return DrawGlInfo::kStatusDone;
   2206     }
   2207 
   2208     // TODO: use quickReject on bounds from vertices
   2209     mCaches.enableScissor();
   2210 
   2211     float left = FLT_MAX;
   2212     float top = FLT_MAX;
   2213     float right = FLT_MIN;
   2214     float bottom = FLT_MIN;
   2215 
   2216     const uint32_t count = meshWidth * meshHeight * 6;
   2217 
   2218     ColorTextureVertex mesh[count];
   2219     ColorTextureVertex* vertex = mesh;
   2220 
   2221     bool cleanupColors = false;
   2222     if (!colors) {
   2223         uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
   2224         colors = new int[colorsCount];
   2225         memset(colors, 0xff, colorsCount * sizeof(int));
   2226         cleanupColors = true;
   2227     }
   2228 
   2229     mCaches.activeTexture(0);
   2230     Texture* texture = mCaches.assetAtlas.getEntryTexture(bitmap);
   2231     const UvMapper& mapper(getMapper(texture));
   2232 
   2233     for (int32_t y = 0; y < meshHeight; y++) {
   2234         for (int32_t x = 0; x < meshWidth; x++) {
   2235             uint32_t i = (y * (meshWidth + 1) + x) * 2;
   2236 
   2237             float u1 = float(x) / meshWidth;
   2238             float u2 = float(x + 1) / meshWidth;
   2239             float v1 = float(y) / meshHeight;
   2240             float v2 = float(y + 1) / meshHeight;
   2241 
   2242             mapper.map(u1, v1, u2, v2);
   2243 
   2244             int ax = i + (meshWidth + 1) * 2;
   2245             int ay = ax + 1;
   2246             int bx = i;
   2247             int by = bx + 1;
   2248             int cx = i + 2;
   2249             int cy = cx + 1;
   2250             int dx = i + (meshWidth + 1) * 2 + 2;
   2251             int dy = dx + 1;
   2252 
   2253             ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
   2254             ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
   2255             ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
   2256 
   2257             ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
   2258             ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
   2259             ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
   2260 
   2261             left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
   2262             top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
   2263             right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
   2264             bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
   2265         }
   2266     }
   2267 
   2268     if (quickReject(left, top, right, bottom)) {
   2269         if (cleanupColors) delete[] colors;
   2270         return DrawGlInfo::kStatusDone;
   2271     }
   2272 
   2273     if (!texture) {
   2274         texture = mCaches.textureCache.get(bitmap);
   2275         if (!texture) {
   2276             if (cleanupColors) delete[] colors;
   2277             return DrawGlInfo::kStatusDone;
   2278         }
   2279     }
   2280     const AutoTexture autoCleanup(texture);
   2281 
   2282     texture->setWrap(GL_CLAMP_TO_EDGE, true);
   2283     texture->setFilter(FILTER(paint), true);
   2284 
   2285     int alpha;
   2286     SkXfermode::Mode mode;
   2287     getAlphaAndMode(paint, &alpha, &mode);
   2288 
   2289     float a = alpha / 255.0f;
   2290 
   2291     if (hasLayer()) {
   2292         dirtyLayer(left, top, right, bottom, currentTransform());
   2293     }
   2294 
   2295     setupDraw();
   2296     setupDrawWithTextureAndColor();
   2297     setupDrawColor(a, a, a, a);
   2298     setupDrawColorFilter();
   2299     setupDrawBlending(true, mode, false);
   2300     setupDrawProgram();
   2301     setupDrawDirtyRegionsDisabled();
   2302     setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, false);
   2303     setupDrawTexture(texture->id);
   2304     setupDrawPureColorUniforms();
   2305     setupDrawColorFilterUniforms();
   2306     setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0], &mesh[0].color[0]);
   2307 
   2308     glDrawArrays(GL_TRIANGLES, 0, count);
   2309 
   2310     int slot = mCaches.currentProgram->getAttrib("colors");
   2311     if (slot >= 0) {
   2312         glDisableVertexAttribArray(slot);
   2313     }
   2314 
   2315     if (cleanupColors) delete[] colors;
   2316 
   2317     return DrawGlInfo::kStatusDrew;
   2318 }
   2319 
   2320 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
   2321          float srcLeft, float srcTop, float srcRight, float srcBottom,
   2322          float dstLeft, float dstTop, float dstRight, float dstBottom,
   2323          SkPaint* paint) {
   2324     if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
   2325         return DrawGlInfo::kStatusDone;
   2326     }
   2327 
   2328     mCaches.activeTexture(0);
   2329     Texture* texture = getTexture(bitmap);
   2330     if (!texture) return DrawGlInfo::kStatusDone;
   2331     const AutoTexture autoCleanup(texture);
   2332 
   2333     const float width = texture->width;
   2334     const float height = texture->height;
   2335 
   2336     float u1 = fmax(0.0f, srcLeft / width);
   2337     float v1 = fmax(0.0f, srcTop / height);
   2338     float u2 = fmin(1.0f, srcRight / width);
   2339     float v2 = fmin(1.0f, srcBottom / height);
   2340 
   2341     getMapper(texture).map(u1, v1, u2, v2);
   2342 
   2343     mCaches.unbindMeshBuffer();
   2344     resetDrawTextureTexCoords(u1, v1, u2, v2);
   2345 
   2346     int alpha;
   2347     SkXfermode::Mode mode;
   2348     getAlphaAndMode(paint, &alpha, &mode);
   2349 
   2350     texture->setWrap(GL_CLAMP_TO_EDGE, true);
   2351 
   2352     float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
   2353     float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);
   2354 
   2355     bool scaled = scaleX != 1.0f || scaleY != 1.0f;
   2356     // Apply a scale transform on the canvas only when a shader is in use
   2357     // Skia handles the ratio between the dst and src rects as a scale factor
   2358     // when a shader is set
   2359     bool useScaleTransform = mDrawModifiers.mShader && scaled;
   2360     bool ignoreTransform = false;
   2361 
   2362     if (CC_LIKELY(currentTransform().isPureTranslate() && !useScaleTransform)) {
   2363         float x = (int) floorf(dstLeft + currentTransform().getTranslateX() + 0.5f);
   2364         float y = (int) floorf(dstTop + currentTransform().getTranslateY() + 0.5f);
   2365 
   2366         dstRight = x + (dstRight - dstLeft);
   2367         dstBottom = y + (dstBottom - dstTop);
   2368 
   2369         dstLeft = x;
   2370         dstTop = y;
   2371 
   2372         texture->setFilter(scaled ? FILTER(paint) : GL_NEAREST, true);
   2373         ignoreTransform = true;
   2374     } else {
   2375         texture->setFilter(FILTER(paint), true);
   2376     }
   2377 
   2378     if (CC_UNLIKELY(useScaleTransform)) {
   2379         save(SkCanvas::kMatrix_SaveFlag);
   2380         translate(dstLeft, dstTop);
   2381         scale(scaleX, scaleY);
   2382 
   2383         dstLeft = 0.0f;
   2384         dstTop = 0.0f;
   2385 
   2386         dstRight = srcRight - srcLeft;
   2387         dstBottom = srcBottom - srcTop;
   2388     }
   2389 
   2390     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
   2391         int color = paint ? paint->getColor() : 0;
   2392         drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
   2393                 texture->id, paint != NULL, color, alpha, mode,
   2394                 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
   2395                 GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
   2396     } else {
   2397         drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
   2398                 texture->id, alpha / 255.0f, mode, texture->blend,
   2399                 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
   2400                 GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
   2401     }
   2402 
   2403     if (CC_UNLIKELY(useScaleTransform)) {
   2404         restore();
   2405     }
   2406 
   2407     resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
   2408 
   2409     return DrawGlInfo::kStatusDrew;
   2410 }
   2411 
   2412 status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
   2413         float left, float top, float right, float bottom, SkPaint* paint) {
   2414     if (quickReject(left, top, right, bottom)) {
   2415         return DrawGlInfo::kStatusDone;
   2416     }
   2417 
   2418     AssetAtlas::Entry* entry = mCaches.assetAtlas.getEntry(bitmap);
   2419     const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
   2420             right - left, bottom - top, patch);
   2421 
   2422     return drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
   2423 }
   2424 
   2425 status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry,
   2426         float left, float top, float right, float bottom, SkPaint* paint) {
   2427     if (quickReject(left, top, right, bottom)) {
   2428         return DrawGlInfo::kStatusDone;
   2429     }
   2430 
   2431     if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
   2432         mCaches.activeTexture(0);
   2433         Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
   2434         if (!texture) return DrawGlInfo::kStatusDone;
   2435         const AutoTexture autoCleanup(texture);
   2436 
   2437         texture->setWrap(GL_CLAMP_TO_EDGE, true);
   2438         texture->setFilter(GL_LINEAR, true);
   2439 
   2440         int alpha;
   2441         SkXfermode::Mode mode;
   2442         getAlphaAndMode(paint, &alpha, &mode);
   2443 
   2444         const bool pureTranslate = currentTransform().isPureTranslate();
   2445         // Mark the current layer dirty where we are going to draw the patch
   2446         if (hasLayer() && mesh->hasEmptyQuads) {
   2447             const float offsetX = left + currentTransform().getTranslateX();
   2448             const float offsetY = top + currentTransform().getTranslateY();
   2449             const size_t count = mesh->quads.size();
   2450             for (size_t i = 0; i < count; i++) {
   2451                 const Rect& bounds = mesh->quads.itemAt(i);
   2452                 if (CC_LIKELY(pureTranslate)) {
   2453                     const float x = (int) floorf(bounds.left + offsetX + 0.5f);
   2454                     const float y = (int) floorf(bounds.top + offsetY + 0.5f);
   2455                     dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
   2456                 } else {
   2457                     dirtyLayer(left + bounds.left, top + bounds.top,
   2458                             left + bounds.right, top + bounds.bottom, currentTransform());
   2459                 }
   2460             }
   2461         }
   2462 
   2463         if (CC_LIKELY(pureTranslate)) {
   2464             const float x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f);
   2465             const float y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f);
   2466 
   2467             right = x + right - left;
   2468             bottom = y + bottom - top;
   2469             drawIndexedTextureMesh(x, y, right, bottom, texture->id, alpha / 255.0f,
   2470                     mode, texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
   2471                     GL_TRIANGLES, mesh->indexCount, false, true,
   2472                     mCaches.patchCache.getMeshBuffer(), true, !mesh->hasEmptyQuads);
   2473         } else {
   2474             drawIndexedTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
   2475                     mode, texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
   2476                     GL_TRIANGLES, mesh->indexCount, false, false,
   2477                     mCaches.patchCache.getMeshBuffer(), true, !mesh->hasEmptyQuads);
   2478         }
   2479     }
   2480 
   2481     return DrawGlInfo::kStatusDrew;
   2482 }
   2483 
   2484 /**
   2485  * Important note: this method is intended to draw batches of 9-patch objects and
   2486  * will not set the scissor enable or dirty the current layer, if any.
   2487  * The caller is responsible for properly dirtying the current layer.
   2488  */
   2489 status_t OpenGLRenderer::drawPatches(SkBitmap* bitmap, AssetAtlas::Entry* entry,
   2490         TextureVertex* vertices, uint32_t indexCount, SkPaint* paint) {
   2491     mCaches.activeTexture(0);
   2492     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
   2493     if (!texture) return DrawGlInfo::kStatusDone;
   2494     const AutoTexture autoCleanup(texture);
   2495 
   2496     texture->setWrap(GL_CLAMP_TO_EDGE, true);
   2497     texture->setFilter(GL_LINEAR, true);
   2498 
   2499     int alpha;
   2500     SkXfermode::Mode mode;
   2501     getAlphaAndMode(paint, &alpha, &mode);
   2502 
   2503     drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f,
   2504             mode, texture->blend, &vertices[0].position[0], &vertices[0].texture[0],
   2505             GL_TRIANGLES, indexCount, false, true, 0, true, false);
   2506 
   2507     return DrawGlInfo::kStatusDrew;
   2508 }
   2509 
   2510 status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, SkPaint* paint,
   2511         bool useOffset) {
   2512     if (!vertexBuffer.getVertexCount()) {
   2513         // no vertices to draw
   2514         return DrawGlInfo::kStatusDone;
   2515     }
   2516 
   2517     int color = paint->getColor();
   2518     SkXfermode::Mode mode = getXfermode(paint->getXfermode());
   2519     bool isAA = paint->isAntiAlias();
   2520 
   2521     setupDraw();
   2522     setupDrawNoTexture();
   2523     if (isAA) setupDrawAA();
   2524     setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
   2525     setupDrawColorFilter();
   2526     setupDrawShader();
   2527     setupDrawBlending(isAA, mode);
   2528     setupDrawProgram();
   2529     setupDrawModelViewIdentity(useOffset);
   2530     setupDrawColorUniforms();
   2531     setupDrawColorFilterUniforms();
   2532     setupDrawShaderIdentityUniforms();
   2533 
   2534     void* vertices = vertexBuffer.getBuffer();
   2535     bool force = mCaches.unbindMeshBuffer();
   2536     mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
   2537     mCaches.resetTexCoordsVertexPointer();
   2538     mCaches.unbindIndicesBuffer();
   2539 
   2540     int alphaSlot = -1;
   2541     if (isAA) {
   2542         void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
   2543         alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
   2544 
   2545         // TODO: avoid enable/disable in back to back uses of the alpha attribute
   2546         glEnableVertexAttribArray(alphaSlot);
   2547         glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
   2548     }
   2549 
   2550     glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
   2551 
   2552     if (isAA) {
   2553         glDisableVertexAttribArray(alphaSlot);
   2554     }
   2555 
   2556     return DrawGlInfo::kStatusDrew;
   2557 }
   2558 
   2559 /**
   2560  * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
   2561  * that of AA lines in the drawLines() function.  We expand the convex path by a half pixel in
   2562  * screen space in all directions. However, instead of using a fragment shader to compute the
   2563  * translucency of the color from its position, we simply use a varying parameter to define how far
   2564  * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
   2565  *
   2566  * Doesn't yet support joins, caps, or path effects.
   2567  */
   2568 status_t OpenGLRenderer::drawConvexPath(const SkPath& path, SkPaint* paint) {
   2569     VertexBuffer vertexBuffer;
   2570     // TODO: try clipping large paths to viewport
   2571     PathTessellator::tessellatePath(path, paint, mSnapshot->transform, vertexBuffer);
   2572 
   2573     if (hasLayer()) {
   2574         SkRect bounds = path.getBounds();
   2575         PathTessellator::expandBoundsForStroke(bounds, paint, false);
   2576         dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform());
   2577     }
   2578 
   2579     return drawVertexBuffer(vertexBuffer, paint);
   2580 }
   2581 
   2582 /**
   2583  * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
   2584  * and additional geometry for defining an alpha slope perimeter.
   2585  *
   2586  * Using GL_LINES can be difficult because the rasterization rules for those lines produces some
   2587  * unexpected results, and may vary between hardware devices. Previously we used a varying-base
   2588  * in-shader alpha region, but found it to be taxing on some GPUs.
   2589  *
   2590  * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
   2591  * memory transfer by removing need for degenerate vertices.
   2592  */
   2593 status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
   2594     if (mSnapshot->isIgnored() || count < 4) return DrawGlInfo::kStatusDone;
   2595 
   2596     count &= ~0x3; // round down to nearest four
   2597 
   2598     VertexBuffer buffer;
   2599     SkRect bounds;
   2600     PathTessellator::tessellateLines(points, count, paint, mSnapshot->transform, bounds, buffer);
   2601 
   2602     if (quickReject(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom)) {
   2603         return DrawGlInfo::kStatusDone;
   2604     }
   2605 
   2606     dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform());
   2607 
   2608     bool useOffset = !paint->isAntiAlias();
   2609     return drawVertexBuffer(buffer, paint, useOffset);
   2610 }
   2611 
   2612 status_t OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) {
   2613     if (mSnapshot->isIgnored() || count < 2) return DrawGlInfo::kStatusDone;
   2614 
   2615     count &= ~0x1; // round down to nearest two
   2616 
   2617     VertexBuffer buffer;
   2618     SkRect bounds;
   2619     PathTessellator::tessellatePoints(points, count, paint, mSnapshot->transform, bounds, buffer);
   2620 
   2621     if (quickReject(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom)) {
   2622         return DrawGlInfo::kStatusDone;
   2623     }
   2624 
   2625     dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform());
   2626 
   2627     bool useOffset = !paint->isAntiAlias();
   2628     return drawVertexBuffer(buffer, paint, useOffset);
   2629 }
   2630 
   2631 status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
   2632     // No need to check against the clip, we fill the clip region
   2633     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
   2634 
   2635     Rect& clip(*mSnapshot->clipRect);
   2636     clip.snapToPixelBoundaries();
   2637 
   2638     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
   2639 
   2640     return DrawGlInfo::kStatusDrew;
   2641 }
   2642 
   2643 status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
   2644         SkPaint* paint) {
   2645     if (!texture) return DrawGlInfo::kStatusDone;
   2646     const AutoTexture autoCleanup(texture);
   2647 
   2648     const float x = left + texture->left - texture->offset;
   2649     const float y = top + texture->top - texture->offset;
   2650 
   2651     drawPathTexture(texture, x, y, paint);
   2652 
   2653     return DrawGlInfo::kStatusDrew;
   2654 }
   2655 
   2656 status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
   2657         float rx, float ry, SkPaint* p) {
   2658     if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
   2659             (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
   2660         return DrawGlInfo::kStatusDone;
   2661     }
   2662 
   2663     if (p->getPathEffect() != 0) {
   2664         mCaches.activeTexture(0);
   2665         const PathTexture* texture = mCaches.pathCache.getRoundRect(
   2666                 right - left, bottom - top, rx, ry, p);
   2667         return drawShape(left, top, texture, p);
   2668     }
   2669 
   2670     SkPath path;
   2671     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
   2672     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
   2673         float outset = p->getStrokeWidth() / 2;
   2674         rect.outset(outset, outset);
   2675         rx += outset;
   2676         ry += outset;
   2677     }
   2678     path.addRoundRect(rect, rx, ry);
   2679     return drawConvexPath(path, p);
   2680 }
   2681 
   2682 status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* p) {
   2683     if (mSnapshot->isIgnored() || quickRejectPreStroke(x - radius, y - radius,
   2684             x + radius, y + radius, p) ||
   2685             (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
   2686         return DrawGlInfo::kStatusDone;
   2687     }
   2688     if (p->getPathEffect() != 0) {
   2689         mCaches.activeTexture(0);
   2690         const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
   2691         return drawShape(x - radius, y - radius, texture, p);
   2692     }
   2693 
   2694     SkPath path;
   2695     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
   2696         path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
   2697     } else {
   2698         path.addCircle(x, y, radius);
   2699     }
   2700     return drawConvexPath(path, p);
   2701 }
   2702 
   2703 status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
   2704         SkPaint* p) {
   2705     if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
   2706             (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
   2707         return DrawGlInfo::kStatusDone;
   2708     }
   2709 
   2710     if (p->getPathEffect() != 0) {
   2711         mCaches.activeTexture(0);
   2712         const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
   2713         return drawShape(left, top, texture, p);
   2714     }
   2715 
   2716     SkPath path;
   2717     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
   2718     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
   2719         rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
   2720     }
   2721     path.addOval(rect);
   2722     return drawConvexPath(path, p);
   2723 }
   2724 
   2725 status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
   2726         float startAngle, float sweepAngle, bool useCenter, SkPaint* p) {
   2727     if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
   2728             (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
   2729         return DrawGlInfo::kStatusDone;
   2730     }
   2731 
   2732     if (fabs(sweepAngle) >= 360.0f) {
   2733         return drawOval(left, top, right, bottom, p);
   2734     }
   2735 
   2736     // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
   2737     if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) {
   2738         mCaches.activeTexture(0);
   2739         const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
   2740                 startAngle, sweepAngle, useCenter, p);
   2741         return drawShape(left, top, texture, p);
   2742     }
   2743 
   2744     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
   2745     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
   2746         rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
   2747     }
   2748 
   2749     SkPath path;
   2750     if (useCenter) {
   2751         path.moveTo(rect.centerX(), rect.centerY());
   2752     }
   2753     path.arcTo(rect, startAngle, sweepAngle, !useCenter);
   2754     if (useCenter) {
   2755         path.close();
   2756     }
   2757     return drawConvexPath(path, p);
   2758 }
   2759 
   2760 // See SkPaintDefaults.h
   2761 #define SkPaintDefaults_MiterLimit SkIntToScalar(4)
   2762 
   2763 status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
   2764     if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
   2765             (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
   2766         return DrawGlInfo::kStatusDone;
   2767     }
   2768 
   2769     if (p->getStyle() != SkPaint::kFill_Style) {
   2770         // only fill style is supported by drawConvexPath, since others have to handle joins
   2771         if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join ||
   2772                 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
   2773             mCaches.activeTexture(0);
   2774             const PathTexture* texture =
   2775                     mCaches.pathCache.getRect(right - left, bottom - top, p);
   2776             return drawShape(left, top, texture, p);
   2777         }
   2778 
   2779         SkPath path;
   2780         SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
   2781         if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
   2782             rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
   2783         }
   2784         path.addRect(rect);
   2785         return drawConvexPath(path, p);
   2786     }
   2787 
   2788     if (p->isAntiAlias() && !currentTransform().isSimple()) {
   2789         SkPath path;
   2790         path.addRect(left, top, right, bottom);
   2791         return drawConvexPath(path, p);
   2792     } else {
   2793         drawColorRect(left, top, right, bottom, p->getColor(), getXfermode(p->getXfermode()));
   2794         return DrawGlInfo::kStatusDrew;
   2795     }
   2796 }
   2797 
   2798 void OpenGLRenderer::drawTextShadow(SkPaint* paint, const char* text, int bytesCount, int count,
   2799         const float* positions, FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode,
   2800         float x, float y) {
   2801     mCaches.activeTexture(0);
   2802 
   2803     // NOTE: The drop shadow will not perform gamma correction
   2804     //       if shader-based correction is enabled
   2805     mCaches.dropShadowCache.setFontRenderer(fontRenderer);
   2806     const ShadowTexture* shadow = mCaches.dropShadowCache.get(
   2807             paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
   2808     // If the drop shadow exceeds the max texture size or couldn't be
   2809     // allocated, skip drawing
   2810     if (!shadow) return;
   2811     const AutoTexture autoCleanup(shadow);
   2812 
   2813     const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
   2814     const float sy = y - shadow->top + mDrawModifiers.mShadowDy;
   2815 
   2816     const int shadowAlpha = ((mDrawModifiers.mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
   2817     int shadowColor = mDrawModifiers.mShadowColor;
   2818     if (mDrawModifiers.mShader) {
   2819         shadowColor = 0xffffffff;
   2820     }
   2821 
   2822     setupDraw();
   2823     setupDrawWithTexture(true);
   2824     setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
   2825     setupDrawColorFilter();
   2826     setupDrawShader();
   2827     setupDrawBlending(true, mode);
   2828     setupDrawProgram();
   2829     setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height);
   2830     setupDrawTexture(shadow->id);
   2831     setupDrawPureColorUniforms();
   2832     setupDrawColorFilterUniforms();
   2833     setupDrawShaderUniforms();
   2834     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
   2835 
   2836     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
   2837 }
   2838 
   2839 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
   2840     float alpha = (mDrawModifiers.mHasShadow ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
   2841     return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
   2842 }
   2843 
   2844 status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
   2845         const float* positions, SkPaint* paint) {
   2846     if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) {
   2847         return DrawGlInfo::kStatusDone;
   2848     }
   2849 
   2850     // NOTE: Skia does not support perspective transform on drawPosText yet
   2851     if (!currentTransform().isSimple()) {
   2852         return DrawGlInfo::kStatusDone;
   2853     }
   2854 
   2855     mCaches.enableScissor();
   2856 
   2857     float x = 0.0f;
   2858     float y = 0.0f;
   2859     const bool pureTranslate = currentTransform().isPureTranslate();
   2860     if (pureTranslate) {
   2861         x = (int) floorf(x + currentTransform().getTranslateX() + 0.5f);
   2862         y = (int) floorf(y + currentTransform().getTranslateY() + 0.5f);
   2863     }
   2864 
   2865     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
   2866     fontRenderer.setFont(paint, mat4::identity());
   2867 
   2868     int alpha;
   2869     SkXfermode::Mode mode;
   2870     getAlphaAndMode(paint, &alpha, &mode);
   2871 
   2872     if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
   2873         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
   2874                 alpha, mode, 0.0f, 0.0f);
   2875     }
   2876 
   2877     // Pick the appropriate texture filtering
   2878     bool linearFilter = currentTransform().changesBounds();
   2879     if (pureTranslate && !linearFilter) {
   2880         linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
   2881     }
   2882     fontRenderer.setTextureFiltering(linearFilter);
   2883 
   2884     const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
   2885     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
   2886 
   2887     const bool hasActiveLayer = hasLayer();
   2888 
   2889     TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
   2890     if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
   2891             positions, hasActiveLayer ? &bounds : NULL, &functor)) {
   2892         if (hasActiveLayer) {
   2893             if (!pureTranslate) {
   2894                 currentTransform().mapRect(bounds);
   2895             }
   2896             dirtyLayerUnchecked(bounds, getRegion());
   2897         }
   2898     }
   2899 
   2900     return DrawGlInfo::kStatusDrew;
   2901 }
   2902 
   2903 mat4 OpenGLRenderer::findBestFontTransform(const mat4& transform) const {
   2904     mat4 fontTransform;
   2905     if (CC_LIKELY(transform.isPureTranslate())) {
   2906         fontTransform = mat4::identity();
   2907     } else {
   2908         if (CC_UNLIKELY(transform.isPerspective())) {
   2909             fontTransform = mat4::identity();
   2910         } else {
   2911             float sx, sy;
   2912             currentTransform().decomposeScale(sx, sy);
   2913             fontTransform.loadScale(sx, sy, 1.0f);
   2914         }
   2915     }
   2916     return fontTransform;
   2917 }
   2918 
   2919 status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
   2920         const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds,
   2921         DrawOpMode drawOpMode) {
   2922 
   2923     if (drawOpMode == kDrawOpMode_Immediate) {
   2924         // The checks for corner-case ignorable text and quick rejection is only done for immediate
   2925         // drawing as ops from DeferredDisplayList are already filtered for these
   2926         if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint) ||
   2927                 quickReject(bounds)) {
   2928             return DrawGlInfo::kStatusDone;
   2929         }
   2930     }
   2931 
   2932     const float oldX = x;
   2933     const float oldY = y;
   2934 
   2935     const mat4& transform = currentTransform();
   2936     const bool pureTranslate = transform.isPureTranslate();
   2937 
   2938     if (CC_LIKELY(pureTranslate)) {
   2939         x = (int) floorf(x + transform.getTranslateX() + 0.5f);
   2940         y = (int) floorf(y + transform.getTranslateY() + 0.5f);
   2941     }
   2942 
   2943     int alpha;
   2944     SkXfermode::Mode mode;
   2945     getAlphaAndMode(paint, &alpha, &mode);
   2946 
   2947     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
   2948 
   2949     if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
   2950         fontRenderer.setFont(paint, mat4::identity());
   2951         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
   2952                 alpha, mode, oldX, oldY);
   2953     }
   2954 
   2955     const bool hasActiveLayer = hasLayer();
   2956 
   2957     // We only pass a partial transform to the font renderer. That partial
   2958     // matrix defines how glyphs are rasterized. Typically we want glyphs
   2959     // to be rasterized at their final size on screen, which means the partial
   2960     // matrix needs to take the scale factor into account.
   2961     // When a partial matrix is used to transform glyphs during rasterization,
   2962     // the mesh is generated with the inverse transform (in the case of scale,
   2963     // the mesh is generated at 1.0 / scale for instance.) This allows us to
   2964     // apply the full transform matrix at draw time in the vertex shader.
   2965     // Applying the full matrix in the shader is the easiest way to handle
   2966     // rotation and perspective and allows us to always generated quads in the
   2967     // font renderer which greatly simplifies the code, clipping in particular.
   2968     mat4 fontTransform = findBestFontTransform(transform);
   2969     fontRenderer.setFont(paint, fontTransform);
   2970 
   2971     // Pick the appropriate texture filtering
   2972     bool linearFilter = !pureTranslate || fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
   2973     fontRenderer.setTextureFiltering(linearFilter);
   2974 
   2975     // TODO: Implement better clipping for scaled/rotated text
   2976     const Rect* clip = !pureTranslate ? NULL : mSnapshot->clipRect;
   2977     Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
   2978 
   2979     bool status;
   2980     TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
   2981 
   2982     // don't call issuedrawcommand, do it at end of batch
   2983     bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
   2984     if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
   2985         SkPaint paintCopy(*paint);
   2986         paintCopy.setTextAlign(SkPaint::kLeft_Align);
   2987         status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
   2988                 positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
   2989     } else {
   2990         status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
   2991                 positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
   2992     }
   2993 
   2994     if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
   2995         if (!pureTranslate) {
   2996             transform.mapRect(layerBounds);
   2997         }
   2998         dirtyLayerUnchecked(layerBounds, getRegion());
   2999     }
   3000 
   3001     drawTextDecorations(text, bytesCount, totalAdvance, oldX, oldY, paint);
   3002 
   3003     return DrawGlInfo::kStatusDrew;
   3004 }
   3005 
   3006 status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
   3007         float hOffset, float vOffset, SkPaint* paint) {
   3008     if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) {
   3009         return DrawGlInfo::kStatusDone;
   3010     }
   3011 
   3012     // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
   3013     mCaches.enableScissor();
   3014 
   3015     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
   3016     fontRenderer.setFont(paint, mat4::identity());
   3017     fontRenderer.setTextureFiltering(true);
   3018 
   3019     int alpha;
   3020     SkXfermode::Mode mode;
   3021     getAlphaAndMode(paint, &alpha, &mode);
   3022     TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
   3023 
   3024     const Rect* clip = &mSnapshot->getLocalClip();
   3025     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
   3026 
   3027     const bool hasActiveLayer = hasLayer();
   3028 
   3029     if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
   3030             hOffset, vOffset, hasActiveLayer ? &bounds : NULL, &functor)) {
   3031         if (hasActiveLayer) {
   3032             currentTransform().mapRect(bounds);
   3033             dirtyLayerUnchecked(bounds, getRegion());
   3034         }
   3035     }
   3036 
   3037     return DrawGlInfo::kStatusDrew;
   3038 }
   3039 
   3040 status_t OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
   3041     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
   3042 
   3043     mCaches.activeTexture(0);
   3044 
   3045     const PathTexture* texture = mCaches.pathCache.get(path, paint);
   3046     if (!texture) return DrawGlInfo::kStatusDone;
   3047     const AutoTexture autoCleanup(texture);
   3048 
   3049     const float x = texture->left - texture->offset;
   3050     const float y = texture->top - texture->offset;
   3051 
   3052     drawPathTexture(texture, x, y, paint);
   3053 
   3054     return DrawGlInfo::kStatusDrew;
   3055 }
   3056 
   3057 status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
   3058     if (!layer) {
   3059         return DrawGlInfo::kStatusDone;
   3060     }
   3061 
   3062     mat4* transform = NULL;
   3063     if (layer->isTextureLayer()) {
   3064         transform = &layer->getTransform();
   3065         if (!transform->isIdentity()) {
   3066             save(0);
   3067             currentTransform().multiply(*transform);
   3068         }
   3069     }
   3070 
   3071     bool clipRequired = false;
   3072     const bool rejected = quickRejectNoScissor(x, y,
   3073             x + layer->layer.getWidth(), y + layer->layer.getHeight(), false, &clipRequired);
   3074 
   3075     if (rejected) {
   3076         if (transform && !transform->isIdentity()) {
   3077             restore();
   3078         }
   3079         return DrawGlInfo::kStatusDone;
   3080     }
   3081 
   3082     updateLayer(layer, true);
   3083 
   3084     mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
   3085     mCaches.activeTexture(0);
   3086 
   3087     if (CC_LIKELY(!layer->region.isEmpty())) {
   3088         SkiaColorFilter* oldFilter = mDrawModifiers.mColorFilter;
   3089         mDrawModifiers.mColorFilter = layer->getColorFilter();
   3090 
   3091         if (layer->region.isRect()) {
   3092             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
   3093                     composeLayerRect(layer, layer->regionRect));
   3094         } else if (layer->mesh) {
   3095             const float a = getLayerAlpha(layer);
   3096             setupDraw();
   3097             setupDrawWithTexture();
   3098             setupDrawColor(a, a, a, a);
   3099             setupDrawColorFilter();
   3100             setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false);
   3101             setupDrawProgram();
   3102             setupDrawPureColorUniforms();
   3103             setupDrawColorFilterUniforms();
   3104             setupDrawTexture(layer->getTexture());
   3105             if (CC_LIKELY(currentTransform().isPureTranslate())) {
   3106                 int tx = (int) floorf(x + currentTransform().getTranslateX() + 0.5f);
   3107                 int ty = (int) floorf(y + currentTransform().getTranslateY() + 0.5f);
   3108 
   3109                 layer->setFilter(GL_NEAREST);
   3110                 setupDrawModelViewTranslate(tx, ty,
   3111                         tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
   3112             } else {
   3113                 layer->setFilter(GL_LINEAR);
   3114                 setupDrawModelViewTranslate(x, y,
   3115                         x + layer->layer.getWidth(), y + layer->layer.getHeight());
   3116             }
   3117 
   3118             TextureVertex* mesh = &layer->mesh[0];
   3119             GLsizei elementsCount = layer->meshElementCount;
   3120 
   3121             while (elementsCount > 0) {
   3122                 GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
   3123 
   3124                 setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]);
   3125                 DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
   3126                         glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL));
   3127 
   3128                 elementsCount -= drawCount;
   3129                 // Though there are 4 vertices in a quad, we use 6 indices per
   3130                 // quad to draw with GL_TRIANGLES
   3131                 mesh += (drawCount / 6) * 4;
   3132             }
   3133 
   3134 #if DEBUG_LAYERS_AS_REGIONS
   3135             drawRegionRects(layer->region);
   3136 #endif
   3137         }
   3138 
   3139         mDrawModifiers.mColorFilter = oldFilter;
   3140 
   3141         if (layer->debugDrawUpdate) {
   3142             layer->debugDrawUpdate = false;
   3143             drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
   3144                     0x7f00ff00, SkXfermode::kSrcOver_Mode);
   3145         }
   3146     }
   3147     layer->hasDrawnSinceUpdate = true;
   3148 
   3149     if (transform && !transform->isIdentity()) {
   3150         restore();
   3151     }
   3152 
   3153     return DrawGlInfo::kStatusDrew;
   3154 }
   3155 
   3156 ///////////////////////////////////////////////////////////////////////////////
   3157 // Shaders
   3158 ///////////////////////////////////////////////////////////////////////////////
   3159 
   3160 void OpenGLRenderer::resetShader() {
   3161     mDrawModifiers.mShader = NULL;
   3162 }
   3163 
   3164 void OpenGLRenderer::setupShader(SkiaShader* shader) {
   3165     mDrawModifiers.mShader = shader;
   3166     if (mDrawModifiers.mShader) {
   3167         mDrawModifiers.mShader->setCaches(mCaches);
   3168     }
   3169 }
   3170 
   3171 ///////////////////////////////////////////////////////////////////////////////
   3172 // Color filters
   3173 ///////////////////////////////////////////////////////////////////////////////
   3174 
   3175 void OpenGLRenderer::resetColorFilter() {
   3176     mDrawModifiers.mColorFilter = NULL;
   3177 }
   3178 
   3179 void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
   3180     mDrawModifiers.mColorFilter = filter;
   3181 }
   3182 
   3183 ///////////////////////////////////////////////////////////////////////////////
   3184 // Drop shadow
   3185 ///////////////////////////////////////////////////////////////////////////////
   3186 
   3187 void OpenGLRenderer::resetShadow() {
   3188     mDrawModifiers.mHasShadow = false;
   3189 }
   3190 
   3191 void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
   3192     mDrawModifiers.mHasShadow = true;
   3193     mDrawModifiers.mShadowRadius = radius;
   3194     mDrawModifiers.mShadowDx = dx;
   3195     mDrawModifiers.mShadowDy = dy;
   3196     mDrawModifiers.mShadowColor = color;
   3197 }
   3198 
   3199 ///////////////////////////////////////////////////////////////////////////////
   3200 // Draw filters
   3201 ///////////////////////////////////////////////////////////////////////////////
   3202 
   3203 void OpenGLRenderer::resetPaintFilter() {
   3204     // when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier
   3205     // comparison, see MergingDrawBatch::canMergeWith
   3206     mDrawModifiers.mHasDrawFilter = false;
   3207     mDrawModifiers.mPaintFilterClearBits = 0;
   3208     mDrawModifiers.mPaintFilterSetBits = 0;
   3209 }
   3210 
   3211 void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
   3212     mDrawModifiers.mHasDrawFilter = true;
   3213     mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
   3214     mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
   3215 }
   3216 
   3217 SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) {
   3218     if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) {
   3219         return paint;
   3220     }
   3221 
   3222     uint32_t flags = paint->getFlags();
   3223 
   3224     mFilteredPaint = *paint;
   3225     mFilteredPaint.setFlags((flags & ~mDrawModifiers.mPaintFilterClearBits) |
   3226             mDrawModifiers.mPaintFilterSetBits);
   3227 
   3228     return &mFilteredPaint;
   3229 }
   3230 
   3231 ///////////////////////////////////////////////////////////////////////////////
   3232 // Drawing implementation
   3233 ///////////////////////////////////////////////////////////////////////////////
   3234 
   3235 Texture* OpenGLRenderer::getTexture(SkBitmap* bitmap) {
   3236     Texture* texture = mCaches.assetAtlas.getEntryTexture(bitmap);
   3237     if (!texture) {
   3238         return mCaches.textureCache.get(bitmap);
   3239     }
   3240     return texture;
   3241 }
   3242 
   3243 void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
   3244         float x, float y, SkPaint* paint) {
   3245     if (quickReject(x, y, x + texture->width, y + texture->height)) {
   3246         return;
   3247     }
   3248 
   3249     int alpha;
   3250     SkXfermode::Mode mode;
   3251     getAlphaAndMode(paint, &alpha, &mode);
   3252 
   3253     setupDraw();
   3254     setupDrawWithTexture(true);
   3255     setupDrawAlpha8Color(paint->getColor(), alpha);
   3256     setupDrawColorFilter();
   3257     setupDrawShader();
   3258     setupDrawBlending(true, mode);
   3259     setupDrawProgram();
   3260     setupDrawModelView(x, y, x + texture->width, y + texture->height);
   3261     setupDrawTexture(texture->id);
   3262     setupDrawPureColorUniforms();
   3263     setupDrawColorFilterUniforms();
   3264     setupDrawShaderUniforms();
   3265     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
   3266 
   3267     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
   3268 }
   3269 
   3270 // Same values used by Skia
   3271 #define kStdStrikeThru_Offset   (-6.0f / 21.0f)
   3272 #define kStdUnderline_Offset    (1.0f / 9.0f)
   3273 #define kStdUnderline_Thickness (1.0f / 18.0f)
   3274 
   3275 void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float underlineWidth,
   3276         float x, float y, SkPaint* paint) {
   3277     // Handle underline and strike-through
   3278     uint32_t flags = paint->getFlags();
   3279     if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
   3280         SkPaint paintCopy(*paint);
   3281 
   3282         if (CC_LIKELY(underlineWidth > 0.0f)) {
   3283             const float textSize = paintCopy.getTextSize();
   3284             const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
   3285 
   3286             const float left = x;
   3287             float top = 0.0f;
   3288 
   3289             int linesCount = 0;
   3290             if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
   3291             if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
   3292 
   3293             const int pointsCount = 4 * linesCount;
   3294             float points[pointsCount];
   3295             int currentPoint = 0;
   3296 
   3297             if (flags & SkPaint::kUnderlineText_Flag) {
   3298                 top = y + textSize * kStdUnderline_Offset;
   3299                 points[currentPoint++] = left;
   3300                 points[currentPoint++] = top;
   3301                 points[currentPoint++] = left + underlineWidth;
   3302                 points[currentPoint++] = top;
   3303             }
   3304 
   3305             if (flags & SkPaint::kStrikeThruText_Flag) {
   3306                 top = y + textSize * kStdStrikeThru_Offset;
   3307                 points[currentPoint++] = left;
   3308                 points[currentPoint++] = top;
   3309                 points[currentPoint++] = left + underlineWidth;
   3310                 points[currentPoint++] = top;
   3311             }
   3312 
   3313             paintCopy.setStrokeWidth(strokeWidth);
   3314 
   3315             drawLines(&points[0], pointsCount, &paintCopy);
   3316         }
   3317     }
   3318 }
   3319 
   3320 status_t OpenGLRenderer::drawRects(const float* rects, int count, SkPaint* paint) {
   3321     if (mSnapshot->isIgnored()) {
   3322         return DrawGlInfo::kStatusDone;
   3323     }
   3324 
   3325     int color = paint->getColor();
   3326     // If a shader is set, preserve only the alpha
   3327     if (mDrawModifiers.mShader) {
   3328         color |= 0x00ffffff;
   3329     }
   3330     SkXfermode::Mode mode = getXfermode(paint->getXfermode());
   3331 
   3332     return drawColorRects(rects, count, color, mode);
   3333 }
   3334 
   3335 status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color,
   3336         SkXfermode::Mode mode, bool ignoreTransform, bool dirty, bool clip) {
   3337     if (count == 0) {
   3338         return DrawGlInfo::kStatusDone;
   3339     }
   3340 
   3341     float left = FLT_MAX;
   3342     float top = FLT_MAX;
   3343     float right = FLT_MIN;
   3344     float bottom = FLT_MIN;
   3345 
   3346     Vertex mesh[count];
   3347     Vertex* vertex = mesh;
   3348 
   3349     for (int index = 0; index < count; index += 4) {
   3350         float l = rects[index + 0];
   3351         float t = rects[index + 1];
   3352         float r = rects[index + 2];
   3353         float b = rects[index + 3];
   3354 
   3355         Vertex::set(vertex++, l, t);
   3356         Vertex::set(vertex++, r, t);
   3357         Vertex::set(vertex++, l, b);
   3358         Vertex::set(vertex++, r, b);
   3359 
   3360         left = fminf(left, l);
   3361         top = fminf(top, t);
   3362         right = fmaxf(right, r);
   3363         bottom = fmaxf(bottom, b);
   3364     }
   3365 
   3366     if (clip && quickReject(left, top, right, bottom)) {
   3367         return DrawGlInfo::kStatusDone;
   3368     }
   3369 
   3370     setupDraw();
   3371     setupDrawNoTexture();
   3372     setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
   3373     setupDrawShader();
   3374     setupDrawColorFilter();
   3375     setupDrawBlending(mode);
   3376     setupDrawProgram();
   3377     setupDrawDirtyRegionsDisabled();
   3378     setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, ignoreTransform, true);
   3379     setupDrawColorUniforms();
   3380     setupDrawShaderUniforms();
   3381     setupDrawColorFilterUniforms();
   3382 
   3383     if (dirty && hasLayer()) {
   3384         dirtyLayer(left, top, right, bottom, currentTransform());
   3385     }
   3386 
   3387     drawIndexedQuads(&mesh[0], count / 4);
   3388 
   3389     return DrawGlInfo::kStatusDrew;
   3390 }
   3391 
   3392 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
   3393         int color, SkXfermode::Mode mode, bool ignoreTransform) {
   3394     // If a shader is set, preserve only the alpha
   3395     if (mDrawModifiers.mShader) {
   3396         color |= 0x00ffffff;
   3397     }
   3398 
   3399     setupDraw();
   3400     setupDrawNoTexture();
   3401     setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
   3402     setupDrawShader();
   3403     setupDrawColorFilter();
   3404     setupDrawBlending(mode);
   3405     setupDrawProgram();
   3406     setupDrawModelView(left, top, right, bottom, ignoreTransform);
   3407     setupDrawColorUniforms();
   3408     setupDrawShaderUniforms(ignoreTransform);
   3409     setupDrawColorFilterUniforms();
   3410     setupDrawSimpleMesh();
   3411 
   3412     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
   3413 }
   3414 
   3415 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
   3416         Texture* texture, SkPaint* paint) {
   3417     int alpha;
   3418     SkXfermode::Mode mode;
   3419     getAlphaAndMode(paint, &alpha, &mode);
   3420 
   3421     texture->setWrap(GL_CLAMP_TO_EDGE, true);
   3422 
   3423     GLvoid* vertices = (GLvoid*) NULL;
   3424     GLvoid* texCoords = (GLvoid*) gMeshTextureOffset;
   3425 
   3426     if (texture->uvMapper) {
   3427         vertices = &mMeshVertices[0].position[0];
   3428         texCoords = &mMeshVertices[0].texture[0];
   3429 
   3430         Rect uvs(0.0f, 0.0f, 1.0f, 1.0f);
   3431         texture->uvMapper->map(uvs);
   3432 
   3433         resetDrawTextureTexCoords(uvs.left, uvs.top, uvs.right, uvs.bottom);
   3434     }
   3435 
   3436     if (CC_LIKELY(currentTransform().isPureTranslate())) {
   3437         const float x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f);
   3438         const float y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f);
   3439 
   3440         texture->setFilter(GL_NEAREST, true);
   3441         drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
   3442                 alpha / 255.0f, mode, texture->blend, vertices, texCoords,
   3443                 GL_TRIANGLE_STRIP, gMeshCount, false, true);
   3444     } else {
   3445         texture->setFilter(FILTER(paint), true);
   3446         drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
   3447                 texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
   3448     }
   3449 
   3450     if (texture->uvMapper) {
   3451         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
   3452     }
   3453 }
   3454 
   3455 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
   3456         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
   3457     drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
   3458             (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount);
   3459 }
   3460 
   3461 void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
   3462         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
   3463         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
   3464         bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) {
   3465 
   3466     setupDraw();
   3467     setupDrawWithTexture();
   3468     setupDrawColor(alpha, alpha, alpha, alpha);
   3469     setupDrawColorFilter();
   3470     setupDrawBlending(blend, mode, swapSrcDst);
   3471     setupDrawProgram();
   3472     if (!dirty) setupDrawDirtyRegionsDisabled();
   3473     if (!ignoreScale) {
   3474         setupDrawModelView(left, top, right, bottom, ignoreTransform);
   3475     } else {
   3476         setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
   3477     }
   3478     setupDrawTexture(texture);
   3479     setupDrawPureColorUniforms();
   3480     setupDrawColorFilterUniforms();
   3481     setupDrawMesh(vertices, texCoords, vbo);
   3482 
   3483     glDrawArrays(drawMode, 0, elementsCount);
   3484 }
   3485 
   3486 void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
   3487         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
   3488         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
   3489         bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) {
   3490 
   3491     setupDraw();
   3492     setupDrawWithTexture();
   3493     setupDrawColor(alpha, alpha, alpha, alpha);
   3494     setupDrawColorFilter();
   3495     setupDrawBlending(blend, mode, swapSrcDst);
   3496     setupDrawProgram();
   3497     if (!dirty) setupDrawDirtyRegionsDisabled();
   3498     if (!ignoreScale) {
   3499         setupDrawModelView(left, top, right, bottom, ignoreTransform);
   3500     } else {
   3501         setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
   3502     }
   3503     setupDrawTexture(texture);
   3504     setupDrawPureColorUniforms();
   3505     setupDrawColorFilterUniforms();
   3506     setupDrawMeshIndices(vertices, texCoords, vbo);
   3507 
   3508     glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL);
   3509 }
   3510 
   3511 void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
   3512         GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
   3513         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
   3514         bool ignoreTransform, bool ignoreScale, bool dirty) {
   3515 
   3516     setupDraw();
   3517     setupDrawWithTexture(true);
   3518     if (hasColor) {
   3519         setupDrawAlpha8Color(color, alpha);
   3520     }
   3521     setupDrawColorFilter();
   3522     setupDrawShader();
   3523     setupDrawBlending(true, mode);
   3524     setupDrawProgram();
   3525     if (!dirty) setupDrawDirtyRegionsDisabled();
   3526     if (!ignoreScale) {
   3527         setupDrawModelView(left, top, right, bottom, ignoreTransform);
   3528     } else {
   3529         setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
   3530     }
   3531     setupDrawTexture(texture);
   3532     setupDrawPureColorUniforms();
   3533     setupDrawColorFilterUniforms();
   3534     setupDrawShaderUniforms();
   3535     setupDrawMesh(vertices, texCoords);
   3536 
   3537     glDrawArrays(drawMode, 0, elementsCount);
   3538 }
   3539 
   3540 void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
   3541         ProgramDescription& description, bool swapSrcDst) {
   3542     if (mCountOverdraw) {
   3543         if (!mCaches.blend) glEnable(GL_BLEND);
   3544         if (mCaches.lastSrcMode != GL_ONE || mCaches.lastDstMode != GL_ONE) {
   3545             glBlendFunc(GL_ONE, GL_ONE);
   3546         }
   3547 
   3548         mCaches.blend = true;
   3549         mCaches.lastSrcMode = GL_ONE;
   3550         mCaches.lastDstMode = GL_ONE;
   3551 
   3552         return;
   3553     }
   3554 
   3555     blend = blend || mode != SkXfermode::kSrcOver_Mode;
   3556 
   3557     if (blend) {
   3558         // These blend modes are not supported by OpenGL directly and have
   3559         // to be implemented using shaders. Since the shader will perform
   3560         // the blending, turn blending off here
   3561         // If the blend mode cannot be implemented using shaders, fall
   3562         // back to the default SrcOver blend mode instead
   3563         if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
   3564             if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) {
   3565                 description.framebufferMode = mode;
   3566                 description.swapSrcDst = swapSrcDst;
   3567 
   3568                 if (mCaches.blend) {
   3569                     glDisable(GL_BLEND);
   3570                     mCaches.blend = false;
   3571                 }
   3572 
   3573                 return;
   3574             } else {
   3575                 mode = SkXfermode::kSrcOver_Mode;
   3576             }
   3577         }
   3578 
   3579         if (!mCaches.blend) {
   3580             glEnable(GL_BLEND);
   3581         }
   3582 
   3583         GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
   3584         GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
   3585 
   3586         if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
   3587             glBlendFunc(sourceMode, destMode);
   3588             mCaches.lastSrcMode = sourceMode;
   3589             mCaches.lastDstMode = destMode;
   3590         }
   3591     } else if (mCaches.blend) {
   3592         glDisable(GL_BLEND);
   3593     }
   3594     mCaches.blend = blend;
   3595 }
   3596 
   3597 bool OpenGLRenderer::useProgram(Program* program) {
   3598     if (!program->isInUse()) {
   3599         if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
   3600         program->use();
   3601         mCaches.currentProgram = program;
   3602         return false;
   3603     }
   3604     return true;
   3605 }
   3606 
   3607 void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
   3608     TextureVertex* v = &mMeshVertices[0];
   3609     TextureVertex::setUV(v++, u1, v1);
   3610     TextureVertex::setUV(v++, u2, v1);
   3611     TextureVertex::setUV(v++, u1, v2);
   3612     TextureVertex::setUV(v++, u2, v2);
   3613 }
   3614 
   3615 void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const {
   3616     getAlphaAndModeDirect(paint, alpha,  mode);
   3617     if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
   3618         // if drawing a layer, ignore the paint's alpha
   3619         *alpha = mDrawModifiers.mOverrideLayerAlpha * 255;
   3620     }
   3621     *alpha *= mSnapshot->alpha;
   3622 }
   3623 
   3624 float OpenGLRenderer::getLayerAlpha(Layer* layer) const {
   3625     float alpha;
   3626     if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
   3627         alpha = mDrawModifiers.mOverrideLayerAlpha;
   3628     } else {
   3629         alpha = layer->getAlpha() / 255.0f;
   3630     }
   3631     return alpha * mSnapshot->alpha;
   3632 }
   3633 
   3634 }; // namespace uirenderer
   3635 }; // namespace android
   3636