OSDN Git Service

Merge \\\"DO NOT MERGE: Allow apps with CREATE_USERS permission to call UM.getProfile...
[android-x86/frameworks-base.git] / libs / hwui / TessellationCache.cpp
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