blob: cc96de71df826bdff57bc25fbf66451b50a904f3 [file] [log] [blame]
Romain Guy7fbcc042010-08-04 15:40:07 -07001/*
Romain Guyc46d07a2013-03-15 19:06:39 -07002 * Copyright (C) 2013 The Android Open Source Project
Romain Guy7fbcc042010-08-04 15:40:07 -07003 *
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
Romain Guyc46d07a2013-03-15 19:06:39 -070017#include <SkBitmap.h>
18#include <SkCanvas.h>
Chris Craik98d608d2014-07-17 12:25:11 -070019#include <SkColor.h>
Mike Reed260ab722016-10-07 15:59:20 -040020#include <SkColorFilter.h>
21#include <SkMaskFilter.h>
Romain Guyc46d07a2013-03-15 19:06:39 -070022#include <SkPaint.h>
23#include <SkPath.h>
sergeyv7224e2b2016-04-07 18:06:53 -070024#include <SkPathEffect.h>
Romain Guyc46d07a2013-03-15 19:06:39 -070025#include <SkRect.h>
Romain Guya2341a92010-09-08 18:04:33 -070026
Romain Guyc46d07a2013-03-15 19:06:39 -070027#include <utils/JenkinsHash.h>
28#include <utils/Trace.h>
Romain Guyca89e2a2013-03-08 17:44:20 -080029
30#include "Caches.h"
Romain Guy7fbcc042010-08-04 15:40:07 -070031#include "PathCache.h"
Romain Guyc46d07a2013-03-15 19:06:39 -070032
33#include "thread/Signal.h"
Romain Guyc46d07a2013-03-15 19:06:39 -070034#include "thread/TaskProcessor.h"
Romain Guy7fbcc042010-08-04 15:40:07 -070035
John Reck6b507802015-11-03 10:09:59 -080036#include <cutils/properties.h>
37
Romain Guy7fbcc042010-08-04 15:40:07 -070038namespace android {
39namespace uirenderer {
40
sergeyv7224e2b2016-04-07 18:06:53 -070041template <class T>
42static bool compareWidthHeight(const T& lhs, const T& rhs) {
43 return (lhs.mWidth == rhs.mWidth) && (lhs.mHeight == rhs.mHeight);
44}
45
46static bool compareRoundRects(const PathDescription::Shape::RoundRect& lhs,
47 const PathDescription::Shape::RoundRect& rhs) {
48 return compareWidthHeight(lhs, rhs) && lhs.mRx == rhs.mRx && lhs.mRy == rhs.mRy;
49}
50
51static bool compareArcs(const PathDescription::Shape::Arc& lhs, const PathDescription::Shape::Arc& rhs) {
52 return compareWidthHeight(lhs, rhs) && lhs.mStartAngle == rhs.mStartAngle &&
53 lhs.mSweepAngle == rhs.mSweepAngle && lhs.mUseCenter == rhs.mUseCenter;
54}
55
Romain Guyca89e2a2013-03-08 17:44:20 -080056///////////////////////////////////////////////////////////////////////////////
Romain Guyc46d07a2013-03-15 19:06:39 -070057// Cache entries
58///////////////////////////////////////////////////////////////////////////////
59
Chris Craike2bb3802015-03-13 15:07:52 -070060PathDescription::PathDescription()
sergeyv7224e2b2016-04-07 18:06:53 -070061 : type(ShapeType::None)
Chris Craike2bb3802015-03-13 15:07:52 -070062 , join(SkPaint::kDefault_Join)
63 , cap(SkPaint::kDefault_Cap)
64 , style(SkPaint::kFill_Style)
65 , miter(4.0f)
66 , strokeWidth(1.0f)
67 , pathEffect(nullptr) {
sergeyv7224e2b2016-04-07 18:06:53 -070068 // Shape bits should be set to zeroes, because they are used for hash calculation.
Romain Guyc46d07a2013-03-15 19:06:39 -070069 memset(&shape, 0, sizeof(Shape));
70}
71
Chris Craike2bb3802015-03-13 15:07:52 -070072PathDescription::PathDescription(ShapeType type, const SkPaint* paint)
73 : type(type)
74 , join(paint->getStrokeJoin())
75 , cap(paint->getStrokeCap())
76 , style(paint->getStyle())
77 , miter(paint->getStrokeMiter())
78 , strokeWidth(paint->getStrokeWidth())
79 , pathEffect(paint->getPathEffect()) {
sergeyv7224e2b2016-04-07 18:06:53 -070080 // Shape bits should be set to zeroes, because they are used for hash calculation.
Romain Guyc46d07a2013-03-15 19:06:39 -070081 memset(&shape, 0, sizeof(Shape));
82}
83
84hash_t PathDescription::hash() const {
sergeyv7224e2b2016-04-07 18:06:53 -070085 uint32_t hash = JenkinsHashMix(0, static_cast<int>(type));
Romain Guyc46d07a2013-03-15 19:06:39 -070086 hash = JenkinsHashMix(hash, join);
87 hash = JenkinsHashMix(hash, cap);
88 hash = JenkinsHashMix(hash, style);
89 hash = JenkinsHashMix(hash, android::hash_type(miter));
90 hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
91 hash = JenkinsHashMix(hash, android::hash_type(pathEffect));
92 hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
93 return JenkinsHashWhiten(hash);
94}
95
sergeyv7224e2b2016-04-07 18:06:53 -070096bool PathDescription::operator==(const PathDescription& rhs) const {
97 if (type != rhs.type) return false;
98 if (join != rhs.join) return false;
99 if (cap != rhs.cap) return false;
100 if (style != rhs.style) return false;
101 if (miter != rhs.miter) return false;
102 if (strokeWidth != rhs.strokeWidth) return false;
103 if (pathEffect != rhs.pathEffect) return false;
104 switch (type) {
105 case ShapeType::None:
106 return 0;
107 case ShapeType::Rect:
108 return compareWidthHeight(shape.rect, rhs.shape.rect);
109 case ShapeType::RoundRect:
110 return compareRoundRects(shape.roundRect, rhs.shape.roundRect);
111 case ShapeType::Circle:
112 return shape.circle.mRadius == rhs.shape.circle.mRadius;
113 case ShapeType::Oval:
114 return compareWidthHeight(shape.oval, rhs.shape.oval);
115 case ShapeType::Arc:
116 return compareArcs(shape.arc, rhs.shape.arc);
117 case ShapeType::Path:
118 return shape.path.mGenerationID == rhs.shape.path.mGenerationID;
119 }
120}
121
Romain Guyc46d07a2013-03-15 19:06:39 -0700122///////////////////////////////////////////////////////////////////////////////
123// Utilities
124///////////////////////////////////////////////////////////////////////////////
125
sergeyvd93b9bd2016-08-04 16:18:22 -0700126static void computePathBounds(const SkPath* path, const SkPaint* paint, PathTexture* texture,
127 uint32_t& width, uint32_t& height) {
Romain Guyc46d07a2013-03-15 19:06:39 -0700128 const SkRect& bounds = path->getBounds();
Chris Craike6a15ee2015-07-07 18:42:17 -0700129 const float pathWidth = std::max(bounds.width(), 1.0f);
130 const float pathHeight = std::max(bounds.height(), 1.0f);
Romain Guyc46d07a2013-03-15 19:06:39 -0700131
sergeyv89561e62016-08-04 16:21:07 -0700132 texture->left = floorf(bounds.fLeft);
133 texture->top = floorf(bounds.fTop);
Romain Guyc46d07a2013-03-15 19:06:39 -0700134
sergeyvd93b9bd2016-08-04 16:18:22 -0700135 texture->offset = (int) floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
Romain Guyc46d07a2013-03-15 19:06:39 -0700136
sergeyvd93b9bd2016-08-04 16:18:22 -0700137 width = uint32_t(pathWidth + texture->offset * 2.0 + 0.5);
138 height = uint32_t(pathHeight + texture->offset * 2.0 + 0.5);
Romain Guyc46d07a2013-03-15 19:06:39 -0700139}
140
Romain Guyc46d07a2013-03-15 19:06:39 -0700141static void initPaint(SkPaint& paint) {
142 // Make sure the paint is opaque, color, alpha, filter, etc.
143 // will be applied later when compositing the alpha8 texture
Chris Craik98d608d2014-07-17 12:25:11 -0700144 paint.setColor(SK_ColorBLACK);
Romain Guyc46d07a2013-03-15 19:06:39 -0700145 paint.setAlpha(255);
Chris Craikd41c4d82015-01-05 15:51:13 -0800146 paint.setColorFilter(nullptr);
147 paint.setMaskFilter(nullptr);
148 paint.setShader(nullptr);
Mike Reed260ab722016-10-07 15:59:20 -0400149 paint.setBlendMode(SkBlendMode::kSrc);
Romain Guyc46d07a2013-03-15 19:06:39 -0700150}
151
sergeyv98fa4f92016-10-24 15:35:21 -0700152static sk_sp<Bitmap> drawPath(const SkPath* path, const SkPaint* paint, PathTexture* texture,
sergeyvd93b9bd2016-08-04 16:18:22 -0700153 uint32_t maxTextureSize) {
154 uint32_t width, height;
155 computePathBounds(path, paint, texture, width, height);
156 if (width > maxTextureSize || height > maxTextureSize) {
157 ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)",
158 width, height, maxTextureSize, maxTextureSize);
159 return nullptr;
160 }
161
sergeyv98fa4f92016-10-24 15:35:21 -0700162 sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(SkImageInfo::MakeA8(width, height));
Romain Guyc46d07a2013-03-15 19:06:39 -0700163 SkPaint pathPaint(*paint);
164 initPaint(pathPaint);
165
sergeyv98fa4f92016-10-24 15:35:21 -0700166 SkBitmap skBitmap;
167 bitmap->getSkBitmap(&skBitmap);
168 skBitmap.eraseColor(0);
169 SkCanvas canvas(skBitmap);
sergeyvd93b9bd2016-08-04 16:18:22 -0700170 canvas.translate(-texture->left + texture->offset, -texture->top + texture->offset);
Romain Guyc46d07a2013-03-15 19:06:39 -0700171 canvas.drawPath(*path, pathPaint);
sergeyvd93b9bd2016-08-04 16:18:22 -0700172 return bitmap;
Romain Guyc46d07a2013-03-15 19:06:39 -0700173}
174
Romain Guyc46d07a2013-03-15 19:06:39 -0700175///////////////////////////////////////////////////////////////////////////////
176// Cache constructor/destructor
177///////////////////////////////////////////////////////////////////////////////
178
Chris Craik48a8f432016-02-05 15:59:29 -0800179PathCache::PathCache()
180 : mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity)
181 , mSize(0)
John Reckcecec702016-10-12 14:08:49 -0700182 , mMaxSize(Properties::pathCacheSize) {
Romain Guyc46d07a2013-03-15 19:06:39 -0700183 mCache.setOnEntryRemovedListener(this);
184
185 GLint maxTextureSize;
186 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
187 mMaxTextureSize = maxTextureSize;
188
Chris Craik2507c342015-05-04 14:36:49 -0700189 mDebugEnabled = Properties::debugLevel & kDebugCaches;
Romain Guyc46d07a2013-03-15 19:06:39 -0700190}
191
Chris Craik05f3d6e2014-06-02 16:27:04 -0700192PathCache::~PathCache() {
193 mCache.clear();
194}
195
Romain Guyc46d07a2013-03-15 19:06:39 -0700196///////////////////////////////////////////////////////////////////////////////
197// Size management
198///////////////////////////////////////////////////////////////////////////////
199
200uint32_t PathCache::getSize() {
201 return mSize;
202}
203
204uint32_t PathCache::getMaxSize() {
205 return mMaxSize;
206}
207
Romain Guyc46d07a2013-03-15 19:06:39 -0700208///////////////////////////////////////////////////////////////////////////////
209// Callbacks
210///////////////////////////////////////////////////////////////////////////////
211
Andreas Gampe64bb4132014-11-22 00:35:09 +0000212void PathCache::operator()(PathDescription& entry, PathTexture*& texture) {
Romain Guyc46d07a2013-03-15 19:06:39 -0700213 removeTexture(texture);
214}
215
216///////////////////////////////////////////////////////////////////////////////
217// Caching
218///////////////////////////////////////////////////////////////////////////////
219
220void PathCache::removeTexture(PathTexture* texture) {
221 if (texture) {
John Reck38e0c322015-11-10 12:19:17 -0800222 const uint32_t size = texture->width() * texture->height();
Romain Guy5d923202013-08-21 18:40:24 -0700223
224 // If there is a pending task we must wait for it to return
225 // before attempting our cleanup
sergeyv98fa4f92016-10-24 15:35:21 -0700226 const sp<PathTask>& task = texture->task();
Chris Craikd41c4d82015-01-05 15:51:13 -0800227 if (task != nullptr) {
Andreas Gampe1e196742014-11-10 15:23:43 -0800228 task->getResult();
Romain Guy5d923202013-08-21 18:40:24 -0700229 texture->clearTask();
230 } else {
231 // If there is a pending task, the path was not added
232 // to the cache and the size wasn't increased
233 if (size > mSize) {
234 ALOGE("Removing path texture of size %d will leave "
235 "the cache in an inconsistent state", size);
236 }
237 mSize -= size;
238 }
Romain Guyc46d07a2013-03-15 19:06:39 -0700239
240 PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
241 texture->id, size, mSize);
242 if (mDebugEnabled) {
243 ALOGD("Shape deleted, size = %d", size);
244 }
245
John Reck38e0c322015-11-10 12:19:17 -0800246 texture->deleteTexture();
Romain Guyc46d07a2013-03-15 19:06:39 -0700247 delete texture;
248 }
249}
250
251void PathCache::purgeCache(uint32_t width, uint32_t height) {
252 const uint32_t size = width * height;
253 // Don't even try to cache a bitmap that's bigger than the cache
254 if (size < mMaxSize) {
255 while (mSize + size > mMaxSize) {
256 mCache.removeOldest();
257 }
258 }
259}
260
261void PathCache::trim() {
John Reckcecec702016-10-12 14:08:49 -0700262 // 25 is just an arbitrary lower bound to ensure we aren't in weird edge cases
263 // of things like a cap of 0 or 1 as that's going to break things.
264 // It does not represent a reasonable minimum value
265 static_assert(DEFAULT_PATH_TEXTURE_CAP > 25, "Path cache texture cap is too small");
266
267 while (mSize > mMaxSize || mCache.size() > DEFAULT_PATH_TEXTURE_CAP) {
268 LOG_ALWAYS_FATAL_IF(!mCache.size(), "Inconsistent mSize! Ran out of items to remove!"
269 " mSize = %u, mMaxSize = %u", mSize, mMaxSize);
Romain Guyc46d07a2013-03-15 19:06:39 -0700270 mCache.removeOldest();
271 }
272}
273
274PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *path,
275 const SkPaint* paint) {
Chris Craik70850ea2014-11-18 10:49:23 -0800276 ATRACE_NAME("Generate Path Texture");
Romain Guyc46d07a2013-03-15 19:06:39 -0700277
sergeyvd93b9bd2016-08-04 16:18:22 -0700278 PathTexture* texture = new PathTexture(Caches::getInstance(), path->getGenerationID());
sergeyv98fa4f92016-10-24 15:35:21 -0700279 sk_sp<Bitmap> bitmap(drawPath(path, paint, texture, mMaxTextureSize));
280 if (!bitmap) {
sergeyvd93b9bd2016-08-04 16:18:22 -0700281 delete texture;
282 return nullptr;
283 }
Romain Guyc46d07a2013-03-15 19:06:39 -0700284
sergeyvd93b9bd2016-08-04 16:18:22 -0700285 purgeCache(bitmap->width(), bitmap->height());
sergeyv98fa4f92016-10-24 15:35:21 -0700286 generateTexture(entry, *bitmap, texture);
Romain Guyc46d07a2013-03-15 19:06:39 -0700287 return texture;
288}
289
sergeyv98fa4f92016-10-24 15:35:21 -0700290void PathCache::generateTexture(const PathDescription& entry, Bitmap& bitmap,
Romain Guy4500a8d2013-03-26 17:29:51 -0700291 PathTexture* texture, bool addToCache) {
sergeyv98fa4f92016-10-24 15:35:21 -0700292 generateTexture(bitmap, texture);
Romain Guyc46d07a2013-03-15 19:06:39 -0700293
Chris Craik42455fc2015-05-11 18:23:09 -0700294 // Note here that we upload to a texture even if it's bigger than mMaxSize.
295 // Such an entry in mCache will only be temporary, since it will be evicted
296 // immediately on trim, or on any other Path entering the cache.
John Reck38e0c322015-11-10 12:19:17 -0800297 uint32_t size = texture->width() * texture->height();
Chris Craik42455fc2015-05-11 18:23:09 -0700298 mSize += size;
299 PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d",
300 texture->id, size, mSize);
301 if (mDebugEnabled) {
302 ALOGD("Shape created, size = %d", size);
303 }
304 if (addToCache) {
305 mCache.put(entry, texture);
Romain Guyc46d07a2013-03-15 19:06:39 -0700306 }
307}
308
309void PathCache::clear() {
310 mCache.clear();
311}
312
sergeyv98fa4f92016-10-24 15:35:21 -0700313void PathCache::generateTexture(Bitmap& bitmap, Texture* texture) {
Chris Craikcf8426c2015-05-13 17:05:48 -0700314 ATRACE_NAME("Upload Path Texture");
John Reck38e0c322015-11-10 12:19:17 -0800315 texture->upload(bitmap);
Romain Guyc46d07a2013-03-15 19:06:39 -0700316 texture->setFilter(GL_LINEAR);
Romain Guyc46d07a2013-03-15 19:06:39 -0700317}
318
319///////////////////////////////////////////////////////////////////////////////
Romain Guyca89e2a2013-03-08 17:44:20 -0800320// Path precaching
321///////////////////////////////////////////////////////////////////////////////
Romain Guyfdd6fc12012-04-27 11:47:13 -0700322
Romain Guy5dc7fa72013-03-11 20:48:31 -0700323PathCache::PathProcessor::PathProcessor(Caches& caches):
sergeyv98fa4f92016-10-24 15:35:21 -0700324 TaskProcessor<sk_sp<Bitmap> >(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {
Romain Guyfdd6fc12012-04-27 11:47:13 -0700325}
Romain Guy33f6beb2012-02-16 19:24:51 -0800326
sergeyv98fa4f92016-10-24 15:35:21 -0700327void PathCache::PathProcessor::onProcess(const sp<Task<sk_sp<Bitmap> > >& task) {
Chris Craik05f3d6e2014-06-02 16:27:04 -0700328 PathTask* t = static_cast<PathTask*>(task.get());
Romain Guy5dc7fa72013-03-11 20:48:31 -0700329 ATRACE_NAME("pathPrecache");
330
sergeyvd93b9bd2016-08-04 16:18:22 -0700331 t->setResult(drawPath(&t->path, &t->paint, t->texture, mMaxTextureSize));
Romain Guy33f6beb2012-02-16 19:24:51 -0800332}
333
Romain Guy7fbcc042010-08-04 15:40:07 -0700334///////////////////////////////////////////////////////////////////////////////
Romain Guyc46d07a2013-03-15 19:06:39 -0700335// Paths
Romain Guy7fbcc042010-08-04 15:40:07 -0700336///////////////////////////////////////////////////////////////////////////////
337
Derek Sollenbergeree248592015-02-12 14:10:21 -0500338void PathCache::removeDeferred(const SkPath* path) {
Romain Guyca89e2a2013-03-08 17:44:20 -0800339 Mutex::Autolock l(mLock);
John Reck272a6852015-07-29 16:48:58 -0700340 mGarbage.push_back(path->getGenerationID());
Romain Guyfe48f652010-11-11 15:36:56 -0800341}
342
343void PathCache::clearGarbage() {
Romain Guye3b0a012013-06-26 15:45:41 -0700344 Vector<PathDescription> pathsToRemove;
345
346 { // scope for the mutex
347 Mutex::Autolock l(mLock);
John Reck272a6852015-07-29 16:48:58 -0700348 for (const uint32_t generationID : mGarbage) {
Derek Sollenbergeree248592015-02-12 14:10:21 -0500349 LruCache<PathDescription, PathTexture*>::Iterator iter(mCache);
350 while (iter.next()) {
351 const PathDescription& key = iter.key();
sergeyv7224e2b2016-04-07 18:06:53 -0700352 if (key.type == ShapeType::Path && key.shape.path.mGenerationID == generationID) {
Derek Sollenbergeree248592015-02-12 14:10:21 -0500353 pathsToRemove.push(key);
354 }
355 }
Romain Guye3b0a012013-06-26 15:45:41 -0700356 }
357 mGarbage.clear();
Romain Guyfe48f652010-11-11 15:36:56 -0800358 }
Romain Guye3b0a012013-06-26 15:45:41 -0700359
360 for (size_t i = 0; i < pathsToRemove.size(); i++) {
361 mCache.remove(pathsToRemove.itemAt(i));
362 }
Romain Guya2341a92010-09-08 18:04:33 -0700363}
364
Chris Craikd218a922014-01-02 17:13:34 -0800365PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700366 PathDescription entry(ShapeType::Path, paint);
Derek Sollenbergeree248592015-02-12 14:10:21 -0500367 entry.shape.path.mGenerationID = path->getGenerationID();
Romain Guyc46d07a2013-03-15 19:06:39 -0700368
Romain Guy7fbcc042010-08-04 15:40:07 -0700369 PathTexture* texture = mCache.get(entry);
370
371 if (!texture) {
372 texture = addTexture(entry, path, paint);
Romain Guyca89e2a2013-03-08 17:44:20 -0800373 } else {
374 // A bitmap is attached to the texture, this means we need to
375 // upload it as a GL texture
sergeyv98fa4f92016-10-24 15:35:21 -0700376 const sp<PathTask>& task = texture->task();
Chris Craikd41c4d82015-01-05 15:51:13 -0800377 if (task != nullptr) {
Romain Guyca89e2a2013-03-08 17:44:20 -0800378 // But we must first wait for the worker thread to be done
379 // producing the bitmap, so let's wait
sergeyv98fa4f92016-10-24 15:35:21 -0700380 sk_sp<Bitmap> bitmap = task->getResult();
Romain Guyca89e2a2013-03-08 17:44:20 -0800381 if (bitmap) {
sergeyv98fa4f92016-10-24 15:35:21 -0700382 generateTexture(entry, *bitmap, texture, false);
Romain Guy5dc7fa72013-03-11 20:48:31 -0700383 texture->clearTask();
Romain Guyca89e2a2013-03-08 17:44:20 -0800384 } else {
Romain Guy5dc7fa72013-03-11 20:48:31 -0700385 texture->clearTask();
Chris Craikd41c4d82015-01-05 15:51:13 -0800386 texture = nullptr;
Romain Guyca89e2a2013-03-08 17:44:20 -0800387 mCache.remove(entry);
388 }
Romain Guyca89e2a2013-03-08 17:44:20 -0800389 }
Romain Guy7fbcc042010-08-04 15:40:07 -0700390 }
391
Romain Guy7fbcc042010-08-04 15:40:07 -0700392 return texture;
393}
394
sergeyv7224e2b2016-04-07 18:06:53 -0700395void PathCache::remove(const SkPath* path, const SkPaint* paint) {
396 PathDescription entry(ShapeType::Path, paint);
Digish Pandya2e4f67c2015-11-04 11:00:28 +0530397 entry.shape.path.mGenerationID = path->getGenerationID();
398 mCache.remove(entry);
399}
400
Chris Craikd218a922014-01-02 17:13:34 -0800401void PathCache::precache(const SkPath* path, const SkPaint* paint) {
Romain Guy5dc7fa72013-03-11 20:48:31 -0700402 if (!Caches::getInstance().tasks.canRunTasks()) {
403 return;
404 }
405
sergeyv7224e2b2016-04-07 18:06:53 -0700406 PathDescription entry(ShapeType::Path, paint);
Derek Sollenbergeree248592015-02-12 14:10:21 -0500407 entry.shape.path.mGenerationID = path->getGenerationID();
Romain Guyc46d07a2013-03-15 19:06:39 -0700408
Romain Guyca89e2a2013-03-08 17:44:20 -0800409 PathTexture* texture = mCache.get(entry);
410
411 bool generate = false;
412 if (!texture) {
413 generate = true;
Romain Guyca89e2a2013-03-08 17:44:20 -0800414 }
415
416 if (generate) {
417 // It is important to specify the generation ID so we do not
418 // attempt to precache the same path several times
Chris Craike2bb3802015-03-13 15:07:52 -0700419 texture = new PathTexture(Caches::getInstance(), path->getGenerationID());
Romain Guy5dc7fa72013-03-11 20:48:31 -0700420 sp<PathTask> task = new PathTask(path, paint, texture);
421 texture->setTask(task);
Romain Guyca89e2a2013-03-08 17:44:20 -0800422
423 // During the precaching phase we insert path texture objects into
424 // the cache that do not point to any GL texture. They are instead
425 // treated as a task for the precaching worker thread. This is why
426 // we do not check the cache limit when inserting these objects.
427 // The conversion into GL texture will happen in get(), when a client
428 // asks for a path texture. This is also when the cache limit will
429 // be enforced.
430 mCache.put(entry, texture);
Romain Guy5dc7fa72013-03-11 20:48:31 -0700431
Chris Craikd41c4d82015-01-05 15:51:13 -0800432 if (mProcessor == nullptr) {
Romain Guy5dc7fa72013-03-11 20:48:31 -0700433 mProcessor = new PathProcessor(Caches::getInstance());
434 }
Chris Craikdee66b62015-04-20 14:54:49 -0700435 mProcessor->add(task);
Romain Guyca89e2a2013-03-08 17:44:20 -0800436 }
437}
438
Romain Guyc46d07a2013-03-15 19:06:39 -0700439///////////////////////////////////////////////////////////////////////////////
440// Rounded rects
441///////////////////////////////////////////////////////////////////////////////
442
443PathTexture* PathCache::getRoundRect(float width, float height,
Chris Craikd218a922014-01-02 17:13:34 -0800444 float rx, float ry, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700445 PathDescription entry(ShapeType::RoundRect, paint);
Romain Guyc46d07a2013-03-15 19:06:39 -0700446 entry.shape.roundRect.mWidth = width;
447 entry.shape.roundRect.mHeight = height;
448 entry.shape.roundRect.mRx = rx;
449 entry.shape.roundRect.mRy = ry;
450
451 PathTexture* texture = get(entry);
452
453 if (!texture) {
454 SkPath path;
455 SkRect r;
456 r.set(0.0f, 0.0f, width, height);
457 path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
458
459 texture = addTexture(entry, &path, paint);
460 }
461
462 return texture;
463}
464
465///////////////////////////////////////////////////////////////////////////////
466// Circles
467///////////////////////////////////////////////////////////////////////////////
468
Chris Craikd218a922014-01-02 17:13:34 -0800469PathTexture* PathCache::getCircle(float radius, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700470 PathDescription entry(ShapeType::Circle, paint);
Romain Guyc46d07a2013-03-15 19:06:39 -0700471 entry.shape.circle.mRadius = radius;
472
473 PathTexture* texture = get(entry);
474
475 if (!texture) {
476 SkPath path;
477 path.addCircle(radius, radius, radius, SkPath::kCW_Direction);
478
479 texture = addTexture(entry, &path, paint);
480 }
481
482 return texture;
483}
484
485///////////////////////////////////////////////////////////////////////////////
486// Ovals
487///////////////////////////////////////////////////////////////////////////////
488
Chris Craikd218a922014-01-02 17:13:34 -0800489PathTexture* PathCache::getOval(float width, float height, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700490 PathDescription entry(ShapeType::Oval, paint);
Romain Guyc46d07a2013-03-15 19:06:39 -0700491 entry.shape.oval.mWidth = width;
492 entry.shape.oval.mHeight = height;
493
494 PathTexture* texture = get(entry);
495
496 if (!texture) {
497 SkPath path;
498 SkRect r;
499 r.set(0.0f, 0.0f, width, height);
500 path.addOval(r, SkPath::kCW_Direction);
501
502 texture = addTexture(entry, &path, paint);
503 }
504
505 return texture;
506}
507
508///////////////////////////////////////////////////////////////////////////////
509// Rects
510///////////////////////////////////////////////////////////////////////////////
511
Chris Craikd218a922014-01-02 17:13:34 -0800512PathTexture* PathCache::getRect(float width, float height, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700513 PathDescription entry(ShapeType::Rect, paint);
Romain Guyc46d07a2013-03-15 19:06:39 -0700514 entry.shape.rect.mWidth = width;
515 entry.shape.rect.mHeight = height;
516
517 PathTexture* texture = get(entry);
518
519 if (!texture) {
520 SkPath path;
521 SkRect r;
522 r.set(0.0f, 0.0f, width, height);
523 path.addRect(r, SkPath::kCW_Direction);
524
525 texture = addTexture(entry, &path, paint);
526 }
527
528 return texture;
529}
530
531///////////////////////////////////////////////////////////////////////////////
532// Arcs
533///////////////////////////////////////////////////////////////////////////////
534
535PathTexture* PathCache::getArc(float width, float height,
Chris Craikd218a922014-01-02 17:13:34 -0800536 float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700537 PathDescription entry(ShapeType::Arc, paint);
Romain Guyc46d07a2013-03-15 19:06:39 -0700538 entry.shape.arc.mWidth = width;
539 entry.shape.arc.mHeight = height;
540 entry.shape.arc.mStartAngle = startAngle;
541 entry.shape.arc.mSweepAngle = sweepAngle;
542 entry.shape.arc.mUseCenter = useCenter;
543
544 PathTexture* texture = get(entry);
545
546 if (!texture) {
547 SkPath path;
548 SkRect r;
549 r.set(0.0f, 0.0f, width, height);
550 if (useCenter) {
551 path.moveTo(r.centerX(), r.centerY());
552 }
553 path.arcTo(r, startAngle, sweepAngle, !useCenter);
554 if (useCenter) {
555 path.close();
556 }
557
558 texture = addTexture(entry, &path, paint);
559 }
560
561 return texture;
562}
563
Romain Guy7fbcc042010-08-04 15:40:07 -0700564}; // namespace uirenderer
565}; // namespace android