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