OSDN Git Service

Merge "Ensure Dequeue/Queue duration is always set" into nyc-mr1-dev
[android-x86/frameworks-base.git] / libs / hwui / TessellationCache.cpp
index 1d6b7cc..cfdc084 100644 (file)
@@ -35,13 +35,14 @@ namespace uirenderer {
 ///////////////////////////////////////////////////////////////////////////////
 
 TessellationCache::Description::Description()
-        : type(kNone)
+        : type(Type::None)
         , scaleX(1.0f)
         , scaleY(1.0f)
         , aa(false)
         , cap(SkPaint::kDefault_Cap)
         , style(SkPaint::kFill_Style)
         , strokeWidth(1.0f) {
+    // Shape bits should be set to zeroes, because they are used for hash calculation.
     memset(&shape, 0, sizeof(Shape));
 }
 
@@ -52,11 +53,30 @@ TessellationCache::Description::Description(Type type, const Matrix4& transform,
         , style(paint.getStyle())
         , strokeWidth(paint.getStrokeWidth()) {
     PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY);
+    // Shape bits should be set to zeroes, because they are used for hash calculation.
     memset(&shape, 0, sizeof(Shape));
 }
 
+bool TessellationCache::Description::operator==(const TessellationCache::Description& rhs) const {
+    if (type != rhs.type) return false;
+    if (scaleX != rhs.scaleX) return false;
+    if (scaleY != rhs.scaleY) return false;
+    if (aa != rhs.aa) return false;
+    if (cap != rhs.cap) return false;
+    if (style != rhs.style) return false;
+    if (strokeWidth != rhs.strokeWidth) return false;
+    if (type == Type::None) return true;
+    const Shape::RoundRect& lRect = shape.roundRect;
+    const Shape::RoundRect& rRect = rhs.shape.roundRect;
+
+    if (lRect.width != rRect.width) return false;
+    if (lRect.height != rRect.height) return false;
+    if (lRect.rx != rRect.rx) return false;
+    return lRect.ry == rRect.ry;
+}
+
 hash_t TessellationCache::Description::hash() const {
-    uint32_t hash = JenkinsHashMix(0, type);
+    uint32_t hash = JenkinsHashMix(0, static_cast<int>(type));
     hash = JenkinsHashMix(hash, aa);
     hash = JenkinsHashMix(hash, cap);
     hash = JenkinsHashMix(hash, style);
@@ -76,18 +96,24 @@ void TessellationCache::Description::setupMatrixAndPaint(Matrix4* matrix, SkPain
 }
 
 TessellationCache::ShadowDescription::ShadowDescription()
-        : nodeKey(NULL) {
-    memset(&matrixData, 0, 16 * sizeof(float));
+        : nodeKey(nullptr) {
+    memset(&matrixData, 0, sizeof(matrixData));
 }
 
-TessellationCache::ShadowDescription::ShadowDescription(const void* nodeKey, const Matrix4* drawTransform)
+TessellationCache::ShadowDescription::ShadowDescription(const SkPath* nodeKey, const Matrix4* drawTransform)
         : nodeKey(nodeKey) {
-    memcpy(&matrixData, drawTransform->data, 16 * sizeof(float));
+    memcpy(&matrixData, drawTransform->data, sizeof(matrixData));
+}
+
+bool TessellationCache::ShadowDescription::operator==(
+        const TessellationCache::ShadowDescription& rhs) const {
+    return nodeKey == rhs.nodeKey
+            && memcmp(&matrixData, &rhs.matrixData, sizeof(matrixData)) == 0;
 }
 
 hash_t TessellationCache::ShadowDescription::hash() const {
     uint32_t hash = JenkinsHashMixBytes(0, (uint8_t*) &nodeKey, sizeof(const void*));
-    hash = JenkinsHashMixBytes(hash, (uint8_t*) &matrixData, 16 * sizeof(float));
+    hash = JenkinsHashMixBytes(hash, (uint8_t*) &matrixData, sizeof(matrixData));
     return JenkinsHashWhiten(hash);
 }
 
@@ -114,7 +140,7 @@ public:
             : TaskProcessor<VertexBuffer*>(&caches.tasks) {}
     ~TessellationProcessor() {}
 
-    virtual void onProcess(const sp<Task<VertexBuffer*> >& task) {
+    virtual void onProcess(const sp<Task<VertexBuffer*> >& task) override {
         TessellationTask* t = static_cast<TessellationTask*>(task.get());
         ATRACE_NAME("shape tessellation");
         VertexBuffer* buffer = t->tessellator(t->description);
@@ -126,7 +152,7 @@ class TessellationCache::Buffer {
 public:
     Buffer(const sp<Task<VertexBuffer*> >& task)
             : mTask(task)
-            , mBuffer(NULL) {
+            , mBuffer(nullptr) {
     }
 
     ~Buffer() {
@@ -146,9 +172,9 @@ public:
 
 private:
     void blockOnPrecache() {
-        if (mTask != NULL) {
+        if (mTask != nullptr) {
             mBuffer = mTask->getResult();
-            LOG_ALWAYS_FATAL_IF(mBuffer == NULL, "Failed to precache");
+            LOG_ALWAYS_FATAL_IF(mBuffer == nullptr, "Failed to precache");
             mTask.clear();
         }
     }
@@ -160,45 +186,6 @@ private:
 // Shadow tessellation task processing
 ///////////////////////////////////////////////////////////////////////////////
 
-class ShadowTask : public Task<TessellationCache::vertexBuffer_pair_t*> {
-public:
-    ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
-            const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
-            const Vector3& lightCenter, float lightRadius)
-        : drawTransform(*drawTransform)
-        , localClip(localClip)
-        , opaque(opaque)
-        , casterPerimeter(*casterPerimeter)
-        , transformXY(*transformXY)
-        , transformZ(*transformZ)
-        , lightCenter(lightCenter)
-        , lightRadius(lightRadius) {
-    }
-
-    ~ShadowTask() {
-        TessellationCache::vertexBuffer_pair_t* bufferPair = getResult();
-        delete bufferPair->getFirst();
-        delete bufferPair->getSecond();
-        delete bufferPair;
-    }
-
-    /* Note - we deep copy all task parameters, because *even though* pointers into Allocator
-     * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
-     * certain Allocators are destroyed before trim() is called to flush incomplete tasks.
-     *
-     * These deep copies could be avoided, long term, by cancelling or flushing outstanding tasks
-     * before tearning down single-frame LinearAllocators.
-     */
-    const Matrix4 drawTransform;
-    const Rect localClip;
-    bool opaque;
-    const SkPath casterPerimeter;
-    const Matrix4 transformXY;
-    const Matrix4 transformZ;
-    const Vector3 lightCenter;
-    const float lightRadius;
-};
-
 static void mapPointFakeZ(Vector3& point, const mat4* transformXY, const mat4* transformZ) {
     // map z coordinate with true 3d matrix
     point.z = transformZ->mapZ(point);
@@ -207,7 +194,17 @@ static void mapPointFakeZ(Vector3& point, const mat4* transformXY, const mat4* t
     transformXY->mapPoint(point.x, point.y);
 }
 
-static void tessellateShadows(
+static void reverseVertexArray(Vertex* polygon, int len) {
+    int n = len / 2;
+    for (int i = 0; i < n; i++) {
+        Vertex tmp = polygon[i];
+        int k = len - 1 - i;
+        polygon[i] = polygon[k];
+        polygon[k] = tmp;
+    }
+}
+
+void tessellateShadows(
         const Matrix4* drawTransform, const Rect* localClip,
         bool isCasterOpaque, const SkPath* casterPerimeter,
         const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
@@ -215,14 +212,13 @@ static void tessellateShadows(
         VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) {
 
     // tessellate caster outline into a 2d polygon
-    Vector<Vertex> casterVertices2d;
-    const float casterRefinementThresholdSquared = 4.0f;
+    std::vector<Vertex> casterVertices2d;
+    const float casterRefinementThreshold = 2.0f;
     PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
-            casterRefinementThresholdSquared, casterVertices2d);
-    if (!ShadowTessellator::isClockwisePath(*casterPerimeter)) {
-        ShadowTessellator::reverseVertexArray(casterVertices2d.editArray(),
-                casterVertices2d.size());
-    }
+            casterRefinementThreshold, casterVertices2d);
+
+    // Shadow requires CCW for now. TODO: remove potential double-reverse
+    reverseVertexArray(&casterVertices2d.front(), casterVertices2d.size());
 
     if (casterVertices2d.size() == 0) return;
 
@@ -235,13 +231,13 @@ static void tessellateShadows(
         const Vertex& point2d = casterVertices2d[i];
         casterPolygon[i] = (Vector3){point2d.x, point2d.y, 0};
         mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ);
-        minZ = fmin(minZ, casterPolygon[i].z);
-        maxZ = fmax(maxZ, casterPolygon[i].z);
+        minZ = std::min(minZ, casterPolygon[i].z);
+        maxZ = std::max(maxZ, casterPolygon[i].z);
     }
 
     // map the centroid of the caster into 3d
     Vector2 centroid =  ShadowTessellator::centroid2d(
-            reinterpret_cast<const Vector2*>(casterVertices2d.array()),
+            reinterpret_cast<const Vector2*>(&casterVertices2d.front()),
             casterVertexCount);
     Vector3 centroid3d = {centroid.x, centroid.y, 0};
     mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ);
@@ -272,23 +268,21 @@ static void tessellateShadows(
             spotBuffer);
 }
 
-class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t*> {
+class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t> {
 public:
     ShadowProcessor(Caches& caches)
-            : TaskProcessor<TessellationCache::vertexBuffer_pair_t*>(&caches.tasks) {}
+            : TaskProcessor<TessellationCache::vertexBuffer_pair_t>(&caches.tasks) {}
     ~ShadowProcessor() {}
 
-    virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) {
-        ShadowTask* t = static_cast<ShadowTask*>(task.get());
+    virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t> >& task) override {
+        TessellationCache::ShadowTask* t = static_cast<TessellationCache::ShadowTask*>(task.get());
         ATRACE_NAME("shadow tessellation");
 
-        VertexBuffer* ambientBuffer = new VertexBuffer;
-        VertexBuffer* spotBuffer = new VertexBuffer;
         tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter,
                 &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
-                *ambientBuffer, *spotBuffer);
+                t->ambientBuffer, t->spotBuffer);
 
-        t->setResult(new TessellationCache::vertexBuffer_pair_t(ambientBuffer, spotBuffer));
+        t->setResult(TessellationCache::vertexBuffer_pair_t(&t->ambientBuffer, &t->spotBuffer));
     }
 };
 
@@ -297,21 +291,12 @@ public:
 ///////////////////////////////////////////////////////////////////////////////
 
 TessellationCache::TessellationCache()
-        : mSize(0)
-        , mMaxSize(MB(DEFAULT_VERTEX_CACHE_SIZE))
+        : mMaxSize(Properties::tessellationCacheSize)
         , mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity)
         , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
-    char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, NULL) > 0) {
-        INIT_LOGD("  Setting %s cache size to %sMB", name, property);
-        setMaxSize(MB(atof(property)));
-    } else {
-        INIT_LOGD("  Using default %s cache size of %.2fMB", name, DEFAULT_VERTEX_CACHE_SIZE);
-    }
-
     mCache.setOnEntryRemovedListener(&mBufferRemovedListener);
     mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener);
-    mDebugEnabled = readDebugLevel() & kDebugCaches;
+    mDebugEnabled = Properties::debugLevel & kDebugCaches;
 }
 
 TessellationCache::~TessellationCache() {
@@ -335,13 +320,6 @@ uint32_t TessellationCache::getMaxSize() {
     return mMaxSize;
 }
 
-void TessellationCache::setMaxSize(uint32_t maxSize) {
-    mMaxSize = maxSize;
-    while (mSize > mMaxSize) {
-        mCache.removeOldest();
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Caching
 ///////////////////////////////////////////////////////////////////////////////
@@ -383,14 +361,11 @@ void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect
     if (mShadowCache.get(key)) return;
     sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
             casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
-    if (mShadowProcessor == NULL) {
+    if (mShadowProcessor == nullptr) {
         mShadowProcessor = new ShadowProcessor(Caches::getInstance());
     }
-    if (!mShadowProcessor->add(task)) {
-        mShadowProcessor->process(task);
-    }
-
-    task->incStrong(NULL); // not using sp<>s, so manually ref while in the cache
+    mShadowProcessor->add(task);
+    task->incStrong(nullptr); // not using sp<>s, so manually ref while in the cache
     mShadowCache.put(key, task.get());
 }
 
@@ -405,8 +380,24 @@ void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rec
                 transformXY, transformZ, lightCenter, lightRadius);
         task = static_cast<ShadowTask*>(mShadowCache.get(key));
     }
-    LOG_ALWAYS_FATAL_IF(task == NULL, "shadow not precached");
-    outBuffers = *(task->getResult());
+    LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached");
+    outBuffers = task->getResult();
+}
+
+sp<TessellationCache::ShadowTask> TessellationCache::getShadowTask(
+        const Matrix4* drawTransform, const Rect& localClip,
+        bool opaque, const SkPath* casterPerimeter,
+        const Matrix4* transformXY, const Matrix4* transformZ,
+        const Vector3& lightCenter, float lightRadius) {
+    ShadowDescription key(casterPerimeter, drawTransform);
+    ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key));
+    if (!task) {
+        precacheShadows(drawTransform, localClip, opaque, casterPerimeter,
+                transformXY, transformZ, lightCenter, lightRadius);
+        task = static_cast<ShadowTask*>(mShadowCache.get(key));
+    }
+    LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached");
+    return task;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -421,12 +412,10 @@ TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(
         sp<TessellationTask> task = new TessellationTask(tessellator, entry);
         buffer = new Buffer(task);
 
-        if (mProcessor == NULL) {
+        if (mProcessor == nullptr) {
             mProcessor = new TessellationProcessor(Caches::getInstance());
         }
-        if (!mProcessor->add(task)) {
-            mProcessor->process(task);
-        }
+        mProcessor->add(task);
         mCache.put(entry, buffer);
     }
     return buffer;
@@ -465,7 +454,7 @@ static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& d
 TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(
         const Matrix4& transform, const SkPaint& paint,
         float width, float height, float rx, float ry) {
-    Description entry(Description::kRoundRect, transform, paint);
+    Description entry(Description::Type::RoundRect, transform, paint);
     entry.shape.roundRect.width = width;
     entry.shape.roundRect.height = height;
     entry.shape.roundRect.rx = rx;