DisplayListRenderer.h revision 2dbd185fd0e5dfe9addb677f42716c442b7e62bd
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#ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
18#define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
19
20#include <SkChunkAlloc.h>
21#include <SkReader32.h>
22#include <SkWriter32.h>
23#include <SkMatrix.h>
24#include <SkCamera.h>
25#include <SkPaint.h>
26#include <SkPath.h>
27#include <SkRefCnt.h>
28#include <SkTDArray.h>
29#include <SkTSearch.h>
30
31#include <cutils/compiler.h>
32
33#include "DisplayListLogBuffer.h"
34#include "OpenGLRenderer.h"
35#include "utils/LinearAllocator.h"
36
37namespace android {
38namespace uirenderer {
39
40///////////////////////////////////////////////////////////////////////////////
41// Defines
42///////////////////////////////////////////////////////////////////////////////
43
44#define MIN_WRITER_SIZE 4096
45#define OP_MAY_BE_SKIPPED_MASK 0xff000000
46
47// Debug
48#if DEBUG_DISPLAY_LIST
49    #define DISPLAY_LIST_LOGD(...) ALOGD(__VA_ARGS__)
50#else
51    #define DISPLAY_LIST_LOGD(...)
52#endif
53
54#define TRANSLATION 0x0001
55#define ROTATION    0x0002
56#define ROTATION_3D 0x0004
57#define SCALE       0x0008
58#define PIVOT       0x0010
59
60///////////////////////////////////////////////////////////////////////////////
61// Display list
62///////////////////////////////////////////////////////////////////////////////
63
64class DisplayListRenderer;
65class DisplayListOp;
66class DrawOp;
67class StateOp;
68
69/**
70 * Refcounted structure that holds data used in display list stream
71 */
72class DisplayListData: public LightRefBase<DisplayListData> {
73public:
74    LinearAllocator allocator;
75    Vector<DisplayListOp*> displayListOps;
76};
77
78/**
79 * Replays recorded drawing commands.
80 */
81class DisplayList {
82public:
83    DisplayList(const DisplayListRenderer& recorder);
84    ANDROID_API ~DisplayList();
85
86    // See flags defined in DisplayList.java
87    enum ReplayFlag {
88        kReplayFlag_ClipChildren = 0x1
89    };
90
91    void setViewProperties(OpenGLRenderer& renderer, uint32_t level);
92    void outputViewProperties(uint32_t level);
93
94    ANDROID_API size_t getSize();
95    ANDROID_API static void destroyDisplayListDeferred(DisplayList* displayList);
96    ANDROID_API static void outputLogBuffer(int fd);
97
98    void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
99
100    status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
101
102    void output(uint32_t level = 0);
103
104    ANDROID_API void reset();
105
106    void setRenderable(bool renderable) {
107        mIsRenderable = renderable;
108    }
109
110    bool isRenderable() const {
111        return mIsRenderable;
112    }
113
114    void setName(const char* name) {
115        if (name) {
116            mName.setTo(name);
117        }
118    }
119
120    void setClipChildren(bool clipChildren) {
121        mClipChildren = clipChildren;
122    }
123
124    void setStaticMatrix(SkMatrix* matrix) {
125        delete mStaticMatrix;
126        mStaticMatrix = new SkMatrix(*matrix);
127    }
128
129    void setAnimationMatrix(SkMatrix* matrix) {
130        delete mAnimationMatrix;
131        if (matrix) {
132            mAnimationMatrix = new SkMatrix(*matrix);
133        } else {
134            mAnimationMatrix = NULL;
135        }
136    }
137
138    void setAlpha(float alpha) {
139        alpha = fminf(1.0f, fmaxf(0.0f, alpha));
140        if (alpha != mAlpha) {
141            mAlpha = alpha;
142            mMultipliedAlpha = (int) (255 * alpha);
143        }
144    }
145
146    void setHasOverlappingRendering(bool hasOverlappingRendering) {
147        mHasOverlappingRendering = hasOverlappingRendering;
148    }
149
150    void setTranslationX(float translationX) {
151        if (translationX != mTranslationX) {
152            mTranslationX = translationX;
153            mMatrixDirty = true;
154            if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
155                mMatrixFlags &= ~TRANSLATION;
156            } else {
157                mMatrixFlags |= TRANSLATION;
158            }
159        }
160    }
161
162    void setTranslationY(float translationY) {
163        if (translationY != mTranslationY) {
164            mTranslationY = translationY;
165            mMatrixDirty = true;
166            if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
167                mMatrixFlags &= ~TRANSLATION;
168            } else {
169                mMatrixFlags |= TRANSLATION;
170            }
171        }
172    }
173
174    void setRotation(float rotation) {
175        if (rotation != mRotation) {
176            mRotation = rotation;
177            mMatrixDirty = true;
178            if (mRotation == 0.0f) {
179                mMatrixFlags &= ~ROTATION;
180            } else {
181                mMatrixFlags |= ROTATION;
182            }
183        }
184    }
185
186    void setRotationX(float rotationX) {
187        if (rotationX != mRotationX) {
188            mRotationX = rotationX;
189            mMatrixDirty = true;
190            if (mRotationX == 0.0f && mRotationY == 0.0f) {
191                mMatrixFlags &= ~ROTATION_3D;
192            } else {
193                mMatrixFlags |= ROTATION_3D;
194            }
195        }
196    }
197
198    void setRotationY(float rotationY) {
199        if (rotationY != mRotationY) {
200            mRotationY = rotationY;
201            mMatrixDirty = true;
202            if (mRotationX == 0.0f && mRotationY == 0.0f) {
203                mMatrixFlags &= ~ROTATION_3D;
204            } else {
205                mMatrixFlags |= ROTATION_3D;
206            }
207        }
208    }
209
210    void setScaleX(float scaleX) {
211        if (scaleX != mScaleX) {
212            mScaleX = scaleX;
213            mMatrixDirty = true;
214            if (mScaleX == 1.0f && mScaleY == 1.0f) {
215                mMatrixFlags &= ~SCALE;
216            } else {
217                mMatrixFlags |= SCALE;
218            }
219        }
220    }
221
222    void setScaleY(float scaleY) {
223        if (scaleY != mScaleY) {
224            mScaleY = scaleY;
225            mMatrixDirty = true;
226            if (mScaleX == 1.0f && mScaleY == 1.0f) {
227                mMatrixFlags &= ~SCALE;
228            } else {
229                mMatrixFlags |= SCALE;
230            }
231        }
232    }
233
234    void setPivotX(float pivotX) {
235        mPivotX = pivotX;
236        mMatrixDirty = true;
237        if (mPivotX == 0.0f && mPivotY == 0.0f) {
238            mMatrixFlags &= ~PIVOT;
239        } else {
240            mMatrixFlags |= PIVOT;
241        }
242        mPivotExplicitlySet = true;
243    }
244
245    void setPivotY(float pivotY) {
246        mPivotY = pivotY;
247        mMatrixDirty = true;
248        if (mPivotX == 0.0f && mPivotY == 0.0f) {
249            mMatrixFlags &= ~PIVOT;
250        } else {
251            mMatrixFlags |= PIVOT;
252        }
253        mPivotExplicitlySet = true;
254    }
255
256    void setCameraDistance(float distance) {
257        if (distance != mCameraDistance) {
258            mCameraDistance = distance;
259            mMatrixDirty = true;
260            if (!mTransformCamera) {
261                mTransformCamera = new Sk3DView();
262                mTransformMatrix3D = new SkMatrix();
263            }
264            mTransformCamera->setCameraLocation(0, 0, distance);
265        }
266    }
267
268    void setLeft(int left) {
269        if (left != mLeft) {
270            mLeft = left;
271            mWidth = mRight - mLeft;
272            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
273                mMatrixDirty = true;
274            }
275        }
276    }
277
278    void setTop(int top) {
279        if (top != mTop) {
280            mTop = top;
281            mHeight = mBottom - mTop;
282            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
283                mMatrixDirty = true;
284            }
285        }
286    }
287
288    void setRight(int right) {
289        if (right != mRight) {
290            mRight = right;
291            mWidth = mRight - mLeft;
292            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
293                mMatrixDirty = true;
294            }
295        }
296    }
297
298    void setBottom(int bottom) {
299        if (bottom != mBottom) {
300            mBottom = bottom;
301            mHeight = mBottom - mTop;
302            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
303                mMatrixDirty = true;
304            }
305        }
306    }
307
308    void setLeftTop(int left, int top) {
309        if (left != mLeft || top != mTop) {
310            mLeft = left;
311            mTop = top;
312            mWidth = mRight - mLeft;
313            mHeight = mBottom - mTop;
314            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
315                mMatrixDirty = true;
316            }
317        }
318    }
319
320    void setLeftTopRightBottom(int left, int top, int right, int bottom) {
321        if (left != mLeft || top != mTop || right != mRight || bottom != mBottom) {
322            mLeft = left;
323            mTop = top;
324            mRight = right;
325            mBottom = bottom;
326            mWidth = mRight - mLeft;
327            mHeight = mBottom - mTop;
328            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
329                mMatrixDirty = true;
330            }
331        }
332    }
333
334    void offsetLeftRight(int offset) {
335        if (offset != 0) {
336            mLeft += offset;
337            mRight += offset;
338            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
339                mMatrixDirty = true;
340            }
341        }
342    }
343
344    void offsetTopBottom(int offset) {
345        if (offset != 0) {
346            mTop += offset;
347            mBottom += offset;
348            if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
349                mMatrixDirty = true;
350            }
351        }
352    }
353
354    void setCaching(bool caching) {
355        mCaching = caching;
356    }
357
358    int getWidth() {
359        return mWidth;
360    }
361
362    int getHeight() {
363        return mHeight;
364    }
365
366private:
367    void init();
368
369    void clearResources();
370
371    void updateMatrix();
372
373    class TextContainer {
374    public:
375        size_t length() const {
376            return mByteLength;
377        }
378
379        const char* text() const {
380            return (const char*) mText;
381        }
382
383        size_t mByteLength;
384        const char* mText;
385    };
386
387    Vector<SkBitmap*> mBitmapResources;
388    Vector<SkBitmap*> mOwnedBitmapResources;
389    Vector<SkiaColorFilter*> mFilterResources;
390
391    Vector<SkPaint*> mPaints;
392    Vector<SkPath*> mPaths;
393    SortedVector<SkPath*> mSourcePaths;
394    Vector<SkRegion*> mRegions;
395    Vector<SkMatrix*> mMatrices;
396    Vector<SkiaShader*> mShaders;
397    Vector<Layer*> mLayers;
398
399    sp<DisplayListData> mDisplayListData;
400
401    size_t mSize;
402
403    bool mIsRenderable;
404    uint32_t mFunctorCount;
405
406    String8 mName;
407
408    // View properties
409    bool mClipChildren;
410    float mAlpha;
411    int mMultipliedAlpha;
412    bool mHasOverlappingRendering;
413    float mTranslationX, mTranslationY;
414    float mRotation, mRotationX, mRotationY;
415    float mScaleX, mScaleY;
416    float mPivotX, mPivotY;
417    float mCameraDistance;
418    int mLeft, mTop, mRight, mBottom;
419    int mWidth, mHeight;
420    int mPrevWidth, mPrevHeight;
421    bool mPivotExplicitlySet;
422    bool mMatrixDirty;
423    bool mMatrixIsIdentity;
424    uint32_t mMatrixFlags;
425    SkMatrix* mTransformMatrix;
426    Sk3DView* mTransformCamera;
427    SkMatrix* mTransformMatrix3D;
428    SkMatrix* mStaticMatrix;
429    SkMatrix* mAnimationMatrix;
430    bool mCaching;
431};
432
433///////////////////////////////////////////////////////////////////////////////
434// Renderer
435///////////////////////////////////////////////////////////////////////////////
436
437/**
438 * Records drawing commands in a display list for latter playback.
439 */
440class DisplayListRenderer: public OpenGLRenderer {
441public:
442    ANDROID_API DisplayListRenderer();
443    virtual ~DisplayListRenderer();
444
445    ANDROID_API DisplayList* getDisplayList(DisplayList* displayList);
446
447    virtual bool isDeferred();
448
449    virtual void setViewport(int width, int height);
450    virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
451    virtual void finish();
452
453    virtual status_t callDrawGLFunction(Functor *functor, Rect& dirty);
454
455    virtual void interrupt();
456    virtual void resume();
457
458    virtual int save(int flags);
459    virtual void restore();
460    virtual void restoreToCount(int saveCount);
461
462    virtual int saveLayer(float left, float top, float right, float bottom,
463            SkPaint* p, int flags);
464    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
465                int alpha, int flags);
466
467    virtual void translate(float dx, float dy);
468    virtual void rotate(float degrees);
469    virtual void scale(float sx, float sy);
470    virtual void skew(float sx, float sy);
471
472    virtual void setMatrix(SkMatrix* matrix);
473    virtual void concatMatrix(SkMatrix* matrix);
474
475    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
476    virtual bool clipPath(SkPath* path, SkRegion::Op op);
477    virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
478
479    virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags,
480            uint32_t level = 0);
481    virtual status_t drawLayer(Layer* layer, float x, float y, SkPaint* paint);
482    virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
483    virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
484    virtual status_t drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
485            float srcRight, float srcBottom, float dstLeft, float dstTop,
486            float dstRight, float dstBottom, SkPaint* paint);
487    virtual status_t drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint);
488    virtual status_t drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
489            float* vertices, int* colors, SkPaint* paint);
490    virtual status_t drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
491            const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
492            float left, float top, float right, float bottom, SkPaint* paint);
493    virtual status_t drawColor(int color, SkXfermode::Mode mode);
494    virtual status_t drawRect(float left, float top, float right, float bottom, SkPaint* paint);
495    virtual status_t drawRoundRect(float left, float top, float right, float bottom,
496            float rx, float ry, SkPaint* paint);
497    virtual status_t drawCircle(float x, float y, float radius, SkPaint* paint);
498    virtual status_t drawOval(float left, float top, float right, float bottom, SkPaint* paint);
499    virtual status_t drawArc(float left, float top, float right, float bottom,
500            float startAngle, float sweepAngle, bool useCenter, SkPaint* paint);
501    virtual status_t drawPath(SkPath* path, SkPaint* paint);
502    virtual status_t drawLines(float* points, int count, SkPaint* paint);
503    virtual status_t drawPoints(float* points, int count, SkPaint* paint);
504    virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
505            float hOffset, float vOffset, SkPaint* paint);
506    virtual status_t drawPosText(const char* text, int bytesCount, int count,
507            const float* positions, SkPaint* paint);
508    virtual status_t drawText(const char* text, int bytesCount, int count,
509            float x, float y, const float* positions, SkPaint* paint, float length);
510    virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
511
512    virtual void resetShader();
513    virtual void setupShader(SkiaShader* shader);
514
515    virtual void resetColorFilter();
516    virtual void setupColorFilter(SkiaColorFilter* filter);
517
518    virtual void resetShadow();
519    virtual void setupShadow(float radius, float dx, float dy, int color);
520
521    virtual void resetPaintFilter();
522    virtual void setupPaintFilter(int clearBits, int setBits);
523
524    ANDROID_API void reset();
525
526    sp<DisplayListData> getDisplayListData() const {
527        return mDisplayListData;
528    }
529
530    const Vector<SkBitmap*>& getBitmapResources() const {
531        return mBitmapResources;
532    }
533
534    const Vector<SkBitmap*>& getOwnedBitmapResources() const {
535        return mOwnedBitmapResources;
536    }
537
538    const Vector<SkiaColorFilter*>& getFilterResources() const {
539        return mFilterResources;
540    }
541
542    const Vector<SkiaShader*>& getShaders() const {
543        return mShaders;
544    }
545
546    const Vector<SkPaint*>& getPaints() const {
547        return mPaints;
548    }
549
550    const Vector<SkPath*>& getPaths() const {
551        return mPaths;
552    }
553
554    const SortedVector<SkPath*>& getSourcePaths() const {
555        return mSourcePaths;
556    }
557
558    const Vector<SkRegion*>& getRegions() const {
559        return mRegions;
560    }
561
562    const Vector<Layer*>& getLayers() const {
563        return mLayers;
564    }
565
566    const Vector<SkMatrix*>& getMatrices() const {
567        return mMatrices;
568    }
569
570    uint32_t getFunctorCount() const {
571        return mFunctorCount;
572    }
573
574private:
575    void insertRestoreToCount();
576    void insertTranslate();
577
578    LinearAllocator& alloc() { return mDisplayListData->allocator; }
579    void addStateOp(StateOp* op);
580    bool addDrawOp(DrawOp* op); // returns true if op not rejected
581    void addOpInternal(DisplayListOp* op) {
582        insertRestoreToCount();
583        insertTranslate();
584        mDisplayListData->displayListOps.add(op);
585    }
586
587    template<class T>
588    inline T* refBuffer(const T* srcBuffer, int32_t count) {
589        if (srcBuffer == NULL) return NULL;
590        T* dstBuffer = (T*) mDisplayListData->allocator.alloc(count * sizeof(T));
591        memcpy(dstBuffer, srcBuffer, count * sizeof(T));
592        return dstBuffer;
593    }
594
595    inline char* refText(const char* text, size_t byteLength) {
596        return (char*) refBuffer<uint8_t>((uint8_t*)text, byteLength);
597    }
598
599    inline SkPath* refPath(SkPath* path) {
600        if (!path) return NULL;
601
602        SkPath* pathCopy = mPathMap.valueFor(path);
603        if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) {
604            pathCopy = new SkPath(*path);
605            pathCopy->setSourcePath(path);
606            // replaceValueFor() performs an add if the entry doesn't exist
607            mPathMap.replaceValueFor(path, pathCopy);
608            mPaths.add(pathCopy);
609        }
610        if (mSourcePaths.indexOf(path) < 0) {
611            mCaches.resourceCache.incrementRefcount(path);
612            mSourcePaths.add(path);
613        }
614        return pathCopy;
615    }
616
617    inline SkPaint* refPaint(SkPaint* paint) {
618        if (!paint) {
619            return paint;
620        }
621
622        SkPaint* paintCopy = mPaintMap.valueFor(paint);
623        if (paintCopy == NULL || paintCopy->getGenerationID() != paint->getGenerationID()) {
624            paintCopy = new SkPaint(*paint);
625            // replaceValueFor() performs an add if the entry doesn't exist
626            mPaintMap.replaceValueFor(paint, paintCopy);
627            mPaints.add(paintCopy);
628        }
629
630        return paintCopy;
631    }
632
633    inline SkRegion* refRegion(SkRegion* region) {
634        if (!region) {
635            return region;
636        }
637
638        SkRegion* regionCopy = mRegionMap.valueFor(region);
639        // TODO: Add generation ID to SkRegion
640        if (regionCopy == NULL) {
641            regionCopy = new SkRegion(*region);
642            // replaceValueFor() performs an add if the entry doesn't exist
643            mRegionMap.replaceValueFor(region, regionCopy);
644            mRegions.add(regionCopy);
645        }
646
647        return regionCopy;
648    }
649
650    inline SkMatrix* refMatrix(SkMatrix* matrix) {
651        // Copying the matrix is cheap and prevents against the user changing the original
652        // matrix before the operation that uses it
653        SkMatrix* copy = new SkMatrix(*matrix);
654        mMatrices.add(copy);
655        return copy;
656    }
657
658    inline SkBitmap* refBitmap(SkBitmap* bitmap) {
659        // Note that this assumes the bitmap is immutable. There are cases this won't handle
660        // correctly, such as creating the bitmap from scratch, drawing with it, changing its
661        // contents, and drawing again. The only fix would be to always copy it the first time,
662        // which doesn't seem worth the extra cycles for this unlikely case.
663        mBitmapResources.add(bitmap);
664        mCaches.resourceCache.incrementRefcount(bitmap);
665        return bitmap;
666    }
667
668    inline SkBitmap* refBitmapData(SkBitmap* bitmap) {
669        mOwnedBitmapResources.add(bitmap);
670        mCaches.resourceCache.incrementRefcount(bitmap);
671        return bitmap;
672    }
673
674    inline SkiaShader* refShader(SkiaShader* shader) {
675        if (!shader) return NULL;
676
677        SkiaShader* shaderCopy = mShaderMap.valueFor(shader);
678        // TODO: We also need to handle generation ID changes in compose shaders
679        if (shaderCopy == NULL || shaderCopy->getGenerationId() != shader->getGenerationId()) {
680            shaderCopy = shader->copy();
681            // replaceValueFor() performs an add if the entry doesn't exist
682            mShaderMap.replaceValueFor(shader, shaderCopy);
683            mShaders.add(shaderCopy);
684            mCaches.resourceCache.incrementRefcount(shaderCopy);
685        }
686        return shaderCopy;
687    }
688
689    inline SkiaColorFilter* refColorFilter(SkiaColorFilter* colorFilter) {
690        mFilterResources.add(colorFilter);
691        mCaches.resourceCache.incrementRefcount(colorFilter);
692        return colorFilter;
693    }
694
695    Vector<SkBitmap*> mBitmapResources;
696    Vector<SkBitmap*> mOwnedBitmapResources;
697    Vector<SkiaColorFilter*> mFilterResources;
698
699    Vector<SkPaint*> mPaints;
700    DefaultKeyedVector<SkPaint*, SkPaint*> mPaintMap;
701
702    Vector<SkPath*> mPaths;
703    DefaultKeyedVector<SkPath*, SkPath*> mPathMap;
704
705    SortedVector<SkPath*> mSourcePaths;
706
707    Vector<SkRegion*> mRegions;
708    DefaultKeyedVector<SkRegion*, SkRegion*> mRegionMap;
709
710    Vector<SkiaShader*> mShaders;
711    DefaultKeyedVector<SkiaShader*, SkiaShader*> mShaderMap;
712
713    Vector<SkMatrix*> mMatrices;
714
715    Vector<Layer*> mLayers;
716
717    int mRestoreSaveCount;
718
719    Caches& mCaches;
720    sp<DisplayListData> mDisplayListData;
721
722    float mTranslateX;
723    float mTranslateY;
724    bool mHasTranslate;
725    bool mHasDrawOps;
726
727    uint32_t mFunctorCount;
728
729    friend class DisplayList;
730
731}; // class DisplayListRenderer
732
733}; // namespace uirenderer
734}; // namespace android
735
736#endif // ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
737