blob: ef3d0d765ba255210bd15c17a59d7517ed666d32 [file] [log] [blame]
Chris Craik05f3d6e2014-06-02 16:27:04 -07001/*
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#define LOG_TAG "OpenGLRenderer"
18#define ATRACE_TAG ATRACE_TAG_VIEW
19
20#include <utils/JenkinsHash.h>
21#include <utils/Trace.h>
22
23#include "Caches.h"
24#include "OpenGLRenderer.h"
25#include "PathTessellator.h"
26#include "ShadowTessellator.h"
27#include "TessellationCache.h"
28
29#include "thread/Signal.h"
30#include "thread/Task.h"
31#include "thread/TaskProcessor.h"
32
33namespace android {
34namespace uirenderer {
35
36///////////////////////////////////////////////////////////////////////////////
37// Cache entries
38///////////////////////////////////////////////////////////////////////////////
39
40TessellationCache::Description::Description()
41 : type(kNone)
Chris Craiked4ef0b2014-06-12 13:27:30 -070042 , aa(false)
Chris Craik05f3d6e2014-06-02 16:27:04 -070043 , cap(SkPaint::kDefault_Cap)
44 , style(SkPaint::kFill_Style)
45 , strokeWidth(1.0f) {
46 memset(&shape, 0, sizeof(Shape));
47}
48
49TessellationCache::Description::Description(Type type)
50 : type(type)
Chris Craiked4ef0b2014-06-12 13:27:30 -070051 , aa(false)
Chris Craik05f3d6e2014-06-02 16:27:04 -070052 , cap(SkPaint::kDefault_Cap)
53 , style(SkPaint::kFill_Style)
54 , strokeWidth(1.0f) {
55 memset(&shape, 0, sizeof(Shape));
56}
57
58TessellationCache::Description::Description(Type type, const SkPaint* paint)
59 : type(type)
Chris Craiked4ef0b2014-06-12 13:27:30 -070060 , aa(paint->isAntiAlias())
Chris Craik05f3d6e2014-06-02 16:27:04 -070061 , cap(paint->getStrokeCap())
62 , style(paint->getStyle())
63 , strokeWidth(paint->getStrokeWidth()) {
64 memset(&shape, 0, sizeof(Shape));
65}
66
67hash_t TessellationCache::Description::hash() const {
68 uint32_t hash = JenkinsHashMix(0, type);
Chris Craiked4ef0b2014-06-12 13:27:30 -070069 hash = JenkinsHashMix(hash, aa);
Chris Craik05f3d6e2014-06-02 16:27:04 -070070 hash = JenkinsHashMix(hash, cap);
71 hash = JenkinsHashMix(hash, style);
72 hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
73 hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
74 return JenkinsHashWhiten(hash);
75}
76
77TessellationCache::ShadowDescription::ShadowDescription()
78 : nodeKey(NULL) {
79 memset(&matrixData, 0, 16 * sizeof(float));
80}
81
82TessellationCache::ShadowDescription::ShadowDescription(const void* nodeKey, const Matrix4* drawTransform)
83 : nodeKey(nodeKey) {
84 memcpy(&matrixData, drawTransform->data, 16 * sizeof(float));
85}
86
87hash_t TessellationCache::ShadowDescription::hash() const {
88 uint32_t hash = JenkinsHashMixBytes(0, (uint8_t*) &nodeKey, sizeof(const void*));
89 hash = JenkinsHashMixBytes(hash, (uint8_t*) &matrixData, 16 * sizeof(float));
90 return JenkinsHashWhiten(hash);
91}
92
93///////////////////////////////////////////////////////////////////////////////
94// General purpose tessellation task processing
95///////////////////////////////////////////////////////////////////////////////
96
97class TessellationCache::TessellationTask : public Task<VertexBuffer*> {
98public:
99 TessellationTask(Tessellator tessellator, const Description& description,
100 const SkPaint* paint)
101 : tessellator(tessellator)
102 , description(description)
103 , paint(*paint) {
104 }
105
106 ~TessellationTask() {}
107
108 Tessellator tessellator;
109 Description description;
110
111 //copied, since input paint may not be immutable
112 const SkPaint paint;
113};
114
115class TessellationCache::TessellationProcessor : public TaskProcessor<VertexBuffer*> {
116public:
117 TessellationProcessor(Caches& caches)
118 : TaskProcessor<VertexBuffer*>(&caches.tasks) {}
119 ~TessellationProcessor() {}
120
121 virtual void onProcess(const sp<Task<VertexBuffer*> >& task) {
122 TessellationTask* t = static_cast<TessellationTask*>(task.get());
123 ATRACE_NAME("shape tessellation");
124 VertexBuffer* buffer = t->tessellator(t->description, t->paint);
125 t->setResult(buffer);
126 }
127};
128
129struct TessellationCache::Buffer {
130public:
131 Buffer(const sp<Task<VertexBuffer*> >& task)
132 : mTask(task)
133 , mBuffer(NULL) {
134 }
135
136 ~Buffer() {
137 mTask.clear();
138 delete mBuffer;
139 }
140
141 unsigned int getSize() {
142 blockOnPrecache();
143 return mBuffer->getSize();
144 }
145
146 const VertexBuffer* getVertexBuffer() {
147 blockOnPrecache();
148 return mBuffer;
149 }
150
151private:
152 void blockOnPrecache() {
153 if (mTask != NULL) {
154 mBuffer = mTask->getResult();
155 LOG_ALWAYS_FATAL_IF(mBuffer == NULL, "Failed to precache");
156 mTask.clear();
157 }
158 }
159 sp<Task<VertexBuffer*> > mTask;
160 VertexBuffer* mBuffer;
161};
162
163///////////////////////////////////////////////////////////////////////////////
164// Shadow tessellation task processing
165///////////////////////////////////////////////////////////////////////////////
166
167class ShadowTask : public Task<TessellationCache::vertexBuffer_pair_t*> {
168public:
169 ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
170 const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
171 const Vector3& lightCenter, float lightRadius)
Chris Craik1b3be082014-06-11 13:44:19 -0700172 : drawTransform(*drawTransform)
Chris Craik05f3d6e2014-06-02 16:27:04 -0700173 , localClip(localClip)
174 , opaque(opaque)
Chris Craik1b3be082014-06-11 13:44:19 -0700175 , casterPerimeter(*casterPerimeter)
176 , transformXY(*transformXY)
177 , transformZ(*transformZ)
Chris Craik05f3d6e2014-06-02 16:27:04 -0700178 , lightCenter(lightCenter)
179 , lightRadius(lightRadius) {
180 }
181
182 ~ShadowTask() {
183 TessellationCache::vertexBuffer_pair_t* bufferPair = getResult();
184 delete bufferPair->getFirst();
185 delete bufferPair->getSecond();
186 delete bufferPair;
187 }
188
Chris Craik1b3be082014-06-11 13:44:19 -0700189 /* Note - we deep copy all task parameters, because *even though* pointers into Allocator
190 * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
191 * certain Allocators are destroyed before trim() is called to flush incomplete tasks.
192 *
193 * These deep copies could be avoided, long term, by cancelling or flushing outstanding tasks
194 * before tearning down single-frame LinearAllocators.
195 */
196 const Matrix4 drawTransform;
Chris Craik05f3d6e2014-06-02 16:27:04 -0700197 const Rect localClip;
198 bool opaque;
Chris Craik1b3be082014-06-11 13:44:19 -0700199 const SkPath casterPerimeter;
200 const Matrix4 transformXY;
201 const Matrix4 transformZ;
Chris Craik05f3d6e2014-06-02 16:27:04 -0700202 const Vector3 lightCenter;
203 const float lightRadius;
204};
205
206static void mapPointFakeZ(Vector3& point, const mat4* transformXY, const mat4* transformZ) {
207 // map z coordinate with true 3d matrix
208 point.z = transformZ->mapZ(point);
209
210 // map x,y coordinates with draw/Skia matrix
211 transformXY->mapPoint(point.x, point.y);
212}
213
214static void tessellateShadows(
215 const Matrix4* drawTransform, const Rect* localClip,
216 bool isCasterOpaque, const SkPath* casterPerimeter,
217 const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
218 const Vector3& lightCenter, float lightRadius,
219 VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) {
220
221 // tessellate caster outline into a 2d polygon
222 Vector<Vertex> casterVertices2d;
223 const float casterRefinementThresholdSquared = 20.0f; // TODO: experiment with this value
224 PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
225 casterRefinementThresholdSquared, casterVertices2d);
226 if (!ShadowTessellator::isClockwisePath(*casterPerimeter)) {
227 ShadowTessellator::reverseVertexArray(casterVertices2d.editArray(),
228 casterVertices2d.size());
229 }
230
231 if (casterVertices2d.size() == 0) return;
232
233 // map 2d caster poly into 3d
234 const int casterVertexCount = casterVertices2d.size();
235 Vector3 casterPolygon[casterVertexCount];
236 float minZ = FLT_MAX;
237 float maxZ = -FLT_MAX;
238 for (int i = 0; i < casterVertexCount; i++) {
239 const Vertex& point2d = casterVertices2d[i];
240 casterPolygon[i] = Vector3(point2d.x, point2d.y, 0);
241 mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ);
242 minZ = fmin(minZ, casterPolygon[i].z);
243 maxZ = fmax(maxZ, casterPolygon[i].z);
244 }
245
246 // map the centroid of the caster into 3d
247 Vector2 centroid = ShadowTessellator::centroid2d(
248 reinterpret_cast<const Vector2*>(casterVertices2d.array()),
249 casterVertexCount);
250 Vector3 centroid3d(centroid.x, centroid.y, 0);
251 mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ);
252
253 // if the caster intersects the z=0 plane, lift it in Z so it doesn't
254 if (minZ < SHADOW_MIN_CASTER_Z) {
255 float casterLift = SHADOW_MIN_CASTER_Z - minZ;
256 for (int i = 0; i < casterVertexCount; i++) {
257 casterPolygon[i].z += casterLift;
258 }
259 centroid3d.z += casterLift;
260 }
261
262 // Check whether we want to draw the shadow at all by checking the caster's bounds against clip.
263 // We only have ortho projection, so we can just ignore the Z in caster for
264 // simple rejection calculation.
265 Rect casterBounds(casterPerimeter->getBounds());
266 casterTransformXY->mapRect(casterBounds);
267
268 // actual tessellation of both shadows
269 ShadowTessellator::tessellateAmbientShadow(
270 isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
271 casterBounds, *localClip, maxZ, ambientBuffer);
272
273 ShadowTessellator::tessellateSpotShadow(
274 isCasterOpaque, casterPolygon, casterVertexCount,
275 *drawTransform, lightCenter, lightRadius, casterBounds, *localClip,
276 spotBuffer);
277
278 // TODO: set ambientBuffer & spotBuffer's bounds for correct layer damage
279}
280
281class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t*> {
282public:
283 ShadowProcessor(Caches& caches)
284 : TaskProcessor<TessellationCache::vertexBuffer_pair_t*>(&caches.tasks) {}
285 ~ShadowProcessor() {}
286
287 virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) {
288 ShadowTask* t = static_cast<ShadowTask*>(task.get());
289 ATRACE_NAME("shadow tessellation");
290
291 VertexBuffer* ambientBuffer = new VertexBuffer;
292 VertexBuffer* spotBuffer = new VertexBuffer;
Chris Craik1b3be082014-06-11 13:44:19 -0700293 tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter,
294 &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
Chris Craik05f3d6e2014-06-02 16:27:04 -0700295 *ambientBuffer, *spotBuffer);
296
297 t->setResult(new TessellationCache::vertexBuffer_pair_t(ambientBuffer, spotBuffer));
298 }
299};
300
301///////////////////////////////////////////////////////////////////////////////
302// Cache constructor/destructor
303///////////////////////////////////////////////////////////////////////////////
304
305TessellationCache::TessellationCache()
306 : mSize(0)
307 , mMaxSize(MB(DEFAULT_VERTEX_CACHE_SIZE))
308 , mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity)
309 , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
310 char property[PROPERTY_VALUE_MAX];
311 if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, NULL) > 0) {
312 INIT_LOGD(" Setting %s cache size to %sMB", name, property);
313 setMaxSize(MB(atof(property)));
314 } else {
315 INIT_LOGD(" Using default %s cache size of %.2fMB", name, DEFAULT_VERTEX_CACHE_SIZE);
316 }
317
318 mCache.setOnEntryRemovedListener(&mBufferRemovedListener);
319 mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener);
320 mDebugEnabled = readDebugLevel() & kDebugCaches;
321}
322
323TessellationCache::~TessellationCache() {
324 mCache.clear();
325}
326
327///////////////////////////////////////////////////////////////////////////////
328// Size management
329///////////////////////////////////////////////////////////////////////////////
330
331uint32_t TessellationCache::getSize() {
332 LruCache<Description, Buffer*>::Iterator iter(mCache);
333 uint32_t size = 0;
334 while (iter.next()) {
335 size += iter.value()->getSize();
336 }
337 return size;
338}
339
340uint32_t TessellationCache::getMaxSize() {
341 return mMaxSize;
342}
343
344void TessellationCache::setMaxSize(uint32_t maxSize) {
345 mMaxSize = maxSize;
346 while (mSize > mMaxSize) {
347 mCache.removeOldest();
348 }
349}
350
351///////////////////////////////////////////////////////////////////////////////
352// Caching
353///////////////////////////////////////////////////////////////////////////////
354
355
356void TessellationCache::trim() {
357 uint32_t size = getSize();
358 while (size > mMaxSize) {
359 size -= mCache.peekOldestValue()->getSize();
360 mCache.removeOldest();
361 }
362 mShadowCache.clear();
363}
364
365void TessellationCache::clear() {
366 mCache.clear();
367 mShadowCache.clear();
368}
369
370///////////////////////////////////////////////////////////////////////////////
371// Callbacks
372///////////////////////////////////////////////////////////////////////////////
373
374void TessellationCache::BufferRemovedListener::operator()(Description& description,
375 Buffer*& buffer) {
376 delete buffer;
377}
378
379///////////////////////////////////////////////////////////////////////////////
380// Shadows
381///////////////////////////////////////////////////////////////////////////////
382
383void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
384 bool opaque, const SkPath* casterPerimeter,
385 const Matrix4* transformXY, const Matrix4* transformZ,
386 const Vector3& lightCenter, float lightRadius) {
387 ShadowDescription key(casterPerimeter, drawTransform);
388
389 sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
390 casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
391 if (mShadowProcessor == NULL) {
392 mShadowProcessor = new ShadowProcessor(Caches::getInstance());
393 }
394 mShadowProcessor->add(task);
395
396 task->incStrong(NULL); // not using sp<>s, so manually ref while in the cache
397 mShadowCache.put(key, task.get());
398}
399
400void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip,
401 bool opaque, const SkPath* casterPerimeter,
402 const Matrix4* transformXY, const Matrix4* transformZ,
403 const Vector3& lightCenter, float lightRadius, vertexBuffer_pair_t& outBuffers) {
404 ShadowDescription key(casterPerimeter, drawTransform);
405 ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key));
406 if (!task) {
407 precacheShadows(drawTransform, localClip, opaque, casterPerimeter,
408 transformXY, transformZ, lightCenter, lightRadius);
409 task = static_cast<ShadowTask*>(mShadowCache.get(key));
410 }
411 LOG_ALWAYS_FATAL_IF(task == NULL, "shadow not precached");
412 outBuffers = *(task->getResult());
413}
414
415///////////////////////////////////////////////////////////////////////////////
416// Tessellation precaching
417///////////////////////////////////////////////////////////////////////////////
418
419static VertexBuffer* tessellatePath(const SkPath& path, const SkPaint* paint,
420 float scaleX, float scaleY) {
421 VertexBuffer* buffer = new VertexBuffer();
422 Matrix4 matrix;
423 matrix.loadScale(scaleX, scaleY, 1);
424 PathTessellator::tessellatePath(path, paint, matrix, *buffer);
425 return buffer;
426}
427
428TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(
429 const Description& entry, Tessellator tessellator, const SkPaint* paint) {
430 Buffer* buffer = mCache.get(entry);
431 if (!buffer) {
432 // not cached, enqueue a task to fill the buffer
433 sp<TessellationTask> task = new TessellationTask(tessellator, entry, paint);
434 buffer = new Buffer(task);
435
436 if (mProcessor == NULL) {
437 mProcessor = new TessellationProcessor(Caches::getInstance());
438 }
439 mProcessor->add(task);
440 mCache.put(entry, buffer);
441 }
442 return buffer;
443}
444
445///////////////////////////////////////////////////////////////////////////////
446// Rounded rects
447///////////////////////////////////////////////////////////////////////////////
448
449static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description,
450 const SkPaint& paint) {
451 SkRect rect = SkRect::MakeWH(description.shape.roundRect.mWidth,
452 description.shape.roundRect.mHeight);
453 float rx = description.shape.roundRect.mRx;
454 float ry = description.shape.roundRect.mRy;
455 if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
456 float outset = paint.getStrokeWidth() / 2;
457 rect.outset(outset, outset);
458 rx += outset;
459 ry += outset;
460 }
461 SkPath path;
462 path.addRoundRect(rect, rx, ry);
463 return tessellatePath(path, &paint,
464 description.shape.roundRect.mScaleX, description.shape.roundRect.mScaleY);
465}
466
467TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(const Matrix4& transform,
468 float width, float height, float rx, float ry, const SkPaint* paint) {
469 Description entry(Description::kRoundRect, paint);
470 entry.shape.roundRect.mWidth = width;
471 entry.shape.roundRect.mHeight = height;
472 entry.shape.roundRect.mRx = rx;
473 entry.shape.roundRect.mRy = ry;
474 PathTessellator::extractTessellationScales(transform,
475 &entry.shape.roundRect.mScaleX, &entry.shape.roundRect.mScaleY);
476
477 return getOrCreateBuffer(entry, &tessellateRoundRect, paint);
478}
479const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform,
480 float width, float height, float rx, float ry, const SkPaint* paint) {
481 return getRoundRectBuffer(transform, width, height, rx, ry, paint)->getVertexBuffer();
482}
483
484}; // namespace uirenderer
485}; // namespace android