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