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