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
17c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <SkBitmap.h>
18c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <SkCanvas.h>
1998d608dba6a0b3c15fb08f1fa2c8b9d170124c7cChris Craik#include <SkColor.h>
20c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <SkPaint.h>
21c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <SkPath.h>
227224e2b624daea67b5653285c9640f170c096bdbsergeyv#include <SkPathEffect.h>
23c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <SkRect.h>
24a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy
25c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <utils/JenkinsHash.h>
26c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include <utils/Trace.h>
27ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
28ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy#include "Caches.h"
297fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy#include "PathCache.h"
30c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
31c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include "thread/Signal.h"
32c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy#include "thread/TaskProcessor.h"
337fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
346b50780363d3bb8db600c770183fa07677509ae8John Reck#include <cutils/properties.h>
356b50780363d3bb8db600c770183fa07677509ae8John Reck
367fbcc0492fca03857e3c45064f4aa040af817d55Romain Guynamespace android {
377fbcc0492fca03857e3c45064f4aa040af817d55Romain Guynamespace uirenderer {
387fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
397224e2b624daea67b5653285c9640f170c096bdbsergeyvtemplate <class T>
407224e2b624daea67b5653285c9640f170c096bdbsergeyvstatic bool compareWidthHeight(const T& lhs, const T& rhs) {
417224e2b624daea67b5653285c9640f170c096bdbsergeyv    return (lhs.mWidth == rhs.mWidth) && (lhs.mHeight == rhs.mHeight);
427224e2b624daea67b5653285c9640f170c096bdbsergeyv}
437224e2b624daea67b5653285c9640f170c096bdbsergeyv
447224e2b624daea67b5653285c9640f170c096bdbsergeyvstatic bool compareRoundRects(const PathDescription::Shape::RoundRect& lhs,
457224e2b624daea67b5653285c9640f170c096bdbsergeyv        const PathDescription::Shape::RoundRect& rhs) {
467224e2b624daea67b5653285c9640f170c096bdbsergeyv    return compareWidthHeight(lhs, rhs) && lhs.mRx == rhs.mRx && lhs.mRy == rhs.mRy;
477224e2b624daea67b5653285c9640f170c096bdbsergeyv}
487224e2b624daea67b5653285c9640f170c096bdbsergeyv
497224e2b624daea67b5653285c9640f170c096bdbsergeyvstatic bool compareArcs(const PathDescription::Shape::Arc& lhs, const PathDescription::Shape::Arc& rhs) {
507224e2b624daea67b5653285c9640f170c096bdbsergeyv    return compareWidthHeight(lhs, rhs) && lhs.mStartAngle == rhs.mStartAngle &&
517224e2b624daea67b5653285c9640f170c096bdbsergeyv            lhs.mSweepAngle == rhs.mSweepAngle && lhs.mUseCenter == rhs.mUseCenter;
527224e2b624daea67b5653285c9640f170c096bdbsergeyv}
537224e2b624daea67b5653285c9640f170c096bdbsergeyv
54ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy///////////////////////////////////////////////////////////////////////////////
55c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Cache entries
56c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
57c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
58e2bb380bc26749782c873e5488cfdf4e42b27346Chris CraikPathDescription::PathDescription()
597224e2b624daea67b5653285c9640f170c096bdbsergeyv        : type(ShapeType::None)
60e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , join(SkPaint::kDefault_Join)
61e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , cap(SkPaint::kDefault_Cap)
62e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , style(SkPaint::kFill_Style)
63e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , miter(4.0f)
64e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , strokeWidth(1.0f)
65e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , pathEffect(nullptr) {
667224e2b624daea67b5653285c9640f170c096bdbsergeyv    // Shape bits should be set to zeroes, because they are used for hash calculation.
67c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    memset(&shape, 0, sizeof(Shape));
68c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
69c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
70e2bb380bc26749782c873e5488cfdf4e42b27346Chris CraikPathDescription::PathDescription(ShapeType type, const SkPaint* paint)
71e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        : type(type)
72e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , join(paint->getStrokeJoin())
73e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , cap(paint->getStrokeCap())
74e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , style(paint->getStyle())
75e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , miter(paint->getStrokeMiter())
76e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , strokeWidth(paint->getStrokeWidth())
77e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , pathEffect(paint->getPathEffect()) {
787224e2b624daea67b5653285c9640f170c096bdbsergeyv    // Shape bits should be set to zeroes, because they are used for hash calculation.
79c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    memset(&shape, 0, sizeof(Shape));
80c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
81c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
82c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyhash_t PathDescription::hash() const {
837224e2b624daea67b5653285c9640f170c096bdbsergeyv    uint32_t hash = JenkinsHashMix(0, static_cast<int>(type));
84c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, join);
85c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, cap);
86c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, style);
87c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, android::hash_type(miter));
88c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
89c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMix(hash, android::hash_type(pathEffect));
90c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
91c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return JenkinsHashWhiten(hash);
92c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
93c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
947224e2b624daea67b5653285c9640f170c096bdbsergeyvbool PathDescription::operator==(const PathDescription& rhs) const {
957224e2b624daea67b5653285c9640f170c096bdbsergeyv    if (type != rhs.type) return false;
967224e2b624daea67b5653285c9640f170c096bdbsergeyv    if (join != rhs.join) return false;
977224e2b624daea67b5653285c9640f170c096bdbsergeyv    if (cap != rhs.cap) return false;
987224e2b624daea67b5653285c9640f170c096bdbsergeyv    if (style != rhs.style) return false;
997224e2b624daea67b5653285c9640f170c096bdbsergeyv    if (miter != rhs.miter) return false;
1007224e2b624daea67b5653285c9640f170c096bdbsergeyv    if (strokeWidth != rhs.strokeWidth) return false;
1017224e2b624daea67b5653285c9640f170c096bdbsergeyv    if (pathEffect != rhs.pathEffect) return false;
1027224e2b624daea67b5653285c9640f170c096bdbsergeyv    switch (type) {
1037224e2b624daea67b5653285c9640f170c096bdbsergeyv        case ShapeType::None:
1047224e2b624daea67b5653285c9640f170c096bdbsergeyv            return 0;
1057224e2b624daea67b5653285c9640f170c096bdbsergeyv        case ShapeType::Rect:
1067224e2b624daea67b5653285c9640f170c096bdbsergeyv            return compareWidthHeight(shape.rect, rhs.shape.rect);
1077224e2b624daea67b5653285c9640f170c096bdbsergeyv        case ShapeType::RoundRect:
1087224e2b624daea67b5653285c9640f170c096bdbsergeyv            return compareRoundRects(shape.roundRect, rhs.shape.roundRect);
1097224e2b624daea67b5653285c9640f170c096bdbsergeyv        case ShapeType::Circle:
1107224e2b624daea67b5653285c9640f170c096bdbsergeyv            return shape.circle.mRadius == rhs.shape.circle.mRadius;
1117224e2b624daea67b5653285c9640f170c096bdbsergeyv        case ShapeType::Oval:
1127224e2b624daea67b5653285c9640f170c096bdbsergeyv            return compareWidthHeight(shape.oval, rhs.shape.oval);
1137224e2b624daea67b5653285c9640f170c096bdbsergeyv        case ShapeType::Arc:
1147224e2b624daea67b5653285c9640f170c096bdbsergeyv            return compareArcs(shape.arc, rhs.shape.arc);
1157224e2b624daea67b5653285c9640f170c096bdbsergeyv        case ShapeType::Path:
1167224e2b624daea67b5653285c9640f170c096bdbsergeyv            return shape.path.mGenerationID == rhs.shape.path.mGenerationID;
1177224e2b624daea67b5653285c9640f170c096bdbsergeyv    }
1187224e2b624daea67b5653285c9640f170c096bdbsergeyv}
1197224e2b624daea67b5653285c9640f170c096bdbsergeyv
120c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
121c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Utilities
122c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
123c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
124d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craikbool PathCache::canDrawAsConvexPath(SkPath* path, const SkPaint* paint) {
125c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    // NOTE: This should only be used after PathTessellator handles joins properly
126d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    return paint->getPathEffect() == nullptr && path->getConvexity() == SkPath::kConvex_Convexity;
127c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
128c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
129c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::computePathBounds(const SkPath* path, const SkPaint* paint,
130c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
131c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    const SkRect& bounds = path->getBounds();
132c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathCache::computeBounds(bounds, paint, left, top, offset, width, height);
133c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
134c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
135c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::computeBounds(const SkRect& bounds, const SkPaint* paint,
136c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
137e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik    const float pathWidth = std::max(bounds.width(), 1.0f);
138e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik    const float pathHeight = std::max(bounds.height(), 1.0f);
139c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
140c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    left = bounds.fLeft;
141c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    top = bounds.fTop;
142c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
143e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik    offset = (int) floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
144c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
145c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    width = uint32_t(pathWidth + offset * 2.0 + 0.5);
146c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    height = uint32_t(pathHeight + offset * 2.0 + 0.5);
147c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
148c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
149c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guystatic void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) {
150b933055cf3f7f8ea89bfd3bc9c37a3891ff7310aMike Reed    bitmap.allocPixels(SkImageInfo::MakeA8(width, height));
151c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    bitmap.eraseColor(0);
152c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
153c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
154c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guystatic void initPaint(SkPaint& paint) {
155c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    // Make sure the paint is opaque, color, alpha, filter, etc.
156c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    // will be applied later when compositing the alpha8 texture
15798d608dba6a0b3c15fb08f1fa2c8b9d170124c7cChris Craik    paint.setColor(SK_ColorBLACK);
158c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    paint.setAlpha(255);
159d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    paint.setColorFilter(nullptr);
160d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    paint.setMaskFilter(nullptr);
161d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    paint.setShader(nullptr);
162c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
163c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    SkSafeUnref(paint.setXfermode(mode));
164c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
165c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
166c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guystatic void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap,
167c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        float left, float top, float offset, uint32_t width, uint32_t height) {
168c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    initBitmap(bitmap, width, height);
169c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
170c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    SkPaint pathPaint(*paint);
171c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    initPaint(pathPaint);
172c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
173c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    SkCanvas canvas(bitmap);
174c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    canvas.translate(-left + offset, -top + offset);
175c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    canvas.drawPath(*path, pathPaint);
176c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
177c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
178c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
179c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Cache constructor/destructor
180c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
181c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
18248a8f431fa52ae2ee25ffba9d20676f03bb710ffChris CraikPathCache::PathCache()
18348a8f431fa52ae2ee25ffba9d20676f03bb710ffChris Craik        : mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity)
18448a8f431fa52ae2ee25ffba9d20676f03bb710ffChris Craik        , mSize(0)
18548a8f431fa52ae2ee25ffba9d20676f03bb710ffChris Craik        , mMaxSize(Properties::pathCacheSize) {
186c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    mCache.setOnEntryRemovedListener(this);
187c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
188c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    GLint maxTextureSize;
189c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
190c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    mMaxTextureSize = maxTextureSize;
191c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
1922507c34d91bb0d722b6012e85cb47387b2aa6873Chris Craik    mDebugEnabled = Properties::debugLevel & kDebugCaches;
193c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
194c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
19505f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris CraikPathCache::~PathCache() {
19605f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    mCache.clear();
19705f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik}
19805f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik
199c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
200c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Size management
201c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
202c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
203c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyuint32_t PathCache::getSize() {
204c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return mSize;
205c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
206c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
207c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyuint32_t PathCache::getMaxSize() {
208c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return mMaxSize;
209c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
210c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
211c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
212c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Callbacks
213c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
214c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
21564bb413a664001c95c8439cf097dc3033f4ed733Andreas Gampevoid PathCache::operator()(PathDescription& entry, PathTexture*& texture) {
216c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    removeTexture(texture);
217c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
218c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
219c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
220c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Caching
221c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
222c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
223c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::removeTexture(PathTexture* texture) {
224c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (texture) {
22538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        const uint32_t size = texture->width() * texture->height();
2265d923200846ed59e813373bde789d97d4ccc40b5Romain Guy
2275d923200846ed59e813373bde789d97d4ccc40b5Romain Guy        // If there is a pending task we must wait for it to return
2285d923200846ed59e813373bde789d97d4ccc40b5Romain Guy        // before attempting our cleanup
2295d923200846ed59e813373bde789d97d4ccc40b5Romain Guy        const sp<Task<SkBitmap*> >& task = texture->task();
230d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        if (task != nullptr) {
2311e19674107e1aa2224c2b8c7d12bfa057efe80eaAndreas Gampe            task->getResult();
2325d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            texture->clearTask();
2335d923200846ed59e813373bde789d97d4ccc40b5Romain Guy        } else {
2345d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            // If there is a pending task, the path was not added
2355d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            // to the cache and the size wasn't increased
2365d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            if (size > mSize) {
2375d923200846ed59e813373bde789d97d4ccc40b5Romain Guy                ALOGE("Removing path texture of size %d will leave "
2385d923200846ed59e813373bde789d97d4ccc40b5Romain Guy                        "the cache in an inconsistent state", size);
2395d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            }
2405d923200846ed59e813373bde789d97d4ccc40b5Romain Guy            mSize -= size;
2415d923200846ed59e813373bde789d97d4ccc40b5Romain Guy        }
242c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
243c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
244c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy                texture->id, size, mSize);
245c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        if (mDebugEnabled) {
246c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy            ALOGD("Shape deleted, size = %d", size);
247c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        }
248c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
24938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        texture->deleteTexture();
250c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        delete texture;
251c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
252c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
253c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
254c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::purgeCache(uint32_t width, uint32_t height) {
255c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    const uint32_t size = width * height;
256c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    // Don't even try to cache a bitmap that's bigger than the cache
257c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (size < mMaxSize) {
258c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        while (mSize + size > mMaxSize) {
259c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy            mCache.removeOldest();
260c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        }
261c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
262c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
263c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
264c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::trim() {
265c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    while (mSize > mMaxSize) {
266c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        mCache.removeOldest();
267c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
268c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
269c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
270c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *path,
271c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        const SkPaint* paint) {
27270850ea258cbf91477efa57a1f1a23cc0044cc93Chris Craik    ATRACE_NAME("Generate Path Texture");
273c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
274c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    float left, top, offset;
275c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    uint32_t width, height;
276c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    computePathBounds(path, paint, left, top, offset, width, height);
277c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
278d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    if (!checkTextureSize(width, height)) return nullptr;
279c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
280c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    purgeCache(width, height);
281c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
282c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    SkBitmap bitmap;
283c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    drawPath(path, paint, bitmap, left, top, offset, width, height);
284c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
285e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    PathTexture* texture = new PathTexture(Caches::getInstance(),
28638e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck            left, top, offset, path->getGenerationID());
2874500a8d5d7fbec9dba5e693212da160849e401ffRomain Guy    generateTexture(entry, &bitmap, texture);
288c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
289c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
290c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
291c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
2924500a8d5d7fbec9dba5e693212da160849e401ffRomain Guyvoid PathCache::generateTexture(const PathDescription& entry, SkBitmap* bitmap,
2934500a8d5d7fbec9dba5e693212da160849e401ffRomain Guy        PathTexture* texture, bool addToCache) {
294c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    generateTexture(*bitmap, texture);
295c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
29642455fc9182cfe0c9f91c77712541888ca61df9eChris Craik    // Note here that we upload to a texture even if it's bigger than mMaxSize.
29742455fc9182cfe0c9f91c77712541888ca61df9eChris Craik    // Such an entry in mCache will only be temporary, since it will be evicted
29842455fc9182cfe0c9f91c77712541888ca61df9eChris Craik    // immediately on trim, or on any other Path entering the cache.
29938e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    uint32_t size = texture->width() * texture->height();
30042455fc9182cfe0c9f91c77712541888ca61df9eChris Craik    mSize += size;
30142455fc9182cfe0c9f91c77712541888ca61df9eChris Craik    PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d",
30242455fc9182cfe0c9f91c77712541888ca61df9eChris Craik            texture->id, size, mSize);
30342455fc9182cfe0c9f91c77712541888ca61df9eChris Craik    if (mDebugEnabled) {
30442455fc9182cfe0c9f91c77712541888ca61df9eChris Craik        ALOGD("Shape created, size = %d", size);
30542455fc9182cfe0c9f91c77712541888ca61df9eChris Craik    }
30642455fc9182cfe0c9f91c77712541888ca61df9eChris Craik    if (addToCache) {
30742455fc9182cfe0c9f91c77712541888ca61df9eChris Craik        mCache.put(entry, texture);
308c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
309c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
310c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
311c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::clear() {
312c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    mCache.clear();
313c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
314c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
315c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guyvoid PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) {
316cf8426c4eb60924d2387e0769d6cdc426178a31fChris Craik    ATRACE_NAME("Upload Path Texture");
31738e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    texture->upload(bitmap);
318c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    texture->setFilter(GL_LINEAR);
319c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
320c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
321c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
322ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy// Path precaching
323ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy///////////////////////////////////////////////////////////////////////////////
324ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
3255dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain GuyPathCache::PathProcessor::PathProcessor(Caches& caches):
3265dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        TaskProcessor<SkBitmap*>(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {
327fdd6fc1beb5076a630c7066b8b1731995636c09fRomain Guy}
32833f6beb10f98e8ba96250e284876d607055d278dRomain Guy
3295dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guyvoid PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
33005f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    PathTask* t = static_cast<PathTask*>(task.get());
3315dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    ATRACE_NAME("pathPrecache");
3325dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy
3335dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    float left, top, offset;
3345dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    uint32_t width, height;
335906d47fd2bcedb9674b5765d01bd9c758069074cChris Craik    PathCache::computePathBounds(&t->path, &t->paint, left, top, offset, width, height);
3365dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy
3375dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    PathTexture* texture = t->texture;
3385dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    texture->left = left;
3395dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    texture->top = top;
3405dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    texture->offset = offset;
3415dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy
3425dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    if (width <= mMaxTextureSize && height <= mMaxTextureSize) {
3435dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        SkBitmap* bitmap = new SkBitmap();
344906d47fd2bcedb9674b5765d01bd9c758069074cChris Craik        drawPath(&t->path, &t->paint, *bitmap, left, top, offset, width, height);
3455dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        t->setResult(bitmap);
3465dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    } else {
347d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        t->setResult(nullptr);
348ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    }
34933f6beb10f98e8ba96250e284876d607055d278dRomain Guy}
35033f6beb10f98e8ba96250e284876d607055d278dRomain Guy
3517fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy///////////////////////////////////////////////////////////////////////////////
352c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Paths
3537fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy///////////////////////////////////////////////////////////////////////////////
3547fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
355ee248599d49a15fc207c5aeb0b90ec263cc1d600Derek Sollenbergervoid PathCache::removeDeferred(const SkPath* path) {
356ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    Mutex::Autolock l(mLock);
357272a685f17cc4828257e521a6f62b7b17870f75eJohn Reck    mGarbage.push_back(path->getGenerationID());
358fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy}
359fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy
360fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guyvoid PathCache::clearGarbage() {
361e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    Vector<PathDescription> pathsToRemove;
362e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
363e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    { // scope for the mutex
364e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        Mutex::Autolock l(mLock);
365272a685f17cc4828257e521a6f62b7b17870f75eJohn Reck        for (const uint32_t generationID : mGarbage) {
366ee248599d49a15fc207c5aeb0b90ec263cc1d600Derek Sollenberger            LruCache<PathDescription, PathTexture*>::Iterator iter(mCache);
367ee248599d49a15fc207c5aeb0b90ec263cc1d600Derek Sollenberger            while (iter.next()) {
368ee248599d49a15fc207c5aeb0b90ec263cc1d600Derek Sollenberger                const PathDescription& key = iter.key();
3697224e2b624daea67b5653285c9640f170c096bdbsergeyv                if (key.type == ShapeType::Path && key.shape.path.mGenerationID == generationID) {
370ee248599d49a15fc207c5aeb0b90ec263cc1d600Derek Sollenberger                    pathsToRemove.push(key);
371ee248599d49a15fc207c5aeb0b90ec263cc1d600Derek Sollenberger                }
372ee248599d49a15fc207c5aeb0b90ec263cc1d600Derek Sollenberger            }
373e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        }
374e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        mGarbage.clear();
375e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    }
376e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy
377e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy    for (size_t i = 0; i < pathsToRemove.size(); i++) {
378e3b0a0117a2ab4118f868a731b238fe8f2430276Romain Guy        mCache.remove(pathsToRemove.itemAt(i));
379fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy    }
380a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy}
381a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy
382d218a92c0afb8c0d98135b20b52ac87236e1c935Chris CraikPathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) {
3837224e2b624daea67b5653285c9640f170c096bdbsergeyv    PathDescription entry(ShapeType::Path, paint);
384ee248599d49a15fc207c5aeb0b90ec263cc1d600Derek Sollenberger    entry.shape.path.mGenerationID = path->getGenerationID();
385c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
3867fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    PathTexture* texture = mCache.get(entry);
3877fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
3887fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    if (!texture) {
3897fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy        texture = addTexture(entry, path, paint);
390ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    } else {
391ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // A bitmap is attached to the texture, this means we need to
392ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // upload it as a GL texture
3935dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        const sp<Task<SkBitmap*> >& task = texture->task();
394d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        if (task != nullptr) {
395ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            // But we must first wait for the worker thread to be done
396ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            // producing the bitmap, so let's wait
3975dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy            SkBitmap* bitmap = task->getResult();
398ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            if (bitmap) {
3994500a8d5d7fbec9dba5e693212da160849e401ffRomain Guy                generateTexture(entry, bitmap, texture, false);
4005dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy                texture->clearTask();
401ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            } else {
4020f809f3b794174f044366bf421f8d0c72d9afc14Romain Guy                ALOGW("Path too large to be rendered into a texture");
4035dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy                texture->clearTask();
404d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik                texture = nullptr;
405ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy                mCache.remove(entry);
406ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy            }
407ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        }
408ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    }
409ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
410ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    return texture;
411ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy}
412ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
4137224e2b624daea67b5653285c9640f170c096bdbsergeyvvoid PathCache::remove(const SkPath* path, const SkPaint* paint) {
4147224e2b624daea67b5653285c9640f170c096bdbsergeyv    PathDescription entry(ShapeType::Path, paint);
4152e4f67c388aff0def50dd619388624f1dbe359adDigish Pandya    entry.shape.path.mGenerationID = path->getGenerationID();
4162e4f67c388aff0def50dd619388624f1dbe359adDigish Pandya    mCache.remove(entry);
4172e4f67c388aff0def50dd619388624f1dbe359adDigish Pandya}
4182e4f67c388aff0def50dd619388624f1dbe359adDigish Pandya
419d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craikvoid PathCache::precache(const SkPath* path, const SkPaint* paint) {
4205dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    if (!Caches::getInstance().tasks.canRunTasks()) {
4215dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        return;
4225dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy    }
4235dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy
4247224e2b624daea67b5653285c9640f170c096bdbsergeyv    PathDescription entry(ShapeType::Path, paint);
425ee248599d49a15fc207c5aeb0b90ec263cc1d600Derek Sollenberger    entry.shape.path.mGenerationID = path->getGenerationID();
426c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
427ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    PathTexture* texture = mCache.get(entry);
428ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
429ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    bool generate = false;
430ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    if (!texture) {
431ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        generate = true;
4327fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    }
4337fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
434ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    if (generate) {
435ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // It is important to specify the generation ID so we do not
436ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // attempt to precache the same path several times
437e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        texture = new PathTexture(Caches::getInstance(), path->getGenerationID());
4385dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        sp<PathTask> task = new PathTask(path, paint, texture);
4395dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        texture->setTask(task);
440ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
441ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // During the precaching phase we insert path texture objects into
442ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // the cache that do not point to any GL texture. They are instead
443ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // treated as a task for the precaching worker thread. This is why
444ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // we do not check the cache limit when inserting these objects.
445ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // The conversion into GL texture will happen in get(), when a client
446ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // asks for a path texture. This is also when the cache limit will
447ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        // be enforced.
448ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        mCache.put(entry, texture);
4495dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy
450d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        if (mProcessor == nullptr) {
4515dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy            mProcessor = new PathProcessor(Caches::getInstance());
4525dc7fa709646799a5207a5d217f70aa02bf4a3aaRomain Guy        }
453dee66b6d99dec8bc97843542d5388e50ebd0f6eeChris Craik        mProcessor->add(task);
454ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    }
4557fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy}
4567fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
457c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
458c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Rounded rects
459c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
460c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
461c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathTexture* PathCache::getRoundRect(float width, float height,
462d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        float rx, float ry, const SkPaint* paint) {
4637224e2b624daea67b5653285c9640f170c096bdbsergeyv    PathDescription entry(ShapeType::RoundRect, paint);
464c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.roundRect.mWidth = width;
465c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.roundRect.mHeight = height;
466c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.roundRect.mRx = rx;
467c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.roundRect.mRy = ry;
468c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
469c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathTexture* texture = get(entry);
470c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
471c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!texture) {
472c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkPath path;
473c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkRect r;
474c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        r.set(0.0f, 0.0f, width, height);
475c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
476c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
477c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        texture = addTexture(entry, &path, paint);
478c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
479c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
480c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
481c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
482c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
483c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
484c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Circles
485c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
486c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
487d218a92c0afb8c0d98135b20b52ac87236e1c935Chris CraikPathTexture* PathCache::getCircle(float radius, const SkPaint* paint) {
4887224e2b624daea67b5653285c9640f170c096bdbsergeyv    PathDescription entry(ShapeType::Circle, paint);
489c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.circle.mRadius = radius;
490c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
491c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathTexture* texture = get(entry);
492c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
493c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!texture) {
494c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkPath path;
495c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        path.addCircle(radius, radius, radius, SkPath::kCW_Direction);
496c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
497c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        texture = addTexture(entry, &path, paint);
498c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
499c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
500c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
501c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
502c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
503c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
504c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Ovals
505c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
506c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
507d218a92c0afb8c0d98135b20b52ac87236e1c935Chris CraikPathTexture* PathCache::getOval(float width, float height, const SkPaint* paint) {
5087224e2b624daea67b5653285c9640f170c096bdbsergeyv    PathDescription entry(ShapeType::Oval, paint);
509c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.oval.mWidth = width;
510c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.oval.mHeight = height;
511c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
512c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathTexture* texture = get(entry);
513c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
514c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!texture) {
515c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkPath path;
516c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkRect r;
517c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        r.set(0.0f, 0.0f, width, height);
518c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        path.addOval(r, SkPath::kCW_Direction);
519c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
520c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        texture = addTexture(entry, &path, paint);
521c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
522c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
523c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
524c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
525c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
526c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
527c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Rects
528c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
529c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
530d218a92c0afb8c0d98135b20b52ac87236e1c935Chris CraikPathTexture* PathCache::getRect(float width, float height, const SkPaint* paint) {
5317224e2b624daea67b5653285c9640f170c096bdbsergeyv    PathDescription entry(ShapeType::Rect, paint);
532c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.rect.mWidth = width;
533c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.rect.mHeight = height;
534c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
535c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathTexture* texture = get(entry);
536c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
537c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!texture) {
538c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkPath path;
539c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkRect r;
540c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        r.set(0.0f, 0.0f, width, height);
541c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        path.addRect(r, SkPath::kCW_Direction);
542c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
543c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        texture = addTexture(entry, &path, paint);
544c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
545c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
546c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
547c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
548c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
549c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
550c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy// Arcs
551c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy///////////////////////////////////////////////////////////////////////////////
552c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
553c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain GuyPathTexture* PathCache::getArc(float width, float height,
554d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) {
5557224e2b624daea67b5653285c9640f170c096bdbsergeyv    PathDescription entry(ShapeType::Arc, paint);
556c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.arc.mWidth = width;
557c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.arc.mHeight = height;
558c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.arc.mStartAngle = startAngle;
559c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.arc.mSweepAngle = sweepAngle;
560c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    entry.shape.arc.mUseCenter = useCenter;
561c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
562c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    PathTexture* texture = get(entry);
563c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
564c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    if (!texture) {
565c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkPath path;
566c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        SkRect r;
567c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        r.set(0.0f, 0.0f, width, height);
568c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        if (useCenter) {
569c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy            path.moveTo(r.centerX(), r.centerY());
570c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        }
571c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        path.arcTo(r, startAngle, sweepAngle, !useCenter);
572c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        if (useCenter) {
573c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy            path.close();
574c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        }
575c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
576c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy        texture = addTexture(entry, &path, paint);
577c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    }
578c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
579c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy    return texture;
580c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy}
581c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy
5827fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy}; // namespace uirenderer
5837fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy}; // namespace android
584