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