OpenGLRenderer.cpp revision b265e2ca50b6ceb2fd2987ef1f7d063b1bde19ae
11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 2010 The Android Open Source Project
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * you may not use this file except in compliance with the License.
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * You may obtain a copy of the License at
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * See the License for the specific language governing permissions and
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * limitations under the License.
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define LOG_TAG "OpenGLRenderer"
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h>
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdint.h>
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/types.h>
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <SkCanvas.h>
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <SkTypeface.h>
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <utils/Log.h>
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <utils/StopWatch.h>
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <private/hwui/DrawGlInfo.h>
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <ui/Rect.h>
32bfeab1bbe7e8d0c08b7e3f46aedab64e3b2bf706Elliott Hughes
3336fa67bcdd90f18a3c68f8637ae836762407fa51Elliott Hughes#include "OpenGLRenderer.h"
341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "DeferredDisplayList.h"
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "DisplayListRenderer.h"
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "Fence.h"
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "PathTessellator.h"
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "Properties.h"
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "ShadowTessellator.h"
404f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughes#include "Vector.h"
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "VertexBuffer.h"
4240eabe24e4e3ae8ebe437f1f4e43cf39cbba2e9eElliott Hughes
434f251bee5d51228217c1bf4dfc9219f3058bd3edElliott Hughesnamespace android {
441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectnamespace uirenderer {
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
46d0c884d3595ecca03c3e70de9909c090cd5f9caePierre Peiffer///////////////////////////////////////////////////////////////////////////////
471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// Defines
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
495419b9474753d25dff947c7740532f86d130c0beElliott Hughes
5084114c8dd5b17efecf7988f263ce431208d7be5aElliott Hughes#define RAD_TO_DEG (180.0f / 3.14159265f)
5184114c8dd5b17efecf7988f263ce431208d7be5aElliott Hughes#define MIN_ANGLE 0.001f
525419b9474753d25dff947c7740532f86d130c0beElliott Hughes
535419b9474753d25dff947c7740532f86d130c0beElliott Hughes#define ALPHA_THRESHOLD 0
545419b9474753d25dff947c7740532f86d130c0beElliott Hughes
555419b9474753d25dff947c7740532f86d130c0beElliott Hughesstatic GLenum getFilter(const SkPaint* paint) {
565419b9474753d25dff947c7740532f86d130c0beElliott Hughes    if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
575419b9474753d25dff947c7740532f86d130c0beElliott Hughes        return GL_LINEAR;
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return GL_NEAREST;
6040eabe24e4e3ae8ebe437f1f4e43cf39cbba2e9eElliott Hughes}
6140eabe24e4e3ae8ebe437f1f4e43cf39cbba2e9eElliott Hughes
629d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes///////////////////////////////////////////////////////////////////////////////
631a78fbb5c8228e4aea2a516818828b76044310f2Evgeniy Stepanov// Globals
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
6544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes
669d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes/**
6744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * Structure mapping Skia xfermodes to OpenGL blending factors.
680f020d18b138e24b1fe34074808e07ac412f35a4msg */
693e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughesstruct Blender {
700f020d18b138e24b1fe34074808e07ac412f35a4msg    SkXfermode::Mode mode;
710f020d18b138e24b1fe34074808e07ac412f35a4msg    GLenum src;
723e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes    GLenum dst;
733e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes}; // struct Blender
740f020d18b138e24b1fe34074808e07ac412f35a4msg
750f020d18b138e24b1fe34074808e07ac412f35a4msg// In this array, the index of each Blender equals the value of the first
760f020d18b138e24b1fe34074808e07ac412f35a4msg// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
770f020d18b138e24b1fe34074808e07ac412f35a4msgstatic const Blender gBlends[] = {
780f020d18b138e24b1fe34074808e07ac412f35a4msg    { SkXfermode::kClear_Mode,    GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
790f020d18b138e24b1fe34074808e07ac412f35a4msg    { SkXfermode::kSrc_Mode,      GL_ONE,                 GL_ZERO },
8050af69e8f326b2762a44d5fea2b118e7616e5d20Brian Carlstrom    { SkXfermode::kDst_Mode,      GL_ZERO,                GL_ONE },
8150af69e8f326b2762a44d5fea2b118e7616e5d20Brian Carlstrom    { SkXfermode::kSrcOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
8250af69e8f326b2762a44d5fea2b118e7616e5d20Brian Carlstrom    { SkXfermode::kDstOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
8350af69e8f326b2762a44d5fea2b118e7616e5d20Brian Carlstrom    { SkXfermode::kSrcIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
8450af69e8f326b2762a44d5fea2b118e7616e5d20Brian Carlstrom    { SkXfermode::kDstIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
8550af69e8f326b2762a44d5fea2b118e7616e5d20Brian Carlstrom    { SkXfermode::kSrcOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
8650af69e8f326b2762a44d5fea2b118e7616e5d20Brian Carlstrom    { SkXfermode::kDstOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
8750af69e8f326b2762a44d5fea2b118e7616e5d20Brian Carlstrom    { SkXfermode::kSrcATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
8850af69e8f326b2762a44d5fea2b118e7616e5d20Brian Carlstrom    { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
899d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
909d23e04c43dbb8480bea8be28b8a2f37423bec49Elliott Hughes    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
9144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes    { SkXfermode::kModulate_Mode, GL_ZERO,                GL_SRC_COLOR },
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project};
944f086aeb4aa06e13079b7fec71a8178ceeacf318Matt Fischer
954f086aeb4aa06e13079b7fec71a8178ceeacf318Matt Fischer// This array contains the swapped version of each SkXfermode. For instance
964f086aeb4aa06e13079b7fec71a8178ceeacf318Matt Fischer// this array's SrcOver blending mode is actually DstOver. You can refer to
971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// createLayer() for more information on the purpose of this array.
981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic const Blender gBlendsSwap[] = {
991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    { SkXfermode::kClear_Mode,    GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    { SkXfermode::kSrc_Mode,      GL_ZERO,                GL_ONE },
101    { SkXfermode::kDst_Mode,      GL_ONE,                 GL_ZERO },
102    { SkXfermode::kSrcOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
103    { SkXfermode::kDstOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
104    { SkXfermode::kSrcIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
105    { SkXfermode::kDstIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
106    { SkXfermode::kSrcOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
107    { SkXfermode::kDstOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
108    { SkXfermode::kSrcATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
109    { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
110    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
111    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
112    { SkXfermode::kModulate_Mode, GL_DST_COLOR,           GL_ZERO },
113    { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
114};
115
116///////////////////////////////////////////////////////////////////////////////
117// Functions
118///////////////////////////////////////////////////////////////////////////////
119
120template<typename T>
121static inline T min(T a, T b) {
122    return a < b ? a : b;
123}
124
125///////////////////////////////////////////////////////////////////////////////
126// Constructors/destructor
127///////////////////////////////////////////////////////////////////////////////
128
129OpenGLRenderer::OpenGLRenderer():
130        mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) {
131    // *set* draw modifiers to be 0
132    memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
133    mDrawModifiers.mOverrideLayerAlpha = 1.0f;
134
135    memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
136
137    mFrameStarted = false;
138    mCountOverdraw = false;
139
140    mScissorOptimizationDisabled = false;
141}
142
143OpenGLRenderer::~OpenGLRenderer() {
144    // The context has already been destroyed at this point, do not call
145    // GL APIs. All GL state should be kept in Caches.h
146}
147
148void OpenGLRenderer::initProperties() {
149    char property[PROPERTY_VALUE_MAX];
150    if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) {
151        mScissorOptimizationDisabled = !strcasecmp(property, "true");
152        INIT_LOGD("  Scissor optimization %s",
153                mScissorOptimizationDisabled ? "disabled" : "enabled");
154    } else {
155        INIT_LOGD("  Scissor optimization enabled");
156    }
157}
158
159///////////////////////////////////////////////////////////////////////////////
160// Setup
161///////////////////////////////////////////////////////////////////////////////
162
163void OpenGLRenderer::setViewport(int width, int height) {
164    initViewport(width, height);
165
166    glDisable(GL_DITHER);
167    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
168
169    glEnableVertexAttribArray(Program::kBindingPosition);
170}
171
172void OpenGLRenderer::initViewport(int width, int height) {
173    mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
174
175    initializeViewport(width, height);
176}
177
178void OpenGLRenderer::setupFrameState(float left, float top,
179        float right, float bottom, bool opaque) {
180    mCaches.clearGarbage();
181
182    initializeSaveStack(left, top, right, bottom);
183    mOpaque = opaque;
184    mTilingClip.set(left, top, right, bottom);
185}
186
187status_t OpenGLRenderer::startFrame() {
188    if (mFrameStarted) return DrawGlInfo::kStatusDone;
189    mFrameStarted = true;
190
191    mDirtyClip = true;
192
193    discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
194
195    glViewport(0, 0, getWidth(), getHeight());
196
197    // Functors break the tiling extension in pretty spectacular ways
198    // This ensures we don't use tiling when a functor is going to be
199    // invoked during the frame
200    mSuppressTiling = mCaches.hasRegisteredFunctors();
201
202    startTilingCurrentClip(true);
203
204    debugOverdraw(true, true);
205
206    return clear(mTilingClip.left, mTilingClip.top,
207            mTilingClip.right, mTilingClip.bottom, mOpaque);
208}
209
210status_t OpenGLRenderer::prepareDirty(float left, float top,
211        float right, float bottom, bool opaque) {
212
213    setupFrameState(left, top, right, bottom, opaque);
214
215    // Layer renderers will start the frame immediately
216    // The framebuffer renderer will first defer the display list
217    // for each layer and wait until the first drawing command
218    // to start the frame
219    if (currentSnapshot()->fbo == 0) {
220        syncState();
221        updateLayers();
222    } else {
223        return startFrame();
224    }
225
226    return DrawGlInfo::kStatusDone;
227}
228
229void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
230    // If we know that we are going to redraw the entire framebuffer,
231    // perform a discard to let the driver know we don't need to preserve
232    // the back buffer for this frame.
233    if (mExtensions.hasDiscardFramebuffer() &&
234            left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) {
235        const bool isFbo = getTargetFbo() == 0;
236        const GLenum attachments[] = {
237                isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
238                isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT };
239        glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
240    }
241}
242
243status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
244    if (!opaque || mCountOverdraw) {
245        mCaches.enableScissor();
246        mCaches.setScissor(left, currentSnapshot()->height - bottom, right - left, bottom - top);
247        glClear(GL_COLOR_BUFFER_BIT);
248        return DrawGlInfo::kStatusDrew;
249    }
250
251    mCaches.resetScissor();
252    return DrawGlInfo::kStatusDone;
253}
254
255void OpenGLRenderer::syncState() {
256    if (mCaches.blend) {
257        glEnable(GL_BLEND);
258    } else {
259        glDisable(GL_BLEND);
260    }
261}
262
263void OpenGLRenderer::startTilingCurrentClip(bool opaque) {
264    if (!mSuppressTiling) {
265        const Snapshot* snapshot = currentSnapshot();
266
267        const Rect* clip = &mTilingClip;
268        if (snapshot->flags & Snapshot::kFlagFboTarget) {
269            clip = &(snapshot->layer->clipRect);
270        }
271
272        startTiling(*clip, snapshot->height, opaque);
273    }
274}
275
276void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque) {
277    if (!mSuppressTiling) {
278        mCaches.startTiling(clip.left, windowHeight - clip.bottom,
279                clip.right - clip.left, clip.bottom - clip.top, opaque);
280    }
281}
282
283void OpenGLRenderer::endTiling() {
284    if (!mSuppressTiling) mCaches.endTiling();
285}
286
287void OpenGLRenderer::finish() {
288    renderOverdraw();
289    endTiling();
290
291    // When finish() is invoked on FBO 0 we've reached the end
292    // of the current frame
293    if (getTargetFbo() == 0) {
294        mCaches.pathCache.trim();
295    }
296
297    if (!suppressErrorChecks()) {
298#if DEBUG_OPENGL
299        GLenum status = GL_NO_ERROR;
300        while ((status = glGetError()) != GL_NO_ERROR) {
301            ALOGD("GL error from OpenGLRenderer: 0x%x", status);
302            switch (status) {
303                case GL_INVALID_ENUM:
304                    ALOGE("  GL_INVALID_ENUM");
305                    break;
306                case GL_INVALID_VALUE:
307                    ALOGE("  GL_INVALID_VALUE");
308                    break;
309                case GL_INVALID_OPERATION:
310                    ALOGE("  GL_INVALID_OPERATION");
311                    break;
312                case GL_OUT_OF_MEMORY:
313                    ALOGE("  Out of memory!");
314                    break;
315            }
316        }
317#endif
318
319#if DEBUG_MEMORY_USAGE
320        mCaches.dumpMemoryUsage();
321#else
322        if (mCaches.getDebugLevel() & kDebugMemory) {
323            mCaches.dumpMemoryUsage();
324        }
325#endif
326    }
327
328    if (mCountOverdraw) {
329        countOverdraw();
330    }
331
332    mFrameStarted = false;
333}
334
335void OpenGLRenderer::interrupt() {
336    if (mCaches.currentProgram) {
337        if (mCaches.currentProgram->isInUse()) {
338            mCaches.currentProgram->remove();
339            mCaches.currentProgram = NULL;
340        }
341    }
342    mCaches.resetActiveTexture();
343    mCaches.unbindMeshBuffer();
344    mCaches.unbindIndicesBuffer();
345    mCaches.resetVertexPointers();
346    mCaches.disableTexCoordsVertexArray();
347    debugOverdraw(false, false);
348}
349
350void OpenGLRenderer::resume() {
351    const Snapshot* snapshot = currentSnapshot();
352    glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
353    glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
354    debugOverdraw(true, false);
355
356    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
357
358    mCaches.scissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
359    mCaches.enableScissor();
360    mCaches.resetScissor();
361    dirtyClip();
362
363    mCaches.activeTexture(0);
364    mCaches.resetBoundTextures();
365
366    mCaches.blend = true;
367    glEnable(GL_BLEND);
368    glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode);
369    glBlendEquation(GL_FUNC_ADD);
370}
371
372void OpenGLRenderer::resumeAfterLayer() {
373    const Snapshot* snapshot = currentSnapshot();
374    glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
375    glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
376    debugOverdraw(true, false);
377
378    mCaches.resetScissor();
379    dirtyClip();
380}
381
382void OpenGLRenderer::detachFunctor(Functor* functor) {
383    mFunctors.remove(functor);
384}
385
386void OpenGLRenderer::attachFunctor(Functor* functor) {
387    mFunctors.add(functor);
388}
389
390status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
391    status_t result = DrawGlInfo::kStatusDone;
392    size_t count = mFunctors.size();
393
394    if (count > 0) {
395        interrupt();
396        SortedVector<Functor*> functors(mFunctors);
397        mFunctors.clear();
398
399        DrawGlInfo info;
400        info.clipLeft = 0;
401        info.clipTop = 0;
402        info.clipRight = 0;
403        info.clipBottom = 0;
404        info.isLayer = false;
405        info.width = 0;
406        info.height = 0;
407        memset(info.transform, 0, sizeof(float) * 16);
408
409        for (size_t i = 0; i < count; i++) {
410            Functor* f = functors.itemAt(i);
411            result |= (*f)(DrawGlInfo::kModeProcess, &info);
412
413            if (result & DrawGlInfo::kStatusDraw) {
414                Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
415                dirty.unionWith(localDirty);
416            }
417
418            if (result & DrawGlInfo::kStatusInvoke) {
419                mFunctors.add(f);
420            }
421        }
422        resume();
423    }
424
425    return result;
426}
427
428status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
429    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
430
431    detachFunctor(functor);
432
433
434    Rect clip(*currentClipRect());
435    clip.snapToPixelBoundaries();
436
437    // Since we don't know what the functor will draw, let's dirty
438    // the entire clip region
439    if (hasLayer()) {
440        dirtyLayerUnchecked(clip, getRegion());
441    }
442
443    DrawGlInfo info;
444    info.clipLeft = clip.left;
445    info.clipTop = clip.top;
446    info.clipRight = clip.right;
447    info.clipBottom = clip.bottom;
448    info.isLayer = hasLayer();
449    info.width = currentSnapshot()->viewport.getWidth();
450    info.height = currentSnapshot()->height;
451    currentTransform()->copyTo(&info.transform[0]);
452
453    bool dirtyClip = mDirtyClip;
454    // setup GL state for functor
455    if (mDirtyClip) {
456        setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
457    }
458    if (mCaches.enableScissor() || dirtyClip) {
459        setScissorFromClip();
460    }
461    interrupt();
462
463    // call functor immediately after GL state setup
464    status_t result = (*functor)(DrawGlInfo::kModeDraw, &info);
465
466    if (result != DrawGlInfo::kStatusDone) {
467        Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
468        dirty.unionWith(localDirty);
469
470        if (result & DrawGlInfo::kStatusInvoke) {
471            mFunctors.add(functor);
472        }
473    }
474
475    resume();
476    return result | DrawGlInfo::kStatusDrew;
477}
478
479///////////////////////////////////////////////////////////////////////////////
480// Debug
481///////////////////////////////////////////////////////////////////////////////
482
483void OpenGLRenderer::eventMark(const char* name) const {
484    mCaches.eventMark(0, name);
485}
486
487void OpenGLRenderer::startMark(const char* name) const {
488    mCaches.startMark(0, name);
489}
490
491void OpenGLRenderer::endMark() const {
492    mCaches.endMark();
493}
494
495void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
496    if (mCaches.debugOverdraw && getTargetFbo() == 0) {
497        if (clear) {
498            mCaches.disableScissor();
499            mCaches.stencil.clear();
500        }
501        if (enable) {
502            mCaches.stencil.enableDebugWrite();
503        } else {
504            mCaches.stencil.disable();
505        }
506    }
507}
508
509void OpenGLRenderer::renderOverdraw() {
510    if (mCaches.debugOverdraw && getTargetFbo() == 0) {
511        const Rect* clip = &mTilingClip;
512
513        mCaches.enableScissor();
514        mCaches.setScissor(clip->left, firstSnapshot()->height - clip->bottom,
515                clip->right - clip->left, clip->bottom - clip->top);
516
517        // 1x overdraw
518        mCaches.stencil.enableDebugTest(2);
519        drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
520
521        // 2x overdraw
522        mCaches.stencil.enableDebugTest(3);
523        drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
524
525        // 3x overdraw
526        mCaches.stencil.enableDebugTest(4);
527        drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
528
529        // 4x overdraw and higher
530        mCaches.stencil.enableDebugTest(4, true);
531        drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
532
533        mCaches.stencil.disable();
534    }
535}
536
537void OpenGLRenderer::countOverdraw() {
538    size_t count = getWidth() * getHeight();
539    uint32_t* buffer = new uint32_t[count];
540    glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
541
542    size_t total = 0;
543    for (size_t i = 0; i < count; i++) {
544        total += buffer[i] & 0xff;
545    }
546
547    mOverdraw = total / float(count);
548
549    delete[] buffer;
550}
551
552///////////////////////////////////////////////////////////////////////////////
553// Layers
554///////////////////////////////////////////////////////////////////////////////
555
556bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
557    if (layer->deferredUpdateScheduled && layer->renderer &&
558            layer->displayList && layer->displayList->isRenderable()) {
559        ATRACE_CALL();
560
561        Rect& dirty = layer->dirtyRect;
562
563        if (inFrame) {
564            endTiling();
565            debugOverdraw(false, false);
566        }
567
568        if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
569            layer->render();
570        } else {
571            layer->defer();
572        }
573
574        if (inFrame) {
575            resumeAfterLayer();
576            startTilingCurrentClip();
577        }
578
579        layer->debugDrawUpdate = mCaches.debugLayersUpdates;
580        layer->hasDrawnSinceUpdate = false;
581
582        return true;
583    }
584
585    return false;
586}
587
588void OpenGLRenderer::updateLayers() {
589    // If draw deferring is enabled this method will simply defer
590    // the display list of each individual layer. The layers remain
591    // in the layer updates list which will be cleared by flushLayers().
592    int count = mLayerUpdates.size();
593    if (count > 0) {
594        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
595            startMark("Layer Updates");
596        } else {
597            startMark("Defer Layer Updates");
598        }
599
600        // Note: it is very important to update the layers in order
601        for (int i = 0; i < count; i++) {
602            Layer* layer = mLayerUpdates.itemAt(i);
603            updateLayer(layer, false);
604            if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
605                mCaches.resourceCache.decrementRefcount(layer);
606            }
607        }
608
609        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
610            mLayerUpdates.clear();
611            glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
612        }
613        endMark();
614    }
615}
616
617void OpenGLRenderer::flushLayers() {
618    int count = mLayerUpdates.size();
619    if (count > 0) {
620        startMark("Apply Layer Updates");
621        char layerName[12];
622
623        // Note: it is very important to update the layers in order
624        for (int i = 0; i < count; i++) {
625            sprintf(layerName, "Layer #%d", i);
626            startMark(layerName);
627
628            ATRACE_BEGIN("flushLayer");
629            Layer* layer = mLayerUpdates.itemAt(i);
630            layer->flush();
631            ATRACE_END();
632
633            mCaches.resourceCache.decrementRefcount(layer);
634
635            endMark();
636        }
637
638        mLayerUpdates.clear();
639        glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
640
641        endMark();
642    }
643}
644
645void OpenGLRenderer::pushLayerUpdate(Layer* layer) {
646    if (layer) {
647        // Make sure we don't introduce duplicates.
648        // SortedVector would do this automatically but we need to respect
649        // the insertion order. The linear search is not an issue since
650        // this list is usually very short (typically one item, at most a few)
651        for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
652            if (mLayerUpdates.itemAt(i) == layer) {
653                return;
654            }
655        }
656        mLayerUpdates.push_back(layer);
657        mCaches.resourceCache.incrementRefcount(layer);
658    }
659}
660
661void OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
662    if (layer) {
663        for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
664            if (mLayerUpdates.itemAt(i) == layer) {
665                mLayerUpdates.removeAt(i);
666                mCaches.resourceCache.decrementRefcount(layer);
667                break;
668            }
669        }
670    }
671}
672
673void OpenGLRenderer::clearLayerUpdates() {
674    size_t count = mLayerUpdates.size();
675    if (count > 0) {
676        mCaches.resourceCache.lock();
677        for (size_t i = 0; i < count; i++) {
678            mCaches.resourceCache.decrementRefcountLocked(mLayerUpdates.itemAt(i));
679        }
680        mCaches.resourceCache.unlock();
681        mLayerUpdates.clear();
682    }
683}
684
685void OpenGLRenderer::flushLayerUpdates() {
686    syncState();
687    updateLayers();
688    flushLayers();
689    // Wait for all the layer updates to be executed
690    AutoFence fence;
691}
692
693///////////////////////////////////////////////////////////////////////////////
694// State management
695///////////////////////////////////////////////////////////////////////////////
696
697void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
698    bool restoreOrtho = removed.flags & Snapshot::kFlagDirtyOrtho;
699    bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
700    bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
701
702    if (restoreOrtho) {
703        const Rect& r = restored.viewport;
704        glViewport(r.left, r.top, r.right, r.bottom);
705        mViewProjMatrix.load(removed.orthoMatrix); // TODO: should ortho be stored in 'restored'?
706    }
707
708    if (restoreClip) {
709        dirtyClip();
710    }
711
712    if (restoreLayer) {
713        endMark(); // Savelayer
714        startMark("ComposeLayer");
715        composeLayer(removed, restored);
716        endMark();
717    }
718}
719
720///////////////////////////////////////////////////////////////////////////////
721// Layers
722///////////////////////////////////////////////////////////////////////////////
723
724int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
725        const SkPaint* paint, int flags) {
726    const int count = saveSnapshot(flags);
727
728    if (!currentSnapshot()->isIgnored()) {
729        createLayer(left, top, right, bottom, paint, flags);
730    }
731
732    return count;
733}
734
735void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) {
736    const Rect untransformedBounds(bounds);
737
738    currentTransform()->mapRect(bounds);
739
740    // Layers only make sense if they are in the framebuffer's bounds
741    if (bounds.intersect(*currentClipRect())) {
742        // We cannot work with sub-pixels in this case
743        bounds.snapToPixelBoundaries();
744
745        // When the layer is not an FBO, we may use glCopyTexImage so we
746        // need to make sure the layer does not extend outside the bounds
747        // of the framebuffer
748        if (!bounds.intersect(currentSnapshot()->previous->viewport)) {
749            bounds.setEmpty();
750        } else if (fboLayer) {
751            clip.set(bounds);
752            mat4 inverse;
753            inverse.loadInverse(*currentTransform());
754            inverse.mapRect(clip);
755            clip.snapToPixelBoundaries();
756            if (clip.intersect(untransformedBounds)) {
757                clip.translate(-untransformedBounds.left, -untransformedBounds.top);
758                bounds.set(untransformedBounds);
759            } else {
760                clip.setEmpty();
761            }
762        }
763    } else {
764        bounds.setEmpty();
765    }
766}
767
768void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip,
769        bool fboLayer, int alpha) {
770    if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
771            bounds.getHeight() > mCaches.maxTextureSize ||
772            (fboLayer && clip.isEmpty())) {
773        mSnapshot->empty = fboLayer;
774    } else {
775        mSnapshot->invisible = mSnapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer);
776    }
777}
778
779int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
780        const SkPaint* paint, int flags) {
781    const int count = saveSnapshot(flags);
782
783    if (!currentSnapshot()->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
784        // initialize the snapshot as though it almost represents an FBO layer so deferred draw
785        // operations will be able to store and restore the current clip and transform info, and
786        // quick rejection will be correct (for display lists)
787
788        Rect bounds(left, top, right, bottom);
789        Rect clip;
790        calculateLayerBoundsAndClip(bounds, clip, true);
791        updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
792
793        if (!currentSnapshot()->isIgnored()) {
794            mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
795            mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
796            mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
797        }
798    }
799
800    return count;
801}
802
803
804/**
805 * Layers are viewed by Skia are slightly different than layers in image editing
806 * programs (for instance.) When a layer is created, previously created layers
807 * and the frame buffer still receive every drawing command. For instance, if a
808 * layer is created and a shape intersecting the bounds of the layers and the
809 * framebuffer is draw, the shape will be drawn on both (unless the layer was
810 * created with the SkCanvas::kClipToLayer_SaveFlag flag.)
811 *
812 * A way to implement layers is to create an FBO for each layer, backed by an RGBA
813 * texture. Unfortunately, this is inefficient as it requires every primitive to
814 * be drawn n + 1 times, where n is the number of active layers. In practice this
815 * means, for every primitive:
816 *   - Switch active frame buffer
817 *   - Change viewport, clip and projection matrix
818 *   - Issue the drawing
819 *
820 * Switching rendering target n + 1 times per drawn primitive is extremely costly.
821 * To avoid this, layers are implemented in a different way here, at least in the
822 * general case. FBOs are used, as an optimization, when the "clip to layer" flag
823 * is set. When this flag is set we can redirect all drawing operations into a
824 * single FBO.
825 *
826 * This implementation relies on the frame buffer being at least RGBA 8888. When
827 * a layer is created, only a texture is created, not an FBO. The content of the
828 * frame buffer contained within the layer's bounds is copied into this texture
829 * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
830 * buffer and drawing continues as normal. This technique therefore treats the
831 * frame buffer as a scratch buffer for the layers.
832 *
833 * To compose the layers back onto the frame buffer, each layer texture
834 * (containing the original frame buffer data) is drawn as a simple quad over
835 * the frame buffer. The trick is that the quad is set as the composition
836 * destination in the blending equation, and the frame buffer becomes the source
837 * of the composition.
838 *
839 * Drawing layers with an alpha value requires an extra step before composition.
840 * An empty quad is drawn over the layer's region in the frame buffer. This quad
841 * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
842 * quad is used to multiply the colors in the frame buffer. This is achieved by
843 * changing the GL blend functions for the GL_FUNC_ADD blend equation to
844 * GL_ZERO, GL_SRC_ALPHA.
845 *
846 * Because glCopyTexImage2D() can be slow, an alternative implementation might
847 * be use to draw a single clipped layer. The implementation described above
848 * is correct in every case.
849 *
850 * (1) The frame buffer is actually not cleared right away. To allow the GPU
851 *     to potentially optimize series of calls to glCopyTexImage2D, the frame
852 *     buffer is left untouched until the first drawing operation. Only when
853 *     something actually gets drawn are the layers regions cleared.
854 */
855bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
856        const SkPaint* paint, int flags) {
857    LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
858    LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
859
860    const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
861
862    // Window coordinates of the layer
863    Rect clip;
864    Rect bounds(left, top, right, bottom);
865    calculateLayerBoundsAndClip(bounds, clip, fboLayer);
866    updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
867
868    // Bail out if we won't draw in this snapshot
869    if (currentSnapshot()->isIgnored()) {
870        return false;
871    }
872
873    mCaches.activeTexture(0);
874    Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
875    if (!layer) {
876        return false;
877    }
878
879    layer->setPaint(paint);
880    layer->layer.set(bounds);
881    layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
882            bounds.getWidth() / float(layer->getWidth()), 0.0f);
883
884    layer->setBlend(true);
885    layer->setDirty(false);
886
887    // Save the layer in the snapshot
888    mSnapshot->flags |= Snapshot::kFlagIsLayer;
889    mSnapshot->layer = layer;
890
891    startMark("SaveLayer");
892    if (fboLayer) {
893        return createFboLayer(layer, bounds, clip);
894    } else {
895        // Copy the framebuffer into the layer
896        layer->bindTexture();
897        if (!bounds.isEmpty()) {
898            if (layer->isEmpty()) {
899                // Workaround for some GL drivers. When reading pixels lying outside
900                // of the window we should get undefined values for those pixels.
901                // Unfortunately some drivers will turn the entire target texture black
902                // when reading outside of the window.
903                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(),
904                        0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
905                layer->setEmpty(false);
906            }
907
908            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
909                    mSnapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
910
911            // Enqueue the buffer coordinates to clear the corresponding region later
912            mLayers.push(new Rect(bounds));
913        }
914    }
915
916    return true;
917}
918
919bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
920    layer->clipRect.set(clip);
921    layer->setFbo(mCaches.fboCache.get());
922
923    mSnapshot->region = &mSnapshot->layer->region;
924    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer |
925            Snapshot::kFlagDirtyOrtho;
926    mSnapshot->fbo = layer->getFbo();
927    mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
928    mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
929    mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
930    mSnapshot->height = bounds.getHeight();
931    mSnapshot->orthoMatrix.load(mViewProjMatrix);
932
933    endTiling();
934    debugOverdraw(false, false);
935    // Bind texture to FBO
936    glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
937    layer->bindTexture();
938
939    // Initialize the texture if needed
940    if (layer->isEmpty()) {
941        layer->allocateTexture();
942        layer->setEmpty(false);
943    }
944
945    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
946            layer->getTexture(), 0);
947
948    startTilingCurrentClip(true);
949
950    // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
951    mCaches.enableScissor();
952    mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
953            clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
954    glClear(GL_COLOR_BUFFER_BIT);
955
956    dirtyClip();
957
958    // Change the ortho projection
959    glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
960
961    // TODO: determine best way to support 3d drawing within HW layers
962    mViewProjMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
963
964    return true;
965}
966
967/**
968 * Read the documentation of createLayer() before doing anything in this method.
969 */
970void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) {
971    if (!removed.layer) {
972        ALOGE("Attempting to compose a layer that does not exist");
973        return;
974    }
975
976    Layer* layer = removed.layer;
977    const Rect& rect = layer->layer;
978    const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
979
980    bool clipRequired = false;
981    calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
982            &clipRequired, false); // safely ignore return, should never be rejected
983    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
984
985    if (fboLayer) {
986        endTiling();
987
988        // Detach the texture from the FBO
989        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
990
991        layer->removeFbo(false);
992
993        // Unbind current FBO and restore previous one
994        glBindFramebuffer(GL_FRAMEBUFFER, restored.fbo);
995        debugOverdraw(true, false);
996
997        startTilingCurrentClip();
998    }
999
1000    if (!fboLayer && layer->getAlpha() < 255) {
1001        SkPaint layerPaint;
1002        layerPaint.setAlpha(layer->getAlpha());
1003        layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
1004        layerPaint.setColorFilter(layer->getColorFilter());
1005
1006        drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true);
1007        // Required below, composeLayerRect() will divide by 255
1008        layer->setAlpha(255);
1009    }
1010
1011    mCaches.unbindMeshBuffer();
1012
1013    mCaches.activeTexture(0);
1014
1015    // When the layer is stored in an FBO, we can save a bit of fillrate by
1016    // drawing only the dirty region
1017    if (fboLayer) {
1018        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);
1019        composeLayerRegion(layer, rect);
1020    } else if (!rect.isEmpty()) {
1021        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
1022
1023        save(0);
1024        // the layer contains screen buffer content that shouldn't be alpha modulated
1025        // (and any necessary alpha modulation was handled drawing into the layer)
1026        mSnapshot->alpha = 1.0f;
1027        composeLayerRect(layer, rect, true);
1028        restore();
1029    }
1030
1031    dirtyClip();
1032
1033    // Failing to add the layer to the cache should happen only if the layer is too large
1034    if (!mCaches.layerCache.put(layer)) {
1035        LAYER_LOGD("Deleting layer");
1036        Caches::getInstance().resourceCache.decrementRefcount(layer);
1037    }
1038}
1039
1040void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
1041    float alpha = getLayerAlpha(layer);
1042
1043    setupDraw();
1044    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
1045        setupDrawWithTexture();
1046    } else {
1047        setupDrawWithExternalTexture();
1048    }
1049    setupDrawTextureTransform();
1050    setupDrawColor(alpha, alpha, alpha, alpha);
1051    setupDrawColorFilter(layer->getColorFilter());
1052    setupDrawBlending(layer);
1053    setupDrawProgram();
1054    setupDrawPureColorUniforms();
1055    setupDrawColorFilterUniforms(layer->getColorFilter());
1056    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
1057        setupDrawTexture(layer->getTexture());
1058    } else {
1059        setupDrawExternalTexture(layer->getTexture());
1060    }
1061    if (currentTransform()->isPureTranslate() &&
1062            !layer->getForceFilter() &&
1063            layer->getWidth() == (uint32_t) rect.getWidth() &&
1064            layer->getHeight() == (uint32_t) rect.getHeight()) {
1065        const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
1066        const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
1067
1068        layer->setFilter(GL_NEAREST);
1069        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
1070                x, y, x + rect.getWidth(), y + rect.getHeight(), true);
1071    } else {
1072        layer->setFilter(GL_LINEAR);
1073        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
1074                rect.left, rect.top, rect.right, rect.bottom);
1075    }
1076    setupDrawTextureTransformUniforms(layer->getTexTransform());
1077    setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
1078
1079    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
1080}
1081
1082void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
1083    if (!layer->isTextureLayer()) {
1084        const Rect& texCoords = layer->texCoords;
1085        resetDrawTextureTexCoords(texCoords.left, texCoords.top,
1086                texCoords.right, texCoords.bottom);
1087
1088        float x = rect.left;
1089        float y = rect.top;
1090        bool simpleTransform = currentTransform()->isPureTranslate() &&
1091                layer->getWidth() == (uint32_t) rect.getWidth() &&
1092                layer->getHeight() == (uint32_t) rect.getHeight();
1093
1094        if (simpleTransform) {
1095            // When we're swapping, the layer is already in screen coordinates
1096            if (!swap) {
1097                x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
1098                y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
1099            }
1100
1101            layer->setFilter(GL_NEAREST, true);
1102        } else {
1103            layer->setFilter(GL_LINEAR, true);
1104        }
1105
1106        SkPaint layerPaint;
1107        layerPaint.setAlpha(getLayerAlpha(layer) * 255);
1108        layerPaint.setXfermodeMode(layer->getMode());
1109        layerPaint.setColorFilter(layer->getColorFilter());
1110
1111        bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f;
1112        drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
1113                layer->getTexture(), &layerPaint, blend,
1114                &mMeshVertices[0].x, &mMeshVertices[0].u,
1115                GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
1116
1117        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
1118    } else {
1119        resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
1120        drawTextureLayer(layer, rect);
1121        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
1122    }
1123}
1124
1125/**
1126 * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
1127 * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
1128 * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
1129 * by saveLayer's restore
1130 */
1131#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) {                             \
1132        DRAW_COMMAND;                                                            \
1133        if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
1134            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);                 \
1135            DRAW_COMMAND;                                                        \
1136            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                     \
1137        }                                                                        \
1138    }
1139
1140#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
1141
1142void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
1143    if (layer->region.isRect()) {
1144        layer->setRegionAsRect();
1145
1146        DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
1147
1148        layer->region.clear();
1149        return;
1150    }
1151
1152    if (CC_LIKELY(!layer->region.isEmpty())) {
1153        size_t count;
1154        const android::Rect* rects;
1155        Region safeRegion;
1156        if (CC_LIKELY(hasRectToRectTransform())) {
1157            rects = layer->region.getArray(&count);
1158        } else {
1159            safeRegion = Region::createTJunctionFreeRegion(layer->region);
1160            rects = safeRegion.getArray(&count);
1161        }
1162
1163        const float alpha = getLayerAlpha(layer);
1164        const float texX = 1.0f / float(layer->getWidth());
1165        const float texY = 1.0f / float(layer->getHeight());
1166        const float height = rect.getHeight();
1167
1168        setupDraw();
1169
1170        // We must get (and therefore bind) the region mesh buffer
1171        // after we setup drawing in case we need to mess with the
1172        // stencil buffer in setupDraw()
1173        TextureVertex* mesh = mCaches.getRegionMesh();
1174        uint32_t numQuads = 0;
1175
1176        setupDrawWithTexture();
1177        setupDrawColor(alpha, alpha, alpha, alpha);
1178        setupDrawColorFilter(layer->getColorFilter());
1179        setupDrawBlending(layer);
1180        setupDrawProgram();
1181        setupDrawDirtyRegionsDisabled();
1182        setupDrawPureColorUniforms();
1183        setupDrawColorFilterUniforms(layer->getColorFilter());
1184        setupDrawTexture(layer->getTexture());
1185        if (currentTransform()->isPureTranslate()) {
1186            const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
1187            const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
1188
1189            layer->setFilter(GL_NEAREST);
1190            setupDrawModelView(kModelViewMode_Translate, false,
1191                    x, y, x + rect.getWidth(), y + rect.getHeight(), true);
1192        } else {
1193            layer->setFilter(GL_LINEAR);
1194            setupDrawModelView(kModelViewMode_Translate, false,
1195                    rect.left, rect.top, rect.right, rect.bottom);
1196        }
1197        setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
1198
1199        for (size_t i = 0; i < count; i++) {
1200            const android::Rect* r = &rects[i];
1201
1202            const float u1 = r->left * texX;
1203            const float v1 = (height - r->top) * texY;
1204            const float u2 = r->right * texX;
1205            const float v2 = (height - r->bottom) * texY;
1206
1207            // TODO: Reject quads outside of the clip
1208            TextureVertex::set(mesh++, r->left, r->top, u1, v1);
1209            TextureVertex::set(mesh++, r->right, r->top, u2, v1);
1210            TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
1211            TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
1212
1213            numQuads++;
1214
1215            if (numQuads >= gMaxNumberOfQuads) {
1216                DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1217                                GL_UNSIGNED_SHORT, NULL));
1218                numQuads = 0;
1219                mesh = mCaches.getRegionMesh();
1220            }
1221        }
1222
1223        if (numQuads > 0) {
1224            DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1225                            GL_UNSIGNED_SHORT, NULL));
1226        }
1227
1228#if DEBUG_LAYERS_AS_REGIONS
1229        drawRegionRectsDebug(layer->region);
1230#endif
1231
1232        layer->region.clear();
1233    }
1234}
1235
1236#if DEBUG_LAYERS_AS_REGIONS
1237void OpenGLRenderer::drawRegionRectsDebug(const Region& region) {
1238    size_t count;
1239    const android::Rect* rects = region.getArray(&count);
1240
1241    uint32_t colors[] = {
1242            0x7fff0000, 0x7f00ff00,
1243            0x7f0000ff, 0x7fff00ff,
1244    };
1245
1246    int offset = 0;
1247    int32_t top = rects[0].top;
1248
1249    for (size_t i = 0; i < count; i++) {
1250        if (top != rects[i].top) {
1251            offset ^= 0x2;
1252            top = rects[i].top;
1253        }
1254
1255        SkPaint paint;
1256        paint.setColor(colors[offset + (i & 0x1)]);
1257        Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
1258        drawColorRect(r.left, r.top, r.right, r.bottom, paint);
1259    }
1260}
1261#endif
1262
1263void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) {
1264    Vector<float> rects;
1265
1266    SkRegion::Iterator it(region);
1267    while (!it.done()) {
1268        const SkIRect& r = it.rect();
1269        rects.push(r.fLeft);
1270        rects.push(r.fTop);
1271        rects.push(r.fRight);
1272        rects.push(r.fBottom);
1273        it.next();
1274    }
1275
1276    drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false);
1277}
1278
1279void OpenGLRenderer::dirtyLayer(const float left, const float top,
1280        const float right, const float bottom, const mat4 transform) {
1281    if (hasLayer()) {
1282        Rect bounds(left, top, right, bottom);
1283        transform.mapRect(bounds);
1284        dirtyLayerUnchecked(bounds, getRegion());
1285    }
1286}
1287
1288void OpenGLRenderer::dirtyLayer(const float left, const float top,
1289        const float right, const float bottom) {
1290    if (hasLayer()) {
1291        Rect bounds(left, top, right, bottom);
1292        dirtyLayerUnchecked(bounds, getRegion());
1293    }
1294}
1295
1296void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
1297    if (bounds.intersect(*currentClipRect())) {
1298        bounds.snapToPixelBoundaries();
1299        android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
1300        if (!dirty.isEmpty()) {
1301            region->orSelf(dirty);
1302        }
1303    }
1304}
1305
1306void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
1307    GLsizei elementsCount = quadsCount * 6;
1308    while (elementsCount > 0) {
1309        GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
1310
1311        setupDrawIndexedVertices(&mesh[0].x);
1312        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL);
1313
1314        elementsCount -= drawCount;
1315        // Though there are 4 vertices in a quad, we use 6 indices per
1316        // quad to draw with GL_TRIANGLES
1317        mesh += (drawCount / 6) * 4;
1318    }
1319}
1320
1321void OpenGLRenderer::clearLayerRegions() {
1322    const size_t count = mLayers.size();
1323    if (count == 0) return;
1324
1325    if (!currentSnapshot()->isIgnored()) {
1326        // Doing several glScissor/glClear here can negatively impact
1327        // GPUs with a tiler architecture, instead we draw quads with
1328        // the Clear blending mode
1329
1330        // The list contains bounds that have already been clipped
1331        // against their initial clip rect, and the current clip
1332        // is likely different so we need to disable clipping here
1333        bool scissorChanged = mCaches.disableScissor();
1334
1335        Vertex mesh[count * 4];
1336        Vertex* vertex = mesh;
1337
1338        for (uint32_t i = 0; i < count; i++) {
1339            Rect* bounds = mLayers.itemAt(i);
1340
1341            Vertex::set(vertex++, bounds->left, bounds->top);
1342            Vertex::set(vertex++, bounds->right, bounds->top);
1343            Vertex::set(vertex++, bounds->left, bounds->bottom);
1344            Vertex::set(vertex++, bounds->right, bounds->bottom);
1345
1346            delete bounds;
1347        }
1348        // We must clear the list of dirty rects before we
1349        // call setupDraw() to prevent stencil setup to do
1350        // the same thing again
1351        mLayers.clear();
1352
1353        SkPaint clearPaint;
1354        clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
1355
1356        setupDraw(false);
1357        setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
1358        setupDrawBlending(&clearPaint, true);
1359        setupDrawProgram();
1360        setupDrawPureColorUniforms();
1361        setupDrawModelView(kModelViewMode_Translate, false,
1362                0.0f, 0.0f, 0.0f, 0.0f, true);
1363
1364        issueIndexedQuadDraw(&mesh[0], count);
1365
1366        if (scissorChanged) mCaches.enableScissor();
1367    } else {
1368        for (uint32_t i = 0; i < count; i++) {
1369            delete mLayers.itemAt(i);
1370        }
1371        mLayers.clear();
1372    }
1373}
1374
1375///////////////////////////////////////////////////////////////////////////////
1376// State Deferral
1377///////////////////////////////////////////////////////////////////////////////
1378
1379bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
1380    const Rect* currentClip = currentClipRect();
1381    const mat4* currentMatrix = currentTransform();
1382
1383    if (stateDeferFlags & kStateDeferFlag_Draw) {
1384        // state has bounds initialized in local coordinates
1385        if (!state.mBounds.isEmpty()) {
1386            currentMatrix->mapRect(state.mBounds);
1387            Rect clippedBounds(state.mBounds);
1388            // NOTE: if we ever want to use this clipping info to drive whether the scissor
1389            // is used, it should more closely duplicate the quickReject logic (in how it uses
1390            // snapToPixelBoundaries)
1391
1392            if(!clippedBounds.intersect(*currentClip)) {
1393                // quick rejected
1394                return true;
1395            }
1396
1397            state.mClipSideFlags = kClipSide_None;
1398            if (!currentClip->contains(state.mBounds)) {
1399                int& flags = state.mClipSideFlags;
1400                // op partially clipped, so record which sides are clipped for clip-aware merging
1401                if (currentClip->left > state.mBounds.left) flags |= kClipSide_Left;
1402                if (currentClip->top > state.mBounds.top) flags |= kClipSide_Top;
1403                if (currentClip->right < state.mBounds.right) flags |= kClipSide_Right;
1404                if (currentClip->bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
1405            }
1406            state.mBounds.set(clippedBounds);
1407        } else {
1408            // Empty bounds implies size unknown. Label op as conservatively clipped to disable
1409            // overdraw avoidance (since we don't know what it overlaps)
1410            state.mClipSideFlags = kClipSide_ConservativeFull;
1411            state.mBounds.set(*currentClip);
1412        }
1413    }
1414
1415    state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
1416    if (state.mClipValid) {
1417        state.mClip.set(*currentClip);
1418    }
1419
1420    // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
1421    // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
1422    state.mMatrix.load(*currentMatrix);
1423    state.mDrawModifiers = mDrawModifiers;
1424    state.mAlpha = currentSnapshot()->alpha;
1425    return false;
1426}
1427
1428void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
1429    setMatrix(state.mMatrix);
1430    mSnapshot->alpha = state.mAlpha;
1431    mDrawModifiers = state.mDrawModifiers;
1432
1433    if (state.mClipValid && !skipClipRestore) {
1434        mSnapshot->setClip(state.mClip.left, state.mClip.top,
1435                state.mClip.right, state.mClip.bottom);
1436        dirtyClip();
1437    }
1438}
1439
1440/**
1441 * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done
1442 * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at
1443 * least one op is clipped), or disabled entirely (because no merged op is clipped)
1444 *
1445 * This method should be called when restoreDisplayState() won't be restoring the clip
1446 */
1447void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
1448    if (clipRect != NULL) {
1449        mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
1450    } else {
1451        mSnapshot->setClip(0, 0, getWidth(), getHeight());
1452    }
1453    dirtyClip();
1454    mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);
1455}
1456
1457///////////////////////////////////////////////////////////////////////////////
1458// Clipping
1459///////////////////////////////////////////////////////////////////////////////
1460
1461void OpenGLRenderer::setScissorFromClip() {
1462    Rect clip(*currentClipRect());
1463    clip.snapToPixelBoundaries();
1464
1465    if (mCaches.setScissor(clip.left, currentSnapshot()->height - clip.bottom,
1466            clip.getWidth(), clip.getHeight())) {
1467        mDirtyClip = false;
1468    }
1469}
1470
1471void OpenGLRenderer::ensureStencilBuffer() {
1472    // Thanks to the mismatch between EGL and OpenGL ES FBO we
1473    // cannot attach a stencil buffer to fbo0 dynamically. Let's
1474    // just hope we have one when hasLayer() returns false.
1475    if (hasLayer()) {
1476        attachStencilBufferToLayer(currentSnapshot()->layer);
1477    }
1478}
1479
1480void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
1481    // The layer's FBO is already bound when we reach this stage
1482    if (!layer->getStencilRenderBuffer()) {
1483        // GL_QCOM_tiled_rendering doesn't like it if a renderbuffer
1484        // is attached after we initiated tiling. We must turn it off,
1485        // attach the new render buffer then turn tiling back on
1486        endTiling();
1487
1488        RenderBuffer* buffer = mCaches.renderBufferCache.get(
1489                Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
1490        layer->setStencilRenderBuffer(buffer);
1491
1492        startTiling(layer->clipRect, layer->layer.getHeight());
1493    }
1494}
1495
1496void OpenGLRenderer::setStencilFromClip() {
1497    if (!mCaches.debugOverdraw) {
1498        if (!currentSnapshot()->clipRegion->isEmpty()) {
1499            // NOTE: The order here is important, we must set dirtyClip to false
1500            //       before any draw call to avoid calling back into this method
1501            mDirtyClip = false;
1502
1503            ensureStencilBuffer();
1504
1505            mCaches.stencil.enableWrite();
1506
1507            // Clear the stencil but first make sure we restrict drawing
1508            // to the region's bounds
1509            bool resetScissor = mCaches.enableScissor();
1510            if (resetScissor) {
1511                // The scissor was not set so we now need to update it
1512                setScissorFromClip();
1513            }
1514            mCaches.stencil.clear();
1515            if (resetScissor) mCaches.disableScissor();
1516
1517            SkPaint paint;
1518            paint.setColor(0xff000000);
1519            paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1520
1521            // NOTE: We could use the region contour path to generate a smaller mesh
1522            //       Since we are using the stencil we could use the red book path
1523            //       drawing technique. It might increase bandwidth usage though.
1524
1525            // The last parameter is important: we are not drawing in the color buffer
1526            // so we don't want to dirty the current layer, if any
1527            drawRegionRects(*(currentSnapshot()->clipRegion), paint, false);
1528
1529            mCaches.stencil.enableTest();
1530
1531            // Draw the region used to generate the stencil if the appropriate debug
1532            // mode is enabled
1533            if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
1534                paint.setColor(0x7f0000ff);
1535                paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
1536                drawRegionRects(*(currentSnapshot()->clipRegion), paint);
1537            }
1538        } else {
1539            mCaches.stencil.disable();
1540        }
1541    }
1542}
1543
1544/**
1545 * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out.
1546 *
1547 * @param paint if not null, the bounds will be expanded to account for stroke depending on paint
1548 *         style, and tessellated AA ramp
1549 */
1550bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom,
1551        const SkPaint* paint) {
1552    bool clipRequired = false;
1553    bool snapOut = paint && paint->isAntiAlias();
1554
1555    if (paint && paint->getStyle() != SkPaint::kFill_Style) {
1556        float outset = paint->getStrokeWidth() * 0.5f;
1557        left -= outset;
1558        top -= outset;
1559        right += outset;
1560        bottom += outset;
1561    }
1562
1563    if (calculateQuickRejectForScissor(left, top, right, bottom, &clipRequired, snapOut)) {
1564        return true;
1565    }
1566
1567    if (!isRecording()) {
1568        // not quick rejected, so enable the scissor if clipRequired
1569        mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
1570    }
1571    return false;
1572}
1573
1574void OpenGLRenderer::debugClip() {
1575#if DEBUG_CLIP_REGIONS
1576    if (!isRecording() && !currentSnapshot()->clipRegion->isEmpty()) {
1577        SkPaint paint;
1578        paint.setColor(0x7f00ff00);
1579        drawRegionRects(*(currentSnapshot()->clipRegion, paint);
1580
1581    }
1582#endif
1583}
1584
1585///////////////////////////////////////////////////////////////////////////////
1586// Drawing commands
1587///////////////////////////////////////////////////////////////////////////////
1588
1589void OpenGLRenderer::setupDraw(bool clear) {
1590    // TODO: It would be best if we could do this before quickRejectSetupScissor()
1591    //       changes the scissor test state
1592    if (clear) clearLayerRegions();
1593    // Make sure setScissor & setStencil happen at the beginning of
1594    // this method
1595    if (mDirtyClip) {
1596        if (mCaches.scissorEnabled) {
1597            setScissorFromClip();
1598        }
1599        setStencilFromClip();
1600    }
1601
1602    mDescription.reset();
1603
1604    mSetShaderColor = false;
1605    mColorSet = false;
1606    mColorA = mColorR = mColorG = mColorB = 0.0f;
1607    mTextureUnit = 0;
1608    mTrackDirtyRegions = true;
1609
1610    // Enable debug highlight when what we're about to draw is tested against
1611    // the stencil buffer and if stencil highlight debugging is on
1612    mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
1613            mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
1614            mCaches.stencil.isTestEnabled();
1615
1616    mDescription.emulateStencil = mCountOverdraw;
1617}
1618
1619void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
1620    mDescription.hasTexture = true;
1621    mDescription.hasAlpha8Texture = isAlpha8;
1622}
1623
1624void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
1625    mDescription.hasTexture = true;
1626    mDescription.hasColors = true;
1627    mDescription.hasAlpha8Texture = isAlpha8;
1628}
1629
1630void OpenGLRenderer::setupDrawWithExternalTexture() {
1631    mDescription.hasExternalTexture = true;
1632}
1633
1634void OpenGLRenderer::setupDrawNoTexture() {
1635    mCaches.disableTexCoordsVertexArray();
1636}
1637
1638void OpenGLRenderer::setupDrawAA() {
1639    mDescription.isAA = true;
1640}
1641
1642void OpenGLRenderer::setupDrawColor(int color, int alpha) {
1643    mColorA = alpha / 255.0f;
1644    mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
1645    mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
1646    mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
1647    mColorSet = true;
1648    mSetShaderColor = mDescription.setColorModulate(mColorA);
1649}
1650
1651void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
1652    mColorA = alpha / 255.0f;
1653    mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
1654    mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
1655    mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
1656    mColorSet = true;
1657    mSetShaderColor = mDescription.setAlpha8ColorModulate(mColorR, mColorG, mColorB, mColorA);
1658}
1659
1660void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
1661    mCaches.fontRenderer->describe(mDescription, paint);
1662}
1663
1664void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
1665    mColorA = a;
1666    mColorR = r;
1667    mColorG = g;
1668    mColorB = b;
1669    mColorSet = true;
1670    mSetShaderColor = mDescription.setColorModulate(a);
1671}
1672
1673void OpenGLRenderer::setupDrawShader() {
1674    if (mDrawModifiers.mShader) {
1675        mDrawModifiers.mShader->describe(mDescription, mExtensions);
1676    }
1677}
1678
1679void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
1680    if (filter == NULL) {
1681        return;
1682    }
1683
1684    SkXfermode::Mode mode;
1685    if (filter->asColorMode(NULL, &mode)) {
1686        mDescription.colorOp = ProgramDescription::kColorBlend;
1687        mDescription.colorMode = mode;
1688    } else if (filter->asColorMatrix(NULL)) {
1689        mDescription.colorOp = ProgramDescription::kColorMatrix;
1690    }
1691}
1692
1693void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
1694    if (mColorSet && mode == SkXfermode::kClear_Mode) {
1695        mColorA = 1.0f;
1696        mColorR = mColorG = mColorB = 0.0f;
1697        mSetShaderColor = mDescription.modulate = true;
1698    }
1699}
1700
1701void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
1702    SkXfermode::Mode mode = layer->getMode();
1703    // When the blending mode is kClear_Mode, we need to use a modulate color
1704    // argb=1,0,0,0
1705    accountForClear(mode);
1706    bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f ||
1707            (mColorSet && mColorA < 1.0f) ||
1708            (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
1709            layer->getColorFilter();
1710    chooseBlending(blend, mode, mDescription, swapSrcDst);
1711}
1712
1713void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool swapSrcDst) {
1714    SkXfermode::Mode mode = getXfermodeDirect(paint);
1715    // When the blending mode is kClear_Mode, we need to use a modulate color
1716    // argb=1,0,0,0
1717    accountForClear(mode);
1718    blend |= (mColorSet && mColorA < 1.0f) ||
1719            (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
1720            (paint && paint->getColorFilter());
1721    chooseBlending(blend, mode, mDescription, swapSrcDst);
1722}
1723
1724void OpenGLRenderer::setupDrawProgram() {
1725    useProgram(mCaches.programCache.get(mDescription));
1726}
1727
1728void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
1729    mTrackDirtyRegions = false;
1730}
1731
1732void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
1733        float left, float top, float right, float bottom, bool ignoreTransform) {
1734    mModelView.loadTranslate(left, top, 0.0f);
1735    if (mode == kModelViewMode_TranslateAndScale) {
1736        mModelView.scale(right - left, bottom - top, 1.0f);
1737    }
1738
1739    bool dirty = right - left > 0.0f && bottom - top > 0.0f;
1740    if (!ignoreTransform) {
1741        mCaches.currentProgram->set(mViewProjMatrix, mModelView, *currentTransform(), offset);
1742        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, *currentTransform());
1743    } else {
1744        mCaches.currentProgram->set(mViewProjMatrix, mModelView, mat4::identity(), offset);
1745        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
1746    }
1747}
1748
1749void OpenGLRenderer::setupDrawColorUniforms() {
1750    if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) {
1751        mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
1752    }
1753}
1754
1755void OpenGLRenderer::setupDrawPureColorUniforms() {
1756    if (mSetShaderColor) {
1757        mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
1758    }
1759}
1760
1761void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) {
1762    if (mDrawModifiers.mShader) {
1763        if (ignoreTransform) {
1764            // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
1765            // because it was built into modelView / the geometry, and the SkiaShader needs to
1766            // compensate.
1767            mat4 modelViewWithoutTransform;
1768            modelViewWithoutTransform.loadInverse(*currentTransform());
1769            modelViewWithoutTransform.multiply(mModelView);
1770            mModelView.load(modelViewWithoutTransform);
1771        }
1772        mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
1773                mModelView, *mSnapshot, &mTextureUnit);
1774    }
1775}
1776
1777void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
1778    if (NULL == filter) {
1779        return;
1780    }
1781
1782    SkColor color;
1783    SkXfermode::Mode mode;
1784    if (filter->asColorMode(&color, &mode)) {
1785        const int alpha = SkColorGetA(color);
1786        const GLfloat a = alpha / 255.0f;
1787        const GLfloat r = a * SkColorGetR(color) / 255.0f;
1788        const GLfloat g = a * SkColorGetG(color) / 255.0f;
1789        const GLfloat b = a * SkColorGetB(color) / 255.0f;
1790        glUniform4f(mCaches.currentProgram->getUniform("colorBlend"), r, g, b, a);
1791        return;
1792    }
1793
1794    SkScalar srcColorMatrix[20];
1795    if (filter->asColorMatrix(srcColorMatrix)) {
1796
1797        float colorMatrix[16];
1798        memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
1799        memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
1800        memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
1801        memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
1802
1803        // Skia uses the range [0..255] for the addition vector, but we need
1804        // the [0..1] range to apply the vector in GLSL
1805        float colorVector[4];
1806        colorVector[0] = srcColorMatrix[4] / 255.0f;
1807        colorVector[1] = srcColorMatrix[9] / 255.0f;
1808        colorVector[2] = srcColorMatrix[14] / 255.0f;
1809        colorVector[3] = srcColorMatrix[19] / 255.0f;
1810
1811        glUniformMatrix4fv(mCaches.currentProgram->getUniform("colorMatrix"), 1,
1812                GL_FALSE, colorMatrix);
1813        glUniform4fv(mCaches.currentProgram->getUniform("colorMatrixVector"), 1, colorVector);
1814        return;
1815    }
1816
1817    // it is an error if we ever get here
1818}
1819
1820void OpenGLRenderer::setupDrawTextGammaUniforms() {
1821    mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram);
1822}
1823
1824void OpenGLRenderer::setupDrawSimpleMesh() {
1825    bool force = mCaches.bindMeshBuffer();
1826    mCaches.bindPositionVertexPointer(force, 0);
1827    mCaches.unbindIndicesBuffer();
1828}
1829
1830void OpenGLRenderer::setupDrawTexture(GLuint texture) {
1831    if (texture) bindTexture(texture);
1832    mTextureUnit++;
1833    mCaches.enableTexCoordsVertexArray();
1834}
1835
1836void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
1837    bindExternalTexture(texture);
1838    mTextureUnit++;
1839    mCaches.enableTexCoordsVertexArray();
1840}
1841
1842void OpenGLRenderer::setupDrawTextureTransform() {
1843    mDescription.hasTextureTransform = true;
1844}
1845
1846void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
1847    glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
1848            GL_FALSE, &transform.data[0]);
1849}
1850
1851void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1852        const GLvoid* texCoords, GLuint vbo) {
1853    bool force = false;
1854    if (!vertices || vbo) {
1855        force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
1856    } else {
1857        force = mCaches.unbindMeshBuffer();
1858    }
1859
1860    mCaches.bindPositionVertexPointer(force, vertices);
1861    if (mCaches.currentProgram->texCoords >= 0) {
1862        mCaches.bindTexCoordsVertexPointer(force, texCoords);
1863    }
1864
1865    mCaches.unbindIndicesBuffer();
1866}
1867
1868void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1869        const GLvoid* texCoords, const GLvoid* colors) {
1870    bool force = mCaches.unbindMeshBuffer();
1871    GLsizei stride = sizeof(ColorTextureVertex);
1872
1873    mCaches.bindPositionVertexPointer(force, vertices, stride);
1874    if (mCaches.currentProgram->texCoords >= 0) {
1875        mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
1876    }
1877    int slot = mCaches.currentProgram->getAttrib("colors");
1878    if (slot >= 0) {
1879        glEnableVertexAttribArray(slot);
1880        glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
1881    }
1882
1883    mCaches.unbindIndicesBuffer();
1884}
1885
1886void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
1887        const GLvoid* texCoords, GLuint vbo) {
1888    bool force = false;
1889    // If vbo is != 0 we want to treat the vertices parameter as an offset inside
1890    // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
1891    // use the default VBO found in Caches
1892    if (!vertices || vbo) {
1893        force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
1894    } else {
1895        force = mCaches.unbindMeshBuffer();
1896    }
1897    mCaches.bindQuadIndicesBuffer();
1898
1899    mCaches.bindPositionVertexPointer(force, vertices);
1900    if (mCaches.currentProgram->texCoords >= 0) {
1901        mCaches.bindTexCoordsVertexPointer(force, texCoords);
1902    }
1903}
1904
1905void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
1906    bool force = mCaches.unbindMeshBuffer();
1907    mCaches.bindQuadIndicesBuffer();
1908    mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
1909}
1910
1911///////////////////////////////////////////////////////////////////////////////
1912// Drawing
1913///////////////////////////////////////////////////////////////////////////////
1914
1915status_t OpenGLRenderer::drawDisplayList(RenderNode* displayList, Rect& dirty,
1916        int32_t replayFlags) {
1917    status_t status;
1918    // All the usual checks and setup operations (quickReject, setupDraw, etc.)
1919    // will be performed by the display list itself
1920    if (displayList && displayList->isRenderable()) {
1921        // compute 3d ordering
1922        displayList->updateProperties();
1923        displayList->computeOrdering();
1924        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
1925            status = startFrame();
1926            ReplayStateStruct replayStruct(*this, dirty, replayFlags);
1927            displayList->replayNodeTree(replayStruct);
1928            return status | replayStruct.mDrawGlStatus;
1929        }
1930
1931        bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs!
1932        DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw);
1933        DeferStateStruct deferStruct(deferredList, *this, replayFlags);
1934        displayList->deferNodeTree(deferStruct);
1935
1936        flushLayers();
1937        status = startFrame();
1938
1939        return deferredList.flush(*this, dirty) | status;
1940    }
1941
1942    return DrawGlInfo::kStatusDone;
1943}
1944
1945void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint) {
1946    int color = paint != NULL ? paint->getColor() : 0;
1947
1948    float x = left;
1949    float y = top;
1950
1951    texture->setWrap(GL_CLAMP_TO_EDGE, true);
1952
1953    bool ignoreTransform = false;
1954    if (currentTransform()->isPureTranslate()) {
1955        x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
1956        y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
1957        ignoreTransform = true;
1958
1959        texture->setFilter(GL_NEAREST, true);
1960    } else {
1961        texture->setFilter(getFilter(paint), true);
1962    }
1963
1964    // No need to check for a UV mapper on the texture object, only ARGB_8888
1965    // bitmaps get packed in the atlas
1966    drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
1967            paint, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
1968            GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
1969}
1970
1971/**
1972 * Important note: this method is intended to draw batches of bitmaps and
1973 * will not set the scissor enable or dirty the current layer, if any.
1974 * The caller is responsible for properly dirtying the current layer.
1975 */
1976status_t OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
1977        int bitmapCount, TextureVertex* vertices, bool pureTranslate,
1978        const Rect& bounds, const SkPaint* paint) {
1979    mCaches.activeTexture(0);
1980    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
1981    if (!texture) return DrawGlInfo::kStatusDone;
1982
1983    const AutoTexture autoCleanup(texture);
1984
1985    texture->setWrap(GL_CLAMP_TO_EDGE, true);
1986    texture->setFilter(pureTranslate ? GL_NEAREST : getFilter(paint), true);
1987
1988    const float x = (int) floorf(bounds.left + 0.5f);
1989    const float y = (int) floorf(bounds.top + 0.5f);
1990    if (CC_UNLIKELY(bitmap->config() == SkBitmap::kA8_Config)) {
1991        drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
1992                texture->id, paint, &vertices[0].x, &vertices[0].u,
1993                GL_TRIANGLES, bitmapCount * 6, true,
1994                kModelViewMode_Translate, false);
1995    } else {
1996        drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
1997                texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u,
1998                GL_TRIANGLES, bitmapCount * 6, false, true, 0,
1999                kModelViewMode_Translate, false);
2000    }
2001
2002    return DrawGlInfo::kStatusDrew;
2003}
2004
2005status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, float left, float top,
2006        const SkPaint* paint) {
2007    const float right = left + bitmap->width();
2008    const float bottom = top + bitmap->height();
2009
2010    if (quickRejectSetupScissor(left, top, right, bottom)) {
2011        return DrawGlInfo::kStatusDone;
2012    }
2013
2014    mCaches.activeTexture(0);
2015    Texture* texture = getTexture(bitmap);
2016    if (!texture) return DrawGlInfo::kStatusDone;
2017    const AutoTexture autoCleanup(texture);
2018
2019    if (CC_UNLIKELY(bitmap->config() == SkBitmap::kA8_Config)) {
2020        drawAlphaBitmap(texture, left, top, paint);
2021    } else {
2022        drawTextureRect(left, top, right, bottom, texture, paint);
2023    }
2024
2025    return DrawGlInfo::kStatusDrew;
2026}
2027
2028status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkMatrix* matrix,
2029        const SkPaint* paint) {
2030    Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
2031    const mat4 transform(*matrix);
2032    transform.mapRect(r);
2033
2034    if (quickRejectSetupScissor(r.left, r.top, r.right, r.bottom)) {
2035        return DrawGlInfo::kStatusDone;
2036    }
2037
2038    mCaches.activeTexture(0);
2039    Texture* texture = getTexture(bitmap);
2040    if (!texture) return DrawGlInfo::kStatusDone;
2041    const AutoTexture autoCleanup(texture);
2042
2043    // This could be done in a cheaper way, all we need is pass the matrix
2044    // to the vertex shader. The save/restore is a bit overkill.
2045    save(SkCanvas::kMatrix_SaveFlag);
2046    concatMatrix(matrix);
2047    if (CC_UNLIKELY(bitmap->config() == SkBitmap::kA8_Config)) {
2048        drawAlphaBitmap(texture, 0.0f, 0.0f, paint);
2049    } else {
2050        drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
2051    }
2052    restore();
2053
2054    return DrawGlInfo::kStatusDrew;
2055}
2056
2057status_t OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, float left, float top,
2058        const SkPaint* paint) {
2059    const float right = left + bitmap->width();
2060    const float bottom = top + bitmap->height();
2061
2062    if (quickRejectSetupScissor(left, top, right, bottom)) {
2063        return DrawGlInfo::kStatusDone;
2064    }
2065
2066    mCaches.activeTexture(0);
2067    Texture* texture = mCaches.textureCache.getTransient(bitmap);
2068    const AutoTexture autoCleanup(texture);
2069
2070    if (CC_UNLIKELY(bitmap->config() == SkBitmap::kA8_Config)) {
2071        drawAlphaBitmap(texture, left, top, paint);
2072    } else {
2073        drawTextureRect(left, top, right, bottom, texture, paint);
2074    }
2075
2076    return DrawGlInfo::kStatusDrew;
2077}
2078
2079status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
2080        const float* vertices, const int* colors, const SkPaint* paint) {
2081    if (!vertices || currentSnapshot()->isIgnored()) {
2082        return DrawGlInfo::kStatusDone;
2083    }
2084
2085    // TODO: use quickReject on bounds from vertices
2086    mCaches.enableScissor();
2087
2088    float left = FLT_MAX;
2089    float top = FLT_MAX;
2090    float right = FLT_MIN;
2091    float bottom = FLT_MIN;
2092
2093    const uint32_t count = meshWidth * meshHeight * 6;
2094
2095    Vector<ColorTextureVertex> mesh; // TODO: use C++11 unique_ptr
2096    mesh.setCapacity(count);
2097    ColorTextureVertex* vertex = mesh.editArray();
2098
2099    bool cleanupColors = false;
2100    if (!colors) {
2101        uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
2102        int* newColors = new int[colorsCount];
2103        memset(newColors, 0xff, colorsCount * sizeof(int));
2104        colors = newColors;
2105        cleanupColors = true;
2106    }
2107
2108    mCaches.activeTexture(0);
2109    Texture* texture = mCaches.assetAtlas.getEntryTexture(bitmap);
2110    const UvMapper& mapper(getMapper(texture));
2111
2112    for (int32_t y = 0; y < meshHeight; y++) {
2113        for (int32_t x = 0; x < meshWidth; x++) {
2114            uint32_t i = (y * (meshWidth + 1) + x) * 2;
2115
2116            float u1 = float(x) / meshWidth;
2117            float u2 = float(x + 1) / meshWidth;
2118            float v1 = float(y) / meshHeight;
2119            float v2 = float(y + 1) / meshHeight;
2120
2121            mapper.map(u1, v1, u2, v2);
2122
2123            int ax = i + (meshWidth + 1) * 2;
2124            int ay = ax + 1;
2125            int bx = i;
2126            int by = bx + 1;
2127            int cx = i + 2;
2128            int cy = cx + 1;
2129            int dx = i + (meshWidth + 1) * 2 + 2;
2130            int dy = dx + 1;
2131
2132            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2133            ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
2134            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
2135
2136            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2137            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
2138            ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
2139
2140            left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
2141            top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
2142            right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
2143            bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
2144        }
2145    }
2146
2147    if (quickRejectSetupScissor(left, top, right, bottom)) {
2148        if (cleanupColors) delete[] colors;
2149        return DrawGlInfo::kStatusDone;
2150    }
2151
2152    if (!texture) {
2153        texture = mCaches.textureCache.get(bitmap);
2154        if (!texture) {
2155            if (cleanupColors) delete[] colors;
2156            return DrawGlInfo::kStatusDone;
2157        }
2158    }
2159    const AutoTexture autoCleanup(texture);
2160
2161    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2162    texture->setFilter(getFilter(paint), true);
2163
2164    int alpha;
2165    SkXfermode::Mode mode;
2166    getAlphaAndMode(paint, &alpha, &mode);
2167
2168    float a = alpha / 255.0f;
2169
2170    if (hasLayer()) {
2171        dirtyLayer(left, top, right, bottom, *currentTransform());
2172    }
2173
2174    setupDraw();
2175    setupDrawWithTextureAndColor();
2176    setupDrawColor(a, a, a, a);
2177    setupDrawColorFilter(getColorFilter(paint));
2178    setupDrawBlending(paint, true);
2179    setupDrawProgram();
2180    setupDrawDirtyRegionsDisabled();
2181    setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f);
2182    setupDrawTexture(texture->id);
2183    setupDrawPureColorUniforms();
2184    setupDrawColorFilterUniforms(getColorFilter(paint));
2185    setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
2186
2187    glDrawArrays(GL_TRIANGLES, 0, count);
2188
2189    int slot = mCaches.currentProgram->getAttrib("colors");
2190    if (slot >= 0) {
2191        glDisableVertexAttribArray(slot);
2192    }
2193
2194    if (cleanupColors) delete[] colors;
2195
2196    return DrawGlInfo::kStatusDrew;
2197}
2198
2199status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
2200         float srcLeft, float srcTop, float srcRight, float srcBottom,
2201         float dstLeft, float dstTop, float dstRight, float dstBottom,
2202         const SkPaint* paint) {
2203    if (quickRejectSetupScissor(dstLeft, dstTop, dstRight, dstBottom)) {
2204        return DrawGlInfo::kStatusDone;
2205    }
2206
2207    mCaches.activeTexture(0);
2208    Texture* texture = getTexture(bitmap);
2209    if (!texture) return DrawGlInfo::kStatusDone;
2210    const AutoTexture autoCleanup(texture);
2211
2212    const float width = texture->width;
2213    const float height = texture->height;
2214
2215    float u1 = fmax(0.0f, srcLeft / width);
2216    float v1 = fmax(0.0f, srcTop / height);
2217    float u2 = fmin(1.0f, srcRight / width);
2218    float v2 = fmin(1.0f, srcBottom / height);
2219
2220    getMapper(texture).map(u1, v1, u2, v2);
2221
2222    mCaches.unbindMeshBuffer();
2223    resetDrawTextureTexCoords(u1, v1, u2, v2);
2224
2225    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2226
2227    float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
2228    float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);
2229
2230    bool scaled = scaleX != 1.0f || scaleY != 1.0f;
2231    // Apply a scale transform on the canvas only when a shader is in use
2232    // Skia handles the ratio between the dst and src rects as a scale factor
2233    // when a shader is set
2234    bool useScaleTransform = mDrawModifiers.mShader && scaled;
2235    bool ignoreTransform = false;
2236
2237    if (CC_LIKELY(currentTransform()->isPureTranslate() && !useScaleTransform)) {
2238        float x = (int) floorf(dstLeft + currentTransform()->getTranslateX() + 0.5f);
2239        float y = (int) floorf(dstTop + currentTransform()->getTranslateY() + 0.5f);
2240
2241        dstRight = x + (dstRight - dstLeft);
2242        dstBottom = y + (dstBottom - dstTop);
2243
2244        dstLeft = x;
2245        dstTop = y;
2246
2247        texture->setFilter(scaled ? getFilter(paint) : GL_NEAREST, true);
2248        ignoreTransform = true;
2249    } else {
2250        texture->setFilter(getFilter(paint), true);
2251    }
2252
2253    if (CC_UNLIKELY(useScaleTransform)) {
2254        save(SkCanvas::kMatrix_SaveFlag);
2255        translate(dstLeft, dstTop);
2256        scale(scaleX, scaleY);
2257
2258        dstLeft = 0.0f;
2259        dstTop = 0.0f;
2260
2261        dstRight = srcRight - srcLeft;
2262        dstBottom = srcBottom - srcTop;
2263    }
2264
2265    if (CC_UNLIKELY(bitmap->config() == SkBitmap::kA8_Config)) {
2266        drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
2267                texture->id, paint,
2268                &mMeshVertices[0].x, &mMeshVertices[0].u,
2269                GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
2270    } else {
2271        drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
2272                texture->id, paint, texture->blend,
2273                &mMeshVertices[0].x, &mMeshVertices[0].u,
2274                GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
2275    }
2276
2277    if (CC_UNLIKELY(useScaleTransform)) {
2278        restore();
2279    }
2280
2281    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
2282
2283    return DrawGlInfo::kStatusDrew;
2284}
2285
2286status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
2287        float left, float top, float right, float bottom, const SkPaint* paint) {
2288    if (quickRejectSetupScissor(left, top, right, bottom)) {
2289        return DrawGlInfo::kStatusDone;
2290    }
2291
2292    AssetAtlas::Entry* entry = mCaches.assetAtlas.getEntry(bitmap);
2293    const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
2294            right - left, bottom - top, patch);
2295
2296    return drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
2297}
2298
2299status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
2300        AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
2301        const SkPaint* paint) {
2302    if (quickRejectSetupScissor(left, top, right, bottom)) {
2303        return DrawGlInfo::kStatusDone;
2304    }
2305
2306    if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
2307        mCaches.activeTexture(0);
2308        Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2309        if (!texture) return DrawGlInfo::kStatusDone;
2310        const AutoTexture autoCleanup(texture);
2311
2312        texture->setWrap(GL_CLAMP_TO_EDGE, true);
2313        texture->setFilter(GL_LINEAR, true);
2314
2315        const bool pureTranslate = currentTransform()->isPureTranslate();
2316        // Mark the current layer dirty where we are going to draw the patch
2317        if (hasLayer() && mesh->hasEmptyQuads) {
2318            const float offsetX = left + currentTransform()->getTranslateX();
2319            const float offsetY = top + currentTransform()->getTranslateY();
2320            const size_t count = mesh->quads.size();
2321            for (size_t i = 0; i < count; i++) {
2322                const Rect& bounds = mesh->quads.itemAt(i);
2323                if (CC_LIKELY(pureTranslate)) {
2324                    const float x = (int) floorf(bounds.left + offsetX + 0.5f);
2325                    const float y = (int) floorf(bounds.top + offsetY + 0.5f);
2326                    dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
2327                } else {
2328                    dirtyLayer(left + bounds.left, top + bounds.top,
2329                            left + bounds.right, top + bounds.bottom, *currentTransform());
2330                }
2331            }
2332        }
2333
2334        bool ignoreTransform = false;
2335        if (CC_LIKELY(pureTranslate)) {
2336            const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
2337            const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
2338
2339            right = x + right - left;
2340            bottom = y + bottom - top;
2341            left = x;
2342            top = y;
2343            ignoreTransform = true;
2344        }
2345        drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
2346                texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
2347                GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
2348                mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
2349    }
2350
2351    return DrawGlInfo::kStatusDrew;
2352}
2353
2354/**
2355 * Important note: this method is intended to draw batches of 9-patch objects and
2356 * will not set the scissor enable or dirty the current layer, if any.
2357 * The caller is responsible for properly dirtying the current layer.
2358 */
2359status_t OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
2360        TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) {
2361    mCaches.activeTexture(0);
2362    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2363    if (!texture) return DrawGlInfo::kStatusDone;
2364    const AutoTexture autoCleanup(texture);
2365
2366    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2367    texture->setFilter(GL_LINEAR, true);
2368
2369    drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint,
2370            texture->blend, &vertices[0].x, &vertices[0].u,
2371            GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false);
2372
2373    return DrawGlInfo::kStatusDrew;
2374}
2375
2376status_t OpenGLRenderer::drawVertexBuffer(VertexBufferMode mode,
2377        const VertexBuffer& vertexBuffer, const SkPaint* paint, bool useOffset) {
2378    // not missing call to quickReject/dirtyLayer, always done at a higher level
2379    if (!vertexBuffer.getVertexCount()) {
2380        // no vertices to draw
2381        return DrawGlInfo::kStatusDone;
2382    }
2383
2384    int color = paint->getColor();
2385    bool isAA = paint->isAntiAlias();
2386
2387    setupDraw();
2388    setupDrawNoTexture();
2389    if (isAA) setupDrawAA();
2390    setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
2391    setupDrawColorFilter(getColorFilter(paint));
2392    setupDrawShader();
2393    setupDrawBlending(paint, isAA);
2394    setupDrawProgram();
2395    setupDrawModelView(kModelViewMode_Translate, useOffset, 0, 0, 0, 0);
2396    setupDrawColorUniforms();
2397    setupDrawColorFilterUniforms(getColorFilter(paint));
2398    setupDrawShaderUniforms();
2399
2400    const void* vertices = vertexBuffer.getBuffer();
2401    bool force = mCaches.unbindMeshBuffer();
2402    mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
2403    mCaches.resetTexCoordsVertexPointer();
2404
2405
2406    int alphaSlot = -1;
2407    if (isAA) {
2408        void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
2409        alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
2410        // TODO: avoid enable/disable in back to back uses of the alpha attribute
2411        glEnableVertexAttribArray(alphaSlot);
2412        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
2413    }
2414
2415    if (mode == kVertexBufferMode_Standard) {
2416        mCaches.unbindIndicesBuffer();
2417        glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
2418    } else if (mode == kVertexBufferMode_OnePolyRingShadow) {
2419        mCaches.bindShadowIndicesBuffer();
2420        glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
2421    } else if (mode == kVertexBufferMode_TwoPolyRingShadow) {
2422        mCaches.bindShadowIndicesBuffer();
2423        glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
2424    }
2425
2426    if (isAA) {
2427        glDisableVertexAttribArray(alphaSlot);
2428    }
2429
2430    return DrawGlInfo::kStatusDrew;
2431}
2432
2433/**
2434 * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
2435 * that of AA lines in the drawLines() function.  We expand the convex path by a half pixel in
2436 * screen space in all directions. However, instead of using a fragment shader to compute the
2437 * translucency of the color from its position, we simply use a varying parameter to define how far
2438 * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
2439 *
2440 * Doesn't yet support joins, caps, or path effects.
2441 */
2442status_t OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
2443    VertexBuffer vertexBuffer;
2444    // TODO: try clipping large paths to viewport
2445    PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
2446
2447    if (hasLayer()) {
2448        SkRect bounds = path.getBounds();
2449        PathTessellator::expandBoundsForStroke(bounds, paint);
2450        dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
2451    }
2452
2453    return drawVertexBuffer(kVertexBufferMode_Standard, vertexBuffer, paint);
2454}
2455
2456/**
2457 * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
2458 * and additional geometry for defining an alpha slope perimeter.
2459 *
2460 * Using GL_LINES can be difficult because the rasterization rules for those lines produces some
2461 * unexpected results, and may vary between hardware devices. Previously we used a varying-base
2462 * in-shader alpha region, but found it to be taxing on some GPUs.
2463 *
2464 * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
2465 * memory transfer by removing need for degenerate vertices.
2466 */
2467status_t OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
2468    if (currentSnapshot()->isIgnored() || count < 4) return DrawGlInfo::kStatusDone;
2469
2470    count &= ~0x3; // round down to nearest four
2471
2472    VertexBuffer buffer;
2473    SkRect bounds;
2474    PathTessellator::tessellateLines(points, count, paint, *currentTransform(), bounds, buffer);
2475
2476    // can't pass paint, since style would be checked for outset. outset done by tessellation.
2477    if (quickRejectSetupScissor(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom)) {
2478        return DrawGlInfo::kStatusDone;
2479    }
2480
2481    dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
2482
2483    bool useOffset = !paint->isAntiAlias();
2484    return drawVertexBuffer(kVertexBufferMode_Standard, buffer, paint, useOffset);
2485}
2486
2487status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
2488    if (currentSnapshot()->isIgnored() || count < 2) return DrawGlInfo::kStatusDone;
2489
2490    count &= ~0x1; // round down to nearest two
2491
2492    VertexBuffer buffer;
2493    SkRect bounds;
2494    PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), bounds, buffer);
2495
2496    // can't pass paint, since style would be checked for outset. outset done by tessellation.
2497    if (quickRejectSetupScissor(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom)) {
2498        return DrawGlInfo::kStatusDone;
2499    }
2500
2501    dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
2502
2503    bool useOffset = !paint->isAntiAlias();
2504    return drawVertexBuffer(kVertexBufferMode_Standard, buffer, paint, useOffset);
2505}
2506
2507status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
2508    // No need to check against the clip, we fill the clip region
2509    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
2510
2511    Rect clip(*currentClipRect());
2512    clip.snapToPixelBoundaries();
2513
2514    SkPaint paint;
2515    paint.setColor(color);
2516    paint.setXfermodeMode(mode);
2517
2518    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
2519
2520    return DrawGlInfo::kStatusDrew;
2521}
2522
2523status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
2524        const SkPaint* paint) {
2525    if (!texture) return DrawGlInfo::kStatusDone;
2526    const AutoTexture autoCleanup(texture);
2527
2528    const float x = left + texture->left - texture->offset;
2529    const float y = top + texture->top - texture->offset;
2530
2531    drawPathTexture(texture, x, y, paint);
2532
2533    return DrawGlInfo::kStatusDrew;
2534}
2535
2536status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
2537        float rx, float ry, const SkPaint* p) {
2538    if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
2539            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
2540        return DrawGlInfo::kStatusDone;
2541    }
2542
2543    if (p->getPathEffect() != 0) {
2544        mCaches.activeTexture(0);
2545        const PathTexture* texture = mCaches.pathCache.getRoundRect(
2546                right - left, bottom - top, rx, ry, p);
2547        return drawShape(left, top, texture, p);
2548    }
2549
2550    SkPath path;
2551    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2552    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2553        float outset = p->getStrokeWidth() / 2;
2554        rect.outset(outset, outset);
2555        rx += outset;
2556        ry += outset;
2557    }
2558    path.addRoundRect(rect, rx, ry);
2559    return drawConvexPath(path, p);
2560}
2561
2562status_t OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
2563    if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(x - radius, y - radius,
2564            x + radius, y + radius, p) ||
2565            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
2566        return DrawGlInfo::kStatusDone;
2567    }
2568    if (p->getPathEffect() != 0) {
2569        mCaches.activeTexture(0);
2570        const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
2571        return drawShape(x - radius, y - radius, texture, p);
2572    }
2573
2574    SkPath path;
2575    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2576        path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
2577    } else {
2578        path.addCircle(x, y, radius);
2579    }
2580    return drawConvexPath(path, p);
2581}
2582
2583status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
2584        const SkPaint* p) {
2585    if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
2586            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
2587        return DrawGlInfo::kStatusDone;
2588    }
2589
2590    if (p->getPathEffect() != 0) {
2591        mCaches.activeTexture(0);
2592        const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
2593        return drawShape(left, top, texture, p);
2594    }
2595
2596    SkPath path;
2597    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2598    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2599        rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2600    }
2601    path.addOval(rect);
2602    return drawConvexPath(path, p);
2603}
2604
2605status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
2606        float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
2607    if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
2608            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
2609        return DrawGlInfo::kStatusDone;
2610    }
2611
2612    if (fabs(sweepAngle) >= 360.0f) {
2613        return drawOval(left, top, right, bottom, p);
2614    }
2615
2616    // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
2617    if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) {
2618        mCaches.activeTexture(0);
2619        const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
2620                startAngle, sweepAngle, useCenter, p);
2621        return drawShape(left, top, texture, p);
2622    }
2623
2624    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2625    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2626        rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2627    }
2628
2629    SkPath path;
2630    if (useCenter) {
2631        path.moveTo(rect.centerX(), rect.centerY());
2632    }
2633    path.arcTo(rect, startAngle, sweepAngle, !useCenter);
2634    if (useCenter) {
2635        path.close();
2636    }
2637    return drawConvexPath(path, p);
2638}
2639
2640// See SkPaintDefaults.h
2641#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
2642
2643status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
2644        const SkPaint* p) {
2645    if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
2646            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
2647        return DrawGlInfo::kStatusDone;
2648    }
2649
2650    if (p->getStyle() != SkPaint::kFill_Style) {
2651        // only fill style is supported by drawConvexPath, since others have to handle joins
2652        if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join ||
2653                p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
2654            mCaches.activeTexture(0);
2655            const PathTexture* texture =
2656                    mCaches.pathCache.getRect(right - left, bottom - top, p);
2657            return drawShape(left, top, texture, p);
2658        }
2659
2660        SkPath path;
2661        SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2662        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2663            rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2664        }
2665        path.addRect(rect);
2666        return drawConvexPath(path, p);
2667    }
2668
2669    if (p->isAntiAlias() && !currentTransform()->isSimple()) {
2670        SkPath path;
2671        path.addRect(left, top, right, bottom);
2672        return drawConvexPath(path, p);
2673    } else {
2674        drawColorRect(left, top, right, bottom, p);
2675        return DrawGlInfo::kStatusDrew;
2676    }
2677}
2678
2679void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
2680        int bytesCount, int count, const float* positions,
2681        FontRenderer& fontRenderer, int alpha, float x, float y) {
2682    mCaches.activeTexture(0);
2683
2684    // NOTE: The drop shadow will not perform gamma correction
2685    //       if shader-based correction is enabled
2686    mCaches.dropShadowCache.setFontRenderer(fontRenderer);
2687    const ShadowTexture* shadow = mCaches.dropShadowCache.get(
2688            paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
2689    // If the drop shadow exceeds the max texture size or couldn't be
2690    // allocated, skip drawing
2691    if (!shadow) return;
2692    const AutoTexture autoCleanup(shadow);
2693
2694    const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
2695    const float sy = y - shadow->top + mDrawModifiers.mShadowDy;
2696
2697    const int shadowAlpha = ((mDrawModifiers.mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
2698    int shadowColor = mDrawModifiers.mShadowColor;
2699    if (mDrawModifiers.mShader) {
2700        shadowColor = 0xffffffff;
2701    }
2702
2703    setupDraw();
2704    setupDrawWithTexture(true);
2705    setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
2706    setupDrawColorFilter(getColorFilter(paint));
2707    setupDrawShader();
2708    setupDrawBlending(paint, true);
2709    setupDrawProgram();
2710    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
2711            sx, sy, sx + shadow->width, sy + shadow->height);
2712    setupDrawTexture(shadow->id);
2713    setupDrawPureColorUniforms();
2714    setupDrawColorFilterUniforms(getColorFilter(paint));
2715    setupDrawShaderUniforms();
2716    setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
2717
2718    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
2719}
2720
2721bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
2722    float alpha = (mDrawModifiers.mHasShadow ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
2723    return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
2724}
2725
2726status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
2727        const float* positions, const SkPaint* paint) {
2728    if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
2729        return DrawGlInfo::kStatusDone;
2730    }
2731
2732    // NOTE: Skia does not support perspective transform on drawPosText yet
2733    if (!currentTransform()->isSimple()) {
2734        return DrawGlInfo::kStatusDone;
2735    }
2736
2737    mCaches.enableScissor();
2738
2739    float x = 0.0f;
2740    float y = 0.0f;
2741    const bool pureTranslate = currentTransform()->isPureTranslate();
2742    if (pureTranslate) {
2743        x = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
2744        y = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
2745    }
2746
2747    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2748    fontRenderer.setFont(paint, mat4::identity());
2749
2750    int alpha;
2751    SkXfermode::Mode mode;
2752    getAlphaAndMode(paint, &alpha, &mode);
2753
2754    if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
2755        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
2756                alpha, 0.0f, 0.0f);
2757    }
2758
2759    // Pick the appropriate texture filtering
2760    bool linearFilter = currentTransform()->changesBounds();
2761    if (pureTranslate && !linearFilter) {
2762        linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2763    }
2764    fontRenderer.setTextureFiltering(linearFilter);
2765
2766    const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
2767    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2768
2769    const bool hasActiveLayer = hasLayer();
2770
2771    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2772    if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2773            positions, hasActiveLayer ? &bounds : NULL, &functor)) {
2774        if (hasActiveLayer) {
2775            if (!pureTranslate) {
2776                currentTransform()->mapRect(bounds);
2777            }
2778            dirtyLayerUnchecked(bounds, getRegion());
2779        }
2780    }
2781
2782    return DrawGlInfo::kStatusDrew;
2783}
2784
2785mat4 OpenGLRenderer::findBestFontTransform(const mat4& transform) const {
2786    mat4 fontTransform;
2787    if (CC_LIKELY(transform.isPureTranslate())) {
2788        fontTransform = mat4::identity();
2789    } else {
2790        if (CC_UNLIKELY(transform.isPerspective())) {
2791            fontTransform = mat4::identity();
2792        } else {
2793            float sx, sy;
2794            currentTransform()->decomposeScale(sx, sy);
2795            fontTransform.loadScale(sx, sy, 1.0f);
2796        }
2797    }
2798    return fontTransform;
2799}
2800
2801status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
2802        const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
2803        DrawOpMode drawOpMode) {
2804
2805    if (drawOpMode == kDrawOpMode_Immediate) {
2806        // The checks for corner-case ignorable text and quick rejection is only done for immediate
2807        // drawing as ops from DeferredDisplayList are already filtered for these
2808        if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint) ||
2809                quickRejectSetupScissor(bounds)) {
2810            return DrawGlInfo::kStatusDone;
2811        }
2812    }
2813
2814    const float oldX = x;
2815    const float oldY = y;
2816
2817    const mat4& transform = *currentTransform();
2818    const bool pureTranslate = transform.isPureTranslate();
2819
2820    if (CC_LIKELY(pureTranslate)) {
2821        x = (int) floorf(x + transform.getTranslateX() + 0.5f);
2822        y = (int) floorf(y + transform.getTranslateY() + 0.5f);
2823    }
2824
2825    int alpha;
2826    SkXfermode::Mode mode;
2827    getAlphaAndMode(paint, &alpha, &mode);
2828
2829    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2830
2831    if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
2832        fontRenderer.setFont(paint, mat4::identity());
2833        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
2834                alpha, oldX, oldY);
2835    }
2836
2837    const bool hasActiveLayer = hasLayer();
2838
2839    // We only pass a partial transform to the font renderer. That partial
2840    // matrix defines how glyphs are rasterized. Typically we want glyphs
2841    // to be rasterized at their final size on screen, which means the partial
2842    // matrix needs to take the scale factor into account.
2843    // When a partial matrix is used to transform glyphs during rasterization,
2844    // the mesh is generated with the inverse transform (in the case of scale,
2845    // the mesh is generated at 1.0 / scale for instance.) This allows us to
2846    // apply the full transform matrix at draw time in the vertex shader.
2847    // Applying the full matrix in the shader is the easiest way to handle
2848    // rotation and perspective and allows us to always generated quads in the
2849    // font renderer which greatly simplifies the code, clipping in particular.
2850    mat4 fontTransform = findBestFontTransform(transform);
2851    fontRenderer.setFont(paint, fontTransform);
2852
2853    // Pick the appropriate texture filtering
2854    bool linearFilter = !pureTranslate || fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2855    fontRenderer.setTextureFiltering(linearFilter);
2856
2857    // TODO: Implement better clipping for scaled/rotated text
2858    const Rect* clip = !pureTranslate ? NULL : currentClipRect();
2859    Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2860
2861    bool status;
2862    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2863
2864    // don't call issuedrawcommand, do it at end of batch
2865    bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
2866    if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
2867        SkPaint paintCopy(*paint);
2868        paintCopy.setTextAlign(SkPaint::kLeft_Align);
2869        status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
2870                positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
2871    } else {
2872        status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2873                positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
2874    }
2875
2876    if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
2877        if (!pureTranslate) {
2878            transform.mapRect(layerBounds);
2879        }
2880        dirtyLayerUnchecked(layerBounds, getRegion());
2881    }
2882
2883    drawTextDecorations(totalAdvance, oldX, oldY, paint);
2884
2885    return DrawGlInfo::kStatusDrew;
2886}
2887
2888status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
2889        const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
2890    if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
2891        return DrawGlInfo::kStatusDone;
2892    }
2893
2894    // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
2895    mCaches.enableScissor();
2896
2897    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2898    fontRenderer.setFont(paint, mat4::identity());
2899    fontRenderer.setTextureFiltering(true);
2900
2901    int alpha;
2902    SkXfermode::Mode mode;
2903    getAlphaAndMode(paint, &alpha, &mode);
2904    TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
2905
2906    const Rect* clip = &mSnapshot->getLocalClip();
2907    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2908
2909    const bool hasActiveLayer = hasLayer();
2910
2911    if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
2912            hOffset, vOffset, hasActiveLayer ? &bounds : NULL, &functor)) {
2913        if (hasActiveLayer) {
2914            currentTransform()->mapRect(bounds);
2915            dirtyLayerUnchecked(bounds, getRegion());
2916        }
2917    }
2918
2919    return DrawGlInfo::kStatusDrew;
2920}
2921
2922status_t OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
2923    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
2924
2925    mCaches.activeTexture(0);
2926
2927    const PathTexture* texture = mCaches.pathCache.get(path, paint);
2928    if (!texture) return DrawGlInfo::kStatusDone;
2929    const AutoTexture autoCleanup(texture);
2930
2931    const float x = texture->left - texture->offset;
2932    const float y = texture->top - texture->offset;
2933
2934    drawPathTexture(texture, x, y, paint);
2935
2936    return DrawGlInfo::kStatusDrew;
2937}
2938
2939status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
2940    if (!layer) {
2941        return DrawGlInfo::kStatusDone;
2942    }
2943
2944    mat4* transform = NULL;
2945    if (layer->isTextureLayer()) {
2946        transform = &layer->getTransform();
2947        if (!transform->isIdentity()) {
2948            save(0);
2949            concatMatrix(*transform);
2950        }
2951    }
2952
2953    bool clipRequired = false;
2954    const bool rejected = calculateQuickRejectForScissor(x, y,
2955            x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, false);
2956
2957    if (rejected) {
2958        if (transform && !transform->isIdentity()) {
2959            restore();
2960        }
2961        return DrawGlInfo::kStatusDone;
2962    }
2963
2964    updateLayer(layer, true);
2965
2966    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
2967    mCaches.activeTexture(0);
2968
2969    if (CC_LIKELY(!layer->region.isEmpty())) {
2970        if (layer->region.isRect()) {
2971            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
2972                    composeLayerRect(layer, layer->regionRect));
2973        } else if (layer->mesh) {
2974
2975            const float a = getLayerAlpha(layer);
2976            setupDraw();
2977            setupDrawWithTexture();
2978            setupDrawColor(a, a, a, a);
2979            setupDrawColorFilter(layer->getColorFilter());
2980            setupDrawBlending(layer);
2981            setupDrawProgram();
2982            setupDrawPureColorUniforms();
2983            setupDrawColorFilterUniforms(layer->getColorFilter());
2984            setupDrawTexture(layer->getTexture());
2985            if (CC_LIKELY(currentTransform()->isPureTranslate())) {
2986                int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
2987                int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
2988
2989                layer->setFilter(GL_NEAREST);
2990                setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
2991                        tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
2992            } else {
2993                layer->setFilter(GL_LINEAR);
2994                setupDrawModelView(kModelViewMode_Translate, false, x, y,
2995                        x + layer->layer.getWidth(), y + layer->layer.getHeight());
2996            }
2997
2998            TextureVertex* mesh = &layer->mesh[0];
2999            GLsizei elementsCount = layer->meshElementCount;
3000
3001            while (elementsCount > 0) {
3002                GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
3003
3004                setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
3005                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
3006                        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL));
3007
3008                elementsCount -= drawCount;
3009                // Though there are 4 vertices in a quad, we use 6 indices per
3010                // quad to draw with GL_TRIANGLES
3011                mesh += (drawCount / 6) * 4;
3012            }
3013
3014#if DEBUG_LAYERS_AS_REGIONS
3015            drawRegionRectsDebug(layer->region);
3016#endif
3017        }
3018
3019        if (layer->debugDrawUpdate) {
3020            layer->debugDrawUpdate = false;
3021
3022            SkPaint paint;
3023            paint.setColor(0x7f00ff00);
3024            drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
3025        }
3026    }
3027    layer->hasDrawnSinceUpdate = true;
3028
3029    if (transform && !transform->isIdentity()) {
3030        restore();
3031    }
3032
3033    return DrawGlInfo::kStatusDrew;
3034}
3035
3036///////////////////////////////////////////////////////////////////////////////
3037// Shaders
3038///////////////////////////////////////////////////////////////////////////////
3039
3040void OpenGLRenderer::resetShader() {
3041    mDrawModifiers.mShader = NULL;
3042}
3043
3044void OpenGLRenderer::setupShader(SkiaShader* shader) {
3045    mDrawModifiers.mShader = shader;
3046    if (mDrawModifiers.mShader) {
3047        mDrawModifiers.mShader->setCaches(mCaches);
3048    }
3049}
3050
3051///////////////////////////////////////////////////////////////////////////////
3052// Drop shadow
3053///////////////////////////////////////////////////////////////////////////////
3054
3055void OpenGLRenderer::resetShadow() {
3056    mDrawModifiers.mHasShadow = false;
3057}
3058
3059void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
3060    mDrawModifiers.mHasShadow = true;
3061    mDrawModifiers.mShadowRadius = radius;
3062    mDrawModifiers.mShadowDx = dx;
3063    mDrawModifiers.mShadowDy = dy;
3064    mDrawModifiers.mShadowColor = color;
3065}
3066
3067///////////////////////////////////////////////////////////////////////////////
3068// Draw filters
3069///////////////////////////////////////////////////////////////////////////////
3070
3071void OpenGLRenderer::resetPaintFilter() {
3072    // when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier
3073    // comparison, see MergingDrawBatch::canMergeWith
3074    mDrawModifiers.mHasDrawFilter = false;
3075    mDrawModifiers.mPaintFilterClearBits = 0;
3076    mDrawModifiers.mPaintFilterSetBits = 0;
3077}
3078
3079void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
3080    mDrawModifiers.mHasDrawFilter = true;
3081    mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
3082    mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
3083}
3084
3085const SkPaint* OpenGLRenderer::filterPaint(const SkPaint* paint) {
3086    if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) {
3087        return paint;
3088    }
3089
3090    uint32_t flags = paint->getFlags();
3091
3092    mFilteredPaint = *paint;
3093    mFilteredPaint.setFlags((flags & ~mDrawModifiers.mPaintFilterClearBits) |
3094            mDrawModifiers.mPaintFilterSetBits);
3095
3096    return &mFilteredPaint;
3097}
3098
3099///////////////////////////////////////////////////////////////////////////////
3100// Drawing implementation
3101///////////////////////////////////////////////////////////////////////////////
3102
3103Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) {
3104    Texture* texture = mCaches.assetAtlas.getEntryTexture(bitmap);
3105    if (!texture) {
3106        return mCaches.textureCache.get(bitmap);
3107    }
3108    return texture;
3109}
3110
3111void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
3112        float x, float y, const SkPaint* paint) {
3113    if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) {
3114        return;
3115    }
3116
3117    int alpha;
3118    SkXfermode::Mode mode;
3119    getAlphaAndMode(paint, &alpha, &mode);
3120
3121    setupDraw();
3122    setupDrawWithTexture(true);
3123    setupDrawAlpha8Color(paint->getColor(), alpha);
3124    setupDrawColorFilter(getColorFilter(paint));
3125    setupDrawShader();
3126    setupDrawBlending(paint, true);
3127    setupDrawProgram();
3128    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
3129            x, y, x + texture->width, y + texture->height);
3130    setupDrawTexture(texture->id);
3131    setupDrawPureColorUniforms();
3132    setupDrawColorFilterUniforms(getColorFilter(paint));
3133    setupDrawShaderUniforms();
3134    setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
3135
3136    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
3137}
3138
3139// Same values used by Skia
3140#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
3141#define kStdUnderline_Offset    (1.0f / 9.0f)
3142#define kStdUnderline_Thickness (1.0f / 18.0f)
3143
3144void OpenGLRenderer::drawTextDecorations(float underlineWidth, float x, float y,
3145        const SkPaint* paint) {
3146    // Handle underline and strike-through
3147    uint32_t flags = paint->getFlags();
3148    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
3149        SkPaint paintCopy(*paint);
3150
3151        if (CC_LIKELY(underlineWidth > 0.0f)) {
3152            const float textSize = paintCopy.getTextSize();
3153            const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
3154
3155            const float left = x;
3156            float top = 0.0f;
3157
3158            int linesCount = 0;
3159            if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
3160            if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
3161
3162            const int pointsCount = 4 * linesCount;
3163            float points[pointsCount];
3164            int currentPoint = 0;
3165
3166            if (flags & SkPaint::kUnderlineText_Flag) {
3167                top = y + textSize * kStdUnderline_Offset;
3168                points[currentPoint++] = left;
3169                points[currentPoint++] = top;
3170                points[currentPoint++] = left + underlineWidth;
3171                points[currentPoint++] = top;
3172            }
3173
3174            if (flags & SkPaint::kStrikeThruText_Flag) {
3175                top = y + textSize * kStdStrikeThru_Offset;
3176                points[currentPoint++] = left;
3177                points[currentPoint++] = top;
3178                points[currentPoint++] = left + underlineWidth;
3179                points[currentPoint++] = top;
3180            }
3181
3182            paintCopy.setStrokeWidth(strokeWidth);
3183
3184            drawLines(&points[0], pointsCount, &paintCopy);
3185        }
3186    }
3187}
3188
3189status_t OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
3190    if (currentSnapshot()->isIgnored()) {
3191        return DrawGlInfo::kStatusDone;
3192    }
3193
3194    return drawColorRects(rects, count, paint, false, true, true);
3195}
3196
3197static void mapPointFakeZ(Vector3& point, const mat4& transformXY, const mat4& transformZ) {
3198    // map z coordinate with true 3d matrix
3199    point.z = transformZ.mapZ(point);
3200
3201    // map x,y coordinates with draw/Skia matrix
3202    transformXY.mapPoint(point.x, point.y);
3203}
3204
3205status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ,
3206        float casterAlpha, bool casterUnclipped, const SkPath* casterPerimeter) {
3207    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
3208
3209    // TODO: use quickRejectWithScissor. For now, always force enable scissor.
3210    mCaches.enableScissor();
3211
3212    SkPaint paint;
3213    paint.setAntiAlias(true); // want to use AlphaVertex
3214
3215    // tessellate caster outline into a 2d polygon
3216    Vector<Vertex> casterVertices2d;
3217    const float casterRefinementThresholdSquared = 20.0f; // TODO: experiment with this value
3218    PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
3219            casterRefinementThresholdSquared, casterVertices2d);
3220
3221    if (casterVertices2d.size() == 0) {
3222        // empty caster polygon computed from path
3223        return DrawGlInfo::kStatusDone;
3224    }
3225
3226    // map 2d caster poly into 3d
3227    const int casterVertexCount = casterVertices2d.size();
3228    Vector3 casterPolygon[casterVertexCount];
3229    float minZ = FLT_MAX;
3230    float maxZ = -FLT_MAX;
3231    for (int i = 0; i < casterVertexCount; i++) {
3232        const Vertex& point2d = casterVertices2d[i];
3233        casterPolygon[i] = Vector3(point2d.x, point2d.y, 0);
3234        mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ);
3235        minZ = fmin(minZ, casterPolygon[i].z);
3236        maxZ = fmax(maxZ, casterPolygon[i].z);
3237    }
3238
3239    // map the centroid of the caster into 3d
3240    Vector2 centroid =  ShadowTessellator::centroid2d(
3241            reinterpret_cast<const Vector2*>(casterVertices2d.array()),
3242            casterVertexCount);
3243    Vector3 centroid3d(centroid.x, centroid.y, 0);
3244    mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ);
3245
3246    // if the caster intersects the z=0 plane, lift it in Z so it doesn't
3247    if (minZ < SHADOW_MIN_CASTER_Z) {
3248        float casterLift = SHADOW_MIN_CASTER_Z - minZ;
3249        for (int i = 0; i < casterVertexCount; i++) {
3250            casterPolygon[i].z += casterLift;
3251        }
3252        centroid3d.z += casterLift;
3253    }
3254
3255    // Check whether we want to draw the shadow at all by checking the caster's
3256    // bounds against clip.
3257    // We only have ortho projection, so we can just ignore the Z in caster for
3258    // simple rejection calculation.
3259    Rect localClip = mSnapshot->getLocalClip();
3260    Rect casterBounds(casterPerimeter->getBounds());
3261    casterTransformXY.mapRect(casterBounds);
3262
3263    bool isCasterOpaque = (casterAlpha == 1.0f) && casterUnclipped;
3264    // draw caster's shadows
3265    if (mCaches.propertyAmbientShadowStrength > 0) {
3266        paint.setARGB(casterAlpha * mCaches.propertyAmbientShadowStrength, 0, 0, 0);
3267        VertexBuffer ambientShadowVertexBuffer;
3268        VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateAmbientShadow(
3269                isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
3270                casterBounds, localClip, maxZ, ambientShadowVertexBuffer);
3271        drawVertexBuffer(vertexBufferMode, ambientShadowVertexBuffer, &paint);
3272    }
3273
3274    if (mCaches.propertySpotShadowStrength > 0) {
3275        paint.setARGB(casterAlpha * mCaches.propertySpotShadowStrength, 0, 0, 0);
3276        VertexBuffer spotShadowVertexBuffer;
3277        Vector3 lightPosScale(mCaches.propertyLightPosXScale,
3278                mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale);
3279        VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateSpotShadow(
3280                isCasterOpaque, casterPolygon, casterVertexCount, lightPosScale,
3281                *currentTransform(), getWidth(), getHeight(), casterBounds, localClip,
3282                spotShadowVertexBuffer);
3283        drawVertexBuffer(vertexBufferMode, spotShadowVertexBuffer, &paint);
3284    }
3285
3286    return DrawGlInfo::kStatusDrew;
3287}
3288
3289status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
3290        bool ignoreTransform, bool dirty, bool clip) {
3291    if (count == 0) {
3292        return DrawGlInfo::kStatusDone;
3293    }
3294
3295    int color = paint->getColor();
3296    // If a shader is set, preserve only the alpha
3297    if (mDrawModifiers.mShader) {
3298        color |= 0x00ffffff;
3299    }
3300
3301    float left = FLT_MAX;
3302    float top = FLT_MAX;
3303    float right = FLT_MIN;
3304    float bottom = FLT_MIN;
3305
3306    Vertex mesh[count];
3307    Vertex* vertex = mesh;
3308
3309    for (int index = 0; index < count; index += 4) {
3310        float l = rects[index + 0];
3311        float t = rects[index + 1];
3312        float r = rects[index + 2];
3313        float b = rects[index + 3];
3314
3315        Vertex::set(vertex++, l, t);
3316        Vertex::set(vertex++, r, t);
3317        Vertex::set(vertex++, l, b);
3318        Vertex::set(vertex++, r, b);
3319
3320        left = fminf(left, l);
3321        top = fminf(top, t);
3322        right = fmaxf(right, r);
3323        bottom = fmaxf(bottom, b);
3324    }
3325
3326    if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
3327        return DrawGlInfo::kStatusDone;
3328    }
3329
3330    setupDraw();
3331    setupDrawNoTexture();
3332    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
3333    setupDrawShader();
3334    setupDrawColorFilter(getColorFilter(paint));
3335    setupDrawBlending(paint);
3336    setupDrawProgram();
3337    setupDrawDirtyRegionsDisabled();
3338    setupDrawModelView(kModelViewMode_Translate, false,
3339            0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
3340    setupDrawColorUniforms();
3341    setupDrawShaderUniforms();
3342    setupDrawColorFilterUniforms(getColorFilter(paint));
3343
3344    if (dirty && hasLayer()) {
3345        dirtyLayer(left, top, right, bottom, *currentTransform());
3346    }
3347
3348    issueIndexedQuadDraw(&mesh[0], count / 4);
3349
3350    return DrawGlInfo::kStatusDrew;
3351}
3352
3353void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
3354        const SkPaint* paint, bool ignoreTransform) {
3355    int color = paint->getColor();
3356    // If a shader is set, preserve only the alpha
3357    if (mDrawModifiers.mShader) {
3358        color |= 0x00ffffff;
3359    }
3360
3361    setupDraw();
3362    setupDrawNoTexture();
3363    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
3364    setupDrawShader();
3365    setupDrawColorFilter(getColorFilter(paint));
3366    setupDrawBlending(paint);
3367    setupDrawProgram();
3368    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
3369            left, top, right, bottom, ignoreTransform);
3370    setupDrawColorUniforms();
3371    setupDrawShaderUniforms(ignoreTransform);
3372    setupDrawColorFilterUniforms(getColorFilter(paint));
3373    setupDrawSimpleMesh();
3374
3375    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
3376}
3377
3378void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
3379        Texture* texture, const SkPaint* paint) {
3380    texture->setWrap(GL_CLAMP_TO_EDGE, true);
3381
3382    GLvoid* vertices = (GLvoid*) NULL;
3383    GLvoid* texCoords = (GLvoid*) gMeshTextureOffset;
3384
3385    if (texture->uvMapper) {
3386        vertices = &mMeshVertices[0].x;
3387        texCoords = &mMeshVertices[0].u;
3388
3389        Rect uvs(0.0f, 0.0f, 1.0f, 1.0f);
3390        texture->uvMapper->map(uvs);
3391
3392        resetDrawTextureTexCoords(uvs.left, uvs.top, uvs.right, uvs.bottom);
3393    }
3394
3395    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
3396        const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
3397        const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
3398
3399        texture->setFilter(GL_NEAREST, true);
3400        drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
3401                paint, texture->blend, vertices, texCoords,
3402                GL_TRIANGLE_STRIP, gMeshCount, false, true);
3403    } else {
3404        texture->setFilter(getFilter(paint), true);
3405        drawTextureMesh(left, top, right, bottom, texture->id, paint,
3406                texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
3407    }
3408
3409    if (texture->uvMapper) {
3410        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
3411    }
3412}
3413
3414void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
3415        GLuint texture, const SkPaint* paint, bool blend,
3416        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
3417        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
3418        ModelViewMode modelViewMode, bool dirty) {
3419
3420    int a;
3421    SkXfermode::Mode mode;
3422    getAlphaAndMode(paint, &a, &mode);
3423    const float alpha = a / 255.0f;
3424
3425    setupDraw();
3426    setupDrawWithTexture();
3427    setupDrawColor(alpha, alpha, alpha, alpha);
3428    setupDrawColorFilter(getColorFilter(paint));
3429    setupDrawBlending(paint, blend, swapSrcDst);
3430    setupDrawProgram();
3431    if (!dirty) setupDrawDirtyRegionsDisabled();
3432    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3433    setupDrawTexture(texture);
3434    setupDrawPureColorUniforms();
3435    setupDrawColorFilterUniforms(getColorFilter(paint));
3436    setupDrawMesh(vertices, texCoords, vbo);
3437
3438    glDrawArrays(drawMode, 0, elementsCount);
3439}
3440
3441void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
3442        GLuint texture, const SkPaint* paint, bool blend,
3443        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
3444        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
3445        ModelViewMode modelViewMode, bool dirty) {
3446
3447    int a;
3448    SkXfermode::Mode mode;
3449    getAlphaAndMode(paint, &a, &mode);
3450    const float alpha = a / 255.0f;
3451
3452    setupDraw();
3453    setupDrawWithTexture();
3454    setupDrawColor(alpha, alpha, alpha, alpha);
3455    setupDrawColorFilter(getColorFilter(paint));
3456    setupDrawBlending(paint, blend, swapSrcDst);
3457    setupDrawProgram();
3458    if (!dirty) setupDrawDirtyRegionsDisabled();
3459    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3460    setupDrawTexture(texture);
3461    setupDrawPureColorUniforms();
3462    setupDrawColorFilterUniforms(getColorFilter(paint));
3463    setupDrawMeshIndices(vertices, texCoords, vbo);
3464
3465    glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL);
3466}
3467
3468void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
3469        GLuint texture, const SkPaint* paint,
3470        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
3471        bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
3472
3473    int color = paint != NULL ? paint->getColor() : 0;
3474    int alpha;
3475    SkXfermode::Mode mode;
3476    getAlphaAndMode(paint, &alpha, &mode);
3477
3478    setupDraw();
3479    setupDrawWithTexture(true);
3480    if (paint != NULL) {
3481        setupDrawAlpha8Color(color, alpha);
3482    }
3483    setupDrawColorFilter(getColorFilter(paint));
3484    setupDrawShader();
3485    setupDrawBlending(paint, true);
3486    setupDrawProgram();
3487    if (!dirty) setupDrawDirtyRegionsDisabled();
3488    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3489    setupDrawTexture(texture);
3490    setupDrawPureColorUniforms();
3491    setupDrawColorFilterUniforms(getColorFilter(paint));
3492    setupDrawShaderUniforms(ignoreTransform);
3493    setupDrawMesh(vertices, texCoords);
3494
3495    glDrawArrays(drawMode, 0, elementsCount);
3496}
3497
3498void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
3499        ProgramDescription& description, bool swapSrcDst) {
3500    if (mCountOverdraw) {
3501        if (!mCaches.blend) glEnable(GL_BLEND);
3502        if (mCaches.lastSrcMode != GL_ONE || mCaches.lastDstMode != GL_ONE) {
3503            glBlendFunc(GL_ONE, GL_ONE);
3504        }
3505
3506        mCaches.blend = true;
3507        mCaches.lastSrcMode = GL_ONE;
3508        mCaches.lastDstMode = GL_ONE;
3509
3510        return;
3511    }
3512
3513    blend = blend || mode != SkXfermode::kSrcOver_Mode;
3514
3515    if (blend) {
3516        // These blend modes are not supported by OpenGL directly and have
3517        // to be implemented using shaders. Since the shader will perform
3518        // the blending, turn blending off here
3519        // If the blend mode cannot be implemented using shaders, fall
3520        // back to the default SrcOver blend mode instead
3521        if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
3522            if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) {
3523                description.framebufferMode = mode;
3524                description.swapSrcDst = swapSrcDst;
3525
3526                if (mCaches.blend) {
3527                    glDisable(GL_BLEND);
3528                    mCaches.blend = false;
3529                }
3530
3531                return;
3532            } else {
3533                mode = SkXfermode::kSrcOver_Mode;
3534            }
3535        }
3536
3537        if (!mCaches.blend) {
3538            glEnable(GL_BLEND);
3539        }
3540
3541        GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
3542        GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
3543
3544        if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
3545            glBlendFunc(sourceMode, destMode);
3546            mCaches.lastSrcMode = sourceMode;
3547            mCaches.lastDstMode = destMode;
3548        }
3549    } else if (mCaches.blend) {
3550        glDisable(GL_BLEND);
3551    }
3552    mCaches.blend = blend;
3553}
3554
3555bool OpenGLRenderer::useProgram(Program* program) {
3556    if (!program->isInUse()) {
3557        if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
3558        program->use();
3559        mCaches.currentProgram = program;
3560        return false;
3561    }
3562    return true;
3563}
3564
3565void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
3566    TextureVertex* v = &mMeshVertices[0];
3567    TextureVertex::setUV(v++, u1, v1);
3568    TextureVertex::setUV(v++, u2, v1);
3569    TextureVertex::setUV(v++, u1, v2);
3570    TextureVertex::setUV(v++, u2, v2);
3571}
3572
3573void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const {
3574    getAlphaAndModeDirect(paint, alpha,  mode);
3575    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
3576        // if drawing a layer, ignore the paint's alpha
3577        *alpha = mDrawModifiers.mOverrideLayerAlpha * 255;
3578    }
3579    *alpha *= currentSnapshot()->alpha;
3580}
3581
3582float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
3583    float alpha;
3584    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
3585        alpha = mDrawModifiers.mOverrideLayerAlpha;
3586    } else {
3587        alpha = layer->getAlpha() / 255.0f;
3588    }
3589    return alpha * currentSnapshot()->alpha;
3590}
3591
3592}; // namespace uirenderer
3593}; // namespace android
3594