OSDN Git Service

docs: Fixed option for \"launchMode\" within Android manifest doc.
[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(Type::None)
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     // Shape bits should be set to zeroes, because they are used for hash calculation.
46     memset(&shape, 0, sizeof(Shape));
47 }
48
49 TessellationCache::Description::Description(Type type, const Matrix4& transform, const SkPaint& paint)
50         : type(type)
51         , aa(paint.isAntiAlias())
52         , cap(paint.getStrokeCap())
53         , style(paint.getStyle())
54         , strokeWidth(paint.getStrokeWidth()) {
55     PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY);
56     // Shape bits should be set to zeroes, because they are used for hash calculation.
57     memset(&shape, 0, sizeof(Shape));
58 }
59
60 bool TessellationCache::Description::operator==(const TessellationCache::Description& rhs) const {
61     if (type != rhs.type) return false;
62     if (scaleX != rhs.scaleX) return false;
63     if (scaleY != rhs.scaleY) return false;
64     if (aa != rhs.aa) return false;
65     if (cap != rhs.cap) return false;
66     if (style != rhs.style) return false;
67     if (strokeWidth != rhs.strokeWidth) return false;
68     if (type == Type::None) return true;
69     const Shape::RoundRect& lRect = shape.roundRect;
70     const Shape::RoundRect& rRect = rhs.shape.roundRect;
71
72     if (lRect.width != rRect.width) return false;
73     if (lRect.height != rRect.height) return false;
74     if (lRect.rx != rRect.rx) return false;
75     return lRect.ry == rRect.ry;
76 }
77
78 hash_t TessellationCache::Description::hash() const {
79     uint32_t hash = JenkinsHashMix(0, static_cast<int>(type));
80     hash = JenkinsHashMix(hash, aa);
81     hash = JenkinsHashMix(hash, cap);
82     hash = JenkinsHashMix(hash, style);
83     hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
84     hash = JenkinsHashMix(hash, android::hash_type(scaleX));
85     hash = JenkinsHashMix(hash, android::hash_type(scaleY));
86     hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
87     return JenkinsHashWhiten(hash);
88 }
89
90 void TessellationCache::Description::setupMatrixAndPaint(Matrix4* matrix, SkPaint* paint) const {
91     matrix->loadScale(scaleX, scaleY, 1.0f);
92     paint->setAntiAlias(aa);
93     paint->setStrokeCap(cap);
94     paint->setStyle(style);
95     paint->setStrokeWidth(strokeWidth);
96 }
97
98 TessellationCache::ShadowDescription::ShadowDescription()
99         : nodeKey(nullptr) {
100     memset(&matrixData, 0, sizeof(matrixData));
101 }
102
103 TessellationCache::ShadowDescription::ShadowDescription(const SkPath* nodeKey, const Matrix4* drawTransform)
104         : nodeKey(nodeKey) {
105     memcpy(&matrixData, drawTransform->data, sizeof(matrixData));
106 }
107
108 bool TessellationCache::ShadowDescription::operator==(
109         const TessellationCache::ShadowDescription& rhs) const {
110     return nodeKey == rhs.nodeKey
111             && memcmp(&matrixData, &rhs.matrixData, sizeof(matrixData)) == 0;
112 }
113
114 hash_t TessellationCache::ShadowDescription::hash() const {
115     uint32_t hash = JenkinsHashMixBytes(0, (uint8_t*) &nodeKey, sizeof(const void*));
116     hash = JenkinsHashMixBytes(hash, (uint8_t*) &matrixData, sizeof(matrixData));
117     return JenkinsHashWhiten(hash);
118 }
119
120 ///////////////////////////////////////////////////////////////////////////////
121 // General purpose tessellation task processing
122 ///////////////////////////////////////////////////////////////////////////////
123
124 class TessellationCache::TessellationTask : public Task<VertexBuffer*> {
125 public:
126     TessellationTask(Tessellator tessellator, const Description& description)
127         : tessellator(tessellator)
128         , description(description) {
129     }
130
131     ~TessellationTask() {}
132
133     Tessellator tessellator;
134     Description description;
135 };
136
137 class TessellationCache::TessellationProcessor : public TaskProcessor<VertexBuffer*> {
138 public:
139     TessellationProcessor(Caches& caches)
140             : TaskProcessor<VertexBuffer*>(&caches.tasks) {}
141     ~TessellationProcessor() {}
142
143     virtual void onProcess(const sp<Task<VertexBuffer*> >& task) override {
144         TessellationTask* t = static_cast<TessellationTask*>(task.get());
145         ATRACE_NAME("shape tessellation");
146         VertexBuffer* buffer = t->tessellator(t->description);
147         t->setResult(buffer);
148     }
149 };
150
151 class TessellationCache::Buffer {
152 public:
153     Buffer(const sp<Task<VertexBuffer*> >& task)
154             : mTask(task)
155             , mBuffer(nullptr) {
156     }
157
158     ~Buffer() {
159         mTask.clear();
160         delete mBuffer;
161     }
162
163     unsigned int getSize() {
164         blockOnPrecache();
165         return mBuffer->getSize();
166     }
167
168     const VertexBuffer* getVertexBuffer() {
169         blockOnPrecache();
170         return mBuffer;
171     }
172
173 private:
174     void blockOnPrecache() {
175         if (mTask != nullptr) {
176             mBuffer = mTask->getResult();
177             LOG_ALWAYS_FATAL_IF(mBuffer == nullptr, "Failed to precache");
178             mTask.clear();
179         }
180     }
181     sp<Task<VertexBuffer*> > mTask;
182     VertexBuffer* mBuffer;
183 };
184
185 ///////////////////////////////////////////////////////////////////////////////
186 // Shadow tessellation task processing
187 ///////////////////////////////////////////////////////////////////////////////
188
189 static void mapPointFakeZ(Vector3& point, const mat4* transformXY, const mat4* transformZ) {
190     // map z coordinate with true 3d matrix
191     point.z = transformZ->mapZ(point);
192
193     // map x,y coordinates with draw/Skia matrix
194     transformXY->mapPoint(point.x, point.y);
195 }
196
197 static void reverseVertexArray(Vertex* polygon, int len) {
198     int n = len / 2;
199     for (int i = 0; i < n; i++) {
200         Vertex tmp = polygon[i];
201         int k = len - 1 - i;
202         polygon[i] = polygon[k];
203         polygon[k] = tmp;
204     }
205 }
206
207 void tessellateShadows(
208         const Matrix4* drawTransform, const Rect* localClip,
209         bool isCasterOpaque, const SkPath* casterPerimeter,
210         const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
211         const Vector3& lightCenter, float lightRadius,
212         VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) {
213
214     // tessellate caster outline into a 2d polygon
215     std::vector<Vertex> casterVertices2d;
216     const float casterRefinementThreshold = 2.0f;
217     PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
218             casterRefinementThreshold, casterVertices2d);
219
220     // Shadow requires CCW for now. TODO: remove potential double-reverse
221     reverseVertexArray(&casterVertices2d.front(), casterVertices2d.size());
222
223     if (casterVertices2d.size() == 0) return;
224
225     // map 2d caster poly into 3d
226     const int casterVertexCount = casterVertices2d.size();
227     Vector3 casterPolygon[casterVertexCount];
228     float minZ = FLT_MAX;
229     float maxZ = -FLT_MAX;
230     for (int i = 0; i < casterVertexCount; i++) {
231         const Vertex& point2d = casterVertices2d[i];
232         casterPolygon[i] = (Vector3){point2d.x, point2d.y, 0};
233         mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ);
234         minZ = std::min(minZ, casterPolygon[i].z);
235         maxZ = std::max(maxZ, casterPolygon[i].z);
236     }
237
238     // map the centroid of the caster into 3d
239     Vector2 centroid =  ShadowTessellator::centroid2d(
240             reinterpret_cast<const Vector2*>(&casterVertices2d.front()),
241             casterVertexCount);
242     Vector3 centroid3d = {centroid.x, centroid.y, 0};
243     mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ);
244
245     // if the caster intersects the z=0 plane, lift it in Z so it doesn't
246     if (minZ < SHADOW_MIN_CASTER_Z) {
247         float casterLift = SHADOW_MIN_CASTER_Z - minZ;
248         for (int i = 0; i < casterVertexCount; i++) {
249             casterPolygon[i].z += casterLift;
250         }
251         centroid3d.z += casterLift;
252     }
253
254     // Check whether we want to draw the shadow at all by checking the caster's bounds against clip.
255     // We only have ortho projection, so we can just ignore the Z in caster for
256     // simple rejection calculation.
257     Rect casterBounds(casterPerimeter->getBounds());
258     casterTransformXY->mapRect(casterBounds);
259
260     // actual tessellation of both shadows
261     ShadowTessellator::tessellateAmbientShadow(
262             isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
263             casterBounds, *localClip, maxZ, ambientBuffer);
264
265     ShadowTessellator::tessellateSpotShadow(
266             isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
267             *drawTransform, lightCenter, lightRadius, casterBounds, *localClip,
268             spotBuffer);
269 }
270
271 class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t> {
272 public:
273     ShadowProcessor(Caches& caches)
274             : TaskProcessor<TessellationCache::vertexBuffer_pair_t>(&caches.tasks) {}
275     ~ShadowProcessor() {}
276
277     virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t> >& task) override {
278         TessellationCache::ShadowTask* t = static_cast<TessellationCache::ShadowTask*>(task.get());
279         ATRACE_NAME("shadow tessellation");
280
281         tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter,
282                 &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
283                 t->ambientBuffer, t->spotBuffer);
284
285         t->setResult(TessellationCache::vertexBuffer_pair_t(&t->ambientBuffer, &t->spotBuffer));
286     }
287 };
288
289 ///////////////////////////////////////////////////////////////////////////////
290 // Cache constructor/destructor
291 ///////////////////////////////////////////////////////////////////////////////
292
293 TessellationCache::TessellationCache()
294         : mMaxSize(Properties::tessellationCacheSize)
295         , mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity)
296         , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
297     mCache.setOnEntryRemovedListener(&mBufferRemovedListener);
298     mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener);
299     mDebugEnabled = Properties::debugLevel & kDebugCaches;
300 }
301
302 TessellationCache::~TessellationCache() {
303     mCache.clear();
304 }
305
306 ///////////////////////////////////////////////////////////////////////////////
307 // Size management
308 ///////////////////////////////////////////////////////////////////////////////
309
310 uint32_t TessellationCache::getSize() {
311     LruCache<Description, Buffer*>::Iterator iter(mCache);
312     uint32_t size = 0;
313     while (iter.next()) {
314         size += iter.value()->getSize();
315     }
316     return size;
317 }
318
319 uint32_t TessellationCache::getMaxSize() {
320     return mMaxSize;
321 }
322
323 ///////////////////////////////////////////////////////////////////////////////
324 // Caching
325 ///////////////////////////////////////////////////////////////////////////////
326
327
328 void TessellationCache::trim() {
329     uint32_t size = getSize();
330     while (size > mMaxSize) {
331         size -= mCache.peekOldestValue()->getSize();
332         mCache.removeOldest();
333     }
334     mShadowCache.clear();
335 }
336
337 void TessellationCache::clear() {
338     mCache.clear();
339     mShadowCache.clear();
340 }
341
342 ///////////////////////////////////////////////////////////////////////////////
343 // Callbacks
344 ///////////////////////////////////////////////////////////////////////////////
345
346 void TessellationCache::BufferRemovedListener::operator()(Description& description,
347         Buffer*& buffer) {
348     delete buffer;
349 }
350
351 ///////////////////////////////////////////////////////////////////////////////
352 // Shadows
353 ///////////////////////////////////////////////////////////////////////////////
354
355 void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
356         bool opaque, const SkPath* casterPerimeter,
357         const Matrix4* transformXY, const Matrix4* transformZ,
358         const Vector3& lightCenter, float lightRadius) {
359     ShadowDescription key(casterPerimeter, drawTransform);
360
361     if (mShadowCache.get(key)) return;
362     sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
363             casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
364     if (mShadowProcessor == nullptr) {
365         mShadowProcessor = new ShadowProcessor(Caches::getInstance());
366     }
367     mShadowProcessor->add(task);
368     task->incStrong(nullptr); // not using sp<>s, so manually ref while in the cache
369     mShadowCache.put(key, task.get());
370 }
371
372 void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip,
373         bool opaque, const SkPath* casterPerimeter,
374         const Matrix4* transformXY, const Matrix4* transformZ,
375         const Vector3& lightCenter, float lightRadius, vertexBuffer_pair_t& outBuffers) {
376     ShadowDescription key(casterPerimeter, drawTransform);
377     ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key));
378     if (!task) {
379         precacheShadows(drawTransform, localClip, opaque, casterPerimeter,
380                 transformXY, transformZ, lightCenter, lightRadius);
381         task = static_cast<ShadowTask*>(mShadowCache.get(key));
382     }
383     LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached");
384     outBuffers = task->getResult();
385 }
386
387 sp<TessellationCache::ShadowTask> TessellationCache::getShadowTask(
388         const Matrix4* drawTransform, const Rect& localClip,
389         bool opaque, const SkPath* casterPerimeter,
390         const Matrix4* transformXY, const Matrix4* transformZ,
391         const Vector3& lightCenter, float lightRadius) {
392     ShadowDescription key(casterPerimeter, drawTransform);
393     ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key));
394     if (!task) {
395         precacheShadows(drawTransform, localClip, opaque, casterPerimeter,
396                 transformXY, transformZ, lightCenter, lightRadius);
397         task = static_cast<ShadowTask*>(mShadowCache.get(key));
398     }
399     LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached");
400     return task;
401 }
402
403 ///////////////////////////////////////////////////////////////////////////////
404 // Tessellation precaching
405 ///////////////////////////////////////////////////////////////////////////////
406
407 TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(
408         const Description& entry, Tessellator tessellator) {
409     Buffer* buffer = mCache.get(entry);
410     if (!buffer) {
411         // not cached, enqueue a task to fill the buffer
412         sp<TessellationTask> task = new TessellationTask(tessellator, entry);
413         buffer = new Buffer(task);
414
415         if (mProcessor == nullptr) {
416             mProcessor = new TessellationProcessor(Caches::getInstance());
417         }
418         mProcessor->add(task);
419         mCache.put(entry, buffer);
420     }
421     return buffer;
422 }
423
424 static VertexBuffer* tessellatePath(const TessellationCache::Description& description,
425         const SkPath& path) {
426     Matrix4 matrix;
427     SkPaint paint;
428     description.setupMatrixAndPaint(&matrix, &paint);
429     VertexBuffer* buffer = new VertexBuffer();
430     PathTessellator::tessellatePath(path, &paint, matrix, *buffer);
431     return buffer;
432 }
433
434 ///////////////////////////////////////////////////////////////////////////////
435 // RoundRect
436 ///////////////////////////////////////////////////////////////////////////////
437
438 static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description) {
439     SkRect rect = SkRect::MakeWH(description.shape.roundRect.width,
440             description.shape.roundRect.height);
441     float rx = description.shape.roundRect.rx;
442     float ry = description.shape.roundRect.ry;
443     if (description.style == SkPaint::kStrokeAndFill_Style) {
444         float outset = description.strokeWidth / 2;
445         rect.outset(outset, outset);
446         rx += outset;
447         ry += outset;
448     }
449     SkPath path;
450     path.addRoundRect(rect, rx, ry);
451     return tessellatePath(description, path);
452 }
453
454 TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(
455         const Matrix4& transform, const SkPaint& paint,
456         float width, float height, float rx, float ry) {
457     Description entry(Description::Type::RoundRect, transform, paint);
458     entry.shape.roundRect.width = width;
459     entry.shape.roundRect.height = height;
460     entry.shape.roundRect.rx = rx;
461     entry.shape.roundRect.ry = ry;
462     return getOrCreateBuffer(entry, &tessellateRoundRect);
463 }
464 const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform, const SkPaint& paint,
465         float width, float height, float rx, float ry) {
466     return getRoundRectBuffer(transform, paint, width, height, rx, ry)->getVertexBuffer();
467 }
468
469 }; // namespace uirenderer
470 }; // namespace android