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