PathCache.cpp revision 5dc7fa709646799a5207a5d217f70aa02bf4a3aa
1/* 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 19#include <utils/Mutex.h> 20 21#include <sys/sysinfo.h> 22 23#include "Caches.h" 24#include "PathCache.h" 25#include "Properties.h" 26 27namespace android { 28namespace uirenderer { 29 30/////////////////////////////////////////////////////////////////////////////// 31// Path precaching 32/////////////////////////////////////////////////////////////////////////////// 33 34PathCache::PathProcessor::PathProcessor(Caches& caches): 35 TaskProcessor<SkBitmap*>(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) { 36} 37 38void 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); 59 } 60} 61 62/////////////////////////////////////////////////////////////////////////////// 63// Path cache 64/////////////////////////////////////////////////////////////////////////////// 65 66PathCache::PathCache(): ShapeCache<PathCacheEntry>("path", 67 PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE) { 68} 69 70PathCache::~PathCache() { 71} 72 73void PathCache::remove(SkPath* path) { 74 Vector<PathCacheEntry> pathsToRemove; 75 LruCache<PathCacheEntry, PathTexture*>::Iterator i(mCache); 76 77 while (i.next()) { 78 const PathCacheEntry& key = i.key(); 79 if (key.path == path || key.path == path->getSourcePath()) { 80 pathsToRemove.push(key); 81 } 82 } 83 84 for (size_t i = 0; i < pathsToRemove.size(); i++) { 85 mCache.remove(pathsToRemove.itemAt(i)); 86 } 87} 88 89void PathCache::removeDeferred(SkPath* path) { 90 Mutex::Autolock l(mLock); 91 mGarbage.push(path); 92} 93 94void PathCache::clearGarbage() { 95 Mutex::Autolock l(mLock); 96 size_t count = mGarbage.size(); 97 for (size_t i = 0; i < count; i++) { 98 remove(mGarbage.itemAt(i)); 99 } 100 mGarbage.clear(); 101} 102 103/** 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) { 112 const SkPath* sourcePath = path->getSourcePath(); 113 if (sourcePath && sourcePath->getGenerationID() == path->getGenerationID()) { 114 return const_cast<SkPath*>(sourcePath); 115 } 116 return path; 117} 118 119PathTexture* PathCache::get(SkPath* path, SkPaint* paint) { 120 path = getSourcePath(path); 121 122 PathCacheEntry entry(path, paint); 123 PathTexture* texture = mCache.get(entry); 124 125 if (!texture) { 126 texture = addTexture(entry, path, paint); 127 } else { 128 // A bitmap is attached to the texture, this means we need to 129 // upload it as a GL texture 130 const sp<Task<SkBitmap*> >& task = texture->task(); 131 if (task != NULL) { 132 // But we must first wait for the worker thread to be done 133 // producing the bitmap, so let's wait 134 SkBitmap* bitmap = task->getResult(); 135 if (bitmap) { 136 addTexture(entry, bitmap, texture); 137 texture->clearTask(); 138 } else { 139 ALOGW("Path too large to be rendered into a texture (%dx%d)", 140 texture->width, texture->height); 141 texture->clearTask(); 142 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 } 149 } 150 151 return texture; 152} 153 154void PathCache::precache(SkPath* path, SkPaint* paint) { 155 if (!Caches::getInstance().tasks.canRunTasks()) { 156 return; 157 } 158 159 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 175 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); 178 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); 187 188 if (mProcessor == NULL) { 189 mProcessor = new PathProcessor(Caches::getInstance()); 190 } 191 mProcessor->add(task); 192 } 193} 194 195}; // namespace uirenderer 196}; // namespace android 197