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