| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include "Debug.h" |
| #include "Matrix.h" |
| #include "Rect.h" |
| #include "Vector.h" |
| #include "VertexBuffer.h" |
| #include "thread/TaskProcessor.h" |
| #include "utils/Macros.h" |
| #include "utils/Pair.h" |
| |
| #include <SkPaint.h> |
| #include <SkPath.h> |
| |
| #include <utils/LruCache.h> |
| #include <utils/Mutex.h> |
| #include <utils/StrongPointer.h> |
| |
| class SkBitmap; |
| class SkCanvas; |
| struct SkRect; |
| |
| namespace android { |
| namespace uirenderer { |
| |
| class Caches; |
| class VertexBuffer; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Classes |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| class TessellationCache { |
| public: |
| typedef Pair<VertexBuffer*, VertexBuffer*> vertexBuffer_pair_t; |
| |
| struct Description { |
| HASHABLE_TYPE(Description); |
| enum class Type { |
| None, |
| RoundRect, |
| }; |
| |
| Type type; |
| float scaleX; |
| float scaleY; |
| bool aa; |
| SkPaint::Cap cap; |
| SkPaint::Style style; |
| float strokeWidth; |
| union Shape { |
| struct RoundRect { |
| float width; |
| float height; |
| float rx; |
| float ry; |
| } roundRect; |
| } shape; |
| |
| Description(); |
| Description(Type type, const Matrix4& transform, const SkPaint& paint); |
| void setupMatrixAndPaint(Matrix4* matrix, SkPaint* paint) const; |
| }; |
| |
| struct ShadowDescription { |
| HASHABLE_TYPE(ShadowDescription); |
| const SkPath* nodeKey; |
| float matrixData[16]; |
| |
| ShadowDescription(); |
| ShadowDescription(const SkPath* nodeKey, const Matrix4* drawTransform); |
| }; |
| |
| class ShadowTask : public Task<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) {} |
| |
| /* 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 canceling or flushing outstanding |
| * tasks before tearing 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; |
| VertexBuffer ambientBuffer; |
| VertexBuffer spotBuffer; |
| }; |
| |
| TessellationCache(); |
| ~TessellationCache(); |
| |
| /** |
| * Clears the cache. This causes all TessellationBuffers to be deleted. |
| */ |
| void clear(); |
| /** |
| * Returns the maximum size of the cache in bytes. |
| */ |
| uint32_t getMaxSize(); |
| /** |
| * Returns the current size of the cache in bytes. |
| */ |
| uint32_t getSize(); |
| |
| /** |
| * Trims the contents of the cache, removing items until it's under its |
| * specified limit. |
| * |
| * Trimming is used for caches that support pre-caching from a worker |
| * thread. During pre-caching the maximum limit of the cache can be |
| * exceeded for the duration of the frame. It is therefore required to |
| * trim the cache at the end of the frame to keep the total amount of |
| * memory used under control. |
| * |
| * Also removes transient Shadow VertexBuffers, which aren't cached between frames. |
| */ |
| void trim(); |
| |
| // TODO: precache/get for Oval, Lines, Points, etc. |
| |
| void precacheRoundRect(const Matrix4& transform, const SkPaint& paint, float width, |
| float height, float rx, float ry) { |
| getRoundRectBuffer(transform, paint, width, height, rx, ry); |
| } |
| const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint, float width, |
| float height, float rx, float ry); |
| |
| sp<ShadowTask> getShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque, |
| const SkPath* casterPerimeter, const Matrix4* transformXY, |
| const Matrix4* transformZ, const Vector3& lightCenter, |
| float lightRadius); |
| |
| private: |
| class Buffer; |
| class TessellationTask; |
| class TessellationProcessor; |
| |
| typedef VertexBuffer* (*Tessellator)(const Description&); |
| |
| void precacheShadows(const Matrix4* drawTransform, const Rect& localClip, bool opaque, |
| const SkPath* casterPerimeter, const Matrix4* transformXY, |
| const Matrix4* transformZ, const Vector3& lightCenter, float lightRadius); |
| |
| Buffer* getRectBuffer(const Matrix4& transform, const SkPaint& paint, float width, |
| float height); |
| Buffer* getRoundRectBuffer(const Matrix4& transform, const SkPaint& paint, float width, |
| float height, float rx, float ry); |
| |
| Buffer* getOrCreateBuffer(const Description& entry, Tessellator tessellator); |
| |
| const uint32_t mMaxSize; |
| |
| bool mDebugEnabled; |
| |
| mutable Mutex mLock; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // General tessellation caching |
| /////////////////////////////////////////////////////////////////////////////// |
| sp<TaskProcessor<VertexBuffer*> > mProcessor; |
| LruCache<Description, Buffer*> mCache; |
| class BufferRemovedListener : public OnEntryRemoved<Description, Buffer*> { |
| void operator()(Description& description, Buffer*& buffer) override; |
| }; |
| BufferRemovedListener mBufferRemovedListener; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Shadow tessellation caching |
| /////////////////////////////////////////////////////////////////////////////// |
| sp<TaskProcessor<vertexBuffer_pair_t> > mShadowProcessor; |
| |
| // holds a pointer, and implicit strong ref to each shadow task of the frame |
| LruCache<ShadowDescription, Task<vertexBuffer_pair_t>*> mShadowCache; |
| class BufferPairRemovedListener |
| : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t>*> { |
| void operator()(ShadowDescription& description, |
| Task<vertexBuffer_pair_t>*& bufferPairTask) override { |
| bufferPairTask->decStrong(nullptr); |
| } |
| }; |
| BufferPairRemovedListener mBufferPairRemovedListener; |
| |
| }; // class TessellationCache |
| |
| void tessellateShadows(const Matrix4* drawTransform, const Rect* localClip, bool isCasterOpaque, |
| const SkPath* casterPerimeter, const Matrix4* casterTransformXY, |
| const Matrix4* casterTransformZ, const Vector3& lightCenter, |
| float lightRadius, VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer); |
| |
| }; // namespace uirenderer |
| }; // namespace android |