OpenGLRenderer.cpp revision 710f46d9d6a5bf9ea1c1833384caf61e1934124f
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 <SkPathMeasure.h>
25#include <SkTypeface.h>
26
27#include <utils/Log.h>
28#include <utils/StopWatch.h>
29
30#include <private/hwui/DrawGlInfo.h>
31
32#include <ui/Rect.h>
33
34#include "OpenGLRenderer.h"
35#include "DisplayListRenderer.h"
36#include "PathRenderer.h"
37#include "Vector.h"
38
39namespace android {
40namespace uirenderer {
41
42///////////////////////////////////////////////////////////////////////////////
43// Defines
44///////////////////////////////////////////////////////////////////////////////
45
46#define RAD_TO_DEG (180.0f / 3.14159265f)
47#define MIN_ANGLE 0.001f
48
49#define ALPHA_THRESHOLD 0
50
51#define FILTER(paint) (paint && paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST)
52
53///////////////////////////////////////////////////////////////////////////////
54// Globals
55///////////////////////////////////////////////////////////////////////////////
56
57/**
58 * Structure mapping Skia xfermodes to OpenGL blending factors.
59 */
60struct Blender {
61    SkXfermode::Mode mode;
62    GLenum src;
63    GLenum dst;
64}; // struct Blender
65
66// In this array, the index of each Blender equals the value of the first
67// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
68static const Blender gBlends[] = {
69    { SkXfermode::kClear_Mode,    GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
70    { SkXfermode::kSrc_Mode,      GL_ONE,                 GL_ZERO },
71    { SkXfermode::kDst_Mode,      GL_ZERO,                GL_ONE },
72    { SkXfermode::kSrcOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
73    { SkXfermode::kDstOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
74    { SkXfermode::kSrcIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
75    { SkXfermode::kDstIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
76    { SkXfermode::kSrcOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
77    { SkXfermode::kDstOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
78    { SkXfermode::kSrcATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
79    { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
80    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
81    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
82    { SkXfermode::kMultiply_Mode, GL_ZERO,                GL_SRC_COLOR },
83    { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
84};
85
86// This array contains the swapped version of each SkXfermode. For instance
87// this array's SrcOver blending mode is actually DstOver. You can refer to
88// createLayer() for more information on the purpose of this array.
89static const Blender gBlendsSwap[] = {
90    { SkXfermode::kClear_Mode,    GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
91    { SkXfermode::kSrc_Mode,      GL_ZERO,                GL_ONE },
92    { SkXfermode::kDst_Mode,      GL_ONE,                 GL_ZERO },
93    { SkXfermode::kSrcOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
94    { SkXfermode::kDstOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
95    { SkXfermode::kSrcIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
96    { SkXfermode::kDstIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
97    { SkXfermode::kSrcOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
98    { SkXfermode::kDstOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
99    { SkXfermode::kSrcATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
100    { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
101    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
102    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
103    { SkXfermode::kMultiply_Mode, GL_DST_COLOR,           GL_ZERO },
104    { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
105};
106
107///////////////////////////////////////////////////////////////////////////////
108// Constructors/destructor
109///////////////////////////////////////////////////////////////////////////////
110
111OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) {
112    mShader = NULL;
113    mColorFilter = NULL;
114    mHasShadow = false;
115    mHasDrawFilter = false;
116
117    memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
118
119    mFirstSnapshot = new Snapshot;
120}
121
122OpenGLRenderer::~OpenGLRenderer() {
123    // The context has already been destroyed at this point, do not call
124    // GL APIs. All GL state should be kept in Caches.h
125}
126
127///////////////////////////////////////////////////////////////////////////////
128// Debug
129///////////////////////////////////////////////////////////////////////////////
130
131void OpenGLRenderer::startMark(const char* name) const {
132    mCaches.startMark(0, name);
133}
134
135void OpenGLRenderer::endMark() const {
136    mCaches.endMark();
137}
138
139///////////////////////////////////////////////////////////////////////////////
140// Setup
141///////////////////////////////////////////////////////////////////////////////
142
143bool OpenGLRenderer::isDeferred() {
144    return false;
145}
146
147void OpenGLRenderer::setViewport(int width, int height) {
148    initViewport(width, height);
149
150    glDisable(GL_DITHER);
151    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
152
153    glEnableVertexAttribArray(Program::kBindingPosition);
154}
155
156void OpenGLRenderer::initViewport(int width, int height) {
157    mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
158
159    mWidth = width;
160    mHeight = height;
161
162    mFirstSnapshot->height = height;
163    mFirstSnapshot->viewport.set(0, 0, width, height);
164}
165
166int OpenGLRenderer::prepare(bool opaque) {
167    return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
168}
169
170int OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
171    mCaches.clearGarbage();
172
173    mSnapshot = new Snapshot(mFirstSnapshot,
174            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
175    mSnapshot->fbo = getTargetFbo();
176    mSaveCount = 1;
177
178    mSnapshot->setClip(left, top, right, bottom);
179    mDirtyClip = mOpaqueFrame = opaque;
180
181    // If we know that we are going to redraw the entire framebuffer,
182    // perform a discard to let the driver know we don't need to preserve
183    // the back buffer for this frame.
184    if (mCaches.extensions.hasDiscardFramebuffer() &&
185            left <= 0.0f && top <= 0.0f && right >= mWidth && bottom >= mHeight) {
186        const GLenum attachments[] = { getTargetFbo() == 0 ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0 };
187        glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
188    }
189
190    syncState();
191
192    mTilingSnapshot = mSnapshot;
193    startTiling();
194
195    if (!opaque) {
196        mCaches.enableScissor();
197        mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
198        glClear(GL_COLOR_BUFFER_BIT);
199        return DrawGlInfo::kStatusDrew;
200    } else {
201        mCaches.resetScissor();
202    }
203
204    return DrawGlInfo::kStatusDone;
205}
206
207void OpenGLRenderer::syncState() {
208    glViewport(0, 0, mWidth, mHeight);
209
210    if (mCaches.blend) {
211        glEnable(GL_BLEND);
212    } else {
213        glDisable(GL_BLEND);
214    }
215}
216
217void OpenGLRenderer::startTiling() {
218    startTiling(mTilingSnapshot);
219}
220
221void OpenGLRenderer::startTiling(const sp<Snapshot>& s) {
222    bool opaque = mOpaqueFrame;
223    Rect* clip = mTilingSnapshot->clipRect;
224
225    if (s->flags & Snapshot::kFlagIsFboLayer) {
226        opaque = !s->layer->isBlend();
227        clip = s->clipRect;
228    }
229
230    mCaches.startTiling(clip->left, s->height - clip->bottom,
231            clip->right - clip->left, clip->bottom - clip->top, opaque);
232}
233
234void OpenGLRenderer::endTiling() {
235    mCaches.endTiling();
236}
237
238void OpenGLRenderer::finish() {
239    endTiling();
240
241#if DEBUG_OPENGL
242    GLenum status = GL_NO_ERROR;
243    while ((status = glGetError()) != GL_NO_ERROR) {
244        ALOGD("GL error from OpenGLRenderer: 0x%x", status);
245        switch (status) {
246            case GL_INVALID_ENUM:
247                ALOGE("  GL_INVALID_ENUM");
248                break;
249            case GL_INVALID_VALUE:
250                ALOGE("  GL_INVALID_VALUE");
251                break;
252            case GL_INVALID_OPERATION:
253                ALOGE("  GL_INVALID_OPERATION");
254                break;
255            case GL_OUT_OF_MEMORY:
256                ALOGE("  Out of memory!");
257                break;
258        }
259    }
260#endif
261#if DEBUG_MEMORY_USAGE
262    mCaches.dumpMemoryUsage();
263#else
264    if (mCaches.getDebugLevel() & kDebugMemory) {
265        mCaches.dumpMemoryUsage();
266    }
267#endif
268}
269
270void OpenGLRenderer::interrupt() {
271    if (mCaches.currentProgram) {
272        if (mCaches.currentProgram->isInUse()) {
273            mCaches.currentProgram->remove();
274            mCaches.currentProgram = NULL;
275        }
276    }
277    mCaches.unbindMeshBuffer();
278    mCaches.unbindIndicesBuffer();
279    mCaches.resetVertexPointers();
280    mCaches.disbaleTexCoordsVertexArray();
281}
282
283void OpenGLRenderer::resume() {
284    sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
285    glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
286    glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
287
288    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
289
290    mCaches.scissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
291    mCaches.enableScissor();
292    mCaches.resetScissor();
293    dirtyClip();
294
295    mCaches.activeTexture(0);
296
297    mCaches.blend = true;
298    glEnable(GL_BLEND);
299    glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode);
300    glBlendEquation(GL_FUNC_ADD);
301}
302
303void OpenGLRenderer::resumeAfterLayer() {
304    sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
305    glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
306    glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
307
308    mCaches.resetScissor();
309    dirtyClip();
310}
311
312void OpenGLRenderer::detachFunctor(Functor* functor) {
313    mFunctors.remove(functor);
314}
315
316void OpenGLRenderer::attachFunctor(Functor* functor) {
317    mFunctors.add(functor);
318}
319
320status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
321    status_t result = DrawGlInfo::kStatusDone;
322    size_t count = mFunctors.size();
323
324    if (count > 0) {
325        SortedVector<Functor*> functors(mFunctors);
326        mFunctors.clear();
327
328        DrawGlInfo info;
329        info.clipLeft = 0;
330        info.clipTop = 0;
331        info.clipRight = 0;
332        info.clipBottom = 0;
333        info.isLayer = false;
334        info.width = 0;
335        info.height = 0;
336        memset(info.transform, 0, sizeof(float) * 16);
337
338        for (size_t i = 0; i < count; i++) {
339            Functor* f = functors.itemAt(i);
340            result |= (*f)(DrawGlInfo::kModeProcess, &info);
341
342            if (result & DrawGlInfo::kStatusDraw) {
343                Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
344                dirty.unionWith(localDirty);
345            }
346
347            if (result & DrawGlInfo::kStatusInvoke) {
348                mFunctors.add(f);
349            }
350        }
351        // protect against functors binding to other buffers
352        mCaches.unbindMeshBuffer();
353        mCaches.unbindIndicesBuffer();
354        mCaches.activeTexture(0);
355    }
356
357    return result;
358}
359
360status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
361    interrupt();
362    detachFunctor(functor);
363
364    mCaches.enableScissor();
365    if (mDirtyClip) {
366        setScissorFromClip();
367    }
368
369    Rect clip(*mSnapshot->clipRect);
370    clip.snapToPixelBoundaries();
371
372    // Since we don't know what the functor will draw, let's dirty
373    // tne entire clip region
374    if (hasLayer()) {
375        dirtyLayerUnchecked(clip, getRegion());
376    }
377
378    DrawGlInfo info;
379    info.clipLeft = clip.left;
380    info.clipTop = clip.top;
381    info.clipRight = clip.right;
382    info.clipBottom = clip.bottom;
383    info.isLayer = hasLayer();
384    info.width = getSnapshot()->viewport.getWidth();
385    info.height = getSnapshot()->height;
386    getSnapshot()->transform->copyTo(&info.transform[0]);
387
388    status_t result = (*functor)(DrawGlInfo::kModeDraw, &info) | DrawGlInfo::kStatusDrew;
389
390    if (result != DrawGlInfo::kStatusDone) {
391        Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
392        dirty.unionWith(localDirty);
393
394        if (result & DrawGlInfo::kStatusInvoke) {
395            mFunctors.add(functor);
396        }
397    }
398
399    resume();
400    return result;
401}
402
403///////////////////////////////////////////////////////////////////////////////
404// State management
405///////////////////////////////////////////////////////////////////////////////
406
407int OpenGLRenderer::getSaveCount() const {
408    return mSaveCount;
409}
410
411int OpenGLRenderer::save(int flags) {
412    return saveSnapshot(flags);
413}
414
415void OpenGLRenderer::restore() {
416    if (mSaveCount > 1) {
417        restoreSnapshot();
418    }
419}
420
421void OpenGLRenderer::restoreToCount(int saveCount) {
422    if (saveCount < 1) saveCount = 1;
423
424    while (mSaveCount > saveCount) {
425        restoreSnapshot();
426    }
427}
428
429int OpenGLRenderer::saveSnapshot(int flags) {
430    mSnapshot = new Snapshot(mSnapshot, flags);
431    return mSaveCount++;
432}
433
434bool OpenGLRenderer::restoreSnapshot() {
435    bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
436    bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
437    bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho;
438
439    sp<Snapshot> current = mSnapshot;
440    sp<Snapshot> previous = mSnapshot->previous;
441
442    if (restoreOrtho) {
443        Rect& r = previous->viewport;
444        glViewport(r.left, r.top, r.right, r.bottom);
445        mOrthoMatrix.load(current->orthoMatrix);
446    }
447
448    mSaveCount--;
449    mSnapshot = previous;
450
451    if (restoreClip) {
452        dirtyClip();
453    }
454
455    if (restoreLayer) {
456        composeLayer(current, previous);
457    }
458
459    return restoreClip;
460}
461
462///////////////////////////////////////////////////////////////////////////////
463// Layers
464///////////////////////////////////////////////////////////////////////////////
465
466int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
467        SkPaint* p, int flags) {
468    const GLuint previousFbo = mSnapshot->fbo;
469    const int count = saveSnapshot(flags);
470
471    if (!mSnapshot->isIgnored()) {
472        int alpha = 255;
473        SkXfermode::Mode mode;
474
475        if (p) {
476            alpha = p->getAlpha();
477            mode = getXfermode(p->getXfermode());
478        } else {
479            mode = SkXfermode::kSrcOver_Mode;
480        }
481
482        createLayer(left, top, right, bottom, alpha, mode, flags, previousFbo);
483    }
484
485    return count;
486}
487
488int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
489        int alpha, int flags) {
490    if (alpha >= 255) {
491        return saveLayer(left, top, right, bottom, NULL, flags);
492    } else {
493        SkPaint paint;
494        paint.setAlpha(alpha);
495        return saveLayer(left, top, right, bottom, &paint, flags);
496    }
497}
498
499/**
500 * Layers are viewed by Skia are slightly different than layers in image editing
501 * programs (for instance.) When a layer is created, previously created layers
502 * and the frame buffer still receive every drawing command. For instance, if a
503 * layer is created and a shape intersecting the bounds of the layers and the
504 * framebuffer is draw, the shape will be drawn on both (unless the layer was
505 * created with the SkCanvas::kClipToLayer_SaveFlag flag.)
506 *
507 * A way to implement layers is to create an FBO for each layer, backed by an RGBA
508 * texture. Unfortunately, this is inefficient as it requires every primitive to
509 * be drawn n + 1 times, where n is the number of active layers. In practice this
510 * means, for every primitive:
511 *   - Switch active frame buffer
512 *   - Change viewport, clip and projection matrix
513 *   - Issue the drawing
514 *
515 * Switching rendering target n + 1 times per drawn primitive is extremely costly.
516 * To avoid this, layers are implemented in a different way here, at least in the
517 * general case. FBOs are used, as an optimization, when the "clip to layer" flag
518 * is set. When this flag is set we can redirect all drawing operations into a
519 * single FBO.
520 *
521 * This implementation relies on the frame buffer being at least RGBA 8888. When
522 * a layer is created, only a texture is created, not an FBO. The content of the
523 * frame buffer contained within the layer's bounds is copied into this texture
524 * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
525 * buffer and drawing continues as normal. This technique therefore treats the
526 * frame buffer as a scratch buffer for the layers.
527 *
528 * To compose the layers back onto the frame buffer, each layer texture
529 * (containing the original frame buffer data) is drawn as a simple quad over
530 * the frame buffer. The trick is that the quad is set as the composition
531 * destination in the blending equation, and the frame buffer becomes the source
532 * of the composition.
533 *
534 * Drawing layers with an alpha value requires an extra step before composition.
535 * An empty quad is drawn over the layer's region in the frame buffer. This quad
536 * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
537 * quad is used to multiply the colors in the frame buffer. This is achieved by
538 * changing the GL blend functions for the GL_FUNC_ADD blend equation to
539 * GL_ZERO, GL_SRC_ALPHA.
540 *
541 * Because glCopyTexImage2D() can be slow, an alternative implementation might
542 * be use to draw a single clipped layer. The implementation described above
543 * is correct in every case.
544 *
545 * (1) The frame buffer is actually not cleared right away. To allow the GPU
546 *     to potentially optimize series of calls to glCopyTexImage2D, the frame
547 *     buffer is left untouched until the first drawing operation. Only when
548 *     something actually gets drawn are the layers regions cleared.
549 */
550bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
551        int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo) {
552    LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
553    LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
554
555    const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
556
557    // Window coordinates of the layer
558    Rect clip;
559    Rect bounds(left, top, right, bottom);
560    Rect untransformedBounds(bounds);
561    mSnapshot->transform->mapRect(bounds);
562
563    // Layers only make sense if they are in the framebuffer's bounds
564    if (bounds.intersect(*mSnapshot->clipRect)) {
565        // We cannot work with sub-pixels in this case
566        bounds.snapToPixelBoundaries();
567
568        // When the layer is not an FBO, we may use glCopyTexImage so we
569        // need to make sure the layer does not extend outside the bounds
570        // of the framebuffer
571        if (!bounds.intersect(mSnapshot->previous->viewport)) {
572            bounds.setEmpty();
573        } else if (fboLayer) {
574            clip.set(bounds);
575            mat4 inverse;
576            inverse.loadInverse(*mSnapshot->transform);
577            inverse.mapRect(clip);
578            clip.snapToPixelBoundaries();
579            if (clip.intersect(untransformedBounds)) {
580                clip.translate(-left, -top);
581                bounds.set(untransformedBounds);
582            } else {
583                clip.setEmpty();
584            }
585        }
586    } else {
587        bounds.setEmpty();
588    }
589
590    if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
591            bounds.getHeight() > mCaches.maxTextureSize ||
592            (fboLayer && clip.isEmpty())) {
593        mSnapshot->empty = fboLayer;
594    } else {
595        mSnapshot->invisible = mSnapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer);
596    }
597
598    // Bail out if we won't draw in this snapshot
599    if (mSnapshot->invisible || mSnapshot->empty) {
600        return false;
601    }
602
603    mCaches.activeTexture(0);
604    Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
605    if (!layer) {
606        return false;
607    }
608
609    layer->setAlpha(alpha, mode);
610    layer->layer.set(bounds);
611    layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
612            bounds.getWidth() / float(layer->getWidth()), 0.0f);
613    layer->setColorFilter(mColorFilter);
614    layer->setBlend(true);
615
616    // Save the layer in the snapshot
617    mSnapshot->flags |= Snapshot::kFlagIsLayer;
618    mSnapshot->layer = layer;
619
620    if (fboLayer) {
621        return createFboLayer(layer, bounds, clip, previousFbo);
622    } else {
623        // Copy the framebuffer into the layer
624        layer->bindTexture();
625        if (!bounds.isEmpty()) {
626            if (layer->isEmpty()) {
627                glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
628                        bounds.left, mSnapshot->height - bounds.bottom,
629                        layer->getWidth(), layer->getHeight(), 0);
630                layer->setEmpty(false);
631            } else {
632                glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
633                        mSnapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
634            }
635
636            // Enqueue the buffer coordinates to clear the corresponding region later
637            mLayers.push(new Rect(bounds));
638        }
639    }
640
641    return true;
642}
643
644bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLuint previousFbo) {
645    layer->setFbo(mCaches.fboCache.get());
646
647    mSnapshot->region = &mSnapshot->layer->region;
648    mSnapshot->flags |= Snapshot::kFlagFboTarget;
649
650    mSnapshot->flags |= Snapshot::kFlagIsFboLayer;
651    mSnapshot->fbo = layer->getFbo();
652    mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
653    mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
654    mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
655    mSnapshot->height = bounds.getHeight();
656    mSnapshot->flags |= Snapshot::kFlagDirtyOrtho;
657    mSnapshot->orthoMatrix.load(mOrthoMatrix);
658
659    endTiling();
660    // Bind texture to FBO
661    glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
662    layer->bindTexture();
663
664    // Initialize the texture if needed
665    if (layer->isEmpty()) {
666        layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
667        layer->setEmpty(false);
668    }
669
670    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
671            layer->getTexture(), 0);
672
673    startTiling(mSnapshot);
674
675    // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
676    mCaches.enableScissor();
677    mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
678            clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
679    glClear(GL_COLOR_BUFFER_BIT);
680
681    dirtyClip();
682
683    // Change the ortho projection
684    glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
685    mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
686
687    return true;
688}
689
690/**
691 * Read the documentation of createLayer() before doing anything in this method.
692 */
693void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
694    if (!current->layer) {
695        ALOGE("Attempting to compose a layer that does not exist");
696        return;
697    }
698
699    const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
700
701    if (fboLayer) {
702        endTiling();
703
704        // Detach the texture from the FBO
705        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
706        // Unbind current FBO and restore previous one
707        glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
708
709        startTiling(previous);
710    }
711
712    Layer* layer = current->layer;
713    const Rect& rect = layer->layer;
714
715    if (!fboLayer && layer->getAlpha() < 255) {
716        drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
717                layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true);
718        // Required below, composeLayerRect() will divide by 255
719        layer->setAlpha(255);
720    }
721
722    mCaches.unbindMeshBuffer();
723
724    mCaches.activeTexture(0);
725
726    // When the layer is stored in an FBO, we can save a bit of fillrate by
727    // drawing only the dirty region
728    if (fboLayer) {
729        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
730        if (layer->getColorFilter()) {
731            setupColorFilter(layer->getColorFilter());
732        }
733        composeLayerRegion(layer, rect);
734        if (layer->getColorFilter()) {
735            resetColorFilter();
736        }
737    } else if (!rect.isEmpty()) {
738        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
739        composeLayerRect(layer, rect, true);
740    }
741
742    if (fboLayer) {
743        // Note: No need to use glDiscardFramebufferEXT() since we never
744        //       create/compose layers that are not on screen with this
745        //       code path
746        // See LayerRenderer::destroyLayer(Layer*)
747
748        // Put the FBO name back in the cache, if it doesn't fit, it will be destroyed
749        mCaches.fboCache.put(current->fbo);
750        layer->setFbo(0);
751    }
752
753    dirtyClip();
754
755    // Failing to add the layer to the cache should happen only if the layer is too large
756    if (!mCaches.layerCache.put(layer)) {
757        LAYER_LOGD("Deleting layer");
758        Caches::getInstance().resourceCache.decrementRefcount(layer);
759    }
760}
761
762void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
763    float alpha = layer->getAlpha() / 255.0f;
764
765    mat4& transform = layer->getTransform();
766    if (!transform.isIdentity()) {
767        save(0);
768        mSnapshot->transform->multiply(transform);
769    }
770
771    setupDraw();
772    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
773        setupDrawWithTexture();
774    } else {
775        setupDrawWithExternalTexture();
776    }
777    setupDrawTextureTransform();
778    setupDrawColor(alpha, alpha, alpha, alpha);
779    setupDrawColorFilter();
780    setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode());
781    setupDrawProgram();
782    setupDrawPureColorUniforms();
783    setupDrawColorFilterUniforms();
784    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
785        setupDrawTexture(layer->getTexture());
786    } else {
787        setupDrawExternalTexture(layer->getTexture());
788    }
789    if (mSnapshot->transform->isPureTranslate() &&
790            layer->getWidth() == (uint32_t) rect.getWidth() &&
791            layer->getHeight() == (uint32_t) rect.getHeight()) {
792        const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
793        const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
794
795        layer->setFilter(GL_NEAREST);
796        setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
797    } else {
798        layer->setFilter(GL_LINEAR);
799        setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
800    }
801    setupDrawTextureTransformUniforms(layer->getTexTransform());
802    setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
803
804    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
805
806    finishDrawTexture();
807
808    if (!transform.isIdentity()) {
809        restore();
810    }
811}
812
813void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
814    if (!layer->isTextureLayer()) {
815        const Rect& texCoords = layer->texCoords;
816        resetDrawTextureTexCoords(texCoords.left, texCoords.top,
817                texCoords.right, texCoords.bottom);
818
819        float x = rect.left;
820        float y = rect.top;
821        bool simpleTransform = mSnapshot->transform->isPureTranslate() &&
822                layer->getWidth() == (uint32_t) rect.getWidth() &&
823                layer->getHeight() == (uint32_t) rect.getHeight();
824
825        if (simpleTransform) {
826            // When we're swapping, the layer is already in screen coordinates
827            if (!swap) {
828                x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
829                y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
830            }
831
832            layer->setFilter(GL_NEAREST, true);
833        } else {
834            layer->setFilter(GL_LINEAR, true);
835        }
836
837        drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
838                layer->getTexture(), layer->getAlpha() / 255.0f,
839                layer->getMode(), layer->isBlend(),
840                &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
841                GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
842
843        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
844    } else {
845        resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
846        drawTextureLayer(layer, rect);
847        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
848    }
849}
850
851void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
852    if (layer->region.isRect()) {
853        layer->setRegionAsRect();
854
855        composeLayerRect(layer, layer->regionRect);
856
857        layer->region.clear();
858        return;
859    }
860
861    // TODO: See LayerRenderer.cpp::generateMesh() for important
862    //       information about this implementation
863    if (CC_LIKELY(!layer->region.isEmpty())) {
864        size_t count;
865        const android::Rect* rects = layer->region.getArray(&count);
866
867        const float alpha = layer->getAlpha() / 255.0f;
868        const float texX = 1.0f / float(layer->getWidth());
869        const float texY = 1.0f / float(layer->getHeight());
870        const float height = rect.getHeight();
871
872        TextureVertex* mesh = mCaches.getRegionMesh();
873        GLsizei numQuads = 0;
874
875        setupDraw();
876        setupDrawWithTexture();
877        setupDrawColor(alpha, alpha, alpha, alpha);
878        setupDrawColorFilter();
879        setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false);
880        setupDrawProgram();
881        setupDrawDirtyRegionsDisabled();
882        setupDrawPureColorUniforms();
883        setupDrawColorFilterUniforms();
884        setupDrawTexture(layer->getTexture());
885        if (mSnapshot->transform->isPureTranslate()) {
886            const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
887            const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
888
889            layer->setFilter(GL_NEAREST);
890            setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
891        } else {
892            layer->setFilter(GL_LINEAR);
893            setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
894        }
895        setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]);
896
897        for (size_t i = 0; i < count; i++) {
898            const android::Rect* r = &rects[i];
899
900            const float u1 = r->left * texX;
901            const float v1 = (height - r->top) * texY;
902            const float u2 = r->right * texX;
903            const float v2 = (height - r->bottom) * texY;
904
905            // TODO: Reject quads outside of the clip
906            TextureVertex::set(mesh++, r->left, r->top, u1, v1);
907            TextureVertex::set(mesh++, r->right, r->top, u2, v1);
908            TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
909            TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
910
911            numQuads++;
912
913            if (numQuads >= REGION_MESH_QUAD_COUNT) {
914                glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
915                numQuads = 0;
916                mesh = mCaches.getRegionMesh();
917            }
918        }
919
920        if (numQuads > 0) {
921            glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
922        }
923
924        finishDrawTexture();
925
926#if DEBUG_LAYERS_AS_REGIONS
927        drawRegionRects(layer->region);
928#endif
929
930        layer->region.clear();
931    }
932}
933
934void OpenGLRenderer::drawRegionRects(const Region& region) {
935#if DEBUG_LAYERS_AS_REGIONS
936    size_t count;
937    const android::Rect* rects = region.getArray(&count);
938
939    uint32_t colors[] = {
940            0x7fff0000, 0x7f00ff00,
941            0x7f0000ff, 0x7fff00ff,
942    };
943
944    int offset = 0;
945    int32_t top = rects[0].top;
946
947    for (size_t i = 0; i < count; i++) {
948        if (top != rects[i].top) {
949            offset ^= 0x2;
950            top = rects[i].top;
951        }
952
953        Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
954        drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)],
955                SkXfermode::kSrcOver_Mode);
956    }
957#endif
958}
959
960void OpenGLRenderer::dirtyLayer(const float left, const float top,
961        const float right, const float bottom, const mat4 transform) {
962    if (hasLayer()) {
963        Rect bounds(left, top, right, bottom);
964        transform.mapRect(bounds);
965        dirtyLayerUnchecked(bounds, getRegion());
966    }
967}
968
969void OpenGLRenderer::dirtyLayer(const float left, const float top,
970        const float right, const float bottom) {
971    if (hasLayer()) {
972        Rect bounds(left, top, right, bottom);
973        dirtyLayerUnchecked(bounds, getRegion());
974    }
975}
976
977void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
978    if (bounds.intersect(*mSnapshot->clipRect)) {
979        bounds.snapToPixelBoundaries();
980        android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
981        if (!dirty.isEmpty()) {
982            region->orSelf(dirty);
983        }
984    }
985}
986
987void OpenGLRenderer::clearLayerRegions() {
988    const size_t count = mLayers.size();
989    if (count == 0) return;
990
991    if (!mSnapshot->isIgnored()) {
992        // Doing several glScissor/glClear here can negatively impact
993        // GPUs with a tiler architecture, instead we draw quads with
994        // the Clear blending mode
995
996        // The list contains bounds that have already been clipped
997        // against their initial clip rect, and the current clip
998        // is likely different so we need to disable clipping here
999        bool scissorChanged = mCaches.disableScissor();
1000
1001        Vertex mesh[count * 6];
1002        Vertex* vertex = mesh;
1003
1004        for (uint32_t i = 0; i < count; i++) {
1005            Rect* bounds = mLayers.itemAt(i);
1006
1007            Vertex::set(vertex++, bounds->left, bounds->bottom);
1008            Vertex::set(vertex++, bounds->left, bounds->top);
1009            Vertex::set(vertex++, bounds->right, bounds->top);
1010            Vertex::set(vertex++, bounds->left, bounds->bottom);
1011            Vertex::set(vertex++, bounds->right, bounds->top);
1012            Vertex::set(vertex++, bounds->right, bounds->bottom);
1013
1014            delete bounds;
1015        }
1016
1017        setupDraw(false);
1018        setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
1019        setupDrawBlending(true, SkXfermode::kClear_Mode);
1020        setupDrawProgram();
1021        setupDrawPureColorUniforms();
1022        setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
1023        setupDrawVertices(&mesh[0].position[0]);
1024
1025        glDrawArrays(GL_TRIANGLES, 0, count * 6);
1026
1027        if (scissorChanged) mCaches.enableScissor();
1028    } else {
1029        for (uint32_t i = 0; i < count; i++) {
1030            delete mLayers.itemAt(i);
1031        }
1032    }
1033
1034    mLayers.clear();
1035}
1036
1037///////////////////////////////////////////////////////////////////////////////
1038// Transforms
1039///////////////////////////////////////////////////////////////////////////////
1040
1041void OpenGLRenderer::translate(float dx, float dy) {
1042    mSnapshot->transform->translate(dx, dy, 0.0f);
1043}
1044
1045void OpenGLRenderer::rotate(float degrees) {
1046    mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
1047}
1048
1049void OpenGLRenderer::scale(float sx, float sy) {
1050    mSnapshot->transform->scale(sx, sy, 1.0f);
1051}
1052
1053void OpenGLRenderer::skew(float sx, float sy) {
1054    mSnapshot->transform->skew(sx, sy);
1055}
1056
1057void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
1058    if (matrix) {
1059        mSnapshot->transform->load(*matrix);
1060    } else {
1061        mSnapshot->transform->loadIdentity();
1062    }
1063}
1064
1065void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
1066    mSnapshot->transform->copyTo(*matrix);
1067}
1068
1069void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
1070    SkMatrix transform;
1071    mSnapshot->transform->copyTo(transform);
1072    transform.preConcat(*matrix);
1073    mSnapshot->transform->load(transform);
1074}
1075
1076///////////////////////////////////////////////////////////////////////////////
1077// Clipping
1078///////////////////////////////////////////////////////////////////////////////
1079
1080void OpenGLRenderer::setScissorFromClip() {
1081    Rect clip(*mSnapshot->clipRect);
1082    clip.snapToPixelBoundaries();
1083
1084    if (mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom,
1085            clip.getWidth(), clip.getHeight())) {
1086        mDirtyClip = false;
1087    }
1088}
1089
1090const Rect& OpenGLRenderer::getClipBounds() {
1091    return mSnapshot->getLocalClip();
1092}
1093
1094bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom) {
1095    if (mSnapshot->isIgnored()) {
1096        return true;
1097    }
1098
1099    Rect r(left, top, right, bottom);
1100    mSnapshot->transform->mapRect(r);
1101    r.snapToPixelBoundaries();
1102
1103    Rect clipRect(*mSnapshot->clipRect);
1104    clipRect.snapToPixelBoundaries();
1105
1106    return !clipRect.intersects(r);
1107}
1108
1109bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
1110        Rect& transformed, Rect& clip) {
1111    if (mSnapshot->isIgnored()) {
1112        return true;
1113    }
1114
1115    transformed.set(left, top, right, bottom);
1116    mSnapshot->transform->mapRect(transformed);
1117    transformed.snapToPixelBoundaries();
1118
1119    clip.set(*mSnapshot->clipRect);
1120    clip.snapToPixelBoundaries();
1121
1122    return !clip.intersects(transformed);
1123}
1124
1125bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
1126    if (mSnapshot->isIgnored()) {
1127        return true;
1128    }
1129
1130    Rect r(left, top, right, bottom);
1131    mSnapshot->transform->mapRect(r);
1132    r.snapToPixelBoundaries();
1133
1134    Rect clipRect(*mSnapshot->clipRect);
1135    clipRect.snapToPixelBoundaries();
1136
1137    bool rejected = !clipRect.intersects(r);
1138    if (!isDeferred() && !rejected) {
1139        mCaches.setScissorEnabled(!clipRect.contains(r));
1140    }
1141
1142    return rejected;
1143}
1144
1145bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
1146    bool clipped = mSnapshot->clip(left, top, right, bottom, op);
1147    if (clipped) {
1148        dirtyClip();
1149    }
1150    return !mSnapshot->clipRect->isEmpty();
1151}
1152
1153Rect* OpenGLRenderer::getClipRect() {
1154    return mSnapshot->clipRect;
1155}
1156
1157///////////////////////////////////////////////////////////////////////////////
1158// Drawing commands
1159///////////////////////////////////////////////////////////////////////////////
1160
1161void OpenGLRenderer::setupDraw(bool clear) {
1162    // TODO: It would be best if we could do this before quickReject()
1163    //       changes the scissor test state
1164    if (clear) clearLayerRegions();
1165    if (mDirtyClip) {
1166        setScissorFromClip();
1167    }
1168    mDescription.reset();
1169    mSetShaderColor = false;
1170    mColorSet = false;
1171    mColorA = mColorR = mColorG = mColorB = 0.0f;
1172    mTextureUnit = 0;
1173    mTrackDirtyRegions = true;
1174}
1175
1176void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
1177    mDescription.hasTexture = true;
1178    mDescription.hasAlpha8Texture = isAlpha8;
1179}
1180
1181void OpenGLRenderer::setupDrawWithExternalTexture() {
1182    mDescription.hasExternalTexture = true;
1183}
1184
1185void OpenGLRenderer::setupDrawNoTexture() {
1186    mCaches.disbaleTexCoordsVertexArray();
1187}
1188
1189void OpenGLRenderer::setupDrawAA() {
1190    mDescription.isAA = true;
1191}
1192
1193void OpenGLRenderer::setupDrawVertexShape() {
1194    mDescription.isVertexShape = true;
1195}
1196
1197void OpenGLRenderer::setupDrawPoint(float pointSize) {
1198    mDescription.isPoint = true;
1199    mDescription.pointSize = pointSize;
1200}
1201
1202void OpenGLRenderer::setupDrawColor(int color) {
1203    setupDrawColor(color, (color >> 24) & 0xFF);
1204}
1205
1206void OpenGLRenderer::setupDrawColor(int color, int alpha) {
1207    mColorA = alpha / 255.0f;
1208    // Second divide of a by 255 is an optimization, allowing us to simply multiply
1209    // the rgb values by a instead of also dividing by 255
1210    const float a = mColorA / 255.0f;
1211    mColorR = a * ((color >> 16) & 0xFF);
1212    mColorG = a * ((color >>  8) & 0xFF);
1213    mColorB = a * ((color      ) & 0xFF);
1214    mColorSet = true;
1215    mSetShaderColor = mDescription.setColor(mColorR, mColorG, mColorB, mColorA);
1216}
1217
1218void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
1219    mColorA = alpha / 255.0f;
1220    // Double-divide of a by 255 is an optimization, allowing us to simply multiply
1221    // the rgb values by a instead of also dividing by 255
1222    const float a = mColorA / 255.0f;
1223    mColorR = a * ((color >> 16) & 0xFF);
1224    mColorG = a * ((color >>  8) & 0xFF);
1225    mColorB = a * ((color      ) & 0xFF);
1226    mColorSet = true;
1227    mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA);
1228}
1229
1230void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
1231    mCaches.fontRenderer->describe(mDescription, paint);
1232}
1233
1234void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
1235    mColorA = a;
1236    mColorR = r;
1237    mColorG = g;
1238    mColorB = b;
1239    mColorSet = true;
1240    mSetShaderColor = mDescription.setColor(r, g, b, a);
1241}
1242
1243void OpenGLRenderer::setupDrawShader() {
1244    if (mShader) {
1245        mShader->describe(mDescription, mCaches.extensions);
1246    }
1247}
1248
1249void OpenGLRenderer::setupDrawColorFilter() {
1250    if (mColorFilter) {
1251        mColorFilter->describe(mDescription, mCaches.extensions);
1252    }
1253}
1254
1255void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
1256    if (mColorSet && mode == SkXfermode::kClear_Mode) {
1257        mColorA = 1.0f;
1258        mColorR = mColorG = mColorB = 0.0f;
1259        mSetShaderColor = mDescription.modulate = true;
1260    }
1261}
1262
1263void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) {
1264    // When the blending mode is kClear_Mode, we need to use a modulate color
1265    // argb=1,0,0,0
1266    accountForClear(mode);
1267    chooseBlending((mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()), mode,
1268            mDescription, swapSrcDst);
1269}
1270
1271void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) {
1272    // When the blending mode is kClear_Mode, we need to use a modulate color
1273    // argb=1,0,0,0
1274    accountForClear(mode);
1275    chooseBlending(blend || (mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()), mode,
1276            mDescription, swapSrcDst);
1277}
1278
1279void OpenGLRenderer::setupDrawProgram() {
1280    useProgram(mCaches.programCache.get(mDescription));
1281}
1282
1283void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
1284    mTrackDirtyRegions = false;
1285}
1286
1287void OpenGLRenderer::setupDrawModelViewTranslate(float left, float top, float right, float bottom,
1288        bool ignoreTransform) {
1289    mModelView.loadTranslate(left, top, 0.0f);
1290    if (!ignoreTransform) {
1291        mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
1292        if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
1293    } else {
1294        mCaches.currentProgram->set(mOrthoMatrix, mModelView, mIdentity);
1295        if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
1296    }
1297}
1298
1299void OpenGLRenderer::setupDrawModelViewIdentity(bool offset) {
1300    mCaches.currentProgram->set(mOrthoMatrix, mIdentity, *mSnapshot->transform, offset);
1301}
1302
1303void OpenGLRenderer::setupDrawModelView(float left, float top, float right, float bottom,
1304        bool ignoreTransform, bool ignoreModelView) {
1305    if (!ignoreModelView) {
1306        mModelView.loadTranslate(left, top, 0.0f);
1307        mModelView.scale(right - left, bottom - top, 1.0f);
1308    } else {
1309        mModelView.loadIdentity();
1310    }
1311    bool dirty = right - left > 0.0f && bottom - top > 0.0f;
1312    if (!ignoreTransform) {
1313        mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
1314        if (mTrackDirtyRegions && dirty) {
1315            dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
1316        }
1317    } else {
1318        mCaches.currentProgram->set(mOrthoMatrix, mModelView, mIdentity);
1319        if (mTrackDirtyRegions && dirty) dirtyLayer(left, top, right, bottom);
1320    }
1321}
1322
1323void OpenGLRenderer::setupDrawPointUniforms() {
1324    int slot = mCaches.currentProgram->getUniform("pointSize");
1325    glUniform1f(slot, mDescription.pointSize);
1326}
1327
1328void OpenGLRenderer::setupDrawColorUniforms() {
1329    if ((mColorSet && !mShader) || (mShader && mSetShaderColor)) {
1330        mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
1331    }
1332}
1333
1334void OpenGLRenderer::setupDrawPureColorUniforms() {
1335    if (mSetShaderColor) {
1336        mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
1337    }
1338}
1339
1340void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) {
1341    if (mShader) {
1342        if (ignoreTransform) {
1343            mModelView.loadInverse(*mSnapshot->transform);
1344        }
1345        mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &mTextureUnit);
1346    }
1347}
1348
1349void OpenGLRenderer::setupDrawShaderIdentityUniforms() {
1350    if (mShader) {
1351        mShader->setupProgram(mCaches.currentProgram, mIdentity, *mSnapshot, &mTextureUnit);
1352    }
1353}
1354
1355void OpenGLRenderer::setupDrawColorFilterUniforms() {
1356    if (mColorFilter) {
1357        mColorFilter->setupProgram(mCaches.currentProgram);
1358    }
1359}
1360
1361void OpenGLRenderer::setupDrawTextGammaUniforms() {
1362    mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram);
1363}
1364
1365void OpenGLRenderer::setupDrawSimpleMesh() {
1366    bool force = mCaches.bindMeshBuffer();
1367    mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, 0);
1368    mCaches.unbindIndicesBuffer();
1369}
1370
1371void OpenGLRenderer::setupDrawTexture(GLuint texture) {
1372    bindTexture(texture);
1373    mTextureUnit++;
1374    mCaches.enableTexCoordsVertexArray();
1375}
1376
1377void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
1378    bindExternalTexture(texture);
1379    mTextureUnit++;
1380    mCaches.enableTexCoordsVertexArray();
1381}
1382
1383void OpenGLRenderer::setupDrawTextureTransform() {
1384    mDescription.hasTextureTransform = true;
1385}
1386
1387void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
1388    glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
1389            GL_FALSE, &transform.data[0]);
1390}
1391
1392void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
1393    bool force = false;
1394    if (!vertices) {
1395        force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
1396    } else {
1397        force = mCaches.unbindMeshBuffer();
1398    }
1399
1400    mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices);
1401    if (mCaches.currentProgram->texCoords >= 0) {
1402        mCaches.bindTexCoordsVertexPointer(force, mCaches.currentProgram->texCoords, texCoords);
1403    }
1404
1405    mCaches.unbindIndicesBuffer();
1406}
1407
1408void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) {
1409    bool force = mCaches.unbindMeshBuffer();
1410    mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices);
1411    if (mCaches.currentProgram->texCoords >= 0) {
1412        mCaches.bindTexCoordsVertexPointer(force, mCaches.currentProgram->texCoords, texCoords);
1413    }
1414}
1415
1416void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
1417    bool force = mCaches.unbindMeshBuffer();
1418    mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
1419            vertices, gVertexStride);
1420    mCaches.unbindIndicesBuffer();
1421}
1422
1423/**
1424 * Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an
1425 * outer boundary that fades out to 0. The variables set in the shader define the proportion of
1426 * the width and length of the primitive occupied by the AA region. The vtxWidth and vtxLength
1427 * attributes (one per vertex) are values from zero to one that tells the fragment
1428 * shader where the fragment is in relation to the line width/length overall; these values are
1429 * then used to compute the proper color, based on whether the fragment lies in the fading AA
1430 * region of the line.
1431 * Note that we only pass down the width values in this setup function. The length coordinates
1432 * are set up for each individual segment.
1433 */
1434void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords,
1435        GLvoid* lengthCoords, float boundaryWidthProportion, int& widthSlot, int& lengthSlot) {
1436    bool force = mCaches.unbindMeshBuffer();
1437    mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
1438            vertices, gAAVertexStride);
1439    mCaches.resetTexCoordsVertexPointer();
1440    mCaches.unbindIndicesBuffer();
1441
1442    widthSlot = mCaches.currentProgram->getAttrib("vtxWidth");
1443    glEnableVertexAttribArray(widthSlot);
1444    glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords);
1445
1446    lengthSlot = mCaches.currentProgram->getAttrib("vtxLength");
1447    glEnableVertexAttribArray(lengthSlot);
1448    glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords);
1449
1450    int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth");
1451    glUniform1f(boundaryWidthSlot, boundaryWidthProportion);
1452}
1453
1454void OpenGLRenderer::finishDrawAALine(const int widthSlot, const int lengthSlot) {
1455    glDisableVertexAttribArray(widthSlot);
1456    glDisableVertexAttribArray(lengthSlot);
1457}
1458
1459void OpenGLRenderer::finishDrawTexture() {
1460}
1461
1462///////////////////////////////////////////////////////////////////////////////
1463// Drawing
1464///////////////////////////////////////////////////////////////////////////////
1465
1466status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList,
1467        Rect& dirty, int32_t flags, uint32_t level) {
1468
1469    // All the usual checks and setup operations (quickReject, setupDraw, etc.)
1470    // will be performed by the display list itself
1471    if (displayList && displayList->isRenderable()) {
1472        return displayList->replay(*this, dirty, flags, level);
1473    }
1474
1475    return DrawGlInfo::kStatusDone;
1476}
1477
1478void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
1479    if (displayList) {
1480        displayList->output(*this, level);
1481    }
1482}
1483
1484void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) {
1485    int alpha;
1486    SkXfermode::Mode mode;
1487    getAlphaAndMode(paint, &alpha, &mode);
1488
1489    float x = left;
1490    float y = top;
1491
1492    GLenum filter = GL_LINEAR;
1493    bool ignoreTransform = false;
1494    if (mSnapshot->transform->isPureTranslate()) {
1495        x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
1496        y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
1497        ignoreTransform = true;
1498        filter = GL_NEAREST;
1499    } else {
1500        filter = FILTER(paint);
1501    }
1502
1503    setupDraw();
1504    setupDrawWithTexture(true);
1505    if (paint) {
1506        setupDrawAlpha8Color(paint->getColor(), alpha);
1507    }
1508    setupDrawColorFilter();
1509    setupDrawShader();
1510    setupDrawBlending(true, mode);
1511    setupDrawProgram();
1512    setupDrawModelView(x, y, x + texture->width, y + texture->height, ignoreTransform);
1513
1514    setupDrawTexture(texture->id);
1515    texture->setWrap(GL_CLAMP_TO_EDGE);
1516    texture->setFilter(filter);
1517
1518    setupDrawPureColorUniforms();
1519    setupDrawColorFilterUniforms();
1520    setupDrawShaderUniforms();
1521    setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
1522
1523    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
1524
1525    finishDrawTexture();
1526}
1527
1528status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
1529    const float right = left + bitmap->width();
1530    const float bottom = top + bitmap->height();
1531
1532    if (quickReject(left, top, right, bottom)) {
1533        return DrawGlInfo::kStatusDone;
1534    }
1535
1536    mCaches.activeTexture(0);
1537    Texture* texture = mCaches.textureCache.get(bitmap);
1538    if (!texture) return DrawGlInfo::kStatusDone;
1539    const AutoTexture autoCleanup(texture);
1540
1541    if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
1542        drawAlphaBitmap(texture, left, top, paint);
1543    } else {
1544        drawTextureRect(left, top, right, bottom, texture, paint);
1545    }
1546
1547    return DrawGlInfo::kStatusDrew;
1548}
1549
1550status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
1551    Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
1552    const mat4 transform(*matrix);
1553    transform.mapRect(r);
1554
1555    if (quickReject(r.left, r.top, r.right, r.bottom)) {
1556        return DrawGlInfo::kStatusDone;
1557    }
1558
1559    mCaches.activeTexture(0);
1560    Texture* texture = mCaches.textureCache.get(bitmap);
1561    if (!texture) return DrawGlInfo::kStatusDone;
1562    const AutoTexture autoCleanup(texture);
1563
1564    // This could be done in a cheaper way, all we need is pass the matrix
1565    // to the vertex shader. The save/restore is a bit overkill.
1566    save(SkCanvas::kMatrix_SaveFlag);
1567    concatMatrix(matrix);
1568    drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
1569    restore();
1570
1571    return DrawGlInfo::kStatusDrew;
1572}
1573
1574status_t OpenGLRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
1575    const float right = left + bitmap->width();
1576    const float bottom = top + bitmap->height();
1577
1578    if (quickReject(left, top, right, bottom)) {
1579        return DrawGlInfo::kStatusDone;
1580    }
1581
1582    mCaches.activeTexture(0);
1583    Texture* texture = mCaches.textureCache.getTransient(bitmap);
1584    const AutoTexture autoCleanup(texture);
1585
1586    drawTextureRect(left, top, right, bottom, texture, paint);
1587
1588    return DrawGlInfo::kStatusDrew;
1589}
1590
1591status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
1592        float* vertices, int* colors, SkPaint* paint) {
1593    // TODO: Do a quickReject
1594    if (!vertices || mSnapshot->isIgnored()) {
1595        return DrawGlInfo::kStatusDone;
1596    }
1597
1598    mCaches.activeTexture(0);
1599    Texture* texture = mCaches.textureCache.get(bitmap);
1600    if (!texture) return DrawGlInfo::kStatusDone;
1601    const AutoTexture autoCleanup(texture);
1602
1603    texture->setWrap(GL_CLAMP_TO_EDGE, true);
1604    texture->setFilter(FILTER(paint), true);
1605
1606    int alpha;
1607    SkXfermode::Mode mode;
1608    getAlphaAndMode(paint, &alpha, &mode);
1609
1610    const uint32_t count = meshWidth * meshHeight * 6;
1611
1612    float left = FLT_MAX;
1613    float top = FLT_MAX;
1614    float right = FLT_MIN;
1615    float bottom = FLT_MIN;
1616
1617    const bool hasActiveLayer = hasLayer();
1618
1619    // TODO: Support the colors array
1620    TextureVertex mesh[count];
1621    TextureVertex* vertex = mesh;
1622    for (int32_t y = 0; y < meshHeight; y++) {
1623        for (int32_t x = 0; x < meshWidth; x++) {
1624            uint32_t i = (y * (meshWidth + 1) + x) * 2;
1625
1626            float u1 = float(x) / meshWidth;
1627            float u2 = float(x + 1) / meshWidth;
1628            float v1 = float(y) / meshHeight;
1629            float v2 = float(y + 1) / meshHeight;
1630
1631            int ax = i + (meshWidth + 1) * 2;
1632            int ay = ax + 1;
1633            int bx = i;
1634            int by = bx + 1;
1635            int cx = i + 2;
1636            int cy = cx + 1;
1637            int dx = i + (meshWidth + 1) * 2 + 2;
1638            int dy = dx + 1;
1639
1640            TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2);
1641            TextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1);
1642            TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1);
1643
1644            TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2);
1645            TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1);
1646            TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2);
1647
1648            if (hasActiveLayer) {
1649                // TODO: This could be optimized to avoid unnecessary ops
1650                left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
1651                top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
1652                right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
1653                bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
1654            }
1655        }
1656    }
1657
1658    if (hasActiveLayer) {
1659        dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
1660    }
1661
1662    drawTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f,
1663            mode, texture->blend, &mesh[0].position[0], &mesh[0].texture[0],
1664            GL_TRIANGLES, count, false, false, 0, false, false);
1665
1666    return DrawGlInfo::kStatusDrew;
1667}
1668
1669status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
1670         float srcLeft, float srcTop, float srcRight, float srcBottom,
1671         float dstLeft, float dstTop, float dstRight, float dstBottom,
1672         SkPaint* paint) {
1673    if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
1674        return DrawGlInfo::kStatusDone;
1675    }
1676
1677    mCaches.activeTexture(0);
1678    Texture* texture = mCaches.textureCache.get(bitmap);
1679    if (!texture) return DrawGlInfo::kStatusDone;
1680    const AutoTexture autoCleanup(texture);
1681
1682    const float width = texture->width;
1683    const float height = texture->height;
1684
1685    const float u1 = fmax(0.0f, srcLeft / width);
1686    const float v1 = fmax(0.0f, srcTop / height);
1687    const float u2 = fmin(1.0f, srcRight / width);
1688    const float v2 = fmin(1.0f, srcBottom / height);
1689
1690    mCaches.unbindMeshBuffer();
1691    resetDrawTextureTexCoords(u1, v1, u2, v2);
1692
1693    int alpha;
1694    SkXfermode::Mode mode;
1695    getAlphaAndMode(paint, &alpha, &mode);
1696
1697    texture->setWrap(GL_CLAMP_TO_EDGE, true);
1698
1699    if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
1700        const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f);
1701        const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f);
1702
1703        GLenum filter = GL_NEAREST;
1704        // Enable linear filtering if the source rectangle is scaled
1705        if (srcRight - srcLeft != dstRight - dstLeft || srcBottom - srcTop != dstBottom - dstTop) {
1706            filter = FILTER(paint);
1707        }
1708
1709        texture->setFilter(filter, true);
1710        drawTextureMesh(x, y, x + (dstRight - dstLeft), y + (dstBottom - dstTop),
1711                texture->id, alpha / 255.0f, mode, texture->blend,
1712                &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
1713                GL_TRIANGLE_STRIP, gMeshCount, false, true);
1714    } else {
1715        texture->setFilter(FILTER(paint), true);
1716        drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, texture->id, alpha / 255.0f,
1717                mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
1718                GL_TRIANGLE_STRIP, gMeshCount);
1719    }
1720
1721    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
1722
1723    return DrawGlInfo::kStatusDrew;
1724}
1725
1726status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
1727        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
1728        float left, float top, float right, float bottom, SkPaint* paint) {
1729    int alpha;
1730    SkXfermode::Mode mode;
1731    getAlphaAndModeDirect(paint, &alpha, &mode);
1732
1733    return drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors,
1734            left, top, right, bottom, alpha, mode);
1735}
1736
1737status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
1738        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
1739        float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode) {
1740    if (quickReject(left, top, right, bottom)) {
1741        return DrawGlInfo::kStatusDone;
1742    }
1743
1744    alpha *= mSnapshot->alpha;
1745
1746    mCaches.activeTexture(0);
1747    Texture* texture = mCaches.textureCache.get(bitmap);
1748    if (!texture) return DrawGlInfo::kStatusDone;
1749    const AutoTexture autoCleanup(texture);
1750    texture->setWrap(GL_CLAMP_TO_EDGE, true);
1751    texture->setFilter(GL_LINEAR, true);
1752
1753    const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
1754            right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
1755
1756    if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
1757        const bool pureTranslate = mSnapshot->transform->isPureTranslate();
1758        // Mark the current layer dirty where we are going to draw the patch
1759        if (hasLayer() && mesh->hasEmptyQuads) {
1760            const float offsetX = left + mSnapshot->transform->getTranslateX();
1761            const float offsetY = top + mSnapshot->transform->getTranslateY();
1762            const size_t count = mesh->quads.size();
1763            for (size_t i = 0; i < count; i++) {
1764                const Rect& bounds = mesh->quads.itemAt(i);
1765                if (CC_LIKELY(pureTranslate)) {
1766                    const float x = (int) floorf(bounds.left + offsetX + 0.5f);
1767                    const float y = (int) floorf(bounds.top + offsetY + 0.5f);
1768                    dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
1769                } else {
1770                    dirtyLayer(left + bounds.left, top + bounds.top,
1771                            left + bounds.right, top + bounds.bottom, *mSnapshot->transform);
1772                }
1773            }
1774        }
1775
1776        if (CC_LIKELY(pureTranslate)) {
1777            const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
1778            const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
1779
1780            drawTextureMesh(x, y, x + right - left, y + bottom - top, texture->id, alpha / 255.0f,
1781                    mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
1782                    GL_TRIANGLES, mesh->verticesCount, false, true, mesh->meshBuffer,
1783                    true, !mesh->hasEmptyQuads);
1784        } else {
1785            drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
1786                    mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
1787                    GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer,
1788                    true, !mesh->hasEmptyQuads);
1789        }
1790    }
1791
1792    return DrawGlInfo::kStatusDrew;
1793}
1794
1795/**
1796 * This function uses a similar approach to that of AA lines in the drawLines() function.
1797 * We expand the rectangle by a half pixel in screen space on all sides. However, instead of using
1798 * a fragment shader to compute the translucency of the color from its position, we simply use a
1799 * varying parameter to define how far a given pixel is into the region.
1800 */
1801void OpenGLRenderer::drawConvexPath(const SkPath& path, int color, SkXfermode::Mode mode, bool isAA) {
1802    VertexBuffer vertexBuffer;
1803    // TODO: try clipping large paths to viewport
1804    PathRenderer::convexPathFillVertices(path, mSnapshot->transform, vertexBuffer, isAA);
1805
1806    setupDraw();
1807    setupDrawNoTexture();
1808    if (isAA) setupDrawAA();
1809    setupDrawVertexShape();
1810    setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
1811    setupDrawColorFilter();
1812    setupDrawShader();
1813    setupDrawBlending(isAA, mode);
1814    setupDrawProgram();
1815    setupDrawModelViewIdentity(true);
1816    setupDrawColorUniforms();
1817    setupDrawColorFilterUniforms();
1818    setupDrawShaderIdentityUniforms();
1819
1820    void* vertices = vertexBuffer.getBuffer();
1821    bool force = mCaches.unbindMeshBuffer();
1822    mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
1823                                      vertices, isAA ? gAlphaVertexStride : gVertexStride);
1824    mCaches.resetTexCoordsVertexPointer();
1825    mCaches.unbindIndicesBuffer();
1826
1827    int alphaSlot = -1;
1828    if (isAA) {
1829        void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
1830        alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
1831
1832        // TODO: avoid enable/disable in back to back uses of the alpha attribute
1833        glEnableVertexAttribArray(alphaSlot);
1834        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
1835    }
1836
1837    SkRect bounds = path.getBounds();
1838    dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *mSnapshot->transform);
1839
1840    glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getSize());
1841
1842    if (isAA) {
1843        glDisableVertexAttribArray(alphaSlot);
1844    }
1845}
1846
1847/**
1848 * We draw lines as quads (tristrips). Using GL_LINES can be difficult because the rasterization
1849 * rules for those lines produces some unexpected results, and may vary between hardware devices.
1850 * The basics of lines-as-quads is easy; we simply find the normal to the line and position the
1851 * corners of the quads on either side of each line endpoint, separated by the strokeWidth
1852 * of the line. Hairlines are more involved because we need to account for transform scaling
1853 * to end up with a one-pixel-wide line in screen space..
1854 * Anti-aliased lines add another factor to the approach. We use a specialized fragment shader
1855 * in combination with values that we calculate and pass down in this method. The basic approach
1856 * is that the quad we create contains both the core line area plus a bounding area in which
1857 * the translucent/AA pixels are drawn. The values we calculate tell the shader what
1858 * proportion of the width and the length of a given segment is represented by the boundary
1859 * region. The quad ends up being exactly .5 pixel larger in all directions than the non-AA quad.
1860 * The bounding region is actually 1 pixel wide on all sides (half pixel on the outside, half pixel
1861 * on the inside). This ends up giving the result we want, with pixels that are completely
1862 * 'inside' the line area being filled opaquely and the other pixels being filled according to
1863 * how far into the boundary region they are, which is determined by shader interpolation.
1864 */
1865status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
1866    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
1867
1868    const bool isAA = paint->isAntiAlias();
1869    // We use half the stroke width here because we're going to position the quad
1870    // corner vertices half of the width away from the line endpoints
1871    float halfStrokeWidth = paint->getStrokeWidth() * 0.5f;
1872    // A stroke width of 0 has a special meaning in Skia:
1873    // it draws a line 1 px wide regardless of current transform
1874    bool isHairLine = paint->getStrokeWidth() == 0.0f;
1875
1876    float inverseScaleX = 1.0f;
1877    float inverseScaleY = 1.0f;
1878    bool scaled = false;
1879
1880    int alpha;
1881    SkXfermode::Mode mode;
1882
1883    int generatedVerticesCount = 0;
1884    int verticesCount = count;
1885    if (count > 4) {
1886        // Polyline: account for extra vertices needed for continuous tri-strip
1887        verticesCount += (count - 4);
1888    }
1889
1890    if (isHairLine || isAA) {
1891        // The quad that we use for AA and hairlines needs to account for scaling. For hairlines
1892        // the line on the screen should always be one pixel wide regardless of scale. For
1893        // AA lines, we only want one pixel of translucent boundary around the quad.
1894        if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) {
1895            Matrix4 *mat = mSnapshot->transform;
1896            float m00 = mat->data[Matrix4::kScaleX];
1897            float m01 = mat->data[Matrix4::kSkewY];
1898            float m10 = mat->data[Matrix4::kSkewX];
1899            float m11 = mat->data[Matrix4::kScaleY];
1900
1901            float scaleX = sqrtf(m00 * m00 + m01 * m01);
1902            float scaleY = sqrtf(m10 * m10 + m11 * m11);
1903
1904            inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0;
1905            inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0;
1906
1907            if (inverseScaleX != 1.0f || inverseScaleY != 1.0f) {
1908                scaled = true;
1909            }
1910        }
1911    }
1912
1913    getAlphaAndMode(paint, &alpha, &mode);
1914
1915    mCaches.enableScissor();
1916
1917    setupDraw();
1918    setupDrawNoTexture();
1919    if (isAA) {
1920        setupDrawAA();
1921    }
1922    setupDrawColor(paint->getColor(), alpha);
1923    setupDrawColorFilter();
1924    setupDrawShader();
1925    setupDrawBlending(isAA, mode);
1926    setupDrawProgram();
1927    setupDrawModelViewIdentity(true);
1928    setupDrawColorUniforms();
1929    setupDrawColorFilterUniforms();
1930    setupDrawShaderIdentityUniforms();
1931
1932    if (isHairLine) {
1933        // Set a real stroke width to be used in quad construction
1934        halfStrokeWidth = isAA? 1 : .5;
1935    } else if (isAA && !scaled) {
1936        // Expand boundary to enable AA calculations on the quad border
1937        halfStrokeWidth += .5f;
1938    }
1939
1940    int widthSlot;
1941    int lengthSlot;
1942
1943    Vertex lines[verticesCount];
1944    Vertex* vertices = &lines[0];
1945
1946    AAVertex wLines[verticesCount];
1947    AAVertex* aaVertices = &wLines[0];
1948
1949    if (CC_UNLIKELY(!isAA)) {
1950        setupDrawVertices(vertices);
1951    } else {
1952        void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
1953        void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;
1954        // innerProportion is the ratio of the inner (non-AA) part of the line to the total
1955        // AA stroke width (the base stroke width expanded by a half pixel on either side).
1956        // This value is used in the fragment shader to determine how to fill fragments.
1957        // We will need to calculate the actual width proportion on each segment for
1958        // scaled non-hairlines, since the boundary proportion may differ per-axis when scaled.
1959        float boundaryWidthProportion = .5 - 1 / (2 * halfStrokeWidth);
1960        setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords,
1961                boundaryWidthProportion, widthSlot, lengthSlot);
1962    }
1963
1964    AAVertex* prevAAVertex = NULL;
1965    Vertex* prevVertex = NULL;
1966
1967    int boundaryLengthSlot = -1;
1968    int boundaryWidthSlot = -1;
1969
1970    for (int i = 0; i < count; i += 4) {
1971        // a = start point, b = end point
1972        vec2 a(points[i], points[i + 1]);
1973        vec2 b(points[i + 2], points[i + 3]);
1974
1975        float length = 0;
1976        float boundaryLengthProportion = 0;
1977        float boundaryWidthProportion = 0;
1978
1979        // Find the normal to the line
1980        vec2 n = (b - a).copyNormalized() * halfStrokeWidth;
1981        float x = n.x;
1982        n.x = -n.y;
1983        n.y = x;
1984
1985        if (isHairLine) {
1986            if (isAA) {
1987                float wideningFactor;
1988                if (fabs(n.x) >= fabs(n.y)) {
1989                    wideningFactor = fabs(1.0f / n.x);
1990                } else {
1991                    wideningFactor = fabs(1.0f / n.y);
1992                }
1993                n *= wideningFactor;
1994            }
1995
1996            if (scaled) {
1997                n.x *= inverseScaleX;
1998                n.y *= inverseScaleY;
1999            }
2000        } else if (scaled) {
2001            // Extend n by .5 pixel on each side, post-transform
2002            vec2 extendedN = n.copyNormalized();
2003            extendedN /= 2;
2004            extendedN.x *= inverseScaleX;
2005            extendedN.y *= inverseScaleY;
2006
2007            float extendedNLength = extendedN.length();
2008            // We need to set this value on the shader prior to drawing
2009            boundaryWidthProportion = .5 - extendedNLength / (halfStrokeWidth + extendedNLength);
2010            n += extendedN;
2011        }
2012
2013        // aa lines expand the endpoint vertices to encompass the AA boundary
2014        if (isAA) {
2015            vec2 abVector = (b - a);
2016            length = abVector.length();
2017            abVector.normalize();
2018
2019            if (scaled) {
2020                abVector.x *= inverseScaleX;
2021                abVector.y *= inverseScaleY;
2022                float abLength = abVector.length();
2023                boundaryLengthProportion = .5 - abLength / (length + abLength);
2024            } else {
2025                boundaryLengthProportion = .5 - .5 / (length + 1);
2026            }
2027
2028            abVector /= 2;
2029            a -= abVector;
2030            b += abVector;
2031        }
2032
2033        // Four corners of the rectangle defining a thick line
2034        vec2 p1 = a - n;
2035        vec2 p2 = a + n;
2036        vec2 p3 = b + n;
2037        vec2 p4 = b - n;
2038
2039
2040        const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x)));
2041        const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x)));
2042        const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y)));
2043        const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y)));
2044
2045        if (!quickRejectNoScissor(left, top, right, bottom)) {
2046            if (!isAA) {
2047                if (prevVertex != NULL) {
2048                    // Issue two repeat vertices to create degenerate triangles to bridge
2049                    // between the previous line and the new one. This is necessary because
2050                    // we are creating a single triangle_strip which will contain
2051                    // potentially discontinuous line segments.
2052                    Vertex::set(vertices++, prevVertex->position[0], prevVertex->position[1]);
2053                    Vertex::set(vertices++, p1.x, p1.y);
2054                    generatedVerticesCount += 2;
2055                }
2056
2057                Vertex::set(vertices++, p1.x, p1.y);
2058                Vertex::set(vertices++, p2.x, p2.y);
2059                Vertex::set(vertices++, p4.x, p4.y);
2060                Vertex::set(vertices++, p3.x, p3.y);
2061
2062                prevVertex = vertices - 1;
2063                generatedVerticesCount += 4;
2064            } else {
2065                if (!isHairLine && scaled) {
2066                    // Must set width proportions per-segment for scaled non-hairlines to use the
2067                    // correct AA boundary dimensions
2068                    if (boundaryWidthSlot < 0) {
2069                        boundaryWidthSlot =
2070                                mCaches.currentProgram->getUniform("boundaryWidth");
2071                    }
2072
2073                    glUniform1f(boundaryWidthSlot, boundaryWidthProportion);
2074                }
2075
2076                if (boundaryLengthSlot < 0) {
2077                    boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
2078                }
2079
2080                glUniform1f(boundaryLengthSlot, boundaryLengthProportion);
2081
2082                if (prevAAVertex != NULL) {
2083                    // Issue two repeat vertices to create degenerate triangles to bridge
2084                    // between the previous line and the new one. This is necessary because
2085                    // we are creating a single triangle_strip which will contain
2086                    // potentially discontinuous line segments.
2087                    AAVertex::set(aaVertices++,prevAAVertex->position[0],
2088                            prevAAVertex->position[1], prevAAVertex->width, prevAAVertex->length);
2089                    AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
2090                    generatedVerticesCount += 2;
2091                }
2092
2093                AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
2094                AAVertex::set(aaVertices++, p1.x, p1.y, 1, 0);
2095                AAVertex::set(aaVertices++, p3.x, p3.y, 0, 1);
2096                AAVertex::set(aaVertices++, p2.x, p2.y, 0, 0);
2097
2098                prevAAVertex = aaVertices - 1;
2099                generatedVerticesCount += 4;
2100            }
2101
2102            dirtyLayer(a.x == b.x ? left - 1 : left, a.y == b.y ? top - 1 : top,
2103                    a.x == b.x ? right: right, a.y == b.y ? bottom: bottom,
2104                    *mSnapshot->transform);
2105        }
2106    }
2107
2108    if (generatedVerticesCount > 0) {
2109       glDrawArrays(GL_TRIANGLE_STRIP, 0, generatedVerticesCount);
2110    }
2111
2112    if (isAA) {
2113        finishDrawAALine(widthSlot, lengthSlot);
2114    }
2115
2116    return DrawGlInfo::kStatusDrew;
2117}
2118
2119status_t OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) {
2120    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2121
2122    // TODO: The paint's cap style defines whether the points are square or circular
2123    // TODO: Handle AA for round points
2124
2125    // A stroke width of 0 has a special meaning in Skia:
2126    // it draws an unscaled 1px point
2127    float strokeWidth = paint->getStrokeWidth();
2128    const bool isHairLine = paint->getStrokeWidth() == 0.0f;
2129    if (isHairLine) {
2130        // Now that we know it's hairline, we can set the effective width, to be used later
2131        strokeWidth = 1.0f;
2132    }
2133    const float halfWidth = strokeWidth / 2;
2134    int alpha;
2135    SkXfermode::Mode mode;
2136    getAlphaAndMode(paint, &alpha, &mode);
2137
2138    int verticesCount = count >> 1;
2139    int generatedVerticesCount = 0;
2140
2141    TextureVertex pointsData[verticesCount];
2142    TextureVertex* vertex = &pointsData[0];
2143
2144    // TODO: We should optimize this method to not generate vertices for points
2145    // that lie outside of the clip.
2146    mCaches.enableScissor();
2147
2148    setupDraw();
2149    setupDrawNoTexture();
2150    setupDrawPoint(strokeWidth);
2151    setupDrawColor(paint->getColor(), alpha);
2152    setupDrawColorFilter();
2153    setupDrawShader();
2154    setupDrawBlending(mode);
2155    setupDrawProgram();
2156    setupDrawModelViewIdentity(true);
2157    setupDrawColorUniforms();
2158    setupDrawColorFilterUniforms();
2159    setupDrawPointUniforms();
2160    setupDrawShaderIdentityUniforms();
2161    setupDrawMesh(vertex);
2162
2163    for (int i = 0; i < count; i += 2) {
2164        TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f);
2165        generatedVerticesCount++;
2166
2167        float left = points[i] - halfWidth;
2168        float right = points[i] + halfWidth;
2169        float top = points[i + 1] - halfWidth;
2170        float bottom = points [i + 1] + halfWidth;
2171
2172        dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
2173    }
2174
2175    glDrawArrays(GL_POINTS, 0, generatedVerticesCount);
2176
2177    return DrawGlInfo::kStatusDrew;
2178}
2179
2180status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
2181    // No need to check against the clip, we fill the clip region
2182    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2183
2184    Rect& clip(*mSnapshot->clipRect);
2185    clip.snapToPixelBoundaries();
2186
2187    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
2188
2189    return DrawGlInfo::kStatusDrew;
2190}
2191
2192status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
2193        SkPaint* paint) {
2194    if (!texture) return DrawGlInfo::kStatusDone;
2195    const AutoTexture autoCleanup(texture);
2196
2197    const float x = left + texture->left - texture->offset;
2198    const float y = top + texture->top - texture->offset;
2199
2200    drawPathTexture(texture, x, y, paint);
2201
2202    return DrawGlInfo::kStatusDrew;
2203}
2204
2205status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
2206        float rx, float ry, SkPaint* p) {
2207    if (mSnapshot->isIgnored() || quickReject(left, top, right, bottom)) {
2208        return DrawGlInfo::kStatusDone;
2209    }
2210
2211    if (p->getStyle() != SkPaint::kFill_Style) {
2212        mCaches.activeTexture(0);
2213        const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
2214                right - left, bottom - top, rx, ry, p);
2215        return drawShape(left, top, texture, p);
2216    }
2217
2218    SkPath path;
2219    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2220    path.addRoundRect(rect, rx, ry);
2221    drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), p->isAntiAlias());
2222
2223    return DrawGlInfo::kStatusDrew;
2224}
2225
2226status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* p) {
2227    if (mSnapshot->isIgnored() || quickReject(x - radius, y - radius, x + radius, y + radius)) {
2228        return DrawGlInfo::kStatusDone;
2229    }
2230
2231    if (p->getStyle() != SkPaint::kFill_Style) {
2232        mCaches.activeTexture(0);
2233        const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, p);
2234        return drawShape(x - radius, y - radius, texture, p);
2235    }
2236
2237    SkPath path;
2238    path.addCircle(x, y, radius);
2239    drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), p->isAntiAlias());
2240
2241    return DrawGlInfo::kStatusDrew;
2242}
2243
2244status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
2245        SkPaint* p) {
2246    if (mSnapshot->isIgnored() || quickReject(left, top, right, bottom)) {
2247        return DrawGlInfo::kStatusDone;
2248    }
2249
2250    if (p->getStyle() != SkPaint::kFill_Style) {
2251        mCaches.activeTexture(0);
2252        const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, p);
2253        return drawShape(left, top, texture, p);
2254    }
2255
2256    SkPath path;
2257    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2258    path.addOval(rect);
2259    drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), p->isAntiAlias());
2260
2261    return DrawGlInfo::kStatusDrew;
2262}
2263
2264status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
2265        float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
2266    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2267
2268    if (fabs(sweepAngle) >= 360.0f) {
2269        return drawOval(left, top, right, bottom, paint);
2270    }
2271
2272    mCaches.activeTexture(0);
2273    const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
2274            startAngle, sweepAngle, useCenter, paint);
2275    return drawShape(left, top, texture, paint);
2276}
2277
2278status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
2279    if (mSnapshot->isIgnored() || quickReject(left, top, right, bottom)) {
2280        return DrawGlInfo::kStatusDone;
2281    }
2282
2283    if (p->getStyle() != SkPaint::kFill_Style) {
2284        mCaches.activeTexture(0);
2285        const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, p);
2286        return drawShape(left, top, texture, p);
2287    }
2288
2289    if (p->isAntiAlias() && !mSnapshot->transform->isSimple()) {
2290        SkPath path;
2291        path.addRect(left, top, right, bottom);
2292        drawConvexPath(path, p->getColor(), getXfermode(p->getXfermode()), true);
2293    } else {
2294        drawColorRect(left, top, right, bottom, p->getColor(), getXfermode(p->getXfermode()));
2295    }
2296
2297    return DrawGlInfo::kStatusDrew;
2298}
2299
2300void OpenGLRenderer::drawTextShadow(SkPaint* paint, const char* text, int bytesCount, int count,
2301        const float* positions, FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode,
2302        float x, float y) {
2303    mCaches.activeTexture(0);
2304
2305    // NOTE: The drop shadow will not perform gamma correction
2306    //       if shader-based correction is enabled
2307    mCaches.dropShadowCache.setFontRenderer(fontRenderer);
2308    const ShadowTexture* shadow = mCaches.dropShadowCache.get(
2309            paint, text, bytesCount, count, mShadowRadius, positions);
2310    const AutoTexture autoCleanup(shadow);
2311
2312    const float sx = x - shadow->left + mShadowDx;
2313    const float sy = y - shadow->top + mShadowDy;
2314
2315    const int shadowAlpha = ((mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
2316    int shadowColor = mShadowColor;
2317    if (mShader) {
2318        shadowColor = 0xffffffff;
2319    }
2320
2321    setupDraw();
2322    setupDrawWithTexture(true);
2323    setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
2324    setupDrawColorFilter();
2325    setupDrawShader();
2326    setupDrawBlending(true, mode);
2327    setupDrawProgram();
2328    setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height);
2329    setupDrawTexture(shadow->id);
2330    setupDrawPureColorUniforms();
2331    setupDrawColorFilterUniforms();
2332    setupDrawShaderUniforms();
2333    setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
2334
2335    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
2336}
2337
2338status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
2339        const float* positions, SkPaint* paint) {
2340    if (text == NULL || count == 0 || mSnapshot->isIgnored() ||
2341            (paint->getAlpha() * mSnapshot->alpha == 0 && paint->getXfermode() == NULL)) {
2342        return DrawGlInfo::kStatusDone;
2343    }
2344
2345    // NOTE: Skia does not support perspective transform on drawPosText yet
2346    if (!mSnapshot->transform->isSimple()) {
2347        return DrawGlInfo::kStatusDone;
2348    }
2349
2350    float x = 0.0f;
2351    float y = 0.0f;
2352    const bool pureTranslate = mSnapshot->transform->isPureTranslate();
2353    if (pureTranslate) {
2354        x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
2355        y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
2356    }
2357
2358    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2359    fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
2360            paint->getTextSize());
2361
2362    int alpha;
2363    SkXfermode::Mode mode;
2364    getAlphaAndMode(paint, &alpha, &mode);
2365
2366    if (CC_UNLIKELY(mHasShadow)) {
2367        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode,
2368                0.0f, 0.0f);
2369    }
2370
2371    // Pick the appropriate texture filtering
2372    bool linearFilter = mSnapshot->transform->changesBounds();
2373    if (pureTranslate && !linearFilter) {
2374        linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2375    }
2376
2377    mCaches.activeTexture(0);
2378    setupDraw();
2379    setupDrawTextGamma(paint);
2380    setupDrawDirtyRegionsDisabled();
2381    setupDrawWithTexture(true);
2382    setupDrawAlpha8Color(paint->getColor(), alpha);
2383    setupDrawColorFilter();
2384    setupDrawShader();
2385    setupDrawBlending(true, mode);
2386    setupDrawProgram();
2387    setupDrawModelView(x, y, x, y, pureTranslate, true);
2388    setupDrawTexture(fontRenderer.getTexture(linearFilter));
2389    setupDrawPureColorUniforms();
2390    setupDrawColorFilterUniforms();
2391    setupDrawShaderUniforms(pureTranslate);
2392    setupDrawTextGammaUniforms();
2393
2394    const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
2395    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2396
2397    const bool hasActiveLayer = hasLayer();
2398
2399    if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2400            positions, hasActiveLayer ? &bounds : NULL)) {
2401        if (hasActiveLayer) {
2402            if (!pureTranslate) {
2403                mSnapshot->transform->mapRect(bounds);
2404            }
2405            dirtyLayerUnchecked(bounds, getRegion());
2406        }
2407    }
2408
2409    return DrawGlInfo::kStatusDrew;
2410}
2411
2412status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
2413        float x, float y, const float* positions, SkPaint* paint, float length) {
2414    if (text == NULL || count == 0 || mSnapshot->isIgnored() ||
2415            (paint->getAlpha() * mSnapshot->alpha == 0 && paint->getXfermode() == NULL)) {
2416        return DrawGlInfo::kStatusDone;
2417    }
2418
2419    if (length < 0.0f) length = paint->measureText(text, bytesCount);
2420    switch (paint->getTextAlign()) {
2421        case SkPaint::kCenter_Align:
2422            x -= length / 2.0f;
2423            break;
2424        case SkPaint::kRight_Align:
2425            x -= length;
2426            break;
2427        default:
2428            break;
2429    }
2430
2431    SkPaint::FontMetrics metrics;
2432    paint->getFontMetrics(&metrics, 0.0f);
2433    if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
2434        return DrawGlInfo::kStatusDone;
2435    }
2436
2437    const float oldX = x;
2438    const float oldY = y;
2439    const bool pureTranslate = mSnapshot->transform->isPureTranslate();
2440    if (CC_LIKELY(pureTranslate)) {
2441        x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
2442        y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
2443    }
2444
2445#if DEBUG_GLYPHS
2446    ALOGD("OpenGLRenderer drawText() with FontID=%d",
2447            SkTypeface::UniqueID(paint->getTypeface()));
2448#endif
2449
2450    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2451    fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
2452            paint->getTextSize());
2453
2454    int alpha;
2455    SkXfermode::Mode mode;
2456    getAlphaAndMode(paint, &alpha, &mode);
2457
2458    if (CC_UNLIKELY(mHasShadow)) {
2459        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode,
2460                oldX, oldY);
2461    }
2462
2463    // Pick the appropriate texture filtering
2464    bool linearFilter = mSnapshot->transform->changesBounds();
2465    if (pureTranslate && !linearFilter) {
2466        linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2467    }
2468
2469    // The font renderer will always use texture unit 0
2470    mCaches.activeTexture(0);
2471    setupDraw();
2472    setupDrawTextGamma(paint);
2473    setupDrawDirtyRegionsDisabled();
2474    setupDrawWithTexture(true);
2475    setupDrawAlpha8Color(paint->getColor(), alpha);
2476    setupDrawColorFilter();
2477    setupDrawShader();
2478    setupDrawBlending(true, mode);
2479    setupDrawProgram();
2480    setupDrawModelView(x, y, x, y, pureTranslate, true);
2481    // See comment above; the font renderer must use texture unit 0
2482    // assert(mTextureUnit == 0)
2483    setupDrawTexture(fontRenderer.getTexture(linearFilter));
2484    setupDrawPureColorUniforms();
2485    setupDrawColorFilterUniforms();
2486    setupDrawShaderUniforms(pureTranslate);
2487    setupDrawTextGammaUniforms();
2488
2489    const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
2490    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2491
2492    const bool hasActiveLayer = hasLayer();
2493
2494    bool status;
2495    if (paint->getTextAlign() != SkPaint::kLeft_Align) {
2496        SkPaint paintCopy(*paint);
2497        paintCopy.setTextAlign(SkPaint::kLeft_Align);
2498        status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
2499            positions, hasActiveLayer ? &bounds : NULL);
2500    } else {
2501        status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2502            positions, hasActiveLayer ? &bounds : NULL);
2503    }
2504
2505    if (status && hasActiveLayer) {
2506        if (!pureTranslate) {
2507            mSnapshot->transform->mapRect(bounds);
2508        }
2509        dirtyLayerUnchecked(bounds, getRegion());
2510    }
2511
2512    drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
2513
2514    return DrawGlInfo::kStatusDrew;
2515}
2516
2517status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
2518        float hOffset, float vOffset, SkPaint* paint) {
2519    if (text == NULL || count == 0 || mSnapshot->isIgnored() ||
2520            (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
2521        return DrawGlInfo::kStatusDone;
2522    }
2523
2524    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2525    fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
2526            paint->getTextSize());
2527
2528    int alpha;
2529    SkXfermode::Mode mode;
2530    getAlphaAndMode(paint, &alpha, &mode);
2531
2532    mCaches.activeTexture(0);
2533    setupDraw();
2534    setupDrawTextGamma(paint);
2535    setupDrawDirtyRegionsDisabled();
2536    setupDrawWithTexture(true);
2537    setupDrawAlpha8Color(paint->getColor(), alpha);
2538    setupDrawColorFilter();
2539    setupDrawShader();
2540    setupDrawBlending(true, mode);
2541    setupDrawProgram();
2542    setupDrawModelView(0.0f, 0.0f, 0.0f, 0.0f, false, true);
2543    setupDrawTexture(fontRenderer.getTexture(true));
2544    setupDrawPureColorUniforms();
2545    setupDrawColorFilterUniforms();
2546    setupDrawShaderUniforms(false);
2547    setupDrawTextGammaUniforms();
2548
2549    const Rect* clip = &mSnapshot->getLocalClip();
2550    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2551
2552    const bool hasActiveLayer = hasLayer();
2553
2554    if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
2555            hOffset, vOffset, hasActiveLayer ? &bounds : NULL)) {
2556        if (hasActiveLayer) {
2557            mSnapshot->transform->mapRect(bounds);
2558            dirtyLayerUnchecked(bounds, getRegion());
2559        }
2560    }
2561
2562    return DrawGlInfo::kStatusDrew;
2563}
2564
2565status_t OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
2566    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2567
2568    mCaches.activeTexture(0);
2569
2570    // TODO: Perform early clip test before we rasterize the path
2571    const PathTexture* texture = mCaches.pathCache.get(path, paint);
2572    if (!texture) return DrawGlInfo::kStatusDone;
2573    const AutoTexture autoCleanup(texture);
2574
2575    const float x = texture->left - texture->offset;
2576    const float y = texture->top - texture->offset;
2577
2578    drawPathTexture(texture, x, y, paint);
2579
2580    return DrawGlInfo::kStatusDrew;
2581}
2582
2583status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
2584    if (!layer) {
2585        return DrawGlInfo::kStatusDone;
2586    }
2587
2588    Rect transformed;
2589    Rect clip;
2590    const bool rejected = quickRejectNoScissor(x, y,
2591            x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip);
2592
2593    if (rejected) {
2594        return DrawGlInfo::kStatusDone;
2595    }
2596
2597    bool debugLayerUpdate = false;
2598    if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) {
2599        OpenGLRenderer* renderer = layer->renderer;
2600        Rect& dirty = layer->dirtyRect;
2601
2602        endTiling();
2603
2604        renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight());
2605        renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend());
2606        renderer->drawDisplayList(layer->displayList, dirty, DisplayList::kReplayFlag_ClipChildren);
2607        renderer->finish();
2608
2609        resumeAfterLayer();
2610        startTiling(mSnapshot);
2611
2612        dirty.setEmpty();
2613        layer->deferredUpdateScheduled = false;
2614        layer->renderer = NULL;
2615        layer->displayList = NULL;
2616
2617        debugLayerUpdate = mCaches.debugLayersUpdates;
2618    }
2619
2620    mCaches.setScissorEnabled(!clip.contains(transformed));
2621    mCaches.activeTexture(0);
2622
2623    if (CC_LIKELY(!layer->region.isEmpty())) {
2624        if (layer->region.isRect()) {
2625            composeLayerRect(layer, layer->regionRect);
2626        } else if (layer->mesh) {
2627            const float a = layer->getAlpha() / 255.0f;
2628            SkiaColorFilter *oldFilter = mColorFilter;
2629            mColorFilter = layer->getColorFilter();
2630
2631            setupDraw();
2632            setupDrawWithTexture();
2633            setupDrawColor(a, a, a, a);
2634            setupDrawColorFilter();
2635            setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false);
2636            setupDrawProgram();
2637            setupDrawPureColorUniforms();
2638            setupDrawColorFilterUniforms();
2639            setupDrawTexture(layer->getTexture());
2640            if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
2641                int tx = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
2642                int ty = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
2643
2644                layer->setFilter(GL_NEAREST);
2645                setupDrawModelViewTranslate(tx, ty,
2646                        tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
2647            } else {
2648                layer->setFilter(GL_LINEAR);
2649                setupDrawModelViewTranslate(x, y,
2650                        x + layer->layer.getWidth(), y + layer->layer.getHeight());
2651            }
2652            setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);
2653
2654            glDrawElements(GL_TRIANGLES, layer->meshElementCount,
2655                    GL_UNSIGNED_SHORT, layer->meshIndices);
2656
2657            finishDrawTexture();
2658
2659            mColorFilter = oldFilter;
2660
2661#if DEBUG_LAYERS_AS_REGIONS
2662            drawRegionRects(layer->region);
2663#endif
2664        }
2665
2666        if (debugLayerUpdate) {
2667            drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
2668                    0x7f00ff00, SkXfermode::kSrcOver_Mode);
2669        }
2670    }
2671
2672    return DrawGlInfo::kStatusDrew;
2673}
2674
2675///////////////////////////////////////////////////////////////////////////////
2676// Shaders
2677///////////////////////////////////////////////////////////////////////////////
2678
2679void OpenGLRenderer::resetShader() {
2680    mShader = NULL;
2681}
2682
2683void OpenGLRenderer::setupShader(SkiaShader* shader) {
2684    mShader = shader;
2685    if (mShader) {
2686        mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
2687    }
2688}
2689
2690///////////////////////////////////////////////////////////////////////////////
2691// Color filters
2692///////////////////////////////////////////////////////////////////////////////
2693
2694void OpenGLRenderer::resetColorFilter() {
2695    mColorFilter = NULL;
2696}
2697
2698void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
2699    mColorFilter = filter;
2700}
2701
2702///////////////////////////////////////////////////////////////////////////////
2703// Drop shadow
2704///////////////////////////////////////////////////////////////////////////////
2705
2706void OpenGLRenderer::resetShadow() {
2707    mHasShadow = false;
2708}
2709
2710void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
2711    mHasShadow = true;
2712    mShadowRadius = radius;
2713    mShadowDx = dx;
2714    mShadowDy = dy;
2715    mShadowColor = color;
2716}
2717
2718///////////////////////////////////////////////////////////////////////////////
2719// Draw filters
2720///////////////////////////////////////////////////////////////////////////////
2721
2722void OpenGLRenderer::resetPaintFilter() {
2723    mHasDrawFilter = false;
2724}
2725
2726void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
2727    mHasDrawFilter = true;
2728    mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
2729    mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
2730}
2731
2732SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) {
2733    if (CC_LIKELY(!mHasDrawFilter || !paint)) return paint;
2734
2735    uint32_t flags = paint->getFlags();
2736
2737    mFilteredPaint = *paint;
2738    mFilteredPaint.setFlags((flags & ~mPaintFilterClearBits) | mPaintFilterSetBits);
2739
2740    return &mFilteredPaint;
2741}
2742
2743///////////////////////////////////////////////////////////////////////////////
2744// Drawing implementation
2745///////////////////////////////////////////////////////////////////////////////
2746
2747void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
2748        float x, float y, SkPaint* paint) {
2749    if (quickReject(x, y, x + texture->width, y + texture->height)) {
2750        return;
2751    }
2752
2753    int alpha;
2754    SkXfermode::Mode mode;
2755    getAlphaAndMode(paint, &alpha, &mode);
2756
2757    setupDraw();
2758    setupDrawWithTexture(true);
2759    setupDrawAlpha8Color(paint->getColor(), alpha);
2760    setupDrawColorFilter();
2761    setupDrawShader();
2762    setupDrawBlending(true, mode);
2763    setupDrawProgram();
2764    setupDrawModelView(x, y, x + texture->width, y + texture->height);
2765    setupDrawTexture(texture->id);
2766    setupDrawPureColorUniforms();
2767    setupDrawColorFilterUniforms();
2768    setupDrawShaderUniforms();
2769    setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
2770
2771    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
2772
2773    finishDrawTexture();
2774}
2775
2776// Same values used by Skia
2777#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
2778#define kStdUnderline_Offset    (1.0f / 9.0f)
2779#define kStdUnderline_Thickness (1.0f / 18.0f)
2780
2781void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length,
2782        float x, float y, SkPaint* paint) {
2783    // Handle underline and strike-through
2784    uint32_t flags = paint->getFlags();
2785    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
2786        SkPaint paintCopy(*paint);
2787        float underlineWidth = length;
2788        // If length is > 0.0f, we already measured the text for the text alignment
2789        if (length <= 0.0f) {
2790            underlineWidth = paintCopy.measureText(text, bytesCount);
2791        }
2792
2793        if (CC_LIKELY(underlineWidth > 0.0f)) {
2794            const float textSize = paintCopy.getTextSize();
2795            const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
2796
2797            const float left = x;
2798            float top = 0.0f;
2799
2800            int linesCount = 0;
2801            if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
2802            if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
2803
2804            const int pointsCount = 4 * linesCount;
2805            float points[pointsCount];
2806            int currentPoint = 0;
2807
2808            if (flags & SkPaint::kUnderlineText_Flag) {
2809                top = y + textSize * kStdUnderline_Offset;
2810                points[currentPoint++] = left;
2811                points[currentPoint++] = top;
2812                points[currentPoint++] = left + underlineWidth;
2813                points[currentPoint++] = top;
2814            }
2815
2816            if (flags & SkPaint::kStrikeThruText_Flag) {
2817                top = y + textSize * kStdStrikeThru_Offset;
2818                points[currentPoint++] = left;
2819                points[currentPoint++] = top;
2820                points[currentPoint++] = left + underlineWidth;
2821                points[currentPoint++] = top;
2822            }
2823
2824            paintCopy.setStrokeWidth(strokeWidth);
2825
2826            drawLines(&points[0], pointsCount, &paintCopy);
2827        }
2828    }
2829}
2830
2831void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
2832        int color, SkXfermode::Mode mode, bool ignoreTransform) {
2833    // If a shader is set, preserve only the alpha
2834    if (mShader) {
2835        color |= 0x00ffffff;
2836    }
2837
2838    setupDraw();
2839    setupDrawNoTexture();
2840    setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
2841    setupDrawShader();
2842    setupDrawColorFilter();
2843    setupDrawBlending(mode);
2844    setupDrawProgram();
2845    setupDrawModelView(left, top, right, bottom, ignoreTransform);
2846    setupDrawColorUniforms();
2847    setupDrawShaderUniforms(ignoreTransform);
2848    setupDrawColorFilterUniforms();
2849    setupDrawSimpleMesh();
2850
2851    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
2852}
2853
2854void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
2855        Texture* texture, SkPaint* paint) {
2856    int alpha;
2857    SkXfermode::Mode mode;
2858    getAlphaAndMode(paint, &alpha, &mode);
2859
2860    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2861
2862    if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
2863        const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
2864        const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
2865
2866        texture->setFilter(GL_NEAREST, true);
2867        drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
2868                alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL,
2869                (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, false, true);
2870    } else {
2871        texture->setFilter(FILTER(paint), true);
2872        drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
2873                texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
2874                GL_TRIANGLE_STRIP, gMeshCount);
2875    }
2876}
2877
2878void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
2879        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
2880    drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
2881            (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount);
2882}
2883
2884void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
2885        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
2886        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
2887        bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) {
2888
2889    setupDraw();
2890    setupDrawWithTexture();
2891    setupDrawColor(alpha, alpha, alpha, alpha);
2892    setupDrawColorFilter();
2893    setupDrawBlending(blend, mode, swapSrcDst);
2894    setupDrawProgram();
2895    if (!dirty) {
2896        setupDrawDirtyRegionsDisabled();
2897    }
2898    if (!ignoreScale) {
2899        setupDrawModelView(left, top, right, bottom, ignoreTransform);
2900    } else {
2901        setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
2902    }
2903    setupDrawPureColorUniforms();
2904    setupDrawColorFilterUniforms();
2905    setupDrawTexture(texture);
2906    setupDrawMesh(vertices, texCoords, vbo);
2907
2908    glDrawArrays(drawMode, 0, elementsCount);
2909
2910    finishDrawTexture();
2911}
2912
2913void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
2914        ProgramDescription& description, bool swapSrcDst) {
2915    blend = blend || mode != SkXfermode::kSrcOver_Mode;
2916
2917    if (blend) {
2918        // These blend modes are not supported by OpenGL directly and have
2919        // to be implemented using shaders. Since the shader will perform
2920        // the blending, turn blending off here
2921        // If the blend mode cannot be implemented using shaders, fall
2922        // back to the default SrcOver blend mode instead
2923        if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
2924            if (CC_UNLIKELY(mCaches.extensions.hasFramebufferFetch())) {
2925                description.framebufferMode = mode;
2926                description.swapSrcDst = swapSrcDst;
2927
2928                if (mCaches.blend) {
2929                    glDisable(GL_BLEND);
2930                    mCaches.blend = false;
2931                }
2932
2933                return;
2934            } else {
2935                mode = SkXfermode::kSrcOver_Mode;
2936            }
2937        }
2938
2939        if (!mCaches.blend) {
2940            glEnable(GL_BLEND);
2941        }
2942
2943        GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
2944        GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
2945
2946        if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
2947            glBlendFunc(sourceMode, destMode);
2948            mCaches.lastSrcMode = sourceMode;
2949            mCaches.lastDstMode = destMode;
2950        }
2951    } else if (mCaches.blend) {
2952        glDisable(GL_BLEND);
2953    }
2954    mCaches.blend = blend;
2955}
2956
2957bool OpenGLRenderer::useProgram(Program* program) {
2958    if (!program->isInUse()) {
2959        if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
2960        program->use();
2961        mCaches.currentProgram = program;
2962        return false;
2963    }
2964    return true;
2965}
2966
2967void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
2968    TextureVertex* v = &mMeshVertices[0];
2969    TextureVertex::setUV(v++, u1, v1);
2970    TextureVertex::setUV(v++, u2, v1);
2971    TextureVertex::setUV(v++, u1, v2);
2972    TextureVertex::setUV(v++, u2, v2);
2973}
2974
2975void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
2976    getAlphaAndModeDirect(paint, alpha,  mode);
2977    *alpha *= mSnapshot->alpha;
2978}
2979
2980}; // namespace uirenderer
2981}; // namespace android
2982