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 <SkPath.h>
29#include <utils/LruCache.h>
30#include <utils/Mutex.h>
31#include <utils/Vector.h>
32
33class SkBitmap;
34class SkCanvas;
35class SkPaint;
36struct SkRect;
37
38namespace android {
39namespace uirenderer {
40
41class Caches;
42
43///////////////////////////////////////////////////////////////////////////////
44// Defines
45///////////////////////////////////////////////////////////////////////////////
46
47// Debug
48#if DEBUG_PATHS
49    #define PATH_LOGD(...) ALOGD(__VA_ARGS__)
50#else
51    #define PATH_LOGD(...)
52#endif
53
54///////////////////////////////////////////////////////////////////////////////
55// Classes
56///////////////////////////////////////////////////////////////////////////////
57
58/**
59 * Alpha texture used to represent a path.
60 */
61struct PathTexture: public Texture {
62    PathTexture(Caches& caches, float left, float top,
63            float offset, int width, int height, int generation)
64            : Texture(caches)
65            , left(left)
66            , top(top)
67            , offset(offset) {
68        this->width = width;
69        this->height = height;
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 ShapeType {
113    kShapeNone,
114    kShapeRect,
115    kShapeRoundRect,
116    kShapeCircle,
117    kShapeOval,
118    kShapeArc,
119    kShapePath
120};
121
122struct PathDescription {
123    DESCRIPTION_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    hash_t hash() const;
165};
166
167/**
168 * A simple LRU shape cache. The cache has a maximum size expressed in bytes.
169 * Any texture added to the cache causing the cache to grow beyond the maximum
170 * allowed size will also cause the oldest texture to be kicked out.
171 */
172class PathCache: public OnEntryRemoved<PathDescription, PathTexture*> {
173public:
174    PathCache();
175    ~PathCache();
176
177    /**
178     * Used as a callback when an entry is removed from the cache.
179     * Do not invoke directly.
180     */
181    void operator()(PathDescription& path, PathTexture*& texture) override;
182
183    /**
184     * Clears the cache. This causes all textures to be deleted.
185     */
186    void clear();
187
188    /**
189     * Returns the maximum size of the cache in bytes.
190     */
191    uint32_t getMaxSize();
192    /**
193     * Returns the current size of the cache in bytes.
194     */
195    uint32_t getSize();
196
197    PathTexture* getRoundRect(float width, float height, float rx, float ry, const SkPaint* paint);
198    PathTexture* getCircle(float radius, const SkPaint* paint);
199    PathTexture* getOval(float width, float height, const SkPaint* paint);
200    PathTexture* getRect(float width, float height, const SkPaint* paint);
201    PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
202            bool useCenter, const SkPaint* paint);
203    PathTexture* get(const SkPath* path, const SkPaint* paint);
204
205    /**
206     * Removes the specified path. This is meant to be called from threads
207     * that are not the EGL context thread.
208     */
209    ANDROID_API void removeDeferred(const SkPath* path);
210    /**
211     * Process deferred removals.
212     */
213    void clearGarbage();
214    /**
215     * Trims the contents of the cache, removing items until it's under its
216     * specified limit.
217     *
218     * Trimming is used for caches that support pre-caching from a worker
219     * thread. During pre-caching the maximum limit of the cache can be
220     * exceeded for the duration of the frame. It is therefore required to
221     * trim the cache at the end of the frame to keep the total amount of
222     * memory used under control.
223     */
224    void trim();
225
226    /**
227     * Precaches the specified path using background threads.
228     */
229    void precache(const SkPath* path, const SkPaint* paint);
230
231    static bool canDrawAsConvexPath(SkPath* path, const SkPaint* paint);
232    static void computePathBounds(const SkPath* path, const SkPaint* paint,
233            float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
234    static void computeBounds(const SkRect& bounds, const SkPaint* paint,
235            float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
236
237private:
238    PathTexture* addTexture(const PathDescription& entry,
239            const SkPath *path, const SkPaint* paint);
240    PathTexture* addTexture(const PathDescription& entry, SkBitmap* bitmap);
241
242    /**
243     * Generates the texture from a bitmap into the specified texture structure.
244     */
245    void generateTexture(SkBitmap& bitmap, Texture* texture);
246    void generateTexture(const PathDescription& entry, SkBitmap* bitmap, PathTexture* texture,
247            bool addToCache = true);
248
249    PathTexture* get(const PathDescription& entry) {
250        return mCache.get(entry);
251    }
252
253    /**
254     * Ensures there is enough space in the cache for a texture of the specified
255     * dimensions.
256     */
257    void purgeCache(uint32_t width, uint32_t height);
258
259    void removeTexture(PathTexture* texture);
260
261    bool checkTextureSize(uint32_t width, uint32_t height) {
262        if (width > mMaxTextureSize || height > mMaxTextureSize) {
263            ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)",
264                    width, height, mMaxTextureSize, mMaxTextureSize);
265            return false;
266        }
267        return true;
268    }
269
270    void init();
271
272    class PathTask: public Task<SkBitmap*> {
273    public:
274        PathTask(const SkPath* path, const SkPaint* paint, PathTexture* texture):
275            path(*path), paint(*paint), texture(texture) {
276        }
277
278        ~PathTask() {
279            delete future()->get();
280        }
281
282        // copied, since input path not guaranteed to survive for duration of task
283        const SkPath path;
284
285        // copied, since input paint may not be immutable
286        const SkPaint paint;
287        PathTexture* texture;
288    };
289
290    class PathProcessor: public TaskProcessor<SkBitmap*> {
291    public:
292        PathProcessor(Caches& caches);
293        ~PathProcessor() { }
294
295        virtual void onProcess(const sp<Task<SkBitmap*> >& task) override;
296
297    private:
298        uint32_t mMaxTextureSize;
299    };
300
301    LruCache<PathDescription, PathTexture*> mCache;
302    uint32_t mSize;
303    uint32_t mMaxSize;
304    GLuint mMaxTextureSize;
305
306    bool mDebugEnabled;
307
308    sp<PathProcessor> mProcessor;
309
310    Vector<uint32_t> mGarbage;
311    mutable Mutex mLock;
312}; // class PathCache
313
314}; // namespace uirenderer
315}; // namespace android
316
317#endif // ANDROID_HWUI_PATH_CACHE_H
318