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