PathCache.cpp revision 5d923200846ed59e813373bde789d97d4ccc40b5
17fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy/*
2c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy * Copyright (C) 2013 The Android Open Source Project
37fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy *
47fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
57fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy * you may not use this file except in compliance with the License.
67fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy * You may obtain a copy of the License at
77fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy *
87fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
97fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy *
107fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy * Unless required by applicable law or agreed to in writing, software
117fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
127fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy * See the License for the specific language governing permissions and
147fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy * limitations under the License.
157fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy */
167fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
177fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy#define LOG_TAG "OpenGLRenderer"
18c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#define ATRACE_TAG ATRACE_TAG_VIEW
197fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
20c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <SkBitmap.h>
21c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <SkCanvas.h>
22c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <SkPaint.h>
23c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <SkPath.h>
24c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <SkRect.h>
25a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy
26c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <utils/JenkinsHash.h>
27c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <utils/Trace.h>
28ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
29ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy#include "Caches.h"
307fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy#include "PathCache.h"
31c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
32c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include "thread/Signal.h"
33c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include "thread/Task.h"
34c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include "thread/TaskProcessor.h"
357fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
367fbcc0492fca03857e3c45064f4aa040af817d55Romain Guynamespace android {
377fbcc0492fca03857e3c45064f4aa040af817d55Romain Guynamespace uirenderer {
387fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
39ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy///////////////////////////////////////////////////////////////////////////////
40c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Cache entries
41c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
42c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
43c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathDescription::PathDescription():
44c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        type(kShapeNone),
45c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        join(SkPaint::kDefault_Join),
46c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        cap(SkPaint::kDefault_Cap),
47c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        style(SkPaint::kFill_Style),
48c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        miter(4.0f),
49c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        strokeWidth(1.0f),
50c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        pathEffect(NULL) {
51c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    memset(&shape, 0, sizeof(Shape));
52c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
53c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
54c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathDescription::PathDescription(ShapeType type, SkPaint* paint):
55c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        type(type),
56c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        join(paint->getStrokeJoin()),
57c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        cap(paint->getStrokeCap()),
58c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        style(paint->getStyle()),
59c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        miter(paint->getStrokeMiter()),
60c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        strokeWidth(paint->getStrokeWidth()),
61c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        pathEffect(paint->getPathEffect()) {
62c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    memset(&shape, 0, sizeof(Shape));
63c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
64c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
65c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyhash_t PathDescription::hash() const {
66c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    uint32_t hash = JenkinsHashMix(0, type);
67c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, join);
68c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, cap);
69c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, style);
70c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, android::hash_type(miter));
71c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
72c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, android::hash_type(pathEffect));
73c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
74c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return JenkinsHashWhiten(hash);
75c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
76c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
77c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyint PathDescription::compare(const PathDescription& rhs) const {
78c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return memcmp(this, &rhs, sizeof(PathDescription));
79c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
80c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
81c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
82c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Utilities
83c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
84c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
85c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guybool PathCache::canDrawAsConvexPath(SkPath* path, SkPaint* paint) {
86c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    // NOTE: This should only be used after PathTessellator handles joins properly
87c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return paint->getPathEffect() == NULL && path->getConvexity() == SkPath::kConvex_Convexity;
88c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
89c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
90c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::computePathBounds(const SkPath* path, const SkPaint* paint,
91c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
92c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    const SkRect& bounds = path->getBounds();
93c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathCache::computeBounds(bounds, paint, left, top, offset, width, height);
94c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
95c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
96c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::computeBounds(const SkRect& bounds, const SkPaint* paint,
97c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
98c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    const float pathWidth = fmax(bounds.width(), 1.0f);
99c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    const float pathHeight = fmax(bounds.height(), 1.0f);
100c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
101c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    left = bounds.fLeft;
102c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    top = bounds.fTop;
103c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
104c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
105c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
106c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    width = uint32_t(pathWidth + offset * 2.0 + 0.5);
107c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    height = uint32_t(pathHeight + offset * 2.0 + 0.5);
108c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
109c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
110c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guystatic void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) {
111c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    bitmap.setConfig(SkBitmap::kA8_Config, width, height);
112c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    bitmap.allocPixels();
113c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    bitmap.eraseColor(0);
114c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
115c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
116c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guystatic void initPaint(SkPaint& paint) {
117c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    // Make sure the paint is opaque, color, alpha, filter, etc.
118c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    // will be applied later when compositing the alpha8 texture
119c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    paint.setColor(0xff000000);
120c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    paint.setAlpha(255);
121c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    paint.setColorFilter(NULL);
122c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    paint.setMaskFilter(NULL);
123c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    paint.setShader(NULL);
124c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
125c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    SkSafeUnref(paint.setXfermode(mode));
126c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
127c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
128c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guystatic void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap,
129c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        float left, float top, float offset, uint32_t width, uint32_t height) {
130c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    initBitmap(bitmap, width, height);
131c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
132c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    SkPaint pathPaint(*paint);
133c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    initPaint(pathPaint);
134c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
135c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    SkCanvas canvas(bitmap);
136c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    canvas.translate(-left + offset, -top + offset);
137c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    canvas.drawPath(*path, pathPaint);
138c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
139c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
140c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guystatic PathTexture* createTexture(float left, float top, float offset,
141c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        uint32_t width, uint32_t height, uint32_t id) {
1428aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy    PathTexture* texture = new PathTexture(Caches::getInstance());
143c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    texture->left = left;
144c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    texture->top = top;
145c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    texture->offset = offset;
146c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    texture->width = width;
147c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    texture->height = height;
148c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    texture->generation = id;
149c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
150c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
151c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
152c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
153c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Cache constructor/destructor
154c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
155c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
156c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathCache::PathCache():
157c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity),
158c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) {
159c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    char property[PROPERTY_VALUE_MAX];
160c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (property_get(PROPERTY_PATH_CACHE_SIZE, property, NULL) > 0) {
161c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        INIT_LOGD("  Setting %s cache size to %sMB", name, property);
162c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        setMaxSize(MB(atof(property)));
163c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    } else {
164c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        INIT_LOGD("  Using default %s cache size of %.2fMB", name, DEFAULT_PATH_CACHE_SIZE);
165c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
166c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    init();
167c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
168c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
169c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathCache::~PathCache() {
170c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    mCache.clear();
171c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
172c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
173c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::init() {
174c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    mCache.setOnEntryRemovedListener(this);
175c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
176c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    GLint maxTextureSize;
177c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
178c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    mMaxTextureSize = maxTextureSize;
179c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
180c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    mDebugEnabled = readDebugLevel() & kDebugCaches;
181c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
182c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
183c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
184c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Size management
185c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
186c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
187c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyuint32_t PathCache::getSize() {
188c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return mSize;
189c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
190c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
191c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyuint32_t PathCache::getMaxSize() {
192c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return mMaxSize;
193c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
194c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
195c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::setMaxSize(uint32_t maxSize) {
196c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    mMaxSize = maxSize;
197c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    while (mSize > mMaxSize) {
198c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        mCache.removeOldest();
199c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
200c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
201c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
202c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
203c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Callbacks
204c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
205c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
206c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::operator()(PathDescription& entry, PathTexture*& texture) {
207c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    removeTexture(texture);
208c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
209c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
210c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
211c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Caching
212c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
213c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
214c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::removeTexture(PathTexture* texture) {
215c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (texture) {
216c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        const uint32_t size = texture->width * texture->height;
2175d923200846ed59e813373bde789d97d4ccc40b5Romain Guy
2185d923200846ed59e813373bde789d97d4ccc40b5Romain Guy        // If there is a pending task we must wait for it to return
2195d923200846ed59e813373bde789d97d4ccc40b5Romain Guy        // before attempting our cleanup
2205d923200846ed59e813373bde789d97d4ccc40b5Romain Guy        const sp<Task<SkBitmap*> >& task = texture->task();
2215d923200846ed59e813373bde789d97d4ccc40b5Romain Guy        if (task != NULL) {
2225d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            SkBitmap* bitmap = task->getResult();
2235d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            texture->clearTask();
2245d923200846ed59e813373bde789d97d4ccc40b5Romain Guy        } else {
2255d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            // If there is a pending task, the path was not added
2265d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            // to the cache and the size wasn't increased
2275d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            if (size > mSize) {
2285d923200846ed59e813373bde789d97d4ccc40b5Romain Guy                ALOGE("Removing path texture of size %d will leave "
2295d923200846ed59e813373bde789d97d4ccc40b5Romain Guy                        "the cache in an inconsistent state", size);
2305d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            }
2315d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            mSize -= size;
2325d923200846ed59e813373bde789d97d4ccc40b5Romain Guy        }
233c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
234c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
235c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy                texture->id, size, mSize);
236c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        if (mDebugEnabled) {
237c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy            ALOGD("Shape deleted, size = %d", size);
238c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        }
239c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
240c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        if (texture->id) {
241be1b127c7bec252e0c6ab0e06ed6babed07d496fRomain Guy            Caches::getInstance().deleteTexture(texture->id);
242c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        }
243c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        delete texture;
244c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
245c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
246c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
247c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::purgeCache(uint32_t width, uint32_t height) {
248c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    const uint32_t size = width * height;
249c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    // Don't even try to cache a bitmap that's bigger than the cache
250c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (size < mMaxSize) {
251c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        while (mSize + size > mMaxSize) {
252c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy            mCache.removeOldest();
253c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        }
254c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
255c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
256c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
257c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::trim() {
258c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    while (mSize > mMaxSize) {
259c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        mCache.removeOldest();
260c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
261c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
262c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
263c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *path,
264c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        const SkPaint* paint) {
265c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    ATRACE_CALL();
266c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
267c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    float left, top, offset;
268c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    uint32_t width, height;
269c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    computePathBounds(path, paint, left, top, offset, width, height);
270c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
271c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!checkTextureSize(width, height)) return NULL;
272c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
273c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    purgeCache(width, height);
274c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
275c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    SkBitmap bitmap;
276c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    drawPath(path, paint, bitmap, left, top, offset, width, height);
277c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
278c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathTexture* texture = createTexture(left, top, offset, width, height,
279c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy            path->getGenerationID());
2804500a8d5d7fbec9dba5e693212da160849e401ffRomain Guy    generateTexture(entry, &bitmap, texture);
281c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
282c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
283c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
284c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
2854500a8d5d7fbec9dba5e693212da160849e401ffRomain Guyvoid PathCache::generateTexture(const PathDescription& entry, SkBitmap* bitmap,
2864500a8d5d7fbec9dba5e693212da160849e401ffRomain Guy        PathTexture* texture, bool addToCache) {
287c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    generateTexture(*bitmap, texture);
288c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
289c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    uint32_t size = texture->width * texture->height;
290c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (size < mMaxSize) {
291c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        mSize += size;
292c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d",
293c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy                texture->id, size, mSize);
294c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        if (mDebugEnabled) {
295c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy            ALOGD("Shape created, size = %d", size);
296c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        }
2974500a8d5d7fbec9dba5e693212da160849e401ffRomain Guy        if (addToCache) {
2984500a8d5d7fbec9dba5e693212da160849e401ffRomain Guy            mCache.put(entry, texture);
2994500a8d5d7fbec9dba5e693212da160849e401ffRomain Guy        }
300c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    } else {
3010a8c51b1d0d66d6060afcec1eab33091d49332aeRomain Guy        // It's okay to add a texture that's bigger than the cache since
3020a8c51b1d0d66d6060afcec1eab33091d49332aeRomain Guy        // we'll trim the cache later when addToCache is set to false
3030a8c51b1d0d66d6060afcec1eab33091d49332aeRomain Guy        if (!addToCache) {
3040a8c51b1d0d66d6060afcec1eab33091d49332aeRomain Guy            mSize += size;
3050a8c51b1d0d66d6060afcec1eab33091d49332aeRomain Guy        }
306c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        texture->cleanup = true;
307c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
308c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
309c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
310c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::clear() {
311c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    mCache.clear();
312c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
313c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
314c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) {
315c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    SkAutoLockPixels alp(bitmap);
316c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!bitmap.readyToDraw()) {
317c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        ALOGE("Cannot generate texture from bitmap");
318c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        return;
319c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
320c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
321c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    glGenTextures(1, &texture->id);
322c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
3238aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy    Caches::getInstance().bindTexture(texture->id);
324c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    // Textures are Alpha8
325c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
326c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
327c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    texture->blend = true;
328c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
329c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy            GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels());
330c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
331c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    texture->setFilter(GL_LINEAR);
332c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE);
333c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
334c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
335c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
336ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy// Path precaching
337ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy///////////////////////////////////////////////////////////////////////////////
338ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
3395dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain GuyPathCache::PathProcessor::PathProcessor(Caches& caches):
3405dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        TaskProcessor<SkBitmap*>(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {
341fdd6fc1beb5076a630c7066b8b1731995636c09fRomain Guy}
34233f6beb10f98e8ba96250e284876d607055d278dRomain Guy
3435dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guyvoid PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
3445dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    sp<PathTask> t = static_cast<PathTask* >(task.get());
3455dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    ATRACE_NAME("pathPrecache");
3465dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy
3475dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    float left, top, offset;
3485dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    uint32_t width, height;
3495dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    PathCache::computePathBounds(t->path, t->paint, left, top, offset, width, height);
3505dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy
3515dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    PathTexture* texture = t->texture;
3525dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    texture->left = left;
3535dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    texture->top = top;
3545dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    texture->offset = offset;
3555dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    texture->width = width;
3565dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    texture->height = height;
3575dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy
3585dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    if (width <= mMaxTextureSize && height <= mMaxTextureSize) {
3595dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        SkBitmap* bitmap = new SkBitmap();
360c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        drawPath(t->path, t->paint, *bitmap, left, top, offset, width, height);
3615dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        t->setResult(bitmap);
3625dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    } else {
3630f809f3b794174f044366bf421f8d0c72d9afc14Romain Guy        texture->width = 0;
3640f809f3b794174f044366bf421f8d0c72d9afc14Romain Guy        texture->height = 0;
3655dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        t->setResult(NULL);
366ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    }
36733f6beb10f98e8ba96250e284876d607055d278dRomain Guy}
36833f6beb10f98e8ba96250e284876d607055d278dRomain Guy
3697fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy///////////////////////////////////////////////////////////////////////////////
370c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Paths
3717fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy///////////////////////////////////////////////////////////////////////////////
3727fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
373e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guyvoid PathCache::remove(Vector<PathDescription>& pathsToRemove, const path_pair_t& pair) {
374c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    LruCache<PathDescription, PathTexture*>::Iterator i(mCache);
375059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy
376059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy    while (i.next()) {
377c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        const PathDescription& key = i.key();
378c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        if (key.type == kShapePath &&
379c5cbee7d78513527e89450e6369a30a04b2d5e7aRomain Guy                (key.shape.path.mPath == pair.getFirst() ||
380c5cbee7d78513527e89450e6369a30a04b2d5e7aRomain Guy                        key.shape.path.mPath == pair.getSecond())) {
381059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy            pathsToRemove.push(key);
382a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy        }
383a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy    }
384fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy}
385fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy
386fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guyvoid PathCache::removeDeferred(SkPath* path) {
387ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    Mutex::Autolock l(mLock);
388c5cbee7d78513527e89450e6369a30a04b2d5e7aRomain Guy    mGarbage.push(path_pair_t(path, const_cast<SkPath*>(path->getSourcePath())));
389fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy}
390fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy
391fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guyvoid PathCache::clearGarbage() {
392e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    Vector<PathDescription> pathsToRemove;
393e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
394e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    { // scope for the mutex
395e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        Mutex::Autolock l(mLock);
396e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        size_t count = mGarbage.size();
397e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        for (size_t i = 0; i < count; i++) {
398e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy            remove(pathsToRemove, mGarbage.itemAt(i));
399e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        }
400e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        mGarbage.clear();
401e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
402e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
403e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    for (size_t i = 0; i < pathsToRemove.size(); i++) {
404e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        mCache.remove(pathsToRemove.itemAt(i));
405fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy    }
406a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy}
407a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy
408ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy/**
409ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy * To properly handle path mutations at draw time we always make a copy
410ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy * of paths objects when recording display lists. The source path points
411ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy * to the path we originally copied the path from. This ensures we use
412ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy * the original path as a cache key the first time a path is inserted
413ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy * in the cache. The source path is also used to reclaim garbage when a
414ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy * Dalvik Path object is collected.
415ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy */
416ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guystatic SkPath* getSourcePath(SkPath* path) {
4174bcb7467a174ed03a67b0c62950c555813ddf00dRomain Guy    const SkPath* sourcePath = path->getSourcePath();
4184bcb7467a174ed03a67b0c62950c555813ddf00dRomain Guy    if (sourcePath && sourcePath->getGenerationID() == path->getGenerationID()) {
419ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        return const_cast<SkPath*>(sourcePath);
4204bcb7467a174ed03a67b0c62950c555813ddf00dRomain Guy    }
421ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    return path;
422ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy}
423ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
424ca89e2a68703bd428e8b66547d033a6ed35b3595Romain GuyPathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
425ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    path = getSourcePath(path);
4264bcb7467a174ed03a67b0c62950c555813ddf00dRomain Guy
427c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathDescription entry(kShapePath, paint);
428c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.path.mPath = path;
429c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
4307fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    PathTexture* texture = mCache.get(entry);
4317fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
4327fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    if (!texture) {
4337fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy        texture = addTexture(entry, path, paint);
434ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    } else {
435ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // A bitmap is attached to the texture, this means we need to
436ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // upload it as a GL texture
4375dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        const sp<Task<SkBitmap*> >& task = texture->task();
4385dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        if (task != NULL) {
439ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            // But we must first wait for the worker thread to be done
440ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            // producing the bitmap, so let's wait
4415dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy            SkBitmap* bitmap = task->getResult();
442ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            if (bitmap) {
4434500a8d5d7fbec9dba5e693212da160849e401ffRomain Guy                generateTexture(entry, bitmap, texture, false);
4445dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy                texture->clearTask();
445ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            } else {
4460f809f3b794174f044366bf421f8d0c72d9afc14Romain Guy                ALOGW("Path too large to be rendered into a texture");
4475dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy                texture->clearTask();
448ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy                texture = NULL;
449ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy                mCache.remove(entry);
450ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            }
451ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        } else if (path->getGenerationID() != texture->generation) {
4524500a8d5d7fbec9dba5e693212da160849e401ffRomain Guy            // The size of the path might have changed so we first
4534500a8d5d7fbec9dba5e693212da160849e401ffRomain Guy            // remove the entry from the cache
454ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            mCache.remove(entry);
455ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            texture = addTexture(entry, path, paint);
456ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        }
457ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    }
458ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
459ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    return texture;
460ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy}
461ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
462ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guyvoid PathCache::precache(SkPath* path, SkPaint* paint) {
4635dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    if (!Caches::getInstance().tasks.canRunTasks()) {
4645dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        return;
4655dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    }
4665dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy
467ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    path = getSourcePath(path);
468ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
469c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathDescription entry(kShapePath, paint);
470c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.path.mPath = path;
471c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
472ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    PathTexture* texture = mCache.get(entry);
473ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
474ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    bool generate = false;
475ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    if (!texture) {
476ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        generate = true;
4777fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    } else if (path->getGenerationID() != texture->generation) {
4787fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy        mCache.remove(entry);
479ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        generate = true;
4807fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    }
4817fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
482ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    if (generate) {
483ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // It is important to specify the generation ID so we do not
484ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // attempt to precache the same path several times
4855dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        texture = createTexture(0.0f, 0.0f, 0.0f, 0, 0, path->getGenerationID());
4865dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        sp<PathTask> task = new PathTask(path, paint, texture);
4875dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        texture->setTask(task);
488ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
489ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // During the precaching phase we insert path texture objects into
490ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // the cache that do not point to any GL texture. They are instead
491ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // treated as a task for the precaching worker thread. This is why
492ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // we do not check the cache limit when inserting these objects.
493ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // The conversion into GL texture will happen in get(), when a client
494ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // asks for a path texture. This is also when the cache limit will
495ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // be enforced.
496ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        mCache.put(entry, texture);
4975dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy
4985dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        if (mProcessor == NULL) {
4995dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy            mProcessor = new PathProcessor(Caches::getInstance());
5005dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        }
5015dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        mProcessor->add(task);
502ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    }
5037fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy}
5047fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
505c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
506c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Rounded rects
507c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
508c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
509c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathTexture* PathCache::getRoundRect(float width, float height,
510c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        float rx, float ry, SkPaint* paint) {
511c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathDescription entry(kShapeRoundRect, paint);
512c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.roundRect.mWidth = width;
513c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.roundRect.mHeight = height;
514c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.roundRect.mRx = rx;
515c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.roundRect.mRy = ry;
516c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
517c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathTexture* texture = get(entry);
518c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
519c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!texture) {
520c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkPath path;
521c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkRect r;
522c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        r.set(0.0f, 0.0f, width, height);
523c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
524c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
525c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        texture = addTexture(entry, &path, paint);
526c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
527c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
528c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
529c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
530c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
531c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
532c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Circles
533c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
534c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
535c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathTexture* PathCache::getCircle(float radius, SkPaint* paint) {
536c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathDescription entry(kShapeCircle, paint);
537c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.circle.mRadius = radius;
538c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
539c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathTexture* texture = get(entry);
540c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
541c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!texture) {
542c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkPath path;
543c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        path.addCircle(radius, radius, radius, SkPath::kCW_Direction);
544c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
545c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        texture = addTexture(entry, &path, paint);
546c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
547c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
548c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
549c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
550c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
551c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
552c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Ovals
553c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
554c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
555c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathTexture* PathCache::getOval(float width, float height, SkPaint* paint) {
556c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathDescription entry(kShapeOval, paint);
557c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.oval.mWidth = width;
558c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.oval.mHeight = height;
559c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
560c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathTexture* texture = get(entry);
561c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
562c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!texture) {
563c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkPath path;
564c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkRect r;
565c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        r.set(0.0f, 0.0f, width, height);
566c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        path.addOval(r, SkPath::kCW_Direction);
567c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
568c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        texture = addTexture(entry, &path, paint);
569c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
570c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
571c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
572c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
573c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
574c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
575c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Rects
576c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
577c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
578c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathTexture* PathCache::getRect(float width, float height, SkPaint* paint) {
579c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathDescription entry(kShapeRect, paint);
580c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.rect.mWidth = width;
581c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.rect.mHeight = height;
582c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
583c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathTexture* texture = get(entry);
584c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
585c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!texture) {
586c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkPath path;
587c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkRect r;
588c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        r.set(0.0f, 0.0f, width, height);
589c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        path.addRect(r, SkPath::kCW_Direction);
590c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
591c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        texture = addTexture(entry, &path, paint);
592c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
593c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
594c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
595c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
596c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
597c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
598c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Arcs
599c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
600c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
601c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathTexture* PathCache::getArc(float width, float height,
602c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
603c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathDescription entry(kShapeArc, paint);
604c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.arc.mWidth = width;
605c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.arc.mHeight = height;
606c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.arc.mStartAngle = startAngle;
607c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.arc.mSweepAngle = sweepAngle;
608c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.arc.mUseCenter = useCenter;
609c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
610c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathTexture* texture = get(entry);
611c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
612c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!texture) {
613c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkPath path;
614c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkRect r;
615c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        r.set(0.0f, 0.0f, width, height);
616c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        if (useCenter) {
617c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy            path.moveTo(r.centerX(), r.centerY());
618c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        }
619c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        path.arcTo(r, startAngle, sweepAngle, !useCenter);
620c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        if (useCenter) {
621c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy            path.close();
622c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        }
623c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
624c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        texture = addTexture(entry, &path, paint);
625c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
626c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
627c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
628c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
629c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
6307fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy}; // namespace uirenderer
6317fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy}; // namespace android
632