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(...) LOGD(__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 
    340     PathTexture* get(Entry entry) {
    341         return mCache.get(entry);
    342     }
    343 
    344     void removeTexture(PathTexture* texture);
    345 
    346     GenerationCache<Entry, PathTexture*> mCache;
    347     uint32_t mSize;
    348     uint32_t mMaxSize;
    349     GLuint mMaxTextureSize;
    350 
    351     char* mName;
    352     bool mDebugEnabled;
    353 
    354 private:
    355     /**
    356      * Generates the texture from a bitmap into the specified texture structure.
    357      */
    358     void generateTexture(SkBitmap& bitmap, Texture* texture);
    359 
    360     void init();
    361 }; // class ShapeCache
    362 
    363 class RoundRectShapeCache: public ShapeCache<RoundRectShapeCacheEntry> {
    364 public:
    365     RoundRectShapeCache();
    366 
    367     PathTexture* getRoundRect(float width, float height, float rx, float ry, SkPaint* paint);
    368 }; // class RoundRectShapeCache
    369 
    370 class CircleShapeCache: public ShapeCache<CircleShapeCacheEntry> {
    371 public:
    372     CircleShapeCache();
    373 
    374     PathTexture* getCircle(float radius, SkPaint* paint);
    375 }; // class CircleShapeCache
    376 
    377 class OvalShapeCache: public ShapeCache<OvalShapeCacheEntry> {
    378 public:
    379     OvalShapeCache();
    380 
    381     PathTexture* getOval(float width, float height, SkPaint* paint);
    382 }; // class OvalShapeCache
    383 
    384 class RectShapeCache: public ShapeCache<RectShapeCacheEntry> {
    385 public:
    386     RectShapeCache();
    387 
    388     PathTexture* getRect(float width, float height, SkPaint* paint);
    389 }; // class RectShapeCache
    390 
    391 class ArcShapeCache: public ShapeCache<ArcShapeCacheEntry> {
    392 public:
    393     ArcShapeCache();
    394 
    395     PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
    396             bool useCenter, SkPaint* paint);
    397 }; // class ArcShapeCache
    398 
    399 ///////////////////////////////////////////////////////////////////////////////
    400 // Constructors/destructor
    401 ///////////////////////////////////////////////////////////////////////////////
    402 
    403 template<class Entry>
    404 ShapeCache<Entry>::ShapeCache(const char* name, const char* propertyName, float defaultSize):
    405         mCache(GenerationCache<ShapeCacheEntry, PathTexture*>::kUnlimitedCapacity),
    406         mSize(0), mMaxSize(MB(defaultSize)) {
    407     char property[PROPERTY_VALUE_MAX];
    408     if (property_get(propertyName, property, NULL) > 0) {
    409         INIT_LOGD("  Setting %s cache size to %sMB", name, property);
    410         setMaxSize(MB(atof(property)));
    411     } else {
    412         INIT_LOGD("  Using default %s cache size of %.2fMB", name, defaultSize);
    413     }
    414 
    415     size_t len = strlen(name);
    416     mName = new char[len + 1];
    417     strcpy(mName, name);
    418     mName[len] = '\0';
    419 
    420     init();
    421 }
    422 
    423 template<class Entry>
    424 ShapeCache<Entry>::~ShapeCache() {
    425     mCache.clear();
    426     delete[] mName;
    427 }
    428 
    429 template<class Entry>
    430 void ShapeCache<Entry>::init() {
    431     mCache.setOnEntryRemovedListener(this);
    432 
    433     GLint maxTextureSize;
    434     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
    435     mMaxTextureSize = maxTextureSize;
    436 
    437     mDebugEnabled = readDebugLevel() & kDebugCaches;
    438 }
    439 
    440 ///////////////////////////////////////////////////////////////////////////////
    441 // Size management
    442 ///////////////////////////////////////////////////////////////////////////////
    443 
    444 template<class Entry>
    445 uint32_t ShapeCache<Entry>::getSize() {
    446     return mSize;
    447 }
    448 
    449 template<class Entry>
    450 uint32_t ShapeCache<Entry>::getMaxSize() {
    451     return mMaxSize;
    452 }
    453 
    454 template<class Entry>
    455 void ShapeCache<Entry>::setMaxSize(uint32_t maxSize) {
    456     mMaxSize = maxSize;
    457     while (mSize > mMaxSize) {
    458         mCache.removeOldest();
    459     }
    460 }
    461 
    462 ///////////////////////////////////////////////////////////////////////////////
    463 // Callbacks
    464 ///////////////////////////////////////////////////////////////////////////////
    465 
    466 template<class Entry>
    467 void ShapeCache<Entry>::operator()(Entry& path, PathTexture*& texture) {
    468     removeTexture(texture);
    469 }
    470 
    471 ///////////////////////////////////////////////////////////////////////////////
    472 // Caching
    473 ///////////////////////////////////////////////////////////////////////////////
    474 
    475 template<class Entry>
    476 void ShapeCache<Entry>::removeTexture(PathTexture* texture) {
    477     if (texture) {
    478         const uint32_t size = texture->width * texture->height;
    479         mSize -= size;
    480 
    481         SHAPE_LOGD("ShapeCache::callback: delete %s: name, size, mSize = %d, %d, %d",
    482                 mName, texture->id, size, mSize);
    483         if (mDebugEnabled) {
    484             LOGD("Shape %s deleted, size = %d", mName, size);
    485         }
    486 
    487         glDeleteTextures(1, &texture->id);
    488         delete texture;
    489     }
    490 }
    491 
    492 template<class Entry>
    493 PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path,
    494         const SkPaint* paint) {
    495     const SkRect& bounds = path->getBounds();
    496 
    497     const float pathWidth = fmax(bounds.width(), 1.0f);
    498     const float pathHeight = fmax(bounds.height(), 1.0f);
    499 
    500     const float offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
    501 
    502     const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5);
    503     const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5);
    504 
    505     if (width > mMaxTextureSize || height > mMaxTextureSize) {
    506         LOGW("Shape %s too large to be rendered into a texture", mName);
    507         return NULL;
    508     }
    509 
    510     const uint32_t size = width * height;
    511     // Don't even try to cache a bitmap that's bigger than the cache
    512     if (size < mMaxSize) {
    513         while (mSize + size > mMaxSize) {
    514             mCache.removeOldest();
    515         }
    516     }
    517 
    518     PathTexture* texture = new PathTexture;
    519     texture->left = bounds.fLeft;
    520     texture->top = bounds.fTop;
    521     texture->offset = offset;
    522     texture->width = width;
    523     texture->height = height;
    524     texture->generation = path->getGenerationID();
    525 
    526     SkBitmap bitmap;
    527     bitmap.setConfig(SkBitmap::kA8_Config, width, height);
    528     bitmap.allocPixels();
    529     bitmap.eraseColor(0);
    530 
    531     SkPaint pathPaint(*paint);
    532 
    533     // Make sure the paint is opaque, color, alpha, filter, etc.
    534     // will be applied later when compositing the alpha8 texture
    535     pathPaint.setColor(0xff000000);
    536     pathPaint.setAlpha(255);
    537     pathPaint.setColorFilter(NULL);
    538     pathPaint.setMaskFilter(NULL);
    539     pathPaint.setShader(NULL);
    540     SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
    541     SkSafeUnref(pathPaint.setXfermode(mode));
    542 
    543     SkCanvas canvas(bitmap);
    544     canvas.translate(-bounds.fLeft + offset, -bounds.fTop + offset);
    545     canvas.drawPath(*path, pathPaint);
    546 
    547     generateTexture(bitmap, texture);
    548 
    549     if (size < mMaxSize) {
    550         mSize += size;
    551         SHAPE_LOGD("ShapeCache::get: create %s: name, size, mSize = %d, %d, %d",
    552                 mName, texture->id, size, mSize);
    553         if (mDebugEnabled) {
    554             LOGD("Shape %s created, size = %d", mName, size);
    555         }
    556         mCache.put(entry, texture);
    557     } else {
    558         texture->cleanup = true;
    559     }
    560 
    561     return texture;
    562 }
    563 
    564 template<class Entry>
    565 void ShapeCache<Entry>::clear() {
    566     mCache.clear();
    567 }
    568 
    569 template<class Entry>
    570 void ShapeCache<Entry>::generateTexture(SkBitmap& bitmap, Texture* texture) {
    571     SkAutoLockPixels alp(bitmap);
    572     if (!bitmap.readyToDraw()) {
    573         LOGE("Cannot generate texture from bitmap");
    574         return;
    575     }
    576 
    577     glGenTextures(1, &texture->id);
    578 
    579     glBindTexture(GL_TEXTURE_2D, texture->id);
    580     // Textures are Alpha8
    581     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    582 
    583     texture->blend = true;
    584     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
    585             GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels());
    586 
    587     texture->setFilter(GL_LINEAR, GL_LINEAR);
    588     texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
    589 }
    590 
    591 }; // namespace uirenderer
    592 }; // namespace android
    593 
    594 #endif // ANDROID_HWUI_SHAPE_CACHE_H
    595