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 #include "OpenGLRenderer.h"
18 
19 #include "DeferredDisplayList.h"
20 #include "GammaFontRenderer.h"
21 #include "Glop.h"
22 #include "GlopBuilder.h"
23 #include "Patch.h"
24 #include "PathTessellator.h"
25 #include "Properties.h"
26 #include "RenderNode.h"
27 #include "renderstate/MeshState.h"
28 #include "renderstate/RenderState.h"
29 #include "ShadowTessellator.h"
30 #include "SkiaShader.h"
31 #include "Vector.h"
32 #include "VertexBuffer.h"
33 #include "utils/GLUtils.h"
34 #include "utils/PaintUtils.h"
35 #include "utils/TraceUtils.h"
36 
37 #include <stdlib.h>
38 #include <stdint.h>
39 #include <sys/types.h>
40 
41 #include <SkCanvas.h>
42 #include <SkColor.h>
43 #include <SkPathOps.h>
44 #include <SkShader.h>
45 #include <SkTypeface.h>
46 
47 #include <utils/Log.h>
48 #include <utils/StopWatch.h>
49 
50 #include <private/hwui/DrawGlInfo.h>
51 
52 #include <ui/Rect.h>
53 
54 #if DEBUG_DETAILED_EVENTS
55     #define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__)
56 #else
57     #define EVENT_LOGD(...)
58 #endif
59 
60 namespace android {
61 namespace uirenderer {
62 
63 ///////////////////////////////////////////////////////////////////////////////
64 // Constructors/destructor
65 ///////////////////////////////////////////////////////////////////////////////
66 
OpenGLRenderer(RenderState & renderState)67 OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
68         : mState(*this)
69         , mCaches(Caches::getInstance())
70         , mRenderState(renderState)
71         , mFrameStarted(false)
72         , mScissorOptimizationDisabled(false)
73         , mSuppressTiling(false)
74         , mFirstFrameAfterResize(true)
75         , mDirty(false)
76         , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN})
77         , mLightRadius(FLT_MIN)
78         , mAmbientShadowAlpha(0)
79         , mSpotShadowAlpha(0) {
80 }
81 
~OpenGLRenderer()82 OpenGLRenderer::~OpenGLRenderer() {
83     // The context has already been destroyed at this point, do not call
84     // GL APIs. All GL state should be kept in Caches.h
85 }
86 
initProperties()87 void OpenGLRenderer::initProperties() {
88     char property[PROPERTY_VALUE_MAX];
89     if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) {
90         mScissorOptimizationDisabled = !strcasecmp(property, "true");
91         INIT_LOGD("  Scissor optimization %s",
92                 mScissorOptimizationDisabled ? "disabled" : "enabled");
93     } else {
94         INIT_LOGD("  Scissor optimization enabled");
95     }
96 }
97 
initLight(float lightRadius,uint8_t ambientShadowAlpha,uint8_t spotShadowAlpha)98 void OpenGLRenderer::initLight(float lightRadius, uint8_t ambientShadowAlpha,
99         uint8_t spotShadowAlpha) {
100     mLightRadius = lightRadius;
101     mAmbientShadowAlpha = ambientShadowAlpha;
102     mSpotShadowAlpha = spotShadowAlpha;
103 }
104 
setLightCenter(const Vector3 & lightCenter)105 void OpenGLRenderer::setLightCenter(const Vector3& lightCenter) {
106     mLightCenter = lightCenter;
107 }
108 
109 ///////////////////////////////////////////////////////////////////////////////
110 // Setup
111 ///////////////////////////////////////////////////////////////////////////////
112 
onViewportInitialized()113 void OpenGLRenderer::onViewportInitialized() {
114     glDisable(GL_DITHER);
115     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
116     mFirstFrameAfterResize = true;
117 }
118 
setupFrameState(float left,float top,float right,float bottom,bool opaque)119 void OpenGLRenderer::setupFrameState(float left, float top,
120         float right, float bottom, bool opaque) {
121     mCaches.clearGarbage();
122     mState.initializeSaveStack(left, top, right, bottom, mLightCenter);
123     mOpaque = opaque;
124     mTilingClip.set(left, top, right, bottom);
125 }
126 
startFrame()127 void OpenGLRenderer::startFrame() {
128     if (mFrameStarted) return;
129     mFrameStarted = true;
130 
131     mState.setDirtyClip(true);
132 
133     discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
134 
135     mRenderState.setViewport(mState.getWidth(), mState.getHeight());
136 
137     // Functors break the tiling extension in pretty spectacular ways
138     // This ensures we don't use tiling when a functor is going to be
139     // invoked during the frame
140     mSuppressTiling = mCaches.hasRegisteredFunctors()
141             || mFirstFrameAfterResize;
142     mFirstFrameAfterResize = false;
143 
144     startTilingCurrentClip(true);
145 
146     debugOverdraw(true, true);
147 
148     clear(mTilingClip.left, mTilingClip.top,
149             mTilingClip.right, mTilingClip.bottom, mOpaque);
150 }
151 
prepareDirty(float left,float top,float right,float bottom,bool opaque)152 void OpenGLRenderer::prepareDirty(float left, float top,
153         float right, float bottom, bool opaque) {
154 
155     setupFrameState(left, top, right, bottom, opaque);
156 
157     // Layer renderers will start the frame immediately
158     // The framebuffer renderer will first defer the display list
159     // for each layer and wait until the first drawing command
160     // to start the frame
161     if (currentSnapshot()->fbo == 0) {
162         mRenderState.blend().syncEnabled();
163         updateLayers();
164     } else {
165         startFrame();
166     }
167 }
168 
discardFramebuffer(float left,float top,float right,float bottom)169 void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
170     // If we know that we are going to redraw the entire framebuffer,
171     // perform a discard to let the driver know we don't need to preserve
172     // the back buffer for this frame.
173     if (mCaches.extensions().hasDiscardFramebuffer() &&
174             left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) {
175         const bool isFbo = getTargetFbo() == 0;
176         const GLenum attachments[] = {
177                 isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
178                 isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT };
179         glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
180     }
181 }
182 
clear(float left,float top,float right,float bottom,bool opaque)183 void OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
184     if (!opaque) {
185         mRenderState.scissor().setEnabled(true);
186         mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top);
187         glClear(GL_COLOR_BUFFER_BIT);
188         mDirty = true;
189         return;
190     }
191 
192     mRenderState.scissor().reset();
193 }
194 
startTilingCurrentClip(bool opaque,bool expand)195 void OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) {
196     if (!mSuppressTiling) {
197         const Snapshot* snapshot = currentSnapshot();
198 
199         const Rect* clip = &mTilingClip;
200         if (snapshot->flags & Snapshot::kFlagFboTarget) {
201             clip = &(snapshot->layer->clipRect);
202         }
203 
204         startTiling(*clip, getViewportHeight(), opaque, expand);
205     }
206 }
207 
startTiling(const Rect & clip,int windowHeight,bool opaque,bool expand)208 void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque, bool expand) {
209     if (!mSuppressTiling) {
210         if(expand) {
211             // Expand the startTiling region by 1
212             int leftNotZero = (clip.left > 0) ? 1 : 0;
213             int topNotZero = (windowHeight - clip.bottom > 0) ? 1 : 0;
214 
215             mCaches.startTiling(
216                 clip.left - leftNotZero,
217                 windowHeight - clip.bottom - topNotZero,
218                 clip.right - clip.left + leftNotZero + 1,
219                 clip.bottom - clip.top + topNotZero + 1,
220                 opaque);
221         } else {
222             mCaches.startTiling(clip.left, windowHeight - clip.bottom,
223                 clip.right - clip.left, clip.bottom - clip.top, opaque);
224         }
225     }
226 }
227 
endTiling()228 void OpenGLRenderer::endTiling() {
229     if (!mSuppressTiling) mCaches.endTiling();
230 }
231 
finish()232 bool OpenGLRenderer::finish() {
233     renderOverdraw();
234     endTiling();
235     mTempPaths.clear();
236 
237     // When finish() is invoked on FBO 0 we've reached the end
238     // of the current frame
239     if (getTargetFbo() == 0) {
240         mCaches.pathCache.trim();
241         mCaches.tessellationCache.trim();
242     }
243 
244     if (!suppressErrorChecks()) {
245 #if DEBUG_OPENGL
246         GLUtils::dumpGLErrors();
247 #endif
248 
249 #if DEBUG_MEMORY_USAGE
250         mCaches.dumpMemoryUsage();
251 #else
252         if (Properties::debugLevel & kDebugMemory) {
253             mCaches.dumpMemoryUsage();
254         }
255 #endif
256     }
257 
258     mFrameStarted = false;
259 
260     return reportAndClearDirty();
261 }
262 
resumeAfterLayer()263 void OpenGLRenderer::resumeAfterLayer() {
264     mRenderState.setViewport(getViewportWidth(), getViewportHeight());
265     mRenderState.bindFramebuffer(currentSnapshot()->fbo);
266     debugOverdraw(true, false);
267 
268     mRenderState.scissor().reset();
269     dirtyClip();
270 }
271 
callDrawGLFunction(Functor * functor,Rect & dirty)272 void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
273     if (mState.currentlyIgnored()) return;
274 
275     Rect clip(mState.currentClipRect());
276     clip.snapToPixelBoundaries();
277 
278     // Since we don't know what the functor will draw, let's dirty
279     // the entire clip region
280     if (hasLayer()) {
281         dirtyLayerUnchecked(clip, getRegion());
282     }
283 
284     DrawGlInfo info;
285     info.clipLeft = clip.left;
286     info.clipTop = clip.top;
287     info.clipRight = clip.right;
288     info.clipBottom = clip.bottom;
289     info.isLayer = hasLayer();
290     info.width = getViewportWidth();
291     info.height = getViewportHeight();
292     currentTransform()->copyTo(&info.transform[0]);
293 
294     bool prevDirtyClip = mState.getDirtyClip();
295     // setup GL state for functor
296     if (mState.getDirtyClip()) {
297         setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
298     }
299     if (mRenderState.scissor().setEnabled(true) || prevDirtyClip) {
300         setScissorFromClip();
301     }
302 
303     mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info);
304     // Scissor may have been modified, reset dirty clip
305     dirtyClip();
306 
307     mDirty = true;
308 }
309 
310 ///////////////////////////////////////////////////////////////////////////////
311 // Debug
312 ///////////////////////////////////////////////////////////////////////////////
313 
eventMarkDEBUG(const char * fmt,...) const314 void OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const {
315 #if DEBUG_DETAILED_EVENTS
316     const int BUFFER_SIZE = 256;
317     va_list ap;
318     char buf[BUFFER_SIZE];
319 
320     va_start(ap, fmt);
321     vsnprintf(buf, BUFFER_SIZE, fmt, ap);
322     va_end(ap);
323 
324     eventMark(buf);
325 #endif
326 }
327 
328 
eventMark(const char * name) const329 void OpenGLRenderer::eventMark(const char* name) const {
330     mCaches.eventMark(0, name);
331 }
332 
startMark(const char * name) const333 void OpenGLRenderer::startMark(const char* name) const {
334     mCaches.startMark(0, name);
335 }
336 
endMark() const337 void OpenGLRenderer::endMark() const {
338     mCaches.endMark();
339 }
340 
debugOverdraw(bool enable,bool clear)341 void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
342     mRenderState.debugOverdraw(enable, clear);
343 }
344 
renderOverdraw()345 void OpenGLRenderer::renderOverdraw() {
346     if (Properties::debugOverdraw && getTargetFbo() == 0) {
347         const Rect* clip = &mTilingClip;
348 
349         mRenderState.scissor().setEnabled(true);
350         mRenderState.scissor().set(clip->left,
351                 mState.firstSnapshot()->getViewportHeight() - clip->bottom,
352                 clip->right - clip->left,
353                 clip->bottom - clip->top);
354 
355         // 1x overdraw
356         mRenderState.stencil().enableDebugTest(2);
357         drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
358 
359         // 2x overdraw
360         mRenderState.stencil().enableDebugTest(3);
361         drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
362 
363         // 3x overdraw
364         mRenderState.stencil().enableDebugTest(4);
365         drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
366 
367         // 4x overdraw and higher
368         mRenderState.stencil().enableDebugTest(4, true);
369         drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
370 
371         mRenderState.stencil().disable();
372     }
373 }
374 
375 ///////////////////////////////////////////////////////////////////////////////
376 // Layers
377 ///////////////////////////////////////////////////////////////////////////////
378 
updateLayer(Layer * layer,bool inFrame)379 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
380     if (layer->deferredUpdateScheduled && layer->renderer
381             && layer->renderNode.get() && layer->renderNode->isRenderable()) {
382 
383         if (inFrame) {
384             endTiling();
385             debugOverdraw(false, false);
386         }
387 
388         if (CC_UNLIKELY(inFrame || Properties::drawDeferDisabled)) {
389             layer->render(*this);
390         } else {
391             layer->defer(*this);
392         }
393 
394         if (inFrame) {
395             resumeAfterLayer();
396             startTilingCurrentClip();
397         }
398 
399         layer->debugDrawUpdate = Properties::debugLayersUpdates;
400         layer->hasDrawnSinceUpdate = false;
401 
402         return true;
403     }
404 
405     return false;
406 }
407 
updateLayers()408 void OpenGLRenderer::updateLayers() {
409     // If draw deferring is enabled this method will simply defer
410     // the display list of each individual layer. The layers remain
411     // in the layer updates list which will be cleared by flushLayers().
412     int count = mLayerUpdates.size();
413     if (count > 0) {
414         if (CC_UNLIKELY(Properties::drawDeferDisabled)) {
415             startMark("Layer Updates");
416         } else {
417             startMark("Defer Layer Updates");
418         }
419 
420         // Note: it is very important to update the layers in order
421         for (int i = 0; i < count; i++) {
422             Layer* layer = mLayerUpdates.itemAt(i).get();
423             updateLayer(layer, false);
424         }
425 
426         if (CC_UNLIKELY(Properties::drawDeferDisabled)) {
427             mLayerUpdates.clear();
428             mRenderState.bindFramebuffer(getTargetFbo());
429         }
430         endMark();
431     }
432 }
433 
flushLayers()434 void OpenGLRenderer::flushLayers() {
435     int count = mLayerUpdates.size();
436     if (count > 0) {
437         startMark("Apply Layer Updates");
438 
439         // Note: it is very important to update the layers in order
440         for (int i = 0; i < count; i++) {
441             mLayerUpdates.itemAt(i)->flush();
442         }
443 
444         mLayerUpdates.clear();
445         mRenderState.bindFramebuffer(getTargetFbo());
446 
447         endMark();
448     }
449 }
450 
pushLayerUpdate(Layer * layer)451 void OpenGLRenderer::pushLayerUpdate(Layer* layer) {
452     if (layer) {
453         // Make sure we don't introduce duplicates.
454         // SortedVector would do this automatically but we need to respect
455         // the insertion order. The linear search is not an issue since
456         // this list is usually very short (typically one item, at most a few)
457         for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
458             if (mLayerUpdates.itemAt(i) == layer) {
459                 return;
460             }
461         }
462         mLayerUpdates.push_back(layer);
463     }
464 }
465 
cancelLayerUpdate(Layer * layer)466 void OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
467     if (layer) {
468         for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
469             if (mLayerUpdates.itemAt(i) == layer) {
470                 mLayerUpdates.removeAt(i);
471                 break;
472             }
473         }
474     }
475 }
476 
flushLayerUpdates()477 void OpenGLRenderer::flushLayerUpdates() {
478     ATRACE_NAME("Update HW Layers");
479     mRenderState.blend().syncEnabled();
480     updateLayers();
481     flushLayers();
482     // Wait for all the layer updates to be executed
483     glFinish();
484 }
485 
markLayersAsBuildLayers()486 void OpenGLRenderer::markLayersAsBuildLayers() {
487     for (size_t i = 0; i < mLayerUpdates.size(); i++) {
488         mLayerUpdates[i]->wasBuildLayered = true;
489     }
490 }
491 
492 ///////////////////////////////////////////////////////////////////////////////
493 // State management
494 ///////////////////////////////////////////////////////////////////////////////
495 
onSnapshotRestored(const Snapshot & removed,const Snapshot & restored)496 void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
497     bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
498     bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
499     bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
500 
501     if (restoreViewport) {
502         mRenderState.setViewport(getViewportWidth(), getViewportHeight());
503     }
504 
505     if (restoreClip) {
506         dirtyClip();
507     }
508 
509     if (restoreLayer) {
510         endMark(); // Savelayer
511         ATRACE_END(); // SaveLayer
512         startMark("ComposeLayer");
513         composeLayer(removed, restored);
514         endMark();
515     }
516 }
517 
518 ///////////////////////////////////////////////////////////////////////////////
519 // Layers
520 ///////////////////////////////////////////////////////////////////////////////
521 
saveLayer(float left,float top,float right,float bottom,const SkPaint * paint,int flags,const SkPath * convexMask)522 int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
523         const SkPaint* paint, int flags, const SkPath* convexMask) {
524     // force matrix/clip isolation for layer
525     flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
526 
527     const int count = mState.saveSnapshot(flags);
528 
529     if (!mState.currentlyIgnored()) {
530         createLayer(left, top, right, bottom, paint, flags, convexMask);
531     }
532 
533     return count;
534 }
535 
calculateLayerBoundsAndClip(Rect & bounds,Rect & clip,bool fboLayer)536 void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) {
537     const Rect untransformedBounds(bounds);
538 
539     currentTransform()->mapRect(bounds);
540 
541     // Layers only make sense if they are in the framebuffer's bounds
542     if (bounds.intersect(mState.currentClipRect())) {
543         // We cannot work with sub-pixels in this case
544         bounds.snapToPixelBoundaries();
545 
546         // When the layer is not an FBO, we may use glCopyTexImage so we
547         // need to make sure the layer does not extend outside the bounds
548         // of the framebuffer
549         const Snapshot& previous = *(currentSnapshot()->previous);
550         Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight());
551         if (!bounds.intersect(previousViewport)) {
552             bounds.setEmpty();
553         } else if (fboLayer) {
554             clip.set(bounds);
555             mat4 inverse;
556             inverse.loadInverse(*currentTransform());
557             inverse.mapRect(clip);
558             clip.snapToPixelBoundaries();
559             if (clip.intersect(untransformedBounds)) {
560                 clip.translate(-untransformedBounds.left, -untransformedBounds.top);
561                 bounds.set(untransformedBounds);
562             } else {
563                 clip.setEmpty();
564             }
565         }
566     } else {
567         bounds.setEmpty();
568     }
569 }
570 
updateSnapshotIgnoreForLayer(const Rect & bounds,const Rect & clip,bool fboLayer,int alpha)571 void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip,
572         bool fboLayer, int alpha) {
573     if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
574             bounds.getHeight() > mCaches.maxTextureSize ||
575             (fboLayer && clip.isEmpty())) {
576         writableSnapshot()->empty = fboLayer;
577     } else {
578         writableSnapshot()->invisible = writableSnapshot()->invisible || (alpha <= 0 && fboLayer);
579     }
580 }
581 
saveLayerDeferred(float left,float top,float right,float bottom,const SkPaint * paint,int flags)582 int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
583         const SkPaint* paint, int flags) {
584     const int count = mState.saveSnapshot(flags);
585 
586     if (!mState.currentlyIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
587         // initialize the snapshot as though it almost represents an FBO layer so deferred draw
588         // operations will be able to store and restore the current clip and transform info, and
589         // quick rejection will be correct (for display lists)
590 
591         Rect bounds(left, top, right, bottom);
592         Rect clip;
593         calculateLayerBoundsAndClip(bounds, clip, true);
594         updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
595 
596         if (!mState.currentlyIgnored()) {
597             writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
598             writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
599             writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
600             writableSnapshot()->roundRectClipState = nullptr;
601         }
602     }
603 
604     return count;
605 }
606 
607 /**
608  * Layers are viewed by Skia are slightly different than layers in image editing
609  * programs (for instance.) When a layer is created, previously created layers
610  * and the frame buffer still receive every drawing command. For instance, if a
611  * layer is created and a shape intersecting the bounds of the layers and the
612  * framebuffer is draw, the shape will be drawn on both (unless the layer was
613  * created with the SkCanvas::kClipToLayer_SaveFlag flag.)
614  *
615  * A way to implement layers is to create an FBO for each layer, backed by an RGBA
616  * texture. Unfortunately, this is inefficient as it requires every primitive to
617  * be drawn n + 1 times, where n is the number of active layers. In practice this
618  * means, for every primitive:
619  *   - Switch active frame buffer
620  *   - Change viewport, clip and projection matrix
621  *   - Issue the drawing
622  *
623  * Switching rendering target n + 1 times per drawn primitive is extremely costly.
624  * To avoid this, layers are implemented in a different way here, at least in the
625  * general case. FBOs are used, as an optimization, when the "clip to layer" flag
626  * is set. When this flag is set we can redirect all drawing operations into a
627  * single FBO.
628  *
629  * This implementation relies on the frame buffer being at least RGBA 8888. When
630  * a layer is created, only a texture is created, not an FBO. The content of the
631  * frame buffer contained within the layer's bounds is copied into this texture
632  * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
633  * buffer and drawing continues as normal. This technique therefore treats the
634  * frame buffer as a scratch buffer for the layers.
635  *
636  * To compose the layers back onto the frame buffer, each layer texture
637  * (containing the original frame buffer data) is drawn as a simple quad over
638  * the frame buffer. The trick is that the quad is set as the composition
639  * destination in the blending equation, and the frame buffer becomes the source
640  * of the composition.
641  *
642  * Drawing layers with an alpha value requires an extra step before composition.
643  * An empty quad is drawn over the layer's region in the frame buffer. This quad
644  * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
645  * quad is used to multiply the colors in the frame buffer. This is achieved by
646  * changing the GL blend functions for the GL_FUNC_ADD blend equation to
647  * GL_ZERO, GL_SRC_ALPHA.
648  *
649  * Because glCopyTexImage2D() can be slow, an alternative implementation might
650  * be use to draw a single clipped layer. The implementation described above
651  * is correct in every case.
652  *
653  * (1) The frame buffer is actually not cleared right away. To allow the GPU
654  *     to potentially optimize series of calls to glCopyTexImage2D, the frame
655  *     buffer is left untouched until the first drawing operation. Only when
656  *     something actually gets drawn are the layers regions cleared.
657  */
createLayer(float left,float top,float right,float bottom,const SkPaint * paint,int flags,const SkPath * convexMask)658 bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
659         const SkPaint* paint, int flags, const SkPath* convexMask) {
660     LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
661     LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
662 
663     const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
664 
665     // Window coordinates of the layer
666     Rect clip;
667     Rect bounds(left, top, right, bottom);
668     calculateLayerBoundsAndClip(bounds, clip, fboLayer);
669     updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
670 
671     // Bail out if we won't draw in this snapshot
672     if (mState.currentlyIgnored()) {
673         return false;
674     }
675 
676     mCaches.textureState().activateTexture(0);
677     Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
678     if (!layer) {
679         return false;
680     }
681 
682     layer->setPaint(paint);
683     layer->layer.set(bounds);
684     layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
685             bounds.getWidth() / float(layer->getWidth()), 0.0f);
686 
687     layer->setBlend(true);
688     layer->setDirty(false);
689     layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
690 
691     // Save the layer in the snapshot
692     writableSnapshot()->flags |= Snapshot::kFlagIsLayer;
693     writableSnapshot()->layer = layer;
694 
695     ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
696             fboLayer ? "" : "unclipped ",
697             layer->getWidth(), layer->getHeight());
698     startMark("SaveLayer");
699     if (fboLayer) {
700         return createFboLayer(layer, bounds, clip);
701     } else {
702         // Copy the framebuffer into the layer
703         layer->bindTexture();
704         if (!bounds.isEmpty()) {
705             if (layer->isEmpty()) {
706                 // Workaround for some GL drivers. When reading pixels lying outside
707                 // of the window we should get undefined values for those pixels.
708                 // Unfortunately some drivers will turn the entire target texture black
709                 // when reading outside of the window.
710                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(),
711                         0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
712                 layer->setEmpty(false);
713             }
714 
715             glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
716                     bounds.left, getViewportHeight() - bounds.bottom,
717                     bounds.getWidth(), bounds.getHeight());
718 
719             // Enqueue the buffer coordinates to clear the corresponding region later
720             mLayers.push_back(Rect(bounds));
721         }
722     }
723 
724     return true;
725 }
726 
createFboLayer(Layer * layer,Rect & bounds,Rect & clip)727 bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
728     layer->clipRect.set(clip);
729     layer->setFbo(mCaches.fboCache.get());
730 
731     writableSnapshot()->region = &writableSnapshot()->layer->region;
732     writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
733     writableSnapshot()->fbo = layer->getFbo();
734     writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
735     writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
736     writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
737     writableSnapshot()->roundRectClipState = nullptr;
738 
739     endTiling();
740     debugOverdraw(false, false);
741     // Bind texture to FBO
742     mRenderState.bindFramebuffer(layer->getFbo());
743     layer->bindTexture();
744 
745     // Initialize the texture if needed
746     if (layer->isEmpty()) {
747         layer->allocateTexture();
748         layer->setEmpty(false);
749     }
750 
751     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
752             layer->getTextureId(), 0);
753 
754     // Expand the startTiling region by 1
755     startTilingCurrentClip(true, true);
756 
757     // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
758     mRenderState.scissor().setEnabled(true);
759     mRenderState.scissor().set(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
760             clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
761     glClear(GL_COLOR_BUFFER_BIT);
762 
763     dirtyClip();
764 
765     // Change the ortho projection
766     mRenderState.setViewport(bounds.getWidth(), bounds.getHeight());
767     return true;
768 }
769 
770 /**
771  * Read the documentation of createLayer() before doing anything in this method.
772  */
composeLayer(const Snapshot & removed,const Snapshot & restored)773 void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) {
774     if (!removed.layer) {
775         ALOGE("Attempting to compose a layer that does not exist");
776         return;
777     }
778 
779     Layer* layer = removed.layer;
780     const Rect& rect = layer->layer;
781     const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
782 
783     bool clipRequired = false;
784     mState.calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
785             &clipRequired, nullptr, false); // safely ignore return, should never be rejected
786     mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
787 
788     if (fboLayer) {
789         endTiling();
790 
791         // Detach the texture from the FBO
792         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
793 
794         layer->removeFbo(false);
795 
796         // Unbind current FBO and restore previous one
797         mRenderState.bindFramebuffer(restored.fbo);
798         debugOverdraw(true, false);
799 
800         startTilingCurrentClip();
801     }
802 
803     if (!fboLayer && layer->getAlpha() < 255) {
804         SkPaint layerPaint;
805         layerPaint.setAlpha(layer->getAlpha());
806         layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
807         layerPaint.setColorFilter(layer->getColorFilter());
808 
809         drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true);
810         // Required below, composeLayerRect() will divide by 255
811         layer->setAlpha(255);
812     }
813 
814     mRenderState.meshState().unbindMeshBuffer();
815 
816     mCaches.textureState().activateTexture(0);
817 
818     // When the layer is stored in an FBO, we can save a bit of fillrate by
819     // drawing only the dirty region
820     if (fboLayer) {
821         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);
822         composeLayerRegion(layer, rect);
823     } else if (!rect.isEmpty()) {
824         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
825 
826         save(0);
827         // the layer contains screen buffer content that shouldn't be alpha modulated
828         // (and any necessary alpha modulation was handled drawing into the layer)
829         writableSnapshot()->alpha = 1.0f;
830         composeLayerRectSwapped(layer, rect);
831         restore();
832     }
833 
834     dirtyClip();
835 
836     // Failing to add the layer to the cache should happen only if the layer is too large
837     layer->setConvexMask(nullptr);
838     if (!mCaches.layerCache.put(layer)) {
839         LAYER_LOGD("Deleting layer");
840         layer->decStrong(nullptr);
841     }
842 }
843 
drawTextureLayer(Layer * layer,const Rect & rect)844 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
845     const bool tryToSnap = !layer->getForceFilter()
846             && layer->getWidth() == (uint32_t) rect.getWidth()
847             && layer->getHeight() == (uint32_t) rect.getHeight();
848     Glop glop;
849     GlopBuilder(mRenderState, mCaches, &glop)
850             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
851             .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
852             .setFillTextureLayer(*layer, getLayerAlpha(layer))
853             .setTransform(*currentSnapshot(), TransformFlags::None)
854             .setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect)
855             .build();
856     renderGlop(glop);
857 }
858 
composeLayerRectSwapped(Layer * layer,const Rect & rect)859 void OpenGLRenderer::composeLayerRectSwapped(Layer* layer, const Rect& rect) {
860     Glop glop;
861     GlopBuilder(mRenderState, mCaches, &glop)
862             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
863             .setMeshTexturedUvQuad(nullptr, layer->texCoords)
864             .setFillLayer(layer->getTexture(), layer->getColorFilter(),
865                     getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::Swap)
866             .setTransform(*currentSnapshot(), TransformFlags::MeshIgnoresCanvasTransform)
867             .setModelViewMapUnitToRect(rect)
868             .build();
869     renderGlop(glop);
870 }
871 
composeLayerRect(Layer * layer,const Rect & rect)872 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect) {
873     if (layer->isTextureLayer()) {
874         EVENT_LOGD("composeTextureLayerRect");
875         drawTextureLayer(layer, rect);
876     } else {
877         EVENT_LOGD("composeHardwareLayerRect");
878 
879         const bool tryToSnap = layer->getWidth() == static_cast<uint32_t>(rect.getWidth())
880                 && layer->getHeight() == static_cast<uint32_t>(rect.getHeight());
881         Glop glop;
882         GlopBuilder(mRenderState, mCaches, &glop)
883                 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
884                 .setMeshTexturedUvQuad(nullptr, layer->texCoords)
885                 .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
886                 .setTransform(*currentSnapshot(), TransformFlags::None)
887                 .setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect)
888                 .build();
889         renderGlop(glop);
890     }
891 }
892 
893 /**
894  * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
895  * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
896  * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
897  * by saveLayer's restore
898  */
899 #define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) { \
900         DRAW_COMMAND; \
901         if (CC_UNLIKELY(Properties::debugOverdraw && getTargetFbo() == 0 && COND)) { \
902             glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); \
903             DRAW_COMMAND; \
904             glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); \
905         } \
906     }
907 
908 #define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
909 
910 // This class is purely for inspection. It inherits from SkShader, but Skia does not know how to
911 // use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque.
912 class LayerShader : public SkShader {
913 public:
LayerShader(Layer * layer,const SkMatrix * localMatrix)914     LayerShader(Layer* layer, const SkMatrix* localMatrix)
915     : INHERITED(localMatrix)
916     , mLayer(layer) {
917     }
918 
asACustomShader(void ** data) const919     virtual bool asACustomShader(void** data) const override {
920         if (data) {
921             *data = static_cast<void*>(mLayer);
922         }
923         return true;
924     }
925 
isOpaque() const926     virtual bool isOpaque() const override {
927         return !mLayer->isBlend();
928     }
929 
930 protected:
shadeSpan(int x,int y,SkPMColor[],int count)931     virtual void shadeSpan(int x, int y, SkPMColor[], int count) {
932         LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
933     }
934 
flatten(SkWriteBuffer &) const935     virtual void flatten(SkWriteBuffer&) const override {
936         LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
937     }
938 
getFactory() const939     virtual Factory getFactory() const override {
940         LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
941         return nullptr;
942     }
943 private:
944     // Unowned.
945     Layer* mLayer;
946     typedef SkShader INHERITED;
947 };
948 
composeLayerRegion(Layer * layer,const Rect & rect)949 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
950     if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
951 
952     if (layer->getConvexMask()) {
953         save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
954 
955         // clip to the area of the layer the mask can be larger
956         clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
957 
958         SkPaint paint;
959         paint.setAntiAlias(true);
960         paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
961 
962         // create LayerShader to map SaveLayer content into subsequent draw
963         SkMatrix shaderMatrix;
964         shaderMatrix.setTranslate(rect.left, rect.bottom);
965         shaderMatrix.preScale(1, -1);
966         LayerShader layerShader(layer, &shaderMatrix);
967         paint.setShader(&layerShader);
968 
969         // Since the drawing primitive is defined in local drawing space,
970         // we don't need to modify the draw matrix
971         const SkPath* maskPath = layer->getConvexMask();
972         DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
973 
974         paint.setShader(nullptr);
975         restore();
976 
977         return;
978     }
979 
980     if (layer->region.isRect()) {
981         layer->setRegionAsRect();
982 
983         DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
984 
985         layer->region.clear();
986         return;
987     }
988 
989     EVENT_LOGD("composeLayerRegion");
990     // standard Region based draw
991     size_t count;
992     const android::Rect* rects;
993     Region safeRegion;
994     if (CC_LIKELY(hasRectToRectTransform())) {
995         rects = layer->region.getArray(&count);
996     } else {
997         safeRegion = Region::createTJunctionFreeRegion(layer->region);
998         rects = safeRegion.getArray(&count);
999     }
1000 
1001     const float texX = 1.0f / float(layer->getWidth());
1002     const float texY = 1.0f / float(layer->getHeight());
1003     const float height = rect.getHeight();
1004 
1005     TextureVertex quadVertices[count * 4];
1006     TextureVertex* mesh = &quadVertices[0];
1007     for (size_t i = 0; i < count; i++) {
1008         const android::Rect* r = &rects[i];
1009 
1010         const float u1 = r->left * texX;
1011         const float v1 = (height - r->top) * texY;
1012         const float u2 = r->right * texX;
1013         const float v2 = (height - r->bottom) * texY;
1014 
1015         // TODO: Reject quads outside of the clip
1016         TextureVertex::set(mesh++, r->left, r->top, u1, v1);
1017         TextureVertex::set(mesh++, r->right, r->top, u2, v1);
1018         TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
1019         TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
1020     }
1021     Rect modelRect = Rect(rect.getWidth(), rect.getHeight());
1022     Glop glop;
1023     GlopBuilder(mRenderState, mCaches, &glop)
1024             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1025             .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6)
1026             .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
1027             .setTransform(*currentSnapshot(),  TransformFlags::None)
1028             .setModelViewOffsetRectSnap(rect.left, rect.top, modelRect)
1029             .build();
1030     DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
1031 
1032 #if DEBUG_LAYERS_AS_REGIONS
1033     drawRegionRectsDebug(layer->region);
1034 #endif
1035 
1036     layer->region.clear();
1037 }
1038 
1039 #if DEBUG_LAYERS_AS_REGIONS
drawRegionRectsDebug(const Region & region)1040 void OpenGLRenderer::drawRegionRectsDebug(const Region& region) {
1041     size_t count;
1042     const android::Rect* rects = region.getArray(&count);
1043 
1044     uint32_t colors[] = {
1045             0x7fff0000, 0x7f00ff00,
1046             0x7f0000ff, 0x7fff00ff,
1047     };
1048 
1049     int offset = 0;
1050     int32_t top = rects[0].top;
1051 
1052     for (size_t i = 0; i < count; i++) {
1053         if (top != rects[i].top) {
1054             offset ^= 0x2;
1055             top = rects[i].top;
1056         }
1057 
1058         SkPaint paint;
1059         paint.setColor(colors[offset + (i & 0x1)]);
1060         Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
1061         drawColorRect(r.left, r.top, r.right, r.bottom, paint);
1062     }
1063 }
1064 #endif
1065 
drawRegionRects(const SkRegion & region,const SkPaint & paint,bool dirty)1066 void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) {
1067     Vector<float> rects;
1068 
1069     SkRegion::Iterator it(region);
1070     while (!it.done()) {
1071         const SkIRect& r = it.rect();
1072         rects.push(r.fLeft);
1073         rects.push(r.fTop);
1074         rects.push(r.fRight);
1075         rects.push(r.fBottom);
1076         it.next();
1077     }
1078 
1079     drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false);
1080 }
1081 
dirtyLayer(const float left,const float top,const float right,const float bottom,const Matrix4 & transform)1082 void OpenGLRenderer::dirtyLayer(const float left, const float top,
1083         const float right, const float bottom, const Matrix4& transform) {
1084     if (hasLayer()) {
1085         Rect bounds(left, top, right, bottom);
1086         transform.mapRect(bounds);
1087         dirtyLayerUnchecked(bounds, getRegion());
1088     }
1089 }
1090 
dirtyLayer(const float left,const float top,const float right,const float bottom)1091 void OpenGLRenderer::dirtyLayer(const float left, const float top,
1092         const float right, const float bottom) {
1093     if (hasLayer()) {
1094         Rect bounds(left, top, right, bottom);
1095         dirtyLayerUnchecked(bounds, getRegion());
1096     }
1097 }
1098 
dirtyLayerUnchecked(Rect & bounds,Region * region)1099 void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
1100     if (CC_LIKELY(!bounds.isEmpty() && bounds.intersect(mState.currentClipRect()))) {
1101         bounds.snapToPixelBoundaries();
1102         android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
1103         if (!dirty.isEmpty()) {
1104             region->orSelf(dirty);
1105         }
1106     }
1107 }
1108 
clearLayerRegions()1109 void OpenGLRenderer::clearLayerRegions() {
1110     const size_t quadCount = mLayers.size();
1111     if (quadCount == 0) return;
1112 
1113     if (!mState.currentlyIgnored()) {
1114         EVENT_LOGD("clearLayerRegions");
1115         // Doing several glScissor/glClear here can negatively impact
1116         // GPUs with a tiler architecture, instead we draw quads with
1117         // the Clear blending mode
1118 
1119         // The list contains bounds that have already been clipped
1120         // against their initial clip rect, and the current clip
1121         // is likely different so we need to disable clipping here
1122         bool scissorChanged = mRenderState.scissor().setEnabled(false);
1123 
1124         Vertex mesh[quadCount * 4];
1125         Vertex* vertex = mesh;
1126 
1127         for (uint32_t i = 0; i < quadCount; i++) {
1128             const Rect& bounds = mLayers[i];
1129 
1130             Vertex::set(vertex++, bounds.left, bounds.top);
1131             Vertex::set(vertex++, bounds.right, bounds.top);
1132             Vertex::set(vertex++, bounds.left, bounds.bottom);
1133             Vertex::set(vertex++, bounds.right, bounds.bottom);
1134         }
1135         // We must clear the list of dirty rects before we
1136         // call clearLayerRegions() in renderGlop to prevent
1137         // stencil setup from doing the same thing again
1138         mLayers.clear();
1139 
1140         const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
1141         Glop glop;
1142         GlopBuilder(mRenderState, mCaches, &glop)
1143                 .setRoundRectClipState(nullptr) // clear ignores clip state
1144                 .setMeshIndexedQuads(&mesh[0], quadCount)
1145                 .setFillClear()
1146                 .setTransform(*currentSnapshot(), transformFlags)
1147                 .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect()))
1148                 .build();
1149         renderGlop(glop, GlopRenderType::LayerClear);
1150 
1151         if (scissorChanged) mRenderState.scissor().setEnabled(true);
1152     } else {
1153         mLayers.clear();
1154     }
1155 }
1156 
1157 ///////////////////////////////////////////////////////////////////////////////
1158 // State Deferral
1159 ///////////////////////////////////////////////////////////////////////////////
1160 
storeDisplayState(DeferredDisplayState & state,int stateDeferFlags)1161 bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
1162     const Rect& currentClip = mState.currentClipRect();
1163     const mat4* currentMatrix = currentTransform();
1164 
1165     if (stateDeferFlags & kStateDeferFlag_Draw) {
1166         // state has bounds initialized in local coordinates
1167         if (!state.mBounds.isEmpty()) {
1168             currentMatrix->mapRect(state.mBounds);
1169             Rect clippedBounds(state.mBounds);
1170             // NOTE: if we ever want to use this clipping info to drive whether the scissor
1171             // is used, it should more closely duplicate the quickReject logic (in how it uses
1172             // snapToPixelBoundaries)
1173 
1174             if (!clippedBounds.intersect(currentClip)) {
1175                 // quick rejected
1176                 return true;
1177             }
1178 
1179             state.mClipSideFlags = kClipSide_None;
1180             if (!currentClip.contains(state.mBounds)) {
1181                 int& flags = state.mClipSideFlags;
1182                 // op partially clipped, so record which sides are clipped for clip-aware merging
1183                 if (currentClip.left > state.mBounds.left) flags |= kClipSide_Left;
1184                 if (currentClip.top > state.mBounds.top) flags |= kClipSide_Top;
1185                 if (currentClip.right < state.mBounds.right) flags |= kClipSide_Right;
1186                 if (currentClip.bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
1187             }
1188             state.mBounds.set(clippedBounds);
1189         } else {
1190             // Empty bounds implies size unknown. Label op as conservatively clipped to disable
1191             // overdraw avoidance (since we don't know what it overlaps)
1192             state.mClipSideFlags = kClipSide_ConservativeFull;
1193             state.mBounds.set(currentClip);
1194         }
1195     }
1196 
1197     state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
1198     if (state.mClipValid) {
1199         state.mClip.set(currentClip);
1200     }
1201 
1202     // Transform and alpha always deferred, since they are used by state operations
1203     // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
1204     state.mMatrix.load(*currentMatrix);
1205     state.mAlpha = currentSnapshot()->alpha;
1206 
1207     // always store/restore, since these are just pointers
1208     state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
1209     state.mProjectionPathMask = currentSnapshot()->projectionPathMask;
1210     return false;
1211 }
1212 
restoreDisplayState(const DeferredDisplayState & state,bool skipClipRestore)1213 void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
1214     setMatrix(state.mMatrix);
1215     writableSnapshot()->alpha = state.mAlpha;
1216     writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
1217     writableSnapshot()->projectionPathMask = state.mProjectionPathMask;
1218 
1219     if (state.mClipValid && !skipClipRestore) {
1220         writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
1221                 state.mClip.right, state.mClip.bottom);
1222         dirtyClip();
1223     }
1224 }
1225 
1226 /**
1227  * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done
1228  * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at
1229  * least one op is clipped), or disabled entirely (because no merged op is clipped)
1230  *
1231  * This method should be called when restoreDisplayState() won't be restoring the clip
1232  */
setupMergedMultiDraw(const Rect * clipRect)1233 void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
1234     if (clipRect != nullptr) {
1235         writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
1236     } else {
1237         writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight());
1238     }
1239     dirtyClip();
1240     bool enableScissor = (clipRect != nullptr) || mScissorOptimizationDisabled;
1241     mRenderState.scissor().setEnabled(enableScissor);
1242 }
1243 
1244 ///////////////////////////////////////////////////////////////////////////////
1245 // Clipping
1246 ///////////////////////////////////////////////////////////////////////////////
1247 
setScissorFromClip()1248 void OpenGLRenderer::setScissorFromClip() {
1249     Rect clip(mState.currentClipRect());
1250     clip.snapToPixelBoundaries();
1251 
1252     if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom,
1253             clip.getWidth(), clip.getHeight())) {
1254         mState.setDirtyClip(false);
1255     }
1256 }
1257 
ensureStencilBuffer()1258 void OpenGLRenderer::ensureStencilBuffer() {
1259     // Thanks to the mismatch between EGL and OpenGL ES FBO we
1260     // cannot attach a stencil buffer to fbo0 dynamically. Let's
1261     // just hope we have one when hasLayer() returns false.
1262     if (hasLayer()) {
1263         attachStencilBufferToLayer(currentSnapshot()->layer);
1264     }
1265 }
1266 
attachStencilBufferToLayer(Layer * layer)1267 void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
1268     // The layer's FBO is already bound when we reach this stage
1269     if (!layer->getStencilRenderBuffer()) {
1270         // GL_QCOM_tiled_rendering doesn't like it if a renderbuffer
1271         // is attached after we initiated tiling. We must turn it off,
1272         // attach the new render buffer then turn tiling back on
1273         endTiling();
1274 
1275         RenderBuffer* buffer = mCaches.renderBufferCache.get(
1276                 Stencil::getLayerStencilFormat(),
1277                 layer->getWidth(), layer->getHeight());
1278         layer->setStencilRenderBuffer(buffer);
1279 
1280         startTiling(layer->clipRect, layer->layer.getHeight());
1281     }
1282 }
1283 
handlePoint(std::vector<Vertex> & rectangleVertices,const Matrix4 & transform,float x,float y)1284 static void handlePoint(std::vector<Vertex>& rectangleVertices, const Matrix4& transform,
1285         float x, float y) {
1286     Vertex v;
1287     v.x = x;
1288     v.y = y;
1289     transform.mapPoint(v.x, v.y);
1290     rectangleVertices.push_back(v);
1291 }
1292 
handlePointNoTransform(std::vector<Vertex> & rectangleVertices,float x,float y)1293 static void handlePointNoTransform(std::vector<Vertex>& rectangleVertices, float x, float y) {
1294     Vertex v;
1295     v.x = x;
1296     v.y = y;
1297     rectangleVertices.push_back(v);
1298 }
1299 
drawRectangleList(const RectangleList & rectangleList)1300 void OpenGLRenderer::drawRectangleList(const RectangleList& rectangleList) {
1301     int quadCount = rectangleList.getTransformedRectanglesCount();
1302     std::vector<Vertex> rectangleVertices(quadCount * 4);
1303     Rect scissorBox = rectangleList.calculateBounds();
1304     scissorBox.snapToPixelBoundaries();
1305     for (int i = 0; i < quadCount; ++i) {
1306         const TransformedRectangle& tr(rectangleList.getTransformedRectangle(i));
1307         const Matrix4& transform = tr.getTransform();
1308         Rect bounds = tr.getBounds();
1309         if (transform.rectToRect()) {
1310             transform.mapRect(bounds);
1311             if (!bounds.intersect(scissorBox)) {
1312                 bounds.setEmpty();
1313             } else {
1314                 handlePointNoTransform(rectangleVertices, bounds.left, bounds.top);
1315                 handlePointNoTransform(rectangleVertices, bounds.right, bounds.top);
1316                 handlePointNoTransform(rectangleVertices, bounds.left, bounds.bottom);
1317                 handlePointNoTransform(rectangleVertices, bounds.right, bounds.bottom);
1318             }
1319         } else {
1320             handlePoint(rectangleVertices, transform, bounds.left, bounds.top);
1321             handlePoint(rectangleVertices, transform, bounds.right, bounds.top);
1322             handlePoint(rectangleVertices, transform, bounds.left, bounds.bottom);
1323             handlePoint(rectangleVertices, transform, bounds.right, bounds.bottom);
1324         }
1325     }
1326 
1327     mRenderState.scissor().set(scissorBox.left, getViewportHeight() - scissorBox.bottom,
1328             scissorBox.getWidth(), scissorBox.getHeight());
1329     const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
1330     Glop glop;
1331     Vertex* vertices = &rectangleVertices[0];
1332     GlopBuilder(mRenderState, mCaches, &glop)
1333             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1334             .setMeshIndexedQuads(vertices, rectangleVertices.size() / 4)
1335             .setFillBlack()
1336             .setTransform(*currentSnapshot(), transformFlags)
1337             .setModelViewOffsetRect(0, 0, scissorBox)
1338             .build();
1339     renderGlop(glop);
1340 }
1341 
setStencilFromClip()1342 void OpenGLRenderer::setStencilFromClip() {
1343     if (!Properties::debugOverdraw) {
1344         if (!currentSnapshot()->clipIsSimple()) {
1345             int incrementThreshold;
1346             EVENT_LOGD("setStencilFromClip - enabling");
1347 
1348             // NOTE: The order here is important, we must set dirtyClip to false
1349             //       before any draw call to avoid calling back into this method
1350             mState.setDirtyClip(false);
1351 
1352             ensureStencilBuffer();
1353 
1354             const ClipArea& clipArea = currentSnapshot()->getClipArea();
1355 
1356             bool isRectangleList = clipArea.isRectangleList();
1357             if (isRectangleList) {
1358                 incrementThreshold = clipArea.getRectangleList().getTransformedRectanglesCount();
1359             } else {
1360                 incrementThreshold = 0;
1361             }
1362 
1363             mRenderState.stencil().enableWrite(incrementThreshold);
1364 
1365             // Clean and update the stencil, but first make sure we restrict drawing
1366             // to the region's bounds
1367             bool resetScissor = mRenderState.scissor().setEnabled(true);
1368             if (resetScissor) {
1369                 // The scissor was not set so we now need to update it
1370                 setScissorFromClip();
1371             }
1372 
1373             mRenderState.stencil().clear();
1374 
1375             // stash and disable the outline clip state, since stencil doesn't account for outline
1376             bool storedSkipOutlineClip = mSkipOutlineClip;
1377             mSkipOutlineClip = true;
1378 
1379             SkPaint paint;
1380             paint.setColor(SK_ColorBLACK);
1381             paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1382 
1383             if (isRectangleList) {
1384                 drawRectangleList(clipArea.getRectangleList());
1385             } else {
1386                 // NOTE: We could use the region contour path to generate a smaller mesh
1387                 //       Since we are using the stencil we could use the red book path
1388                 //       drawing technique. It might increase bandwidth usage though.
1389 
1390                 // The last parameter is important: we are not drawing in the color buffer
1391                 // so we don't want to dirty the current layer, if any
1392                 drawRegionRects(clipArea.getClipRegion(), paint, false);
1393             }
1394             if (resetScissor) mRenderState.scissor().setEnabled(false);
1395             mSkipOutlineClip = storedSkipOutlineClip;
1396 
1397             mRenderState.stencil().enableTest(incrementThreshold);
1398 
1399             // Draw the region used to generate the stencil if the appropriate debug
1400             // mode is enabled
1401             // TODO: Implement for rectangle list clip areas
1402             if (Properties::debugStencilClip == StencilClipDebug::ShowRegion
1403                     && !clipArea.isRectangleList()) {
1404                 paint.setColor(0x7f0000ff);
1405                 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
1406                 drawRegionRects(currentSnapshot()->getClipRegion(), paint);
1407             }
1408         } else {
1409             EVENT_LOGD("setStencilFromClip - disabling");
1410             mRenderState.stencil().disable();
1411         }
1412     }
1413 }
1414 
1415 /**
1416  * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out.
1417  *
1418  * @param paint if not null, the bounds will be expanded to account for stroke depending on paint
1419  *         style, and tessellated AA ramp
1420  */
quickRejectSetupScissor(float left,float top,float right,float bottom,const SkPaint * paint)1421 bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom,
1422         const SkPaint* paint) {
1423     bool snapOut = paint && paint->isAntiAlias();
1424 
1425     if (paint && paint->getStyle() != SkPaint::kFill_Style) {
1426         float outset = paint->getStrokeWidth() * 0.5f;
1427         left -= outset;
1428         top -= outset;
1429         right += outset;
1430         bottom += outset;
1431     }
1432 
1433     bool clipRequired = false;
1434     bool roundRectClipRequired = false;
1435     if (mState.calculateQuickRejectForScissor(left, top, right, bottom,
1436             &clipRequired, &roundRectClipRequired, snapOut)) {
1437         return true;
1438     }
1439 
1440     // not quick rejected, so enable the scissor if clipRequired
1441     mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
1442     mSkipOutlineClip = !roundRectClipRequired;
1443     return false;
1444 }
1445 
debugClip()1446 void OpenGLRenderer::debugClip() {
1447 #if DEBUG_CLIP_REGIONS
1448     if (!currentSnapshot()->clipRegion->isEmpty()) {
1449         SkPaint paint;
1450         paint.setColor(0x7f00ff00);
1451         drawRegionRects(*(currentSnapshot()->clipRegion, paint);
1452 
1453     }
1454 #endif
1455 }
1456 
1457 void OpenGLRenderer::renderGlop(const Glop& glop, GlopRenderType type) {
1458     // TODO: It would be best if we could do this before quickRejectSetupScissor()
1459     //       changes the scissor test state
1460     if (type != GlopRenderType::LayerClear) {
1461         // Regular draws need to clear the dirty area on the layer before they start drawing on top
1462         // of it. If this draw *is* a layer clear, it skips the clear step (since it would
1463         // infinitely recurse)
1464         clearLayerRegions();
1465     }
1466 
1467     if (mState.getDirtyClip()) {
1468         if (mRenderState.scissor().isEnabled()) {
1469             setScissorFromClip();
1470         }
1471 
1472         setStencilFromClip();
1473     }
1474     mRenderState.render(glop);
1475     if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) {
1476         // TODO: specify more clearly when a draw should dirty the layer.
1477         // is writing to the stencil the only time we should ignore this?
1478         dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
1479         mDirty = true;
1480     }
1481 }
1482 
1483 ///////////////////////////////////////////////////////////////////////////////
1484 // Drawing
1485 ///////////////////////////////////////////////////////////////////////////////
1486 
1487 void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
1488     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
1489     // will be performed by the display list itself
1490     if (renderNode && renderNode->isRenderable()) {
1491         // compute 3d ordering
1492         renderNode->computeOrdering();
1493         if (CC_UNLIKELY(Properties::drawDeferDisabled)) {
1494             startFrame();
1495             ReplayStateStruct replayStruct(*this, dirty, replayFlags);
1496             renderNode->replay(replayStruct, 0);
1497             return;
1498         }
1499 
1500         // Don't avoid overdraw when visualizing, since that makes it harder to
1501         // debug where it's coming from, and when the problem occurs.
1502         bool avoidOverdraw = !Properties::debugOverdraw;
1503         DeferredDisplayList deferredList(mState.currentClipRect(), avoidOverdraw);
1504         DeferStateStruct deferStruct(deferredList, *this, replayFlags);
1505         renderNode->defer(deferStruct, 0);
1506 
1507         flushLayers();
1508         startFrame();
1509 
1510         deferredList.flush(*this, dirty);
1511     } else {
1512         // Even if there is no drawing command(Ex: invisible),
1513         // it still needs startFrame to clear buffer and start tiling.
1514         startFrame();
1515     }
1516 }
1517 
1518 /**
1519  * Important note: this method is intended to draw batches of bitmaps and
1520  * will not set the scissor enable or dirty the current layer, if any.
1521  * The caller is responsible for properly dirtying the current layer.
1522  */
1523 void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
1524         int bitmapCount, TextureVertex* vertices, bool pureTranslate,
1525         const Rect& bounds, const SkPaint* paint) {
1526     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
1527     if (!texture) return;
1528 
1529     const AutoTexture autoCleanup(texture);
1530 
1531     // TODO: remove layer dirty in multi-draw callers
1532     // TODO: snap doesn't need to touch transform, only texture filter.
1533     bool snap = pureTranslate;
1534     const float x = floorf(bounds.left + 0.5f);
1535     const float y = floorf(bounds.top + 0.5f);
1536 
1537     const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
1538             ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
1539     const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
1540     Glop glop;
1541     GlopBuilder(mRenderState, mCaches, &glop)
1542             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1543             .setMeshTexturedMesh(vertices, bitmapCount * 6)
1544             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1545             .setTransform(*currentSnapshot(), transformFlags)
1546             .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight()))
1547             .build();
1548     renderGlop(glop, GlopRenderType::Multi);
1549 }
1550 
1551 void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
1552     if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
1553         return;
1554     }
1555 
1556     mCaches.textureState().activateTexture(0);
1557     Texture* texture = getTexture(bitmap);
1558     if (!texture) return;
1559     const AutoTexture autoCleanup(texture);
1560 
1561     const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
1562             ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
1563     Glop glop;
1564     GlopBuilder(mRenderState, mCaches, &glop)
1565             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1566             .setMeshTexturedUnitQuad(texture->uvMapper)
1567             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1568             .setTransform(*currentSnapshot(),  TransformFlags::None)
1569             .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
1570             .build();
1571     renderGlop(glop);
1572 }
1573 
1574 void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
1575         const float* vertices, const int* colors, const SkPaint* paint) {
1576     if (!vertices || mState.currentlyIgnored()) {
1577         return;
1578     }
1579 
1580     float left = FLT_MAX;
1581     float top = FLT_MAX;
1582     float right = FLT_MIN;
1583     float bottom = FLT_MIN;
1584 
1585     const uint32_t elementCount = meshWidth * meshHeight * 6;
1586 
1587     std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]);
1588     ColorTextureVertex* vertex = &mesh[0];
1589 
1590     std::unique_ptr<int[]> tempColors;
1591     if (!colors) {
1592         uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
1593         tempColors.reset(new int[colorsCount]);
1594         memset(tempColors.get(), 0xff, colorsCount * sizeof(int));
1595         colors = tempColors.get();
1596     }
1597 
1598     Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
1599     const UvMapper& mapper(getMapper(texture));
1600 
1601     for (int32_t y = 0; y < meshHeight; y++) {
1602         for (int32_t x = 0; x < meshWidth; x++) {
1603             uint32_t i = (y * (meshWidth + 1) + x) * 2;
1604 
1605             float u1 = float(x) / meshWidth;
1606             float u2 = float(x + 1) / meshWidth;
1607             float v1 = float(y) / meshHeight;
1608             float v2 = float(y + 1) / meshHeight;
1609 
1610             mapper.map(u1, v1, u2, v2);
1611 
1612             int ax = i + (meshWidth + 1) * 2;
1613             int ay = ax + 1;
1614             int bx = i;
1615             int by = bx + 1;
1616             int cx = i + 2;
1617             int cy = cx + 1;
1618             int dx = i + (meshWidth + 1) * 2 + 2;
1619             int dy = dx + 1;
1620 
1621             ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
1622             ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
1623             ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
1624 
1625             ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
1626             ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
1627             ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
1628 
1629             left = std::min(left, std::min(vertices[ax], std::min(vertices[bx], vertices[cx])));
1630             top = std::min(top, std::min(vertices[ay], std::min(vertices[by], vertices[cy])));
1631             right = std::max(right, std::max(vertices[ax], std::max(vertices[bx], vertices[cx])));
1632             bottom = std::max(bottom, std::max(vertices[ay], std::max(vertices[by], vertices[cy])));
1633         }
1634     }
1635 
1636     if (quickRejectSetupScissor(left, top, right, bottom)) {
1637         return;
1638     }
1639 
1640     if (!texture) {
1641         texture = mCaches.textureCache.get(bitmap);
1642         if (!texture) {
1643             return;
1644         }
1645     }
1646     const AutoTexture autoCleanup(texture);
1647 
1648     /*
1649      * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
1650      * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
1651      */
1652     const int textureFillFlags = TextureFillFlags::None;
1653     Glop glop;
1654     GlopBuilder(mRenderState, mCaches, &glop)
1655             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1656             .setMeshColoredTexturedMesh(mesh.get(), elementCount)
1657             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1658             .setTransform(*currentSnapshot(),  TransformFlags::None)
1659             .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
1660             .build();
1661     renderGlop(glop);
1662 }
1663 
1664 void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) {
1665     if (quickRejectSetupScissor(dst)) {
1666         return;
1667     }
1668 
1669     Texture* texture = getTexture(bitmap);
1670     if (!texture) return;
1671     const AutoTexture autoCleanup(texture);
1672 
1673     Rect uv(std::max(0.0f, src.left / texture->width),
1674             std::max(0.0f, src.top / texture->height),
1675             std::min(1.0f, src.right / texture->width),
1676             std::min(1.0f, src.bottom / texture->height));
1677 
1678     const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
1679             ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
1680     const bool tryToSnap = MathUtils::areEqual(src.getWidth(), dst.getWidth())
1681             && MathUtils::areEqual(src.getHeight(), dst.getHeight());
1682     Glop glop;
1683     GlopBuilder(mRenderState, mCaches, &glop)
1684             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1685             .setMeshTexturedUvQuad(texture->uvMapper, uv)
1686             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1687             .setTransform(*currentSnapshot(),  TransformFlags::None)
1688             .setModelViewMapUnitToRectOptionalSnap(tryToSnap, dst)
1689             .build();
1690     renderGlop(glop);
1691 }
1692 
1693 void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
1694         AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
1695         const SkPaint* paint) {
1696     if (!mesh || !mesh->verticesCount || quickRejectSetupScissor(left, top, right, bottom)) {
1697         return;
1698     }
1699 
1700     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
1701     if (!texture) return;
1702 
1703     // 9 patches are built for stretching - always filter
1704     int textureFillFlags = TextureFillFlags::ForceFilter;
1705     if (bitmap->colorType() == kAlpha_8_SkColorType) {
1706         textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
1707     }
1708     Glop glop;
1709     GlopBuilder(mRenderState, mCaches, &glop)
1710             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1711             .setMeshPatchQuads(*mesh)
1712             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1713             .setTransform(*currentSnapshot(),  TransformFlags::None)
1714             .setModelViewOffsetRectSnap(left, top, Rect(0, 0, right - left, bottom - top)) // TODO: get minimal bounds from patch
1715             .build();
1716     renderGlop(glop);
1717 }
1718 
1719 /**
1720  * Important note: this method is intended to draw batches of 9-patch objects and
1721  * will not set the scissor enable or dirty the current layer, if any.
1722  * The caller is responsible for properly dirtying the current layer.
1723  */
1724 void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
1725         TextureVertex* vertices, uint32_t elementCount, const SkPaint* paint) {
1726     mCaches.textureState().activateTexture(0);
1727     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
1728     if (!texture) return;
1729     const AutoTexture autoCleanup(texture);
1730 
1731     // TODO: get correct bounds from caller
1732     const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
1733     // 9 patches are built for stretching - always filter
1734     int textureFillFlags = TextureFillFlags::ForceFilter;
1735     if (bitmap->colorType() == kAlpha_8_SkColorType) {
1736         textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
1737     }
1738     Glop glop;
1739     GlopBuilder(mRenderState, mCaches, &glop)
1740             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1741             .setMeshTexturedIndexedQuads(vertices, elementCount)
1742             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1743             .setTransform(*currentSnapshot(), transformFlags)
1744             .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
1745             .build();
1746     renderGlop(glop, GlopRenderType::Multi);
1747 }
1748 
1749 void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
1750         const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) {
1751     // not missing call to quickReject/dirtyLayer, always done at a higher level
1752     if (!vertexBuffer.getVertexCount()) {
1753         // no vertices to draw
1754         return;
1755     }
1756 
1757     bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
1758     const int transformFlags = TransformFlags::OffsetByFudgeFactor;
1759     Glop glop;
1760     GlopBuilder(mRenderState, mCaches, &glop)
1761             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1762             .setMeshVertexBuffer(vertexBuffer, shadowInterp)
1763             .setFillPaint(*paint, currentSnapshot()->alpha)
1764             .setTransform(*currentSnapshot(), transformFlags)
1765             .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
1766             .build();
1767     renderGlop(glop);
1768 }
1769 
1770 /**
1771  * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
1772  * that of AA lines in the drawLines() function.  We expand the convex path by a half pixel in
1773  * screen space in all directions. However, instead of using a fragment shader to compute the
1774  * translucency of the color from its position, we simply use a varying parameter to define how far
1775  * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
1776  *
1777  * Doesn't yet support joins, caps, or path effects.
1778  */
1779 void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
1780     VertexBuffer vertexBuffer;
1781     // TODO: try clipping large paths to viewport
1782 
1783     PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
1784     drawVertexBuffer(vertexBuffer, paint);
1785 }
1786 
1787 /**
1788  * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
1789  * and additional geometry for defining an alpha slope perimeter.
1790  *
1791  * Using GL_LINES can be difficult because the rasterization rules for those lines produces some
1792  * unexpected results, and may vary between hardware devices. Previously we used a varying-base
1793  * in-shader alpha region, but found it to be taxing on some GPUs.
1794  *
1795  * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
1796  * memory transfer by removing need for degenerate vertices.
1797  */
1798 void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
1799     if (mState.currentlyIgnored() || count < 4) return;
1800 
1801     count &= ~0x3; // round down to nearest four
1802 
1803     VertexBuffer buffer;
1804     PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer);
1805     const Rect& bounds = buffer.getBounds();
1806 
1807     if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
1808         return;
1809     }
1810 
1811     int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
1812     drawVertexBuffer(buffer, paint, displayFlags);
1813 }
1814 
1815 void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
1816     if (mState.currentlyIgnored() || count < 2) return;
1817 
1818     count &= ~0x1; // round down to nearest two
1819 
1820     VertexBuffer buffer;
1821     PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer);
1822 
1823     const Rect& bounds = buffer.getBounds();
1824     if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
1825         return;
1826     }
1827 
1828     int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
1829     drawVertexBuffer(buffer, paint, displayFlags);
1830 
1831     mDirty = true;
1832 }
1833 
1834 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
1835     // No need to check against the clip, we fill the clip region
1836     if (mState.currentlyIgnored()) return;
1837 
1838     Rect clip(mState.currentClipRect());
1839     clip.snapToPixelBoundaries();
1840 
1841     SkPaint paint;
1842     paint.setColor(color);
1843     paint.setXfermodeMode(mode);
1844 
1845     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
1846 
1847     mDirty = true;
1848 }
1849 
1850 void OpenGLRenderer::drawShape(float left, float top, PathTexture* texture,
1851         const SkPaint* paint) {
1852     if (!texture) return;
1853     const AutoTexture autoCleanup(texture);
1854 
1855     const float x = left + texture->left - texture->offset;
1856     const float y = top + texture->top - texture->offset;
1857 
1858     drawPathTexture(texture, x, y, paint);
1859 
1860     mDirty = true;
1861 }
1862 
1863 void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
1864         float rx, float ry, const SkPaint* p) {
1865     if (mState.currentlyIgnored()
1866             || quickRejectSetupScissor(left, top, right, bottom, p)
1867             || PaintUtils::paintWillNotDraw(*p)) {
1868         return;
1869     }
1870 
1871     if (p->getPathEffect() != nullptr) {
1872         mCaches.textureState().activateTexture(0);
1873         PathTexture* texture = mCaches.pathCache.getRoundRect(
1874                 right - left, bottom - top, rx, ry, p);
1875         drawShape(left, top, texture, p);
1876     } else {
1877         const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
1878                 *currentTransform(), *p, right - left, bottom - top, rx, ry);
1879         drawVertexBuffer(left, top, *vertexBuffer, p);
1880     }
1881 }
1882 
1883 void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
1884     if (mState.currentlyIgnored()
1885             || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
1886             || PaintUtils::paintWillNotDraw(*p)) {
1887         return;
1888     }
1889 
1890     if (p->getPathEffect() != nullptr) {
1891         mCaches.textureState().activateTexture(0);
1892         PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
1893         drawShape(x - radius, y - radius, texture, p);
1894         return;
1895     }
1896 
1897     SkPath path;
1898     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
1899         path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
1900     } else {
1901         path.addCircle(x, y, radius);
1902     }
1903 
1904     if (CC_UNLIKELY(currentSnapshot()->projectionPathMask != nullptr)) {
1905         // mask ripples with projection mask
1906         SkPath maskPath = *(currentSnapshot()->projectionPathMask->projectionMask);
1907 
1908         Matrix4 screenSpaceTransform;
1909         currentSnapshot()->buildScreenSpaceTransform(&screenSpaceTransform);
1910 
1911         Matrix4 totalTransform;
1912         totalTransform.loadInverse(screenSpaceTransform);
1913         totalTransform.multiply(currentSnapshot()->projectionPathMask->projectionMaskTransform);
1914 
1915         SkMatrix skTotalTransform;
1916         totalTransform.copyTo(skTotalTransform);
1917         maskPath.transform(skTotalTransform);
1918 
1919         // Mask the ripple path by the projection mask, now that it's
1920         // in local space. Note that this can create CCW paths.
1921         Op(path, maskPath, kIntersect_PathOp, &path);
1922     }
1923     drawConvexPath(path, p);
1924 }
1925 
1926 void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
1927         const SkPaint* p) {
1928     if (mState.currentlyIgnored()
1929             || quickRejectSetupScissor(left, top, right, bottom, p)
1930             || PaintUtils::paintWillNotDraw(*p)) {
1931         return;
1932     }
1933 
1934     if (p->getPathEffect() != nullptr) {
1935         mCaches.textureState().activateTexture(0);
1936         PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
1937         drawShape(left, top, texture, p);
1938     } else {
1939         SkPath path;
1940         SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
1941         if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
1942             rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
1943         }
1944         path.addOval(rect);
1945         drawConvexPath(path, p);
1946     }
1947 }
1948 
1949 void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
1950         float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
1951     if (mState.currentlyIgnored()
1952             || quickRejectSetupScissor(left, top, right, bottom, p)
1953             || PaintUtils::paintWillNotDraw(*p)) {
1954         return;
1955     }
1956 
1957     // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
1958     if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
1959         mCaches.textureState().activateTexture(0);
1960         PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
1961                 startAngle, sweepAngle, useCenter, p);
1962         drawShape(left, top, texture, p);
1963         return;
1964     }
1965     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
1966     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
1967         rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
1968     }
1969 
1970     SkPath path;
1971     if (useCenter) {
1972         path.moveTo(rect.centerX(), rect.centerY());
1973     }
1974     path.arcTo(rect, startAngle, sweepAngle, !useCenter);
1975     if (useCenter) {
1976         path.close();
1977     }
1978     drawConvexPath(path, p);
1979 }
1980 
1981 // See SkPaintDefaults.h
1982 #define SkPaintDefaults_MiterLimit SkIntToScalar(4)
1983 
1984 void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
1985         const SkPaint* p) {
1986     if (mState.currentlyIgnored()
1987             || quickRejectSetupScissor(left, top, right, bottom, p)
1988             || PaintUtils::paintWillNotDraw(*p)) {
1989         return;
1990     }
1991 
1992     if (p->getStyle() != SkPaint::kFill_Style) {
1993         // only fill style is supported by drawConvexPath, since others have to handle joins
1994         if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
1995                 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
1996             mCaches.textureState().activateTexture(0);
1997             PathTexture* texture =
1998                     mCaches.pathCache.getRect(right - left, bottom - top, p);
1999             drawShape(left, top, texture, p);
2000         } else {
2001             SkPath path;
2002             SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2003             if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2004                 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2005             }
2006             path.addRect(rect);
2007             drawConvexPath(path, p);
2008         }
2009     } else {
2010         if (p->isAntiAlias() && !currentTransform()->isSimple()) {
2011             SkPath path;
2012             path.addRect(left, top, right, bottom);
2013             drawConvexPath(path, p);
2014         } else {
2015             drawColorRect(left, top, right, bottom, p);
2016 
2017             mDirty = true;
2018         }
2019     }
2020 }
2021 
2022 void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
2023         int bytesCount, int count, const float* positions,
2024         FontRenderer& fontRenderer, int alpha, float x, float y) {
2025     mCaches.textureState().activateTexture(0);
2026 
2027     TextShadow textShadow;
2028     if (!getTextShadow(paint, &textShadow)) {
2029         LOG_ALWAYS_FATAL("failed to query shadow attributes");
2030     }
2031 
2032     // NOTE: The drop shadow will not perform gamma correction
2033     //       if shader-based correction is enabled
2034     mCaches.dropShadowCache.setFontRenderer(fontRenderer);
2035     ShadowTexture* texture = mCaches.dropShadowCache.get(
2036             paint, text, bytesCount, count, textShadow.radius, positions);
2037     // If the drop shadow exceeds the max texture size or couldn't be
2038     // allocated, skip drawing
2039     if (!texture) return;
2040     const AutoTexture autoCleanup(texture);
2041 
2042     const float sx = x - texture->left + textShadow.dx;
2043     const float sy = y - texture->top + textShadow.dy;
2044 
2045     Glop glop;
2046     GlopBuilder(mRenderState, mCaches, &glop)
2047             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2048             .setMeshTexturedUnitQuad(nullptr)
2049             .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
2050             .setTransform(*currentSnapshot(),  TransformFlags::None)
2051             .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
2052             .build();
2053     renderGlop(glop);
2054 }
2055 
2056 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
2057     float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
2058     return MathUtils::isZero(alpha)
2059             && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
2060 }
2061 
2062 void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
2063         const float* positions, const SkPaint* paint) {
2064     if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
2065         return;
2066     }
2067 
2068     // NOTE: Skia does not support perspective transform on drawPosText yet
2069     if (!currentTransform()->isSimple()) {
2070         return;
2071     }
2072 
2073     mRenderState.scissor().setEnabled(true);
2074 
2075     float x = 0.0f;
2076     float y = 0.0f;
2077     const bool pureTranslate = currentTransform()->isPureTranslate();
2078     if (pureTranslate) {
2079         x = floorf(x + currentTransform()->getTranslateX() + 0.5f);
2080         y = floorf(y + currentTransform()->getTranslateY() + 0.5f);
2081     }
2082 
2083     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2084     fontRenderer.setFont(paint, SkMatrix::I());
2085 
2086     int alpha;
2087     SkXfermode::Mode mode;
2088     getAlphaAndMode(paint, &alpha, &mode);
2089 
2090     if (CC_UNLIKELY(hasTextShadow(paint))) {
2091         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
2092                 alpha, 0.0f, 0.0f);
2093     }
2094 
2095     // Pick the appropriate texture filtering
2096     bool linearFilter = currentTransform()->changesBounds();
2097     if (pureTranslate && !linearFilter) {
2098         linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2099     }
2100     fontRenderer.setTextureFiltering(linearFilter);
2101 
2102     const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip());
2103     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2104 
2105     TextDrawFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2106     if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y,
2107             positions, hasLayer() ? &bounds : nullptr, &functor)) {
2108         dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
2109         mDirty = true;
2110     }
2111 
2112 }
2113 
2114 bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const {
2115     if (CC_LIKELY(transform.isPureTranslate())) {
2116         outMatrix->setIdentity();
2117         return false;
2118     } else if (CC_UNLIKELY(transform.isPerspective())) {
2119         outMatrix->setIdentity();
2120         return true;
2121     }
2122 
2123     /**
2124      * Input is a non-perspective, scaling transform. Generate a scale-only transform,
2125      * with values rounded to the nearest int.
2126      */
2127     float sx, sy;
2128     transform.decomposeScale(sx, sy);
2129     outMatrix->setScale(
2130             roundf(std::max(1.0f, sx)),
2131             roundf(std::max(1.0f, sy)));
2132     return true;
2133 }
2134 
2135 int OpenGLRenderer::getSaveCount() const {
2136     return mState.getSaveCount();
2137 }
2138 
2139 int OpenGLRenderer::save(int flags) {
2140     return mState.save(flags);
2141 }
2142 
2143 void OpenGLRenderer::restore() {
2144     mState.restore();
2145 }
2146 
2147 void OpenGLRenderer::restoreToCount(int saveCount) {
2148     mState.restoreToCount(saveCount);
2149 }
2150 
2151 
2152 void OpenGLRenderer::translate(float dx, float dy, float dz) {
2153     mState.translate(dx, dy, dz);
2154 }
2155 
2156 void OpenGLRenderer::rotate(float degrees) {
2157     mState.rotate(degrees);
2158 }
2159 
2160 void OpenGLRenderer::scale(float sx, float sy) {
2161     mState.scale(sx, sy);
2162 }
2163 
2164 void OpenGLRenderer::skew(float sx, float sy) {
2165     mState.skew(sx, sy);
2166 }
2167 
2168 void OpenGLRenderer::setMatrix(const Matrix4& matrix) {
2169     mState.setMatrix(matrix);
2170 }
2171 
2172 void OpenGLRenderer::setLocalMatrix(const SkMatrix& matrix) {
2173     mState.setMatrix(mBaseTransform);
2174     mState.concatMatrix(matrix);
2175 }
2176 
2177 void OpenGLRenderer::concatMatrix(const Matrix4& matrix) {
2178     mState.concatMatrix(matrix);
2179 }
2180 
2181 bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
2182     return mState.clipRect(left, top, right, bottom, op);
2183 }
2184 
2185 bool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
2186     return mState.clipPath(path, op);
2187 }
2188 
2189 bool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
2190     return mState.clipRegion(region, op);
2191 }
2192 
2193 void OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
2194     mState.setClippingOutline(allocator, outline);
2195 }
2196 
2197 void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator,
2198         const Rect& rect, float radius, bool highPriority) {
2199     mState.setClippingRoundRect(allocator, rect, radius, highPriority);
2200 }
2201 
2202 void OpenGLRenderer::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
2203     mState.setProjectionPathMask(allocator, path);
2204 }
2205 
2206 void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
2207         const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
2208         DrawOpMode drawOpMode) {
2209 
2210     if (drawOpMode == DrawOpMode::kImmediate) {
2211         // The checks for corner-case ignorable text and quick rejection is only done for immediate
2212         // drawing as ops from DeferredDisplayList are already filtered for these
2213         if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
2214                 quickRejectSetupScissor(bounds)) {
2215             return;
2216         }
2217     }
2218 
2219     const float oldX = x;
2220     const float oldY = y;
2221 
2222     const mat4& transform = *currentTransform();
2223     const bool pureTranslate = transform.isPureTranslate();
2224 
2225     if (CC_LIKELY(pureTranslate)) {
2226         x = floorf(x + transform.getTranslateX() + 0.5f);
2227         y = floorf(y + transform.getTranslateY() + 0.5f);
2228     }
2229 
2230     int alpha;
2231     SkXfermode::Mode mode;
2232     getAlphaAndMode(paint, &alpha, &mode);
2233 
2234     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2235 
2236     if (CC_UNLIKELY(hasTextShadow(paint))) {
2237         fontRenderer.setFont(paint, SkMatrix::I());
2238         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
2239                 alpha, oldX, oldY);
2240     }
2241 
2242     const bool hasActiveLayer = hasLayer();
2243 
2244     // We only pass a partial transform to the font renderer. That partial
2245     // matrix defines how glyphs are rasterized. Typically we want glyphs
2246     // to be rasterized at their final size on screen, which means the partial
2247     // matrix needs to take the scale factor into account.
2248     // When a partial matrix is used to transform glyphs during rasterization,
2249     // the mesh is generated with the inverse transform (in the case of scale,
2250     // the mesh is generated at 1.0 / scale for instance.) This allows us to
2251     // apply the full transform matrix at draw time in the vertex shader.
2252     // Applying the full matrix in the shader is the easiest way to handle
2253     // rotation and perspective and allows us to always generated quads in the
2254     // font renderer which greatly simplifies the code, clipping in particular.
2255     SkMatrix fontTransform;
2256     bool linearFilter = findBestFontTransform(transform, &fontTransform)
2257             || fabs(y - (int) y) > 0.0f
2258             || fabs(x - (int) x) > 0.0f;
2259     fontRenderer.setFont(paint, fontTransform);
2260     fontRenderer.setTextureFiltering(linearFilter);
2261 
2262     // TODO: Implement better clipping for scaled/rotated text
2263     const Rect* clip = !pureTranslate ? nullptr : &mState.currentClipRect();
2264     Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2265 
2266     bool status;
2267     TextDrawFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2268 
2269     // don't call issuedrawcommand, do it at end of batch
2270     bool forceFinish = (drawOpMode != DrawOpMode::kDefer);
2271     if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
2272         SkPaint paintCopy(*paint);
2273         paintCopy.setTextAlign(SkPaint::kLeft_Align);
2274         status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
2275                 positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
2276     } else {
2277         status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2278                 positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
2279     }
2280 
2281     if ((status || drawOpMode != DrawOpMode::kImmediate) && hasActiveLayer) {
2282         if (!pureTranslate) {
2283             transform.mapRect(layerBounds);
2284         }
2285         dirtyLayerUnchecked(layerBounds, getRegion());
2286     }
2287 
2288     drawTextDecorations(totalAdvance, oldX, oldY, paint);
2289 
2290     mDirty = true;
2291 }
2292 
2293 void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
2294         const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
2295     if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
2296         return;
2297     }
2298 
2299     // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
2300     mRenderState.scissor().setEnabled(true);
2301 
2302     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2303     fontRenderer.setFont(paint, SkMatrix::I());
2304     fontRenderer.setTextureFiltering(true);
2305 
2306     int alpha;
2307     SkXfermode::Mode mode;
2308     getAlphaAndMode(paint, &alpha, &mode);
2309     TextDrawFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
2310 
2311     const Rect* clip = &writableSnapshot()->getLocalClip();
2312     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2313 
2314     if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
2315             hOffset, vOffset, hasLayer() ? &bounds : nullptr, &functor)) {
2316         dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
2317         mDirty = true;
2318     }
2319 }
2320 
2321 void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
2322     if (mState.currentlyIgnored()) return;
2323 
2324     mCaches.textureState().activateTexture(0);
2325 
2326     PathTexture* texture = mCaches.pathCache.get(path, paint);
2327     if (!texture) return;
2328     const AutoTexture autoCleanup(texture);
2329 
2330     const float x = texture->left - texture->offset;
2331     const float y = texture->top - texture->offset;
2332 
2333     drawPathTexture(texture, x, y, paint);
2334     mDirty = true;
2335 }
2336 
2337 void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
2338     if (!layer) {
2339         return;
2340     }
2341 
2342     mat4* transform = nullptr;
2343     if (layer->isTextureLayer()) {
2344         transform = &layer->getTransform();
2345         if (!transform->isIdentity()) {
2346             save(SkCanvas::kMatrix_SaveFlag);
2347             concatMatrix(*transform);
2348         }
2349     }
2350 
2351     bool clipRequired = false;
2352     const bool rejected = mState.calculateQuickRejectForScissor(
2353             x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
2354             &clipRequired, nullptr, false);
2355 
2356     if (rejected) {
2357         if (transform && !transform->isIdentity()) {
2358             restore();
2359         }
2360         return;
2361     }
2362 
2363     EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
2364             x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired);
2365 
2366     updateLayer(layer, true);
2367 
2368     mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
2369     mCaches.textureState().activateTexture(0);
2370 
2371     if (CC_LIKELY(!layer->region.isEmpty())) {
2372         if (layer->region.isRect()) {
2373             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
2374                     composeLayerRect(layer, layer->regionRect));
2375         } else if (layer->mesh) {
2376             Glop glop;
2377             GlopBuilder(mRenderState, mCaches, &glop)
2378                     .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2379                     .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
2380                     .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
2381                     .setTransform(*currentSnapshot(),  TransformFlags::None)
2382                     .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
2383                     .build();
2384             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
2385 #if DEBUG_LAYERS_AS_REGIONS
2386             drawRegionRectsDebug(layer->region);
2387 #endif
2388         }
2389 
2390         if (layer->debugDrawUpdate) {
2391             layer->debugDrawUpdate = false;
2392 
2393             SkPaint paint;
2394             paint.setColor(0x7f00ff00);
2395             drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
2396         }
2397     }
2398     layer->hasDrawnSinceUpdate = true;
2399 
2400     if (transform && !transform->isIdentity()) {
2401         restore();
2402     }
2403 
2404     mDirty = true;
2405 }
2406 
2407 ///////////////////////////////////////////////////////////////////////////////
2408 // Draw filters
2409 ///////////////////////////////////////////////////////////////////////////////
2410 void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) {
2411     // We should never get here since we apply the draw filter when stashing
2412     // the paints in the DisplayList.
2413     LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters");
2414 }
2415 
2416 ///////////////////////////////////////////////////////////////////////////////
2417 // Drawing implementation
2418 ///////////////////////////////////////////////////////////////////////////////
2419 
2420 Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) {
2421     Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
2422     if (!texture) {
2423         return mCaches.textureCache.get(bitmap);
2424     }
2425     return texture;
2426 }
2427 
2428 void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y,
2429         const SkPaint* paint) {
2430     if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) {
2431         return;
2432     }
2433 
2434     Glop glop;
2435     GlopBuilder(mRenderState, mCaches, &glop)
2436             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2437             .setMeshTexturedUnitQuad(nullptr)
2438             .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
2439             .setTransform(*currentSnapshot(),  TransformFlags::None)
2440             .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
2441             .build();
2442     renderGlop(glop);
2443 }
2444 
2445 // Same values used by Skia
2446 #define kStdStrikeThru_Offset   (-6.0f / 21.0f)
2447 #define kStdUnderline_Offset    (1.0f / 9.0f)
2448 #define kStdUnderline_Thickness (1.0f / 18.0f)
2449 
2450 void OpenGLRenderer::drawTextDecorations(float underlineWidth, float x, float y,
2451         const SkPaint* paint) {
2452     // Handle underline and strike-through
2453     uint32_t flags = paint->getFlags();
2454     if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
2455         SkPaint paintCopy(*paint);
2456 
2457         if (CC_LIKELY(underlineWidth > 0.0f)) {
2458             const float textSize = paintCopy.getTextSize();
2459             const float strokeWidth = std::max(textSize * kStdUnderline_Thickness, 1.0f);
2460 
2461             const float left = x;
2462             float top = 0.0f;
2463 
2464             int linesCount = 0;
2465             if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
2466             if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
2467 
2468             const int pointsCount = 4 * linesCount;
2469             float points[pointsCount];
2470             int currentPoint = 0;
2471 
2472             if (flags & SkPaint::kUnderlineText_Flag) {
2473                 top = y + textSize * kStdUnderline_Offset;
2474                 points[currentPoint++] = left;
2475                 points[currentPoint++] = top;
2476                 points[currentPoint++] = left + underlineWidth;
2477                 points[currentPoint++] = top;
2478             }
2479 
2480             if (flags & SkPaint::kStrikeThruText_Flag) {
2481                 top = y + textSize * kStdStrikeThru_Offset;
2482                 points[currentPoint++] = left;
2483                 points[currentPoint++] = top;
2484                 points[currentPoint++] = left + underlineWidth;
2485                 points[currentPoint++] = top;
2486             }
2487 
2488             paintCopy.setStrokeWidth(strokeWidth);
2489 
2490             drawLines(&points[0], pointsCount, &paintCopy);
2491         }
2492     }
2493 }
2494 
2495 void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
2496     if (mState.currentlyIgnored()) {
2497         return;
2498     }
2499 
2500     drawColorRects(rects, count, paint, false, true, true);
2501 }
2502 
2503 void OpenGLRenderer::drawShadow(float casterAlpha,
2504         const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
2505     if (mState.currentlyIgnored()) return;
2506 
2507     // TODO: use quickRejectWithScissor. For now, always force enable scissor.
2508     mRenderState.scissor().setEnabled(true);
2509 
2510     SkPaint paint;
2511     paint.setAntiAlias(true); // want to use AlphaVertex
2512 
2513     // The caller has made sure casterAlpha > 0.
2514     float ambientShadowAlpha = mAmbientShadowAlpha;
2515     if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) {
2516         ambientShadowAlpha = Properties::overrideAmbientShadowStrength;
2517     }
2518     if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
2519         paint.setARGB(casterAlpha * ambientShadowAlpha, 0, 0, 0);
2520         drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
2521     }
2522 
2523     float spotShadowAlpha = mSpotShadowAlpha;
2524     if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) {
2525         spotShadowAlpha = Properties::overrideSpotShadowStrength;
2526     }
2527     if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
2528         paint.setARGB(casterAlpha * spotShadowAlpha, 0, 0, 0);
2529         drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
2530     }
2531 
2532     mDirty=true;
2533 }
2534 
2535 void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
2536         bool ignoreTransform, bool dirty, bool clip) {
2537     if (count == 0) {
2538         return;
2539     }
2540 
2541     float left = FLT_MAX;
2542     float top = FLT_MAX;
2543     float right = FLT_MIN;
2544     float bottom = FLT_MIN;
2545 
2546     Vertex mesh[count];
2547     Vertex* vertex = mesh;
2548 
2549     for (int index = 0; index < count; index += 4) {
2550         float l = rects[index + 0];
2551         float t = rects[index + 1];
2552         float r = rects[index + 2];
2553         float b = rects[index + 3];
2554 
2555         Vertex::set(vertex++, l, t);
2556         Vertex::set(vertex++, r, t);
2557         Vertex::set(vertex++, l, b);
2558         Vertex::set(vertex++, r, b);
2559 
2560         left = std::min(left, l);
2561         top = std::min(top, t);
2562         right = std::max(right, r);
2563         bottom = std::max(bottom, b);
2564     }
2565 
2566     if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
2567         return;
2568     }
2569 
2570     const int transformFlags = ignoreTransform
2571             ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
2572     Glop glop;
2573     GlopBuilder(mRenderState, mCaches, &glop)
2574             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2575             .setMeshIndexedQuads(&mesh[0], count / 4)
2576             .setFillPaint(*paint, currentSnapshot()->alpha)
2577             .setTransform(*currentSnapshot(), transformFlags)
2578             .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
2579             .build();
2580     renderGlop(glop);
2581 }
2582 
2583 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
2584         const SkPaint* paint, bool ignoreTransform) {
2585     const int transformFlags = ignoreTransform
2586             ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
2587     Glop glop;
2588     GlopBuilder(mRenderState, mCaches, &glop)
2589             .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2590             .setMeshUnitQuad()
2591             .setFillPaint(*paint, currentSnapshot()->alpha)
2592             .setTransform(*currentSnapshot(), transformFlags)
2593             .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
2594             .build();
2595     renderGlop(glop);
2596 }
2597 
2598 void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha,
2599         SkXfermode::Mode* mode) const {
2600     getAlphaAndModeDirect(paint, alpha,  mode);
2601     *alpha *= currentSnapshot()->alpha;
2602 }
2603 
2604 float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
2605     return (layer->getAlpha() / 255.0f) * currentSnapshot()->alpha;
2606 }
2607 
2608 }; // namespace uirenderer
2609 }; // namespace android
2610