1/*
2 * Copyright (C) 2013 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_TESSELLATION_CACHE_H
18#define ANDROID_HWUI_TESSELLATION_CACHE_H
19
20#include "Debug.h"
21#include "Matrix.h"
22#include "Rect.h"
23#include "Vector.h"
24#include "VertexBuffer.h"
25#include "thread/TaskProcessor.h"
26#include "utils/Macros.h"
27#include "utils/Pair.h"
28
29#include <SkPaint.h>
30#include <SkPath.h>
31
32#include <utils/LruCache.h>
33#include <utils/Mutex.h>
34#include <utils/StrongPointer.h>
35
36class SkBitmap;
37class SkCanvas;
38struct SkRect;
39
40namespace android {
41namespace uirenderer {
42
43class Caches;
44class VertexBuffer;
45
46///////////////////////////////////////////////////////////////////////////////
47// Classes
48///////////////////////////////////////////////////////////////////////////////
49
50class TessellationCache {
51public:
52    typedef Pair<VertexBuffer*, VertexBuffer*> vertexBuffer_pair_t;
53
54    struct Description {
55        HASHABLE_TYPE(Description);
56        enum class Type {
57            None,
58            RoundRect,
59        };
60
61        Type type;
62        float scaleX;
63        float scaleY;
64        bool aa;
65        SkPaint::Cap cap;
66        SkPaint::Style style;
67        float strokeWidth;
68        union Shape {
69            struct RoundRect {
70                float width;
71                float height;
72                float rx;
73                float ry;
74            } roundRect;
75        } shape;
76
77        Description();
78        Description(Type type, const Matrix4& transform, const SkPaint& paint);
79        void setupMatrixAndPaint(Matrix4* matrix, SkPaint* paint) const;
80    };
81
82    struct ShadowDescription {
83        HASHABLE_TYPE(ShadowDescription);
84        const SkPath* nodeKey;
85        float matrixData[16];
86
87        ShadowDescription();
88        ShadowDescription(const SkPath* nodeKey, const Matrix4* drawTransform);
89    };
90
91    class ShadowTask : public Task<vertexBuffer_pair_t> {
92    public:
93        ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
94                const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
95                const Vector3& lightCenter, float lightRadius)
96            : drawTransform(*drawTransform)
97            , localClip(localClip)
98            , opaque(opaque)
99            , casterPerimeter(*casterPerimeter)
100            , transformXY(*transformXY)
101            , transformZ(*transformZ)
102            , lightCenter(lightCenter)
103            , lightRadius(lightRadius) {
104        }
105
106        /* Note - we deep copy all task parameters, because *even though* pointers into Allocator
107         * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
108         * certain Allocators are destroyed before trim() is called to flush incomplete tasks.
109         *
110         * These deep copies could be avoided, long term, by canceling or flushing outstanding
111         * tasks before tearing down single-frame LinearAllocators.
112         */
113        const Matrix4 drawTransform;
114        const Rect localClip;
115        bool opaque;
116        const SkPath casterPerimeter;
117        const Matrix4 transformXY;
118        const Matrix4 transformZ;
119        const Vector3 lightCenter;
120        const float lightRadius;
121        VertexBuffer ambientBuffer;
122        VertexBuffer spotBuffer;
123    };
124
125    TessellationCache();
126    ~TessellationCache();
127
128    /**
129     * Clears the cache. This causes all TessellationBuffers to be deleted.
130     */
131    void clear();
132    /**
133     * Returns the maximum size of the cache in bytes.
134     */
135    uint32_t getMaxSize();
136    /**
137     * Returns the current size of the cache in bytes.
138     */
139    uint32_t getSize();
140
141    /**
142     * Trims the contents of the cache, removing items until it's under its
143     * specified limit.
144     *
145     * Trimming is used for caches that support pre-caching from a worker
146     * thread. During pre-caching the maximum limit of the cache can be
147     * exceeded for the duration of the frame. It is therefore required to
148     * trim the cache at the end of the frame to keep the total amount of
149     * memory used under control.
150     *
151     * Also removes transient Shadow VertexBuffers, which aren't cached between frames.
152     */
153    void trim();
154
155    // TODO: precache/get for Oval, Lines, Points, etc.
156
157    void precacheRoundRect(const Matrix4& transform, const SkPaint& paint,
158            float width, float height, float rx, float ry) {
159        getRoundRectBuffer(transform, paint, width, height, rx, ry);
160    }
161    const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint,
162            float width, float height, float rx, float ry);
163
164    // TODO: delete these when switching to HWUI_NEW_OPS
165    void precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
166            bool opaque, const SkPath* casterPerimeter,
167            const Matrix4* transformXY, const Matrix4* transformZ,
168            const Vector3& lightCenter, float lightRadius);
169    void getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip,
170            bool opaque, const SkPath* casterPerimeter,
171            const Matrix4* transformXY, const Matrix4* transformZ,
172            const Vector3& lightCenter, float lightRadius,
173            vertexBuffer_pair_t& outBuffers);
174
175    sp<ShadowTask> getShadowTask(const Matrix4* drawTransform, const Rect& localClip,
176            bool opaque, const SkPath* casterPerimeter,
177            const Matrix4* transformXY, const Matrix4* transformZ,
178            const Vector3& lightCenter, float lightRadius);
179
180private:
181    class Buffer;
182    class TessellationTask;
183    class TessellationProcessor;
184
185    typedef VertexBuffer* (*Tessellator)(const Description&);
186
187    Buffer* getRectBuffer(const Matrix4& transform, const SkPaint& paint,
188            float width, float height);
189    Buffer* getRoundRectBuffer(const Matrix4& transform, const SkPaint& paint,
190            float width, float height, float rx, float ry);
191
192    Buffer* getOrCreateBuffer(const Description& entry, Tessellator tessellator);
193
194    const uint32_t mMaxSize;
195
196    bool mDebugEnabled;
197
198    mutable Mutex mLock;
199
200    ///////////////////////////////////////////////////////////////////////////////
201    // General tessellation caching
202    ///////////////////////////////////////////////////////////////////////////////
203    sp<TaskProcessor<VertexBuffer*> > mProcessor;
204    LruCache<Description, Buffer*> mCache;
205    class BufferRemovedListener : public OnEntryRemoved<Description, Buffer*> {
206        void operator()(Description& description, Buffer*& buffer) override;
207    };
208    BufferRemovedListener mBufferRemovedListener;
209
210    ///////////////////////////////////////////////////////////////////////////////
211    // Shadow tessellation caching
212    ///////////////////////////////////////////////////////////////////////////////
213    sp<TaskProcessor<vertexBuffer_pair_t> > mShadowProcessor;
214
215    // holds a pointer, and implicit strong ref to each shadow task of the frame
216    LruCache<ShadowDescription, Task<vertexBuffer_pair_t>*> mShadowCache;
217    class BufferPairRemovedListener : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t>*> {
218        void operator()(ShadowDescription& description, Task<vertexBuffer_pair_t>*& bufferPairTask) override {
219            bufferPairTask->decStrong(nullptr);
220        }
221    };
222    BufferPairRemovedListener mBufferPairRemovedListener;
223
224}; // class TessellationCache
225
226void tessellateShadows(
227        const Matrix4* drawTransform, const Rect* localClip,
228        bool isCasterOpaque, const SkPath* casterPerimeter,
229        const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
230        const Vector3& lightCenter, float lightRadius,
231        VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer);
232
233}; // namespace uirenderer
234}; // namespace android
235
236#endif // ANDROID_HWUI_PATH_CACHE_H
237