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*) ℞ 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