blob: d46c46f9381f315f6e18c543537be4fd18118984 [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
141static void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) {
Mike Reedb9330552014-06-16 17:31:48 -0400142 bitmap.allocPixels(SkImageInfo::MakeA8(width, height));
Romain Guyc46d07a2013-03-15 19:06:39 -0700143 bitmap.eraseColor(0);
144}
145
146static void initPaint(SkPaint& paint) {
147 // Make sure the paint is opaque, color, alpha, filter, etc.
148 // will be applied later when compositing the alpha8 texture
Chris Craik98d608d2014-07-17 12:25:11 -0700149 paint.setColor(SK_ColorBLACK);
Romain Guyc46d07a2013-03-15 19:06:39 -0700150 paint.setAlpha(255);
Chris Craikd41c4d82015-01-05 15:51:13 -0800151 paint.setColorFilter(nullptr);
152 paint.setMaskFilter(nullptr);
153 paint.setShader(nullptr);
Mike Reed260ab722016-10-07 15:59:20 -0400154 paint.setBlendMode(SkBlendMode::kSrc);
Romain Guyc46d07a2013-03-15 19:06:39 -0700155}
156
sergeyvd93b9bd2016-08-04 16:18:22 -0700157static SkBitmap* drawPath(const SkPath* path, const SkPaint* paint, PathTexture* texture,
158 uint32_t maxTextureSize) {
159 uint32_t width, height;
160 computePathBounds(path, paint, texture, width, height);
161 if (width > maxTextureSize || height > maxTextureSize) {
162 ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)",
163 width, height, maxTextureSize, maxTextureSize);
164 return nullptr;
165 }
166
167 SkBitmap* bitmap = new SkBitmap();
168 initBitmap(*bitmap, width, height);
Romain Guyc46d07a2013-03-15 19:06:39 -0700169
170 SkPaint pathPaint(*paint);
171 initPaint(pathPaint);
172
sergeyvd93b9bd2016-08-04 16:18:22 -0700173 SkCanvas canvas(*bitmap);
174 canvas.translate(-texture->left + texture->offset, -texture->top + texture->offset);
Romain Guyc46d07a2013-03-15 19:06:39 -0700175 canvas.drawPath(*path, pathPaint);
sergeyvd93b9bd2016-08-04 16:18:22 -0700176 return bitmap;
Romain Guyc46d07a2013-03-15 19:06:39 -0700177}
178
Romain Guyc46d07a2013-03-15 19:06:39 -0700179///////////////////////////////////////////////////////////////////////////////
180// Cache constructor/destructor
181///////////////////////////////////////////////////////////////////////////////
182
Chris Craik48a8f432016-02-05 15:59:29 -0800183PathCache::PathCache()
184 : mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity)
185 , mSize(0)
John Reckcecec702016-10-12 14:08:49 -0700186 , mMaxSize(Properties::pathCacheSize) {
Romain Guyc46d07a2013-03-15 19:06:39 -0700187 mCache.setOnEntryRemovedListener(this);
188
189 GLint maxTextureSize;
190 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
191 mMaxTextureSize = maxTextureSize;
192
Chris Craik2507c342015-05-04 14:36:49 -0700193 mDebugEnabled = Properties::debugLevel & kDebugCaches;
Romain Guyc46d07a2013-03-15 19:06:39 -0700194}
195
Chris Craik05f3d6e2014-06-02 16:27:04 -0700196PathCache::~PathCache() {
197 mCache.clear();
198}
199
Romain Guyc46d07a2013-03-15 19:06:39 -0700200///////////////////////////////////////////////////////////////////////////////
201// Size management
202///////////////////////////////////////////////////////////////////////////////
203
204uint32_t PathCache::getSize() {
205 return mSize;
206}
207
208uint32_t PathCache::getMaxSize() {
209 return mMaxSize;
210}
211
Romain Guyc46d07a2013-03-15 19:06:39 -0700212///////////////////////////////////////////////////////////////////////////////
213// Callbacks
214///////////////////////////////////////////////////////////////////////////////
215
Andreas Gampe64bb4132014-11-22 00:35:09 +0000216void PathCache::operator()(PathDescription& entry, PathTexture*& texture) {
Romain Guyc46d07a2013-03-15 19:06:39 -0700217 removeTexture(texture);
218}
219
220///////////////////////////////////////////////////////////////////////////////
221// Caching
222///////////////////////////////////////////////////////////////////////////////
223
224void PathCache::removeTexture(PathTexture* texture) {
225 if (texture) {
John Reck38e0c322015-11-10 12:19:17 -0800226 const uint32_t size = texture->width() * texture->height();
Romain Guy5d923202013-08-21 18:40:24 -0700227
228 // If there is a pending task we must wait for it to return
229 // before attempting our cleanup
230 const sp<Task<SkBitmap*> >& task = texture->task();
Chris Craikd41c4d82015-01-05 15:51:13 -0800231 if (task != nullptr) {
Andreas Gampe1e196742014-11-10 15:23:43 -0800232 task->getResult();
Romain Guy5d923202013-08-21 18:40:24 -0700233 texture->clearTask();
234 } else {
235 // If there is a pending task, the path was not added
236 // to the cache and the size wasn't increased
237 if (size > mSize) {
238 ALOGE("Removing path texture of size %d will leave "
239 "the cache in an inconsistent state", size);
240 }
241 mSize -= size;
242 }
Romain Guyc46d07a2013-03-15 19:06:39 -0700243
244 PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
245 texture->id, size, mSize);
246 if (mDebugEnabled) {
247 ALOGD("Shape deleted, size = %d", size);
248 }
249
John Reck38e0c322015-11-10 12:19:17 -0800250 texture->deleteTexture();
Romain Guyc46d07a2013-03-15 19:06:39 -0700251 delete texture;
252 }
253}
254
255void PathCache::purgeCache(uint32_t width, uint32_t height) {
256 const uint32_t size = width * height;
257 // Don't even try to cache a bitmap that's bigger than the cache
258 if (size < mMaxSize) {
259 while (mSize + size > mMaxSize) {
260 mCache.removeOldest();
261 }
262 }
263}
264
265void PathCache::trim() {
John Reckcecec702016-10-12 14:08:49 -0700266 // 25 is just an arbitrary lower bound to ensure we aren't in weird edge cases
267 // of things like a cap of 0 or 1 as that's going to break things.
268 // It does not represent a reasonable minimum value
269 static_assert(DEFAULT_PATH_TEXTURE_CAP > 25, "Path cache texture cap is too small");
270
271 while (mSize > mMaxSize || mCache.size() > DEFAULT_PATH_TEXTURE_CAP) {
272 LOG_ALWAYS_FATAL_IF(!mCache.size(), "Inconsistent mSize! Ran out of items to remove!"
273 " mSize = %u, mMaxSize = %u", mSize, mMaxSize);
Romain Guyc46d07a2013-03-15 19:06:39 -0700274 mCache.removeOldest();
275 }
276}
277
278PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *path,
279 const SkPaint* paint) {
Chris Craik70850ea2014-11-18 10:49:23 -0800280 ATRACE_NAME("Generate Path Texture");
Romain Guyc46d07a2013-03-15 19:06:39 -0700281
sergeyvd93b9bd2016-08-04 16:18:22 -0700282 PathTexture* texture = new PathTexture(Caches::getInstance(), path->getGenerationID());
283 std::unique_ptr<SkBitmap> bitmap(drawPath(path, paint, texture, mMaxTextureSize));
284 if (!bitmap.get()) {
285 delete texture;
286 return nullptr;
287 }
Romain Guyc46d07a2013-03-15 19:06:39 -0700288
sergeyvd93b9bd2016-08-04 16:18:22 -0700289 purgeCache(bitmap->width(), bitmap->height());
290 generateTexture(entry, bitmap.get(), texture);
Romain Guyc46d07a2013-03-15 19:06:39 -0700291 return texture;
292}
293
Romain Guy4500a8d2013-03-26 17:29:51 -0700294void PathCache::generateTexture(const PathDescription& entry, SkBitmap* bitmap,
295 PathTexture* texture, bool addToCache) {
Romain Guyc46d07a2013-03-15 19:06:39 -0700296 generateTexture(*bitmap, texture);
297
Chris Craik42455fc2015-05-11 18:23:09 -0700298 // Note here that we upload to a texture even if it's bigger than mMaxSize.
299 // Such an entry in mCache will only be temporary, since it will be evicted
300 // immediately on trim, or on any other Path entering the cache.
John Reck38e0c322015-11-10 12:19:17 -0800301 uint32_t size = texture->width() * texture->height();
Chris Craik42455fc2015-05-11 18:23:09 -0700302 mSize += size;
303 PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d",
304 texture->id, size, mSize);
305 if (mDebugEnabled) {
306 ALOGD("Shape created, size = %d", size);
307 }
308 if (addToCache) {
309 mCache.put(entry, texture);
Romain Guyc46d07a2013-03-15 19:06:39 -0700310 }
311}
312
313void PathCache::clear() {
314 mCache.clear();
315}
316
317void PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) {
Chris Craikcf8426c2015-05-13 17:05:48 -0700318 ATRACE_NAME("Upload Path Texture");
John Reck38e0c322015-11-10 12:19:17 -0800319 texture->upload(bitmap);
Romain Guyc46d07a2013-03-15 19:06:39 -0700320 texture->setFilter(GL_LINEAR);
Romain Guyc46d07a2013-03-15 19:06:39 -0700321}
322
323///////////////////////////////////////////////////////////////////////////////
Romain Guyca89e2a2013-03-08 17:44:20 -0800324// Path precaching
325///////////////////////////////////////////////////////////////////////////////
Romain Guyfdd6fc12012-04-27 11:47:13 -0700326
Romain Guy5dc7fa72013-03-11 20:48:31 -0700327PathCache::PathProcessor::PathProcessor(Caches& caches):
328 TaskProcessor<SkBitmap*>(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {
Romain Guyfdd6fc12012-04-27 11:47:13 -0700329}
Romain Guy33f6beb2012-02-16 19:24:51 -0800330
Romain Guy5dc7fa72013-03-11 20:48:31 -0700331void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
Chris Craik05f3d6e2014-06-02 16:27:04 -0700332 PathTask* t = static_cast<PathTask*>(task.get());
Romain Guy5dc7fa72013-03-11 20:48:31 -0700333 ATRACE_NAME("pathPrecache");
334
sergeyvd93b9bd2016-08-04 16:18:22 -0700335 t->setResult(drawPath(&t->path, &t->paint, t->texture, mMaxTextureSize));
Romain Guy33f6beb2012-02-16 19:24:51 -0800336}
337
Romain Guy7fbcc042010-08-04 15:40:07 -0700338///////////////////////////////////////////////////////////////////////////////
Romain Guyc46d07a2013-03-15 19:06:39 -0700339// Paths
Romain Guy7fbcc042010-08-04 15:40:07 -0700340///////////////////////////////////////////////////////////////////////////////
341
Derek Sollenbergeree248592015-02-12 14:10:21 -0500342void PathCache::removeDeferred(const SkPath* path) {
Romain Guyca89e2a2013-03-08 17:44:20 -0800343 Mutex::Autolock l(mLock);
John Reck272a6852015-07-29 16:48:58 -0700344 mGarbage.push_back(path->getGenerationID());
Romain Guyfe48f652010-11-11 15:36:56 -0800345}
346
347void PathCache::clearGarbage() {
Romain Guye3b0a012013-06-26 15:45:41 -0700348 Vector<PathDescription> pathsToRemove;
349
350 { // scope for the mutex
351 Mutex::Autolock l(mLock);
John Reck272a6852015-07-29 16:48:58 -0700352 for (const uint32_t generationID : mGarbage) {
Derek Sollenbergeree248592015-02-12 14:10:21 -0500353 LruCache<PathDescription, PathTexture*>::Iterator iter(mCache);
354 while (iter.next()) {
355 const PathDescription& key = iter.key();
sergeyv7224e2b2016-04-07 18:06:53 -0700356 if (key.type == ShapeType::Path && key.shape.path.mGenerationID == generationID) {
Derek Sollenbergeree248592015-02-12 14:10:21 -0500357 pathsToRemove.push(key);
358 }
359 }
Romain Guye3b0a012013-06-26 15:45:41 -0700360 }
361 mGarbage.clear();
Romain Guyfe48f652010-11-11 15:36:56 -0800362 }
Romain Guye3b0a012013-06-26 15:45:41 -0700363
364 for (size_t i = 0; i < pathsToRemove.size(); i++) {
365 mCache.remove(pathsToRemove.itemAt(i));
366 }
Romain Guya2341a92010-09-08 18:04:33 -0700367}
368
Chris Craikd218a922014-01-02 17:13:34 -0800369PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700370 PathDescription entry(ShapeType::Path, paint);
Derek Sollenbergeree248592015-02-12 14:10:21 -0500371 entry.shape.path.mGenerationID = path->getGenerationID();
Romain Guyc46d07a2013-03-15 19:06:39 -0700372
Romain Guy7fbcc042010-08-04 15:40:07 -0700373 PathTexture* texture = mCache.get(entry);
374
375 if (!texture) {
376 texture = addTexture(entry, path, paint);
Romain Guyca89e2a2013-03-08 17:44:20 -0800377 } else {
378 // A bitmap is attached to the texture, this means we need to
379 // upload it as a GL texture
Romain Guy5dc7fa72013-03-11 20:48:31 -0700380 const sp<Task<SkBitmap*> >& task = texture->task();
Chris Craikd41c4d82015-01-05 15:51:13 -0800381 if (task != nullptr) {
Romain Guyca89e2a2013-03-08 17:44:20 -0800382 // But we must first wait for the worker thread to be done
383 // producing the bitmap, so let's wait
Romain Guy5dc7fa72013-03-11 20:48:31 -0700384 SkBitmap* bitmap = task->getResult();
Romain Guyca89e2a2013-03-08 17:44:20 -0800385 if (bitmap) {
Romain Guy4500a8d2013-03-26 17:29:51 -0700386 generateTexture(entry, bitmap, texture, false);
Romain Guy5dc7fa72013-03-11 20:48:31 -0700387 texture->clearTask();
Romain Guyca89e2a2013-03-08 17:44:20 -0800388 } else {
Romain Guy5dc7fa72013-03-11 20:48:31 -0700389 texture->clearTask();
Chris Craikd41c4d82015-01-05 15:51:13 -0800390 texture = nullptr;
Romain Guyca89e2a2013-03-08 17:44:20 -0800391 mCache.remove(entry);
392 }
Romain Guyca89e2a2013-03-08 17:44:20 -0800393 }
Romain Guy7fbcc042010-08-04 15:40:07 -0700394 }
395
Romain Guy7fbcc042010-08-04 15:40:07 -0700396 return texture;
397}
398
sergeyv7224e2b2016-04-07 18:06:53 -0700399void PathCache::remove(const SkPath* path, const SkPaint* paint) {
400 PathDescription entry(ShapeType::Path, paint);
Digish Pandya2e4f67c2015-11-04 11:00:28 +0530401 entry.shape.path.mGenerationID = path->getGenerationID();
402 mCache.remove(entry);
403}
404
Chris Craikd218a922014-01-02 17:13:34 -0800405void PathCache::precache(const SkPath* path, const SkPaint* paint) {
Romain Guy5dc7fa72013-03-11 20:48:31 -0700406 if (!Caches::getInstance().tasks.canRunTasks()) {
407 return;
408 }
409
sergeyv7224e2b2016-04-07 18:06:53 -0700410 PathDescription entry(ShapeType::Path, paint);
Derek Sollenbergeree248592015-02-12 14:10:21 -0500411 entry.shape.path.mGenerationID = path->getGenerationID();
Romain Guyc46d07a2013-03-15 19:06:39 -0700412
Romain Guyca89e2a2013-03-08 17:44:20 -0800413 PathTexture* texture = mCache.get(entry);
414
415 bool generate = false;
416 if (!texture) {
417 generate = true;
Romain Guyca89e2a2013-03-08 17:44:20 -0800418 }
419
420 if (generate) {
421 // It is important to specify the generation ID so we do not
422 // attempt to precache the same path several times
Chris Craike2bb3802015-03-13 15:07:52 -0700423 texture = new PathTexture(Caches::getInstance(), path->getGenerationID());
Romain Guy5dc7fa72013-03-11 20:48:31 -0700424 sp<PathTask> task = new PathTask(path, paint, texture);
425 texture->setTask(task);
Romain Guyca89e2a2013-03-08 17:44:20 -0800426
427 // During the precaching phase we insert path texture objects into
428 // the cache that do not point to any GL texture. They are instead
429 // treated as a task for the precaching worker thread. This is why
430 // we do not check the cache limit when inserting these objects.
431 // The conversion into GL texture will happen in get(), when a client
432 // asks for a path texture. This is also when the cache limit will
433 // be enforced.
434 mCache.put(entry, texture);
Romain Guy5dc7fa72013-03-11 20:48:31 -0700435
Chris Craikd41c4d82015-01-05 15:51:13 -0800436 if (mProcessor == nullptr) {
Romain Guy5dc7fa72013-03-11 20:48:31 -0700437 mProcessor = new PathProcessor(Caches::getInstance());
438 }
Chris Craikdee66b62015-04-20 14:54:49 -0700439 mProcessor->add(task);
Romain Guyca89e2a2013-03-08 17:44:20 -0800440 }
441}
442
Romain Guyc46d07a2013-03-15 19:06:39 -0700443///////////////////////////////////////////////////////////////////////////////
444// Rounded rects
445///////////////////////////////////////////////////////////////////////////////
446
447PathTexture* PathCache::getRoundRect(float width, float height,
Chris Craikd218a922014-01-02 17:13:34 -0800448 float rx, float ry, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700449 PathDescription entry(ShapeType::RoundRect, paint);
Romain Guyc46d07a2013-03-15 19:06:39 -0700450 entry.shape.roundRect.mWidth = width;
451 entry.shape.roundRect.mHeight = height;
452 entry.shape.roundRect.mRx = rx;
453 entry.shape.roundRect.mRy = ry;
454
455 PathTexture* texture = get(entry);
456
457 if (!texture) {
458 SkPath path;
459 SkRect r;
460 r.set(0.0f, 0.0f, width, height);
461 path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
462
463 texture = addTexture(entry, &path, paint);
464 }
465
466 return texture;
467}
468
469///////////////////////////////////////////////////////////////////////////////
470// Circles
471///////////////////////////////////////////////////////////////////////////////
472
Chris Craikd218a922014-01-02 17:13:34 -0800473PathTexture* PathCache::getCircle(float radius, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700474 PathDescription entry(ShapeType::Circle, paint);
Romain Guyc46d07a2013-03-15 19:06:39 -0700475 entry.shape.circle.mRadius = radius;
476
477 PathTexture* texture = get(entry);
478
479 if (!texture) {
480 SkPath path;
481 path.addCircle(radius, radius, radius, SkPath::kCW_Direction);
482
483 texture = addTexture(entry, &path, paint);
484 }
485
486 return texture;
487}
488
489///////////////////////////////////////////////////////////////////////////////
490// Ovals
491///////////////////////////////////////////////////////////////////////////////
492
Chris Craikd218a922014-01-02 17:13:34 -0800493PathTexture* PathCache::getOval(float width, float height, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700494 PathDescription entry(ShapeType::Oval, paint);
Romain Guyc46d07a2013-03-15 19:06:39 -0700495 entry.shape.oval.mWidth = width;
496 entry.shape.oval.mHeight = height;
497
498 PathTexture* texture = get(entry);
499
500 if (!texture) {
501 SkPath path;
502 SkRect r;
503 r.set(0.0f, 0.0f, width, height);
504 path.addOval(r, SkPath::kCW_Direction);
505
506 texture = addTexture(entry, &path, paint);
507 }
508
509 return texture;
510}
511
512///////////////////////////////////////////////////////////////////////////////
513// Rects
514///////////////////////////////////////////////////////////////////////////////
515
Chris Craikd218a922014-01-02 17:13:34 -0800516PathTexture* PathCache::getRect(float width, float height, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700517 PathDescription entry(ShapeType::Rect, paint);
Romain Guyc46d07a2013-03-15 19:06:39 -0700518 entry.shape.rect.mWidth = width;
519 entry.shape.rect.mHeight = height;
520
521 PathTexture* texture = get(entry);
522
523 if (!texture) {
524 SkPath path;
525 SkRect r;
526 r.set(0.0f, 0.0f, width, height);
527 path.addRect(r, SkPath::kCW_Direction);
528
529 texture = addTexture(entry, &path, paint);
530 }
531
532 return texture;
533}
534
535///////////////////////////////////////////////////////////////////////////////
536// Arcs
537///////////////////////////////////////////////////////////////////////////////
538
539PathTexture* PathCache::getArc(float width, float height,
Chris Craikd218a922014-01-02 17:13:34 -0800540 float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) {
sergeyv7224e2b2016-04-07 18:06:53 -0700541 PathDescription entry(ShapeType::Arc, paint);
Romain Guyc46d07a2013-03-15 19:06:39 -0700542 entry.shape.arc.mWidth = width;
543 entry.shape.arc.mHeight = height;
544 entry.shape.arc.mStartAngle = startAngle;
545 entry.shape.arc.mSweepAngle = sweepAngle;
546 entry.shape.arc.mUseCenter = useCenter;
547
548 PathTexture* texture = get(entry);
549
550 if (!texture) {
551 SkPath path;
552 SkRect r;
553 r.set(0.0f, 0.0f, width, height);
554 if (useCenter) {
555 path.moveTo(r.centerX(), r.centerY());
556 }
557 path.arcTo(r, startAngle, sweepAngle, !useCenter);
558 if (useCenter) {
559 path.close();
560 }
561
562 texture = addTexture(entry, &path, paint);
563 }
564
565 return texture;
566}
567
Romain Guy7fbcc042010-08-04 15:40:07 -0700568}; // namespace uirenderer
569}; // namespace android