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 #include <GpuMemoryTracker.h>
     18 #include "OpenGLRenderer.h"
     19 
     20 #include "DeferredDisplayList.h"
     21 #include "GammaFontRenderer.h"
     22 #include "Glop.h"
     23 #include "GlopBuilder.h"
     24 #include "Patch.h"
     25 #include "PathTessellator.h"
     26 #include "Properties.h"
     27 #include "RenderNode.h"
     28 #include "renderstate/MeshState.h"
     29 #include "renderstate/RenderState.h"
     30 #include "ShadowTessellator.h"
     31 #include "SkiaShader.h"
     32 #include "Vector.h"
     33 #include "VertexBuffer.h"
     34 #include "hwui/Canvas.h"
     35 #include "utils/GLUtils.h"
     36 #include "utils/PaintUtils.h"
     37 #include "utils/TraceUtils.h"
     38 
     39 #include <stdlib.h>
     40 #include <stdint.h>
     41 #include <sys/types.h>
     42 
     43 #include <SkColor.h>
     44 #include <SkPaintDefaults.h>
     45 #include <SkPathOps.h>
     46 #include <SkShader.h>
     47 #include <SkTypeface.h>
     48 
     49 #include <utils/Log.h>
     50 #include <utils/StopWatch.h>
     51 
     52 #include <private/hwui/DrawGlInfo.h>
     53 
     54 #include <ui/Rect.h>
     55 
     56 #if DEBUG_DETAILED_EVENTS
     57     #define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__)
     58 #else
     59     #define EVENT_LOGD(...)
     60 #endif
     61 
     62 namespace android {
     63 namespace uirenderer {
     64 
     65 ///////////////////////////////////////////////////////////////////////////////
     66 // Constructors/destructor
     67 ///////////////////////////////////////////////////////////////////////////////
     68 
     69 OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
     70         : mState(*this)
     71         , mCaches(Caches::getInstance())
     72         , mRenderState(renderState)
     73         , mFrameStarted(false)
     74         , mScissorOptimizationDisabled(false)
     75         , mDirty(false)
     76         , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN})
     77         , mLightRadius(FLT_MIN)
     78         , mAmbientShadowAlpha(0)
     79         , mSpotShadowAlpha(0) {
     80 }
     81 
     82 OpenGLRenderer::~OpenGLRenderer() {
     83     // The context has already been destroyed at this point, do not call
     84     // GL APIs. All GL state should be kept in Caches.h
     85 }
     86 
     87 void OpenGLRenderer::initProperties() {
     88     char property[PROPERTY_VALUE_MAX];
     89     if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) {
     90         mScissorOptimizationDisabled = !strcasecmp(property, "true");
     91         INIT_LOGD("  Scissor optimization %s",
     92                 mScissorOptimizationDisabled ? "disabled" : "enabled");
     93     } else {
     94         INIT_LOGD("  Scissor optimization enabled");
     95     }
     96 }
     97 
     98 void OpenGLRenderer::initLight(float lightRadius, uint8_t ambientShadowAlpha,
     99         uint8_t spotShadowAlpha) {
    100     mLightRadius = lightRadius;
    101     mAmbientShadowAlpha = ambientShadowAlpha;
    102     mSpotShadowAlpha = spotShadowAlpha;
    103 }
    104 
    105 void OpenGLRenderer::setLightCenter(const Vector3& lightCenter) {
    106     mLightCenter = lightCenter;
    107 }
    108 
    109 ///////////////////////////////////////////////////////////////////////////////
    110 // Setup
    111 ///////////////////////////////////////////////////////////////////////////////
    112 
    113 void OpenGLRenderer::onViewportInitialized() {
    114     glDisable(GL_DITHER);
    115     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    116 }
    117 
    118 void OpenGLRenderer::setupFrameState(int viewportWidth, int viewportHeight,
    119         float left, float top, float right, float bottom, bool opaque) {
    120     mCaches.clearGarbage();
    121     mState.initializeSaveStack(viewportWidth, viewportHeight,
    122             left, top, right, bottom, mLightCenter);
    123     mOpaque = opaque;
    124     mTilingClip.set(left, top, right, bottom);
    125 }
    126 
    127 void OpenGLRenderer::startFrame() {
    128     if (mFrameStarted) return;
    129     mFrameStarted = true;
    130 
    131     mState.setDirtyClip(true);
    132 
    133     discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
    134 
    135     mRenderState.setViewport(mState.getWidth(), mState.getHeight());
    136 
    137     debugOverdraw(true, true);
    138 
    139     clear(mTilingClip.left, mTilingClip.top,
    140             mTilingClip.right, mTilingClip.bottom, mOpaque);
    141 }
    142 
    143 void OpenGLRenderer::prepareDirty(int viewportWidth, int viewportHeight,
    144         float left, float top, float right, float bottom, bool opaque) {
    145 
    146     setupFrameState(viewportWidth, viewportHeight, left, top, right, bottom, opaque);
    147 
    148     // Layer renderers will start the frame immediately
    149     // The framebuffer renderer will first defer the display list
    150     // for each layer and wait until the first drawing command
    151     // to start the frame
    152     if (currentSnapshot()->fbo == 0) {
    153         mRenderState.blend().syncEnabled();
    154         updateLayers();
    155     } else {
    156         startFrame();
    157     }
    158 }
    159 
    160 void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
    161     // If we know that we are going to redraw the entire framebuffer,
    162     // perform a discard to let the driver know we don't need to preserve
    163     // the back buffer for this frame.
    164     if (mCaches.extensions().hasDiscardFramebuffer() &&
    165             left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) {
    166         const bool isFbo = getTargetFbo() == 0;
    167         const GLenum attachments[] = {
    168                 isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
    169                 isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT };
    170         glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
    171     }
    172 }
    173 
    174 void OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
    175     if (!opaque) {
    176         mRenderState.scissor().setEnabled(true);
    177         mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top);
    178         glClear(GL_COLOR_BUFFER_BIT);
    179         mDirty = true;
    180         return;
    181     }
    182 
    183     mRenderState.scissor().reset();
    184 }
    185 
    186 bool OpenGLRenderer::finish() {
    187     renderOverdraw();
    188     mTempPaths.clear();
    189 
    190     // When finish() is invoked on FBO 0 we've reached the end
    191     // of the current frame
    192     if (getTargetFbo() == 0) {
    193         mCaches.pathCache.trim();
    194         mCaches.tessellationCache.trim();
    195     }
    196 
    197     if (!suppressErrorChecks()) {
    198         GL_CHECKPOINT(MODERATE);
    199 
    200 #if DEBUG_MEMORY_USAGE
    201         mCaches.dumpMemoryUsage();
    202         GPUMemoryTracker::dump();
    203 #else
    204         if (Properties::debugLevel & kDebugMemory) {
    205             mCaches.dumpMemoryUsage();
    206         }
    207 #endif
    208     }
    209 
    210     mFrameStarted = false;
    211 
    212     return reportAndClearDirty();
    213 }
    214 
    215 void OpenGLRenderer::resumeAfterLayer() {
    216     mRenderState.setViewport(getViewportWidth(), getViewportHeight());
    217     mRenderState.bindFramebuffer(currentSnapshot()->fbo);
    218     debugOverdraw(true, false);
    219 
    220     mRenderState.scissor().reset();
    221     dirtyClip();
    222 }
    223 
    224 void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
    225     if (mState.currentlyIgnored()) return;
    226 
    227     Rect clip(mState.currentRenderTargetClip());
    228     clip.snapToPixelBoundaries();
    229 
    230     // Since we don't know what the functor will draw, let's dirty
    231     // the entire clip region
    232     if (hasLayer()) {
    233         dirtyLayerUnchecked(clip, getRegion());
    234     }
    235 
    236     DrawGlInfo info;
    237     info.clipLeft = clip.left;
    238     info.clipTop = clip.top;
    239     info.clipRight = clip.right;
    240     info.clipBottom = clip.bottom;
    241     info.isLayer = hasLayer();
    242     info.width = getViewportWidth();
    243     info.height = getViewportHeight();
    244     currentTransform()->copyTo(&info.transform[0]);
    245 
    246     bool prevDirtyClip = mState.getDirtyClip();
    247     // setup GL state for functor
    248     if (mState.getDirtyClip()) {
    249         setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
    250     }
    251     if (mRenderState.scissor().setEnabled(true) || prevDirtyClip) {
    252         setScissorFromClip();
    253     }
    254 
    255     mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info);
    256     // Scissor may have been modified, reset dirty clip
    257     dirtyClip();
    258 
    259     mDirty = true;
    260 }
    261 
    262 ///////////////////////////////////////////////////////////////////////////////
    263 // Debug
    264 ///////////////////////////////////////////////////////////////////////////////
    265 
    266 void OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const {
    267 #if DEBUG_DETAILED_EVENTS
    268     const int BUFFER_SIZE = 256;
    269     va_list ap;
    270     char buf[BUFFER_SIZE];
    271 
    272     va_start(ap, fmt);
    273     vsnprintf(buf, BUFFER_SIZE, fmt, ap);
    274     va_end(ap);
    275 
    276     eventMark(buf);
    277 #endif
    278 }
    279 
    280 
    281 void OpenGLRenderer::eventMark(const char* name) const {
    282     mCaches.eventMark(0, name);
    283 }
    284 
    285 void OpenGLRenderer::startMark(const char* name) const {
    286     mCaches.startMark(0, name);
    287 }
    288 
    289 void OpenGLRenderer::endMark() const {
    290     mCaches.endMark();
    291 }
    292 
    293 void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
    294     mRenderState.debugOverdraw(enable, clear);
    295 }
    296 
    297 void OpenGLRenderer::renderOverdraw() {
    298     if (Properties::debugOverdraw && getTargetFbo() == 0) {
    299         const Rect* clip = &mTilingClip;
    300 
    301         mRenderState.scissor().setEnabled(true);
    302         mRenderState.scissor().set(clip->left,
    303                 mState.firstSnapshot()->getViewportHeight() - clip->bottom,
    304                 clip->right - clip->left,
    305                 clip->bottom - clip->top);
    306 
    307         // 1x overdraw
    308         mRenderState.stencil().enableDebugTest(2);
    309         drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
    310 
    311         // 2x overdraw
    312         mRenderState.stencil().enableDebugTest(3);
    313         drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
    314 
    315         // 3x overdraw
    316         mRenderState.stencil().enableDebugTest(4);
    317         drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
    318 
    319         // 4x overdraw and higher
    320         mRenderState.stencil().enableDebugTest(4, true);
    321         drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
    322 
    323         mRenderState.stencil().disable();
    324     }
    325 }
    326 
    327 ///////////////////////////////////////////////////////////////////////////////
    328 // Layers
    329 ///////////////////////////////////////////////////////////////////////////////
    330 
    331 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
    332     if (layer->deferredUpdateScheduled && layer->renderer
    333             && layer->renderNode.get() && layer->renderNode->isRenderable()) {
    334 
    335         if (inFrame) {
    336             debugOverdraw(false, false);
    337         }
    338 
    339         if (CC_UNLIKELY(inFrame || Properties::drawDeferDisabled)) {
    340             layer->render(*this);
    341         } else {
    342             layer->defer(*this);
    343         }
    344 
    345         if (inFrame) {
    346             resumeAfterLayer();
    347         }
    348 
    349         layer->debugDrawUpdate = Properties::debugLayersUpdates;
    350         layer->hasDrawnSinceUpdate = false;
    351 
    352         return true;
    353     }
    354 
    355     return false;
    356 }
    357 
    358 void OpenGLRenderer::updateLayers() {
    359     // If draw deferring is enabled this method will simply defer
    360     // the display list of each individual layer. The layers remain
    361     // in the layer updates list which will be cleared by flushLayers().
    362     int count = mLayerUpdates.size();
    363     if (count > 0) {
    364         if (CC_UNLIKELY(Properties::drawDeferDisabled)) {
    365             startMark("Layer Updates");
    366         } else {
    367             startMark("Defer Layer Updates");
    368         }
    369 
    370         // Note: it is very important to update the layers in order
    371         for (int i = 0; i < count; i++) {
    372             Layer* layer = mLayerUpdates[i].get();
    373             updateLayer(layer, false);
    374         }
    375 
    376         if (CC_UNLIKELY(Properties::drawDeferDisabled)) {
    377             mLayerUpdates.clear();
    378             mRenderState.bindFramebuffer(getTargetFbo());
    379         }
    380         endMark();
    381     }
    382 }
    383 
    384 void OpenGLRenderer::flushLayers() {
    385     int count = mLayerUpdates.size();
    386     if (count > 0) {
    387         startMark("Apply Layer Updates");
    388 
    389         // Note: it is very important to update the layers in order
    390         for (int i = 0; i < count; i++) {
    391             mLayerUpdates[i]->flush();
    392         }
    393 
    394         mLayerUpdates.clear();
    395         mRenderState.bindFramebuffer(getTargetFbo());
    396 
    397         endMark();
    398     }
    399 }
    400 
    401 void OpenGLRenderer::pushLayerUpdate(Layer* layer) {
    402     if (layer) {
    403         // Make sure we don't introduce duplicates.
    404         // SortedVector would do this automatically but we need to respect
    405         // the insertion order. The linear search is not an issue since
    406         // this list is usually very short (typically one item, at most a few)
    407         for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
    408             if (mLayerUpdates[i] == layer) {
    409                 return;
    410             }
    411         }
    412         mLayerUpdates.push_back(layer);
    413     }
    414 }
    415 
    416 void OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
    417     if (layer) {
    418         for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
    419             if (mLayerUpdates[i] == layer) {
    420                 mLayerUpdates.erase(mLayerUpdates.begin() + i);
    421                 break;
    422             }
    423         }
    424     }
    425 }
    426 
    427 void OpenGLRenderer::flushLayerUpdates() {
    428     ATRACE_NAME("Update HW Layers");
    429     mRenderState.blend().syncEnabled();
    430     updateLayers();
    431     flushLayers();
    432     // Wait for all the layer updates to be executed
    433     glFinish();
    434 }
    435 
    436 void OpenGLRenderer::markLayersAsBuildLayers() {
    437     for (size_t i = 0; i < mLayerUpdates.size(); i++) {
    438         mLayerUpdates[i]->wasBuildLayered = true;
    439     }
    440 }
    441 
    442 ///////////////////////////////////////////////////////////////////////////////
    443 // State management
    444 ///////////////////////////////////////////////////////////////////////////////
    445 
    446 void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
    447     bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
    448     bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
    449     bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
    450 
    451     if (restoreViewport) {
    452         mRenderState.setViewport(getViewportWidth(), getViewportHeight());
    453     }
    454 
    455     if (restoreClip) {
    456         dirtyClip();
    457     }
    458 
    459     if (restoreLayer) {
    460         endMark(); // Savelayer
    461         ATRACE_END(); // SaveLayer
    462         startMark("ComposeLayer");
    463         composeLayer(removed, restored);
    464         endMark();
    465     }
    466 }
    467 
    468 ///////////////////////////////////////////////////////////////////////////////
    469 // Layers
    470 ///////////////////////////////////////////////////////////////////////////////
    471 
    472 int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
    473         const SkPaint* paint, int flags, const SkPath* convexMask) {
    474     // force matrix/clip isolation for layer
    475     flags |= SaveFlags::MatrixClip;
    476 
    477     const int count = mState.saveSnapshot(flags);
    478 
    479     if (!mState.currentlyIgnored()) {
    480         createLayer(left, top, right, bottom, paint, flags, convexMask);
    481     }
    482 
    483     return count;
    484 }
    485 
    486 void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) {
    487     const Rect untransformedBounds(bounds);
    488 
    489     currentTransform()->mapRect(bounds);
    490 
    491     // Layers only make sense if they are in the framebuffer's bounds
    492     bounds.doIntersect(mState.currentRenderTargetClip());
    493     if (!bounds.isEmpty()) {
    494         // We cannot work with sub-pixels in this case
    495         bounds.snapToPixelBoundaries();
    496 
    497         // When the layer is not an FBO, we may use glCopyTexImage so we
    498         // need to make sure the layer does not extend outside the bounds
    499         // of the framebuffer
    500         const Snapshot& previous = *(currentSnapshot()->previous);
    501         Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight());
    502 
    503         bounds.doIntersect(previousViewport);
    504         if (!bounds.isEmpty() && fboLayer) {
    505             clip.set(bounds);
    506             mat4 inverse;
    507             inverse.loadInverse(*currentTransform());
    508             inverse.mapRect(clip);
    509             clip.snapToPixelBoundaries();
    510             clip.doIntersect(untransformedBounds);
    511             if (!clip.isEmpty()) {
    512                 clip.translate(-untransformedBounds.left, -untransformedBounds.top);
    513                 bounds.set(untransformedBounds);
    514             }
    515         }
    516     }
    517 }
    518 
    519 void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip,
    520         bool fboLayer, int alpha) {
    521     if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
    522             bounds.getHeight() > mCaches.maxTextureSize ||
    523             (fboLayer && clip.isEmpty())) {
    524         writableSnapshot()->empty = fboLayer;
    525     } else {
    526         writableSnapshot()->invisible = writableSnapshot()->invisible || (alpha <= 0 && fboLayer);
    527     }
    528 }
    529 
    530 int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
    531         const SkPaint* paint, int flags) {
    532     const int count = mState.saveSnapshot(flags);
    533 
    534     if (!mState.currentlyIgnored() && (flags & SaveFlags::ClipToLayer)) {
    535         // initialize the snapshot as though it almost represents an FBO layer so deferred draw
    536         // operations will be able to store and restore the current clip and transform info, and
    537         // quick rejection will be correct (for display lists)
    538 
    539         Rect bounds(left, top, right, bottom);
    540         Rect clip;
    541         calculateLayerBoundsAndClip(bounds, clip, true);
    542         updateSnapshotIgnoreForLayer(bounds, clip, true, PaintUtils::getAlphaDirect(paint));
    543 
    544         if (!mState.currentlyIgnored()) {
    545             writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
    546             writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
    547             writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
    548             writableSnapshot()->roundRectClipState = nullptr;
    549         }
    550     }
    551 
    552     return count;
    553 }
    554 
    555 /**
    556  * Layers are viewed by Skia are slightly different than layers in image editing
    557  * programs (for instance.) When a layer is created, previously created layers
    558  * and the frame buffer still receive every drawing command. For instance, if a
    559  * layer is created and a shape intersecting the bounds of the layers and the
    560  * framebuffer is draw, the shape will be drawn on both (unless the layer was
    561  * created with the SaveFlags::ClipToLayer flag.)
    562  *
    563  * A way to implement layers is to create an FBO for each layer, backed by an RGBA
    564  * texture. Unfortunately, this is inefficient as it requires every primitive to
    565  * be drawn n + 1 times, where n is the number of active layers. In practice this
    566  * means, for every primitive:
    567  *   - Switch active frame buffer
    568  *   - Change viewport, clip and projection matrix
    569  *   - Issue the drawing
    570  *
    571  * Switching rendering target n + 1 times per drawn primitive is extremely costly.
    572  * To avoid this, layers are implemented in a different way here, at least in the
    573  * general case. FBOs are used, as an optimization, when the "clip to layer" flag
    574  * is set. When this flag is set we can redirect all drawing operations into a
    575  * single FBO.
    576  *
    577  * This implementation relies on the frame buffer being at least RGBA 8888. When
    578  * a layer is created, only a texture is created, not an FBO. The content of the
    579  * frame buffer contained within the layer's bounds is copied into this texture
    580  * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
    581  * buffer and drawing continues as normal. This technique therefore treats the
    582  * frame buffer as a scratch buffer for the layers.
    583  *
    584  * To compose the layers back onto the frame buffer, each layer texture
    585  * (containing the original frame buffer data) is drawn as a simple quad over
    586  * the frame buffer. The trick is that the quad is set as the composition
    587  * destination in the blending equation, and the frame buffer becomes the source
    588  * of the composition.
    589  *
    590  * Drawing layers with an alpha value requires an extra step before composition.
    591  * An empty quad is drawn over the layer's region in the frame buffer. This quad
    592  * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
    593  * quad is used to multiply the colors in the frame buffer. This is achieved by
    594  * changing the GL blend functions for the GL_FUNC_ADD blend equation to
    595  * GL_ZERO, GL_SRC_ALPHA.
    596  *
    597  * Because glCopyTexImage2D() can be slow, an alternative implementation might
    598  * be use to draw a single clipped layer. The implementation described above
    599  * is correct in every case.
    600  *
    601  * (1) The frame buffer is actually not cleared right away. To allow the GPU
    602  *     to potentially optimize series of calls to glCopyTexImage2D, the frame
    603  *     buffer is left untouched until the first drawing operation. Only when
    604  *     something actually gets drawn are the layers regions cleared.
    605  */
    606 bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
    607         const SkPaint* paint, int flags, const SkPath* convexMask) {
    608     LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
    609     LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
    610 
    611     const bool fboLayer = flags & SaveFlags::ClipToLayer;
    612 
    613     // Window coordinates of the layer
    614     Rect clip;
    615     Rect bounds(left, top, right, bottom);
    616     calculateLayerBoundsAndClip(bounds, clip, fboLayer);
    617     updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, PaintUtils::getAlphaDirect(paint));
    618 
    619     // Bail out if we won't draw in this snapshot
    620     if (mState.currentlyIgnored()) {
    621         return false;
    622     }
    623 
    624     mCaches.textureState().activateTexture(0);
    625     Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
    626     if (!layer) {
    627         return false;
    628     }
    629 
    630     layer->setPaint(paint);
    631     layer->layer.set(bounds);
    632     layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
    633             bounds.getWidth() / float(layer->getWidth()), 0.0f);
    634 
    635     layer->setBlend(true);
    636     layer->setDirty(false);
    637     layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
    638 
    639     // Save the layer in the snapshot
    640     writableSnapshot()->flags |= Snapshot::kFlagIsLayer;
    641     writableSnapshot()->layer = layer;
    642 
    643     ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
    644             fboLayer ? "" : "unclipped ",
    645             layer->getWidth(), layer->getHeight());
    646     startMark("SaveLayer");
    647     if (fboLayer) {
    648         return createFboLayer(layer, bounds, clip);
    649     } else {
    650         // Copy the framebuffer into the layer
    651         layer->bindTexture();
    652         if (!bounds.isEmpty()) {
    653             if (layer->isEmpty()) {
    654                 // Workaround for some GL drivers. When reading pixels lying outside
    655                 // of the window we should get undefined values for those pixels.
    656                 // Unfortunately some drivers will turn the entire target texture black
    657                 // when reading outside of the window.
    658                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(),
    659                         0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
    660                 layer->setEmpty(false);
    661             }
    662 
    663             glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
    664                     bounds.left, getViewportHeight() - bounds.bottom,
    665                     bounds.getWidth(), bounds.getHeight());
    666 
    667             // Enqueue the buffer coordinates to clear the corresponding region later
    668             mLayers.push_back(Rect(bounds));
    669         }
    670     }
    671 
    672     return true;
    673 }
    674 
    675 bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
    676     layer->clipRect.set(clip);
    677     layer->setFbo(mRenderState.createFramebuffer());
    678 
    679     writableSnapshot()->region = &writableSnapshot()->layer->region;
    680     writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
    681     writableSnapshot()->fbo = layer->getFbo();
    682     writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
    683     writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
    684     writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
    685     writableSnapshot()->roundRectClipState = nullptr;
    686 
    687     debugOverdraw(false, false);
    688     // Bind texture to FBO
    689     mRenderState.bindFramebuffer(layer->getFbo());
    690     layer->bindTexture();
    691 
    692     // Initialize the texture if needed
    693     if (layer->isEmpty()) {
    694         layer->allocateTexture();
    695         layer->setEmpty(false);
    696     }
    697 
    698     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
    699             layer->getTextureId(), 0);
    700 
    701     // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
    702     mRenderState.scissor().setEnabled(true);
    703     mRenderState.scissor().set(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
    704             clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
    705     glClear(GL_COLOR_BUFFER_BIT);
    706 
    707     dirtyClip();
    708 
    709     // Change the ortho projection
    710     mRenderState.setViewport(bounds.getWidth(), bounds.getHeight());
    711     return true;
    712 }
    713 
    714 /**
    715  * Read the documentation of createLayer() before doing anything in this method.
    716  */
    717 void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) {
    718     if (!removed.layer) {
    719         ALOGE("Attempting to compose a layer that does not exist");
    720         return;
    721     }
    722 
    723     Layer* layer = removed.layer;
    724     const Rect& rect = layer->layer;
    725     const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
    726 
    727     bool clipRequired = false;
    728     mState.calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
    729             &clipRequired, nullptr, false); // safely ignore return, should never be rejected
    730     mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
    731 
    732     if (fboLayer) {
    733         // Detach the texture from the FBO
    734         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
    735 
    736         layer->removeFbo(false);
    737 
    738         // Unbind current FBO and restore previous one
    739         mRenderState.bindFramebuffer(restored.fbo);
    740         debugOverdraw(true, false);
    741     }
    742 
    743     if (!fboLayer && layer->getAlpha() < 255) {
    744         SkPaint layerPaint;
    745         layerPaint.setAlpha(layer->getAlpha());
    746         layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
    747         layerPaint.setColorFilter(layer->getColorFilter());
    748 
    749         drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true);
    750         // Required below, composeLayerRect() will divide by 255
    751         layer->setAlpha(255);
    752     }
    753 
    754     mRenderState.meshState().unbindMeshBuffer();
    755 
    756     mCaches.textureState().activateTexture(0);
    757 
    758     // When the layer is stored in an FBO, we can save a bit of fillrate by
    759     // drawing only the dirty region
    760     if (fboLayer) {
    761         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);
    762         composeLayerRegion(layer, rect);
    763     } else if (!rect.isEmpty()) {
    764         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
    765 
    766         save(0);
    767         // the layer contains screen buffer content that shouldn't be alpha modulated
    768         // (and any necessary alpha modulation was handled drawing into the layer)
    769         writableSnapshot()->alpha = 1.0f;
    770         composeLayerRectSwapped(layer, rect);
    771         restore();
    772     }
    773 
    774     dirtyClip();
    775 
    776     // Failing to add the layer to the cache should happen only if the layer is too large
    777     layer->setConvexMask(nullptr);
    778     if (!mCaches.layerCache.put(layer)) {
    779         LAYER_LOGD("Deleting layer");
    780         layer->decStrong(nullptr);
    781     }
    782 }
    783 
    784 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
    785     const bool tryToSnap = !layer->getForceFilter()
    786             && layer->getWidth() == (uint32_t) rect.getWidth()
    787             && layer->getHeight() == (uint32_t) rect.getHeight();
    788     Glop glop;
    789     GlopBuilder(mRenderState, mCaches, &glop)
    790             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
    791             .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
    792             .setFillTextureLayer(*layer, getLayerAlpha(layer))
    793             .setTransform(*currentSnapshot(), TransformFlags::None)
    794             .setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect)
    795             .build();
    796     renderGlop(glop);
    797 }
    798 
    799 void OpenGLRenderer::composeLayerRectSwapped(Layer* layer, const Rect& rect) {
    800     Glop glop;
    801     GlopBuilder(mRenderState, mCaches, &glop)
    802             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
    803             .setMeshTexturedUvQuad(nullptr, layer->texCoords)
    804             .setFillLayer(layer->getTexture(), layer->getColorFilter(),
    805                     getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::Swap)
    806             .setTransform(*currentSnapshot(), TransformFlags::MeshIgnoresCanvasTransform)
    807             .setModelViewMapUnitToRect(rect)
    808             .build();
    809     renderGlop(glop);
    810 }
    811 
    812 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect) {
    813     if (layer->isTextureLayer()) {
    814         EVENT_LOGD("composeTextureLayerRect");
    815         drawTextureLayer(layer, rect);
    816     } else {
    817         EVENT_LOGD("composeHardwareLayerRect");
    818 
    819         const bool tryToSnap = layer->getWidth() == static_cast<uint32_t>(rect.getWidth())
    820                 && layer->getHeight() == static_cast<uint32_t>(rect.getHeight());
    821         Glop glop;
    822         GlopBuilder(mRenderState, mCaches, &glop)
    823                 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
    824                 .setMeshTexturedUvQuad(nullptr, layer->texCoords)
    825                 .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
    826                 .setTransform(*currentSnapshot(), TransformFlags::None)
    827                 .setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect)
    828                 .build();
    829         renderGlop(glop);
    830     }
    831 }
    832 
    833 /**
    834  * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
    835  * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
    836  * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
    837  * by saveLayer's restore
    838  */
    839 #define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) { \
    840         DRAW_COMMAND; \
    841         if (CC_UNLIKELY(Properties::debugOverdraw && getTargetFbo() == 0 && COND)) { \
    842             glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); \
    843             DRAW_COMMAND; \
    844             glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); \
    845         } \
    846     }
    847 
    848 #define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
    849 
    850 // This class is purely for inspection. It inherits from SkShader, but Skia does not know how to
    851 // use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque.
    852 class LayerShader : public SkShader {
    853 public:
    854     LayerShader(Layer* layer, const SkMatrix* localMatrix)
    855     : INHERITED(localMatrix)
    856     , mLayer(layer) {
    857     }
    858 
    859     virtual bool asACustomShader(void** data) const override {
    860         if (data) {
    861             *data = static_cast<void*>(mLayer);
    862         }
    863         return true;
    864     }
    865 
    866     virtual bool isOpaque() const override {
    867         return !mLayer->isBlend();
    868     }
    869 
    870 protected:
    871     virtual void shadeSpan(int x, int y, SkPMColor[], int count) {
    872         LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
    873     }
    874 
    875     virtual void flatten(SkWriteBuffer&) const override {
    876         LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
    877     }
    878 
    879     virtual Factory getFactory() const override {
    880         LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
    881         return nullptr;
    882     }
    883 private:
    884     // Unowned.
    885     Layer* mLayer;
    886     typedef SkShader INHERITED;
    887 };
    888 
    889 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
    890     if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
    891 
    892     if (layer->getConvexMask()) {
    893         save(SaveFlags::MatrixClip);
    894 
    895         // clip to the area of the layer the mask can be larger
    896         clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
    897 
    898         SkPaint paint;
    899         paint.setAntiAlias(true);
    900         paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
    901 
    902         // create LayerShader to map SaveLayer content into subsequent draw
    903         SkMatrix shaderMatrix;
    904         shaderMatrix.setTranslate(rect.left, rect.bottom);
    905         shaderMatrix.preScale(1, -1);
    906         LayerShader layerShader(layer, &shaderMatrix);
    907         paint.setShader(&layerShader);
    908 
    909         // Since the drawing primitive is defined in local drawing space,
    910         // we don't need to modify the draw matrix
    911         const SkPath* maskPath = layer->getConvexMask();
    912         DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
    913 
    914         paint.setShader(nullptr);
    915         restore();
    916 
    917         return;
    918     }
    919 
    920     if (layer->region.isRect()) {
    921         layer->setRegionAsRect();
    922 
    923         DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
    924 
    925         layer->region.clear();
    926         return;
    927     }
    928 
    929     EVENT_LOGD("composeLayerRegion");
    930     // standard Region based draw
    931     size_t count;
    932     const android::Rect* rects;
    933     Region safeRegion;
    934     if (CC_LIKELY(hasRectToRectTransform())) {
    935         rects = layer->region.getArray(&count);
    936     } else {
    937         safeRegion = Region::createTJunctionFreeRegion(layer->region);
    938         rects = safeRegion.getArray(&count);
    939     }
    940 
    941     const float texX = 1.0f / float(layer->getWidth());
    942     const float texY = 1.0f / float(layer->getHeight());
    943     const float height = rect.getHeight();
    944 
    945     TextureVertex quadVertices[count * 4];
    946     TextureVertex* mesh = &quadVertices[0];
    947     for (size_t i = 0; i < count; i++) {
    948         const android::Rect* r = &rects[i];
    949 
    950         const float u1 = r->left * texX;
    951         const float v1 = (height - r->top) * texY;
    952         const float u2 = r->right * texX;
    953         const float v2 = (height - r->bottom) * texY;
    954 
    955         // TODO: Reject quads outside of the clip
    956         TextureVertex::set(mesh++, r->left, r->top, u1, v1);
    957         TextureVertex::set(mesh++, r->right, r->top, u2, v1);
    958         TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
    959         TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
    960     }
    961     Rect modelRect = Rect(rect.getWidth(), rect.getHeight());
    962     Glop glop;
    963     GlopBuilder(mRenderState, mCaches, &glop)
    964             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
    965             .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6)
    966             .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
    967             .setTransform(*currentSnapshot(),  TransformFlags::None)
    968             .setModelViewOffsetRectSnap(rect.left, rect.top, modelRect)
    969             .build();
    970     DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
    971 
    972 #if DEBUG_LAYERS_AS_REGIONS
    973     drawRegionRectsDebug(layer->region);
    974 #endif
    975 
    976     layer->region.clear();
    977 }
    978 
    979 #if DEBUG_LAYERS_AS_REGIONS
    980 void OpenGLRenderer::drawRegionRectsDebug(const Region& region) {
    981     size_t count;
    982     const android::Rect* rects = region.getArray(&count);
    983 
    984     uint32_t colors[] = {
    985             0x7fff0000, 0x7f00ff00,
    986             0x7f0000ff, 0x7fff00ff,
    987     };
    988 
    989     int offset = 0;
    990     int32_t top = rects[0].top;
    991 
    992     for (size_t i = 0; i < count; i++) {
    993         if (top != rects[i].top) {
    994             offset ^= 0x2;
    995             top = rects[i].top;
    996         }
    997 
    998         SkPaint paint;
    999         paint.setColor(colors[offset + (i & 0x1)]);
   1000         Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
   1001         drawColorRect(r.left, r.top, r.right, r.bottom, paint);
   1002     }
   1003 }
   1004 #endif
   1005 
   1006 void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) {
   1007     Vector<float> rects;
   1008 
   1009     SkRegion::Iterator it(region);
   1010     while (!it.done()) {
   1011         const SkIRect& r = it.rect();
   1012         rects.push(r.fLeft);
   1013         rects.push(r.fTop);
   1014         rects.push(r.fRight);
   1015         rects.push(r.fBottom);
   1016         it.next();
   1017     }
   1018 
   1019     drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false);
   1020 }
   1021 
   1022 void OpenGLRenderer::dirtyLayer(const float left, const float top,
   1023         const float right, const float bottom, const Matrix4& transform) {
   1024     if (hasLayer()) {
   1025         Rect bounds(left, top, right, bottom);
   1026         transform.mapRect(bounds);
   1027         dirtyLayerUnchecked(bounds, getRegion());
   1028     }
   1029 }
   1030 
   1031 void OpenGLRenderer::dirtyLayer(const float left, const float top,
   1032         const float right, const float bottom) {
   1033     if (hasLayer()) {
   1034         Rect bounds(left, top, right, bottom);
   1035         dirtyLayerUnchecked(bounds, getRegion());
   1036     }
   1037 }
   1038 
   1039 void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
   1040     bounds.doIntersect(mState.currentRenderTargetClip());
   1041     if (!bounds.isEmpty()) {
   1042         bounds.snapToPixelBoundaries();
   1043         android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
   1044         if (!dirty.isEmpty()) {
   1045             region->orSelf(dirty);
   1046         }
   1047     }
   1048 }
   1049 
   1050 void OpenGLRenderer::clearLayerRegions() {
   1051     const size_t quadCount = mLayers.size();
   1052     if (quadCount == 0) return;
   1053 
   1054     if (!mState.currentlyIgnored()) {
   1055         EVENT_LOGD("clearLayerRegions");
   1056         // Doing several glScissor/glClear here can negatively impact
   1057         // GPUs with a tiler architecture, instead we draw quads with
   1058         // the Clear blending mode
   1059 
   1060         // The list contains bounds that have already been clipped
   1061         // against their initial clip rect, and the current clip
   1062         // is likely different so we need to disable clipping here
   1063         bool scissorChanged = mRenderState.scissor().setEnabled(false);
   1064 
   1065         Vertex mesh[quadCount * 4];
   1066         Vertex* vertex = mesh;
   1067 
   1068         for (uint32_t i = 0; i < quadCount; i++) {
   1069             const Rect& bounds = mLayers[i];
   1070 
   1071             Vertex::set(vertex++, bounds.left, bounds.top);
   1072             Vertex::set(vertex++, bounds.right, bounds.top);
   1073             Vertex::set(vertex++, bounds.left, bounds.bottom);
   1074             Vertex::set(vertex++, bounds.right, bounds.bottom);
   1075         }
   1076         // We must clear the list of dirty rects before we
   1077         // call clearLayerRegions() in renderGlop to prevent
   1078         // stencil setup from doing the same thing again
   1079         mLayers.clear();
   1080 
   1081         const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
   1082         Glop glop;
   1083         GlopBuilder(mRenderState, mCaches, &glop)
   1084                 .setRoundRectClipState(nullptr) // clear ignores clip state
   1085                 .setMeshIndexedQuads(&mesh[0], quadCount)
   1086                 .setFillClear()
   1087                 .setTransform(*currentSnapshot(), transformFlags)
   1088                 .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getRenderTargetClip()))
   1089                 .build();
   1090         renderGlop(glop, GlopRenderType::LayerClear);
   1091 
   1092         if (scissorChanged) mRenderState.scissor().setEnabled(true);
   1093     } else {
   1094         mLayers.clear();
   1095     }
   1096 }
   1097 
   1098 ///////////////////////////////////////////////////////////////////////////////
   1099 // State Deferral
   1100 ///////////////////////////////////////////////////////////////////////////////
   1101 
   1102 bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
   1103     const Rect& currentClip = mState.currentRenderTargetClip();
   1104     const mat4* currentMatrix = currentTransform();
   1105 
   1106     if (stateDeferFlags & kStateDeferFlag_Draw) {
   1107         // state has bounds initialized in local coordinates
   1108         if (!state.mBounds.isEmpty()) {
   1109             currentMatrix->mapRect(state.mBounds);
   1110             Rect clippedBounds(state.mBounds);
   1111             // NOTE: if we ever want to use this clipping info to drive whether the scissor
   1112             // is used, it should more closely duplicate the quickReject logic (in how it uses
   1113             // snapToPixelBoundaries)
   1114 
   1115             clippedBounds.doIntersect(currentClip);
   1116             if (clippedBounds.isEmpty()) {
   1117                 // quick rejected
   1118                 return true;
   1119             }
   1120 
   1121             state.mClipSideFlags = kClipSide_None;
   1122             if (!currentClip.contains(state.mBounds)) {
   1123                 int& flags = state.mClipSideFlags;
   1124                 // op partially clipped, so record which sides are clipped for clip-aware merging
   1125                 if (currentClip.left > state.mBounds.left) flags |= kClipSide_Left;
   1126                 if (currentClip.top > state.mBounds.top) flags |= kClipSide_Top;
   1127                 if (currentClip.right < state.mBounds.right) flags |= kClipSide_Right;
   1128                 if (currentClip.bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
   1129             }
   1130             state.mBounds.set(clippedBounds);
   1131         } else {
   1132             // Empty bounds implies size unknown. Label op as conservatively clipped to disable
   1133             // overdraw avoidance (since we don't know what it overlaps)
   1134             state.mClipSideFlags = kClipSide_ConservativeFull;
   1135             state.mBounds.set(currentClip);
   1136         }
   1137     }
   1138 
   1139     state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
   1140     if (state.mClipValid) {
   1141         state.mClip.set(currentClip);
   1142     }
   1143 
   1144     // Transform and alpha always deferred, since they are used by state operations
   1145     // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
   1146     state.mMatrix = *currentMatrix;
   1147     state.mAlpha = currentSnapshot()->alpha;
   1148 
   1149     // always store/restore, since these are just pointers
   1150     state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
   1151 #if !HWUI_NEW_OPS
   1152     state.mProjectionPathMask = currentSnapshot()->projectionPathMask;
   1153 #endif
   1154     return false;
   1155 }
   1156 
   1157 void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
   1158     setGlobalMatrix(state.mMatrix);
   1159     writableSnapshot()->alpha = state.mAlpha;
   1160     writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
   1161 #if !HWUI_NEW_OPS
   1162     writableSnapshot()->projectionPathMask = state.mProjectionPathMask;
   1163 #endif
   1164 
   1165     if (state.mClipValid && !skipClipRestore) {
   1166         writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
   1167                 state.mClip.right, state.mClip.bottom);
   1168         dirtyClip();
   1169     }
   1170 }
   1171 
   1172 /**
   1173  * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done
   1174  * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at
   1175  * least one op is clipped), or disabled entirely (because no merged op is clipped)
   1176  *
   1177  * This method should be called when restoreDisplayState() won't be restoring the clip
   1178  */
   1179 void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
   1180     if (clipRect != nullptr) {
   1181         writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
   1182     } else {
   1183         writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight());
   1184     }
   1185     dirtyClip();
   1186     bool enableScissor = (clipRect != nullptr) || mScissorOptimizationDisabled;
   1187     mRenderState.scissor().setEnabled(enableScissor);
   1188 }
   1189 
   1190 ///////////////////////////////////////////////////////////////////////////////
   1191 // Clipping
   1192 ///////////////////////////////////////////////////////////////////////////////
   1193 
   1194 void OpenGLRenderer::setScissorFromClip() {
   1195     Rect clip(mState.currentRenderTargetClip());
   1196     clip.snapToPixelBoundaries();
   1197 
   1198     if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom,
   1199             clip.getWidth(), clip.getHeight())) {
   1200         mState.setDirtyClip(false);
   1201     }
   1202 }
   1203 
   1204 void OpenGLRenderer::ensureStencilBuffer() {
   1205     // Thanks to the mismatch between EGL and OpenGL ES FBO we
   1206     // cannot attach a stencil buffer to fbo0 dynamically. Let's
   1207     // just hope we have one when hasLayer() returns false.
   1208     if (hasLayer()) {
   1209         attachStencilBufferToLayer(currentSnapshot()->layer);
   1210     }
   1211 }
   1212 
   1213 void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
   1214     // The layer's FBO is already bound when we reach this stage
   1215     if (!layer->getStencilRenderBuffer()) {
   1216         RenderBuffer* buffer = mCaches.renderBufferCache.get(
   1217                 Stencil::getLayerStencilFormat(),
   1218                 layer->getWidth(), layer->getHeight());
   1219         layer->setStencilRenderBuffer(buffer);
   1220     }
   1221 }
   1222 
   1223 static void handlePoint(std::vector<Vertex>& rectangleVertices, const Matrix4& transform,
   1224         float x, float y) {
   1225     Vertex v;
   1226     v.x = x;
   1227     v.y = y;
   1228     transform.mapPoint(v.x, v.y);
   1229     rectangleVertices.push_back(v);
   1230 }
   1231 
   1232 static void handlePointNoTransform(std::vector<Vertex>& rectangleVertices, float x, float y) {
   1233     Vertex v;
   1234     v.x = x;
   1235     v.y = y;
   1236     rectangleVertices.push_back(v);
   1237 }
   1238 
   1239 void OpenGLRenderer::drawRectangleList(const RectangleList& rectangleList) {
   1240     int quadCount = rectangleList.getTransformedRectanglesCount();
   1241     std::vector<Vertex> rectangleVertices(quadCount * 4);
   1242     Rect scissorBox = rectangleList.calculateBounds();
   1243     scissorBox.snapToPixelBoundaries();
   1244     for (int i = 0; i < quadCount; ++i) {
   1245         const TransformedRectangle& tr(rectangleList.getTransformedRectangle(i));
   1246         const Matrix4& transform = tr.getTransform();
   1247         Rect bounds = tr.getBounds();
   1248         if (transform.rectToRect()) {
   1249             transform.mapRect(bounds);
   1250             bounds.doIntersect(scissorBox);
   1251             if (!bounds.isEmpty()) {
   1252                 handlePointNoTransform(rectangleVertices, bounds.left, bounds.top);
   1253                 handlePointNoTransform(rectangleVertices, bounds.right, bounds.top);
   1254                 handlePointNoTransform(rectangleVertices, bounds.left, bounds.bottom);
   1255                 handlePointNoTransform(rectangleVertices, bounds.right, bounds.bottom);
   1256             }
   1257         } else {
   1258             handlePoint(rectangleVertices, transform, bounds.left, bounds.top);
   1259             handlePoint(rectangleVertices, transform, bounds.right, bounds.top);
   1260             handlePoint(rectangleVertices, transform, bounds.left, bounds.bottom);
   1261             handlePoint(rectangleVertices, transform, bounds.right, bounds.bottom);
   1262         }
   1263     }
   1264 
   1265     mRenderState.scissor().set(scissorBox.left, getViewportHeight() - scissorBox.bottom,
   1266             scissorBox.getWidth(), scissorBox.getHeight());
   1267     const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
   1268     Glop glop;
   1269     Vertex* vertices = &rectangleVertices[0];
   1270     GlopBuilder(mRenderState, mCaches, &glop)
   1271             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   1272             .setMeshIndexedQuads(vertices, rectangleVertices.size() / 4)
   1273             .setFillBlack()
   1274             .setTransform(*currentSnapshot(), transformFlags)
   1275             .setModelViewOffsetRect(0, 0, scissorBox)
   1276             .build();
   1277     renderGlop(glop);
   1278 }
   1279 
   1280 void OpenGLRenderer::setStencilFromClip() {
   1281     if (!Properties::debugOverdraw) {
   1282         if (!currentSnapshot()->clipIsSimple()) {
   1283             int incrementThreshold;
   1284             EVENT_LOGD("setStencilFromClip - enabling");
   1285 
   1286             // NOTE: The order here is important, we must set dirtyClip to false
   1287             //       before any draw call to avoid calling back into this method
   1288             mState.setDirtyClip(false);
   1289 
   1290             ensureStencilBuffer();
   1291 
   1292             const ClipArea& clipArea = currentSnapshot()->getClipArea();
   1293 
   1294             bool isRectangleList = clipArea.isRectangleList();
   1295             if (isRectangleList) {
   1296                 incrementThreshold = clipArea.getRectangleList().getTransformedRectanglesCount();
   1297             } else {
   1298                 incrementThreshold = 0;
   1299             }
   1300 
   1301             mRenderState.stencil().enableWrite(incrementThreshold);
   1302 
   1303             // Clean and update the stencil, but first make sure we restrict drawing
   1304             // to the region's bounds
   1305             bool resetScissor = mRenderState.scissor().setEnabled(true);
   1306             if (resetScissor) {
   1307                 // The scissor was not set so we now need to update it
   1308                 setScissorFromClip();
   1309             }
   1310 
   1311             mRenderState.stencil().clear();
   1312 
   1313             // stash and disable the outline clip state, since stencil doesn't account for outline
   1314             bool storedSkipOutlineClip = mSkipOutlineClip;
   1315             mSkipOutlineClip = true;
   1316 
   1317             SkPaint paint;
   1318             paint.setColor(SK_ColorBLACK);
   1319             paint.setXfermodeMode(SkXfermode::kSrc_Mode);
   1320 
   1321             if (isRectangleList) {
   1322                 drawRectangleList(clipArea.getRectangleList());
   1323             } else {
   1324                 // NOTE: We could use the region contour path to generate a smaller mesh
   1325                 //       Since we are using the stencil we could use the red book path
   1326                 //       drawing technique. It might increase bandwidth usage though.
   1327 
   1328                 // The last parameter is important: we are not drawing in the color buffer
   1329                 // so we don't want to dirty the current layer, if any
   1330                 drawRegionRects(clipArea.getClipRegion(), paint, false);
   1331             }
   1332             if (resetScissor) mRenderState.scissor().setEnabled(false);
   1333             mSkipOutlineClip = storedSkipOutlineClip;
   1334 
   1335             mRenderState.stencil().enableTest(incrementThreshold);
   1336 
   1337             // Draw the region used to generate the stencil if the appropriate debug
   1338             // mode is enabled
   1339             // TODO: Implement for rectangle list clip areas
   1340             if (Properties::debugStencilClip == StencilClipDebug::ShowRegion
   1341                     && !clipArea.isRectangleList()) {
   1342                 paint.setColor(0x7f0000ff);
   1343                 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
   1344                 drawRegionRects(currentSnapshot()->getClipRegion(), paint);
   1345             }
   1346         } else {
   1347             EVENT_LOGD("setStencilFromClip - disabling");
   1348             mRenderState.stencil().disable();
   1349         }
   1350     }
   1351 }
   1352 
   1353 /**
   1354  * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out.
   1355  *
   1356  * @param paint if not null, the bounds will be expanded to account for stroke depending on paint
   1357  *         style, and tessellated AA ramp
   1358  */
   1359 bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom,
   1360         const SkPaint* paint) {
   1361     bool snapOut = paint && paint->isAntiAlias();
   1362 
   1363     if (paint && paint->getStyle() != SkPaint::kFill_Style) {
   1364         float outset = paint->getStrokeWidth() * 0.5f;
   1365         left -= outset;
   1366         top -= outset;
   1367         right += outset;
   1368         bottom += outset;
   1369     }
   1370 
   1371     bool clipRequired = false;
   1372     bool roundRectClipRequired = false;
   1373     if (mState.calculateQuickRejectForScissor(left, top, right, bottom,
   1374             &clipRequired, &roundRectClipRequired, snapOut)) {
   1375         return true;
   1376     }
   1377 
   1378     // not quick rejected, so enable the scissor if clipRequired
   1379     mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
   1380     mSkipOutlineClip = !roundRectClipRequired;
   1381     return false;
   1382 }
   1383 
   1384 void OpenGLRenderer::debugClip() {
   1385 #if DEBUG_CLIP_REGIONS
   1386     if (!currentSnapshot()->clipRegion->isEmpty()) {
   1387         SkPaint paint;
   1388         paint.setColor(0x7f00ff00);
   1389         drawRegionRects(*(currentSnapshot()->clipRegion, paint);
   1390 
   1391     }
   1392 #endif
   1393 }
   1394 
   1395 void OpenGLRenderer::renderGlop(const Glop& glop, GlopRenderType type) {
   1396     // TODO: It would be best if we could do this before quickRejectSetupScissor()
   1397     //       changes the scissor test state
   1398     if (type != GlopRenderType::LayerClear) {
   1399         // Regular draws need to clear the dirty area on the layer before they start drawing on top
   1400         // of it. If this draw *is* a layer clear, it skips the clear step (since it would
   1401         // infinitely recurse)
   1402         clearLayerRegions();
   1403     }
   1404 
   1405     if (mState.getDirtyClip()) {
   1406         if (mRenderState.scissor().isEnabled()) {
   1407             setScissorFromClip();
   1408         }
   1409 
   1410         setStencilFromClip();
   1411     }
   1412     mRenderState.render(glop, currentSnapshot()->getOrthoMatrix());
   1413     if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) {
   1414         // TODO: specify more clearly when a draw should dirty the layer.
   1415         // is writing to the stencil the only time we should ignore this?
   1416 #if !HWUI_NEW_OPS
   1417         dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
   1418 #endif
   1419         mDirty = true;
   1420     }
   1421 }
   1422 
   1423 ///////////////////////////////////////////////////////////////////////////////
   1424 // Drawing
   1425 ///////////////////////////////////////////////////////////////////////////////
   1426 
   1427 void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
   1428     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
   1429     // will be performed by the display list itself
   1430     if (renderNode && renderNode->isRenderable()) {
   1431         // compute 3d ordering
   1432         renderNode->computeOrdering();
   1433         if (CC_UNLIKELY(Properties::drawDeferDisabled)) {
   1434             startFrame();
   1435             ReplayStateStruct replayStruct(*this, dirty, replayFlags);
   1436             renderNode->replay(replayStruct, 0);
   1437             return;
   1438         }
   1439 
   1440         DeferredDisplayList deferredList(mState.currentRenderTargetClip());
   1441         DeferStateStruct deferStruct(deferredList, *this, replayFlags);
   1442         renderNode->defer(deferStruct, 0);
   1443 
   1444         flushLayers();
   1445         startFrame();
   1446 
   1447         deferredList.flush(*this, dirty);
   1448     } else {
   1449         // Even if there is no drawing command(Ex: invisible),
   1450         // it still needs startFrame to clear buffer and start tiling.
   1451         startFrame();
   1452     }
   1453 }
   1454 
   1455 /**
   1456  * Important note: this method is intended to draw batches of bitmaps and
   1457  * will not set the scissor enable or dirty the current layer, if any.
   1458  * The caller is responsible for properly dirtying the current layer.
   1459  */
   1460 void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
   1461         int bitmapCount, TextureVertex* vertices, bool pureTranslate,
   1462         const Rect& bounds, const SkPaint* paint) {
   1463     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
   1464     if (!texture) return;
   1465 
   1466     const AutoTexture autoCleanup(texture);
   1467 
   1468     // TODO: remove layer dirty in multi-draw callers
   1469     // TODO: snap doesn't need to touch transform, only texture filter.
   1470     bool snap = pureTranslate;
   1471     const float x = floorf(bounds.left + 0.5f);
   1472     const float y = floorf(bounds.top + 0.5f);
   1473 
   1474     const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
   1475             ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
   1476     const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
   1477     Glop glop;
   1478     GlopBuilder(mRenderState, mCaches, &glop)
   1479             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   1480             .setMeshTexturedMesh(vertices, bitmapCount * 6)
   1481             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
   1482             .setTransform(*currentSnapshot(), transformFlags)
   1483             .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(bounds.getWidth(), bounds.getHeight()))
   1484             .build();
   1485     renderGlop(glop, GlopRenderType::Multi);
   1486 }
   1487 
   1488 void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
   1489     if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
   1490         return;
   1491     }
   1492 
   1493     mCaches.textureState().activateTexture(0);
   1494     Texture* texture = getTexture(bitmap);
   1495     if (!texture) return;
   1496     const AutoTexture autoCleanup(texture);
   1497 
   1498     const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
   1499             ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
   1500     Glop glop;
   1501     GlopBuilder(mRenderState, mCaches, &glop)
   1502             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   1503             .setMeshTexturedUnitQuad(texture->uvMapper)
   1504             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
   1505             .setTransform(*currentSnapshot(),  TransformFlags::None)
   1506             .setModelViewMapUnitToRectSnap(Rect(texture->width(), texture->height()))
   1507             .build();
   1508     renderGlop(glop);
   1509 }
   1510 
   1511 void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
   1512         const float* vertices, const int* colors, const SkPaint* paint) {
   1513     if (!vertices || mState.currentlyIgnored()) {
   1514         return;
   1515     }
   1516 
   1517     float left = FLT_MAX;
   1518     float top = FLT_MAX;
   1519     float right = FLT_MIN;
   1520     float bottom = FLT_MIN;
   1521 
   1522     const uint32_t elementCount = meshWidth * meshHeight * 6;
   1523 
   1524     std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]);
   1525     ColorTextureVertex* vertex = &mesh[0];
   1526 
   1527     std::unique_ptr<int[]> tempColors;
   1528     if (!colors) {
   1529         uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
   1530         tempColors.reset(new int[colorsCount]);
   1531         memset(tempColors.get(), 0xff, colorsCount * sizeof(int));
   1532         colors = tempColors.get();
   1533     }
   1534 
   1535     Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef());
   1536     const UvMapper& mapper(getMapper(texture));
   1537 
   1538     for (int32_t y = 0; y < meshHeight; y++) {
   1539         for (int32_t x = 0; x < meshWidth; x++) {
   1540             uint32_t i = (y * (meshWidth + 1) + x) * 2;
   1541 
   1542             float u1 = float(x) / meshWidth;
   1543             float u2 = float(x + 1) / meshWidth;
   1544             float v1 = float(y) / meshHeight;
   1545             float v2 = float(y + 1) / meshHeight;
   1546 
   1547             mapper.map(u1, v1, u2, v2);
   1548 
   1549             int ax = i + (meshWidth + 1) * 2;
   1550             int ay = ax + 1;
   1551             int bx = i;
   1552             int by = bx + 1;
   1553             int cx = i + 2;
   1554             int cy = cx + 1;
   1555             int dx = i + (meshWidth + 1) * 2 + 2;
   1556             int dy = dx + 1;
   1557 
   1558             ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
   1559             ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
   1560             ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
   1561 
   1562             ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
   1563             ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
   1564             ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
   1565 
   1566             left = std::min(left, std::min(vertices[ax], std::min(vertices[bx], vertices[cx])));
   1567             top = std::min(top, std::min(vertices[ay], std::min(vertices[by], vertices[cy])));
   1568             right = std::max(right, std::max(vertices[ax], std::max(vertices[bx], vertices[cx])));
   1569             bottom = std::max(bottom, std::max(vertices[ay], std::max(vertices[by], vertices[cy])));
   1570         }
   1571     }
   1572 
   1573     if (quickRejectSetupScissor(left, top, right, bottom)) {
   1574         return;
   1575     }
   1576 
   1577     if (!texture) {
   1578         texture = mCaches.textureCache.get(bitmap);
   1579         if (!texture) {
   1580             return;
   1581         }
   1582     }
   1583     const AutoTexture autoCleanup(texture);
   1584 
   1585     /*
   1586      * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
   1587      * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
   1588      */
   1589     const int textureFillFlags = TextureFillFlags::None;
   1590     Glop glop;
   1591     GlopBuilder(mRenderState, mCaches, &glop)
   1592             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   1593             .setMeshColoredTexturedMesh(mesh.get(), elementCount)
   1594             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
   1595             .setTransform(*currentSnapshot(),  TransformFlags::None)
   1596             .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
   1597             .build();
   1598     renderGlop(glop);
   1599 }
   1600 
   1601 void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) {
   1602     if (quickRejectSetupScissor(dst)) {
   1603         return;
   1604     }
   1605 
   1606     Texture* texture = getTexture(bitmap);
   1607     if (!texture) return;
   1608     const AutoTexture autoCleanup(texture);
   1609 
   1610     Rect uv(std::max(0.0f, src.left / texture->width()),
   1611             std::max(0.0f, src.top / texture->height()),
   1612             std::min(1.0f, src.right / texture->width()),
   1613             std::min(1.0f, src.bottom / texture->height()));
   1614 
   1615     const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
   1616             ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
   1617     const bool tryToSnap = MathUtils::areEqual(src.getWidth(), dst.getWidth())
   1618             && MathUtils::areEqual(src.getHeight(), dst.getHeight());
   1619     Glop glop;
   1620     GlopBuilder(mRenderState, mCaches, &glop)
   1621             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   1622             .setMeshTexturedUvQuad(texture->uvMapper, uv)
   1623             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
   1624             .setTransform(*currentSnapshot(),  TransformFlags::None)
   1625             .setModelViewMapUnitToRectOptionalSnap(tryToSnap, dst)
   1626             .build();
   1627     renderGlop(glop);
   1628 }
   1629 
   1630 void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
   1631         AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
   1632         const SkPaint* paint) {
   1633     if (!mesh || !mesh->verticesCount || quickRejectSetupScissor(left, top, right, bottom)) {
   1634         return;
   1635     }
   1636 
   1637     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
   1638     if (!texture) return;
   1639     const AutoTexture autoCleanup(texture);
   1640 
   1641     // 9 patches are built for stretching - always filter
   1642     int textureFillFlags = TextureFillFlags::ForceFilter;
   1643     if (bitmap->colorType() == kAlpha_8_SkColorType) {
   1644         textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
   1645     }
   1646     Glop glop;
   1647     GlopBuilder(mRenderState, mCaches, &glop)
   1648             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   1649             .setMeshPatchQuads(*mesh)
   1650             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
   1651             .setTransform(*currentSnapshot(),  TransformFlags::None)
   1652             .setModelViewOffsetRectSnap(left, top, Rect(right - left, bottom - top)) // TODO: get minimal bounds from patch
   1653             .build();
   1654     renderGlop(glop);
   1655 }
   1656 
   1657 /**
   1658  * Important note: this method is intended to draw batches of 9-patch objects and
   1659  * will not set the scissor enable or dirty the current layer, if any.
   1660  * The caller is responsible for properly dirtying the current layer.
   1661  */
   1662 void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
   1663         TextureVertex* vertices, uint32_t elementCount, const SkPaint* paint) {
   1664     mCaches.textureState().activateTexture(0);
   1665     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
   1666     if (!texture) return;
   1667     const AutoTexture autoCleanup(texture);
   1668 
   1669     // TODO: get correct bounds from caller
   1670     const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
   1671     // 9 patches are built for stretching - always filter
   1672     int textureFillFlags = TextureFillFlags::ForceFilter;
   1673     if (bitmap->colorType() == kAlpha_8_SkColorType) {
   1674         textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
   1675     }
   1676     Glop glop;
   1677     GlopBuilder(mRenderState, mCaches, &glop)
   1678             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   1679             .setMeshTexturedIndexedQuads(vertices, elementCount)
   1680             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
   1681             .setTransform(*currentSnapshot(), transformFlags)
   1682             .setModelViewOffsetRect(0, 0, Rect())
   1683             .build();
   1684     renderGlop(glop, GlopRenderType::Multi);
   1685 }
   1686 
   1687 void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
   1688         const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) {
   1689     // not missing call to quickReject/dirtyLayer, always done at a higher level
   1690     if (!vertexBuffer.getVertexCount()) {
   1691         // no vertices to draw
   1692         return;
   1693     }
   1694 
   1695     bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
   1696     const int transformFlags = TransformFlags::OffsetByFudgeFactor;
   1697     Glop glop;
   1698     GlopBuilder(mRenderState, mCaches, &glop)
   1699             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   1700             .setMeshVertexBuffer(vertexBuffer)
   1701             .setFillPaint(*paint, currentSnapshot()->alpha, shadowInterp)
   1702             .setTransform(*currentSnapshot(), transformFlags)
   1703             .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
   1704             .build();
   1705     renderGlop(glop);
   1706 }
   1707 
   1708 /**
   1709  * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
   1710  * that of AA lines in the drawLines() function.  We expand the convex path by a half pixel in
   1711  * screen space in all directions. However, instead of using a fragment shader to compute the
   1712  * translucency of the color from its position, we simply use a varying parameter to define how far
   1713  * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
   1714  *
   1715  * Doesn't yet support joins, caps, or path effects.
   1716  */
   1717 void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
   1718     VertexBuffer vertexBuffer;
   1719     // TODO: try clipping large paths to viewport
   1720 
   1721     PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
   1722     drawVertexBuffer(vertexBuffer, paint);
   1723 }
   1724 
   1725 /**
   1726  * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
   1727  * and additional geometry for defining an alpha slope perimeter.
   1728  *
   1729  * Using GL_LINES can be difficult because the rasterization rules for those lines produces some
   1730  * unexpected results, and may vary between hardware devices. Previously we used a varying-base
   1731  * in-shader alpha region, but found it to be taxing on some GPUs.
   1732  *
   1733  * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
   1734  * memory transfer by removing need for degenerate vertices.
   1735  */
   1736 void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
   1737     if (mState.currentlyIgnored() || count < 4) return;
   1738 
   1739     count &= ~0x3; // round down to nearest four
   1740 
   1741     VertexBuffer buffer;
   1742     PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer);
   1743     const Rect& bounds = buffer.getBounds();
   1744 
   1745     if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
   1746         return;
   1747     }
   1748 
   1749     int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
   1750     drawVertexBuffer(buffer, paint, displayFlags);
   1751 }
   1752 
   1753 void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
   1754     if (mState.currentlyIgnored() || count < 2) return;
   1755 
   1756     count &= ~0x1; // round down to nearest two
   1757 
   1758     VertexBuffer buffer;
   1759     PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer);
   1760 
   1761     const Rect& bounds = buffer.getBounds();
   1762     if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
   1763         return;
   1764     }
   1765 
   1766     int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
   1767     drawVertexBuffer(buffer, paint, displayFlags);
   1768 
   1769     mDirty = true;
   1770 }
   1771 
   1772 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
   1773     // No need to check against the clip, we fill the clip region
   1774     if (mState.currentlyIgnored()) return;
   1775 
   1776     Rect clip(mState.currentRenderTargetClip());
   1777     clip.snapToPixelBoundaries();
   1778 
   1779     SkPaint paint;
   1780     paint.setColor(color);
   1781     paint.setXfermodeMode(mode);
   1782 
   1783     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
   1784 
   1785     mDirty = true;
   1786 }
   1787 
   1788 void OpenGLRenderer::drawShape(float left, float top, PathTexture* texture,
   1789         const SkPaint* paint) {
   1790     if (!texture) return;
   1791     const AutoTexture autoCleanup(texture);
   1792 
   1793     const float x = left + texture->left - texture->offset;
   1794     const float y = top + texture->top - texture->offset;
   1795 
   1796     drawPathTexture(texture, x, y, paint);
   1797 
   1798     mDirty = true;
   1799 }
   1800 
   1801 void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
   1802         float rx, float ry, const SkPaint* p) {
   1803     if (mState.currentlyIgnored()
   1804             || quickRejectSetupScissor(left, top, right, bottom, p)
   1805             || PaintUtils::paintWillNotDraw(*p)) {
   1806         return;
   1807     }
   1808 
   1809     if (p->getPathEffect() != nullptr) {
   1810         mCaches.textureState().activateTexture(0);
   1811         PathTexture* texture = mCaches.pathCache.getRoundRect(
   1812                 right - left, bottom - top, rx, ry, p);
   1813         drawShape(left, top, texture, p);
   1814     } else {
   1815         const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
   1816                 *currentTransform(), *p, right - left, bottom - top, rx, ry);
   1817         drawVertexBuffer(left, top, *vertexBuffer, p);
   1818     }
   1819 }
   1820 
   1821 void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
   1822     if (mState.currentlyIgnored()
   1823             || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
   1824             || PaintUtils::paintWillNotDraw(*p)) {
   1825         return;
   1826     }
   1827 
   1828     if (p->getPathEffect() != nullptr) {
   1829         mCaches.textureState().activateTexture(0);
   1830         PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
   1831         drawShape(x - radius, y - radius, texture, p);
   1832         return;
   1833     }
   1834 
   1835     SkPath path;
   1836     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
   1837         path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
   1838     } else {
   1839         path.addCircle(x, y, radius);
   1840     }
   1841 
   1842 #if !HWUI_NEW_OPS
   1843     if (CC_UNLIKELY(currentSnapshot()->projectionPathMask != nullptr)) {
   1844         // mask ripples with projection mask
   1845         SkPath maskPath = *(currentSnapshot()->projectionPathMask->projectionMask);
   1846 
   1847         Matrix4 screenSpaceTransform;
   1848         currentSnapshot()->buildScreenSpaceTransform(&screenSpaceTransform);
   1849 
   1850         Matrix4 totalTransform;
   1851         totalTransform.loadInverse(screenSpaceTransform);
   1852         totalTransform.multiply(currentSnapshot()->projectionPathMask->projectionMaskTransform);
   1853 
   1854         SkMatrix skTotalTransform;
   1855         totalTransform.copyTo(skTotalTransform);
   1856         maskPath.transform(skTotalTransform);
   1857 
   1858         // Mask the ripple path by the projection mask, now that it's
   1859         // in local space. Note that this can create CCW paths.
   1860         Op(path, maskPath, kIntersect_SkPathOp, &path);
   1861     }
   1862 #endif
   1863     drawConvexPath(path, p);
   1864 }
   1865 
   1866 void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
   1867         const SkPaint* p) {
   1868     if (mState.currentlyIgnored()
   1869             || quickRejectSetupScissor(left, top, right, bottom, p)
   1870             || PaintUtils::paintWillNotDraw(*p)) {
   1871         return;
   1872     }
   1873 
   1874     if (p->getPathEffect() != nullptr) {
   1875         mCaches.textureState().activateTexture(0);
   1876         PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
   1877         drawShape(left, top, texture, p);
   1878     } else {
   1879         SkPath path;
   1880         SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
   1881         if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
   1882             rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
   1883         }
   1884         path.addOval(rect);
   1885         drawConvexPath(path, p);
   1886     }
   1887 }
   1888 
   1889 void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
   1890         float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
   1891     if (mState.currentlyIgnored()
   1892             || quickRejectSetupScissor(left, top, right, bottom, p)
   1893             || PaintUtils::paintWillNotDraw(*p)) {
   1894         return;
   1895     }
   1896 
   1897     // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
   1898     if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
   1899         mCaches.textureState().activateTexture(0);
   1900         PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
   1901                 startAngle, sweepAngle, useCenter, p);
   1902         drawShape(left, top, texture, p);
   1903         return;
   1904     }
   1905     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
   1906     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
   1907         rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
   1908     }
   1909 
   1910     SkPath path;
   1911     if (useCenter) {
   1912         path.moveTo(rect.centerX(), rect.centerY());
   1913     }
   1914     path.arcTo(rect, startAngle, sweepAngle, !useCenter);
   1915     if (useCenter) {
   1916         path.close();
   1917     }
   1918     drawConvexPath(path, p);
   1919 }
   1920 
   1921 void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
   1922         const SkPaint* p) {
   1923     if (mState.currentlyIgnored()
   1924             || quickRejectSetupScissor(left, top, right, bottom, p)
   1925             || PaintUtils::paintWillNotDraw(*p)) {
   1926         return;
   1927     }
   1928 
   1929     if (p->getStyle() != SkPaint::kFill_Style) {
   1930         // only fill style is supported by drawConvexPath, since others have to handle joins
   1931         static_assert(SkPaintDefaults_MiterLimit == 4.0f, "Miter limit has changed");
   1932         if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
   1933                 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
   1934             mCaches.textureState().activateTexture(0);
   1935             PathTexture* texture =
   1936                     mCaches.pathCache.getRect(right - left, bottom - top, p);
   1937             drawShape(left, top, texture, p);
   1938         } else {
   1939             SkPath path;
   1940             SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
   1941             if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
   1942                 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
   1943             }
   1944             path.addRect(rect);
   1945             drawConvexPath(path, p);
   1946         }
   1947     } else {
   1948         if (p->isAntiAlias() && !currentTransform()->isSimple()) {
   1949             SkPath path;
   1950             path.addRect(left, top, right, bottom);
   1951             drawConvexPath(path, p);
   1952         } else {
   1953             drawColorRect(left, top, right, bottom, p);
   1954 
   1955             mDirty = true;
   1956         }
   1957     }
   1958 }
   1959 
   1960 void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const glyph_t* glyphs,
   1961         int count, const float* positions,
   1962         FontRenderer& fontRenderer, int alpha, float x, float y) {
   1963     mCaches.textureState().activateTexture(0);
   1964 
   1965     PaintUtils::TextShadow textShadow;
   1966     if (!PaintUtils::getTextShadow(paint, &textShadow)) {
   1967         LOG_ALWAYS_FATAL("failed to query shadow attributes");
   1968     }
   1969 
   1970     // NOTE: The drop shadow will not perform gamma correction
   1971     //       if shader-based correction is enabled
   1972     mCaches.dropShadowCache.setFontRenderer(fontRenderer);
   1973     ShadowTexture* texture = mCaches.dropShadowCache.get(
   1974             paint, glyphs, count, textShadow.radius, positions);
   1975     // If the drop shadow exceeds the max texture size or couldn't be
   1976     // allocated, skip drawing
   1977     if (!texture) return;
   1978     const AutoTexture autoCleanup(texture);
   1979 
   1980     const float sx = x - texture->left + textShadow.dx;
   1981     const float sy = y - texture->top + textShadow.dy;
   1982 
   1983     Glop glop;
   1984     GlopBuilder(mRenderState, mCaches, &glop)
   1985             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   1986             .setMeshTexturedUnitQuad(nullptr)
   1987             .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
   1988             .setTransform(*currentSnapshot(),  TransformFlags::None)
   1989             .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height()))
   1990             .build();
   1991     renderGlop(glop);
   1992 }
   1993 
   1994 // TODO: remove this, once mState.currentlyIgnored captures snapshot alpha
   1995 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
   1996     float alpha = (PaintUtils::hasTextShadow(paint)
   1997             ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
   1998     return MathUtils::isZero(alpha)
   1999             && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
   2000 }
   2001 
   2002 bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const {
   2003     if (CC_LIKELY(transform.isPureTranslate())) {
   2004         outMatrix->setIdentity();
   2005         return false;
   2006     } else if (CC_UNLIKELY(transform.isPerspective())) {
   2007         outMatrix->setIdentity();
   2008         return true;
   2009     }
   2010 
   2011     /**
   2012      * Input is a non-perspective, scaling transform. Generate a scale-only transform,
   2013      * with values rounded to the nearest int.
   2014      */
   2015     float sx, sy;
   2016     transform.decomposeScale(sx, sy);
   2017     outMatrix->setScale(
   2018             roundf(std::max(1.0f, sx)),
   2019             roundf(std::max(1.0f, sy)));
   2020     return true;
   2021 }
   2022 
   2023 int OpenGLRenderer::getSaveCount() const {
   2024     return mState.getSaveCount();
   2025 }
   2026 
   2027 int OpenGLRenderer::save(int flags) {
   2028     return mState.save(flags);
   2029 }
   2030 
   2031 void OpenGLRenderer::restore() {
   2032     mState.restore();
   2033 }
   2034 
   2035 void OpenGLRenderer::restoreToCount(int saveCount) {
   2036     mState.restoreToCount(saveCount);
   2037 }
   2038 
   2039 
   2040 void OpenGLRenderer::translate(float dx, float dy, float dz) {
   2041     mState.translate(dx, dy, dz);
   2042 }
   2043 
   2044 void OpenGLRenderer::rotate(float degrees) {
   2045     mState.rotate(degrees);
   2046 }
   2047 
   2048 void OpenGLRenderer::scale(float sx, float sy) {
   2049     mState.scale(sx, sy);
   2050 }
   2051 
   2052 void OpenGLRenderer::skew(float sx, float sy) {
   2053     mState.skew(sx, sy);
   2054 }
   2055 
   2056 void OpenGLRenderer::setLocalMatrix(const Matrix4& matrix) {
   2057     mState.setMatrix(mBaseTransform);
   2058     mState.concatMatrix(matrix);
   2059 }
   2060 
   2061 void OpenGLRenderer::setLocalMatrix(const SkMatrix& matrix) {
   2062     mState.setMatrix(mBaseTransform);
   2063     mState.concatMatrix(matrix);
   2064 }
   2065 
   2066 void OpenGLRenderer::concatMatrix(const Matrix4& matrix) {
   2067     mState.concatMatrix(matrix);
   2068 }
   2069 
   2070 bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
   2071     return mState.clipRect(left, top, right, bottom, op);
   2072 }
   2073 
   2074 bool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
   2075     return mState.clipPath(path, op);
   2076 }
   2077 
   2078 bool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
   2079     return mState.clipRegion(region, op);
   2080 }
   2081 
   2082 void OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
   2083     mState.setClippingOutline(allocator, outline);
   2084 }
   2085 
   2086 void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator,
   2087         const Rect& rect, float radius, bool highPriority) {
   2088     mState.setClippingRoundRect(allocator, rect, radius, highPriority);
   2089 }
   2090 
   2091 void OpenGLRenderer::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
   2092     mState.setProjectionPathMask(allocator, path);
   2093 }
   2094 
   2095 void OpenGLRenderer::drawText(const glyph_t* glyphs, int bytesCount, int count, float x, float y,
   2096         const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
   2097         DrawOpMode drawOpMode) {
   2098 
   2099     if (drawOpMode == DrawOpMode::kImmediate) {
   2100         // The checks for corner-case ignorable text and quick rejection is only done for immediate
   2101         // drawing as ops from DeferredDisplayList are already filtered for these
   2102         if (glyphs == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
   2103                 quickRejectSetupScissor(bounds)) {
   2104             return;
   2105         }
   2106     }
   2107 
   2108     const float oldX = x;
   2109     const float oldY = y;
   2110 
   2111     const mat4& transform = *currentTransform();
   2112     const bool pureTranslate = transform.isPureTranslate();
   2113 
   2114     if (CC_LIKELY(pureTranslate)) {
   2115         x = floorf(x + transform.getTranslateX() + 0.5f);
   2116         y = floorf(y + transform.getTranslateY() + 0.5f);
   2117     }
   2118 
   2119     int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha;
   2120     SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint);
   2121 
   2122     FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer();
   2123 
   2124     if (CC_UNLIKELY(PaintUtils::hasTextShadow(paint))) {
   2125         fontRenderer.setFont(paint, SkMatrix::I());
   2126         drawTextShadow(paint, glyphs, count, positions, fontRenderer,
   2127                 alpha, oldX, oldY);
   2128     }
   2129 
   2130     const bool hasActiveLayer = hasLayer();
   2131 
   2132     // We only pass a partial transform to the font renderer. That partial
   2133     // matrix defines how glyphs are rasterized. Typically we want glyphs
   2134     // to be rasterized at their final size on screen, which means the partial
   2135     // matrix needs to take the scale factor into account.
   2136     // When a partial matrix is used to transform glyphs during rasterization,
   2137     // the mesh is generated with the inverse transform (in the case of scale,
   2138     // the mesh is generated at 1.0 / scale for instance.) This allows us to
   2139     // apply the full transform matrix at draw time in the vertex shader.
   2140     // Applying the full matrix in the shader is the easiest way to handle
   2141     // rotation and perspective and allows us to always generated quads in the
   2142     // font renderer which greatly simplifies the code, clipping in particular.
   2143     SkMatrix fontTransform;
   2144     bool linearFilter = findBestFontTransform(transform, &fontTransform)
   2145             || fabs(y - (int) y) > 0.0f
   2146             || fabs(x - (int) x) > 0.0f;
   2147     fontRenderer.setFont(paint, fontTransform);
   2148     fontRenderer.setTextureFiltering(linearFilter);
   2149 
   2150     // TODO: Implement better clipping for scaled/rotated text
   2151     const Rect* clip = !pureTranslate ? nullptr : &mState.currentRenderTargetClip();
   2152     Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
   2153 
   2154     bool status;
   2155 #if HWUI_NEW_OPS
   2156     LOG_ALWAYS_FATAL("unsupported");
   2157     TextDrawFunctor functor(nullptr, nullptr, nullptr, x, y, pureTranslate, alpha, mode, paint);
   2158 #else
   2159     TextDrawFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
   2160 #endif
   2161 
   2162     // don't call issuedrawcommand, do it at end of batch
   2163     bool forceFinish = (drawOpMode != DrawOpMode::kDefer);
   2164     if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
   2165         SkPaint paintCopy(*paint);
   2166         paintCopy.setTextAlign(SkPaint::kLeft_Align);
   2167         status = fontRenderer.renderPosText(&paintCopy, clip, glyphs, count, x, y,
   2168                 positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
   2169     } else {
   2170         status = fontRenderer.renderPosText(paint, clip, glyphs, count, x, y,
   2171                 positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
   2172     }
   2173 
   2174     if ((status || drawOpMode != DrawOpMode::kImmediate) && hasActiveLayer) {
   2175         if (!pureTranslate) {
   2176             transform.mapRect(layerBounds);
   2177         }
   2178         dirtyLayerUnchecked(layerBounds, getRegion());
   2179     }
   2180 
   2181     mDirty = true;
   2182 }
   2183 
   2184 void OpenGLRenderer::drawTextOnPath(const glyph_t* glyphs, int bytesCount, int count,
   2185         const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
   2186     if (glyphs == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
   2187         return;
   2188     }
   2189 
   2190     // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
   2191     mRenderState.scissor().setEnabled(true);
   2192 
   2193     FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer();
   2194     fontRenderer.setFont(paint, SkMatrix::I());
   2195     fontRenderer.setTextureFiltering(true);
   2196 
   2197     int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha;
   2198     SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint);
   2199 #if HWUI_NEW_OPS
   2200     LOG_ALWAYS_FATAL("unsupported");
   2201     TextDrawFunctor functor(nullptr, nullptr, nullptr, 0.0f, 0.0f, false, alpha, mode, paint);
   2202 #else
   2203     TextDrawFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
   2204 #endif
   2205 
   2206     const Rect* clip = &writableSnapshot()->getLocalClip();
   2207     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
   2208 
   2209     if (fontRenderer.renderTextOnPath(paint, clip, glyphs, count, path,
   2210             hOffset, vOffset, hasLayer() ? &bounds : nullptr, &functor)) {
   2211         dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
   2212         mDirty = true;
   2213     }
   2214 }
   2215 
   2216 void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
   2217     if (mState.currentlyIgnored()) return;
   2218 
   2219     mCaches.textureState().activateTexture(0);
   2220 
   2221     PathTexture* texture = mCaches.pathCache.get(path, paint);
   2222     if (!texture) return;
   2223 
   2224     const float x = texture->left - texture->offset;
   2225     const float y = texture->top - texture->offset;
   2226 
   2227     drawPathTexture(texture, x, y, paint);
   2228 
   2229     if (texture->cleanup) {
   2230         mCaches.pathCache.remove(path, paint);
   2231     }
   2232     mDirty = true;
   2233 }
   2234 
   2235 void OpenGLRenderer::drawLayer(Layer* layer) {
   2236     if (!layer) {
   2237         return;
   2238     }
   2239 
   2240     mat4* transform = nullptr;
   2241     if (layer->isTextureLayer()) {
   2242         transform = &layer->getTransform();
   2243         if (!transform->isIdentity()) {
   2244             save(SaveFlags::Matrix);
   2245             concatMatrix(*transform);
   2246         }
   2247     }
   2248 
   2249     bool clipRequired = false;
   2250     const bool rejected = mState.calculateQuickRejectForScissor(
   2251             0, 0, layer->layer.getWidth(), layer->layer.getHeight(),
   2252             &clipRequired, nullptr, false);
   2253 
   2254     if (rejected) {
   2255         if (transform && !transform->isIdentity()) {
   2256             restore();
   2257         }
   2258         return;
   2259     }
   2260 
   2261     EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
   2262             x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired);
   2263 
   2264     updateLayer(layer, true);
   2265 
   2266     mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
   2267     mCaches.textureState().activateTexture(0);
   2268 
   2269     if (CC_LIKELY(!layer->region.isEmpty())) {
   2270         if (layer->region.isRect()) {
   2271             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
   2272                     composeLayerRect(layer, layer->regionRect));
   2273         } else if (layer->mesh) {
   2274             Glop glop;
   2275             GlopBuilder(mRenderState, mCaches, &glop)
   2276                     .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   2277                     .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
   2278                     .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
   2279                     .setTransform(*currentSnapshot(),  TransformFlags::None)
   2280                     .setModelViewOffsetRectSnap(0, 0, Rect(layer->layer.getWidth(), layer->layer.getHeight()))
   2281                     .build();
   2282             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
   2283 #if DEBUG_LAYERS_AS_REGIONS
   2284             drawRegionRectsDebug(layer->region);
   2285 #endif
   2286         }
   2287 
   2288         if (layer->debugDrawUpdate) {
   2289             layer->debugDrawUpdate = false;
   2290 
   2291             SkPaint paint;
   2292             paint.setColor(0x7f00ff00);
   2293             drawColorRect(0, 0, layer->layer.getWidth(), layer->layer.getHeight(), &paint);
   2294         }
   2295     }
   2296     layer->hasDrawnSinceUpdate = true;
   2297 
   2298     if (transform && !transform->isIdentity()) {
   2299         restore();
   2300     }
   2301 
   2302     mDirty = true;
   2303 }
   2304 
   2305 ///////////////////////////////////////////////////////////////////////////////
   2306 // Draw filters
   2307 ///////////////////////////////////////////////////////////////////////////////
   2308 void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) {
   2309     // We should never get here since we apply the draw filter when stashing
   2310     // the paints in the DisplayList.
   2311     LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters");
   2312 }
   2313 
   2314 ///////////////////////////////////////////////////////////////////////////////
   2315 // Drawing implementation
   2316 ///////////////////////////////////////////////////////////////////////////////
   2317 
   2318 Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) {
   2319     Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef());
   2320     if (!texture) {
   2321         return mCaches.textureCache.get(bitmap);
   2322     }
   2323     return texture;
   2324 }
   2325 
   2326 void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y,
   2327         const SkPaint* paint) {
   2328     if (quickRejectSetupScissor(x, y, x + texture->width(), y + texture->height())) {
   2329         return;
   2330     }
   2331 
   2332     Glop glop;
   2333     GlopBuilder(mRenderState, mCaches, &glop)
   2334             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   2335             .setMeshTexturedUnitQuad(nullptr)
   2336             .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
   2337             .setTransform(*currentSnapshot(),  TransformFlags::None)
   2338             .setModelViewMapUnitToRect(Rect(x, y, x + texture->width(), y + texture->height()))
   2339             .build();
   2340     renderGlop(glop);
   2341 }
   2342 
   2343 void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
   2344     if (mState.currentlyIgnored()) {
   2345         return;
   2346     }
   2347 
   2348     drawColorRects(rects, count, paint, false, true, true);
   2349 }
   2350 
   2351 void OpenGLRenderer::drawShadow(float casterAlpha,
   2352         const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
   2353     if (mState.currentlyIgnored()) return;
   2354 
   2355     // TODO: use quickRejectWithScissor. For now, always force enable scissor.
   2356     mRenderState.scissor().setEnabled(true);
   2357 
   2358     SkPaint paint;
   2359     paint.setAntiAlias(true); // want to use AlphaVertex
   2360 
   2361     // The caller has made sure casterAlpha > 0.
   2362     float ambientShadowAlpha = mAmbientShadowAlpha;
   2363     if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) {
   2364         ambientShadowAlpha = Properties::overrideAmbientShadowStrength;
   2365     }
   2366     if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
   2367         paint.setARGB(casterAlpha * ambientShadowAlpha, 0, 0, 0);
   2368         drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
   2369     }
   2370 
   2371     float spotShadowAlpha = mSpotShadowAlpha;
   2372     if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) {
   2373         spotShadowAlpha = Properties::overrideSpotShadowStrength;
   2374     }
   2375     if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
   2376         paint.setARGB(casterAlpha * spotShadowAlpha, 0, 0, 0);
   2377         drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
   2378     }
   2379 
   2380     mDirty=true;
   2381 }
   2382 
   2383 void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
   2384         bool ignoreTransform, bool dirty, bool clip) {
   2385     if (count == 0) {
   2386         return;
   2387     }
   2388 
   2389     float left = FLT_MAX;
   2390     float top = FLT_MAX;
   2391     float right = FLT_MIN;
   2392     float bottom = FLT_MIN;
   2393 
   2394     Vertex mesh[count];
   2395     Vertex* vertex = mesh;
   2396 
   2397     for (int index = 0; index < count; index += 4) {
   2398         float l = rects[index + 0];
   2399         float t = rects[index + 1];
   2400         float r = rects[index + 2];
   2401         float b = rects[index + 3];
   2402 
   2403         Vertex::set(vertex++, l, t);
   2404         Vertex::set(vertex++, r, t);
   2405         Vertex::set(vertex++, l, b);
   2406         Vertex::set(vertex++, r, b);
   2407 
   2408         left = std::min(left, l);
   2409         top = std::min(top, t);
   2410         right = std::max(right, r);
   2411         bottom = std::max(bottom, b);
   2412     }
   2413 
   2414     if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
   2415         return;
   2416     }
   2417 
   2418     const int transformFlags = ignoreTransform
   2419             ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
   2420     Glop glop;
   2421     GlopBuilder(mRenderState, mCaches, &glop)
   2422             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   2423             .setMeshIndexedQuads(&mesh[0], count / 4)
   2424             .setFillPaint(*paint, currentSnapshot()->alpha)
   2425             .setTransform(*currentSnapshot(), transformFlags)
   2426             .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
   2427             .build();
   2428     renderGlop(glop);
   2429 }
   2430 
   2431 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
   2432         const SkPaint* paint, bool ignoreTransform) {
   2433     const int transformFlags = ignoreTransform
   2434             ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
   2435     Glop glop;
   2436     GlopBuilder(mRenderState, mCaches, &glop)
   2437             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
   2438             .setMeshUnitQuad()
   2439             .setFillPaint(*paint, currentSnapshot()->alpha)
   2440             .setTransform(*currentSnapshot(), transformFlags)
   2441             .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
   2442             .build();
   2443     renderGlop(glop);
   2444 }
   2445 
   2446 float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
   2447     return (layer->getAlpha() / 255.0f) * currentSnapshot()->alpha;
   2448 }
   2449 
   2450 }; // namespace uirenderer
   2451 }; // namespace android
   2452