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