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