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