OSDN Git Service

Merge \\\"DO NOT MERGE: Fix CTS regression\\\" into lmp-dev am: 124cc534f8 -s ours...
[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(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     if (mShadowCache.get(key)) return;
384     sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
385             casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
386     if (mShadowProcessor == NULL) {
387         mShadowProcessor = new ShadowProcessor(Caches::getInstance());
388     }
389     if (!mShadowProcessor->add(task)) {
390         mShadowProcessor->process(task);
391     }
392
393     task->incStrong(NULL); // not using sp<>s, so manually ref while in the cache
394     mShadowCache.put(key, task.get());
395 }
396
397 void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip,
398         bool opaque, const SkPath* casterPerimeter,
399         const Matrix4* transformXY, const Matrix4* transformZ,
400         const Vector3& lightCenter, float lightRadius, vertexBuffer_pair_t& outBuffers) {
401     ShadowDescription key(casterPerimeter, drawTransform);
402     ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key));
403     if (!task) {
404         precacheShadows(drawTransform, localClip, opaque, casterPerimeter,
405                 transformXY, transformZ, lightCenter, lightRadius);
406         task = static_cast<ShadowTask*>(mShadowCache.get(key));
407     }
408     LOG_ALWAYS_FATAL_IF(task == NULL, "shadow not precached");
409     outBuffers = *(task->getResult());
410 }
411
412 ///////////////////////////////////////////////////////////////////////////////
413 // Tessellation precaching
414 ///////////////////////////////////////////////////////////////////////////////
415
416 TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(
417         const Description& entry, Tessellator tessellator) {
418     Buffer* buffer = mCache.get(entry);
419     if (!buffer) {
420         // not cached, enqueue a task to fill the buffer
421         sp<TessellationTask> task = new TessellationTask(tessellator, entry);
422         buffer = new Buffer(task);
423
424         if (mProcessor == NULL) {
425             mProcessor = new TessellationProcessor(Caches::getInstance());
426         }
427         if (!mProcessor->add(task)) {
428             mProcessor->process(task);
429         }
430         mCache.put(entry, buffer);
431     }
432     return buffer;
433 }
434
435 static VertexBuffer* tessellatePath(const TessellationCache::Description& description,
436         const SkPath& path) {
437     Matrix4 matrix;
438     SkPaint paint;
439     description.setupMatrixAndPaint(&matrix, &paint);
440     VertexBuffer* buffer = new VertexBuffer();
441     PathTessellator::tessellatePath(path, &paint, matrix, *buffer);
442     return buffer;
443 }
444
445 ///////////////////////////////////////////////////////////////////////////////
446 // RoundRect
447 ///////////////////////////////////////////////////////////////////////////////
448
449 static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description) {
450     SkRect rect = SkRect::MakeWH(description.shape.roundRect.width,
451             description.shape.roundRect.height);
452     float rx = description.shape.roundRect.rx;
453     float ry = description.shape.roundRect.ry;
454     if (description.style == SkPaint::kStrokeAndFill_Style) {
455         float outset = description.strokeWidth / 2;
456         rect.outset(outset, outset);
457         rx += outset;
458         ry += outset;
459     }
460     SkPath path;
461     path.addRoundRect(rect, rx, ry);
462     return tessellatePath(description, path);
463 }
464
465 TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(
466         const Matrix4& transform, const SkPaint& paint,
467         float width, float height, float rx, float ry) {
468     Description entry(Description::kRoundRect, transform, paint);
469     entry.shape.roundRect.width = width;
470     entry.shape.roundRect.height = height;
471     entry.shape.roundRect.rx = rx;
472     entry.shape.roundRect.ry = ry;
473     return getOrCreateBuffer(entry, &tessellateRoundRect);
474 }
475 const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform, const SkPaint& paint,
476         float width, float height, float rx, float ry) {
477     return getRoundRectBuffer(transform, paint, width, height, rx, ry)->getVertexBuffer();
478 }
479
480 }; // namespace uirenderer
481 }; // namespace android