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