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