1 /* 2 * Copyright (C) 2014 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 #include <utils/JenkinsHash.h> 18 #include <utils/Trace.h> 19 20 #include "Caches.h" 21 #include "OpenGLRenderer.h" 22 #include "PathTessellator.h" 23 #include "ShadowTessellator.h" 24 #include "TessellationCache.h" 25 26 #include "thread/Signal.h" 27 #include "thread/Task.h" 28 #include "thread/TaskProcessor.h" 29 30 namespace android { 31 namespace uirenderer { 32 33 /////////////////////////////////////////////////////////////////////////////// 34 // Cache entries 35 /////////////////////////////////////////////////////////////////////////////// 36 37 TessellationCache::Description::Description() 38 : type(kNone) 39 , scaleX(1.0f) 40 , scaleY(1.0f) 41 , aa(false) 42 , cap(SkPaint::kDefault_Cap) 43 , style(SkPaint::kFill_Style) 44 , strokeWidth(1.0f) { 45 memset(&shape, 0, sizeof(Shape)); 46 } 47 48 TessellationCache::Description::Description(Type type, const Matrix4& transform, const SkPaint& paint) 49 : type(type) 50 , aa(paint.isAntiAlias()) 51 , cap(paint.getStrokeCap()) 52 , style(paint.getStyle()) 53 , strokeWidth(paint.getStrokeWidth()) { 54 PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY); 55 memset(&shape, 0, sizeof(Shape)); 56 } 57 58 hash_t TessellationCache::Description::hash() const { 59 uint32_t hash = JenkinsHashMix(0, type); 60 hash = JenkinsHashMix(hash, aa); 61 hash = JenkinsHashMix(hash, cap); 62 hash = JenkinsHashMix(hash, style); 63 hash = JenkinsHashMix(hash, android::hash_type(strokeWidth)); 64 hash = JenkinsHashMix(hash, android::hash_type(scaleX)); 65 hash = JenkinsHashMix(hash, android::hash_type(scaleY)); 66 hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape)); 67 return JenkinsHashWhiten(hash); 68 } 69 70 void TessellationCache::Description::setupMatrixAndPaint(Matrix4* matrix, SkPaint* paint) const { 71 matrix->loadScale(scaleX, scaleY, 1.0f); 72 paint->setAntiAlias(aa); 73 paint->setStrokeCap(cap); 74 paint->setStyle(style); 75 paint->setStrokeWidth(strokeWidth); 76 } 77 78 TessellationCache::ShadowDescription::ShadowDescription() 79 : nodeKey(NULL) { 80 memset(&matrixData, 0, 16 * sizeof(float)); 81 } 82 83 TessellationCache::ShadowDescription::ShadowDescription(const void* nodeKey, const Matrix4* drawTransform) 84 : nodeKey(nodeKey) { 85 memcpy(&matrixData, drawTransform->data, 16 * sizeof(float)); 86 } 87 88 hash_t TessellationCache::ShadowDescription::hash() const { 89 uint32_t hash = JenkinsHashMixBytes(0, (uint8_t*) &nodeKey, sizeof(const void*)); 90 hash = JenkinsHashMixBytes(hash, (uint8_t*) &matrixData, 16 * sizeof(float)); 91 return JenkinsHashWhiten(hash); 92 } 93 94 /////////////////////////////////////////////////////////////////////////////// 95 // General purpose tessellation task processing 96 /////////////////////////////////////////////////////////////////////////////// 97 98 class TessellationCache::TessellationTask : public Task<VertexBuffer*> { 99 public: 100 TessellationTask(Tessellator tessellator, const Description& description) 101 : tessellator(tessellator) 102 , description(description) { 103 } 104 105 ~TessellationTask() {} 106 107 Tessellator tessellator; 108 Description description; 109 }; 110 111 class TessellationCache::TessellationProcessor : public TaskProcessor<VertexBuffer*> { 112 public: 113 TessellationProcessor(Caches& caches) 114 : TaskProcessor<VertexBuffer*>(&caches.tasks) {} 115 ~TessellationProcessor() {} 116 117 virtual void onProcess(const sp<Task<VertexBuffer*> >& task) { 118 TessellationTask* t = static_cast<TessellationTask*>(task.get()); 119 ATRACE_NAME("shape tessellation"); 120 VertexBuffer* buffer = t->tessellator(t->description); 121 t->setResult(buffer); 122 } 123 }; 124 125 class TessellationCache::Buffer { 126 public: 127 Buffer(const sp<Task<VertexBuffer*> >& task) 128 : mTask(task) 129 , mBuffer(NULL) { 130 } 131 132 ~Buffer() { 133 mTask.clear(); 134 delete mBuffer; 135 } 136 137 unsigned int getSize() { 138 blockOnPrecache(); 139 return mBuffer->getSize(); 140 } 141 142 const VertexBuffer* getVertexBuffer() { 143 blockOnPrecache(); 144 return mBuffer; 145 } 146 147 private: 148 void blockOnPrecache() { 149 if (mTask != NULL) { 150 mBuffer = mTask->getResult(); 151 LOG_ALWAYS_FATAL_IF(mBuffer == NULL, "Failed to precache"); 152 mTask.clear(); 153 } 154 } 155 sp<Task<VertexBuffer*> > mTask; 156 VertexBuffer* mBuffer; 157 }; 158 159 /////////////////////////////////////////////////////////////////////////////// 160 // Shadow tessellation task processing 161 /////////////////////////////////////////////////////////////////////////////// 162 163 class ShadowTask : public Task<TessellationCache::vertexBuffer_pair_t*> { 164 public: 165 ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque, 166 const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ, 167 const Vector3& lightCenter, float lightRadius) 168 : drawTransform(*drawTransform) 169 , localClip(localClip) 170 , opaque(opaque) 171 , casterPerimeter(*casterPerimeter) 172 , transformXY(*transformXY) 173 , transformZ(*transformZ) 174 , lightCenter(lightCenter) 175 , lightRadius(lightRadius) { 176 } 177 178 ~ShadowTask() { 179 TessellationCache::vertexBuffer_pair_t* bufferPair = getResult(); 180 delete bufferPair->getFirst(); 181 delete bufferPair->getSecond(); 182 delete bufferPair; 183 } 184 185 /* Note - we deep copy all task parameters, because *even though* pointers into Allocator 186 * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame, 187 * certain Allocators are destroyed before trim() is called to flush incomplete tasks. 188 * 189 * These deep copies could be avoided, long term, by cancelling or flushing outstanding tasks 190 * before tearning down single-frame LinearAllocators. 191 */ 192 const Matrix4 drawTransform; 193 const Rect localClip; 194 bool opaque; 195 const SkPath casterPerimeter; 196 const Matrix4 transformXY; 197 const Matrix4 transformZ; 198 const Vector3 lightCenter; 199 const float lightRadius; 200 }; 201 202 static void mapPointFakeZ(Vector3& point, const mat4* transformXY, const mat4* transformZ) { 203 // map z coordinate with true 3d matrix 204 point.z = transformZ->mapZ(point); 205 206 // map x,y coordinates with draw/Skia matrix 207 transformXY->mapPoint(point.x, point.y); 208 } 209 210 static void tessellateShadows( 211 const Matrix4* drawTransform, const Rect* localClip, 212 bool isCasterOpaque, const SkPath* casterPerimeter, 213 const Matrix4* casterTransformXY, const Matrix4* casterTransformZ, 214 const Vector3& lightCenter, float lightRadius, 215 VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) { 216 217 // tessellate caster outline into a 2d polygon 218 Vector<Vertex> casterVertices2d; 219 const float casterRefinementThresholdSquared = 4.0f; 220 PathTessellator::approximatePathOutlineVertices(*casterPerimeter, 221 casterRefinementThresholdSquared, casterVertices2d); 222 if (!ShadowTessellator::isClockwisePath(*casterPerimeter)) { 223 ShadowTessellator::reverseVertexArray(casterVertices2d.editArray(), 224 casterVertices2d.size()); 225 } 226 227 if (casterVertices2d.size() == 0) return; 228 229 // map 2d caster poly into 3d 230 const int casterVertexCount = casterVertices2d.size(); 231 Vector3 casterPolygon[casterVertexCount]; 232 float minZ = FLT_MAX; 233 float maxZ = -FLT_MAX; 234 for (int i = 0; i < casterVertexCount; i++) { 235 const Vertex& point2d = casterVertices2d[i]; 236 casterPolygon[i] = (Vector3){point2d.x, point2d.y, 0}; 237 mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ); 238 minZ = fmin(minZ, casterPolygon[i].z); 239 maxZ = fmax(maxZ, casterPolygon[i].z); 240 } 241 242 // map the centroid of the caster into 3d 243 Vector2 centroid = ShadowTessellator::centroid2d( 244 reinterpret_cast<const Vector2*>(casterVertices2d.array()), 245 casterVertexCount); 246 Vector3 centroid3d = {centroid.x, centroid.y, 0}; 247 mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ); 248 249 // if the caster intersects the z=0 plane, lift it in Z so it doesn't 250 if (minZ < SHADOW_MIN_CASTER_Z) { 251 float casterLift = SHADOW_MIN_CASTER_Z - minZ; 252 for (int i = 0; i < casterVertexCount; i++) { 253 casterPolygon[i].z += casterLift; 254 } 255 centroid3d.z += casterLift; 256 } 257 258 // Check whether we want to draw the shadow at all by checking the caster's bounds against clip. 259 // We only have ortho projection, so we can just ignore the Z in caster for 260 // simple rejection calculation. 261 Rect casterBounds(casterPerimeter->getBounds()); 262 casterTransformXY->mapRect(casterBounds); 263 264 // actual tessellation of both shadows 265 ShadowTessellator::tessellateAmbientShadow( 266 isCasterOpaque, casterPolygon, casterVertexCount, centroid3d, 267 casterBounds, *localClip, maxZ, ambientBuffer); 268 269 ShadowTessellator::tessellateSpotShadow( 270 isCasterOpaque, casterPolygon, casterVertexCount, centroid3d, 271 *drawTransform, lightCenter, lightRadius, casterBounds, *localClip, 272 spotBuffer); 273 } 274 275 class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t*> { 276 public: 277 ShadowProcessor(Caches& caches) 278 : TaskProcessor<TessellationCache::vertexBuffer_pair_t*>(&caches.tasks) {} 279 ~ShadowProcessor() {} 280 281 virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) { 282 ShadowTask* t = static_cast<ShadowTask*>(task.get()); 283 ATRACE_NAME("shadow tessellation"); 284 285 VertexBuffer* ambientBuffer = new VertexBuffer; 286 VertexBuffer* spotBuffer = new VertexBuffer; 287 tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter, 288 &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius, 289 *ambientBuffer, *spotBuffer); 290 291 t->setResult(new TessellationCache::vertexBuffer_pair_t(ambientBuffer, spotBuffer)); 292 } 293 }; 294 295 /////////////////////////////////////////////////////////////////////////////// 296 // Cache constructor/destructor 297 /////////////////////////////////////////////////////////////////////////////// 298 299 TessellationCache::TessellationCache() 300 : mSize(0) 301 , mMaxSize(MB(DEFAULT_VERTEX_CACHE_SIZE)) 302 , mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity) 303 , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) { 304 char property[PROPERTY_VALUE_MAX]; 305 if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, NULL) > 0) { 306 INIT_LOGD(" Setting %s cache size to %sMB", name, property); 307 setMaxSize(MB(atof(property))); 308 } else { 309 INIT_LOGD(" Using default %s cache size of %.2fMB", name, DEFAULT_VERTEX_CACHE_SIZE); 310 } 311 312 mCache.setOnEntryRemovedListener(&mBufferRemovedListener); 313 mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener); 314 mDebugEnabled = readDebugLevel() & kDebugCaches; 315 } 316 317 TessellationCache::~TessellationCache() { 318 mCache.clear(); 319 } 320 321 /////////////////////////////////////////////////////////////////////////////// 322 // Size management 323 /////////////////////////////////////////////////////////////////////////////// 324 325 uint32_t TessellationCache::getSize() { 326 LruCache<Description, Buffer*>::Iterator iter(mCache); 327 uint32_t size = 0; 328 while (iter.next()) { 329 size += iter.value()->getSize(); 330 } 331 return size; 332 } 333 334 uint32_t TessellationCache::getMaxSize() { 335 return mMaxSize; 336 } 337 338 void TessellationCache::setMaxSize(uint32_t maxSize) { 339 mMaxSize = maxSize; 340 while (mSize > mMaxSize) { 341 mCache.removeOldest(); 342 } 343 } 344 345 /////////////////////////////////////////////////////////////////////////////// 346 // Caching 347 /////////////////////////////////////////////////////////////////////////////// 348 349 350 void TessellationCache::trim() { 351 uint32_t size = getSize(); 352 while (size > mMaxSize) { 353 size -= mCache.peekOldestValue()->getSize(); 354 mCache.removeOldest(); 355 } 356 mShadowCache.clear(); 357 } 358 359 void TessellationCache::clear() { 360 mCache.clear(); 361 mShadowCache.clear(); 362 } 363 364 /////////////////////////////////////////////////////////////////////////////// 365 // Callbacks 366 /////////////////////////////////////////////////////////////////////////////// 367 368 void TessellationCache::BufferRemovedListener::operator()(Description& description, 369 Buffer*& buffer) { 370 delete buffer; 371 } 372 373 /////////////////////////////////////////////////////////////////////////////// 374 // Shadows 375 /////////////////////////////////////////////////////////////////////////////// 376 377 void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect& localClip, 378 bool opaque, const SkPath* casterPerimeter, 379 const Matrix4* transformXY, const Matrix4* transformZ, 380 const Vector3& lightCenter, float lightRadius) { 381 ShadowDescription key(casterPerimeter, drawTransform); 382 383 sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque, 384 casterPerimeter, transformXY, transformZ, lightCenter, lightRadius); 385 if (mShadowProcessor == NULL) { 386 mShadowProcessor = new ShadowProcessor(Caches::getInstance()); 387 } 388 mShadowProcessor->add(task); 389 390 task->incStrong(NULL); // not using sp<>s, so manually ref while in the cache 391 mShadowCache.put(key, task.get()); 392 } 393 394 void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip, 395 bool opaque, const SkPath* casterPerimeter, 396 const Matrix4* transformXY, const Matrix4* transformZ, 397 const Vector3& lightCenter, float lightRadius, vertexBuffer_pair_t& outBuffers) { 398 ShadowDescription key(casterPerimeter, drawTransform); 399 ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key)); 400 if (!task) { 401 precacheShadows(drawTransform, localClip, opaque, casterPerimeter, 402 transformXY, transformZ, lightCenter, lightRadius); 403 task = static_cast<ShadowTask*>(mShadowCache.get(key)); 404 } 405 LOG_ALWAYS_FATAL_IF(task == NULL, "shadow not precached"); 406 outBuffers = *(task->getResult()); 407 } 408 409 /////////////////////////////////////////////////////////////////////////////// 410 // Tessellation precaching 411 /////////////////////////////////////////////////////////////////////////////// 412 413 TessellationCache::Buffer* TessellationCache::getOrCreateBuffer( 414 const Description& entry, Tessellator tessellator) { 415 Buffer* buffer = mCache.get(entry); 416 if (!buffer) { 417 // not cached, enqueue a task to fill the buffer 418 sp<TessellationTask> task = new TessellationTask(tessellator, entry); 419 buffer = new Buffer(task); 420 421 if (mProcessor == NULL) { 422 mProcessor = new TessellationProcessor(Caches::getInstance()); 423 } 424 mProcessor->add(task); 425 mCache.put(entry, buffer); 426 } 427 return buffer; 428 } 429 430 static VertexBuffer* tessellatePath(const TessellationCache::Description& description, 431 const SkPath& path) { 432 Matrix4 matrix; 433 SkPaint paint; 434 description.setupMatrixAndPaint(&matrix, &paint); 435 VertexBuffer* buffer = new VertexBuffer(); 436 PathTessellator::tessellatePath(path, &paint, matrix, *buffer); 437 return buffer; 438 } 439 440 /////////////////////////////////////////////////////////////////////////////// 441 // RoundRect 442 /////////////////////////////////////////////////////////////////////////////// 443 444 static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description) { 445 SkRect rect = SkRect::MakeWH(description.shape.roundRect.width, 446 description.shape.roundRect.height); 447 float rx = description.shape.roundRect.rx; 448 float ry = description.shape.roundRect.ry; 449 if (description.style == SkPaint::kStrokeAndFill_Style) { 450 float outset = description.strokeWidth / 2; 451 rect.outset(outset, outset); 452 rx += outset; 453 ry += outset; 454 } 455 SkPath path; 456 path.addRoundRect(rect, rx, ry); 457 return tessellatePath(description, path); 458 } 459 460 TessellationCache::Buffer* TessellationCache::getRoundRectBuffer( 461 const Matrix4& transform, const SkPaint& paint, 462 float width, float height, float rx, float ry) { 463 Description entry(Description::kRoundRect, transform, paint); 464 entry.shape.roundRect.width = width; 465 entry.shape.roundRect.height = height; 466 entry.shape.roundRect.rx = rx; 467 entry.shape.roundRect.ry = ry; 468 return getOrCreateBuffer(entry, &tessellateRoundRect); 469 } 470 const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform, const SkPaint& paint, 471 float width, float height, float rx, float ry) { 472 return getRoundRectBuffer(transform, paint, width, height, rx, ry)->getVertexBuffer(); 473 } 474 475 }; // namespace uirenderer 476 }; // namespace android 477