OSDN Git Service

Add orientation to configuration for layoutlib.
[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                 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
886                         bounds.left, mSnapshot->height - bounds.bottom,
887                         layer->getWidth(), layer->getHeight(), 0);
888                 layer->setEmpty(false);
889             } else {
890                 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
891                         mSnapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
892             }
893
894             // Enqueue the buffer coordinates to clear the corresponding region later
895             mLayers.push(new Rect(bounds));
896         }
897     }
898
899     return true;
900 }
901
902 bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLuint previousFbo) {
903     layer->clipRect.set(clip);
904     layer->setFbo(mCaches.fboCache.get());
905
906     mSnapshot->region = &mSnapshot->layer->region;
907     mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer |
908             Snapshot::kFlagDirtyOrtho;
909     mSnapshot->fbo = layer->getFbo();
910     mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
911     mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
912     mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
913     mSnapshot->height = bounds.getHeight();
914     mSnapshot->orthoMatrix.load(mOrthoMatrix);
915
916     endTiling();
917     debugOverdraw(false, false);
918     // Bind texture to FBO
919     glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
920     layer->bindTexture();
921
922     // Initialize the texture if needed
923     if (layer->isEmpty()) {
924         layer->allocateTexture();
925         layer->setEmpty(false);
926     }
927
928     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
929             layer->getTexture(), 0);
930
931     startTiling(mSnapshot, true);
932
933     // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
934     mCaches.enableScissor();
935     mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
936             clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
937     glClear(GL_COLOR_BUFFER_BIT);
938
939     dirtyClip();
940
941     // Change the ortho projection
942     glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
943     mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
944
945     return true;
946 }
947
948 /**
949  * Read the documentation of createLayer() before doing anything in this method.
950  */
951 void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
952     if (!current->layer) {
953         ALOGE("Attempting to compose a layer that does not exist");
954         return;
955     }
956
957     Layer* layer = current->layer;
958     const Rect& rect = layer->layer;
959     const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
960
961     if (fboLayer) {
962         endTiling();
963
964         // Detach the texture from the FBO
965         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
966
967         layer->removeFbo(false);
968
969         // Unbind current FBO and restore previous one
970         glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
971         debugOverdraw(true, false);
972
973         startTiling(previous);
974     }
975
976     if (!fboLayer && layer->getAlpha() < 255) {
977         drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
978                 layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true);
979         // Required below, composeLayerRect() will divide by 255
980         layer->setAlpha(255);
981     }
982
983     mCaches.unbindMeshBuffer();
984
985     mCaches.activeTexture(0);
986
987     // When the layer is stored in an FBO, we can save a bit of fillrate by
988     // drawing only the dirty region
989     if (fboLayer) {
990         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
991         if (layer->getColorFilter()) {
992             setupColorFilter(layer->getColorFilter());
993         }
994         composeLayerRegion(layer, rect);
995         if (layer->getColorFilter()) {
996             resetColorFilter();
997         }
998     } else if (!rect.isEmpty()) {
999         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
1000         composeLayerRect(layer, rect, true);
1001     }
1002
1003     dirtyClip();
1004
1005     // Failing to add the layer to the cache should happen only if the layer is too large
1006     if (!mCaches.layerCache.put(layer)) {
1007         LAYER_LOGD("Deleting layer");
1008         Caches::getInstance().resourceCache.decrementRefcount(layer);
1009     }
1010 }
1011
1012 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
1013     float alpha = layer->getAlpha() / 255.0f * mSnapshot->alpha;
1014
1015     setupDraw();
1016     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
1017         setupDrawWithTexture();
1018     } else {
1019         setupDrawWithExternalTexture();
1020     }
1021     setupDrawTextureTransform();
1022     setupDrawColor(alpha, alpha, alpha, alpha);
1023     setupDrawColorFilter();
1024     setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode());
1025     setupDrawProgram();
1026     setupDrawPureColorUniforms();
1027     setupDrawColorFilterUniforms();
1028     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
1029         setupDrawTexture(layer->getTexture());
1030     } else {
1031         setupDrawExternalTexture(layer->getTexture());
1032     }
1033     if (currentTransform().isPureTranslate() &&
1034             layer->getWidth() == (uint32_t) rect.getWidth() &&
1035             layer->getHeight() == (uint32_t) rect.getHeight()) {
1036         const float x = (int) floorf(rect.left + currentTransform().getTranslateX() + 0.5f);
1037         const float y = (int) floorf(rect.top + currentTransform().getTranslateY() + 0.5f);
1038
1039         layer->setFilter(GL_NEAREST);
1040         setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
1041     } else {
1042         layer->setFilter(GL_LINEAR);
1043         setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
1044     }
1045     setupDrawTextureTransformUniforms(layer->getTexTransform());
1046     setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
1047
1048     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
1049
1050     finishDrawTexture();
1051 }
1052
1053 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
1054     if (!layer->isTextureLayer()) {
1055         const Rect& texCoords = layer->texCoords;
1056         resetDrawTextureTexCoords(texCoords.left, texCoords.top,
1057                 texCoords.right, texCoords.bottom);
1058
1059         float x = rect.left;
1060         float y = rect.top;
1061         bool simpleTransform = currentTransform().isPureTranslate() &&
1062                 layer->getWidth() == (uint32_t) rect.getWidth() &&
1063                 layer->getHeight() == (uint32_t) rect.getHeight();
1064
1065         if (simpleTransform) {
1066             // When we're swapping, the layer is already in screen coordinates
1067             if (!swap) {
1068                 x = (int) floorf(rect.left + currentTransform().getTranslateX() + 0.5f);
1069                 y = (int) floorf(rect.top + currentTransform().getTranslateY() + 0.5f);
1070             }
1071
1072             layer->setFilter(GL_NEAREST, true);
1073         } else {
1074             layer->setFilter(GL_LINEAR, true);
1075         }
1076
1077         float alpha = getLayerAlpha(layer);
1078         bool blend = layer->isBlend() || alpha < 1.0f;
1079         drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
1080                 layer->getTexture(), alpha, layer->getMode(), blend,
1081                 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
1082                 GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
1083
1084         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
1085     } else {
1086         resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
1087         drawTextureLayer(layer, rect);
1088         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
1089     }
1090 }
1091
1092 /**
1093  * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
1094  * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
1095  * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
1096  * by saveLayer's restore
1097  */
1098 #define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) {                             \
1099         DRAW_COMMAND;                                                            \
1100         if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
1101             glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);                 \
1102             DRAW_COMMAND;                                                        \
1103             glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                     \
1104         }                                                                        \
1105     }
1106
1107 #define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
1108
1109 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
1110     if (layer->region.isRect()) {
1111         layer->setRegionAsRect();
1112
1113         DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
1114
1115         layer->region.clear();
1116         return;
1117     }
1118
1119     // TODO: See LayerRenderer.cpp::generateMesh() for important
1120     //       information about this implementation
1121     if (CC_LIKELY(!layer->region.isEmpty())) {
1122         size_t count;
1123         const android::Rect* rects;
1124         Region safeRegion;
1125         if (CC_LIKELY(hasRectToRectTransform())) {
1126             rects = layer->region.getArray(&count);
1127         } else {
1128             safeRegion = Region::createTJunctionFreeRegion(layer->region);
1129             rects = safeRegion.getArray(&count);
1130         }
1131
1132         const float alpha = getLayerAlpha(layer);
1133         const float texX = 1.0f / float(layer->getWidth());
1134         const float texY = 1.0f / float(layer->getHeight());
1135         const float height = rect.getHeight();
1136
1137         setupDraw();
1138
1139         // We must get (and therefore bind) the region mesh buffer
1140         // after we setup drawing in case we need to mess with the
1141         // stencil buffer in setupDraw()
1142         TextureVertex* mesh = mCaches.getRegionMesh();
1143         GLsizei numQuads = 0;
1144
1145         setupDrawWithTexture();
1146         setupDrawColor(alpha, alpha, alpha, alpha);
1147         setupDrawColorFilter();
1148         setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false);
1149         setupDrawProgram();
1150         setupDrawDirtyRegionsDisabled();
1151         setupDrawPureColorUniforms();
1152         setupDrawColorFilterUniforms();
1153         setupDrawTexture(layer->getTexture());
1154         if (currentTransform().isPureTranslate()) {
1155             const float x = (int) floorf(rect.left + currentTransform().getTranslateX() + 0.5f);
1156             const float y = (int) floorf(rect.top + currentTransform().getTranslateY() + 0.5f);
1157
1158             layer->setFilter(GL_NEAREST);
1159             setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
1160         } else {
1161             layer->setFilter(GL_LINEAR);
1162             setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
1163         }
1164         setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]);
1165
1166         for (size_t i = 0; i < count; i++) {
1167             const android::Rect* r = &rects[i];
1168
1169             const float u1 = r->left * texX;
1170             const float v1 = (height - r->top) * texY;
1171             const float u2 = r->right * texX;
1172             const float v2 = (height - r->bottom) * texY;
1173
1174             // TODO: Reject quads outside of the clip
1175             TextureVertex::set(mesh++, r->left, r->top, u1, v1);
1176             TextureVertex::set(mesh++, r->right, r->top, u2, v1);
1177             TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
1178             TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
1179
1180             numQuads++;
1181
1182             if (numQuads >= REGION_MESH_QUAD_COUNT) {
1183                 DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1184                                 GL_UNSIGNED_SHORT, NULL));
1185                 numQuads = 0;
1186                 mesh = mCaches.getRegionMesh();
1187             }
1188         }
1189
1190         if (numQuads > 0) {
1191             DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1192                             GL_UNSIGNED_SHORT, NULL));
1193         }
1194
1195         finishDrawTexture();
1196
1197 #if DEBUG_LAYERS_AS_REGIONS
1198         drawRegionRects(layer->region);
1199 #endif
1200
1201         layer->region.clear();
1202     }
1203 }
1204
1205 void OpenGLRenderer::drawRegionRects(const Region& region) {
1206 #if DEBUG_LAYERS_AS_REGIONS
1207     size_t count;
1208     const android::Rect* rects = region.getArray(&count);
1209
1210     uint32_t colors[] = {
1211             0x7fff0000, 0x7f00ff00,
1212             0x7f0000ff, 0x7fff00ff,
1213     };
1214
1215     int offset = 0;
1216     int32_t top = rects[0].top;
1217
1218     for (size_t i = 0; i < count; i++) {
1219         if (top != rects[i].top) {
1220             offset ^= 0x2;
1221             top = rects[i].top;
1222         }
1223
1224         Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
1225         drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)],
1226                 SkXfermode::kSrcOver_Mode);
1227     }
1228 #endif
1229 }
1230
1231 void OpenGLRenderer::drawRegionRects(const SkRegion& region, int color,
1232         SkXfermode::Mode mode, bool dirty) {
1233     int count = 0;
1234     Vector<float> rects;
1235
1236     SkRegion::Iterator it(region);
1237     while (!it.done()) {
1238         const SkIRect& r = it.rect();
1239         rects.push(r.fLeft);
1240         rects.push(r.fTop);
1241         rects.push(r.fRight);
1242         rects.push(r.fBottom);
1243         count += 4;
1244         it.next();
1245     }
1246
1247     drawColorRects(rects.array(), count, color, mode, true, dirty, false);
1248 }
1249
1250 void OpenGLRenderer::dirtyLayer(const float left, const float top,
1251         const float right, const float bottom, const mat4 transform) {
1252     if (hasLayer()) {
1253         Rect bounds(left, top, right, bottom);
1254         transform.mapRect(bounds);
1255         dirtyLayerUnchecked(bounds, getRegion());
1256     }
1257 }
1258
1259 void OpenGLRenderer::dirtyLayer(const float left, const float top,
1260         const float right, const float bottom) {
1261     if (hasLayer()) {
1262         Rect bounds(left, top, right, bottom);
1263         dirtyLayerUnchecked(bounds, getRegion());
1264     }
1265 }
1266
1267 void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
1268     if (bounds.intersect(*mSnapshot->clipRect)) {
1269         bounds.snapToPixelBoundaries();
1270         android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
1271         if (!dirty.isEmpty()) {
1272             region->orSelf(dirty);
1273         }
1274     }
1275 }
1276
1277 void OpenGLRenderer::clearLayerRegions() {
1278     const size_t count = mLayers.size();
1279     if (count == 0) return;
1280
1281     if (!mSnapshot->isIgnored()) {
1282         // Doing several glScissor/glClear here can negatively impact
1283         // GPUs with a tiler architecture, instead we draw quads with
1284         // the Clear blending mode
1285
1286         // The list contains bounds that have already been clipped
1287         // against their initial clip rect, and the current clip
1288         // is likely different so we need to disable clipping here
1289         bool scissorChanged = mCaches.disableScissor();
1290
1291         Vertex mesh[count * 6];
1292         Vertex* vertex = mesh;
1293
1294         for (uint32_t i = 0; i < count; i++) {
1295             Rect* bounds = mLayers.itemAt(i);
1296
1297             Vertex::set(vertex++, bounds->left, bounds->bottom);
1298             Vertex::set(vertex++, bounds->left, bounds->top);
1299             Vertex::set(vertex++, bounds->right, bounds->top);
1300             Vertex::set(vertex++, bounds->left, bounds->bottom);
1301             Vertex::set(vertex++, bounds->right, bounds->top);
1302             Vertex::set(vertex++, bounds->right, bounds->bottom);
1303
1304             delete bounds;
1305         }
1306         // We must clear the list of dirty rects before we
1307         // call setupDraw() to prevent stencil setup to do
1308         // the same thing again
1309         mLayers.clear();
1310
1311         setupDraw(false);
1312         setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
1313         setupDrawBlending(true, SkXfermode::kClear_Mode);
1314         setupDrawProgram();
1315         setupDrawPureColorUniforms();
1316         setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
1317         setupDrawVertices(&mesh[0].position[0]);
1318
1319         glDrawArrays(GL_TRIANGLES, 0, count * 6);
1320
1321         if (scissorChanged) mCaches.enableScissor();
1322     } else {
1323         for (uint32_t i = 0; i < count; i++) {
1324             delete mLayers.itemAt(i);
1325         }
1326         mLayers.clear();
1327     }
1328 }
1329
1330 ///////////////////////////////////////////////////////////////////////////////
1331 // State Deferral
1332 ///////////////////////////////////////////////////////////////////////////////
1333
1334 bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
1335     const Rect& currentClip = *(mSnapshot->clipRect);
1336     const mat4& currentMatrix = *(mSnapshot->transform);
1337
1338     if (stateDeferFlags & kStateDeferFlag_Draw) {
1339         // state has bounds initialized in local coordinates
1340         if (!state.mBounds.isEmpty()) {
1341             currentMatrix.mapRect(state.mBounds);
1342             if (!state.mBounds.intersect(currentClip)) {
1343                 // quick rejected
1344                 return true;
1345             }
1346         } else {
1347             state.mBounds.set(currentClip);
1348         }
1349     }
1350
1351     state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
1352     if (state.mClipValid) {
1353         state.mClip.set(currentClip);
1354     }
1355
1356     // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
1357     // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
1358     state.mMatrix.load(currentMatrix);
1359     state.mDrawModifiers = mDrawModifiers;
1360     state.mAlpha = mSnapshot->alpha;
1361     return false;
1362 }
1363
1364 void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
1365     currentTransform().load(state.mMatrix);
1366     mDrawModifiers = state.mDrawModifiers;
1367     mSnapshot->alpha = state.mAlpha;
1368
1369     if (state.mClipValid && !skipClipRestore) {
1370         mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom);
1371         dirtyClip();
1372     }
1373 }
1374
1375 void OpenGLRenderer::setFullScreenClip() {
1376     mSnapshot->setClip(0, 0, mWidth, mHeight);
1377     dirtyClip();
1378 }
1379
1380 ///////////////////////////////////////////////////////////////////////////////
1381 // Transforms
1382 ///////////////////////////////////////////////////////////////////////////////
1383
1384 void OpenGLRenderer::translate(float dx, float dy) {
1385     currentTransform().translate(dx, dy, 0.0f);
1386 }
1387
1388 void OpenGLRenderer::rotate(float degrees) {
1389     currentTransform().rotate(degrees, 0.0f, 0.0f, 1.0f);
1390 }
1391
1392 void OpenGLRenderer::scale(float sx, float sy) {
1393     currentTransform().scale(sx, sy, 1.0f);
1394 }
1395
1396 void OpenGLRenderer::skew(float sx, float sy) {
1397     currentTransform().skew(sx, sy);
1398 }
1399
1400 void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
1401     if (matrix) {
1402         currentTransform().load(*matrix);
1403     } else {
1404         currentTransform().loadIdentity();
1405     }
1406 }
1407
1408 bool OpenGLRenderer::hasRectToRectTransform() {
1409     return CC_LIKELY(currentTransform().rectToRect());
1410 }
1411
1412 void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
1413     currentTransform().copyTo(*matrix);
1414 }
1415
1416 void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
1417     SkMatrix transform;
1418     currentTransform().copyTo(transform);
1419     transform.preConcat(*matrix);
1420     currentTransform().load(transform);
1421 }
1422
1423 ///////////////////////////////////////////////////////////////////////////////
1424 // Clipping
1425 ///////////////////////////////////////////////////////////////////////////////
1426
1427 void OpenGLRenderer::setScissorFromClip() {
1428     Rect clip(*mSnapshot->clipRect);
1429     clip.snapToPixelBoundaries();
1430
1431     if (mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom,
1432             clip.getWidth(), clip.getHeight())) {
1433         mDirtyClip = false;
1434     }
1435 }
1436
1437 void OpenGLRenderer::ensureStencilBuffer() {
1438     // Thanks to the mismatch between EGL and OpenGL ES FBO we
1439     // cannot attach a stencil buffer to fbo0 dynamically. Let's
1440     // just hope we have one when hasLayer() returns false.
1441     if (hasLayer()) {
1442         attachStencilBufferToLayer(mSnapshot->layer);
1443     }
1444 }
1445
1446 void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
1447     // The layer's FBO is already bound when we reach this stage
1448     if (!layer->getStencilRenderBuffer()) {
1449         // GL_QCOM_tiled_rendering doesn't like it if a renderbuffer
1450         // is attached after we initiated tiling. We must turn it off,
1451         // attach the new render buffer then turn tiling back on
1452         endTiling();
1453
1454         RenderBuffer* buffer = mCaches.renderBufferCache.get(
1455                 Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
1456         layer->setStencilRenderBuffer(buffer);
1457
1458         startTiling(layer->clipRect, layer->layer.getHeight());
1459     }
1460 }
1461
1462 void OpenGLRenderer::setStencilFromClip() {
1463     if (!mCaches.debugOverdraw) {
1464         if (!mSnapshot->clipRegion->isEmpty()) {
1465             // NOTE: The order here is important, we must set dirtyClip to false
1466             //       before any draw call to avoid calling back into this method
1467             mDirtyClip = false;
1468
1469             ensureStencilBuffer();
1470
1471             mCaches.stencil.enableWrite();
1472
1473             // Clear the stencil but first make sure we restrict drawing
1474             // to the region's bounds
1475             bool resetScissor = mCaches.enableScissor();
1476             if (resetScissor) {
1477                 // The scissor was not set so we now need to update it
1478                 setScissorFromClip();
1479             }
1480             mCaches.stencil.clear();
1481             if (resetScissor) mCaches.disableScissor();
1482
1483             // NOTE: We could use the region contour path to generate a smaller mesh
1484             //       Since we are using the stencil we could use the red book path
1485             //       drawing technique. It might increase bandwidth usage though.
1486
1487             // The last parameter is important: we are not drawing in the color buffer
1488             // so we don't want to dirty the current layer, if any
1489             drawRegionRects(*mSnapshot->clipRegion, 0xff000000, SkXfermode::kSrc_Mode, false);
1490
1491             mCaches.stencil.enableTest();
1492
1493             // Draw the region used to generate the stencil if the appropriate debug
1494             // mode is enabled
1495             if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
1496                 drawRegionRects(*mSnapshot->clipRegion, 0x7f0000ff, SkXfermode::kSrcOver_Mode);
1497             }
1498         } else {
1499             mCaches.stencil.disable();
1500         }
1501     }
1502 }
1503
1504 const Rect& OpenGLRenderer::getClipBounds() {
1505     return mSnapshot->getLocalClip();
1506 }
1507
1508 bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom) {
1509     if (mSnapshot->isIgnored()) {
1510         return true;
1511     }
1512
1513     Rect r(left, top, right, bottom);
1514     currentTransform().mapRect(r);
1515     r.snapToPixelBoundaries();
1516
1517     Rect clipRect(*mSnapshot->clipRect);
1518     clipRect.snapToPixelBoundaries();
1519
1520     return !clipRect.intersects(r);
1521 }
1522
1523 bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
1524         Rect& transformed, Rect& clip) {
1525     if (mSnapshot->isIgnored()) {
1526         return true;
1527     }
1528
1529     transformed.set(left, top, right, bottom);
1530     currentTransform().mapRect(transformed);
1531     transformed.snapToPixelBoundaries();
1532
1533     clip.set(*mSnapshot->clipRect);
1534     clip.snapToPixelBoundaries();
1535
1536     return !clip.intersects(transformed);
1537 }
1538
1539 bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom,
1540         SkPaint* paint) {
1541     if (paint->getStyle() != SkPaint::kFill_Style) {
1542         float outset = paint->getStrokeWidth() * 0.5f;
1543         return quickReject(left - outset, top - outset, right + outset, bottom + outset);
1544     } else {
1545         return quickReject(left, top, right, bottom);
1546     }
1547 }
1548
1549 bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
1550     if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
1551         return true;
1552     }
1553
1554     Rect r(left, top, right, bottom);
1555     currentTransform().mapRect(r);
1556     r.snapToPixelBoundaries();
1557
1558     Rect clipRect(*mSnapshot->clipRect);
1559     clipRect.snapToPixelBoundaries();
1560
1561     bool rejected = !clipRect.intersects(r);
1562     if (!isDeferred() && !rejected) {
1563         mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clipRect.contains(r));
1564     }
1565
1566     return rejected;
1567 }
1568
1569 void OpenGLRenderer::debugClip() {
1570 #if DEBUG_CLIP_REGIONS
1571     if (!isDeferred() && !mSnapshot->clipRegion->isEmpty()) {
1572         drawRegionRects(*mSnapshot->clipRegion, 0x7f00ff00, SkXfermode::kSrcOver_Mode);
1573     }
1574 #endif
1575 }
1576
1577 bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
1578     if (CC_LIKELY(currentTransform().rectToRect())) {
1579         bool clipped = mSnapshot->clip(left, top, right, bottom, op);
1580         if (clipped) {
1581             dirtyClip();
1582         }
1583         return !mSnapshot->clipRect->isEmpty();
1584     }
1585
1586     SkPath path;
1587     path.addRect(left, top, right, bottom);
1588
1589     return clipPath(&path, op);
1590 }
1591
1592 bool OpenGLRenderer::clipPath(SkPath* path, SkRegion::Op op) {
1593     SkMatrix transform;
1594     currentTransform().copyTo(transform);
1595
1596     SkPath transformed;
1597     path->transform(transform, &transformed);
1598
1599     SkRegion clip;
1600     if (!mSnapshot->clipRegion->isEmpty()) {
1601         clip.setRegion(*mSnapshot->clipRegion);
1602     } else {
1603         Rect* bounds = mSnapshot->clipRect;
1604         clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
1605     }
1606
1607     SkRegion region;
1608     region.setPath(transformed, clip);
1609
1610     bool clipped = mSnapshot->clipRegionTransformed(region, op);
1611     if (clipped) {
1612         dirtyClip();
1613     }
1614     return !mSnapshot->clipRect->isEmpty();
1615 }
1616
1617 bool OpenGLRenderer::clipRegion(SkRegion* region, SkRegion::Op op) {
1618     bool clipped = mSnapshot->clipRegionTransformed(*region, op);
1619     if (clipped) {
1620         dirtyClip();
1621     }
1622     return !mSnapshot->clipRect->isEmpty();
1623 }
1624
1625 Rect* OpenGLRenderer::getClipRect() {
1626     return mSnapshot->clipRect;
1627 }
1628
1629 ///////////////////////////////////////////////////////////////////////////////
1630 // Drawing commands
1631 ///////////////////////////////////////////////////////////////////////////////
1632
1633 void OpenGLRenderer::setupDraw(bool clear) {
1634     // TODO: It would be best if we could do this before quickReject()
1635     //       changes the scissor test state
1636     if (clear) clearLayerRegions();
1637     // Make sure setScissor & setStencil happen at the beginning of
1638     // this method
1639     if (mDirtyClip) {
1640         if (mCaches.scissorEnabled) {
1641             setScissorFromClip();
1642         }
1643         setStencilFromClip();
1644     }
1645
1646     mDescription.reset();
1647
1648     mSetShaderColor = false;
1649     mColorSet = false;
1650     mColorA = mColorR = mColorG = mColorB = 0.0f;
1651     mTextureUnit = 0;
1652     mTrackDirtyRegions = true;
1653
1654     // Enable debug highlight when what we're about to draw is tested against
1655     // the stencil buffer and if stencil highlight debugging is on
1656     mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
1657             mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
1658             mCaches.stencil.isTestEnabled();
1659 }
1660
1661 void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
1662     mDescription.hasTexture = true;
1663     mDescription.hasAlpha8Texture = isAlpha8;
1664 }
1665
1666 void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
1667     mDescription.hasTexture = true;
1668     mDescription.hasColors = true;
1669     mDescription.hasAlpha8Texture = isAlpha8;
1670 }
1671
1672 void OpenGLRenderer::setupDrawWithExternalTexture() {
1673     mDescription.hasExternalTexture = true;
1674 }
1675
1676 void OpenGLRenderer::setupDrawNoTexture() {
1677     mCaches.disableTexCoordsVertexArray();
1678 }
1679
1680 void OpenGLRenderer::setupDrawAA() {
1681     mDescription.isAA = true;
1682 }
1683
1684 void OpenGLRenderer::setupDrawPoint(float pointSize) {
1685     mDescription.isPoint = true;
1686     mDescription.pointSize = pointSize;
1687 }
1688
1689 void OpenGLRenderer::setupDrawColor(int color, int alpha) {
1690     mColorA = alpha / 255.0f;
1691     mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
1692     mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
1693     mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
1694     mColorSet = true;
1695     mSetShaderColor = mDescription.setColor(mColorR, mColorG, mColorB, mColorA);
1696 }
1697
1698 void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
1699     mColorA = alpha / 255.0f;
1700     mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
1701     mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
1702     mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
1703     mColorSet = true;
1704     mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA);
1705 }
1706
1707 void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
1708     mCaches.fontRenderer->describe(mDescription, paint);
1709 }
1710
1711 void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
1712     mColorA = a;
1713     mColorR = r;
1714     mColorG = g;
1715     mColorB = b;
1716     mColorSet = true;
1717     mSetShaderColor = mDescription.setColor(r, g, b, a);
1718 }
1719
1720 void OpenGLRenderer::setupDrawShader() {
1721     if (mDrawModifiers.mShader) {
1722         mDrawModifiers.mShader->describe(mDescription, mExtensions);
1723     }
1724 }
1725
1726 void OpenGLRenderer::setupDrawColorFilter() {
1727     if (mDrawModifiers.mColorFilter) {
1728         mDrawModifiers.mColorFilter->describe(mDescription, mExtensions);
1729     }
1730 }
1731
1732 void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
1733     if (mColorSet && mode == SkXfermode::kClear_Mode) {
1734         mColorA = 1.0f;
1735         mColorR = mColorG = mColorB = 0.0f;
1736         mSetShaderColor = mDescription.modulate = true;
1737     }
1738 }
1739
1740 void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) {
1741     // When the blending mode is kClear_Mode, we need to use a modulate color
1742     // argb=1,0,0,0
1743     accountForClear(mode);
1744     bool blend = (mColorSet && mColorA < 1.0f) ||
1745             (mDrawModifiers.mShader && mDrawModifiers.mShader->blend());
1746     chooseBlending(blend, mode, mDescription, swapSrcDst);
1747 }
1748
1749 void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) {
1750     // When the blending mode is kClear_Mode, we need to use a modulate color
1751     // argb=1,0,0,0
1752     accountForClear(mode);
1753     blend |= (mColorSet && mColorA < 1.0f) ||
1754             (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
1755             (mDrawModifiers.mColorFilter && mDrawModifiers.mColorFilter->blend());
1756     chooseBlending(blend, mode, mDescription, swapSrcDst);
1757 }
1758
1759 void OpenGLRenderer::setupDrawProgram() {
1760     useProgram(mCaches.programCache.get(mDescription));
1761 }
1762
1763 void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
1764     mTrackDirtyRegions = false;
1765 }
1766
1767 void OpenGLRenderer::setupDrawModelViewTranslate(float left, float top, float right, float bottom,
1768         bool ignoreTransform) {
1769     mModelView.loadTranslate(left, top, 0.0f);
1770     if (!ignoreTransform) {
1771         mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform());
1772         if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, currentTransform());
1773     } else {
1774         mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity());
1775         if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
1776     }
1777 }
1778
1779 void OpenGLRenderer::setupDrawModelViewIdentity(bool offset) {
1780     mCaches.currentProgram->set(mOrthoMatrix, mat4::identity(), currentTransform(), offset);
1781 }
1782
1783 void OpenGLRenderer::setupDrawModelView(float left, float top, float right, float bottom,
1784         bool ignoreTransform, bool ignoreModelView) {
1785     if (!ignoreModelView) {
1786         mModelView.loadTranslate(left, top, 0.0f);
1787         mModelView.scale(right - left, bottom - top, 1.0f);
1788     } else {
1789         mModelView.loadIdentity();
1790     }
1791     bool dirty = right - left > 0.0f && bottom - top > 0.0f;
1792     if (!ignoreTransform) {
1793         mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform());
1794         if (mTrackDirtyRegions && dirty) {
1795             dirtyLayer(left, top, right, bottom, currentTransform());
1796         }
1797     } else {
1798         mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity());
1799         if (mTrackDirtyRegions && dirty) dirtyLayer(left, top, right, bottom);
1800     }
1801 }
1802
1803 void OpenGLRenderer::setupDrawPointUniforms() {
1804     int slot = mCaches.currentProgram->getUniform("pointSize");
1805     glUniform1f(slot, mDescription.pointSize);
1806 }
1807
1808 void OpenGLRenderer::setupDrawColorUniforms() {
1809     if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) {
1810         mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
1811     }
1812 }
1813
1814 void OpenGLRenderer::setupDrawPureColorUniforms() {
1815     if (mSetShaderColor) {
1816         mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
1817     }
1818 }
1819
1820 void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) {
1821     if (mDrawModifiers.mShader) {
1822         if (ignoreTransform) {
1823             mModelView.loadInverse(currentTransform());
1824         }
1825         mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
1826                 mModelView, *mSnapshot, &mTextureUnit);
1827     }
1828 }
1829
1830 void OpenGLRenderer::setupDrawShaderIdentityUniforms() {
1831     if (mDrawModifiers.mShader) {
1832         mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
1833                 mat4::identity(), *mSnapshot, &mTextureUnit);
1834     }
1835 }
1836
1837 void OpenGLRenderer::setupDrawColorFilterUniforms() {
1838     if (mDrawModifiers.mColorFilter) {
1839         mDrawModifiers.mColorFilter->setupProgram(mCaches.currentProgram);
1840     }
1841 }
1842
1843 void OpenGLRenderer::setupDrawTextGammaUniforms() {
1844     mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram);
1845 }
1846
1847 void OpenGLRenderer::setupDrawSimpleMesh() {
1848     bool force = mCaches.bindMeshBuffer();
1849     mCaches.bindPositionVertexPointer(force, 0);
1850     mCaches.unbindIndicesBuffer();
1851 }
1852
1853 void OpenGLRenderer::setupDrawTexture(GLuint texture) {
1854     if (texture) bindTexture(texture);
1855     mTextureUnit++;
1856     mCaches.enableTexCoordsVertexArray();
1857 }
1858
1859 void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
1860     bindExternalTexture(texture);
1861     mTextureUnit++;
1862     mCaches.enableTexCoordsVertexArray();
1863 }
1864
1865 void OpenGLRenderer::setupDrawTextureTransform() {
1866     mDescription.hasTextureTransform = true;
1867 }
1868
1869 void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
1870     glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
1871             GL_FALSE, &transform.data[0]);
1872 }
1873
1874 void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
1875     bool force = false;
1876     if (!vertices) {
1877         force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
1878     } else {
1879         force = mCaches.unbindMeshBuffer();
1880     }
1881
1882     mCaches.bindPositionVertexPointer(force, vertices);
1883     if (mCaches.currentProgram->texCoords >= 0) {
1884         mCaches.bindTexCoordsVertexPointer(force, texCoords);
1885     }
1886
1887     mCaches.unbindIndicesBuffer();
1888 }
1889
1890 void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors) {
1891     bool force = mCaches.unbindMeshBuffer();
1892     GLsizei stride = sizeof(ColorTextureVertex);
1893
1894     mCaches.bindPositionVertexPointer(force, vertices, stride);
1895     if (mCaches.currentProgram->texCoords >= 0) {
1896         mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
1897     }
1898     int slot = mCaches.currentProgram->getAttrib("colors");
1899     if (slot >= 0) {
1900         glEnableVertexAttribArray(slot);
1901         glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
1902     }
1903
1904     mCaches.unbindIndicesBuffer();
1905 }
1906
1907 void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) {
1908     bool force = mCaches.unbindMeshBuffer();
1909     mCaches.bindPositionVertexPointer(force, vertices);
1910     if (mCaches.currentProgram->texCoords >= 0) {
1911         mCaches.bindTexCoordsVertexPointer(force, texCoords);
1912     }
1913 }
1914
1915 void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
1916     bool force = mCaches.unbindMeshBuffer();
1917     mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
1918     mCaches.unbindIndicesBuffer();
1919 }
1920
1921 void OpenGLRenderer::finishDrawTexture() {
1922 }
1923
1924 ///////////////////////////////////////////////////////////////////////////////
1925 // Drawing
1926 ///////////////////////////////////////////////////////////////////////////////
1927
1928 status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
1929         int32_t replayFlags) {
1930     status_t status;
1931     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
1932     // will be performed by the display list itself
1933     if (displayList && displayList->isRenderable()) {
1934         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
1935             status = startFrame();
1936             ReplayStateStruct replayStruct(*this, dirty, replayFlags);
1937             displayList->replay(replayStruct, 0);
1938             return status | replayStruct.mDrawGlStatus;
1939         }
1940
1941         DeferredDisplayList deferredList;
1942         DeferStateStruct deferStruct(deferredList, *this, replayFlags);
1943         displayList->defer(deferStruct, 0);
1944
1945         flushLayers();
1946         status = startFrame();
1947
1948         return status | deferredList.flush(*this, dirty);
1949     }
1950
1951     return DrawGlInfo::kStatusDone;
1952 }
1953
1954 void OpenGLRenderer::outputDisplayList(DisplayList* displayList) {
1955     if (displayList) {
1956         displayList->output(1);
1957     }
1958 }
1959
1960 void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) {
1961     int alpha;
1962     SkXfermode::Mode mode;
1963     getAlphaAndMode(paint, &alpha, &mode);
1964
1965     int color = paint != NULL ? paint->getColor() : 0;
1966
1967     float x = left;
1968     float y = top;
1969
1970     texture->setWrap(GL_CLAMP_TO_EDGE, true);
1971
1972     bool ignoreTransform = false;
1973     if (currentTransform().isPureTranslate()) {
1974         x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f);
1975         y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f);
1976         ignoreTransform = true;
1977
1978         texture->setFilter(GL_NEAREST, true);
1979     } else {
1980         texture->setFilter(FILTER(paint), true);
1981     }
1982
1983     drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
1984             paint != NULL, color, alpha, mode, (GLvoid*) NULL,
1985             (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
1986 }
1987
1988 status_t OpenGLRenderer::drawBitmaps(SkBitmap* bitmap, int bitmapCount, TextureVertex* vertices,
1989         const Rect& bounds, SkPaint* paint) {
1990
1991     // merged draw operations don't need scissor, but clip should still be valid
1992     mCaches.setScissorEnabled(mScissorOptimizationDisabled);
1993
1994     mCaches.activeTexture(0);
1995     Texture* texture = mCaches.textureCache.get(bitmap);
1996     if (!texture) return DrawGlInfo::kStatusDone;
1997     const AutoTexture autoCleanup(texture);
1998
1999     int alpha;
2000     SkXfermode::Mode mode;
2001     getAlphaAndMode(paint, &alpha, &mode);
2002
2003     texture->setWrap(GL_CLAMP_TO_EDGE, true);
2004     texture->setFilter(GL_NEAREST, true); // merged ops are always pure-translation for now
2005
2006     const float x = (int) floorf(bounds.left + 0.5f);
2007     const float y = (int) floorf(bounds.top + 0.5f);
2008     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
2009         int color = paint != NULL ? paint->getColor() : 0;
2010         drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
2011                 texture->id, paint != NULL, color, alpha, mode,
2012                 &vertices[0].position[0], &vertices[0].texture[0],
2013                 GL_TRIANGLES, bitmapCount * 6, true, true);
2014     } else {
2015         drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
2016                 texture->id, alpha / 255.0f, mode, texture->blend,
2017                 &vertices[0].position[0], &vertices[0].texture[0],
2018                 GL_TRIANGLES, bitmapCount * 6, false, true, 0, true);
2019     }
2020
2021     return DrawGlInfo::kStatusDrew;
2022 }
2023
2024 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
2025     const float right = left + bitmap->width();
2026     const float bottom = top + bitmap->height();
2027
2028     if (quickReject(left, top, right, bottom)) {
2029         return DrawGlInfo::kStatusDone;
2030     }
2031
2032     mCaches.activeTexture(0);
2033     Texture* texture = mCaches.textureCache.get(bitmap);
2034     if (!texture) return DrawGlInfo::kStatusDone;
2035     const AutoTexture autoCleanup(texture);
2036
2037     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
2038         drawAlphaBitmap(texture, left, top, paint);
2039     } else {
2040         drawTextureRect(left, top, right, bottom, texture, paint);
2041     }
2042
2043     return DrawGlInfo::kStatusDrew;
2044 }
2045
2046 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
2047     Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
2048     const mat4 transform(*matrix);
2049     transform.mapRect(r);
2050
2051     if (quickReject(r.left, r.top, r.right, r.bottom)) {
2052         return DrawGlInfo::kStatusDone;
2053     }
2054
2055     mCaches.activeTexture(0);
2056     Texture* texture = mCaches.textureCache.get(bitmap);
2057     if (!texture) return DrawGlInfo::kStatusDone;
2058     const AutoTexture autoCleanup(texture);
2059
2060     // This could be done in a cheaper way, all we need is pass the matrix
2061     // to the vertex shader. The save/restore is a bit overkill.
2062     save(SkCanvas::kMatrix_SaveFlag);
2063     concatMatrix(matrix);
2064     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
2065         drawAlphaBitmap(texture, 0.0f, 0.0f, paint);
2066     } else {
2067         drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
2068     }
2069     restore();
2070
2071     return DrawGlInfo::kStatusDrew;
2072 }
2073
2074 status_t OpenGLRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
2075     const float right = left + bitmap->width();
2076     const float bottom = top + bitmap->height();
2077
2078     if (quickReject(left, top, right, bottom)) {
2079         return DrawGlInfo::kStatusDone;
2080     }
2081
2082     mCaches.activeTexture(0);
2083     Texture* texture = mCaches.textureCache.getTransient(bitmap);
2084     const AutoTexture autoCleanup(texture);
2085
2086     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
2087         drawAlphaBitmap(texture, left, top, paint);
2088     } else {
2089         drawTextureRect(left, top, right, bottom, texture, paint);
2090     }
2091
2092     return DrawGlInfo::kStatusDrew;
2093 }
2094
2095 status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
2096         float* vertices, int* colors, SkPaint* paint) {
2097     if (!vertices || mSnapshot->isIgnored()) {
2098         return DrawGlInfo::kStatusDone;
2099     }
2100
2101     float left = FLT_MAX;
2102     float top = FLT_MAX;
2103     float right = FLT_MIN;
2104     float bottom = FLT_MIN;
2105
2106     const uint32_t count = meshWidth * meshHeight * 6;
2107
2108     ColorTextureVertex mesh[count];
2109     ColorTextureVertex* vertex = mesh;
2110
2111     bool cleanupColors = false;
2112     if (!colors) {
2113         uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
2114         colors = new int[colorsCount];
2115         memset(colors, 0xff, colorsCount * sizeof(int));
2116         cleanupColors = true;
2117     }
2118
2119     for (int32_t y = 0; y < meshHeight; y++) {
2120         for (int32_t x = 0; x < meshWidth; x++) {
2121             uint32_t i = (y * (meshWidth + 1) + x) * 2;
2122
2123             float u1 = float(x) / meshWidth;
2124             float u2 = float(x + 1) / meshWidth;
2125             float v1 = float(y) / meshHeight;
2126             float v2 = float(y + 1) / meshHeight;
2127
2128             int ax = i + (meshWidth + 1) * 2;
2129             int ay = ax + 1;
2130             int bx = i;
2131             int by = bx + 1;
2132             int cx = i + 2;
2133             int cy = cx + 1;
2134             int dx = i + (meshWidth + 1) * 2 + 2;
2135             int dy = dx + 1;
2136
2137             ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2138             ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
2139             ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
2140
2141             ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2142             ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
2143             ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
2144
2145             left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
2146             top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
2147             right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
2148             bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
2149         }
2150     }
2151
2152     if (quickReject(left, top, right, bottom)) {
2153         if (cleanupColors) delete[] colors;
2154         return DrawGlInfo::kStatusDone;
2155     }
2156
2157     mCaches.activeTexture(0);
2158     Texture* texture = mCaches.textureCache.get(bitmap);
2159     if (!texture) {
2160         if (cleanupColors) delete[] colors;
2161         return DrawGlInfo::kStatusDone;
2162     }
2163     const AutoTexture autoCleanup(texture);
2164
2165     texture->setWrap(GL_CLAMP_TO_EDGE, true);
2166     texture->setFilter(FILTER(paint), true);
2167
2168     int alpha;
2169     SkXfermode::Mode mode;
2170     getAlphaAndMode(paint, &alpha, &mode);
2171
2172     float a = alpha / 255.0f;
2173
2174     if (hasLayer()) {
2175         dirtyLayer(left, top, right, bottom, currentTransform());
2176     }
2177
2178     setupDraw();
2179     setupDrawWithTextureAndColor();
2180     setupDrawColor(a, a, a, a);
2181     setupDrawColorFilter();
2182     setupDrawBlending(true, mode, false);
2183     setupDrawProgram();
2184     setupDrawDirtyRegionsDisabled();
2185     setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, false);
2186     setupDrawTexture(texture->id);
2187     setupDrawPureColorUniforms();
2188     setupDrawColorFilterUniforms();
2189     setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0], &mesh[0].color[0]);
2190
2191     glDrawArrays(GL_TRIANGLES, 0, count);
2192
2193     finishDrawTexture();
2194
2195     int slot = mCaches.currentProgram->getAttrib("colors");
2196     if (slot >= 0) {
2197         glDisableVertexAttribArray(slot);
2198     }
2199
2200     if (cleanupColors) delete[] colors;
2201
2202     return DrawGlInfo::kStatusDrew;
2203 }
2204
2205 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
2206          float srcLeft, float srcTop, float srcRight, float srcBottom,
2207          float dstLeft, float dstTop, float dstRight, float dstBottom,
2208          SkPaint* paint) {
2209     if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
2210         return DrawGlInfo::kStatusDone;
2211     }
2212
2213     mCaches.activeTexture(0);
2214     Texture* texture = mCaches.textureCache.get(bitmap);
2215     if (!texture) return DrawGlInfo::kStatusDone;
2216     const AutoTexture autoCleanup(texture);
2217
2218     const float width = texture->width;
2219     const float height = texture->height;
2220
2221     const float u1 = fmax(0.0f, srcLeft / width);
2222     const float v1 = fmax(0.0f, srcTop / height);
2223     const float u2 = fmin(1.0f, srcRight / width);
2224     const float v2 = fmin(1.0f, srcBottom / height);
2225
2226     mCaches.unbindMeshBuffer();
2227     resetDrawTextureTexCoords(u1, v1, u2, v2);
2228
2229     int alpha;
2230     SkXfermode::Mode mode;
2231     getAlphaAndMode(paint, &alpha, &mode);
2232
2233     texture->setWrap(GL_CLAMP_TO_EDGE, true);
2234
2235     float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
2236     float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);
2237
2238     bool scaled = scaleX != 1.0f || scaleY != 1.0f;
2239     // Apply a scale transform on the canvas only when a shader is in use
2240     // Skia handles the ratio between the dst and src rects as a scale factor
2241     // when a shader is set
2242     bool useScaleTransform = mDrawModifiers.mShader && scaled;
2243     bool ignoreTransform = false;
2244
2245     if (CC_LIKELY(currentTransform().isPureTranslate() && !useScaleTransform)) {
2246         float x = (int) floorf(dstLeft + currentTransform().getTranslateX() + 0.5f);
2247         float y = (int) floorf(dstTop + currentTransform().getTranslateY() + 0.5f);
2248
2249         dstRight = x + (dstRight - dstLeft);
2250         dstBottom = y + (dstBottom - dstTop);
2251
2252         dstLeft = x;
2253         dstTop = y;
2254
2255         texture->setFilter(scaled ? FILTER(paint) : GL_NEAREST, true);
2256         ignoreTransform = true;
2257     } else {
2258         texture->setFilter(FILTER(paint), true);
2259     }
2260
2261     if (CC_UNLIKELY(useScaleTransform)) {
2262         save(SkCanvas::kMatrix_SaveFlag);
2263         translate(dstLeft, dstTop);
2264         scale(scaleX, scaleY);
2265
2266         dstLeft = 0.0f;
2267         dstTop = 0.0f;
2268
2269         dstRight = srcRight - srcLeft;
2270         dstBottom = srcBottom - srcTop;
2271     }
2272
2273     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
2274         int color = paint ? paint->getColor() : 0;
2275         drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
2276                 texture->id, paint != NULL, color, alpha, mode,
2277                 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
2278                 GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
2279     } else {
2280         drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
2281                 texture->id, alpha / 255.0f, mode, texture->blend,
2282                 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
2283                 GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
2284     }
2285
2286     if (CC_UNLIKELY(useScaleTransform)) {
2287         restore();
2288     }
2289
2290     resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
2291
2292     return DrawGlInfo::kStatusDrew;
2293 }
2294
2295 status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
2296         const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
2297         float left, float top, float right, float bottom, SkPaint* paint) {
2298     int alpha;
2299     SkXfermode::Mode mode;
2300     getAlphaAndMode(paint, &alpha, &mode);
2301
2302     return drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors,
2303             left, top, right, bottom, alpha, mode);
2304 }
2305
2306 status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
2307         const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
2308         float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode) {
2309     if (quickReject(left, top, right, bottom)) {
2310         return DrawGlInfo::kStatusDone;
2311     }
2312
2313     alpha *= mSnapshot->alpha;
2314
2315     const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
2316             right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
2317
2318     if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
2319         mCaches.activeTexture(0);
2320         Texture* texture = mCaches.textureCache.get(bitmap);
2321         if (!texture) return DrawGlInfo::kStatusDone;
2322         const AutoTexture autoCleanup(texture);
2323         texture->setWrap(GL_CLAMP_TO_EDGE, true);
2324         texture->setFilter(GL_LINEAR, true);
2325
2326         const bool pureTranslate = currentTransform().isPureTranslate();
2327         // Mark the current layer dirty where we are going to draw the patch
2328         if (hasLayer() && mesh->hasEmptyQuads) {
2329             const float offsetX = left + currentTransform().getTranslateX();
2330             const float offsetY = top + currentTransform().getTranslateY();
2331             const size_t count = mesh->quads.size();
2332             for (size_t i = 0; i < count; i++) {
2333                 const Rect& bounds = mesh->quads.itemAt(i);
2334                 if (CC_LIKELY(pureTranslate)) {
2335                     const float x = (int) floorf(bounds.left + offsetX + 0.5f);
2336                     const float y = (int) floorf(bounds.top + offsetY + 0.5f);
2337                     dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
2338                 } else {
2339                     dirtyLayer(left + bounds.left, top + bounds.top,
2340                             left + bounds.right, top + bounds.bottom, currentTransform());
2341                 }
2342             }
2343         }
2344
2345         if (CC_LIKELY(pureTranslate)) {
2346             const float x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f);
2347             const float y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f);
2348
2349             drawTextureMesh(x, y, x + right - left, y + bottom - top, texture->id, alpha / 255.0f,
2350                     mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
2351                     GL_TRIANGLES, mesh->verticesCount, false, true, mesh->meshBuffer,
2352                     true, !mesh->hasEmptyQuads);
2353         } else {
2354             drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
2355                     mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
2356                     GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer,
2357                     true, !mesh->hasEmptyQuads);
2358         }
2359     }
2360
2361     return DrawGlInfo::kStatusDrew;
2362 }
2363
2364 status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, SkPaint* paint,
2365         bool useOffset) {
2366     if (!vertexBuffer.getSize()) {
2367         // no vertices to draw
2368         return DrawGlInfo::kStatusDone;
2369     }
2370
2371     int color = paint->getColor();
2372     SkXfermode::Mode mode = getXfermode(paint->getXfermode());
2373     bool isAA = paint->isAntiAlias();
2374
2375     setupDraw();
2376     setupDrawNoTexture();
2377     if (isAA) setupDrawAA();
2378     setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
2379     setupDrawColorFilter();
2380     setupDrawShader();
2381     setupDrawBlending(isAA, mode);
2382     setupDrawProgram();
2383     setupDrawModelViewIdentity(useOffset);
2384     setupDrawColorUniforms();
2385     setupDrawColorFilterUniforms();
2386     setupDrawShaderIdentityUniforms();
2387
2388     void* vertices = vertexBuffer.getBuffer();
2389     bool force = mCaches.unbindMeshBuffer();
2390     mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
2391     mCaches.resetTexCoordsVertexPointer();
2392     mCaches.unbindIndicesBuffer();
2393
2394     int alphaSlot = -1;
2395     if (isAA) {
2396         void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
2397         alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
2398
2399         // TODO: avoid enable/disable in back to back uses of the alpha attribute
2400         glEnableVertexAttribArray(alphaSlot);
2401         glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
2402     }
2403
2404     glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getSize());
2405
2406     if (isAA) {
2407         glDisableVertexAttribArray(alphaSlot);
2408     }
2409
2410     return DrawGlInfo::kStatusDrew;
2411 }
2412
2413 /**
2414  * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
2415  * that of AA lines in the drawLines() function.  We expand the convex path by a half pixel in
2416  * screen space in all directions. However, instead of using a fragment shader to compute the
2417  * translucency of the color from its position, we simply use a varying parameter to define how far
2418  * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
2419  *
2420  * Doesn't yet support joins, caps, or path effects.
2421  */
2422 status_t OpenGLRenderer::drawConvexPath(const SkPath& path, SkPaint* paint) {
2423     VertexBuffer vertexBuffer;
2424     // TODO: try clipping large paths to viewport
2425     PathTessellator::tessellatePath(path, paint, mSnapshot->transform, vertexBuffer);
2426
2427     if (hasLayer()) {
2428         SkRect bounds = path.getBounds();
2429         PathTessellator::expandBoundsForStroke(bounds, paint, false);
2430         dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform());
2431     }
2432
2433     return drawVertexBuffer(vertexBuffer, paint);
2434 }
2435
2436 /**
2437  * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
2438  * and additional geometry for defining an alpha slope perimeter.
2439  *
2440  * Using GL_LINES can be difficult because the rasterization rules for those lines produces some
2441  * unexpected results, and may vary between hardware devices. Previously we used a varying-base
2442  * in-shader alpha region, but found it to be taxing on some GPUs.
2443  *
2444  * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
2445  * memory transfer by removing need for degenerate vertices.
2446  */
2447 status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
2448     if (mSnapshot->isIgnored() || count < 4) return DrawGlInfo::kStatusDone;
2449
2450     count &= ~0x3; // round down to nearest four
2451
2452     VertexBuffer buffer;
2453     SkRect bounds;
2454     PathTessellator::tessellateLines(points, count, paint, mSnapshot->transform, bounds, buffer);
2455
2456     if (quickReject(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom)) {
2457         return DrawGlInfo::kStatusDone;
2458     }
2459
2460     dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform());
2461
2462     bool useOffset = !paint->isAntiAlias();
2463     return drawVertexBuffer(buffer, paint, useOffset);
2464 }
2465
2466 status_t OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) {
2467     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2468
2469     // TODO: The paint's cap style defines whether the points are square or circular
2470     // TODO: Handle AA for round points
2471
2472     // A stroke width of 0 has a special meaning in Skia:
2473     // it draws an unscaled 1px point
2474     float strokeWidth = paint->getStrokeWidth();
2475     const bool isHairLine = paint->getStrokeWidth() == 0.0f;
2476     if (isHairLine) {
2477         // Now that we know it's hairline, we can set the effective width, to be used later
2478         strokeWidth = 1.0f;
2479     }
2480     const float halfWidth = strokeWidth / 2;
2481
2482     int alpha;
2483     SkXfermode::Mode mode;
2484     getAlphaAndMode(paint, &alpha, &mode);
2485
2486     int verticesCount = count >> 1;
2487     int generatedVerticesCount = 0;
2488
2489     TextureVertex pointsData[verticesCount];
2490     TextureVertex* vertex = &pointsData[0];
2491
2492     // TODO: We should optimize this method to not generate vertices for points
2493     // that lie outside of the clip.
2494     mCaches.enableScissor();
2495
2496     setupDraw();
2497     setupDrawNoTexture();
2498     setupDrawPoint(strokeWidth);
2499     setupDrawColor(paint->getColor(), alpha);
2500     setupDrawColorFilter();
2501     setupDrawShader();
2502     setupDrawBlending(mode);
2503     setupDrawProgram();
2504     setupDrawModelViewIdentity(true);
2505     setupDrawColorUniforms();
2506     setupDrawColorFilterUniforms();
2507     setupDrawPointUniforms();
2508     setupDrawShaderIdentityUniforms();
2509     setupDrawMesh(vertex);
2510
2511     for (int i = 0; i < count; i += 2) {
2512         TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f);
2513         generatedVerticesCount++;
2514
2515         float left = points[i] - halfWidth;
2516         float right = points[i] + halfWidth;
2517         float top = points[i + 1] - halfWidth;
2518         float bottom = points [i + 1] + halfWidth;
2519
2520         dirtyLayer(left, top, right, bottom, currentTransform());
2521     }
2522
2523     glDrawArrays(GL_POINTS, 0, generatedVerticesCount);
2524
2525     return DrawGlInfo::kStatusDrew;
2526 }
2527
2528 status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
2529     // No need to check against the clip, we fill the clip region
2530     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2531
2532     Rect& clip(*mSnapshot->clipRect);
2533     clip.snapToPixelBoundaries();
2534
2535     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
2536
2537     return DrawGlInfo::kStatusDrew;
2538 }
2539
2540 status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
2541         SkPaint* paint) {
2542     if (!texture) return DrawGlInfo::kStatusDone;
2543     const AutoTexture autoCleanup(texture);
2544
2545     const float x = left + texture->left - texture->offset;
2546     const float y = top + texture->top - texture->offset;
2547
2548     drawPathTexture(texture, x, y, paint);
2549
2550     return DrawGlInfo::kStatusDrew;
2551 }
2552
2553 status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
2554         float rx, float ry, SkPaint* p) {
2555     if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
2556             (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
2557         return DrawGlInfo::kStatusDone;
2558     }
2559
2560     if (p->getPathEffect() != 0) {
2561         mCaches.activeTexture(0);
2562         const PathTexture* texture = mCaches.pathCache.getRoundRect(
2563                 right - left, bottom - top, rx, ry, p);
2564         return drawShape(left, top, texture, p);
2565     }
2566
2567     SkPath path;
2568     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2569     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2570         float outset = p->getStrokeWidth() / 2;
2571         rect.outset(outset, outset);
2572         rx += outset;
2573         ry += outset;
2574     }
2575     path.addRoundRect(rect, rx, ry);
2576     return drawConvexPath(path, p);
2577 }
2578
2579 status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* p) {
2580     if (mSnapshot->isIgnored() || quickRejectPreStroke(x - radius, y - radius,
2581             x + radius, y + radius, p) ||
2582             (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
2583         return DrawGlInfo::kStatusDone;
2584     }
2585     if (p->getPathEffect() != 0) {
2586         mCaches.activeTexture(0);
2587         const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
2588         return drawShape(x - radius, y - radius, texture, p);
2589     }
2590
2591     SkPath path;
2592     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2593         path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
2594     } else {
2595         path.addCircle(x, y, radius);
2596     }
2597     return drawConvexPath(path, p);
2598 }
2599
2600 status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
2601         SkPaint* p) {
2602     if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
2603             (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
2604         return DrawGlInfo::kStatusDone;
2605     }
2606
2607     if (p->getPathEffect() != 0) {
2608         mCaches.activeTexture(0);
2609         const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
2610         return drawShape(left, top, texture, p);
2611     }
2612
2613     SkPath path;
2614     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2615     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2616         rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2617     }
2618     path.addOval(rect);
2619     return drawConvexPath(path, p);
2620 }
2621
2622 status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
2623         float startAngle, float sweepAngle, bool useCenter, SkPaint* p) {
2624     if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
2625             (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
2626         return DrawGlInfo::kStatusDone;
2627     }
2628
2629     if (fabs(sweepAngle) >= 360.0f) {
2630         return drawOval(left, top, right, bottom, p);
2631     }
2632
2633     // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
2634     if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) {
2635         mCaches.activeTexture(0);
2636         const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
2637                 startAngle, sweepAngle, useCenter, p);
2638         return drawShape(left, top, texture, p);
2639     }
2640
2641     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2642     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2643         rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2644     }
2645
2646     SkPath path;
2647     if (useCenter) {
2648         path.moveTo(rect.centerX(), rect.centerY());
2649     }
2650     path.arcTo(rect, startAngle, sweepAngle, !useCenter);
2651     if (useCenter) {
2652         path.close();
2653     }
2654     return drawConvexPath(path, p);
2655 }
2656
2657 // See SkPaintDefaults.h
2658 #define SkPaintDefaults_MiterLimit SkIntToScalar(4)
2659
2660 status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
2661     if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
2662             (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
2663         return DrawGlInfo::kStatusDone;
2664     }
2665
2666     if (p->getStyle() != SkPaint::kFill_Style) {
2667         // only fill style is supported by drawConvexPath, since others have to handle joins
2668         if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join ||
2669                 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
2670             mCaches.activeTexture(0);
2671             const PathTexture* texture =
2672                     mCaches.pathCache.getRect(right - left, bottom - top, p);
2673             return drawShape(left, top, texture, p);
2674         }
2675
2676         SkPath path;
2677         SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2678         if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2679             rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2680         }
2681         path.addRect(rect);
2682         return drawConvexPath(path, p);
2683     }
2684
2685     if (p->isAntiAlias() && !currentTransform().isSimple()) {
2686         SkPath path;
2687         path.addRect(left, top, right, bottom);
2688         return drawConvexPath(path, p);
2689     } else {
2690         drawColorRect(left, top, right, bottom, p->getColor(), getXfermode(p->getXfermode()));
2691         return DrawGlInfo::kStatusDrew;
2692     }
2693 }
2694
2695 void OpenGLRenderer::drawTextShadow(SkPaint* paint, const char* text, int bytesCount, int count,
2696         const float* positions, FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode,
2697         float x, float y) {
2698     mCaches.activeTexture(0);
2699
2700     // NOTE: The drop shadow will not perform gamma correction
2701     //       if shader-based correction is enabled
2702     mCaches.dropShadowCache.setFontRenderer(fontRenderer);
2703     const ShadowTexture* shadow = mCaches.dropShadowCache.get(
2704             paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
2705     // If the drop shadow exceeds the max texture size or couldn't be
2706     // allocated, skip drawing
2707     if (!shadow) return;
2708     const AutoTexture autoCleanup(shadow);
2709
2710     const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
2711     const float sy = y - shadow->top + mDrawModifiers.mShadowDy;
2712
2713     const int shadowAlpha = ((mDrawModifiers.mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
2714     int shadowColor = mDrawModifiers.mShadowColor;
2715     if (mDrawModifiers.mShader) {
2716         shadowColor = 0xffffffff;
2717     }
2718
2719     setupDraw();
2720     setupDrawWithTexture(true);
2721     setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
2722     setupDrawColorFilter();
2723     setupDrawShader();
2724     setupDrawBlending(true, mode);
2725     setupDrawProgram();
2726     setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height);
2727     setupDrawTexture(shadow->id);
2728     setupDrawPureColorUniforms();
2729     setupDrawColorFilterUniforms();
2730     setupDrawShaderUniforms();
2731     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
2732
2733     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
2734 }
2735
2736 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
2737     float alpha = (mDrawModifiers.mHasShadow ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
2738     return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
2739 }
2740
2741 class TextSetupFunctor: public Functor {
2742 public:
2743     TextSetupFunctor(OpenGLRenderer& renderer, float x, float y, bool pureTranslate,
2744             int alpha, SkXfermode::Mode mode, SkPaint* paint): Functor(),
2745             renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
2746             alpha(alpha), mode(mode), paint(paint) {
2747     }
2748     ~TextSetupFunctor() { }
2749
2750     status_t operator ()(int what, void* data) {
2751         renderer.setupDraw();
2752         renderer.setupDrawTextGamma(paint);
2753         renderer.setupDrawDirtyRegionsDisabled();
2754         renderer.setupDrawWithTexture(true);
2755         renderer.setupDrawAlpha8Color(paint->getColor(), alpha);
2756         renderer.setupDrawColorFilter();
2757         renderer.setupDrawShader();
2758         renderer.setupDrawBlending(true, mode);
2759         renderer.setupDrawProgram();
2760         renderer.setupDrawModelView(x, y, x, y, pureTranslate, true);
2761         // Calling setupDrawTexture with the name 0 will enable the
2762         // uv attributes and increase the texture unit count
2763         // texture binding will be performed by the font renderer as
2764         // needed
2765         renderer.setupDrawTexture(0);
2766         renderer.setupDrawPureColorUniforms();
2767         renderer.setupDrawColorFilterUniforms();
2768         renderer.setupDrawShaderUniforms(pureTranslate);
2769         renderer.setupDrawTextGammaUniforms();
2770
2771         return NO_ERROR;
2772     }
2773
2774     OpenGLRenderer& renderer;
2775     float x;
2776     float y;
2777     bool pureTranslate;
2778     int alpha;
2779     SkXfermode::Mode mode;
2780     SkPaint* paint;
2781 };
2782
2783 status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
2784         const float* positions, SkPaint* paint) {
2785     if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) {
2786         return DrawGlInfo::kStatusDone;
2787     }
2788
2789     // NOTE: Skia does not support perspective transform on drawPosText yet
2790     if (!currentTransform().isSimple()) {
2791         return DrawGlInfo::kStatusDone;
2792     }
2793
2794     float x = 0.0f;
2795     float y = 0.0f;
2796     const bool pureTranslate = currentTransform().isPureTranslate();
2797     if (pureTranslate) {
2798         x = (int) floorf(x + currentTransform().getTranslateX() + 0.5f);
2799         y = (int) floorf(y + currentTransform().getTranslateY() + 0.5f);
2800     }
2801
2802     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2803     fontRenderer.setFont(paint, mat4::identity());
2804
2805     int alpha;
2806     SkXfermode::Mode mode;
2807     getAlphaAndMode(paint, &alpha, &mode);
2808
2809     if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
2810         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
2811                 alpha, mode, 0.0f, 0.0f);
2812     }
2813
2814     // Pick the appropriate texture filtering
2815     bool linearFilter = currentTransform().changesBounds();
2816     if (pureTranslate && !linearFilter) {
2817         linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2818     }
2819     fontRenderer.setTextureFiltering(linearFilter);
2820
2821     const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
2822     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2823
2824     const bool hasActiveLayer = hasLayer();
2825
2826     TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
2827     if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2828             positions, hasActiveLayer ? &bounds : NULL, &functor)) {
2829         if (hasActiveLayer) {
2830             if (!pureTranslate) {
2831                 currentTransform().mapRect(bounds);
2832             }
2833             dirtyLayerUnchecked(bounds, getRegion());
2834         }
2835     }
2836
2837     return DrawGlInfo::kStatusDrew;
2838 }
2839
2840 mat4 OpenGLRenderer::findBestFontTransform(const mat4& transform) const {
2841     mat4 fontTransform;
2842     if (CC_LIKELY(transform.isPureTranslate())) {
2843         fontTransform = mat4::identity();
2844     } else {
2845         if (CC_UNLIKELY(transform.isPerspective())) {
2846             fontTransform = mat4::identity();
2847         } else {
2848             float sx, sy;
2849             currentTransform().decomposeScale(sx, sy);
2850             fontTransform.loadScale(sx, sy, 1.0f);
2851         }
2852     }
2853     return fontTransform;
2854 }
2855
2856 status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
2857         float x, float y, const float* positions, SkPaint* paint, float length,
2858         DrawOpMode drawOpMode) {
2859
2860     if (drawOpMode == kDrawOpMode_Immediate &&
2861             (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint))) {
2862         return DrawGlInfo::kStatusDone;
2863     }
2864
2865     if (length < 0.0f) length = paint->measureText(text, bytesCount);
2866     switch (paint->getTextAlign()) {
2867         case SkPaint::kCenter_Align:
2868             x -= length / 2.0f;
2869             break;
2870         case SkPaint::kRight_Align:
2871             x -= length;
2872             break;
2873         default:
2874             break;
2875     }
2876
2877     SkPaint::FontMetrics metrics;
2878     paint->getFontMetrics(&metrics, 0.0f);
2879     if (drawOpMode == kDrawOpMode_Immediate) {
2880         if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
2881             return DrawGlInfo::kStatusDone;
2882         }
2883     } else {
2884         // merged draw operations don't need scissor, but clip should still be valid
2885         mCaches.setScissorEnabled(mScissorOptimizationDisabled);
2886     }
2887
2888     const float oldX = x;
2889     const float oldY = y;
2890
2891     const mat4& transform = currentTransform();
2892     const bool pureTranslate = transform.isPureTranslate();
2893
2894     if (CC_LIKELY(pureTranslate)) {
2895         x = (int) floorf(x + transform.getTranslateX() + 0.5f);
2896         y = (int) floorf(y + transform.getTranslateY() + 0.5f);
2897     }
2898
2899     int alpha;
2900     SkXfermode::Mode mode;
2901     getAlphaAndMode(paint, &alpha, &mode);
2902
2903     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2904
2905     if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
2906         fontRenderer.setFont(paint, mat4::identity());
2907         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
2908                 alpha, mode, oldX, oldY);
2909     }
2910
2911     const bool hasActiveLayer = hasLayer();
2912
2913     // We only pass a partial transform to the font renderer. That partial
2914     // matrix defines how glyphs are rasterized. Typically we want glyphs
2915     // to be rasterized at their final size on screen, which means the partial
2916     // matrix needs to take the scale factor into account.
2917     // When a partial matrix is used to transform glyphs during rasterization,
2918     // the mesh is generated with the inverse transform (in the case of scale,
2919     // the mesh is generated at 1.0 / scale for instance.) This allows us to
2920     // apply the full transform matrix at draw time in the vertex shader.
2921     // Applying the full matrix in the shader is the easiest way to handle
2922     // rotation and perspective and allows us to always generated quads in the
2923     // font renderer which greatly simplifies the code, clipping in particular.
2924     mat4 fontTransform = findBestFontTransform(transform);
2925     fontRenderer.setFont(paint, fontTransform);
2926
2927     // Pick the appropriate texture filtering
2928     bool linearFilter = !pureTranslate || fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2929     fontRenderer.setTextureFiltering(linearFilter);
2930
2931     // TODO: Implement better clipping for scaled/rotated text
2932     const Rect* clip = !pureTranslate ? NULL : mSnapshot->clipRect;
2933     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2934
2935     bool status;
2936     TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
2937
2938     // don't call issuedrawcommand, do it at end of batch
2939     bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
2940     if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
2941         SkPaint paintCopy(*paint);
2942         paintCopy.setTextAlign(SkPaint::kLeft_Align);
2943         status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
2944                 positions, hasActiveLayer ? &bounds : NULL, &functor, forceFinish);
2945     } else {
2946         status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2947                 positions, hasActiveLayer ? &bounds : NULL, &functor, forceFinish);
2948     }
2949
2950     if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
2951         if (!pureTranslate) {
2952             transform.mapRect(bounds);
2953         }
2954         dirtyLayerUnchecked(bounds, getRegion());
2955     }
2956
2957     drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
2958
2959     return DrawGlInfo::kStatusDrew;
2960 }
2961
2962 status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
2963         float hOffset, float vOffset, SkPaint* paint) {
2964     if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) {
2965         return DrawGlInfo::kStatusDone;
2966     }
2967
2968     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2969     fontRenderer.setFont(paint, mat4::identity());
2970     fontRenderer.setTextureFiltering(true);
2971
2972     int alpha;
2973     SkXfermode::Mode mode;
2974     getAlphaAndMode(paint, &alpha, &mode);
2975
2976     setupDraw();
2977     setupDrawTextGamma(paint);
2978     setupDrawDirtyRegionsDisabled();
2979     setupDrawWithTexture(true);
2980     setupDrawAlpha8Color(paint->getColor(), alpha);
2981     setupDrawColorFilter();
2982     setupDrawShader();
2983     setupDrawBlending(true, mode);
2984     setupDrawProgram();
2985     setupDrawModelView(0.0f, 0.0f, 0.0f, 0.0f, false, true);
2986     // Calling setupDrawTexture with the name 0 will enable the
2987     // uv attributes and increase the texture unit count
2988     // texture binding will be performed by the font renderer as
2989     // needed
2990     setupDrawTexture(0);
2991     setupDrawPureColorUniforms();
2992     setupDrawColorFilterUniforms();
2993     setupDrawShaderUniforms(false);
2994     setupDrawTextGammaUniforms();
2995
2996     const Rect* clip = &mSnapshot->getLocalClip();
2997     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2998
2999     const bool hasActiveLayer = hasLayer();
3000
3001     if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
3002             hOffset, vOffset, hasActiveLayer ? &bounds : NULL)) {
3003         if (hasActiveLayer) {
3004             currentTransform().mapRect(bounds);
3005             dirtyLayerUnchecked(bounds, getRegion());
3006         }
3007     }
3008
3009     return DrawGlInfo::kStatusDrew;
3010 }
3011
3012 status_t OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
3013     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
3014
3015     mCaches.activeTexture(0);
3016
3017     const PathTexture* texture = mCaches.pathCache.get(path, paint);
3018     if (!texture) return DrawGlInfo::kStatusDone;
3019     const AutoTexture autoCleanup(texture);
3020
3021     const float x = texture->left - texture->offset;
3022     const float y = texture->top - texture->offset;
3023
3024     drawPathTexture(texture, x, y, paint);
3025
3026     return DrawGlInfo::kStatusDrew;
3027 }
3028
3029 status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
3030     if (!layer) {
3031         return DrawGlInfo::kStatusDone;
3032     }
3033
3034     mat4* transform = NULL;
3035     if (layer->isTextureLayer()) {
3036         transform = &layer->getTransform();
3037         if (!transform->isIdentity()) {
3038             save(0);
3039             currentTransform().multiply(*transform);
3040         }
3041     }
3042
3043     Rect transformed;
3044     Rect clip;
3045     const bool rejected = quickRejectNoScissor(x, y,
3046             x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip);
3047
3048     if (rejected) {
3049         if (transform && !transform->isIdentity()) {
3050             restore();
3051         }
3052         return DrawGlInfo::kStatusDone;
3053     }
3054
3055     updateLayer(layer, true);
3056
3057     mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clip.contains(transformed));
3058     mCaches.activeTexture(0);
3059
3060     if (CC_LIKELY(!layer->region.isEmpty())) {
3061         SkiaColorFilter* oldFilter = mDrawModifiers.mColorFilter;
3062         mDrawModifiers.mColorFilter = layer->getColorFilter();
3063
3064         if (layer->region.isRect()) {
3065             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
3066                     composeLayerRect(layer, layer->regionRect));
3067         } else if (layer->mesh) {
3068             const float a = getLayerAlpha(layer);
3069             setupDraw();
3070             setupDrawWithTexture();
3071             setupDrawColor(a, a, a, a);
3072             setupDrawColorFilter();
3073             setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false);
3074             setupDrawProgram();
3075             setupDrawPureColorUniforms();
3076             setupDrawColorFilterUniforms();
3077             setupDrawTexture(layer->getTexture());
3078             if (CC_LIKELY(currentTransform().isPureTranslate())) {
3079                 int tx = (int) floorf(x + currentTransform().getTranslateX() + 0.5f);
3080                 int ty = (int) floorf(y + currentTransform().getTranslateY() + 0.5f);
3081
3082                 layer->setFilter(GL_NEAREST);
3083                 setupDrawModelViewTranslate(tx, ty,
3084                         tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
3085             } else {
3086                 layer->setFilter(GL_LINEAR);
3087                 setupDrawModelViewTranslate(x, y,
3088                         x + layer->layer.getWidth(), y + layer->layer.getHeight());
3089             }
3090             setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);
3091
3092             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
3093                     glDrawElements(GL_TRIANGLES, layer->meshElementCount,
3094                             GL_UNSIGNED_SHORT, layer->meshIndices));
3095
3096             finishDrawTexture();
3097
3098 #if DEBUG_LAYERS_AS_REGIONS
3099             drawRegionRects(layer->region);
3100 #endif
3101         }
3102
3103         mDrawModifiers.mColorFilter = oldFilter;
3104
3105         if (layer->debugDrawUpdate) {
3106             layer->debugDrawUpdate = false;
3107             drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
3108                     0x7f00ff00, SkXfermode::kSrcOver_Mode);
3109         }
3110     }
3111     layer->hasDrawnSinceUpdate = true;
3112
3113     if (transform && !transform->isIdentity()) {
3114         restore();
3115     }
3116
3117     return DrawGlInfo::kStatusDrew;
3118 }
3119
3120 ///////////////////////////////////////////////////////////////////////////////
3121 // Shaders
3122 ///////////////////////////////////////////////////////////////////////////////
3123
3124 void OpenGLRenderer::resetShader() {
3125     mDrawModifiers.mShader = NULL;
3126 }
3127
3128 void OpenGLRenderer::setupShader(SkiaShader* shader) {
3129     mDrawModifiers.mShader = shader;
3130     if (mDrawModifiers.mShader) {
3131         mDrawModifiers.mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
3132     }
3133 }
3134
3135 ///////////////////////////////////////////////////////////////////////////////
3136 // Color filters
3137 ///////////////////////////////////////////////////////////////////////////////
3138
3139 void OpenGLRenderer::resetColorFilter() {
3140     mDrawModifiers.mColorFilter = NULL;
3141 }
3142
3143 void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
3144     mDrawModifiers.mColorFilter = filter;
3145 }
3146
3147 ///////////////////////////////////////////////////////////////////////////////
3148 // Drop shadow
3149 ///////////////////////////////////////////////////////////////////////////////
3150
3151 void OpenGLRenderer::resetShadow() {
3152     mDrawModifiers.mHasShadow = false;
3153 }
3154
3155 void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
3156     mDrawModifiers.mHasShadow = true;
3157     mDrawModifiers.mShadowRadius = radius;
3158     mDrawModifiers.mShadowDx = dx;
3159     mDrawModifiers.mShadowDy = dy;
3160     mDrawModifiers.mShadowColor = color;
3161 }
3162
3163 ///////////////////////////////////////////////////////////////////////////////
3164 // Draw filters
3165 ///////////////////////////////////////////////////////////////////////////////
3166
3167 void OpenGLRenderer::resetPaintFilter() {
3168     // when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier
3169     // comparison, see MergingDrawBatch::canMergeWith
3170     mDrawModifiers.mHasDrawFilter = false;
3171     mDrawModifiers.mPaintFilterClearBits = 0;
3172     mDrawModifiers.mPaintFilterSetBits = 0;
3173 }
3174
3175 void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
3176     mDrawModifiers.mHasDrawFilter = true;
3177     mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
3178     mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
3179 }
3180
3181 SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) {
3182     if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) {
3183         return paint;
3184     }
3185
3186     uint32_t flags = paint->getFlags();
3187
3188     mFilteredPaint = *paint;
3189     mFilteredPaint.setFlags((flags & ~mDrawModifiers.mPaintFilterClearBits) |
3190             mDrawModifiers.mPaintFilterSetBits);
3191
3192     return &mFilteredPaint;
3193 }
3194
3195 ///////////////////////////////////////////////////////////////////////////////
3196 // Drawing implementation
3197 ///////////////////////////////////////////////////////////////////////////////
3198
3199 void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
3200         float x, float y, SkPaint* paint) {
3201     if (quickReject(x, y, x + texture->width, y + texture->height)) {
3202         return;
3203     }
3204
3205     int alpha;
3206     SkXfermode::Mode mode;
3207     getAlphaAndMode(paint, &alpha, &mode);
3208
3209     setupDraw();
3210     setupDrawWithTexture(true);
3211     setupDrawAlpha8Color(paint->getColor(), alpha);
3212     setupDrawColorFilter();
3213     setupDrawShader();
3214     setupDrawBlending(true, mode);
3215     setupDrawProgram();
3216     setupDrawModelView(x, y, x + texture->width, y + texture->height);
3217     setupDrawTexture(texture->id);
3218     setupDrawPureColorUniforms();
3219     setupDrawColorFilterUniforms();
3220     setupDrawShaderUniforms();
3221     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
3222
3223     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
3224
3225     finishDrawTexture();
3226 }
3227
3228 // Same values used by Skia
3229 #define kStdStrikeThru_Offset   (-6.0f / 21.0f)
3230 #define kStdUnderline_Offset    (1.0f / 9.0f)
3231 #define kStdUnderline_Thickness (1.0f / 18.0f)
3232
3233 void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length,
3234         float x, float y, SkPaint* paint) {
3235     // Handle underline and strike-through
3236     uint32_t flags = paint->getFlags();
3237     if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
3238         SkPaint paintCopy(*paint);
3239         float underlineWidth = length;
3240         // If length is > 0.0f, we already measured the text for the text alignment
3241         if (length <= 0.0f) {
3242             underlineWidth = paintCopy.measureText(text, bytesCount);
3243         }
3244
3245         if (CC_LIKELY(underlineWidth > 0.0f)) {
3246             const float textSize = paintCopy.getTextSize();
3247             const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
3248
3249             const float left = x;
3250             float top = 0.0f;
3251
3252             int linesCount = 0;
3253             if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
3254             if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
3255
3256             const int pointsCount = 4 * linesCount;
3257             float points[pointsCount];
3258             int currentPoint = 0;
3259
3260             if (flags & SkPaint::kUnderlineText_Flag) {
3261                 top = y + textSize * kStdUnderline_Offset;
3262                 points[currentPoint++] = left;
3263                 points[currentPoint++] = top;
3264                 points[currentPoint++] = left + underlineWidth;
3265                 points[currentPoint++] = top;
3266             }
3267
3268             if (flags & SkPaint::kStrikeThruText_Flag) {
3269                 top = y + textSize * kStdStrikeThru_Offset;
3270                 points[currentPoint++] = left;
3271                 points[currentPoint++] = top;
3272                 points[currentPoint++] = left + underlineWidth;
3273                 points[currentPoint++] = top;
3274             }
3275
3276             paintCopy.setStrokeWidth(strokeWidth);
3277
3278             drawLines(&points[0], pointsCount, &paintCopy);
3279         }
3280     }
3281 }
3282
3283 status_t OpenGLRenderer::drawRects(const float* rects, int count, SkPaint* paint) {
3284     if (mSnapshot->isIgnored()) {
3285         return DrawGlInfo::kStatusDone;
3286     }
3287
3288     int color = paint->getColor();
3289     // If a shader is set, preserve only the alpha
3290     if (mDrawModifiers.mShader) {
3291         color |= 0x00ffffff;
3292     }
3293     SkXfermode::Mode mode = getXfermode(paint->getXfermode());
3294
3295     return drawColorRects(rects, count, color, mode);
3296 }
3297
3298 status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color,
3299         SkXfermode::Mode mode, bool ignoreTransform, bool dirty, bool clip) {
3300     if (count == 0) {
3301         return DrawGlInfo::kStatusDone;
3302     }
3303
3304     float left = FLT_MAX;
3305     float top = FLT_MAX;
3306     float right = FLT_MIN;
3307     float bottom = FLT_MIN;
3308
3309     int vertexCount = 0;
3310     Vertex mesh[count * 6];
3311     Vertex* vertex = mesh;
3312
3313     for (int index = 0; index < count; index += 4) {
3314         float l = rects[index + 0];
3315         float t = rects[index + 1];
3316         float r = rects[index + 2];
3317         float b = rects[index + 3];
3318
3319         Vertex::set(vertex++, l, b);
3320         Vertex::set(vertex++, l, t);
3321         Vertex::set(vertex++, r, t);
3322         Vertex::set(vertex++, l, b);
3323         Vertex::set(vertex++, r, t);
3324         Vertex::set(vertex++, r, b);
3325
3326         vertexCount += 6;
3327
3328         left = fminf(left, l);
3329         top = fminf(top, t);
3330         right = fmaxf(right, r);
3331         bottom = fmaxf(bottom, b);
3332     }
3333
3334     if (clip && quickReject(left, top, right, bottom)) {
3335         return DrawGlInfo::kStatusDone;
3336     }
3337
3338     setupDraw();
3339     setupDrawNoTexture();
3340     setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
3341     setupDrawShader();
3342     setupDrawColorFilter();
3343     setupDrawBlending(mode);
3344     setupDrawProgram();
3345     setupDrawDirtyRegionsDisabled();
3346     setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, ignoreTransform, true);
3347     setupDrawColorUniforms();
3348     setupDrawShaderUniforms();
3349     setupDrawColorFilterUniforms();
3350     setupDrawVertices((GLvoid*) &mesh[0].position[0]);
3351
3352     if (dirty && hasLayer()) {
3353         dirtyLayer(left, top, right, bottom, currentTransform());
3354     }
3355
3356     glDrawArrays(GL_TRIANGLES, 0, vertexCount);
3357
3358     return DrawGlInfo::kStatusDrew;
3359 }
3360
3361 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
3362         int color, SkXfermode::Mode mode, bool ignoreTransform) {
3363     // If a shader is set, preserve only the alpha
3364     if (mDrawModifiers.mShader) {
3365         color |= 0x00ffffff;
3366     }
3367
3368     setupDraw();
3369     setupDrawNoTexture();
3370     setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
3371     setupDrawShader();
3372     setupDrawColorFilter();
3373     setupDrawBlending(mode);
3374     setupDrawProgram();
3375     setupDrawModelView(left, top, right, bottom, ignoreTransform);
3376     setupDrawColorUniforms();
3377     setupDrawShaderUniforms(ignoreTransform);
3378     setupDrawColorFilterUniforms();
3379     setupDrawSimpleMesh();
3380
3381     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
3382 }
3383
3384 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
3385         Texture* texture, SkPaint* paint) {
3386     int alpha;
3387     SkXfermode::Mode mode;
3388     getAlphaAndMode(paint, &alpha, &mode);
3389
3390     texture->setWrap(GL_CLAMP_TO_EDGE, true);
3391
3392     if (CC_LIKELY(currentTransform().isPureTranslate())) {
3393         const float x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f);
3394         const float y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f);
3395
3396         texture->setFilter(GL_NEAREST, true);
3397         drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
3398                 alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL,
3399                 (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, false, true);
3400     } else {
3401         texture->setFilter(FILTER(paint), true);
3402         drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
3403                 texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
3404                 GL_TRIANGLE_STRIP, gMeshCount);
3405     }
3406 }
3407
3408 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
3409         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
3410     drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
3411             (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount);
3412 }
3413
3414 void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
3415         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
3416         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
3417         bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) {
3418
3419     setupDraw();
3420     setupDrawWithTexture();
3421     setupDrawColor(alpha, alpha, alpha, alpha);
3422     setupDrawColorFilter();
3423     setupDrawBlending(blend, mode, swapSrcDst);
3424     setupDrawProgram();
3425     if (!dirty) setupDrawDirtyRegionsDisabled();
3426     if (!ignoreScale) {
3427         setupDrawModelView(left, top, right, bottom, ignoreTransform);
3428     } else {
3429         setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
3430     }
3431     setupDrawTexture(texture);
3432     setupDrawPureColorUniforms();
3433     setupDrawColorFilterUniforms();
3434     setupDrawMesh(vertices, texCoords, vbo);
3435
3436     glDrawArrays(drawMode, 0, elementsCount);
3437
3438     finishDrawTexture();
3439 }
3440
3441 void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
3442         GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
3443         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
3444         bool ignoreTransform, bool ignoreScale, bool dirty) {
3445
3446     setupDraw();
3447     setupDrawWithTexture(true);
3448     if (hasColor) {
3449         setupDrawAlpha8Color(color, alpha);
3450     }
3451     setupDrawColorFilter();
3452     setupDrawShader();
3453     setupDrawBlending(true, mode);
3454     setupDrawProgram();
3455     if (!dirty) setupDrawDirtyRegionsDisabled();
3456     if (!ignoreScale) {
3457         setupDrawModelView(left, top, right, bottom, ignoreTransform);
3458     } else {
3459         setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
3460     }
3461     setupDrawTexture(texture);
3462     setupDrawPureColorUniforms();
3463     setupDrawColorFilterUniforms();
3464     setupDrawShaderUniforms();
3465     setupDrawMesh(vertices, texCoords);
3466
3467     glDrawArrays(drawMode, 0, elementsCount);
3468
3469     finishDrawTexture();
3470 }
3471
3472 void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
3473         ProgramDescription& description, bool swapSrcDst) {
3474     blend = blend || mode != SkXfermode::kSrcOver_Mode;
3475
3476     if (blend) {
3477         // These blend modes are not supported by OpenGL directly and have
3478         // to be implemented using shaders. Since the shader will perform
3479         // the blending, turn blending off here
3480         // If the blend mode cannot be implemented using shaders, fall
3481         // back to the default SrcOver blend mode instead
3482         if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
3483             if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) {
3484                 description.framebufferMode = mode;
3485                 description.swapSrcDst = swapSrcDst;
3486
3487                 if (mCaches.blend) {
3488                     glDisable(GL_BLEND);
3489                     mCaches.blend = false;
3490                 }
3491
3492                 return;
3493             } else {
3494                 mode = SkXfermode::kSrcOver_Mode;
3495             }
3496         }
3497
3498         if (!mCaches.blend) {
3499             glEnable(GL_BLEND);
3500         }
3501
3502         GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
3503         GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
3504
3505         if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
3506             glBlendFunc(sourceMode, destMode);
3507             mCaches.lastSrcMode = sourceMode;
3508             mCaches.lastDstMode = destMode;
3509         }
3510     } else if (mCaches.blend) {
3511         glDisable(GL_BLEND);
3512     }
3513     mCaches.blend = blend;
3514 }
3515
3516 bool OpenGLRenderer::useProgram(Program* program) {
3517     if (!program->isInUse()) {
3518         if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
3519         program->use();
3520         mCaches.currentProgram = program;
3521         return false;
3522     }
3523     return true;
3524 }
3525
3526 void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
3527     TextureVertex* v = &mMeshVertices[0];
3528     TextureVertex::setUV(v++, u1, v1);
3529     TextureVertex::setUV(v++, u2, v1);
3530     TextureVertex::setUV(v++, u1, v2);
3531     TextureVertex::setUV(v++, u2, v2);
3532 }
3533
3534 void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const {
3535     getAlphaAndModeDirect(paint, alpha,  mode);
3536     if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
3537         // if drawing a layer, ignore the paint's alpha
3538         *alpha = mDrawModifiers.mOverrideLayerAlpha * 255;
3539     }
3540     *alpha *= mSnapshot->alpha;
3541 }
3542
3543 float OpenGLRenderer::getLayerAlpha(Layer* layer) const {
3544     float alpha;
3545     if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
3546         alpha = mDrawModifiers.mOverrideLayerAlpha;
3547     } else {
3548         alpha = layer->getAlpha() / 255.0f;
3549     }
3550     return alpha * mSnapshot->alpha;
3551 }
3552
3553 }; // namespace uirenderer
3554 }; // namespace android