OpenGLRenderer.cpp revision 31dbfc1b3e18f24d9a34c4e600c2048e8d244c14
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        renderGlop(glop);
862        return;
863    }
864
865    float alpha = getLayerAlpha(layer);
866    setupDraw();
867    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
868        setupDrawWithTexture();
869    } else {
870        setupDrawWithExternalTexture();
871    }
872    setupDrawTextureTransform();
873    setupDrawColor(alpha, alpha, alpha, alpha);
874    setupDrawColorFilter(layer->getColorFilter());
875    setupDrawBlending(layer);
876    setupDrawProgram();
877    setupDrawPureColorUniforms();
878    setupDrawColorFilterUniforms(layer->getColorFilter());
879    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
880        setupDrawTexture(layer->getTextureId());
881    } else {
882        setupDrawExternalTexture(layer->getTextureId());
883    }
884    if (currentTransform()->isPureTranslate()
885            && !layer->getForceFilter()
886            && layer->getWidth() == (uint32_t) rect.getWidth()
887            && layer->getHeight() == (uint32_t) rect.getHeight()) {
888        const float x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
889        const float y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
890
891        layer->setFilter(GL_NEAREST);
892        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
893                x, y, x + rect.getWidth(), y + rect.getHeight(), true);
894    } else {
895        layer->setFilter(GL_LINEAR);
896        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
897                rect.left, rect.top, rect.right, rect.bottom);
898    }
899    setupDrawTextureTransformUniforms(layer->getTexTransform());
900    setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
901
902    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
903}
904
905void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
906    if (layer->isTextureLayer()) {
907        EVENT_LOGD("composeTextureLayerRect");
908        resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
909        drawTextureLayer(layer, rect);
910        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
911    } else {
912        EVENT_LOGD("composeHardwareLayerRect");
913
914        if (USE_GLOPS) {
915            Blend::ModeOrderSwap modeUsage = swap ?
916                    Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap;
917            const Matrix4& transform = swap ? Matrix4::identity() : *currentTransform();
918            bool snap = !swap
919                    && layer->getWidth() == static_cast<uint32_t>(rect.getWidth())
920                    && layer->getHeight() == static_cast<uint32_t>(rect.getHeight());
921            Glop glop;
922            GlopBuilder(mRenderState, mCaches, &glop)
923                    .setMeshTexturedUvQuad(nullptr, layer->texCoords)
924                    .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), modeUsage)
925                    .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
926                    .setModelViewMapUnitToRectOptionalSnap(snap, rect)
927                    .setRoundRectClipState(currentSnapshot()->roundRectClipState)
928                    .build();
929            renderGlop(glop);
930            return;
931        }
932
933        const Rect& texCoords = layer->texCoords;
934        resetDrawTextureTexCoords(texCoords.left, texCoords.top,
935                texCoords.right, texCoords.bottom);
936
937        float x = rect.left;
938        float y = rect.top;
939        bool simpleTransform = currentTransform()->isPureTranslate()
940                && layer->getWidth() == (uint32_t) rect.getWidth()
941                && layer->getHeight() == (uint32_t) rect.getHeight();
942
943        if (simpleTransform) {
944            // When we're swapping, the layer is already in screen coordinates
945            if (!swap) {
946                x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
947                y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
948            }
949
950            layer->setFilter(GL_NEAREST, true);
951        } else {
952            layer->setFilter(GL_LINEAR, true);
953        }
954
955        SkPaint layerPaint;
956        layerPaint.setAlpha(getLayerAlpha(layer) * 255);
957        layerPaint.setXfermodeMode(layer->getMode());
958        layerPaint.setColorFilter(layer->getColorFilter());
959
960        bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f;
961        drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
962                layer->getTextureId(), &layerPaint, blend,
963                &mMeshVertices[0].x, &mMeshVertices[0].u,
964                GL_TRIANGLE_STRIP, kUnitQuadCount, swap, swap || simpleTransform);
965
966        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
967    }
968}
969
970/**
971 * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
972 * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
973 * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
974 * by saveLayer's restore
975 */
976#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) {                             \
977        DRAW_COMMAND;                                                            \
978        if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
979            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);                 \
980            DRAW_COMMAND;                                                        \
981            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                     \
982        }                                                                        \
983    }
984
985#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
986
987// This class is purely for inspection. It inherits from SkShader, but Skia does not know how to
988// use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque.
989class LayerShader : public SkShader {
990public:
991    LayerShader(Layer* layer, const SkMatrix* localMatrix)
992    : INHERITED(localMatrix)
993    , mLayer(layer) {
994    }
995
996    virtual bool asACustomShader(void** data) const override {
997        if (data) {
998            *data = static_cast<void*>(mLayer);
999        }
1000        return true;
1001    }
1002
1003    virtual bool isOpaque() const override {
1004        return !mLayer->isBlend();
1005    }
1006
1007protected:
1008    virtual void shadeSpan(int x, int y, SkPMColor[], int count) {
1009        LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
1010    }
1011
1012    virtual void flatten(SkWriteBuffer&) const override {
1013        LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
1014    }
1015
1016    virtual Factory getFactory() const override {
1017        LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
1018        return nullptr;
1019    }
1020private:
1021    // Unowned.
1022    Layer* mLayer;
1023    typedef SkShader INHERITED;
1024};
1025
1026void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
1027    if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
1028
1029    if (layer->getConvexMask()) {
1030        save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
1031
1032        // clip to the area of the layer the mask can be larger
1033        clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
1034
1035        SkPaint paint;
1036        paint.setAntiAlias(true);
1037        paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
1038
1039        // create LayerShader to map SaveLayer content into subsequent draw
1040        SkMatrix shaderMatrix;
1041        shaderMatrix.setTranslate(rect.left, rect.bottom);
1042        shaderMatrix.preScale(1, -1);
1043        LayerShader layerShader(layer, &shaderMatrix);
1044        paint.setShader(&layerShader);
1045
1046        // Since the drawing primitive is defined in local drawing space,
1047        // we don't need to modify the draw matrix
1048        const SkPath* maskPath = layer->getConvexMask();
1049        DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
1050
1051        paint.setShader(nullptr);
1052        restore();
1053
1054        return;
1055    }
1056
1057    if (layer->region.isRect()) {
1058        layer->setRegionAsRect();
1059
1060        DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
1061
1062        layer->region.clear();
1063        return;
1064    }
1065
1066    EVENT_LOGD("composeLayerRegion");
1067    // standard Region based draw
1068    size_t count;
1069    const android::Rect* rects;
1070    Region safeRegion;
1071    if (CC_LIKELY(hasRectToRectTransform())) {
1072        rects = layer->region.getArray(&count);
1073    } else {
1074        safeRegion = Region::createTJunctionFreeRegion(layer->region);
1075        rects = safeRegion.getArray(&count);
1076    }
1077
1078    const float texX = 1.0f / float(layer->getWidth());
1079    const float texY = 1.0f / float(layer->getHeight());
1080    const float height = rect.getHeight();
1081
1082    if (USE_GLOPS) {
1083        TextureVertex quadVertices[count * 4];
1084        //std::unique_ptr<TextureVertex[]> quadVertices(new TextureVertex[count * 4]);
1085        TextureVertex* mesh = &quadVertices[0];
1086        for (size_t i = 0; i < count; i++) {
1087            const android::Rect* r = &rects[i];
1088
1089            const float u1 = r->left * texX;
1090            const float v1 = (height - r->top) * texY;
1091            const float u2 = r->right * texX;
1092            const float v2 = (height - r->bottom) * texY;
1093
1094            // TODO: Reject quads outside of the clip
1095            TextureVertex::set(mesh++, r->left, r->top, u1, v1);
1096            TextureVertex::set(mesh++, r->right, r->top, u2, v1);
1097            TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
1098            TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
1099        }
1100        Glop glop;
1101        GlopBuilder(mRenderState, mCaches, &glop)
1102                .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6)
1103                .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
1104                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
1105                .setModelViewOffsetRectSnap(0, 0, rect)
1106                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1107                .build();
1108        DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
1109        return;
1110    }
1111
1112    const float alpha = getLayerAlpha(layer);
1113
1114    setupDraw();
1115
1116    // We must get (and therefore bind) the region mesh buffer
1117    // after we setup drawing in case we need to mess with the
1118    // stencil buffer in setupDraw()
1119    TextureVertex* mesh = mCaches.getRegionMesh();
1120    uint32_t numQuads = 0;
1121
1122    setupDrawWithTexture();
1123    setupDrawColor(alpha, alpha, alpha, alpha);
1124    setupDrawColorFilter(layer->getColorFilter());
1125    setupDrawBlending(layer);
1126    setupDrawProgram();
1127    setupDrawDirtyRegionsDisabled();
1128    setupDrawPureColorUniforms();
1129    setupDrawColorFilterUniforms(layer->getColorFilter());
1130    setupDrawTexture(layer->getTextureId());
1131    if (currentTransform()->isPureTranslate()) {
1132        const float x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
1133        const float y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
1134
1135        layer->setFilter(GL_NEAREST);
1136        setupDrawModelView(kModelViewMode_Translate, false,
1137                x, y, x + rect.getWidth(), y + rect.getHeight(), true);
1138    } else {
1139        layer->setFilter(GL_LINEAR);
1140        setupDrawModelView(kModelViewMode_Translate, false,
1141                rect.left, rect.top, rect.right, rect.bottom);
1142    }
1143    setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
1144
1145    for (size_t i = 0; i < count; i++) {
1146        const android::Rect* r = &rects[i];
1147
1148        const float u1 = r->left * texX;
1149        const float v1 = (height - r->top) * texY;
1150        const float u2 = r->right * texX;
1151        const float v2 = (height - r->bottom) * texY;
1152
1153        // TODO: Reject quads outside of the clip
1154        TextureVertex::set(mesh++, r->left, r->top, u1, v1);
1155        TextureVertex::set(mesh++, r->right, r->top, u2, v1);
1156        TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
1157        TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
1158
1159        numQuads++;
1160
1161        if (numQuads >= kMaxNumberOfQuads) {
1162            DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1163                    GL_UNSIGNED_SHORT, nullptr));
1164            numQuads = 0;
1165            mesh = mCaches.getRegionMesh();
1166        }
1167    }
1168
1169    if (numQuads > 0) {
1170        DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1171                GL_UNSIGNED_SHORT, nullptr));
1172    }
1173
1174#if DEBUG_LAYERS_AS_REGIONS
1175    drawRegionRectsDebug(layer->region);
1176#endif
1177
1178    layer->region.clear();
1179}
1180
1181#if DEBUG_LAYERS_AS_REGIONS
1182void OpenGLRenderer::drawRegionRectsDebug(const Region& region) {
1183    size_t count;
1184    const android::Rect* rects = region.getArray(&count);
1185
1186    uint32_t colors[] = {
1187            0x7fff0000, 0x7f00ff00,
1188            0x7f0000ff, 0x7fff00ff,
1189    };
1190
1191    int offset = 0;
1192    int32_t top = rects[0].top;
1193
1194    for (size_t i = 0; i < count; i++) {
1195        if (top != rects[i].top) {
1196            offset ^= 0x2;
1197            top = rects[i].top;
1198        }
1199
1200        SkPaint paint;
1201        paint.setColor(colors[offset + (i & 0x1)]);
1202        Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
1203        drawColorRect(r.left, r.top, r.right, r.bottom, paint);
1204    }
1205}
1206#endif
1207
1208void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) {
1209    Vector<float> rects;
1210
1211    SkRegion::Iterator it(region);
1212    while (!it.done()) {
1213        const SkIRect& r = it.rect();
1214        rects.push(r.fLeft);
1215        rects.push(r.fTop);
1216        rects.push(r.fRight);
1217        rects.push(r.fBottom);
1218        it.next();
1219    }
1220
1221    drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false);
1222}
1223
1224void OpenGLRenderer::dirtyLayer(const float left, const float top,
1225        const float right, const float bottom, const Matrix4& transform) {
1226    if (hasLayer()) {
1227        Rect bounds(left, top, right, bottom);
1228        transform.mapRect(bounds);
1229        dirtyLayerUnchecked(bounds, getRegion());
1230    }
1231}
1232
1233void OpenGLRenderer::dirtyLayer(const float left, const float top,
1234        const float right, const float bottom) {
1235    if (hasLayer()) {
1236        Rect bounds(left, top, right, bottom);
1237        dirtyLayerUnchecked(bounds, getRegion());
1238    }
1239}
1240
1241void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
1242    if (bounds.intersect(mState.currentClipRect())) {
1243        bounds.snapToPixelBoundaries();
1244        android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
1245        if (!dirty.isEmpty()) {
1246            region->orSelf(dirty);
1247        }
1248    }
1249}
1250
1251void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
1252    GLsizei elementsCount = quadsCount * 6;
1253    while (elementsCount > 0) {
1254        GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
1255
1256        setupDrawIndexedVertices(&mesh[0].x);
1257        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr);
1258
1259        elementsCount -= drawCount;
1260        // Though there are 4 vertices in a quad, we use 6 indices per
1261        // quad to draw with GL_TRIANGLES
1262        mesh += (drawCount / 6) * 4;
1263    }
1264}
1265
1266void OpenGLRenderer::clearLayerRegions() {
1267    const size_t quadCount = mLayers.size();
1268    if (quadCount == 0) return;
1269
1270    if (!mState.currentlyIgnored()) {
1271        EVENT_LOGD("clearLayerRegions");
1272        // Doing several glScissor/glClear here can negatively impact
1273        // GPUs with a tiler architecture, instead we draw quads with
1274        // the Clear blending mode
1275
1276        // The list contains bounds that have already been clipped
1277        // against their initial clip rect, and the current clip
1278        // is likely different so we need to disable clipping here
1279        bool scissorChanged = mRenderState.scissor().setEnabled(false);
1280
1281        Vertex mesh[quadCount * 4];
1282        Vertex* vertex = mesh;
1283
1284        for (uint32_t i = 0; i < quadCount; i++) {
1285            const Rect& bounds = mLayers[i];
1286
1287            Vertex::set(vertex++, bounds.left, bounds.top);
1288            Vertex::set(vertex++, bounds.right, bounds.top);
1289            Vertex::set(vertex++, bounds.left, bounds.bottom);
1290            Vertex::set(vertex++, bounds.right, bounds.bottom);
1291        }
1292        // We must clear the list of dirty rects before we
1293        // call setupDraw() to prevent stencil setup to do
1294        // the same thing again
1295        mLayers.clear();
1296
1297        if (USE_GLOPS) {
1298            Glop glop;
1299            GlopBuilder(mRenderState, mCaches, &glop)
1300                    .setMeshIndexedQuads(&mesh[0], quadCount)
1301                    .setFillClear()
1302                    .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
1303                    .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect()))
1304                    .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1305                    .build();
1306            renderGlop(glop, false);
1307        } else {
1308            SkPaint clearPaint;
1309            clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
1310
1311            setupDraw(false);
1312            setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
1313            setupDrawBlending(&clearPaint, true);
1314            setupDrawProgram();
1315            setupDrawPureColorUniforms();
1316            setupDrawModelView(kModelViewMode_Translate, false,
1317                    0.0f, 0.0f, 0.0f, 0.0f, true);
1318
1319            issueIndexedQuadDraw(&mesh[0], quadCount);
1320        }
1321
1322        if (scissorChanged) mRenderState.scissor().setEnabled(true);
1323    } else {
1324        mLayers.clear();
1325    }
1326}
1327
1328///////////////////////////////////////////////////////////////////////////////
1329// State Deferral
1330///////////////////////////////////////////////////////////////////////////////
1331
1332bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
1333    const Rect& currentClip = mState.currentClipRect();
1334    const mat4* currentMatrix = currentTransform();
1335
1336    if (stateDeferFlags & kStateDeferFlag_Draw) {
1337        // state has bounds initialized in local coordinates
1338        if (!state.mBounds.isEmpty()) {
1339            currentMatrix->mapRect(state.mBounds);
1340            Rect clippedBounds(state.mBounds);
1341            // NOTE: if we ever want to use this clipping info to drive whether the scissor
1342            // is used, it should more closely duplicate the quickReject logic (in how it uses
1343            // snapToPixelBoundaries)
1344
1345            if (!clippedBounds.intersect(currentClip)) {
1346                // quick rejected
1347                return true;
1348            }
1349
1350            state.mClipSideFlags = kClipSide_None;
1351            if (!currentClip.contains(state.mBounds)) {
1352                int& flags = state.mClipSideFlags;
1353                // op partially clipped, so record which sides are clipped for clip-aware merging
1354                if (currentClip.left > state.mBounds.left) flags |= kClipSide_Left;
1355                if (currentClip.top > state.mBounds.top) flags |= kClipSide_Top;
1356                if (currentClip.right < state.mBounds.right) flags |= kClipSide_Right;
1357                if (currentClip.bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
1358            }
1359            state.mBounds.set(clippedBounds);
1360        } else {
1361            // Empty bounds implies size unknown. Label op as conservatively clipped to disable
1362            // overdraw avoidance (since we don't know what it overlaps)
1363            state.mClipSideFlags = kClipSide_ConservativeFull;
1364            state.mBounds.set(currentClip);
1365        }
1366    }
1367
1368    state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
1369    if (state.mClipValid) {
1370        state.mClip.set(currentClip);
1371    }
1372
1373    // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
1374    // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
1375    state.mMatrix.load(*currentMatrix);
1376    state.mDrawModifiers = mDrawModifiers;
1377    state.mAlpha = currentSnapshot()->alpha;
1378
1379    // always store/restore, since it's just a pointer
1380    state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
1381    return false;
1382}
1383
1384void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
1385    setMatrix(state.mMatrix);
1386    writableSnapshot()->alpha = state.mAlpha;
1387    mDrawModifiers = state.mDrawModifiers;
1388    writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
1389
1390    if (state.mClipValid && !skipClipRestore) {
1391        writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
1392                state.mClip.right, state.mClip.bottom);
1393        dirtyClip();
1394    }
1395}
1396
1397/**
1398 * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done
1399 * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at
1400 * least one op is clipped), or disabled entirely (because no merged op is clipped)
1401 *
1402 * This method should be called when restoreDisplayState() won't be restoring the clip
1403 */
1404void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
1405    if (clipRect != nullptr) {
1406        writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
1407    } else {
1408        writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight());
1409    }
1410    dirtyClip();
1411    bool enableScissor = (clipRect != nullptr) || mScissorOptimizationDisabled;
1412    mRenderState.scissor().setEnabled(enableScissor);
1413}
1414
1415///////////////////////////////////////////////////////////////////////////////
1416// Clipping
1417///////////////////////////////////////////////////////////////////////////////
1418
1419void OpenGLRenderer::setScissorFromClip() {
1420    Rect clip(mState.currentClipRect());
1421    clip.snapToPixelBoundaries();
1422
1423    if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom,
1424            clip.getWidth(), clip.getHeight())) {
1425        mState.setDirtyClip(false);
1426    }
1427}
1428
1429void OpenGLRenderer::ensureStencilBuffer() {
1430    // Thanks to the mismatch between EGL and OpenGL ES FBO we
1431    // cannot attach a stencil buffer to fbo0 dynamically. Let's
1432    // just hope we have one when hasLayer() returns false.
1433    if (hasLayer()) {
1434        attachStencilBufferToLayer(currentSnapshot()->layer);
1435    }
1436}
1437
1438void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
1439    // The layer's FBO is already bound when we reach this stage
1440    if (!layer->getStencilRenderBuffer()) {
1441        // GL_QCOM_tiled_rendering doesn't like it if a renderbuffer
1442        // is attached after we initiated tiling. We must turn it off,
1443        // attach the new render buffer then turn tiling back on
1444        endTiling();
1445
1446        RenderBuffer* buffer = mCaches.renderBufferCache.get(
1447                Stencil::getSmallestStencilFormat(),
1448                layer->getWidth(), layer->getHeight());
1449        layer->setStencilRenderBuffer(buffer);
1450
1451        startTiling(layer->clipRect, layer->layer.getHeight());
1452    }
1453}
1454
1455static void handlePoint(std::vector<Vertex>& rectangleVertices, const Matrix4& transform,
1456        float x, float y) {
1457    Vertex v;
1458    v.x = x;
1459    v.y = y;
1460    transform.mapPoint(v.x, v.y);
1461    rectangleVertices.push_back(v);
1462}
1463
1464static void handlePointNoTransform(std::vector<Vertex>& rectangleVertices, float x, float y) {
1465    Vertex v;
1466    v.x = x;
1467    v.y = y;
1468    rectangleVertices.push_back(v);
1469}
1470
1471void OpenGLRenderer::drawRectangleList(const RectangleList& rectangleList) {
1472    int quadCount = rectangleList.getTransformedRectanglesCount();
1473    std::vector<Vertex> rectangleVertices(quadCount * 4);
1474    Rect scissorBox = rectangleList.calculateBounds();
1475    scissorBox.snapToPixelBoundaries();
1476    for (int i = 0; i < quadCount; ++i) {
1477        const TransformedRectangle& tr(rectangleList.getTransformedRectangle(i));
1478        const Matrix4& transform = tr.getTransform();
1479        Rect bounds = tr.getBounds();
1480        if (transform.rectToRect()) {
1481            transform.mapRect(bounds);
1482            if (!bounds.intersect(scissorBox)) {
1483                bounds.setEmpty();
1484            } else {
1485                handlePointNoTransform(rectangleVertices, bounds.left, bounds.top);
1486                handlePointNoTransform(rectangleVertices, bounds.right, bounds.top);
1487                handlePointNoTransform(rectangleVertices, bounds.left, bounds.bottom);
1488                handlePointNoTransform(rectangleVertices, bounds.right, bounds.bottom);
1489            }
1490        } else {
1491            handlePoint(rectangleVertices, transform, bounds.left, bounds.top);
1492            handlePoint(rectangleVertices, transform, bounds.right, bounds.top);
1493            handlePoint(rectangleVertices, transform, bounds.left, bounds.bottom);
1494            handlePoint(rectangleVertices, transform, bounds.right, bounds.bottom);
1495        }
1496    }
1497
1498    mRenderState.scissor().set(scissorBox.left, getViewportHeight() - scissorBox.bottom,
1499            scissorBox.getWidth(), scissorBox.getHeight());
1500
1501    if (USE_GLOPS) {
1502        Glop glop;
1503        GlopBuilder(mRenderState, mCaches, &glop)
1504                .setMeshIndexedQuads(&rectangleVertices[0], rectangleVertices.size() / 4)
1505                .setFillBlack()
1506                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
1507                .setModelViewOffsetRect(0, 0, scissorBox)
1508                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1509                .build();
1510        renderGlop(glop);
1511        return;
1512    }
1513
1514    const SkPaint* paint = nullptr;
1515    setupDraw();
1516    setupDrawNoTexture();
1517    setupDrawColor(0, 0xff * currentSnapshot()->alpha);
1518    setupDrawShader(getShader(paint));
1519    setupDrawColorFilter(getColorFilter(paint));
1520    setupDrawBlending(paint);
1521    setupDrawProgram();
1522    setupDrawDirtyRegionsDisabled();
1523    setupDrawModelView(kModelViewMode_Translate, false,
1524            0.0f, 0.0f, 0.0f, 0.0f, true);
1525    setupDrawColorUniforms(getShader(paint));
1526    setupDrawShaderUniforms(getShader(paint));
1527    setupDrawColorFilterUniforms(getColorFilter(paint));
1528
1529    issueIndexedQuadDraw(&rectangleVertices[0], rectangleVertices.size() / 4);
1530}
1531
1532void OpenGLRenderer::setStencilFromClip() {
1533    if (!mCaches.debugOverdraw) {
1534        if (!currentSnapshot()->clipIsSimple()) {
1535            int incrementThreshold;
1536            EVENT_LOGD("setStencilFromClip - enabling");
1537
1538            // NOTE: The order here is important, we must set dirtyClip to false
1539            //       before any draw call to avoid calling back into this method
1540            mState.setDirtyClip(false);
1541
1542            ensureStencilBuffer();
1543
1544            const ClipArea& clipArea = currentSnapshot()->getClipArea();
1545
1546            bool isRectangleList = clipArea.isRectangleList();
1547            if (isRectangleList) {
1548                incrementThreshold = clipArea.getRectangleList().getTransformedRectanglesCount();
1549            } else {
1550                incrementThreshold = 0;
1551            }
1552
1553            mRenderState.stencil().enableWrite(incrementThreshold);
1554
1555            // Clean and update the stencil, but first make sure we restrict drawing
1556            // to the region's bounds
1557            bool resetScissor = mRenderState.scissor().setEnabled(true);
1558            if (resetScissor) {
1559                // The scissor was not set so we now need to update it
1560                setScissorFromClip();
1561            }
1562
1563            mRenderState.stencil().clear();
1564
1565            // stash and disable the outline clip state, since stencil doesn't account for outline
1566            bool storedSkipOutlineClip = mSkipOutlineClip;
1567            mSkipOutlineClip = true;
1568
1569            SkPaint paint;
1570            paint.setColor(SK_ColorBLACK);
1571            paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1572
1573            if (isRectangleList) {
1574                drawRectangleList(clipArea.getRectangleList());
1575            } else {
1576                // NOTE: We could use the region contour path to generate a smaller mesh
1577                //       Since we are using the stencil we could use the red book path
1578                //       drawing technique. It might increase bandwidth usage though.
1579
1580                // The last parameter is important: we are not drawing in the color buffer
1581                // so we don't want to dirty the current layer, if any
1582                drawRegionRects(clipArea.getClipRegion(), paint, false);
1583            }
1584            if (resetScissor) mRenderState.scissor().setEnabled(false);
1585            mSkipOutlineClip = storedSkipOutlineClip;
1586
1587            mRenderState.stencil().enableTest(incrementThreshold);
1588
1589            // Draw the region used to generate the stencil if the appropriate debug
1590            // mode is enabled
1591            // TODO: Implement for rectangle list clip areas
1592            if (mCaches.debugStencilClip == Caches::kStencilShowRegion &&
1593                    !clipArea.isRectangleList()) {
1594                paint.setColor(0x7f0000ff);
1595                paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
1596                drawRegionRects(currentSnapshot()->getClipRegion(), paint);
1597            }
1598        } else {
1599            EVENT_LOGD("setStencilFromClip - disabling");
1600            mRenderState.stencil().disable();
1601        }
1602    }
1603}
1604
1605/**
1606 * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out.
1607 *
1608 * @param paint if not null, the bounds will be expanded to account for stroke depending on paint
1609 *         style, and tessellated AA ramp
1610 */
1611bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom,
1612        const SkPaint* paint) {
1613    bool snapOut = paint && paint->isAntiAlias();
1614
1615    if (paint && paint->getStyle() != SkPaint::kFill_Style) {
1616        float outset = paint->getStrokeWidth() * 0.5f;
1617        left -= outset;
1618        top -= outset;
1619        right += outset;
1620        bottom += outset;
1621    }
1622
1623    bool clipRequired = false;
1624    bool roundRectClipRequired = false;
1625    if (mState.calculateQuickRejectForScissor(left, top, right, bottom,
1626            &clipRequired, &roundRectClipRequired, snapOut)) {
1627        return true;
1628    }
1629
1630    // not quick rejected, so enable the scissor if clipRequired
1631    mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
1632    mSkipOutlineClip = !roundRectClipRequired;
1633    return false;
1634}
1635
1636void OpenGLRenderer::debugClip() {
1637#if DEBUG_CLIP_REGIONS
1638    if (!currentSnapshot()->clipRegion->isEmpty()) {
1639        SkPaint paint;
1640        paint.setColor(0x7f00ff00);
1641        drawRegionRects(*(currentSnapshot()->clipRegion, paint);
1642
1643    }
1644#endif
1645}
1646
1647void OpenGLRenderer::renderGlop(const Glop& glop, bool clearLayer) {
1648    // TODO: It would be best if we could do this before quickRejectSetupScissor()
1649    //       changes the scissor test state
1650    if (clearLayer) clearLayerRegions();
1651
1652    if (mState.getDirtyClip()) {
1653        if (mRenderState.scissor().isEnabled()) {
1654            setScissorFromClip();
1655        }
1656
1657        setStencilFromClip();
1658    }
1659    mRenderState.render(glop);
1660    if (!mRenderState.stencil().isWriteEnabled()) {
1661        // TODO: specify more clearly when a draw should dirty the layer.
1662        // is writing to the stencil the only time we should ignore this?
1663        dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
1664        mDirty = true;
1665    }
1666}
1667
1668///////////////////////////////////////////////////////////////////////////////
1669// Drawing commands
1670///////////////////////////////////////////////////////////////////////////////
1671
1672void OpenGLRenderer::setupDraw(bool clearLayer) {
1673    // TODO: It would be best if we could do this before quickRejectSetupScissor()
1674    //       changes the scissor test state
1675    if (clearLayer) clearLayerRegions();
1676    // Make sure setScissor & setStencil happen at the beginning of
1677    // this method
1678    if (mState.getDirtyClip()) {
1679        if (mRenderState.scissor().isEnabled()) {
1680            setScissorFromClip();
1681        }
1682
1683        setStencilFromClip();
1684    }
1685
1686    mDescription.reset();
1687
1688    mSetShaderColor = false;
1689    mColorSet = false;
1690    mColor.a = mColor.r = mColor.g = mColor.b = 0.0f;
1691    mTextureUnit = 0;
1692    mTrackDirtyRegions = true;
1693
1694    // Enable debug highlight when what we're about to draw is tested against
1695    // the stencil buffer and if stencil highlight debugging is on
1696    mDescription.hasDebugHighlight = !mCaches.debugOverdraw
1697            && mCaches.debugStencilClip == Caches::kStencilShowHighlight
1698            && mRenderState.stencil().isTestEnabled();
1699}
1700
1701void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
1702    mDescription.hasTexture = true;
1703    mDescription.hasAlpha8Texture = isAlpha8;
1704}
1705
1706void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
1707    mDescription.hasTexture = true;
1708    mDescription.hasColors = true;
1709    mDescription.hasAlpha8Texture = isAlpha8;
1710}
1711
1712void OpenGLRenderer::setupDrawWithExternalTexture() {
1713    mDescription.hasExternalTexture = true;
1714}
1715
1716void OpenGLRenderer::setupDrawNoTexture() {
1717    mRenderState.meshState().disableTexCoordsVertexArray();
1718}
1719
1720void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) {
1721    mDescription.hasVertexAlpha = true;
1722    mDescription.useShadowAlphaInterp = useShadowAlphaInterp;
1723}
1724
1725void OpenGLRenderer::setupDrawColor(int color, int alpha) {
1726    mColor.a = alpha / 255.0f;
1727    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
1728    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
1729    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
1730    mColorSet = true;
1731    mSetShaderColor = mDescription.setColorModulate(mColor.a);
1732}
1733
1734void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
1735    mColor.a = alpha / 255.0f;
1736    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
1737    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
1738    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
1739    mColorSet = true;
1740    mSetShaderColor = mDescription.setAlpha8ColorModulate(mColor.r, mColor.g, mColor.b, mColor.a);
1741}
1742
1743void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
1744    mCaches.fontRenderer->describe(mDescription, paint);
1745}
1746
1747void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
1748    mColor.a = a;
1749    mColor.r = r;
1750    mColor.g = g;
1751    mColor.b = b;
1752    mColorSet = true;
1753    mSetShaderColor = mDescription.setColorModulate(a);
1754}
1755
1756void OpenGLRenderer::setupDrawShader(const SkShader* shader) {
1757    if (shader != nullptr) {
1758        SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
1759    }
1760}
1761
1762void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
1763    if (filter == nullptr) {
1764        return;
1765    }
1766
1767    SkXfermode::Mode mode;
1768    if (filter->asColorMode(nullptr, &mode)) {
1769        mDescription.colorOp = ProgramDescription::kColorBlend;
1770        mDescription.colorMode = mode;
1771    } else if (filter->asColorMatrix(nullptr)) {
1772        mDescription.colorOp = ProgramDescription::kColorMatrix;
1773    }
1774}
1775
1776void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
1777    if (mColorSet && mode == SkXfermode::kClear_Mode) {
1778        mColor.a = 1.0f;
1779        mColor.r = mColor.g = mColor.b = 0.0f;
1780        mSetShaderColor = mDescription.modulate = true;
1781    }
1782}
1783
1784void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
1785    SkXfermode::Mode mode = layer->getMode();
1786    // When the blending mode is kClear_Mode, we need to use a modulate color
1787    // argb=1,0,0,0
1788    accountForClear(mode);
1789    // TODO: check shader blending, once we have shader drawing support for layers.
1790    bool blend = layer->isBlend()
1791            || getLayerAlpha(layer) < 1.0f
1792            || (mColorSet && mColor.a < 1.0f)
1793            || PaintUtils::isBlendedColorFilter(layer->getColorFilter());
1794    chooseBlending(blend, mode, mDescription, swapSrcDst);
1795}
1796
1797void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool swapSrcDst) {
1798    SkXfermode::Mode mode = getXfermodeDirect(paint);
1799    // When the blending mode is kClear_Mode, we need to use a modulate color
1800    // argb=1,0,0,0
1801    accountForClear(mode);
1802    blend |= (mColorSet && mColor.a < 1.0f)
1803            || (getShader(paint) && !getShader(paint)->isOpaque())
1804            || PaintUtils::isBlendedColorFilter(getColorFilter(paint));
1805    chooseBlending(blend, mode, mDescription, swapSrcDst);
1806}
1807
1808void OpenGLRenderer::setupDrawProgram() {
1809    mCaches.setProgram(mDescription);
1810    if (mDescription.hasRoundRectClip) {
1811        // TODO: avoid doing this repeatedly, stashing state pointer in program
1812        const RoundRectClipState* state = writableSnapshot()->roundRectClipState;
1813        const Rect& innerRect = state->innerRect;
1814        glUniform4f(mCaches.program().getUniform("roundRectInnerRectLTRB"),
1815                innerRect.left, innerRect.top,
1816                innerRect.right, innerRect.bottom);
1817        glUniformMatrix4fv(mCaches.program().getUniform("roundRectInvTransform"),
1818                1, GL_FALSE, &state->matrix.data[0]);
1819
1820        // add half pixel to round out integer rect space to cover pixel centers
1821        float roundedOutRadius = state->radius + 0.5f;
1822        glUniform1f(mCaches.program().getUniform("roundRectRadius"),
1823                roundedOutRadius);
1824    }
1825}
1826
1827void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
1828    mTrackDirtyRegions = false;
1829}
1830
1831void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
1832        float left, float top, float right, float bottom, bool ignoreTransform) {
1833    mModelViewMatrix.loadTranslate(left, top, 0.0f);
1834    if (mode == kModelViewMode_TranslateAndScale) {
1835        mModelViewMatrix.scale(right - left, bottom - top, 1.0f);
1836    }
1837
1838    bool dirty = right - left > 0.0f && bottom - top > 0.0f;
1839    const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
1840
1841    mCaches.program().set(currentSnapshot()->getOrthoMatrix(),
1842            mModelViewMatrix, transformMatrix, offset);
1843    if (dirty && mTrackDirtyRegions) {
1844        if (!ignoreTransform) {
1845            dirtyLayer(left, top, right, bottom, *currentTransform());
1846        } else {
1847            dirtyLayer(left, top, right, bottom);
1848        }
1849    }
1850}
1851
1852void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
1853    if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
1854        mCaches.program().setColor(mColor);
1855    }
1856}
1857
1858void OpenGLRenderer::setupDrawPureColorUniforms() {
1859    if (mSetShaderColor) {
1860        mCaches.program().setColor(mColor);
1861    }
1862}
1863
1864void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) {
1865    if (shader == nullptr) {
1866        return;
1867    }
1868
1869    if (ignoreTransform) {
1870        // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
1871        // because it was built into modelView / the geometry, and the description needs to
1872        // compensate.
1873        mat4 modelViewWithoutTransform;
1874        modelViewWithoutTransform.loadInverse(*currentTransform());
1875        modelViewWithoutTransform.multiply(mModelViewMatrix);
1876        mModelViewMatrix.load(modelViewWithoutTransform);
1877    }
1878
1879    SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit,
1880            mCaches.extensions(), *shader);
1881}
1882
1883void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
1884    if (nullptr == filter) {
1885        return;
1886    }
1887
1888    SkColor color;
1889    SkXfermode::Mode mode;
1890    if (filter->asColorMode(&color, &mode)) {
1891        const int alpha = SkColorGetA(color);
1892        const GLfloat a = alpha / 255.0f;
1893        const GLfloat r = a * SkColorGetR(color) / 255.0f;
1894        const GLfloat g = a * SkColorGetG(color) / 255.0f;
1895        const GLfloat b = a * SkColorGetB(color) / 255.0f;
1896        glUniform4f(mCaches.program().getUniform("colorBlend"), r, g, b, a);
1897        return;
1898    }
1899
1900    SkScalar srcColorMatrix[20];
1901    if (filter->asColorMatrix(srcColorMatrix)) {
1902
1903        float colorMatrix[16];
1904        memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
1905        memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
1906        memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
1907        memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
1908
1909        // Skia uses the range [0..255] for the addition vector, but we need
1910        // the [0..1] range to apply the vector in GLSL
1911        float colorVector[4];
1912        colorVector[0] = srcColorMatrix[4] / 255.0f;
1913        colorVector[1] = srcColorMatrix[9] / 255.0f;
1914        colorVector[2] = srcColorMatrix[14] / 255.0f;
1915        colorVector[3] = srcColorMatrix[19] / 255.0f;
1916
1917        glUniformMatrix4fv(mCaches.program().getUniform("colorMatrix"), 1,
1918                GL_FALSE, colorMatrix);
1919        glUniform4fv(mCaches.program().getUniform("colorMatrixVector"), 1, colorVector);
1920        return;
1921    }
1922
1923    // it is an error if we ever get here
1924}
1925
1926void OpenGLRenderer::setupDrawTextGammaUniforms() {
1927    mCaches.fontRenderer->setupProgram(mDescription, mCaches.program());
1928}
1929
1930void OpenGLRenderer::setupDrawSimpleMesh() {
1931    bool force = mRenderState.meshState().bindMeshBuffer();
1932    mRenderState.meshState().bindPositionVertexPointer(force, nullptr);
1933    mRenderState.meshState().unbindIndicesBuffer();
1934}
1935
1936void OpenGLRenderer::setupDrawTexture(GLuint texture) {
1937    if (texture) mCaches.textureState().bindTexture(texture);
1938    mTextureUnit++;
1939    mRenderState.meshState().enableTexCoordsVertexArray();
1940}
1941
1942void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
1943    mCaches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
1944    mTextureUnit++;
1945    mRenderState.meshState().enableTexCoordsVertexArray();
1946}
1947
1948void OpenGLRenderer::setupDrawTextureTransform() {
1949    mDescription.hasTextureTransform = true;
1950}
1951
1952void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
1953    glUniformMatrix4fv(mCaches.program().getUniform("mainTextureTransform"), 1,
1954            GL_FALSE, &transform.data[0]);
1955}
1956
1957void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1958        const GLvoid* texCoords, GLuint vbo) {
1959    bool force = false;
1960    if (!vertices || vbo) {
1961        force = mRenderState.meshState().bindMeshBuffer(vbo);
1962    } else {
1963        force = mRenderState.meshState().unbindMeshBuffer();
1964    }
1965
1966    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
1967    if (mCaches.program().texCoords >= 0) {
1968        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
1969    }
1970
1971    mRenderState.meshState().unbindIndicesBuffer();
1972}
1973
1974void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1975        const GLvoid* texCoords, const GLvoid* colors) {
1976    bool force = mRenderState.meshState().unbindMeshBuffer();
1977    GLsizei stride = sizeof(ColorTextureVertex);
1978
1979    mRenderState.meshState().bindPositionVertexPointer(force, vertices, stride);
1980    if (mCaches.program().texCoords >= 0) {
1981        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords, stride);
1982    }
1983    int slot = mCaches.program().getAttrib("colors");
1984    if (slot >= 0) {
1985        glEnableVertexAttribArray(slot);
1986        glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
1987    }
1988
1989    mRenderState.meshState().unbindIndicesBuffer();
1990}
1991
1992void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
1993        const GLvoid* texCoords, GLuint vbo) {
1994    bool force = false;
1995    // If vbo is != 0 we want to treat the vertices parameter as an offset inside
1996    // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
1997    // use the default VBO found in RenderState
1998    if (!vertices || vbo) {
1999        force = mRenderState.meshState().bindMeshBuffer(vbo);
2000    } else {
2001        force = mRenderState.meshState().unbindMeshBuffer();
2002    }
2003    mRenderState.meshState().bindQuadIndicesBuffer();
2004
2005    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
2006    if (mCaches.program().texCoords >= 0) {
2007        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
2008    }
2009}
2010
2011void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
2012    bool force = mRenderState.meshState().unbindMeshBuffer();
2013    mRenderState.meshState().bindQuadIndicesBuffer();
2014    mRenderState.meshState().bindPositionVertexPointer(force, vertices, kVertexStride);
2015}
2016
2017///////////////////////////////////////////////////////////////////////////////
2018// Drawing
2019///////////////////////////////////////////////////////////////////////////////
2020
2021void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
2022    // All the usual checks and setup operations (quickReject, setupDraw, etc.)
2023    // will be performed by the display list itself
2024    if (renderNode && renderNode->isRenderable()) {
2025        // compute 3d ordering
2026        renderNode->computeOrdering();
2027        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
2028            startFrame();
2029            ReplayStateStruct replayStruct(*this, dirty, replayFlags);
2030            renderNode->replay(replayStruct, 0);
2031            return;
2032        }
2033
2034        // Don't avoid overdraw when visualizing, since that makes it harder to
2035        // debug where it's coming from, and when the problem occurs.
2036        bool avoidOverdraw = !mCaches.debugOverdraw;
2037        DeferredDisplayList deferredList(mState.currentClipRect(), avoidOverdraw);
2038        DeferStateStruct deferStruct(deferredList, *this, replayFlags);
2039        renderNode->defer(deferStruct, 0);
2040
2041        flushLayers();
2042        startFrame();
2043
2044        deferredList.flush(*this, dirty);
2045    } else {
2046        // Even if there is no drawing command(Ex: invisible),
2047        // it still needs startFrame to clear buffer and start tiling.
2048        startFrame();
2049    }
2050}
2051
2052void OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) {
2053    float x = 0;
2054    float y = 0;
2055
2056    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2057
2058    bool ignoreTransform = false;
2059    if (currentTransform()->isPureTranslate()) {
2060        x = floorf(currentTransform()->getTranslateX() + 0.5f);
2061        y = floorf(currentTransform()->getTranslateY() + 0.5f);
2062        ignoreTransform = true;
2063
2064        texture->setFilter(GL_NEAREST, true);
2065    } else {
2066        texture->setFilter(PaintUtils::getFilter(paint), true);
2067    }
2068
2069    // No need to check for a UV mapper on the texture object, only ARGB_8888
2070    // bitmaps get packed in the atlas
2071    drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
2072            paint, (GLvoid*) nullptr, (GLvoid*) kMeshTextureOffset,
2073            GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
2074}
2075
2076/**
2077 * Important note: this method is intended to draw batches of bitmaps and
2078 * will not set the scissor enable or dirty the current layer, if any.
2079 * The caller is responsible for properly dirtying the current layer.
2080 */
2081void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
2082        int bitmapCount, TextureVertex* vertices, bool pureTranslate,
2083        const Rect& bounds, const SkPaint* paint) {
2084    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2085    if (!texture) return;
2086
2087    const AutoTexture autoCleanup(texture);
2088
2089    if (USE_GLOPS) {
2090        // TODO: remove layer dirty in multi-draw callers
2091        // TODO: snap doesn't need to touch transform, only texture filter.
2092        bool snap = pureTranslate;
2093        const float x = floorf(bounds.left + 0.5f);
2094        const float y = floorf(bounds.top + 0.5f);
2095        int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
2096                ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
2097        Glop glop;
2098        GlopBuilder(mRenderState, mCaches, &glop)
2099                .setMeshTexturedMesh(vertices, bitmapCount * 6)
2100                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
2101                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
2102                .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight()))
2103                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2104                .build();
2105        renderGlop(glop);
2106        return;
2107    }
2108
2109    mCaches.textureState().activateTexture(0);
2110    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2111    texture->setFilter(pureTranslate ? GL_NEAREST : PaintUtils::getFilter(paint), true);
2112
2113    const float x = floorf(bounds.left + 0.5f);
2114    const float y = floorf(bounds.top + 0.5f);
2115    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
2116        drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
2117                texture->id, paint, &vertices[0].x, &vertices[0].u,
2118                GL_TRIANGLES, bitmapCount * 6, true,
2119                kModelViewMode_Translate, false);
2120    } else {
2121        drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
2122                texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u,
2123                GL_TRIANGLES, bitmapCount * 6, false, true, 0,
2124                kModelViewMode_Translate, false);
2125    }
2126
2127    mDirty = true;
2128}
2129
2130void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
2131    if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
2132        return;
2133    }
2134
2135    mCaches.textureState().activateTexture(0);
2136    Texture* texture = getTexture(bitmap);
2137    if (!texture) return;
2138    const AutoTexture autoCleanup(texture);
2139
2140    if (USE_GLOPS) {
2141        int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
2142                ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
2143        Glop glop;
2144        GlopBuilder(mRenderState, mCaches, &glop)
2145                .setMeshTexturedUnitQuad(texture->uvMapper)
2146                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
2147                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
2148                .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
2149                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2150                .build();
2151        renderGlop(glop);
2152        return;
2153    }
2154
2155    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
2156        drawAlphaBitmap(texture, paint);
2157    } else {
2158        drawTextureRect(texture, paint);
2159    }
2160
2161    mDirty = true;
2162}
2163
2164void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
2165        const float* vertices, const int* colors, const SkPaint* paint) {
2166    if (!vertices || mState.currentlyIgnored()) {
2167        return;
2168    }
2169
2170    float left = FLT_MAX;
2171    float top = FLT_MAX;
2172    float right = FLT_MIN;
2173    float bottom = FLT_MIN;
2174
2175    const uint32_t elementCount = meshWidth * meshHeight * 6;
2176
2177    std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]);
2178    ColorTextureVertex* vertex = &mesh[0];
2179
2180    std::unique_ptr<int[]> tempColors;
2181    if (!colors) {
2182        uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
2183        tempColors.reset(new int[colorsCount]);
2184        memset(tempColors.get(), 0xff, colorsCount * sizeof(int));
2185        colors = tempColors.get();
2186    }
2187
2188    Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
2189    const UvMapper& mapper(getMapper(texture));
2190
2191    for (int32_t y = 0; y < meshHeight; y++) {
2192        for (int32_t x = 0; x < meshWidth; x++) {
2193            uint32_t i = (y * (meshWidth + 1) + x) * 2;
2194
2195            float u1 = float(x) / meshWidth;
2196            float u2 = float(x + 1) / meshWidth;
2197            float v1 = float(y) / meshHeight;
2198            float v2 = float(y + 1) / meshHeight;
2199
2200            mapper.map(u1, v1, u2, v2);
2201
2202            int ax = i + (meshWidth + 1) * 2;
2203            int ay = ax + 1;
2204            int bx = i;
2205            int by = bx + 1;
2206            int cx = i + 2;
2207            int cy = cx + 1;
2208            int dx = i + (meshWidth + 1) * 2 + 2;
2209            int dy = dx + 1;
2210
2211            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2212            ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
2213            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
2214
2215            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2216            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
2217            ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
2218
2219            left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
2220            top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
2221            right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
2222            bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
2223        }
2224    }
2225
2226    if (quickRejectSetupScissor(left, top, right, bottom)) {
2227        return;
2228    }
2229
2230    if (!texture) {
2231        texture = mCaches.textureCache.get(bitmap);
2232        if (!texture) {
2233            return;
2234        }
2235    }
2236    const AutoTexture autoCleanup(texture);
2237
2238    if (USE_GLOPS) {
2239        /*
2240         * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
2241         * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
2242         */
2243        Glop glop;
2244        GlopBuilder(mRenderState, mCaches, &glop)
2245                .setMeshColoredTexturedMesh(mesh.get(), elementCount)
2246                .setFillTexturePaint(*texture, static_cast<int>(TextureFillFlags::kNone), paint, currentSnapshot()->alpha)
2247                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
2248                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
2249                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2250                .build();
2251        renderGlop(glop);
2252        return;
2253    }
2254
2255    mCaches.textureState().activateTexture(0);
2256    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2257    texture->setFilter(PaintUtils::getFilter(paint), true);
2258
2259    int alpha;
2260    SkXfermode::Mode mode;
2261    getAlphaAndMode(paint, &alpha, &mode);
2262
2263
2264    dirtyLayer(left, top, right, bottom, *currentTransform());
2265
2266    float a = alpha / 255.0f;
2267    setupDraw();
2268    setupDrawWithTextureAndColor();
2269    setupDrawColor(a, a, a, a);
2270    setupDrawColorFilter(getColorFilter(paint));
2271    setupDrawBlending(paint, true);
2272    setupDrawProgram();
2273    setupDrawDirtyRegionsDisabled();
2274    setupDrawModelView(kModelViewMode_Translate, false, 0, 0, 0, 0);
2275    setupDrawTexture(texture->id);
2276    setupDrawPureColorUniforms();
2277    setupDrawColorFilterUniforms(getColorFilter(paint));
2278    setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
2279
2280    glDrawArrays(GL_TRIANGLES, 0, elementCount);
2281
2282    int slot = mCaches.program().getAttrib("colors");
2283    if (slot >= 0) {
2284        glDisableVertexAttribArray(slot);
2285    }
2286
2287    mDirty = true;
2288}
2289
2290void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) {
2291    if (quickRejectSetupScissor(dst)) {
2292        return;
2293    }
2294
2295    Texture* texture = getTexture(bitmap);
2296    if (!texture) return;
2297    const AutoTexture autoCleanup(texture);
2298
2299    if (USE_GLOPS) {
2300        Rect uv(fmax(0.0f, src.left / texture->width),
2301                fmax(0.0f, src.top / texture->height),
2302                fmin(1.0f, src.right / texture->width),
2303                fmin(1.0f, src.bottom / texture->height));
2304
2305        int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
2306                ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
2307        Glop glop;
2308        GlopBuilder(mRenderState, mCaches, &glop)
2309                .setMeshTexturedUvQuad(texture->uvMapper, uv)
2310                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
2311                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
2312                .setModelViewMapUnitToRectSnap(dst)
2313                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2314                .build();
2315        renderGlop(glop);
2316        return;
2317    }
2318
2319    mCaches.textureState().activateTexture(0);
2320
2321    const float width = texture->width;
2322    const float height = texture->height;
2323
2324    float u1 = fmax(0.0f, src.left / width);
2325    float v1 = fmax(0.0f, src.top / height);
2326    float u2 = fmin(1.0f, src.right / width);
2327    float v2 = fmin(1.0f, src.bottom / height);
2328
2329    getMapper(texture).map(u1, v1, u2, v2);
2330
2331    mRenderState.meshState().unbindMeshBuffer();
2332    resetDrawTextureTexCoords(u1, v1, u2, v2);
2333
2334    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2335
2336    float scaleX = (dst.right - dst.left) / (src.right - src.left);
2337    float scaleY = (dst.bottom - dst.top) / (src.bottom - src.top);
2338
2339    bool scaled = scaleX != 1.0f || scaleY != 1.0f;
2340    bool ignoreTransform = false;
2341
2342    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
2343        float x = floorf(dst.left + currentTransform()->getTranslateX() + 0.5f);
2344        float y = floorf(dst.top + currentTransform()->getTranslateY() + 0.5f);
2345
2346        dst.right = x + (dst.right - dst.left);
2347        dst.bottom = y + (dst.bottom - dst.top);
2348
2349        dst.left = x;
2350        dst.top = y;
2351
2352        texture->setFilter(scaled ? PaintUtils::getFilter(paint) : GL_NEAREST, true);
2353        ignoreTransform = true;
2354    } else {
2355        texture->setFilter(PaintUtils::getFilter(paint), true);
2356    }
2357
2358    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
2359        drawAlpha8TextureMesh(dst.left, dst.top, dst.right, dst.bottom,
2360                texture->id, paint,
2361                &mMeshVertices[0].x, &mMeshVertices[0].u,
2362                GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
2363    } else {
2364        drawTextureMesh(dst.left, dst.top, dst.right, dst.bottom,
2365                texture->id, paint, texture->blend,
2366                &mMeshVertices[0].x, &mMeshVertices[0].u,
2367                GL_TRIANGLE_STRIP, kUnitQuadCount, false, ignoreTransform);
2368    }
2369
2370    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
2371
2372    mDirty = true;
2373}
2374
2375void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
2376        AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
2377        const SkPaint* paint) {
2378    if (!mesh || !mesh->verticesCount || quickRejectSetupScissor(left, top, right, bottom)) {
2379        return;
2380    }
2381
2382    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2383    if (!texture) return;
2384
2385    if (USE_GLOPS) {
2386        // 9 patches are built for stretching - always filter
2387        int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter);
2388        if (bitmap->colorType() == kAlpha_8_SkColorType) {
2389            textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture;
2390        }
2391        Glop glop;
2392        GlopBuilder(mRenderState, mCaches, &glop)
2393                .setMeshPatchQuads(*mesh)
2394                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
2395                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
2396                .setModelViewOffsetRectSnap(left, top, Rect(0, 0, right - left, bottom - top)) // TODO: get minimal bounds from patch
2397                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2398                .build();
2399        renderGlop(glop);
2400        return;
2401    }
2402
2403    mCaches.textureState().activateTexture(0);
2404    const AutoTexture autoCleanup(texture);
2405
2406    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2407    texture->setFilter(GL_LINEAR, true);
2408
2409    const bool pureTranslate = currentTransform()->isPureTranslate();
2410    // Mark the current layer dirty where we are going to draw the patch
2411    if (hasLayer() && mesh->hasEmptyQuads) {
2412        const float offsetX = left + currentTransform()->getTranslateX();
2413        const float offsetY = top + currentTransform()->getTranslateY();
2414        const size_t count = mesh->quads.size();
2415        for (size_t i = 0; i < count; i++) {
2416            const Rect& bounds = mesh->quads.itemAt(i);
2417            if (CC_LIKELY(pureTranslate)) {
2418                const float x = floorf(bounds.left + offsetX + 0.5f);
2419                const float y = floorf(bounds.top + offsetY + 0.5f);
2420                dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
2421            } else {
2422                dirtyLayer(left + bounds.left, top + bounds.top,
2423                        left + bounds.right, top + bounds.bottom, *currentTransform());
2424            }
2425        }
2426    }
2427
2428    bool ignoreTransform = false;
2429    if (CC_LIKELY(pureTranslate)) {
2430        const float x = floorf(left + currentTransform()->getTranslateX() + 0.5f);
2431        const float y = floorf(top + currentTransform()->getTranslateY() + 0.5f);
2432
2433        right = x + right - left;
2434        bottom = y + bottom - top;
2435        left = x;
2436        top = y;
2437        ignoreTransform = true;
2438    }
2439    drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
2440            texture->blend, (GLvoid*) mesh->positionOffset, (GLvoid*) mesh->textureOffset,
2441            GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
2442            mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
2443
2444    mDirty = true;
2445}
2446
2447/**
2448 * Important note: this method is intended to draw batches of 9-patch objects and
2449 * will not set the scissor enable or dirty the current layer, if any.
2450 * The caller is responsible for properly dirtying the current layer.
2451 */
2452void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
2453        TextureVertex* vertices, uint32_t elementCount, const SkPaint* paint) {
2454    mCaches.textureState().activateTexture(0);
2455    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2456    if (!texture) return;
2457    const AutoTexture autoCleanup(texture);
2458
2459    if (USE_GLOPS) {
2460        // TODO: get correct bounds from caller
2461        // 9 patches are built for stretching - always filter
2462        int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter);
2463        if (bitmap->colorType() == kAlpha_8_SkColorType) {
2464            textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture;
2465        }
2466        Glop glop;
2467        GlopBuilder(mRenderState, mCaches, &glop)
2468                .setMeshTexturedIndexedQuads(vertices, elementCount)
2469                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
2470                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
2471                .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
2472                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2473                .build();
2474        renderGlop(glop);
2475        return;
2476    }
2477
2478    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2479    texture->setFilter(GL_LINEAR, true);
2480
2481    drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint,
2482            texture->blend, &vertices[0].x, &vertices[0].u,
2483            GL_TRIANGLES, elementCount, false, true, 0, kModelViewMode_Translate, false);
2484
2485    mDirty = true;
2486}
2487
2488void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
2489        const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) {
2490    // not missing call to quickReject/dirtyLayer, always done at a higher level
2491    if (!vertexBuffer.getVertexCount()) {
2492        // no vertices to draw
2493        return;
2494    }
2495
2496    if (USE_GLOPS) {
2497        bool fudgeOffset = displayFlags & kVertexBuffer_Offset;
2498        bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
2499        Glop glop;
2500        GlopBuilder(mRenderState, mCaches, &glop)
2501                .setMeshVertexBuffer(vertexBuffer, shadowInterp)
2502                .setFillPaint(*paint, currentSnapshot()->alpha)
2503                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
2504                .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
2505                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2506                .build();
2507        renderGlop(glop);
2508        return;
2509    }
2510
2511    const VertexBuffer::MeshFeatureFlags meshFeatureFlags = vertexBuffer.getMeshFeatureFlags();
2512    Rect bounds(vertexBuffer.getBounds());
2513    bounds.translate(translateX, translateY);
2514    dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
2515
2516    int color = paint->getColor();
2517    bool isAA = meshFeatureFlags & VertexBuffer::kAlpha;
2518
2519    setupDraw();
2520    setupDrawNoTexture();
2521    if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
2522    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
2523    setupDrawColorFilter(getColorFilter(paint));
2524    setupDrawShader(getShader(paint));
2525    setupDrawBlending(paint, isAA);
2526    setupDrawProgram();
2527    setupDrawModelView(kModelViewMode_Translate, (displayFlags & kVertexBuffer_Offset),
2528            translateX, translateY, 0, 0);
2529    setupDrawColorUniforms(getShader(paint));
2530    setupDrawColorFilterUniforms(getColorFilter(paint));
2531    setupDrawShaderUniforms(getShader(paint));
2532
2533    const void* vertices = vertexBuffer.getBuffer();
2534    mRenderState.meshState().unbindMeshBuffer();
2535    mRenderState.meshState().bindPositionVertexPointer(true, vertices,
2536            isAA ? kAlphaVertexStride : kVertexStride);
2537    mRenderState.meshState().resetTexCoordsVertexPointer();
2538
2539    int alphaSlot = -1;
2540    if (isAA) {
2541        void* alphaCoords = ((GLbyte*) vertices) + kVertexAlphaOffset;
2542        alphaSlot = mCaches.program().getAttrib("vtxAlpha");
2543        // TODO: avoid enable/disable in back to back uses of the alpha attribute
2544        glEnableVertexAttribArray(alphaSlot);
2545        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
2546    }
2547
2548    if (meshFeatureFlags & VertexBuffer::kIndices) {
2549        mRenderState.meshState().unbindIndicesBuffer();
2550        glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(),
2551                GL_UNSIGNED_SHORT, vertexBuffer.getIndices());
2552    } else {
2553        mRenderState.meshState().unbindIndicesBuffer();
2554        glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
2555    }
2556
2557    if (isAA) {
2558        glDisableVertexAttribArray(alphaSlot);
2559    }
2560
2561    mDirty = true;
2562}
2563
2564/**
2565 * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
2566 * that of AA lines in the drawLines() function.  We expand the convex path by a half pixel in
2567 * screen space in all directions. However, instead of using a fragment shader to compute the
2568 * translucency of the color from its position, we simply use a varying parameter to define how far
2569 * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
2570 *
2571 * Doesn't yet support joins, caps, or path effects.
2572 */
2573void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
2574    VertexBuffer vertexBuffer;
2575    // TODO: try clipping large paths to viewport
2576    PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
2577    drawVertexBuffer(vertexBuffer, paint);
2578}
2579
2580/**
2581 * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
2582 * and additional geometry for defining an alpha slope perimeter.
2583 *
2584 * Using GL_LINES can be difficult because the rasterization rules for those lines produces some
2585 * unexpected results, and may vary between hardware devices. Previously we used a varying-base
2586 * in-shader alpha region, but found it to be taxing on some GPUs.
2587 *
2588 * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
2589 * memory transfer by removing need for degenerate vertices.
2590 */
2591void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
2592    if (mState.currentlyIgnored() || count < 4) return;
2593
2594    count &= ~0x3; // round down to nearest four
2595
2596    VertexBuffer buffer;
2597    PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer);
2598    const Rect& bounds = buffer.getBounds();
2599
2600    if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
2601        return;
2602    }
2603
2604    int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
2605    drawVertexBuffer(buffer, paint, displayFlags);
2606}
2607
2608void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
2609    if (mState.currentlyIgnored() || count < 2) return;
2610
2611    count &= ~0x1; // round down to nearest two
2612
2613    VertexBuffer buffer;
2614    PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer);
2615
2616    const Rect& bounds = buffer.getBounds();
2617    if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
2618        return;
2619    }
2620
2621    int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
2622    drawVertexBuffer(buffer, paint, displayFlags);
2623
2624    mDirty = true;
2625}
2626
2627void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
2628    // No need to check against the clip, we fill the clip region
2629    if (mState.currentlyIgnored()) return;
2630
2631    Rect clip(mState.currentClipRect());
2632    clip.snapToPixelBoundaries();
2633
2634    SkPaint paint;
2635    paint.setColor(color);
2636    paint.setXfermodeMode(mode);
2637
2638    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
2639
2640    mDirty = true;
2641}
2642
2643void OpenGLRenderer::drawShape(float left, float top, PathTexture* texture,
2644        const SkPaint* paint) {
2645    if (!texture) return;
2646    const AutoTexture autoCleanup(texture);
2647
2648    const float x = left + texture->left - texture->offset;
2649    const float y = top + texture->top - texture->offset;
2650
2651    drawPathTexture(texture, x, y, paint);
2652
2653    mDirty = true;
2654}
2655
2656void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
2657        float rx, float ry, const SkPaint* p) {
2658    if (mState.currentlyIgnored()
2659            || quickRejectSetupScissor(left, top, right, bottom, p)
2660            || PaintUtils::paintWillNotDraw(*p)) {
2661        return;
2662    }
2663
2664    if (p->getPathEffect() != nullptr) {
2665        mCaches.textureState().activateTexture(0);
2666        PathTexture* texture = mCaches.pathCache.getRoundRect(
2667                right - left, bottom - top, rx, ry, p);
2668        drawShape(left, top, texture, p);
2669    } else {
2670        const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
2671                *currentTransform(), *p, right - left, bottom - top, rx, ry);
2672        drawVertexBuffer(left, top, *vertexBuffer, p);
2673    }
2674}
2675
2676void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
2677    if (mState.currentlyIgnored()
2678            || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
2679            || PaintUtils::paintWillNotDraw(*p)) {
2680        return;
2681    }
2682    if (p->getPathEffect() != nullptr) {
2683        mCaches.textureState().activateTexture(0);
2684        PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
2685        drawShape(x - radius, y - radius, texture, p);
2686    } else {
2687        SkPath path;
2688        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2689            path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
2690        } else {
2691            path.addCircle(x, y, radius);
2692        }
2693        drawConvexPath(path, p);
2694    }
2695}
2696
2697void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
2698        const SkPaint* p) {
2699    if (mState.currentlyIgnored()
2700            || quickRejectSetupScissor(left, top, right, bottom, p)
2701            || PaintUtils::paintWillNotDraw(*p)) {
2702        return;
2703    }
2704
2705    if (p->getPathEffect() != nullptr) {
2706        mCaches.textureState().activateTexture(0);
2707        PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
2708        drawShape(left, top, texture, p);
2709    } else {
2710        SkPath path;
2711        SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2712        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2713            rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2714        }
2715        path.addOval(rect);
2716        drawConvexPath(path, p);
2717    }
2718}
2719
2720void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
2721        float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
2722    if (mState.currentlyIgnored()
2723            || quickRejectSetupScissor(left, top, right, bottom, p)
2724            || PaintUtils::paintWillNotDraw(*p)) {
2725        return;
2726    }
2727
2728    // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
2729    if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
2730        mCaches.textureState().activateTexture(0);
2731        PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
2732                startAngle, sweepAngle, useCenter, p);
2733        drawShape(left, top, texture, p);
2734        return;
2735    }
2736    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2737    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2738        rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2739    }
2740
2741    SkPath path;
2742    if (useCenter) {
2743        path.moveTo(rect.centerX(), rect.centerY());
2744    }
2745    path.arcTo(rect, startAngle, sweepAngle, !useCenter);
2746    if (useCenter) {
2747        path.close();
2748    }
2749    drawConvexPath(path, p);
2750}
2751
2752// See SkPaintDefaults.h
2753#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
2754
2755void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
2756        const SkPaint* p) {
2757    if (mState.currentlyIgnored()
2758            || quickRejectSetupScissor(left, top, right, bottom, p)
2759            || PaintUtils::paintWillNotDraw(*p)) {
2760        return;
2761    }
2762
2763    if (p->getStyle() != SkPaint::kFill_Style) {
2764        // only fill style is supported by drawConvexPath, since others have to handle joins
2765        if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
2766                p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
2767            mCaches.textureState().activateTexture(0);
2768            PathTexture* texture =
2769                    mCaches.pathCache.getRect(right - left, bottom - top, p);
2770            drawShape(left, top, texture, p);
2771        } else {
2772            SkPath path;
2773            SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2774            if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2775                rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2776            }
2777            path.addRect(rect);
2778            drawConvexPath(path, p);
2779        }
2780    } else {
2781        if (p->isAntiAlias() && !currentTransform()->isSimple()) {
2782            SkPath path;
2783            path.addRect(left, top, right, bottom);
2784            drawConvexPath(path, p);
2785        } else {
2786            drawColorRect(left, top, right, bottom, p);
2787
2788            mDirty = true;
2789        }
2790    }
2791}
2792
2793void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
2794        int bytesCount, int count, const float* positions,
2795        FontRenderer& fontRenderer, int alpha, float x, float y) {
2796    mCaches.textureState().activateTexture(0);
2797
2798    TextShadow textShadow;
2799    if (!getTextShadow(paint, &textShadow)) {
2800        LOG_ALWAYS_FATAL("failed to query shadow attributes");
2801    }
2802
2803    // NOTE: The drop shadow will not perform gamma correction
2804    //       if shader-based correction is enabled
2805    mCaches.dropShadowCache.setFontRenderer(fontRenderer);
2806    ShadowTexture* texture = mCaches.dropShadowCache.get(
2807            paint, text, bytesCount, count, textShadow.radius, positions);
2808    // If the drop shadow exceeds the max texture size or couldn't be
2809    // allocated, skip drawing
2810    if (!texture) return;
2811    const AutoTexture autoCleanup(texture);
2812
2813    const float sx = x - texture->left + textShadow.dx;
2814    const float sy = y - texture->top + textShadow.dy;
2815
2816    if (USE_GLOPS) {
2817        Glop glop;
2818        GlopBuilder(mRenderState, mCaches, &glop)
2819                .setMeshTexturedUnitQuad(nullptr)
2820                .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
2821                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
2822                .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
2823                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2824                .build();
2825        renderGlop(glop);
2826        return;
2827    }
2828
2829    const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * currentSnapshot()->alpha;
2830    if (getShader(paint)) {
2831        textShadow.color = SK_ColorWHITE;
2832    }
2833
2834    setupDraw();
2835    setupDrawWithTexture(true);
2836    setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
2837    setupDrawColorFilter(getColorFilter(paint));
2838    setupDrawShader(getShader(paint));
2839    setupDrawBlending(paint, true);
2840    setupDrawProgram();
2841    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
2842            sx, sy, sx + texture->width, sy + texture->height);
2843    setupDrawTexture(texture->id);
2844    setupDrawPureColorUniforms();
2845    setupDrawColorFilterUniforms(getColorFilter(paint));
2846    setupDrawShaderUniforms(getShader(paint));
2847    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
2848
2849    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
2850}
2851
2852bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
2853    float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
2854    return MathUtils::isZero(alpha)
2855            && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
2856}
2857
2858void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
2859        const float* positions, const SkPaint* paint) {
2860    if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
2861        return;
2862    }
2863
2864    // NOTE: Skia does not support perspective transform on drawPosText yet
2865    if (!currentTransform()->isSimple()) {
2866        return;
2867    }
2868
2869    mRenderState.scissor().setEnabled(true);
2870
2871    float x = 0.0f;
2872    float y = 0.0f;
2873    const bool pureTranslate = currentTransform()->isPureTranslate();
2874    if (pureTranslate) {
2875        x = floorf(x + currentTransform()->getTranslateX() + 0.5f);
2876        y = floorf(y + currentTransform()->getTranslateY() + 0.5f);
2877    }
2878
2879    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2880    fontRenderer.setFont(paint, SkMatrix::I());
2881
2882    int alpha;
2883    SkXfermode::Mode mode;
2884    getAlphaAndMode(paint, &alpha, &mode);
2885
2886    if (CC_UNLIKELY(hasTextShadow(paint))) {
2887        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
2888                alpha, 0.0f, 0.0f);
2889    }
2890
2891    // Pick the appropriate texture filtering
2892    bool linearFilter = currentTransform()->changesBounds();
2893    if (pureTranslate && !linearFilter) {
2894        linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2895    }
2896    fontRenderer.setTextureFiltering(linearFilter);
2897
2898    const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip());
2899    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2900
2901    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2902    if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y,
2903            positions, hasLayer() ? &bounds : nullptr, &functor)) {
2904        dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
2905        mDirty = true;
2906    }
2907
2908}
2909
2910bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const {
2911    if (CC_LIKELY(transform.isPureTranslate())) {
2912        outMatrix->setIdentity();
2913        return false;
2914    } else if (CC_UNLIKELY(transform.isPerspective())) {
2915        outMatrix->setIdentity();
2916        return true;
2917    }
2918
2919    /**
2920     * Input is a non-perspective, scaling transform. Generate a scale-only transform,
2921     * with values rounded to the nearest int.
2922     */
2923    float sx, sy;
2924    transform.decomposeScale(sx, sy);
2925    outMatrix->setScale(
2926            roundf(fmaxf(1.0f, sx)),
2927            roundf(fmaxf(1.0f, sy)));
2928    return true;
2929}
2930
2931int OpenGLRenderer::getSaveCount() const {
2932    return mState.getSaveCount();
2933}
2934
2935int OpenGLRenderer::save(int flags) {
2936    return mState.save(flags);
2937}
2938
2939void OpenGLRenderer::restore() {
2940    mState.restore();
2941}
2942
2943void OpenGLRenderer::restoreToCount(int saveCount) {
2944    mState.restoreToCount(saveCount);
2945}
2946
2947void OpenGLRenderer::translate(float dx, float dy, float dz) {
2948    mState.translate(dx, dy, dz);
2949}
2950
2951void OpenGLRenderer::rotate(float degrees) {
2952    mState.rotate(degrees);
2953}
2954
2955void OpenGLRenderer::scale(float sx, float sy) {
2956    mState.scale(sx, sy);
2957}
2958
2959void OpenGLRenderer::skew(float sx, float sy) {
2960    mState.skew(sx, sy);
2961}
2962
2963void OpenGLRenderer::setMatrix(const Matrix4& matrix) {
2964    mState.setMatrix(matrix);
2965}
2966
2967void OpenGLRenderer::concatMatrix(const Matrix4& matrix) {
2968    mState.concatMatrix(matrix);
2969}
2970
2971bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
2972    return mState.clipRect(left, top, right, bottom, op);
2973}
2974
2975bool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
2976    return mState.clipPath(path, op);
2977}
2978
2979bool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
2980    return mState.clipRegion(region, op);
2981}
2982
2983void OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
2984    mState.setClippingOutline(allocator, outline);
2985}
2986
2987void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator,
2988        const Rect& rect, float radius, bool highPriority) {
2989    mState.setClippingRoundRect(allocator, rect, radius, highPriority);
2990}
2991
2992void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
2993        const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
2994        DrawOpMode drawOpMode) {
2995
2996    if (drawOpMode == DrawOpMode::kImmediate) {
2997        // The checks for corner-case ignorable text and quick rejection is only done for immediate
2998        // drawing as ops from DeferredDisplayList are already filtered for these
2999        if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
3000                quickRejectSetupScissor(bounds)) {
3001            return;
3002        }
3003    }
3004
3005    const float oldX = x;
3006    const float oldY = y;
3007
3008    const mat4& transform = *currentTransform();
3009    const bool pureTranslate = transform.isPureTranslate();
3010
3011    if (CC_LIKELY(pureTranslate)) {
3012        x = floorf(x + transform.getTranslateX() + 0.5f);
3013        y = floorf(y + transform.getTranslateY() + 0.5f);
3014    }
3015
3016    int alpha;
3017    SkXfermode::Mode mode;
3018    getAlphaAndMode(paint, &alpha, &mode);
3019
3020    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
3021
3022    if (CC_UNLIKELY(hasTextShadow(paint))) {
3023        fontRenderer.setFont(paint, SkMatrix::I());
3024        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
3025                alpha, oldX, oldY);
3026    }
3027
3028    const bool hasActiveLayer = hasLayer();
3029
3030    // We only pass a partial transform to the font renderer. That partial
3031    // matrix defines how glyphs are rasterized. Typically we want glyphs
3032    // to be rasterized at their final size on screen, which means the partial
3033    // matrix needs to take the scale factor into account.
3034    // When a partial matrix is used to transform glyphs during rasterization,
3035    // the mesh is generated with the inverse transform (in the case of scale,
3036    // the mesh is generated at 1.0 / scale for instance.) This allows us to
3037    // apply the full transform matrix at draw time in the vertex shader.
3038    // Applying the full matrix in the shader is the easiest way to handle
3039    // rotation and perspective and allows us to always generated quads in the
3040    // font renderer which greatly simplifies the code, clipping in particular.
3041    SkMatrix fontTransform;
3042    bool linearFilter = findBestFontTransform(transform, &fontTransform)
3043            || fabs(y - (int) y) > 0.0f
3044            || fabs(x - (int) x) > 0.0f;
3045    fontRenderer.setFont(paint, fontTransform);
3046    fontRenderer.setTextureFiltering(linearFilter);
3047
3048    // TODO: Implement better clipping for scaled/rotated text
3049    const Rect* clip = !pureTranslate ? nullptr : &mState.currentClipRect();
3050    Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
3051
3052    bool status;
3053    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
3054
3055    // don't call issuedrawcommand, do it at end of batch
3056    bool forceFinish = (drawOpMode != DrawOpMode::kDefer);
3057    if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
3058        SkPaint paintCopy(*paint);
3059        paintCopy.setTextAlign(SkPaint::kLeft_Align);
3060        status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
3061                positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
3062    } else {
3063        status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
3064                positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
3065    }
3066
3067    if ((status || drawOpMode != DrawOpMode::kImmediate) && hasActiveLayer) {
3068        if (!pureTranslate) {
3069            transform.mapRect(layerBounds);
3070        }
3071        dirtyLayerUnchecked(layerBounds, getRegion());
3072    }
3073
3074    drawTextDecorations(totalAdvance, oldX, oldY, paint);
3075
3076    mDirty = true;
3077}
3078
3079void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
3080        const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
3081    if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
3082        return;
3083    }
3084
3085    // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
3086    mRenderState.scissor().setEnabled(true);
3087
3088    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
3089    fontRenderer.setFont(paint, SkMatrix::I());
3090    fontRenderer.setTextureFiltering(true);
3091
3092    int alpha;
3093    SkXfermode::Mode mode;
3094    getAlphaAndMode(paint, &alpha, &mode);
3095    TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
3096
3097    const Rect* clip = &writableSnapshot()->getLocalClip();
3098    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
3099
3100    if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
3101            hOffset, vOffset, hasLayer() ? &bounds : nullptr, &functor)) {
3102        dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
3103        mDirty = true;
3104    }
3105}
3106
3107void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
3108    if (mState.currentlyIgnored()) return;
3109
3110    mCaches.textureState().activateTexture(0);
3111
3112    PathTexture* texture = mCaches.pathCache.get(path, paint);
3113    if (!texture) return;
3114    const AutoTexture autoCleanup(texture);
3115
3116    const float x = texture->left - texture->offset;
3117    const float y = texture->top - texture->offset;
3118
3119    drawPathTexture(texture, x, y, paint);
3120    mDirty = true;
3121}
3122
3123void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
3124    if (!layer) {
3125        return;
3126    }
3127
3128    mat4* transform = nullptr;
3129    if (layer->isTextureLayer()) {
3130        transform = &layer->getTransform();
3131        if (!transform->isIdentity()) {
3132            save(SkCanvas::kMatrix_SaveFlag);
3133            concatMatrix(*transform);
3134        }
3135    }
3136
3137    bool clipRequired = false;
3138    const bool rejected = mState.calculateQuickRejectForScissor(
3139            x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
3140            &clipRequired, nullptr, false);
3141
3142    if (rejected) {
3143        if (transform && !transform->isIdentity()) {
3144            restore();
3145        }
3146        return;
3147    }
3148
3149    EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
3150            x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired);
3151
3152    updateLayer(layer, true);
3153
3154    mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
3155    mCaches.textureState().activateTexture(0);
3156
3157    if (CC_LIKELY(!layer->region.isEmpty())) {
3158        if (layer->region.isRect()) {
3159            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
3160                    composeLayerRect(layer, layer->regionRect));
3161        } else if (layer->mesh) {
3162            if (USE_GLOPS) {
3163                Glop glop;
3164                GlopBuilder(mRenderState, mCaches, &glop)
3165                        .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
3166                        .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
3167                        .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
3168                        .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
3169                        .setRoundRectClipState(currentSnapshot()->roundRectClipState)
3170                        .build();
3171                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
3172            } else {
3173                const float a = getLayerAlpha(layer);
3174                setupDraw();
3175                setupDrawWithTexture();
3176                setupDrawColor(a, a, a, a);
3177                setupDrawColorFilter(layer->getColorFilter());
3178                setupDrawBlending(layer);
3179                setupDrawProgram();
3180                setupDrawPureColorUniforms();
3181                setupDrawColorFilterUniforms(layer->getColorFilter());
3182                setupDrawTexture(layer->getTextureId());
3183                if (CC_LIKELY(currentTransform()->isPureTranslate())) {
3184                    int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
3185                    int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
3186
3187                    layer->setFilter(GL_NEAREST);
3188                    setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
3189                            tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
3190                } else {
3191                    layer->setFilter(GL_LINEAR);
3192                    setupDrawModelView(kModelViewMode_Translate, false, x, y,
3193                            x + layer->layer.getWidth(), y + layer->layer.getHeight());
3194                }
3195
3196                TextureVertex* mesh = &layer->mesh[0];
3197                GLsizei elementsCount = layer->meshElementCount;
3198
3199                while (elementsCount > 0) {
3200                    GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
3201
3202                    setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
3203                    DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
3204                            glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr));
3205
3206                    elementsCount -= drawCount;
3207                    // Though there are 4 vertices in a quad, we use 6 indices per
3208                    // quad to draw with GL_TRIANGLES
3209                    mesh += (drawCount / 6) * 4;
3210                }
3211            }
3212#if DEBUG_LAYERS_AS_REGIONS
3213            drawRegionRectsDebug(layer->region);
3214#endif
3215        }
3216
3217        if (layer->debugDrawUpdate) {
3218            layer->debugDrawUpdate = false;
3219
3220            SkPaint paint;
3221            paint.setColor(0x7f00ff00);
3222            drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
3223        }
3224    }
3225    layer->hasDrawnSinceUpdate = true;
3226
3227    if (transform && !transform->isIdentity()) {
3228        restore();
3229    }
3230
3231    mDirty = true;
3232}
3233
3234///////////////////////////////////////////////////////////////////////////////
3235// Draw filters
3236///////////////////////////////////////////////////////////////////////////////
3237void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) {
3238    // We should never get here since we apply the draw filter when stashing
3239    // the paints in the DisplayList.
3240    LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters");
3241}
3242
3243///////////////////////////////////////////////////////////////////////////////
3244// Drawing implementation
3245///////////////////////////////////////////////////////////////////////////////
3246
3247Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) {
3248    Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
3249    if (!texture) {
3250        return mCaches.textureCache.get(bitmap);
3251    }
3252    return texture;
3253}
3254
3255void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y,
3256        const SkPaint* paint) {
3257    if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) {
3258        return;
3259    }
3260
3261    if (USE_GLOPS) {
3262        Glop glop;
3263        GlopBuilder(mRenderState, mCaches, &glop)
3264                .setMeshTexturedUnitQuad(nullptr)
3265                .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
3266                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
3267                .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
3268                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
3269                .build();
3270        renderGlop(glop);
3271        return;
3272    }
3273
3274
3275    int alpha;
3276    SkXfermode::Mode mode;
3277    getAlphaAndMode(paint, &alpha, &mode);
3278
3279    setupDraw();
3280    setupDrawWithTexture(true);
3281    setupDrawAlpha8Color(paint->getColor(), alpha);
3282    setupDrawColorFilter(getColorFilter(paint));
3283    setupDrawShader(getShader(paint));
3284    setupDrawBlending(paint, true);
3285    setupDrawProgram();
3286    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
3287            x, y, x + texture->width, y + texture->height);
3288    setupDrawTexture(texture->id);
3289    setupDrawPureColorUniforms();
3290    setupDrawColorFilterUniforms(getColorFilter(paint));
3291    setupDrawShaderUniforms(getShader(paint));
3292    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
3293
3294    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
3295}
3296
3297// Same values used by Skia
3298#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
3299#define kStdUnderline_Offset    (1.0f / 9.0f)
3300#define kStdUnderline_Thickness (1.0f / 18.0f)
3301
3302void OpenGLRenderer::drawTextDecorations(float underlineWidth, float x, float y,
3303        const SkPaint* paint) {
3304    // Handle underline and strike-through
3305    uint32_t flags = paint->getFlags();
3306    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
3307        SkPaint paintCopy(*paint);
3308
3309        if (CC_LIKELY(underlineWidth > 0.0f)) {
3310            const float textSize = paintCopy.getTextSize();
3311            const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
3312
3313            const float left = x;
3314            float top = 0.0f;
3315
3316            int linesCount = 0;
3317            if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
3318            if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
3319
3320            const int pointsCount = 4 * linesCount;
3321            float points[pointsCount];
3322            int currentPoint = 0;
3323
3324            if (flags & SkPaint::kUnderlineText_Flag) {
3325                top = y + textSize * kStdUnderline_Offset;
3326                points[currentPoint++] = left;
3327                points[currentPoint++] = top;
3328                points[currentPoint++] = left + underlineWidth;
3329                points[currentPoint++] = top;
3330            }
3331
3332            if (flags & SkPaint::kStrikeThruText_Flag) {
3333                top = y + textSize * kStdStrikeThru_Offset;
3334                points[currentPoint++] = left;
3335                points[currentPoint++] = top;
3336                points[currentPoint++] = left + underlineWidth;
3337                points[currentPoint++] = top;
3338            }
3339
3340            paintCopy.setStrokeWidth(strokeWidth);
3341
3342            drawLines(&points[0], pointsCount, &paintCopy);
3343        }
3344    }
3345}
3346
3347void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
3348    if (mState.currentlyIgnored()) {
3349        return;
3350    }
3351
3352    drawColorRects(rects, count, paint, false, true, true);
3353}
3354
3355void OpenGLRenderer::drawShadow(float casterAlpha,
3356        const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
3357    if (mState.currentlyIgnored()) return;
3358
3359    // TODO: use quickRejectWithScissor. For now, always force enable scissor.
3360    mRenderState.scissor().setEnabled(true);
3361
3362    SkPaint paint;
3363    paint.setAntiAlias(true); // want to use AlphaVertex
3364
3365    // The caller has made sure casterAlpha > 0.
3366    float ambientShadowAlpha = mAmbientShadowAlpha;
3367    if (CC_UNLIKELY(mCaches.propertyAmbientShadowStrength >= 0)) {
3368        ambientShadowAlpha = mCaches.propertyAmbientShadowStrength;
3369    }
3370    if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
3371        paint.setARGB(casterAlpha * ambientShadowAlpha, 0, 0, 0);
3372        drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
3373    }
3374
3375    float spotShadowAlpha = mSpotShadowAlpha;
3376    if (CC_UNLIKELY(mCaches.propertySpotShadowStrength >= 0)) {
3377        spotShadowAlpha = mCaches.propertySpotShadowStrength;
3378    }
3379    if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
3380        paint.setARGB(casterAlpha * spotShadowAlpha, 0, 0, 0);
3381        drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
3382    }
3383
3384    mDirty=true;
3385}
3386
3387void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
3388        bool ignoreTransform, bool dirty, bool clip) {
3389    if (count == 0) {
3390        return;
3391    }
3392
3393    float left = FLT_MAX;
3394    float top = FLT_MAX;
3395    float right = FLT_MIN;
3396    float bottom = FLT_MIN;
3397
3398    Vertex mesh[count];
3399    Vertex* vertex = mesh;
3400
3401    for (int index = 0; index < count; index += 4) {
3402        float l = rects[index + 0];
3403        float t = rects[index + 1];
3404        float r = rects[index + 2];
3405        float b = rects[index + 3];
3406
3407        Vertex::set(vertex++, l, t);
3408        Vertex::set(vertex++, r, t);
3409        Vertex::set(vertex++, l, b);
3410        Vertex::set(vertex++, r, b);
3411
3412        left = fminf(left, l);
3413        top = fminf(top, t);
3414        right = fmaxf(right, r);
3415        bottom = fmaxf(bottom, b);
3416    }
3417
3418    if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
3419        return;
3420    }
3421
3422    if (USE_GLOPS) {
3423        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
3424        Glop glop;
3425        GlopBuilder(mRenderState, mCaches, &glop)
3426                .setMeshIndexedQuads(&mesh[0], count / 4)
3427                .setFillPaint(*paint, currentSnapshot()->alpha)
3428                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
3429                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
3430                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
3431                .build();
3432        renderGlop(glop);
3433        return;
3434    }
3435
3436    int color = paint->getColor();
3437    // If a shader is set, preserve only the alpha
3438    if (getShader(paint)) {
3439        color |= 0x00ffffff;
3440    }
3441
3442    setupDraw();
3443    setupDrawNoTexture();
3444    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
3445    setupDrawShader(getShader(paint));
3446    setupDrawColorFilter(getColorFilter(paint));
3447    setupDrawBlending(paint);
3448    setupDrawProgram();
3449    setupDrawDirtyRegionsDisabled();
3450    setupDrawModelView(kModelViewMode_Translate, false,
3451            0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
3452    setupDrawColorUniforms(getShader(paint));
3453    setupDrawShaderUniforms(getShader(paint));
3454    setupDrawColorFilterUniforms(getColorFilter(paint));
3455
3456    if (dirty && hasLayer()) {
3457        dirtyLayer(left, top, right, bottom, *currentTransform());
3458    }
3459
3460    issueIndexedQuadDraw(&mesh[0], count / 4);
3461
3462    mDirty = true;
3463}
3464
3465void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
3466        const SkPaint* paint, bool ignoreTransform) {
3467
3468    if (USE_GLOPS) {
3469        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
3470        Glop glop;
3471        GlopBuilder(mRenderState, mCaches, &glop)
3472                .setMeshUnitQuad()
3473                .setFillPaint(*paint, currentSnapshot()->alpha)
3474                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
3475                .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
3476                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
3477                .build();
3478        renderGlop(glop);
3479        return;
3480    }
3481
3482    int color = paint->getColor();
3483    // If a shader is set, preserve only the alpha
3484    if (getShader(paint)) {
3485        color |= 0x00ffffff;
3486    }
3487
3488    setupDraw();
3489    setupDrawNoTexture();
3490    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
3491    setupDrawShader(getShader(paint));
3492    setupDrawColorFilter(getColorFilter(paint));
3493    setupDrawBlending(paint);
3494    setupDrawProgram();
3495    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
3496            left, top, right, bottom, ignoreTransform);
3497    setupDrawColorUniforms(getShader(paint));
3498    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
3499    setupDrawColorFilterUniforms(getColorFilter(paint));
3500    setupDrawSimpleMesh();
3501
3502    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
3503}
3504
3505void OpenGLRenderer::drawTextureRect(Texture* texture, const SkPaint* paint) {
3506    texture->setWrap(GL_CLAMP_TO_EDGE, true);
3507
3508    GLvoid* vertices = (GLvoid*) nullptr;
3509    GLvoid* texCoords = (GLvoid*) kMeshTextureOffset;
3510
3511    if (texture->uvMapper) {
3512        vertices = &mMeshVertices[0].x;
3513        texCoords = &mMeshVertices[0].u;
3514
3515        Rect uvs(0.0f, 0.0f, 1.0f, 1.0f);
3516        texture->uvMapper->map(uvs);
3517
3518        resetDrawTextureTexCoords(uvs.left, uvs.top, uvs.right, uvs.bottom);
3519    }
3520
3521    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
3522        const float x = floorf(currentTransform()->getTranslateX() + 0.5f);
3523        const float y = floorf(currentTransform()->getTranslateY() + 0.5f);
3524
3525        texture->setFilter(GL_NEAREST, true);
3526        drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
3527                paint, texture->blend, vertices, texCoords,
3528                GL_TRIANGLE_STRIP, kUnitQuadCount, false, true);
3529    } else {
3530        texture->setFilter(PaintUtils::getFilter(paint), true);
3531        drawTextureMesh(0, 0, texture->width, texture->height, texture->id, paint,
3532                texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kUnitQuadCount);
3533    }
3534
3535    if (texture->uvMapper) {
3536        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
3537    }
3538}
3539
3540void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
3541        GLuint texture, const SkPaint* paint, bool blend,
3542        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
3543        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
3544        ModelViewMode modelViewMode, bool dirty) {
3545
3546    int a;
3547    SkXfermode::Mode mode;
3548    getAlphaAndMode(paint, &a, &mode);
3549    const float alpha = a / 255.0f;
3550
3551    setupDraw();
3552    setupDrawWithTexture();
3553    setupDrawColor(alpha, alpha, alpha, alpha);
3554    setupDrawColorFilter(getColorFilter(paint));
3555    setupDrawBlending(paint, blend, swapSrcDst);
3556    setupDrawProgram();
3557    if (!dirty) setupDrawDirtyRegionsDisabled();
3558    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3559    setupDrawTexture(texture);
3560    setupDrawPureColorUniforms();
3561    setupDrawColorFilterUniforms(getColorFilter(paint));
3562    setupDrawMesh(vertices, texCoords, vbo);
3563
3564    glDrawArrays(drawMode, 0, elementsCount);
3565}
3566
3567void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
3568        GLuint texture, const SkPaint* paint, bool blend,
3569        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
3570        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
3571        ModelViewMode modelViewMode, bool dirty) {
3572
3573    int a;
3574    SkXfermode::Mode mode;
3575    getAlphaAndMode(paint, &a, &mode);
3576    const float alpha = a / 255.0f;
3577
3578    setupDraw();
3579    setupDrawWithTexture();
3580    setupDrawColor(alpha, alpha, alpha, alpha);
3581    setupDrawColorFilter(getColorFilter(paint));
3582    setupDrawBlending(paint, blend, swapSrcDst);
3583    setupDrawProgram();
3584    if (!dirty) setupDrawDirtyRegionsDisabled();
3585    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3586    setupDrawTexture(texture);
3587    setupDrawPureColorUniforms();
3588    setupDrawColorFilterUniforms(getColorFilter(paint));
3589    setupDrawMeshIndices(vertices, texCoords, vbo);
3590
3591    glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, nullptr);
3592}
3593
3594void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
3595        GLuint texture, const SkPaint* paint,
3596        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
3597        bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
3598
3599    int color = paint != nullptr ? paint->getColor() : 0;
3600    int alpha;
3601    SkXfermode::Mode mode;
3602    getAlphaAndMode(paint, &alpha, &mode);
3603
3604    setupDraw();
3605    setupDrawWithTexture(true);
3606    if (paint != nullptr) {
3607        setupDrawAlpha8Color(color, alpha);
3608    }
3609    setupDrawColorFilter(getColorFilter(paint));
3610    setupDrawShader(getShader(paint));
3611    setupDrawBlending(paint, true);
3612    setupDrawProgram();
3613    if (!dirty) setupDrawDirtyRegionsDisabled();
3614    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3615    setupDrawTexture(texture);
3616    setupDrawPureColorUniforms();
3617    setupDrawColorFilterUniforms(getColorFilter(paint));
3618    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
3619    setupDrawMesh(vertices, texCoords);
3620
3621    glDrawArrays(drawMode, 0, elementsCount);
3622}
3623
3624void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
3625        ProgramDescription& description, bool swapSrcDst) {
3626
3627    if (currentSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) {
3628        blend = true;
3629        mDescription.hasRoundRectClip = true;
3630    }
3631    mSkipOutlineClip = true;
3632
3633    blend = blend || mode != SkXfermode::kSrcOver_Mode;
3634
3635    if (blend) {
3636        // These blend modes are not supported by OpenGL directly and have
3637        // to be implemented using shaders. Since the shader will perform
3638        // the blending, turn blending off here
3639        // If the blend mode cannot be implemented using shaders, fall
3640        // back to the default SrcOver blend mode instead
3641        if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
3642            if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
3643                description.framebufferMode = mode;
3644                description.swapSrcDst = swapSrcDst;
3645
3646                mRenderState.blend().disable();
3647                return;
3648            } else {
3649                mode = SkXfermode::kSrcOver_Mode;
3650            }
3651        }
3652        mRenderState.blend().enable(mode,
3653                swapSrcDst ? Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap);
3654    } else {
3655        mRenderState.blend().disable();
3656    }
3657}
3658
3659void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
3660    TextureVertex* v = &mMeshVertices[0];
3661    TextureVertex::setUV(v++, u1, v1);
3662    TextureVertex::setUV(v++, u2, v1);
3663    TextureVertex::setUV(v++, u1, v2);
3664    TextureVertex::setUV(v++, u2, v2);
3665}
3666
3667void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha,
3668        SkXfermode::Mode* mode) const {
3669    getAlphaAndModeDirect(paint, alpha,  mode);
3670    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
3671        // if drawing a layer, ignore the paint's alpha
3672        *alpha = mDrawModifiers.mOverrideLayerAlpha * 255;
3673    }
3674    *alpha *= currentSnapshot()->alpha;
3675}
3676
3677float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
3678    float alpha;
3679    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
3680        alpha = mDrawModifiers.mOverrideLayerAlpha;
3681    } else {
3682        alpha = layer->getAlpha() / 255.0f;
3683    }
3684    return alpha * currentSnapshot()->alpha;
3685}
3686
3687}; // namespace uirenderer
3688}; // namespace android
3689