OSDN Git Service

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