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_PATH_CACHE_H
18#define ANDROID_HWUI_PATH_CACHE_H
19
20#include "Debug.h"
21#include "Texture.h"
22#include "thread/Task.h"
23#include "thread/TaskProcessor.h"
24#include "utils/Macros.h"
25#include "utils/Pair.h"
26
27#include <GLES2/gl2.h>
28#include <SkPaint.h>
29#include <SkPath.h>
30#include <utils/LruCache.h>
31#include <utils/Mutex.h>
32
33#include <vector>
34
35class SkBitmap;
36class SkCanvas;
37class SkPaint;
38struct SkRect;
39
40namespace android {
41namespace uirenderer {
42
43class Caches;
44
45///////////////////////////////////////////////////////////////////////////////
46// Defines
47///////////////////////////////////////////////////////////////////////////////
48
49// Debug
50#if DEBUG_PATHS
51    #define PATH_LOGD(...) ALOGD(__VA_ARGS__)
52#else
53    #define PATH_LOGD(...)
54#endif
55
56///////////////////////////////////////////////////////////////////////////////
57// Classes
58///////////////////////////////////////////////////////////////////////////////
59
60/**
61 * Alpha texture used to represent a path.
62 */
63struct PathTexture: public Texture {
64    PathTexture(Caches& caches, float left, float top,
65            float offset, int generation)
66            : Texture(caches)
67            , left(left)
68            , top(top)
69            , offset(offset) {
70        this->generation = generation;
71    }
72    PathTexture(Caches& caches, int generation)
73        : Texture(caches) {
74        this->generation = generation;
75    }
76
77    ~PathTexture() {
78        clearTask();
79    }
80
81    /**
82     * Left coordinate of the path bounds.
83     */
84    float left = 0;
85    /**
86     * Top coordinate of the path bounds.
87     */
88    float top = 0;
89    /**
90     * Offset to draw the path at the correct origin.
91     */
92    float offset = 0;
93
94    sp<Task<SkBitmap*> > task() const {
95        return mTask;
96    }
97
98    void setTask(const sp<Task<SkBitmap*> >& task) {
99        mTask = task;
100    }
101
102    void clearTask() {
103        if (mTask != nullptr) {
104            mTask.clear();
105        }
106    }
107
108private:
109    sp<Task<SkBitmap*> > mTask;
110}; // struct PathTexture
111
112enum class ShapeType {
113    None,
114    Rect,
115    RoundRect,
116    Circle,
117    Oval,
118    Arc,
119    Path
120};
121
122struct PathDescription {
123    HASHABLE_TYPE(PathDescription);
124    ShapeType type;
125    SkPaint::Join join;
126    SkPaint::Cap cap;
127    SkPaint::Style style;
128    float miter;
129    float strokeWidth;
130    SkPathEffect* pathEffect;
131    union Shape {
132        struct Path {
133            uint32_t mGenerationID;
134        } path;
135        struct RoundRect {
136            float mWidth;
137            float mHeight;
138            float mRx;
139            float mRy;
140        } roundRect;
141        struct Circle {
142            float mRadius;
143        } circle;
144        struct Oval {
145            float mWidth;
146            float mHeight;
147        } oval;
148        struct Rect {
149            float mWidth;
150            float mHeight;
151        } rect;
152        struct Arc {
153            float mWidth;
154            float mHeight;
155            float mStartAngle;
156            float mSweepAngle;
157            bool mUseCenter;
158        } arc;
159    } shape;
160
161    PathDescription();
162    PathDescription(ShapeType shapeType, const SkPaint* paint);
163};
164
165/**
166 * A simple LRU shape cache. The cache has a maximum size expressed in bytes.
167 * Any texture added to the cache causing the cache to grow beyond the maximum
168 * allowed size will also cause the oldest texture to be kicked out.
169 */
170class PathCache: public OnEntryRemoved<PathDescription, PathTexture*> {
171public:
172    PathCache();
173    ~PathCache();
174
175    /**
176     * Used as a callback when an entry is removed from the cache.
177     * Do not invoke directly.
178     */
179    void operator()(PathDescription& path, PathTexture*& texture) override;
180
181    /**
182     * Clears the cache. This causes all textures to be deleted.
183     */
184    void clear();
185
186    /**
187     * Returns the maximum size of the cache in bytes.
188     */
189    uint32_t getMaxSize();
190    /**
191     * Returns the current size of the cache in bytes.
192     */
193    uint32_t getSize();
194
195    PathTexture* getRoundRect(float width, float height, float rx, float ry, const SkPaint* paint);
196    PathTexture* getCircle(float radius, const SkPaint* paint);
197    PathTexture* getOval(float width, float height, const SkPaint* paint);
198    PathTexture* getRect(float width, float height, const SkPaint* paint);
199    PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
200            bool useCenter, const SkPaint* paint);
201    PathTexture* get(const SkPath* path, const SkPaint* paint);
202    void         remove(const SkPath* path, const SkPaint* paint);
203
204    /**
205     * Removes the specified path. This is meant to be called from threads
206     * that are not the EGL context thread.
207     */
208    ANDROID_API void removeDeferred(const SkPath* path);
209    /**
210     * Process deferred removals.
211     */
212    void clearGarbage();
213    /**
214     * Trims the contents of the cache, removing items until it's under its
215     * specified limit.
216     *
217     * Trimming is used for caches that support pre-caching from a worker
218     * thread. During pre-caching the maximum limit of the cache can be
219     * exceeded for the duration of the frame. It is therefore required to
220     * trim the cache at the end of the frame to keep the total amount of
221     * memory used under control.
222     */
223    void trim();
224
225    /**
226     * Precaches the specified path using background threads.
227     */
228    void precache(const SkPath* path, const SkPaint* paint);
229
230    static bool canDrawAsConvexPath(SkPath* path, const SkPaint* paint);
231    static void computePathBounds(const SkPath* path, const SkPaint* paint,
232            float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
233    static void computeBounds(const SkRect& bounds, const SkPaint* paint,
234            float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
235
236private:
237    PathTexture* addTexture(const PathDescription& entry,
238            const SkPath *path, const SkPaint* paint);
239    PathTexture* addTexture(const PathDescription& entry, SkBitmap* bitmap);
240
241    /**
242     * Generates the texture from a bitmap into the specified texture structure.
243     */
244    void generateTexture(SkBitmap& bitmap, Texture* texture);
245    void generateTexture(const PathDescription& entry, SkBitmap* bitmap, PathTexture* texture,
246            bool addToCache = true);
247
248    PathTexture* get(const PathDescription& entry) {
249        return mCache.get(entry);
250    }
251
252    /**
253     * Ensures there is enough space in the cache for a texture of the specified
254     * dimensions.
255     */
256    void purgeCache(uint32_t width, uint32_t height);
257
258    void removeTexture(PathTexture* texture);
259
260    bool checkTextureSize(uint32_t width, uint32_t height) {
261        if (width > mMaxTextureSize || height > mMaxTextureSize) {
262            ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)",
263                    width, height, mMaxTextureSize, mMaxTextureSize);
264            return false;
265        }
266        return true;
267    }
268
269    void init();
270
271    class PathTask: public Task<SkBitmap*> {
272    public:
273        PathTask(const SkPath* path, const SkPaint* paint, PathTexture* texture):
274            path(*path), paint(*paint), texture(texture) {
275        }
276
277        ~PathTask() {
278            delete future()->get();
279        }
280
281        // copied, since input path not guaranteed to survive for duration of task
282        const SkPath path;
283
284        // copied, since input paint may not be immutable
285        const SkPaint paint;
286        PathTexture* texture;
287    };
288
289    class PathProcessor: public TaskProcessor<SkBitmap*> {
290    public:
291        PathProcessor(Caches& caches);
292        ~PathProcessor() { }
293
294        virtual void onProcess(const sp<Task<SkBitmap*> >& task) override;
295
296    private:
297        uint32_t mMaxTextureSize;
298    };
299
300    LruCache<PathDescription, PathTexture*> mCache;
301    uint32_t mSize;
302    const uint32_t mMaxSize;
303    GLuint mMaxTextureSize;
304
305    bool mDebugEnabled;
306
307    sp<PathProcessor> mProcessor;
308
309    std::vector<uint32_t> mGarbage;
310    mutable Mutex mLock;
311}; // class PathCache
312
313}; // namespace uirenderer
314}; // namespace android
315
316#endif // ANDROID_HWUI_PATH_CACHE_H
317