1/*
2 * Copyright (C) 2010 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
19#include <SkCamera.h>
20#include <SkCanvas.h>
21
22#include <private/hwui/DrawGlInfo.h>
23
24#include "ResourceCache.h"
25#include "DeferredDisplayList.h"
26#include "DeferredLayerUpdater.h"
27#include "DisplayListLogBuffer.h"
28#include "DisplayListOp.h"
29#include "DisplayListRenderer.h"
30#include "RenderNode.h"
31
32namespace android {
33namespace uirenderer {
34
35DisplayListRenderer::DisplayListRenderer()
36    : mResourceCache(ResourceCache::getInstance())
37    , mDisplayListData(NULL)
38    , mTranslateX(0.0f)
39    , mTranslateY(0.0f)
40    , mDeferredBarrierType(kBarrier_None)
41    , mHighContrastText(false)
42    , mRestoreSaveCount(-1) {
43}
44
45DisplayListRenderer::~DisplayListRenderer() {
46    LOG_ALWAYS_FATAL_IF(mDisplayListData,
47            "Destroyed a DisplayListRenderer during a record!");
48}
49
50///////////////////////////////////////////////////////////////////////////////
51// Operations
52///////////////////////////////////////////////////////////////////////////////
53
54DisplayListData* DisplayListRenderer::finishRecording() {
55    mPaintMap.clear();
56    mRegionMap.clear();
57    mPathMap.clear();
58    DisplayListData* data = mDisplayListData;
59    mDisplayListData = 0;
60    return data;
61}
62
63status_t DisplayListRenderer::prepareDirty(float left, float top,
64        float right, float bottom, bool opaque) {
65
66    LOG_ALWAYS_FATAL_IF(mDisplayListData,
67            "prepareDirty called a second time during a recording!");
68    mDisplayListData = new DisplayListData();
69
70    initializeSaveStack(0, 0, getWidth(), getHeight(), Vector3());
71
72    mDeferredBarrierType = kBarrier_InOrder;
73    mDirtyClip = opaque;
74    mRestoreSaveCount = -1;
75
76    return DrawGlInfo::kStatusDone; // No invalidate needed at record-time
77}
78
79void DisplayListRenderer::finish() {
80    flushRestoreToCount();
81    flushTranslate();
82}
83
84void DisplayListRenderer::interrupt() {
85}
86
87void DisplayListRenderer::resume() {
88}
89
90status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
91    // Ignore dirty during recording, it matters only when we replay
92    addDrawOp(new (alloc()) DrawFunctorOp(functor));
93    mDisplayListData->functors.add(functor);
94    return DrawGlInfo::kStatusDone; // No invalidate needed at record-time
95}
96
97int DisplayListRenderer::save(int flags) {
98    addStateOp(new (alloc()) SaveOp(flags));
99    return StatefulBaseRenderer::save(flags);
100}
101
102void DisplayListRenderer::restore() {
103    if (mRestoreSaveCount < 0) {
104        restoreToCount(getSaveCount() - 1);
105        return;
106    }
107
108    mRestoreSaveCount--;
109    flushTranslate();
110    StatefulBaseRenderer::restore();
111}
112
113void DisplayListRenderer::restoreToCount(int saveCount) {
114    mRestoreSaveCount = saveCount;
115    flushTranslate();
116    StatefulBaseRenderer::restoreToCount(saveCount);
117}
118
119int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
120        const SkPaint* paint, int flags) {
121    // force matrix/clip isolation for layer
122    flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
123
124    paint = refPaint(paint);
125    addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, flags));
126    return StatefulBaseRenderer::save(flags);
127}
128
129void DisplayListRenderer::translate(float dx, float dy, float dz) {
130    // ignore dz, not used at defer time
131    mHasDeferredTranslate = true;
132    mTranslateX += dx;
133    mTranslateY += dy;
134    flushRestoreToCount();
135    StatefulBaseRenderer::translate(dx, dy, dz);
136}
137
138void DisplayListRenderer::rotate(float degrees) {
139    addStateOp(new (alloc()) RotateOp(degrees));
140    StatefulBaseRenderer::rotate(degrees);
141}
142
143void DisplayListRenderer::scale(float sx, float sy) {
144    addStateOp(new (alloc()) ScaleOp(sx, sy));
145    StatefulBaseRenderer::scale(sx, sy);
146}
147
148void DisplayListRenderer::skew(float sx, float sy) {
149    addStateOp(new (alloc()) SkewOp(sx, sy));
150    StatefulBaseRenderer::skew(sx, sy);
151}
152
153void DisplayListRenderer::setMatrix(const SkMatrix& matrix) {
154    addStateOp(new (alloc()) SetMatrixOp(matrix));
155    StatefulBaseRenderer::setMatrix(matrix);
156}
157
158void DisplayListRenderer::concatMatrix(const SkMatrix& matrix) {
159    addStateOp(new (alloc()) ConcatMatrixOp(matrix));
160    StatefulBaseRenderer::concatMatrix(matrix);
161}
162
163bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom,
164        SkRegion::Op op) {
165    addStateOp(new (alloc()) ClipRectOp(left, top, right, bottom, op));
166    return StatefulBaseRenderer::clipRect(left, top, right, bottom, op);
167}
168
169bool DisplayListRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
170    path = refPath(path);
171    addStateOp(new (alloc()) ClipPathOp(path, op));
172    return StatefulBaseRenderer::clipPath(path, op);
173}
174
175bool DisplayListRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
176    region = refRegion(region);
177    addStateOp(new (alloc()) ClipRegionOp(region, op));
178    return StatefulBaseRenderer::clipRegion(region, op);
179}
180
181status_t DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) {
182    LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode");
183
184    // dirty is an out parameter and should not be recorded,
185    // it matters only when replaying the display list
186    DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *currentTransform());
187    addRenderNodeOp(op);
188
189    return DrawGlInfo::kStatusDone;
190}
191
192status_t DisplayListRenderer::drawLayer(DeferredLayerUpdater* layerHandle, float x, float y) {
193    // We ref the DeferredLayerUpdater due to its thread-safe ref-counting
194    // semantics.
195    mDisplayListData->ref(layerHandle);
196    addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer(), x, y));
197    return DrawGlInfo::kStatusDone;
198}
199
200status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
201    bitmap = refBitmap(bitmap);
202    paint = refPaint(paint);
203
204    addDrawOp(new (alloc()) DrawBitmapOp(bitmap, paint));
205    return DrawGlInfo::kStatusDone;
206}
207
208status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
209        float srcRight, float srcBottom, float dstLeft, float dstTop,
210        float dstRight, float dstBottom, const SkPaint* paint) {
211    if (srcLeft == 0 && srcTop == 0
212            && srcRight == bitmap->width() && srcBottom == bitmap->height()
213            && (srcBottom - srcTop == dstBottom - dstTop)
214            && (srcRight - srcLeft == dstRight - dstLeft)) {
215        // transform simple rect to rect drawing case into position bitmap ops, since they merge
216        save(SkCanvas::kMatrix_SaveFlag);
217        translate(dstLeft, dstTop);
218        drawBitmap(bitmap, paint);
219        restore();
220    } else {
221        bitmap = refBitmap(bitmap);
222        paint = refPaint(paint);
223
224        addDrawOp(new (alloc()) DrawBitmapRectOp(bitmap,
225                srcLeft, srcTop, srcRight, srcBottom,
226                dstLeft, dstTop, dstRight, dstBottom, paint));
227    }
228    return DrawGlInfo::kStatusDone;
229}
230
231status_t DisplayListRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) {
232    bitmap = refBitmapData(bitmap);
233    paint = refPaint(paint);
234
235    addDrawOp(new (alloc()) DrawBitmapDataOp(bitmap, paint));
236    return DrawGlInfo::kStatusDone;
237}
238
239status_t DisplayListRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
240        const float* vertices, const int* colors, const SkPaint* paint) {
241    int vertexCount = (meshWidth + 1) * (meshHeight + 1);
242    bitmap = refBitmap(bitmap);
243    vertices = refBuffer<float>(vertices, vertexCount * 2); // 2 floats per vertex
244    paint = refPaint(paint);
245    colors = refBuffer<int>(colors, vertexCount); // 1 color per vertex
246
247    addDrawOp(new (alloc()) DrawBitmapMeshOp(bitmap, meshWidth, meshHeight,
248                    vertices, colors, paint));
249    return DrawGlInfo::kStatusDone;
250}
251
252status_t DisplayListRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
253        float left, float top, float right, float bottom, const SkPaint* paint) {
254    bitmap = refBitmap(bitmap);
255    patch = refPatch(patch);
256    paint = refPaint(paint);
257
258    addDrawOp(new (alloc()) DrawPatchOp(bitmap, patch, left, top, right, bottom, paint));
259    return DrawGlInfo::kStatusDone;
260}
261
262status_t DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
263    addDrawOp(new (alloc()) DrawColorOp(color, mode));
264    return DrawGlInfo::kStatusDone;
265}
266
267status_t DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
268        const SkPaint* paint) {
269    paint = refPaint(paint);
270    addDrawOp(new (alloc()) DrawRectOp(left, top, right, bottom, paint));
271    return DrawGlInfo::kStatusDone;
272}
273
274status_t DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom,
275        float rx, float ry, const SkPaint* paint) {
276    paint = refPaint(paint);
277    addDrawOp(new (alloc()) DrawRoundRectOp(left, top, right, bottom, rx, ry, paint));
278    return DrawGlInfo::kStatusDone;
279}
280
281status_t DisplayListRenderer::drawRoundRect(
282        CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
283        CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
284        CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
285        CanvasPropertyPaint* paint) {
286    mDisplayListData->ref(left);
287    mDisplayListData->ref(top);
288    mDisplayListData->ref(right);
289    mDisplayListData->ref(bottom);
290    mDisplayListData->ref(rx);
291    mDisplayListData->ref(ry);
292    mDisplayListData->ref(paint);
293    addDrawOp(new (alloc()) DrawRoundRectPropsOp(&left->value, &top->value,
294            &right->value, &bottom->value, &rx->value, &ry->value, &paint->value));
295    return DrawGlInfo::kStatusDone;
296}
297
298status_t DisplayListRenderer::drawCircle(float x, float y, float radius, const SkPaint* paint) {
299    paint = refPaint(paint);
300    addDrawOp(new (alloc()) DrawCircleOp(x, y, radius, paint));
301    return DrawGlInfo::kStatusDone;
302}
303
304status_t DisplayListRenderer::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
305        CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
306    mDisplayListData->ref(x);
307    mDisplayListData->ref(y);
308    mDisplayListData->ref(radius);
309    mDisplayListData->ref(paint);
310    addDrawOp(new (alloc()) DrawCirclePropsOp(&x->value, &y->value,
311            &radius->value, &paint->value));
312    return DrawGlInfo::kStatusDone;
313}
314
315status_t DisplayListRenderer::drawOval(float left, float top, float right, float bottom,
316        const SkPaint* paint) {
317    paint = refPaint(paint);
318    addDrawOp(new (alloc()) DrawOvalOp(left, top, right, bottom, paint));
319    return DrawGlInfo::kStatusDone;
320}
321
322status_t DisplayListRenderer::drawArc(float left, float top, float right, float bottom,
323        float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) {
324    if (fabs(sweepAngle) >= 360.0f) {
325        return drawOval(left, top, right, bottom, paint);
326    }
327
328    paint = refPaint(paint);
329    addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom,
330                    startAngle, sweepAngle, useCenter, paint));
331    return DrawGlInfo::kStatusDone;
332}
333
334status_t DisplayListRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
335    path = refPath(path);
336    paint = refPaint(paint);
337
338    addDrawOp(new (alloc()) DrawPathOp(path, paint));
339    return DrawGlInfo::kStatusDone;
340}
341
342status_t DisplayListRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
343    points = refBuffer<float>(points, count);
344    paint = refPaint(paint);
345
346    addDrawOp(new (alloc()) DrawLinesOp(points, count, paint));
347    return DrawGlInfo::kStatusDone;
348}
349
350status_t DisplayListRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
351    points = refBuffer<float>(points, count);
352    paint = refPaint(paint);
353
354    addDrawOp(new (alloc()) DrawPointsOp(points, count, paint));
355    return DrawGlInfo::kStatusDone;
356}
357
358status_t DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
359        const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
360    if (!text || count <= 0) return DrawGlInfo::kStatusDone;
361
362    text = refText(text, bytesCount);
363    path = refPath(path);
364    paint = refPaint(paint);
365
366    DrawOp* op = new (alloc()) DrawTextOnPathOp(text, bytesCount, count, path,
367            hOffset, vOffset, paint);
368    addDrawOp(op);
369    return DrawGlInfo::kStatusDone;
370}
371
372status_t DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count,
373        const float* positions, const SkPaint* paint) {
374    if (!text || count <= 0) return DrawGlInfo::kStatusDone;
375
376    text = refText(text, bytesCount);
377    positions = refBuffer<float>(positions, count * 2);
378    paint = refPaint(paint);
379
380    DrawOp* op = new (alloc()) DrawPosTextOp(text, bytesCount, count, positions, paint);
381    addDrawOp(op);
382    return DrawGlInfo::kStatusDone;
383}
384
385static void simplifyPaint(int color, SkPaint* paint) {
386    paint->setColor(color);
387    paint->setShader(NULL);
388    paint->setColorFilter(NULL);
389    paint->setLooper(NULL);
390    paint->setStrokeWidth(4 + 0.04 * paint->getTextSize());
391    paint->setStrokeJoin(SkPaint::kRound_Join);
392    paint->setLooper(NULL);
393}
394
395status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
396        float x, float y, const float* positions, const SkPaint* paint,
397        float totalAdvance, const Rect& bounds, DrawOpMode drawOpMode) {
398
399    if (!text || count <= 0 || paintWillNotDrawText(*paint)) return DrawGlInfo::kStatusDone;
400
401    text = refText(text, bytesCount);
402    positions = refBuffer<float>(positions, count * 2);
403
404    if (CC_UNLIKELY(mHighContrastText)) {
405        // high contrast draw path
406        int color = paint->getColor();
407        int channelSum = SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color);
408        bool darken = channelSum < (128 * 3);
409
410        // outline
411        SkPaint* outlinePaint = copyPaint(paint);
412        simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, outlinePaint);
413        outlinePaint->setStyle(SkPaint::kStrokeAndFill_Style);
414        addDrawOp(new (alloc()) DrawTextOp(text, bytesCount, count,
415                x, y, positions, outlinePaint, totalAdvance, bounds)); // bounds?
416
417        // inner
418        SkPaint* innerPaint = copyPaint(paint);
419        simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, innerPaint);
420        innerPaint->setStyle(SkPaint::kFill_Style);
421        addDrawOp(new (alloc()) DrawTextOp(text, bytesCount, count,
422                x, y, positions, innerPaint, totalAdvance, bounds));
423    } else {
424        // standard draw path
425        paint = refPaint(paint);
426
427        DrawOp* op = new (alloc()) DrawTextOp(text, bytesCount, count,
428                x, y, positions, paint, totalAdvance, bounds);
429        addDrawOp(op);
430    }
431    return DrawGlInfo::kStatusDone;
432}
433
434status_t DisplayListRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
435    if (count <= 0) return DrawGlInfo::kStatusDone;
436
437    rects = refBuffer<float>(rects, count);
438    paint = refPaint(paint);
439    addDrawOp(new (alloc()) DrawRectsOp(rects, count, paint));
440    return DrawGlInfo::kStatusDone;
441}
442
443void DisplayListRenderer::resetPaintFilter() {
444    addStateOp(new (alloc()) ResetPaintFilterOp());
445}
446
447void DisplayListRenderer::setupPaintFilter(int clearBits, int setBits) {
448    addStateOp(new (alloc()) SetupPaintFilterOp(clearBits, setBits));
449}
450
451void DisplayListRenderer::insertReorderBarrier(bool enableReorder) {
452    flushRestoreToCount();
453    flushTranslate();
454    mDeferredBarrierType = enableReorder ? kBarrier_OutOfOrder : kBarrier_InOrder;
455}
456
457void DisplayListRenderer::flushRestoreToCount() {
458    if (mRestoreSaveCount >= 0) {
459        addOpAndUpdateChunk(new (alloc()) RestoreToCountOp(mRestoreSaveCount));
460        mRestoreSaveCount = -1;
461    }
462}
463
464void DisplayListRenderer::flushTranslate() {
465    if (mHasDeferredTranslate) {
466        if (mTranslateX != 0.0f || mTranslateY != 0.0f) {
467            addOpAndUpdateChunk(new (alloc()) TranslateOp(mTranslateX, mTranslateY));
468            mTranslateX = mTranslateY = 0.0f;
469        }
470        mHasDeferredTranslate = false;
471    }
472}
473
474size_t DisplayListRenderer::addOpAndUpdateChunk(DisplayListOp* op) {
475    int insertIndex = mDisplayListData->displayListOps.add(op);
476    if (mDeferredBarrierType != kBarrier_None) {
477        // op is first in new chunk
478        mDisplayListData->chunks.push();
479        DisplayListData::Chunk& newChunk = mDisplayListData->chunks.editTop();
480        newChunk.beginOpIndex = insertIndex;
481        newChunk.endOpIndex = insertIndex + 1;
482        newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder);
483
484        int nextChildIndex = mDisplayListData->children().size();
485        newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex;
486        mDeferredBarrierType = kBarrier_None;
487    } else {
488        // standard case - append to existing chunk
489        mDisplayListData->chunks.editTop().endOpIndex = insertIndex + 1;
490    }
491    return insertIndex;
492}
493
494size_t DisplayListRenderer::flushAndAddOp(DisplayListOp* op) {
495    flushRestoreToCount();
496    flushTranslate();
497    return addOpAndUpdateChunk(op);
498}
499
500size_t DisplayListRenderer::addStateOp(StateOp* op) {
501    return flushAndAddOp(op);
502}
503
504size_t DisplayListRenderer::addDrawOp(DrawOp* op) {
505    Rect localBounds;
506    if (op->getLocalBounds(localBounds)) {
507        bool rejected = quickRejectConservative(localBounds.left, localBounds.top,
508                localBounds.right, localBounds.bottom);
509        op->setQuickRejected(rejected);
510    }
511
512    mDisplayListData->hasDrawOps = true;
513    return flushAndAddOp(op);
514}
515
516size_t DisplayListRenderer::addRenderNodeOp(DrawRenderNodeOp* op) {
517    int opIndex = addDrawOp(op);
518    int childIndex = mDisplayListData->addChild(op);
519
520    // update the chunk's child indices
521    DisplayListData::Chunk& chunk = mDisplayListData->chunks.editTop();
522    chunk.endChildIndex = childIndex + 1;
523
524    if (op->renderNode()->stagingProperties().isProjectionReceiver()) {
525        // use staging property, since recording on UI thread
526        mDisplayListData->projectionReceiveIndex = opIndex;
527    }
528    return opIndex;
529}
530
531}; // namespace uirenderer
532}; // namespace android
533