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