blob: afdc2c9cd4edede9ffdafd303b60943b0070e912 [file] [log] [blame]
Romain Guy7fbcc042010-08-04 15:40:07 -07001/*
2 * Copyright (C) 2010 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#define LOG_TAG "OpenGLRenderer"
18
Romain Guyca89e2a2013-03-08 17:44:20 -080019#include <utils/Mutex.h>
Romain Guya2341a92010-09-08 18:04:33 -070020
Romain Guyca89e2a2013-03-08 17:44:20 -080021#include <sys/sysinfo.h>
22
23#include "Caches.h"
Romain Guy7fbcc042010-08-04 15:40:07 -070024#include "PathCache.h"
Romain Guyfb8b7632010-08-23 21:05:08 -070025#include "Properties.h"
Romain Guy7fbcc042010-08-04 15:40:07 -070026
27namespace android {
28namespace uirenderer {
29
Romain Guyca89e2a2013-03-08 17:44:20 -080030///////////////////////////////////////////////////////////////////////////////
31// Path precaching
32///////////////////////////////////////////////////////////////////////////////
Romain Guyfdd6fc12012-04-27 11:47:13 -070033
Romain Guy5dc7fa72013-03-11 20:48:31 -070034PathCache::PathProcessor::PathProcessor(Caches& caches):
35 TaskProcessor<SkBitmap*>(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {
Romain Guyfdd6fc12012-04-27 11:47:13 -070036}
Romain Guy33f6beb2012-02-16 19:24:51 -080037
Romain Guy5dc7fa72013-03-11 20:48:31 -070038void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
39 sp<PathTask> t = static_cast<PathTask* >(task.get());
40 ATRACE_NAME("pathPrecache");
41
42 float left, top, offset;
43 uint32_t width, height;
44 PathCache::computePathBounds(t->path, t->paint, left, top, offset, width, height);
45
46 PathTexture* texture = t->texture;
47 texture->left = left;
48 texture->top = top;
49 texture->offset = offset;
50 texture->width = width;
51 texture->height = height;
52
53 if (width <= mMaxTextureSize && height <= mMaxTextureSize) {
54 SkBitmap* bitmap = new SkBitmap();
55 PathCache::drawPath(t->path, t->paint, *bitmap, left, top, offset, width, height);
56 t->setResult(bitmap);
57 } else {
58 t->setResult(NULL);
Romain Guyca89e2a2013-03-08 17:44:20 -080059 }
Romain Guy33f6beb2012-02-16 19:24:51 -080060}
61
Romain Guy7fbcc042010-08-04 15:40:07 -070062///////////////////////////////////////////////////////////////////////////////
Romain Guyff26a0c2011-01-20 11:35:46 -080063// Path cache
Romain Guy7fbcc042010-08-04 15:40:07 -070064///////////////////////////////////////////////////////////////////////////////
65
Romain Guyff26a0c2011-01-20 11:35:46 -080066PathCache::PathCache(): ShapeCache<PathCacheEntry>("path",
Romain Guy5dc7fa72013-03-11 20:48:31 -070067 PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE) {
Romain Guyca89e2a2013-03-08 17:44:20 -080068}
69
70PathCache::~PathCache() {
Romain Guy7fbcc042010-08-04 15:40:07 -070071}
72
Romain Guya2341a92010-09-08 18:04:33 -070073void PathCache::remove(SkPath* path) {
Romain Guy059e12c2012-11-28 17:35:51 -080074 Vector<PathCacheEntry> pathsToRemove;
75 LruCache<PathCacheEntry, PathTexture*>::Iterator i(mCache);
76
77 while (i.next()) {
78 const PathCacheEntry& key = i.key();
Romain Guyca89e2a2013-03-08 17:44:20 -080079 if (key.path == path || key.path == path->getSourcePath()) {
Romain Guy059e12c2012-11-28 17:35:51 -080080 pathsToRemove.push(key);
Romain Guya2341a92010-09-08 18:04:33 -070081 }
82 }
Romain Guy9e108412010-11-09 14:35:20 -080083
84 for (size_t i = 0; i < pathsToRemove.size(); i++) {
Romain Guy059e12c2012-11-28 17:35:51 -080085 mCache.remove(pathsToRemove.itemAt(i));
Romain Guy9e108412010-11-09 14:35:20 -080086 }
Romain Guyfe48f652010-11-11 15:36:56 -080087}
88
89void PathCache::removeDeferred(SkPath* path) {
Romain Guyca89e2a2013-03-08 17:44:20 -080090 Mutex::Autolock l(mLock);
Romain Guyfe48f652010-11-11 15:36:56 -080091 mGarbage.push(path);
92}
93
94void PathCache::clearGarbage() {
Romain Guyca89e2a2013-03-08 17:44:20 -080095 Mutex::Autolock l(mLock);
Romain Guyfe48f652010-11-11 15:36:56 -080096 size_t count = mGarbage.size();
97 for (size_t i = 0; i < count; i++) {
98 remove(mGarbage.itemAt(i));
99 }
100 mGarbage.clear();
Romain Guya2341a92010-09-08 18:04:33 -0700101}
102
Romain Guyca89e2a2013-03-08 17:44:20 -0800103/**
104 * To properly handle path mutations at draw time we always make a copy
105 * of paths objects when recording display lists. The source path points
106 * to the path we originally copied the path from. This ensures we use
107 * the original path as a cache key the first time a path is inserted
108 * in the cache. The source path is also used to reclaim garbage when a
109 * Dalvik Path object is collected.
110 */
111static SkPath* getSourcePath(SkPath* path) {
Romain Guy4bcb7462012-02-23 17:08:38 -0800112 const SkPath* sourcePath = path->getSourcePath();
113 if (sourcePath && sourcePath->getGenerationID() == path->getGenerationID()) {
Romain Guyca89e2a2013-03-08 17:44:20 -0800114 return const_cast<SkPath*>(sourcePath);
Romain Guy4bcb7462012-02-23 17:08:38 -0800115 }
Romain Guyca89e2a2013-03-08 17:44:20 -0800116 return path;
117}
118
119PathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
120 path = getSourcePath(path);
Romain Guy4bcb7462012-02-23 17:08:38 -0800121
Romain Guy7fbcc042010-08-04 15:40:07 -0700122 PathCacheEntry entry(path, paint);
123 PathTexture* texture = mCache.get(entry);
124
125 if (!texture) {
126 texture = addTexture(entry, path, paint);
Romain Guyca89e2a2013-03-08 17:44:20 -0800127 } else {
128 // A bitmap is attached to the texture, this means we need to
129 // upload it as a GL texture
Romain Guy5dc7fa72013-03-11 20:48:31 -0700130 const sp<Task<SkBitmap*> >& task = texture->task();
131 if (task != NULL) {
Romain Guyca89e2a2013-03-08 17:44:20 -0800132 // But we must first wait for the worker thread to be done
133 // producing the bitmap, so let's wait
Romain Guy5dc7fa72013-03-11 20:48:31 -0700134 SkBitmap* bitmap = task->getResult();
Romain Guyca89e2a2013-03-08 17:44:20 -0800135 if (bitmap) {
136 addTexture(entry, bitmap, texture);
Romain Guy5dc7fa72013-03-11 20:48:31 -0700137 texture->clearTask();
Romain Guyca89e2a2013-03-08 17:44:20 -0800138 } else {
139 ALOGW("Path too large to be rendered into a texture (%dx%d)",
140 texture->width, texture->height);
Romain Guy5dc7fa72013-03-11 20:48:31 -0700141 texture->clearTask();
Romain Guyca89e2a2013-03-08 17:44:20 -0800142 texture = NULL;
143 mCache.remove(entry);
144 }
145 } else if (path->getGenerationID() != texture->generation) {
146 mCache.remove(entry);
147 texture = addTexture(entry, path, paint);
148 }
Romain Guy7fbcc042010-08-04 15:40:07 -0700149 }
150
Romain Guy7fbcc042010-08-04 15:40:07 -0700151 return texture;
152}
153
Romain Guyca89e2a2013-03-08 17:44:20 -0800154void PathCache::precache(SkPath* path, SkPaint* paint) {
Romain Guy5dc7fa72013-03-11 20:48:31 -0700155 if (!Caches::getInstance().tasks.canRunTasks()) {
156 return;
157 }
158
Romain Guyca89e2a2013-03-08 17:44:20 -0800159 path = getSourcePath(path);
160
161 PathCacheEntry entry(path, paint);
162 PathTexture* texture = mCache.get(entry);
163
164 bool generate = false;
165 if (!texture) {
166 generate = true;
167 } else if (path->getGenerationID() != texture->generation) {
168 mCache.remove(entry);
169 generate = true;
170 }
171
172 if (generate) {
173 // It is important to specify the generation ID so we do not
174 // attempt to precache the same path several times
Romain Guy5dc7fa72013-03-11 20:48:31 -0700175 texture = createTexture(0.0f, 0.0f, 0.0f, 0, 0, path->getGenerationID());
176 sp<PathTask> task = new PathTask(path, paint, texture);
177 texture->setTask(task);
Romain Guyca89e2a2013-03-08 17:44:20 -0800178
179 // During the precaching phase we insert path texture objects into
180 // the cache that do not point to any GL texture. They are instead
181 // treated as a task for the precaching worker thread. This is why
182 // we do not check the cache limit when inserting these objects.
183 // The conversion into GL texture will happen in get(), when a client
184 // asks for a path texture. This is also when the cache limit will
185 // be enforced.
186 mCache.put(entry, texture);
Romain Guy5dc7fa72013-03-11 20:48:31 -0700187
188 if (mProcessor == NULL) {
189 mProcessor = new PathProcessor(Caches::getInstance());
190 }
191 mProcessor->add(task);
Romain Guyca89e2a2013-03-08 17:44:20 -0800192 }
193}
194
Romain Guy7fbcc042010-08-04 15:40:07 -0700195}; // namespace uirenderer
196}; // namespace android