Home | History | Annotate | Download | only in hwui
      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 {
     56     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 
     87     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 
     99     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 
    111     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 {
    123         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:
    142     virtual bool lessThan(const ShapeCacheEntry& rhs) const {
    143         return false;
    144     }
    145 }; // struct ShapeCacheEntry
    146 
    147 
    148 struct RoundRectShapeCacheEntry: public ShapeCacheEntry {
    149     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 
    157     RoundRectShapeCacheEntry(): ShapeCacheEntry() {
    158         mWidth = 0;
    159         mHeight = 0;
    160         mRx = 0;
    161         mRy = 0;
    162     }
    163 
    164     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 {
    186     CircleShapeCacheEntry(float radius, SkPaint* paint):
    187             ShapeCacheEntry(ShapeCacheEntry::kShapeCircle, paint) {
    188         mRadius = *(uint32_t*) &radius;
    189     }
    190 
    191     CircleShapeCacheEntry(): ShapeCacheEntry() {
    192         mRadius = 0;
    193     }
    194 
    195     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 {
    208     OvalShapeCacheEntry(float width, float height, SkPaint* paint):
    209             ShapeCacheEntry(ShapeCacheEntry::kShapeOval, paint) {
    210         mWidth = *(uint32_t*) &width;
    211         mHeight = *(uint32_t*) &height;
    212     }
    213 
    214     OvalShapeCacheEntry(): ShapeCacheEntry() {
    215         mWidth = mHeight = 0;
    216     }
    217 
    218     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 {
    234     RectShapeCacheEntry(float width, float height, SkPaint* paint):
    235             ShapeCacheEntry(ShapeCacheEntry::kShapeRect, paint) {
    236         mWidth = *(uint32_t*) &width;
    237         mHeight = *(uint32_t*) &height;
    238     }
    239 
    240     RectShapeCacheEntry(): ShapeCacheEntry() {
    241         mWidth = mHeight = 0;
    242     }
    243 
    244     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 {
    260     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 
    270     ArcShapeCacheEntry(): ShapeCacheEntry() {
    271         mWidth = 0;
    272         mHeight = 0;
    273         mStartAngle = 0;
    274         mSweepAngle = 0;
    275         mUseCenter = 0;
    276     }
    277 
    278     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 
    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>
    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>
    437 ShapeCache<Entry>::~ShapeCache() {
    438     mCache.clear();
    439     delete[] mName;
    440 }
    441 
    442 template<class Entry>
    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>
    458 uint32_t ShapeCache<Entry>::getSize() {
    459     return mSize;
    460 }
    461 
    462 template<class Entry>
    463 uint32_t ShapeCache<Entry>::getMaxSize() {
    464     return mMaxSize;
    465 }
    466 
    467 template<class Entry>
    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>
    480 void ShapeCache<Entry>::operator()(Entry& path, PathTexture*& texture) {
    481     removeTexture(texture);
    482 }
    483 
    484 ///////////////////////////////////////////////////////////////////////////////
    485 // Caching
    486 ///////////////////////////////////////////////////////////////////////////////
    487 
    488 template<class Entry>
    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 
    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>
    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>
    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>
    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>
    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>
    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>
    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>
    610 void ShapeCache<Entry>::clear() {
    611     mCache.clear();
    612 }
    613 
    614 template<class Entry>
    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