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