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