| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef ANDROID_HWUI_PATH_CACHE_H |
| #define ANDROID_HWUI_PATH_CACHE_H |
| |
| #include "Debug.h" |
| #include "Texture.h" |
| #include "thread/Task.h" |
| #include "thread/TaskProcessor.h" |
| #include "utils/Macros.h" |
| #include "utils/Pair.h" |
| |
| #include <GLES2/gl2.h> |
| #include <SkPath.h> |
| #include <utils/LruCache.h> |
| #include <utils/Mutex.h> |
| |
| #include <vector> |
| |
| class SkBitmap; |
| class SkCanvas; |
| class SkPaint; |
| struct SkRect; |
| |
| namespace android { |
| namespace uirenderer { |
| |
| class Caches; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Defines |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| // Debug |
| #if DEBUG_PATHS |
| #define PATH_LOGD(...) ALOGD(__VA_ARGS__) |
| #else |
| #define PATH_LOGD(...) |
| #endif |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Classes |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| /** |
| * Alpha texture used to represent a path. |
| */ |
| struct PathTexture: public Texture { |
| PathTexture(Caches& caches, float left, float top, |
| float offset, int generation) |
| : Texture(caches) |
| , left(left) |
| , top(top) |
| , offset(offset) { |
| this->generation = generation; |
| } |
| PathTexture(Caches& caches, int generation) |
| : Texture(caches) { |
| this->generation = generation; |
| } |
| |
| ~PathTexture() { |
| clearTask(); |
| } |
| |
| /** |
| * Left coordinate of the path bounds. |
| */ |
| float left = 0; |
| /** |
| * Top coordinate of the path bounds. |
| */ |
| float top = 0; |
| /** |
| * Offset to draw the path at the correct origin. |
| */ |
| float offset = 0; |
| |
| sp<Task<SkBitmap*> > task() const { |
| return mTask; |
| } |
| |
| void setTask(const sp<Task<SkBitmap*> >& task) { |
| mTask = task; |
| } |
| |
| void clearTask() { |
| if (mTask != nullptr) { |
| mTask.clear(); |
| } |
| } |
| |
| private: |
| sp<Task<SkBitmap*> > mTask; |
| }; // struct PathTexture |
| |
| enum ShapeType { |
| kShapeNone, |
| kShapeRect, |
| kShapeRoundRect, |
| kShapeCircle, |
| kShapeOval, |
| kShapeArc, |
| kShapePath |
| }; |
| |
| struct PathDescription { |
| DESCRIPTION_TYPE(PathDescription); |
| ShapeType type; |
| SkPaint::Join join; |
| SkPaint::Cap cap; |
| SkPaint::Style style; |
| float miter; |
| float strokeWidth; |
| SkPathEffect* pathEffect; |
| union Shape { |
| struct Path { |
| uint32_t mGenerationID; |
| } path; |
| struct RoundRect { |
| float mWidth; |
| float mHeight; |
| float mRx; |
| float mRy; |
| } roundRect; |
| struct Circle { |
| float mRadius; |
| } circle; |
| struct Oval { |
| float mWidth; |
| float mHeight; |
| } oval; |
| struct Rect { |
| float mWidth; |
| float mHeight; |
| } rect; |
| struct Arc { |
| float mWidth; |
| float mHeight; |
| float mStartAngle; |
| float mSweepAngle; |
| bool mUseCenter; |
| } arc; |
| } shape; |
| |
| PathDescription(); |
| PathDescription(ShapeType shapeType, const SkPaint* paint); |
| |
| hash_t hash() const; |
| }; |
| |
| /** |
| * A simple LRU shape cache. The cache has a maximum size expressed in bytes. |
| * Any texture added to the cache causing the cache to grow beyond the maximum |
| * allowed size will also cause the oldest texture to be kicked out. |
| */ |
| class PathCache: public OnEntryRemoved<PathDescription, PathTexture*> { |
| public: |
| PathCache(); |
| ~PathCache(); |
| |
| /** |
| * Used as a callback when an entry is removed from the cache. |
| * Do not invoke directly. |
| */ |
| void operator()(PathDescription& path, PathTexture*& texture) override; |
| |
| /** |
| * Clears the cache. This causes all textures to be deleted. |
| */ |
| void clear(); |
| |
| /** |
| * Returns the maximum size of the cache in bytes. |
| */ |
| uint32_t getMaxSize(); |
| /** |
| * Returns the current size of the cache in bytes. |
| */ |
| uint32_t getSize(); |
| |
| PathTexture* getRoundRect(float width, float height, float rx, float ry, const SkPaint* paint); |
| PathTexture* getCircle(float radius, const SkPaint* paint); |
| PathTexture* getOval(float width, float height, const SkPaint* paint); |
| PathTexture* getRect(float width, float height, const SkPaint* paint); |
| PathTexture* getArc(float width, float height, float startAngle, float sweepAngle, |
| bool useCenter, const SkPaint* paint); |
| PathTexture* get(const SkPath* path, const SkPaint* paint); |
| void remove(const SkPath* path, const SkPaint* paint); |
| |
| /** |
| * Removes the specified path. This is meant to be called from threads |
| * that are not the EGL context thread. |
| */ |
| ANDROID_API void removeDeferred(const SkPath* path); |
| /** |
| * Process deferred removals. |
| */ |
| void clearGarbage(); |
| /** |
| * Trims the contents of the cache, removing items until it's under its |
| * specified limit. |
| * |
| * Trimming is used for caches that support pre-caching from a worker |
| * thread. During pre-caching the maximum limit of the cache can be |
| * exceeded for the duration of the frame. It is therefore required to |
| * trim the cache at the end of the frame to keep the total amount of |
| * memory used under control. |
| */ |
| void trim(); |
| |
| /** |
| * Precaches the specified path using background threads. |
| */ |
| void precache(const SkPath* path, const SkPaint* paint); |
| |
| static bool canDrawAsConvexPath(SkPath* path, const SkPaint* paint); |
| static void computePathBounds(const SkPath* path, const SkPaint* paint, |
| float& left, float& top, float& offset, uint32_t& width, uint32_t& height); |
| static void computeBounds(const SkRect& bounds, const SkPaint* paint, |
| float& left, float& top, float& offset, uint32_t& width, uint32_t& height); |
| |
| private: |
| PathTexture* addTexture(const PathDescription& entry, |
| const SkPath *path, const SkPaint* paint); |
| PathTexture* addTexture(const PathDescription& entry, SkBitmap* bitmap); |
| |
| /** |
| * Generates the texture from a bitmap into the specified texture structure. |
| */ |
| void generateTexture(SkBitmap& bitmap, Texture* texture); |
| void generateTexture(const PathDescription& entry, SkBitmap* bitmap, PathTexture* texture, |
| bool addToCache = true); |
| |
| PathTexture* get(const PathDescription& entry) { |
| return mCache.get(entry); |
| } |
| |
| /** |
| * Ensures there is enough space in the cache for a texture of the specified |
| * dimensions. |
| */ |
| void purgeCache(uint32_t width, uint32_t height); |
| |
| void removeTexture(PathTexture* texture); |
| |
| bool checkTextureSize(uint32_t width, uint32_t height) { |
| if (width > mMaxTextureSize || height > mMaxTextureSize) { |
| ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)", |
| width, height, mMaxTextureSize, mMaxTextureSize); |
| return false; |
| } |
| return true; |
| } |
| |
| void init(); |
| |
| class PathTask: public Task<SkBitmap*> { |
| public: |
| PathTask(const SkPath* path, const SkPaint* paint, PathTexture* texture): |
| path(*path), paint(*paint), texture(texture) { |
| } |
| |
| ~PathTask() { |
| delete future()->get(); |
| } |
| |
| // copied, since input path not guaranteed to survive for duration of task |
| const SkPath path; |
| |
| // copied, since input paint may not be immutable |
| const SkPaint paint; |
| PathTexture* texture; |
| }; |
| |
| class PathProcessor: public TaskProcessor<SkBitmap*> { |
| public: |
| PathProcessor(Caches& caches); |
| ~PathProcessor() { } |
| |
| virtual void onProcess(const sp<Task<SkBitmap*> >& task) override; |
| |
| private: |
| uint32_t mMaxTextureSize; |
| }; |
| |
| LruCache<PathDescription, PathTexture*> mCache; |
| uint32_t mSize; |
| uint32_t mMaxSize; |
| GLuint mMaxTextureSize; |
| |
| bool mDebugEnabled; |
| |
| sp<PathProcessor> mProcessor; |
| |
| std::vector<uint32_t> mGarbage; |
| mutable Mutex mLock; |
| }; // class PathCache |
| |
| }; // namespace uirenderer |
| }; // namespace android |
| |
| #endif // ANDROID_HWUI_PATH_CACHE_H |