• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANDROID_HWUI_SHAPE_CACHE_H
18 #define ANDROID_HWUI_SHAPE_CACHE_H
19 
20 #include <GLES2/gl2.h>
21 
22 #include <SkBitmap.h>
23 #include <SkCanvas.h>
24 #include <SkPaint.h>
25 #include <SkPath.h>
26 #include <SkRect.h>
27 
28 #include "Debug.h"
29 #include "Properties.h"
30 #include "Texture.h"
31 #include "utils/Compare.h"
32 #include "utils/GenerationCache.h"
33 
34 namespace android {
35 namespace uirenderer {
36 
37 ///////////////////////////////////////////////////////////////////////////////
38 // Defines
39 ///////////////////////////////////////////////////////////////////////////////
40 
41 // Debug
42 #if DEBUG_SHAPES
43     #define SHAPE_LOGD(...) ALOGD(__VA_ARGS__)
44 #else
45     #define SHAPE_LOGD(...)
46 #endif
47 
48 ///////////////////////////////////////////////////////////////////////////////
49 // Classes
50 ///////////////////////////////////////////////////////////////////////////////
51 
52 /**
53  * Alpha texture used to represent a path.
54  */
55 struct PathTexture: public Texture {
PathTexturePathTexture56     PathTexture(): Texture() {
57     }
58 
59     /**
60      * Left coordinate of the path bounds.
61      */
62     float left;
63     /**
64      * Top coordinate of the path bounds.
65      */
66     float top;
67     /**
68      * Offset to draw the path at the correct origin.
69      */
70     float offset;
71 }; // struct PathTexture
72 
73 /**
74  * Describe a shape in the shape cache.
75  */
76 struct ShapeCacheEntry {
77     enum ShapeType {
78         kShapeNone,
79         kShapeRect,
80         kShapeRoundRect,
81         kShapeCircle,
82         kShapeOval,
83         kShapeArc,
84         kShapePath
85     };
86 
ShapeCacheEntryShapeCacheEntry87     ShapeCacheEntry() {
88         shapeType = kShapeNone;
89         join = SkPaint::kDefault_Join;
90         cap = SkPaint::kDefault_Cap;
91         style = SkPaint::kFill_Style;
92         float v = 4.0f;
93         miter = *(uint32_t*) &v;
94         v = 1.0f;
95         strokeWidth = *(uint32_t*) &v;
96         pathEffect = NULL;
97     }
98 
ShapeCacheEntryShapeCacheEntry99     ShapeCacheEntry(ShapeType type, SkPaint* paint) {
100         shapeType = type;
101         join = paint->getStrokeJoin();
102         cap = paint->getStrokeCap();
103         float v = paint->getStrokeMiter();
104         miter = *(uint32_t*) &v;
105         v = paint->getStrokeWidth();
106         strokeWidth = *(uint32_t*) &v;
107         style = paint->getStyle();
108         pathEffect = paint->getPathEffect();
109     }
110 
~ShapeCacheEntryShapeCacheEntry111     virtual ~ShapeCacheEntry() {
112     }
113 
114     ShapeType shapeType;
115     SkPaint::Join join;
116     SkPaint::Cap cap;
117     SkPaint::Style style;
118     uint32_t miter;
119     uint32_t strokeWidth;
120     SkPathEffect* pathEffect;
121 
122     bool operator<(const ShapeCacheEntry& rhs) const {
LTE_INTShapeCacheEntry123         LTE_INT(shapeType) {
124             LTE_INT(join) {
125                 LTE_INT(cap) {
126                     LTE_INT(style) {
127                         LTE_INT(miter) {
128                             LTE_INT(strokeWidth) {
129                                 LTE_INT(pathEffect) {
130                                     return lessThan(rhs);
131                                 }
132                             }
133                         }
134                     }
135                 }
136             }
137         }
138         return false;
139     }
140 
141 protected:
lessThanShapeCacheEntry142     virtual bool lessThan(const ShapeCacheEntry& rhs) const {
143         return false;
144     }
145 }; // struct ShapeCacheEntry
146 
147 
148 struct RoundRectShapeCacheEntry: public ShapeCacheEntry {
RoundRectShapeCacheEntryRoundRectShapeCacheEntry149     RoundRectShapeCacheEntry(float width, float height, float rx, float ry, SkPaint* paint):
150             ShapeCacheEntry(ShapeCacheEntry::kShapeRoundRect, paint) {
151         mWidth = *(uint32_t*) &width;
152         mHeight = *(uint32_t*) &height;
153         mRx = *(uint32_t*) &rx;
154         mRy = *(uint32_t*) &ry;
155     }
156 
RoundRectShapeCacheEntryRoundRectShapeCacheEntry157     RoundRectShapeCacheEntry(): ShapeCacheEntry() {
158         mWidth = 0;
159         mHeight = 0;
160         mRx = 0;
161         mRy = 0;
162     }
163 
lessThanRoundRectShapeCacheEntry164     bool lessThan(const ShapeCacheEntry& r) const {
165         const RoundRectShapeCacheEntry& rhs = (const RoundRectShapeCacheEntry&) r;
166         LTE_INT(mWidth) {
167             LTE_INT(mHeight) {
168                 LTE_INT(mRx) {
169                     LTE_INT(mRy) {
170                         return false;
171                     }
172                 }
173             }
174         }
175         return false;
176     }
177 
178 private:
179     uint32_t mWidth;
180     uint32_t mHeight;
181     uint32_t mRx;
182     uint32_t mRy;
183 }; // RoundRectShapeCacheEntry
184 
185 struct CircleShapeCacheEntry: public ShapeCacheEntry {
CircleShapeCacheEntryCircleShapeCacheEntry186     CircleShapeCacheEntry(float radius, SkPaint* paint):
187             ShapeCacheEntry(ShapeCacheEntry::kShapeCircle, paint) {
188         mRadius = *(uint32_t*) &radius;
189     }
190 
CircleShapeCacheEntryCircleShapeCacheEntry191     CircleShapeCacheEntry(): ShapeCacheEntry() {
192         mRadius = 0;
193     }
194 
lessThanCircleShapeCacheEntry195     bool lessThan(const ShapeCacheEntry& r) const {
196         const CircleShapeCacheEntry& rhs = (const CircleShapeCacheEntry&) r;
197         LTE_INT(mRadius) {
198             return false;
199         }
200         return false;
201     }
202 
203 private:
204     uint32_t mRadius;
205 }; // CircleShapeCacheEntry
206 
207 struct OvalShapeCacheEntry: public ShapeCacheEntry {
OvalShapeCacheEntryOvalShapeCacheEntry208     OvalShapeCacheEntry(float width, float height, SkPaint* paint):
209             ShapeCacheEntry(ShapeCacheEntry::kShapeOval, paint) {
210         mWidth = *(uint32_t*) &width;
211         mHeight = *(uint32_t*) &height;
212     }
213 
OvalShapeCacheEntryOvalShapeCacheEntry214     OvalShapeCacheEntry(): ShapeCacheEntry() {
215         mWidth = mHeight = 0;
216     }
217 
lessThanOvalShapeCacheEntry218     bool lessThan(const ShapeCacheEntry& r) const {
219         const OvalShapeCacheEntry& rhs = (const OvalShapeCacheEntry&) r;
220         LTE_INT(mWidth) {
221             LTE_INT(mHeight) {
222                 return false;
223             }
224         }
225         return false;
226     }
227 
228 private:
229     uint32_t mWidth;
230     uint32_t mHeight;
231 }; // OvalShapeCacheEntry
232 
233 struct RectShapeCacheEntry: public ShapeCacheEntry {
RectShapeCacheEntryRectShapeCacheEntry234     RectShapeCacheEntry(float width, float height, SkPaint* paint):
235             ShapeCacheEntry(ShapeCacheEntry::kShapeRect, paint) {
236         mWidth = *(uint32_t*) &width;
237         mHeight = *(uint32_t*) &height;
238     }
239 
RectShapeCacheEntryRectShapeCacheEntry240     RectShapeCacheEntry(): ShapeCacheEntry() {
241         mWidth = mHeight = 0;
242     }
243 
lessThanRectShapeCacheEntry244     bool lessThan(const ShapeCacheEntry& r) const {
245         const RectShapeCacheEntry& rhs = (const RectShapeCacheEntry&) r;
246         LTE_INT(mWidth) {
247             LTE_INT(mHeight) {
248                 return false;
249             }
250         }
251         return false;
252     }
253 
254 private:
255     uint32_t mWidth;
256     uint32_t mHeight;
257 }; // RectShapeCacheEntry
258 
259 struct ArcShapeCacheEntry: public ShapeCacheEntry {
ArcShapeCacheEntryArcShapeCacheEntry260     ArcShapeCacheEntry(float width, float height, float startAngle, float sweepAngle,
261             bool useCenter, SkPaint* paint):
262             ShapeCacheEntry(ShapeCacheEntry::kShapeArc, paint) {
263         mWidth = *(uint32_t*) &width;
264         mHeight = *(uint32_t*) &height;
265         mStartAngle = *(uint32_t*) &startAngle;
266         mSweepAngle = *(uint32_t*) &sweepAngle;
267         mUseCenter = useCenter ? 1 : 0;
268     }
269 
ArcShapeCacheEntryArcShapeCacheEntry270     ArcShapeCacheEntry(): ShapeCacheEntry() {
271         mWidth = 0;
272         mHeight = 0;
273         mStartAngle = 0;
274         mSweepAngle = 0;
275         mUseCenter = 0;
276     }
277 
lessThanArcShapeCacheEntry278     bool lessThan(const ShapeCacheEntry& r) const {
279         const ArcShapeCacheEntry& rhs = (const ArcShapeCacheEntry&) r;
280         LTE_INT(mWidth) {
281             LTE_INT(mHeight) {
282                 LTE_INT(mStartAngle) {
283                     LTE_INT(mSweepAngle) {
284                         LTE_INT(mUseCenter) {
285                             return false;
286                         }
287                     }
288                 }
289             }
290         }
291         return false;
292     }
293 
294 private:
295     uint32_t mWidth;
296     uint32_t mHeight;
297     uint32_t mStartAngle;
298     uint32_t mSweepAngle;
299     uint32_t mUseCenter;
300 }; // ArcShapeCacheEntry
301 
302 /**
303  * A simple LRU shape cache. The cache has a maximum size expressed in bytes.
304  * Any texture added to the cache causing the cache to grow beyond the maximum
305  * allowed size will also cause the oldest texture to be kicked out.
306  */
307 template<typename Entry>
308 class ShapeCache: public OnEntryRemoved<Entry, PathTexture*> {
309 public:
310     ShapeCache(const char* name, const char* propertyName, float defaultSize);
311     ~ShapeCache();
312 
313     /**
314      * Used as a callback when an entry is removed from the cache.
315      * Do not invoke directly.
316      */
317     void operator()(Entry& path, PathTexture*& texture);
318 
319     /**
320      * Clears the cache. This causes all textures to be deleted.
321      */
322     void clear();
323 
324     /**
325      * Sets the maximum size of the cache in bytes.
326      */
327     void setMaxSize(uint32_t maxSize);
328     /**
329      * Returns the maximum size of the cache in bytes.
330      */
331     uint32_t getMaxSize();
332     /**
333      * Returns the current size of the cache in bytes.
334      */
335     uint32_t getSize();
336 
337 protected:
338     PathTexture* addTexture(const Entry& entry, const SkPath *path, const SkPaint* paint);
339     PathTexture* addTexture(const Entry& entry, SkBitmap* bitmap);
340     void addTexture(const Entry& entry, SkBitmap* bitmap, PathTexture* texture);
341 
342     /**
343      * Ensures there is enough space in the cache for a texture of the specified
344      * dimensions.
345      */
346     void purgeCache(uint32_t width, uint32_t height);
347 
348     void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height);
349     void initPaint(SkPaint& paint);
350 
351     bool checkTextureSize(uint32_t width, uint32_t height);
352 
get(Entry entry)353     PathTexture* get(Entry entry) {
354         return mCache.get(entry);
355     }
356 
357     void removeTexture(PathTexture* texture);
358 
359     GenerationCache<Entry, PathTexture*> mCache;
360     uint32_t mSize;
361     uint32_t mMaxSize;
362     GLuint mMaxTextureSize;
363 
364     char* mName;
365     bool mDebugEnabled;
366 
367 private:
368     /**
369      * Generates the texture from a bitmap into the specified texture structure.
370      */
371     void generateTexture(SkBitmap& bitmap, Texture* texture);
372 
373     void init();
374 }; // class ShapeCache
375 
376 class RoundRectShapeCache: public ShapeCache<RoundRectShapeCacheEntry> {
377 public:
378     RoundRectShapeCache();
379 
380     PathTexture* getRoundRect(float width, float height, float rx, float ry, SkPaint* paint);
381 }; // class RoundRectShapeCache
382 
383 class CircleShapeCache: public ShapeCache<CircleShapeCacheEntry> {
384 public:
385     CircleShapeCache();
386 
387     PathTexture* getCircle(float radius, SkPaint* paint);
388 }; // class CircleShapeCache
389 
390 class OvalShapeCache: public ShapeCache<OvalShapeCacheEntry> {
391 public:
392     OvalShapeCache();
393 
394     PathTexture* getOval(float width, float height, SkPaint* paint);
395 }; // class OvalShapeCache
396 
397 class RectShapeCache: public ShapeCache<RectShapeCacheEntry> {
398 public:
399     RectShapeCache();
400 
401     PathTexture* getRect(float width, float height, SkPaint* paint);
402 }; // class RectShapeCache
403 
404 class ArcShapeCache: public ShapeCache<ArcShapeCacheEntry> {
405 public:
406     ArcShapeCache();
407 
408     PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
409             bool useCenter, SkPaint* paint);
410 }; // class ArcShapeCache
411 
412 ///////////////////////////////////////////////////////////////////////////////
413 // Constructors/destructor
414 ///////////////////////////////////////////////////////////////////////////////
415 
416 template<class Entry>
ShapeCache(const char * name,const char * propertyName,float defaultSize)417 ShapeCache<Entry>::ShapeCache(const char* name, const char* propertyName, float defaultSize):
418         mCache(GenerationCache<ShapeCacheEntry, PathTexture*>::kUnlimitedCapacity),
419         mSize(0), mMaxSize(MB(defaultSize)) {
420     char property[PROPERTY_VALUE_MAX];
421     if (property_get(propertyName, property, NULL) > 0) {
422         INIT_LOGD("  Setting %s cache size to %sMB", name, property);
423         setMaxSize(MB(atof(property)));
424     } else {
425         INIT_LOGD("  Using default %s cache size of %.2fMB", name, defaultSize);
426     }
427 
428     size_t len = strlen(name);
429     mName = new char[len + 1];
430     strcpy(mName, name);
431     mName[len] = '\0';
432 
433     init();
434 }
435 
436 template<class Entry>
~ShapeCache()437 ShapeCache<Entry>::~ShapeCache() {
438     mCache.clear();
439     delete[] mName;
440 }
441 
442 template<class Entry>
init()443 void ShapeCache<Entry>::init() {
444     mCache.setOnEntryRemovedListener(this);
445 
446     GLint maxTextureSize;
447     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
448     mMaxTextureSize = maxTextureSize;
449 
450     mDebugEnabled = readDebugLevel() & kDebugCaches;
451 }
452 
453 ///////////////////////////////////////////////////////////////////////////////
454 // Size management
455 ///////////////////////////////////////////////////////////////////////////////
456 
457 template<class Entry>
getSize()458 uint32_t ShapeCache<Entry>::getSize() {
459     return mSize;
460 }
461 
462 template<class Entry>
getMaxSize()463 uint32_t ShapeCache<Entry>::getMaxSize() {
464     return mMaxSize;
465 }
466 
467 template<class Entry>
setMaxSize(uint32_t maxSize)468 void ShapeCache<Entry>::setMaxSize(uint32_t maxSize) {
469     mMaxSize = maxSize;
470     while (mSize > mMaxSize) {
471         mCache.removeOldest();
472     }
473 }
474 
475 ///////////////////////////////////////////////////////////////////////////////
476 // Callbacks
477 ///////////////////////////////////////////////////////////////////////////////
478 
479 template<class Entry>
operator()480 void ShapeCache<Entry>::operator()(Entry& path, PathTexture*& texture) {
481     removeTexture(texture);
482 }
483 
484 ///////////////////////////////////////////////////////////////////////////////
485 // Caching
486 ///////////////////////////////////////////////////////////////////////////////
487 
488 template<class Entry>
removeTexture(PathTexture * texture)489 void ShapeCache<Entry>::removeTexture(PathTexture* texture) {
490     if (texture) {
491         const uint32_t size = texture->width * texture->height;
492         mSize -= size;
493 
494         SHAPE_LOGD("ShapeCache::callback: delete %s: name, size, mSize = %d, %d, %d",
495                 mName, texture->id, size, mSize);
496         if (mDebugEnabled) {
497             ALOGD("Shape %s deleted, size = %d", mName, size);
498         }
499 
500         glDeleteTextures(1, &texture->id);
501         delete texture;
502     }
503 }
504 
505 void computePathBounds(const SkPath* path, const SkPaint* paint,
506         float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
507 void computeBounds(const SkRect& bounds, const SkPaint* paint,
508         float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
509 
createTexture(float left,float top,float offset,uint32_t width,uint32_t height,uint32_t id)510 static PathTexture* createTexture(float left, float top, float offset,
511         uint32_t width, uint32_t height, uint32_t id) {
512     PathTexture* texture = new PathTexture;
513     texture->left = left;
514     texture->top = top;
515     texture->offset = offset;
516     texture->width = width;
517     texture->height = height;
518     texture->generation = id;
519     return texture;
520 }
521 
522 template<class Entry>
purgeCache(uint32_t width,uint32_t height)523 void ShapeCache<Entry>::purgeCache(uint32_t width, uint32_t height) {
524     const uint32_t size = width * height;
525     // Don't even try to cache a bitmap that's bigger than the cache
526     if (size < mMaxSize) {
527         while (mSize + size > mMaxSize) {
528             mCache.removeOldest();
529         }
530     }
531 }
532 
533 template<class Entry>
initBitmap(SkBitmap & bitmap,uint32_t width,uint32_t height)534 void ShapeCache<Entry>::initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) {
535     bitmap.setConfig(SkBitmap::kA8_Config, width, height);
536     bitmap.allocPixels();
537     bitmap.eraseColor(0);
538 }
539 
540 template<class Entry>
initPaint(SkPaint & paint)541 void ShapeCache<Entry>::initPaint(SkPaint& paint) {
542     // Make sure the paint is opaque, color, alpha, filter, etc.
543     // will be applied later when compositing the alpha8 texture
544     paint.setColor(0xff000000);
545     paint.setAlpha(255);
546     paint.setColorFilter(NULL);
547     paint.setMaskFilter(NULL);
548     paint.setShader(NULL);
549     SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
550     SkSafeUnref(paint.setXfermode(mode));
551 }
552 
553 template<class Entry>
checkTextureSize(uint32_t width,uint32_t height)554 bool ShapeCache<Entry>::checkTextureSize(uint32_t width, uint32_t height) {
555     if (width > mMaxTextureSize || height > mMaxTextureSize) {
556         ALOGW("Shape %s too large to be rendered into a texture (%dx%d, max=%dx%d)",
557                 mName, width, height, mMaxTextureSize, mMaxTextureSize);
558         return false;
559     }
560     return true;
561 }
562 
563 template<class Entry>
addTexture(const Entry & entry,const SkPath * path,const SkPaint * paint)564 PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path,
565         const SkPaint* paint) {
566 
567     float left, top, offset;
568     uint32_t width, height;
569     computePathBounds(path, paint, left, top, offset, width, height);
570 
571     if (!checkTextureSize(width, height)) return NULL;
572 
573     purgeCache(width, height);
574 
575     SkBitmap bitmap;
576     initBitmap(bitmap, width, height);
577 
578     SkPaint pathPaint(*paint);
579     initPaint(pathPaint);
580 
581     SkCanvas canvas(bitmap);
582     canvas.translate(-left + offset, -top + offset);
583     canvas.drawPath(*path, pathPaint);
584 
585     PathTexture* texture = createTexture(left, top, offset, width, height, path->getGenerationID());
586     addTexture(entry, &bitmap, texture);
587 
588     return texture;
589 }
590 
591 template<class Entry>
addTexture(const Entry & entry,SkBitmap * bitmap,PathTexture * texture)592 void ShapeCache<Entry>::addTexture(const Entry& entry, SkBitmap* bitmap, PathTexture* texture) {
593     generateTexture(*bitmap, texture);
594 
595     uint32_t size = texture->width * texture->height;
596     if (size < mMaxSize) {
597         mSize += size;
598         SHAPE_LOGD("ShapeCache::get: create %s: name, size, mSize = %d, %d, %d",
599                 mName, texture->id, size, mSize);
600         if (mDebugEnabled) {
601             ALOGD("Shape %s created, size = %d", mName, size);
602         }
603         mCache.put(entry, texture);
604     } else {
605         texture->cleanup = true;
606     }
607 }
608 
609 template<class Entry>
clear()610 void ShapeCache<Entry>::clear() {
611     mCache.clear();
612 }
613 
614 template<class Entry>
generateTexture(SkBitmap & bitmap,Texture * texture)615 void ShapeCache<Entry>::generateTexture(SkBitmap& bitmap, Texture* texture) {
616     SkAutoLockPixels alp(bitmap);
617     if (!bitmap.readyToDraw()) {
618         ALOGE("Cannot generate texture from bitmap");
619         return;
620     }
621 
622     glGenTextures(1, &texture->id);
623 
624     glBindTexture(GL_TEXTURE_2D, texture->id);
625     // Textures are Alpha8
626     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
627 
628     texture->blend = true;
629     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
630             GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels());
631 
632     texture->setFilter(GL_LINEAR);
633     texture->setWrap(GL_CLAMP_TO_EDGE);
634 }
635 
636 }; // namespace uirenderer
637 }; // namespace android
638 
639 #endif // ANDROID_HWUI_SHAPE_CACHE_H
640