Home | History | Annotate | Download | only in hwui
      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(nullptr) {
     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) override {
    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(nullptr) {
    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 != nullptr) {
    150             mBuffer = mTask->getResult();
    151             LOG_ALWAYS_FATAL_IF(mBuffer == nullptr, "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 reverseVertexArray(Vertex* polygon, int len) {
    211     int n = len / 2;
    212     for (int i = 0; i < n; i++) {
    213         Vertex tmp = polygon[i];
    214         int k = len - 1 - i;
    215         polygon[i] = polygon[k];
    216         polygon[k] = tmp;
    217     }
    218 }
    219 
    220 static void tessellateShadows(
    221         const Matrix4* drawTransform, const Rect* localClip,
    222         bool isCasterOpaque, const SkPath* casterPerimeter,
    223         const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
    224         const Vector3& lightCenter, float lightRadius,
    225         VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) {
    226 
    227     // tessellate caster outline into a 2d polygon
    228     Vector<Vertex> casterVertices2d;
    229     const float casterRefinementThreshold = 2.0f;
    230     PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
    231             casterRefinementThreshold, casterVertices2d);
    232 
    233     // Shadow requires CCW for now. TODO: remove potential double-reverse
    234     reverseVertexArray(casterVertices2d.editArray(), casterVertices2d.size());
    235 
    236     if (casterVertices2d.size() == 0) return;
    237 
    238     // map 2d caster poly into 3d
    239     const int casterVertexCount = casterVertices2d.size();
    240     Vector3 casterPolygon[casterVertexCount];
    241     float minZ = FLT_MAX;
    242     float maxZ = -FLT_MAX;
    243     for (int i = 0; i < casterVertexCount; i++) {
    244         const Vertex& point2d = casterVertices2d[i];
    245         casterPolygon[i] = (Vector3){point2d.x, point2d.y, 0};
    246         mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ);
    247         minZ = std::min(minZ, casterPolygon[i].z);
    248         maxZ = std::max(maxZ, casterPolygon[i].z);
    249     }
    250 
    251     // map the centroid of the caster into 3d
    252     Vector2 centroid =  ShadowTessellator::centroid2d(
    253             reinterpret_cast<const Vector2*>(casterVertices2d.array()),
    254             casterVertexCount);
    255     Vector3 centroid3d = {centroid.x, centroid.y, 0};
    256     mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ);
    257 
    258     // if the caster intersects the z=0 plane, lift it in Z so it doesn't
    259     if (minZ < SHADOW_MIN_CASTER_Z) {
    260         float casterLift = SHADOW_MIN_CASTER_Z - minZ;
    261         for (int i = 0; i < casterVertexCount; i++) {
    262             casterPolygon[i].z += casterLift;
    263         }
    264         centroid3d.z += casterLift;
    265     }
    266 
    267     // Check whether we want to draw the shadow at all by checking the caster's bounds against clip.
    268     // We only have ortho projection, so we can just ignore the Z in caster for
    269     // simple rejection calculation.
    270     Rect casterBounds(casterPerimeter->getBounds());
    271     casterTransformXY->mapRect(casterBounds);
    272 
    273     // actual tessellation of both shadows
    274     ShadowTessellator::tessellateAmbientShadow(
    275             isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
    276             casterBounds, *localClip, maxZ, ambientBuffer);
    277 
    278     ShadowTessellator::tessellateSpotShadow(
    279             isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
    280             *drawTransform, lightCenter, lightRadius, casterBounds, *localClip,
    281             spotBuffer);
    282 }
    283 
    284 class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t*> {
    285 public:
    286     ShadowProcessor(Caches& caches)
    287             : TaskProcessor<TessellationCache::vertexBuffer_pair_t*>(&caches.tasks) {}
    288     ~ShadowProcessor() {}
    289 
    290     virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) override {
    291         ShadowTask* t = static_cast<ShadowTask*>(task.get());
    292         ATRACE_NAME("shadow tessellation");
    293 
    294         VertexBuffer* ambientBuffer = new VertexBuffer;
    295         VertexBuffer* spotBuffer = new VertexBuffer;
    296         tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter,
    297                 &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
    298                 *ambientBuffer, *spotBuffer);
    299 
    300         t->setResult(new TessellationCache::vertexBuffer_pair_t(ambientBuffer, spotBuffer));
    301     }
    302 };
    303 
    304 ///////////////////////////////////////////////////////////////////////////////
    305 // Cache constructor/destructor
    306 ///////////////////////////////////////////////////////////////////////////////
    307 
    308 TessellationCache::TessellationCache()
    309         : mSize(0)
    310         , mMaxSize(MB(DEFAULT_VERTEX_CACHE_SIZE))
    311         , mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity)
    312         , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
    313     char property[PROPERTY_VALUE_MAX];
    314     if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, nullptr) > 0) {
    315         INIT_LOGD("  Setting %s cache size to %sMB", name, property);
    316         setMaxSize(MB(atof(property)));
    317     } else {
    318         INIT_LOGD("  Using default %s cache size of %.2fMB", name, DEFAULT_VERTEX_CACHE_SIZE);
    319     }
    320 
    321     mCache.setOnEntryRemovedListener(&mBufferRemovedListener);
    322     mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener);
    323     mDebugEnabled = Properties::debugLevel & kDebugCaches;
    324 }
    325 
    326 TessellationCache::~TessellationCache() {
    327     mCache.clear();
    328 }
    329 
    330 ///////////////////////////////////////////////////////////////////////////////
    331 // Size management
    332 ///////////////////////////////////////////////////////////////////////////////
    333 
    334 uint32_t TessellationCache::getSize() {
    335     LruCache<Description, Buffer*>::Iterator iter(mCache);
    336     uint32_t size = 0;
    337     while (iter.next()) {
    338         size += iter.value()->getSize();
    339     }
    340     return size;
    341 }
    342 
    343 uint32_t TessellationCache::getMaxSize() {
    344     return mMaxSize;
    345 }
    346 
    347 void TessellationCache::setMaxSize(uint32_t maxSize) {
    348     mMaxSize = maxSize;
    349     while (mSize > mMaxSize) {
    350         mCache.removeOldest();
    351     }
    352 }
    353 
    354 ///////////////////////////////////////////////////////////////////////////////
    355 // Caching
    356 ///////////////////////////////////////////////////////////////////////////////
    357 
    358 
    359 void TessellationCache::trim() {
    360     uint32_t size = getSize();
    361     while (size > mMaxSize) {
    362         size -= mCache.peekOldestValue()->getSize();
    363         mCache.removeOldest();
    364     }
    365     mShadowCache.clear();
    366 }
    367 
    368 void TessellationCache::clear() {
    369     mCache.clear();
    370     mShadowCache.clear();
    371 }
    372 
    373 ///////////////////////////////////////////////////////////////////////////////
    374 // Callbacks
    375 ///////////////////////////////////////////////////////////////////////////////
    376 
    377 void TessellationCache::BufferRemovedListener::operator()(Description& description,
    378         Buffer*& buffer) {
    379     delete buffer;
    380 }
    381 
    382 ///////////////////////////////////////////////////////////////////////////////
    383 // Shadows
    384 ///////////////////////////////////////////////////////////////////////////////
    385 
    386 void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
    387         bool opaque, const SkPath* casterPerimeter,
    388         const Matrix4* transformXY, const Matrix4* transformZ,
    389         const Vector3& lightCenter, float lightRadius) {
    390     ShadowDescription key(casterPerimeter, drawTransform);
    391 
    392     if (mShadowCache.get(key)) return;
    393     sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
    394             casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
    395     if (mShadowProcessor == nullptr) {
    396         mShadowProcessor = new ShadowProcessor(Caches::getInstance());
    397     }
    398     mShadowProcessor->add(task);
    399     task->incStrong(nullptr); // not using sp<>s, so manually ref while in the cache
    400     mShadowCache.put(key, task.get());
    401 }
    402 
    403 void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip,
    404         bool opaque, const SkPath* casterPerimeter,
    405         const Matrix4* transformXY, const Matrix4* transformZ,
    406         const Vector3& lightCenter, float lightRadius, vertexBuffer_pair_t& outBuffers) {
    407     ShadowDescription key(casterPerimeter, drawTransform);
    408     ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key));
    409     if (!task) {
    410         precacheShadows(drawTransform, localClip, opaque, casterPerimeter,
    411                 transformXY, transformZ, lightCenter, lightRadius);
    412         task = static_cast<ShadowTask*>(mShadowCache.get(key));
    413     }
    414     LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached");
    415     outBuffers = *(task->getResult());
    416 }
    417 
    418 ///////////////////////////////////////////////////////////////////////////////
    419 // Tessellation precaching
    420 ///////////////////////////////////////////////////////////////////////////////
    421 
    422 TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(
    423         const Description& entry, Tessellator tessellator) {
    424     Buffer* buffer = mCache.get(entry);
    425     if (!buffer) {
    426         // not cached, enqueue a task to fill the buffer
    427         sp<TessellationTask> task = new TessellationTask(tessellator, entry);
    428         buffer = new Buffer(task);
    429 
    430         if (mProcessor == nullptr) {
    431             mProcessor = new TessellationProcessor(Caches::getInstance());
    432         }
    433         mProcessor->add(task);
    434         mCache.put(entry, buffer);
    435     }
    436     return buffer;
    437 }
    438 
    439 static VertexBuffer* tessellatePath(const TessellationCache::Description& description,
    440         const SkPath& path) {
    441     Matrix4 matrix;
    442     SkPaint paint;
    443     description.setupMatrixAndPaint(&matrix, &paint);
    444     VertexBuffer* buffer = new VertexBuffer();
    445     PathTessellator::tessellatePath(path, &paint, matrix, *buffer);
    446     return buffer;
    447 }
    448 
    449 ///////////////////////////////////////////////////////////////////////////////
    450 // RoundRect
    451 ///////////////////////////////////////////////////////////////////////////////
    452 
    453 static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description) {
    454     SkRect rect = SkRect::MakeWH(description.shape.roundRect.width,
    455             description.shape.roundRect.height);
    456     float rx = description.shape.roundRect.rx;
    457     float ry = description.shape.roundRect.ry;
    458     if (description.style == SkPaint::kStrokeAndFill_Style) {
    459         float outset = description.strokeWidth / 2;
    460         rect.outset(outset, outset);
    461         rx += outset;
    462         ry += outset;
    463     }
    464     SkPath path;
    465     path.addRoundRect(rect, rx, ry);
    466     return tessellatePath(description, path);
    467 }
    468 
    469 TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(
    470         const Matrix4& transform, const SkPaint& paint,
    471         float width, float height, float rx, float ry) {
    472     Description entry(Description::kRoundRect, transform, paint);
    473     entry.shape.roundRect.width = width;
    474     entry.shape.roundRect.height = height;
    475     entry.shape.roundRect.rx = rx;
    476     entry.shape.roundRect.ry = ry;
    477     return getOrCreateBuffer(entry, &tessellateRoundRect);
    478 }
    479 const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform, const SkPaint& paint,
    480         float width, float height, float rx, float ry) {
    481     return getRoundRectBuffer(transform, paint, width, height, rx, ry)->getVertexBuffer();
    482 }
    483 
    484 }; // namespace uirenderer
    485 }; // namespace android
    486