RenderNode.cpp revision 3398abb25b6a8614f80f79efcf428a07185fe50f
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 "RenderNode.h"
18
19#include "DamageAccumulator.h"
20#include "Debug.h"
21#if HWUI_NEW_OPS
22#include "RecordedOp.h"
23#endif
24#include "DisplayListOp.h"
25#include "LayerRenderer.h"
26#include "OpenGLRenderer.h"
27#include "TreeInfo.h"
28#include "utils/MathUtils.h"
29#include "utils/TraceUtils.h"
30#include "renderthread/CanvasContext.h"
31
32#include "protos/hwui.pb.h"
33#include "protos/ProtoHelpers.h"
34
35#include <SkCanvas.h>
36
37#include <algorithm>
38#include <sstream>
39#include <string>
40
41namespace android {
42namespace uirenderer {
43
44void RenderNode::debugDumpLayers(const char* prefix) {
45    if (mLayer) {
46        ALOGD("%sNode %p (%s) has layer %p (fbo = %u, wasBuildLayered = %s)",
47                prefix, this, getName(), mLayer, mLayer->getFbo(),
48                mLayer->wasBuildLayered ? "true" : "false");
49    }
50    if (mDisplayList) {
51        for (auto&& child : mDisplayList->getChildren()) {
52            child->renderNode->debugDumpLayers(prefix);
53        }
54    }
55}
56
57RenderNode::RenderNode()
58        : mDirtyPropertyFields(0)
59        , mNeedsDisplayListSync(false)
60        , mDisplayList(nullptr)
61        , mStagingDisplayList(nullptr)
62        , mAnimatorManager(*this)
63        , mLayer(nullptr)
64        , mParentCount(0) {
65}
66
67RenderNode::~RenderNode() {
68    deleteDisplayList();
69    delete mStagingDisplayList;
70    if (mLayer) {
71        ALOGW("Memory Warning: Layer %p missed its detachment, held on to for far too long!", mLayer);
72        mLayer->postDecStrong();
73        mLayer = nullptr;
74    }
75}
76
77void RenderNode::setStagingDisplayList(DisplayList* displayList) {
78    mNeedsDisplayListSync = true;
79    delete mStagingDisplayList;
80    mStagingDisplayList = displayList;
81    // If mParentCount == 0 we are the sole reference to this RenderNode,
82    // so immediately free the old display list
83    if (!mParentCount && !mStagingDisplayList) {
84        deleteDisplayList();
85    }
86}
87
88/**
89 * This function is a simplified version of replay(), where we simply retrieve and log the
90 * display list. This function should remain in sync with the replay() function.
91 */
92void RenderNode::output(uint32_t level) {
93    ALOGD("%*sStart display list (%p, %s%s%s%s%s%s)", (level - 1) * 2, "", this,
94            getName(),
95            (MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : ""),
96            (properties().hasShadow() ? ", casting shadow" : ""),
97            (isRenderable() ? "" : ", empty"),
98            (properties().getProjectBackwards() ? ", projected" : ""),
99            (mLayer != nullptr ? ", on HW Layer" : ""));
100    ALOGD("%*s%s %d", level * 2, "", "Save",
101            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
102
103    properties().debugOutputProperties(level);
104
105    if (mDisplayList) {
106#if HWUI_NEW_OPS
107        LOG_ALWAYS_FATAL("op dumping unsupported");
108#else
109        // TODO: consider printing the chunk boundaries here
110        for (auto&& op : mDisplayList->getOps()) {
111            op->output(level, DisplayListOp::kOpLogFlag_Recurse);
112        }
113#endif
114    }
115
116    ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName());
117}
118
119void RenderNode::copyTo(proto::RenderNode *pnode) {
120    pnode->set_id(static_cast<uint64_t>(
121            reinterpret_cast<uintptr_t>(this)));
122    pnode->set_name(mName.string(), mName.length());
123
124    proto::RenderProperties* pprops = pnode->mutable_properties();
125    pprops->set_left(properties().getLeft());
126    pprops->set_top(properties().getTop());
127    pprops->set_right(properties().getRight());
128    pprops->set_bottom(properties().getBottom());
129    pprops->set_clip_flags(properties().getClippingFlags());
130    pprops->set_alpha(properties().getAlpha());
131    pprops->set_translation_x(properties().getTranslationX());
132    pprops->set_translation_y(properties().getTranslationY());
133    pprops->set_translation_z(properties().getTranslationZ());
134    pprops->set_elevation(properties().getElevation());
135    pprops->set_rotation(properties().getRotation());
136    pprops->set_rotation_x(properties().getRotationX());
137    pprops->set_rotation_y(properties().getRotationY());
138    pprops->set_scale_x(properties().getScaleX());
139    pprops->set_scale_y(properties().getScaleY());
140    pprops->set_pivot_x(properties().getPivotX());
141    pprops->set_pivot_y(properties().getPivotY());
142    pprops->set_has_overlapping_rendering(properties().getHasOverlappingRendering());
143    pprops->set_pivot_explicitly_set(properties().isPivotExplicitlySet());
144    pprops->set_project_backwards(properties().getProjectBackwards());
145    pprops->set_projection_receiver(properties().isProjectionReceiver());
146    set(pprops->mutable_clip_bounds(), properties().getClipBounds());
147
148    const Outline& outline = properties().getOutline();
149    if (outline.getType() != Outline::Type::None) {
150        proto::Outline* poutline = pprops->mutable_outline();
151        poutline->clear_path();
152        if (outline.getType() == Outline::Type::Empty) {
153            poutline->set_type(proto::Outline_Type_Empty);
154        } else if (outline.getType() == Outline::Type::ConvexPath) {
155            poutline->set_type(proto::Outline_Type_ConvexPath);
156            if (const SkPath* path = outline.getPath()) {
157                set(poutline->mutable_path(), *path);
158            }
159        } else if (outline.getType() == Outline::Type::RoundRect) {
160            poutline->set_type(proto::Outline_Type_RoundRect);
161        } else {
162            ALOGW("Uknown outline type! %d", static_cast<int>(outline.getType()));
163            poutline->set_type(proto::Outline_Type_None);
164        }
165        poutline->set_should_clip(outline.getShouldClip());
166        poutline->set_alpha(outline.getAlpha());
167        poutline->set_radius(outline.getRadius());
168        set(poutline->mutable_bounds(), outline.getBounds());
169    } else {
170        pprops->clear_outline();
171    }
172
173    const RevealClip& revealClip = properties().getRevealClip();
174    if (revealClip.willClip()) {
175        proto::RevealClip* prevealClip = pprops->mutable_reveal_clip();
176        prevealClip->set_x(revealClip.getX());
177        prevealClip->set_y(revealClip.getY());
178        prevealClip->set_radius(revealClip.getRadius());
179    } else {
180        pprops->clear_reveal_clip();
181    }
182
183    pnode->clear_children();
184    if (mDisplayList) {
185        for (auto&& child : mDisplayList->getChildren()) {
186            child->renderNode->copyTo(pnode->add_children());
187        }
188    }
189}
190
191int RenderNode::getDebugSize() {
192    int size = sizeof(RenderNode);
193    if (mStagingDisplayList) {
194        size += mStagingDisplayList->getUsedSize();
195    }
196    if (mDisplayList && mDisplayList != mStagingDisplayList) {
197        size += mDisplayList->getUsedSize();
198    }
199    return size;
200}
201
202void RenderNode::prepareTree(TreeInfo& info) {
203    ATRACE_CALL();
204    LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing");
205
206    // Functors don't correctly handle stencil usage of overdraw debugging - shove 'em in a layer.
207    bool functorsNeedLayer = Properties::debugOverdraw;
208
209    prepareTreeImpl(info, functorsNeedLayer);
210}
211
212void RenderNode::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
213    mAnimatorManager.addAnimator(animator);
214}
215
216void RenderNode::damageSelf(TreeInfo& info) {
217    if (isRenderable()) {
218        if (properties().getClipDamageToBounds()) {
219            info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
220        } else {
221            // Hope this is big enough?
222            // TODO: Get this from the display list ops or something
223            info.damageAccumulator->dirty(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX);
224        }
225    }
226}
227
228void RenderNode::prepareLayer(TreeInfo& info, uint32_t dirtyMask) {
229    LayerType layerType = properties().effectiveLayerType();
230    if (CC_UNLIKELY(layerType == LayerType::RenderLayer)) {
231        // Damage applied so far needs to affect our parent, but does not require
232        // the layer to be updated. So we pop/push here to clear out the current
233        // damage and get a clean state for display list or children updates to
234        // affect, which will require the layer to be updated
235        info.damageAccumulator->popTransform();
236        info.damageAccumulator->pushTransform(this);
237        if (dirtyMask & DISPLAY_LIST) {
238            damageSelf(info);
239        }
240    }
241}
242
243void RenderNode::pushLayerUpdate(TreeInfo& info) {
244    LayerType layerType = properties().effectiveLayerType();
245    // If we are not a layer OR we cannot be rendered (eg, view was detached)
246    // we need to destroy any Layers we may have had previously
247    if (CC_LIKELY(layerType != LayerType::RenderLayer) || CC_UNLIKELY(!isRenderable())) {
248        if (CC_UNLIKELY(mLayer)) {
249            LayerRenderer::destroyLayer(mLayer);
250            mLayer = nullptr;
251        }
252        return;
253    }
254
255    bool transformUpdateNeeded = false;
256    if (!mLayer) {
257        mLayer = LayerRenderer::createRenderLayer(info.renderState, getWidth(), getHeight());
258        applyLayerPropertiesToLayer(info);
259        damageSelf(info);
260        transformUpdateNeeded = true;
261    } else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
262        if (!LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight())) {
263            LayerRenderer::destroyLayer(mLayer);
264            mLayer = nullptr;
265        }
266        damageSelf(info);
267        transformUpdateNeeded = true;
268    }
269
270    SkRect dirty;
271    info.damageAccumulator->peekAtDirty(&dirty);
272
273    if (!mLayer) {
274        Caches::getInstance().dumpMemoryUsage();
275        if (info.errorHandler) {
276            std::ostringstream err;
277            err << "Unable to create layer for " << getName();
278            const int maxTextureSize = Caches::getInstance().maxTextureSize;
279            if (getWidth() > maxTextureSize || getHeight() > maxTextureSize) {
280                err << ", size " << getWidth() << "x" << getHeight()
281                        << " exceeds max size " << maxTextureSize;
282            } else {
283                err << ", see logcat for more info";
284            }
285            info.errorHandler->onError(err.str());
286        }
287        return;
288    }
289
290    if (transformUpdateNeeded) {
291        // update the transform in window of the layer to reset its origin wrt light source position
292        Matrix4 windowTransform;
293        info.damageAccumulator->computeCurrentTransform(&windowTransform);
294        mLayer->setWindowTransform(windowTransform);
295    }
296
297    if (dirty.intersect(0, 0, getWidth(), getHeight())) {
298        dirty.roundOut(&dirty);
299        mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom);
300    }
301    // This is not inside the above if because we may have called
302    // updateDeferred on a previous prepare pass that didn't have a renderer
303    if (info.renderer && mLayer->deferredUpdateScheduled) {
304        info.renderer->pushLayerUpdate(mLayer);
305    }
306
307    if (info.canvasContext) {
308        // There might be prefetched layers that need to be accounted for.
309        // That might be us, so tell CanvasContext that this layer is in the
310        // tree and should not be destroyed.
311        info.canvasContext->markLayerInUse(this);
312    }
313}
314
315/**
316 * Traverse down the the draw tree to prepare for a frame.
317 *
318 * MODE_FULL = UI Thread-driven (thus properties must be synced), otherwise RT driven
319 *
320 * While traversing down the tree, functorsNeedLayer flag is set to true if anything that uses the
321 * stencil buffer may be needed. Views that use a functor to draw will be forced onto a layer.
322 */
323void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) {
324    info.damageAccumulator->pushTransform(this);
325
326    if (info.mode == TreeInfo::MODE_FULL) {
327        pushStagingPropertiesChanges(info);
328    }
329    uint32_t animatorDirtyMask = 0;
330    if (CC_LIKELY(info.runAnimations)) {
331        animatorDirtyMask = mAnimatorManager.animate(info);
332    }
333
334    bool willHaveFunctor = false;
335    if (info.mode == TreeInfo::MODE_FULL && mStagingDisplayList) {
336        willHaveFunctor = !mStagingDisplayList->getFunctors().empty();
337    } else if (mDisplayList) {
338        willHaveFunctor = !mDisplayList->getFunctors().empty();
339    }
340    bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence(
341            willHaveFunctor, functorsNeedLayer);
342
343    prepareLayer(info, animatorDirtyMask);
344    if (info.mode == TreeInfo::MODE_FULL) {
345        pushStagingDisplayListChanges(info);
346    }
347    prepareSubTree(info, childFunctorsNeedLayer, mDisplayList);
348    pushLayerUpdate(info);
349
350    info.damageAccumulator->popTransform();
351}
352
353void RenderNode::syncProperties() {
354    mProperties = mStagingProperties;
355}
356
357void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
358    // Push the animators first so that setupStartValueIfNecessary() is called
359    // before properties() is trampled by stagingProperties(), as they are
360    // required by some animators.
361    if (CC_LIKELY(info.runAnimations)) {
362        mAnimatorManager.pushStaging();
363    }
364    if (mDirtyPropertyFields) {
365        mDirtyPropertyFields = 0;
366        damageSelf(info);
367        info.damageAccumulator->popTransform();
368        syncProperties();
369        applyLayerPropertiesToLayer(info);
370        // We could try to be clever and only re-damage if the matrix changed.
371        // However, we don't need to worry about that. The cost of over-damaging
372        // here is only going to be a single additional map rect of this node
373        // plus a rect join(). The parent's transform (and up) will only be
374        // performed once.
375        info.damageAccumulator->pushTransform(this);
376        damageSelf(info);
377    }
378}
379
380void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) {
381    if (CC_LIKELY(!mLayer)) return;
382
383    const LayerProperties& props = properties().layerProperties();
384    mLayer->setAlpha(props.alpha(), props.xferMode());
385    mLayer->setColorFilter(props.colorFilter());
386    mLayer->setBlend(props.needsBlending());
387}
388
389void RenderNode::syncDisplayList() {
390    // Make sure we inc first so that we don't fluctuate between 0 and 1,
391    // which would thrash the layer cache
392    if (mStagingDisplayList) {
393        for (auto&& child : mStagingDisplayList->getChildren()) {
394            child->renderNode->incParentRefCount();
395        }
396    }
397    deleteDisplayList();
398    mDisplayList = mStagingDisplayList;
399    mStagingDisplayList = nullptr;
400    if (mDisplayList) {
401        for (size_t i = 0; i < mDisplayList->getFunctors().size(); i++) {
402            (*mDisplayList->getFunctors()[i])(DrawGlInfo::kModeSync, nullptr);
403        }
404    }
405}
406
407void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
408    if (mNeedsDisplayListSync) {
409        mNeedsDisplayListSync = false;
410        // Damage with the old display list first then the new one to catch any
411        // changes in isRenderable or, in the future, bounds
412        damageSelf(info);
413        syncDisplayList();
414        damageSelf(info);
415    }
416}
417
418void RenderNode::deleteDisplayList() {
419    if (mDisplayList) {
420        for (auto&& child : mDisplayList->getChildren()) {
421            child->renderNode->decParentRefCount();
422        }
423    }
424    delete mDisplayList;
425    mDisplayList = nullptr;
426}
427
428void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayList* subtree) {
429    if (subtree) {
430        TextureCache& cache = Caches::getInstance().textureCache;
431        info.out.hasFunctors |= subtree->getFunctors().size();
432        for (auto&& bitmapResource : subtree->getBitmapResources()) {
433            info.prepareTextures = cache.prefetchAndMarkInUse(info.canvasContext, bitmapResource);
434        }
435        for (auto&& op : subtree->getChildren()) {
436            RenderNode* childNode = op->renderNode;
437#if HWUI_NEW_OPS
438            info.damageAccumulator->pushTransform(&op->localMatrix);
439            bool childFunctorsNeedLayer = functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
440#else
441            info.damageAccumulator->pushTransform(&op->mTransformFromParent);
442            bool childFunctorsNeedLayer = functorsNeedLayer
443                    // Recorded with non-rect clip, or canvas-rotated by parent
444                    || op->mRecordedWithPotentialStencilClip;
445#endif
446            childNode->prepareTreeImpl(info, childFunctorsNeedLayer);
447            info.damageAccumulator->popTransform();
448        }
449    }
450}
451
452void RenderNode::destroyHardwareResources() {
453    if (mLayer) {
454        LayerRenderer::destroyLayer(mLayer);
455        mLayer = nullptr;
456    }
457    if (mDisplayList) {
458        for (auto&& child : mDisplayList->getChildren()) {
459            child->renderNode->destroyHardwareResources();
460        }
461        if (mNeedsDisplayListSync) {
462            // Next prepare tree we are going to push a new display list, so we can
463            // drop our current one now
464            deleteDisplayList();
465        }
466    }
467}
468
469void RenderNode::decParentRefCount() {
470    LOG_ALWAYS_FATAL_IF(!mParentCount, "already 0!");
471    mParentCount--;
472    if (!mParentCount) {
473        // If a child of ours is being attached to our parent then this will incorrectly
474        // destroy its hardware resources. However, this situation is highly unlikely
475        // and the failure is "just" that the layer is re-created, so this should
476        // be safe enough
477        destroyHardwareResources();
478    }
479}
480
481bool RenderNode::applyViewProperties(CanvasState& canvasState) const {
482    const Outline& outline = properties().getOutline();
483    if (properties().getAlpha() <= 0
484            || (outline.getShouldClip() && outline.isEmpty())
485            || properties().getScaleX() == 0
486            || properties().getScaleY() == 0) {
487        return false; // rejected
488    }
489
490    if (properties().getLeft() != 0 || properties().getTop() != 0) {
491        canvasState.translate(properties().getLeft(), properties().getTop());
492    }
493    if (properties().getStaticMatrix()) {
494        canvasState.concatMatrix(*properties().getStaticMatrix());
495    } else if (properties().getAnimationMatrix()) {
496        canvasState.concatMatrix(*properties().getAnimationMatrix());
497    }
498    if (properties().hasTransformMatrix()) {
499        if (properties().isTransformTranslateOnly()) {
500            canvasState.translate(properties().getTranslationX(), properties().getTranslationY());
501        } else {
502            canvasState.concatMatrix(*properties().getTransformMatrix());
503        }
504    }
505    return !canvasState.quickRejectConservative(
506            0, 0, properties().getWidth(), properties().getHeight());
507}
508
509/*
510 * For property operations, we pass a savecount of 0, since the operations aren't part of the
511 * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
512 * base saveCount (i.e., how RestoreToCount uses saveCount + properties().getCount())
513 */
514#define PROPERTY_SAVECOUNT 0
515
516template <class T>
517void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) {
518#if DEBUG_DISPLAY_LIST
519    properties().debugOutputProperties(handler.level() + 1);
520#endif
521    if (properties().getLeft() != 0 || properties().getTop() != 0) {
522        renderer.translate(properties().getLeft(), properties().getTop());
523    }
524    if (properties().getStaticMatrix()) {
525        renderer.concatMatrix(*properties().getStaticMatrix());
526    } else if (properties().getAnimationMatrix()) {
527        renderer.concatMatrix(*properties().getAnimationMatrix());
528    }
529    if (properties().hasTransformMatrix()) {
530        if (properties().isTransformTranslateOnly()) {
531            renderer.translate(properties().getTranslationX(), properties().getTranslationY());
532        } else {
533            renderer.concatMatrix(*properties().getTransformMatrix());
534        }
535    }
536    const bool isLayer = properties().effectiveLayerType() != LayerType::None;
537    int clipFlags = properties().getClippingFlags();
538    if (properties().getAlpha() < 1) {
539        if (isLayer) {
540            clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
541        }
542        if (CC_LIKELY(isLayer || !properties().getHasOverlappingRendering())) {
543            // simply scale rendering content's alpha
544            renderer.scaleAlpha(properties().getAlpha());
545        } else {
546            // savelayer needed to create an offscreen buffer
547            Rect layerBounds(0, 0, getWidth(), getHeight());
548            if (clipFlags) {
549                properties().getClippingRectForFlags(clipFlags, &layerBounds);
550                clipFlags = 0; // all clipping done by savelayer
551            }
552            SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
553                    layerBounds.left, layerBounds.top,
554                    layerBounds.right, layerBounds.bottom,
555                    (int) (properties().getAlpha() * 255),
556                    SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag);
557            handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
558        }
559
560        if (CC_UNLIKELY(ATRACE_ENABLED() && properties().promotedToLayer())) {
561            // pretend alpha always causes savelayer to warn about
562            // performance problem affecting old versions
563            ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", getName(),
564                    static_cast<int>(getWidth()),
565                    static_cast<int>(getHeight()));
566        }
567    }
568    if (clipFlags) {
569        Rect clipRect;
570        properties().getClippingRectForFlags(clipFlags, &clipRect);
571        ClipRectOp* op = new (handler.allocator()) ClipRectOp(
572                clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
573                SkRegion::kIntersect_Op);
574        handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
575    }
576
577    // TODO: support nesting round rect clips
578    if (mProperties.getRevealClip().willClip()) {
579        Rect bounds;
580        mProperties.getRevealClip().getBounds(&bounds);
581        renderer.setClippingRoundRect(handler.allocator(), bounds, mProperties.getRevealClip().getRadius());
582    } else if (mProperties.getOutline().willClip()) {
583        renderer.setClippingOutline(handler.allocator(), &(mProperties.getOutline()));
584    }
585}
586
587/**
588 * Apply property-based transformations to input matrix
589 *
590 * If true3dTransform is set to true, the transform applied to the input matrix will use true 4x4
591 * matrix computation instead of the Skia 3x3 matrix + camera hackery.
592 */
593void RenderNode::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform) const {
594    if (properties().getLeft() != 0 || properties().getTop() != 0) {
595        matrix.translate(properties().getLeft(), properties().getTop());
596    }
597    if (properties().getStaticMatrix()) {
598        mat4 stat(*properties().getStaticMatrix());
599        matrix.multiply(stat);
600    } else if (properties().getAnimationMatrix()) {
601        mat4 anim(*properties().getAnimationMatrix());
602        matrix.multiply(anim);
603    }
604
605    bool applyTranslationZ = true3dTransform && !MathUtils::isZero(properties().getZ());
606    if (properties().hasTransformMatrix() || applyTranslationZ) {
607        if (properties().isTransformTranslateOnly()) {
608            matrix.translate(properties().getTranslationX(), properties().getTranslationY(),
609                    true3dTransform ? properties().getZ() : 0.0f);
610        } else {
611            if (!true3dTransform) {
612                matrix.multiply(*properties().getTransformMatrix());
613            } else {
614                mat4 true3dMat;
615                true3dMat.loadTranslate(
616                        properties().getPivotX() + properties().getTranslationX(),
617                        properties().getPivotY() + properties().getTranslationY(),
618                        properties().getZ());
619                true3dMat.rotate(properties().getRotationX(), 1, 0, 0);
620                true3dMat.rotate(properties().getRotationY(), 0, 1, 0);
621                true3dMat.rotate(properties().getRotation(), 0, 0, 1);
622                true3dMat.scale(properties().getScaleX(), properties().getScaleY(), 1);
623                true3dMat.translate(-properties().getPivotX(), -properties().getPivotY());
624
625                matrix.multiply(true3dMat);
626            }
627        }
628    }
629}
630
631/**
632 * Organizes the DisplayList hierarchy to prepare for background projection reordering.
633 *
634 * This should be called before a call to defer() or drawDisplayList()
635 *
636 * Each DisplayList that serves as a 3d root builds its list of composited children,
637 * which are flagged to not draw in the standard draw loop.
638 */
639void RenderNode::computeOrdering() {
640#if !HWUI_NEW_OPS
641    ATRACE_CALL();
642    mProjectedNodes.clear();
643
644    // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
645    // transform properties are applied correctly to top level children
646    if (mDisplayList == nullptr) return;
647    for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) {
648        DrawRenderNodeOp* childOp = mDisplayList->getChildren()[i];
649        childOp->renderNode->computeOrderingImpl(childOp, &mProjectedNodes, &mat4::identity());
650    }
651#endif
652}
653
654void RenderNode::computeOrderingImpl(
655        DrawRenderNodeOp* opState,
656        std::vector<DrawRenderNodeOp*>* compositedChildrenOfProjectionSurface,
657        const mat4* transformFromProjectionSurface) {
658#if !HWUI_NEW_OPS
659    mProjectedNodes.clear();
660    if (mDisplayList == nullptr || mDisplayList->isEmpty()) return;
661
662    // TODO: should avoid this calculation in most cases
663    // TODO: just calculate single matrix, down to all leaf composited elements
664    Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface);
665    localTransformFromProjectionSurface.multiply(opState->mTransformFromParent);
666
667    if (properties().getProjectBackwards()) {
668        // composited projectee, flag for out of order draw, save matrix, and store in proj surface
669        opState->mSkipInOrderDraw = true;
670        opState->mTransformFromCompositingAncestor = localTransformFromProjectionSurface;
671        compositedChildrenOfProjectionSurface->push_back(opState);
672    } else {
673        // standard in order draw
674        opState->mSkipInOrderDraw = false;
675    }
676
677    if (mDisplayList->getChildren().size() > 0) {
678        const bool isProjectionReceiver = mDisplayList->projectionReceiveIndex >= 0;
679        bool haveAppliedPropertiesToProjection = false;
680        for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) {
681            DrawRenderNodeOp* childOp = mDisplayList->getChildren()[i];
682            RenderNode* child = childOp->renderNode;
683
684            std::vector<DrawRenderNodeOp*>* projectionChildren = nullptr;
685            const mat4* projectionTransform = nullptr;
686            if (isProjectionReceiver && !child->properties().getProjectBackwards()) {
687                // if receiving projections, collect projecting descendant
688
689                // Note that if a direct descendant is projecting backwards, we pass its
690                // grandparent projection collection, since it shouldn't project onto its
691                // parent, where it will already be drawing.
692                projectionChildren = &mProjectedNodes;
693                projectionTransform = &mat4::identity();
694            } else {
695                if (!haveAppliedPropertiesToProjection) {
696                    applyViewPropertyTransforms(localTransformFromProjectionSurface);
697                    haveAppliedPropertiesToProjection = true;
698                }
699                projectionChildren = compositedChildrenOfProjectionSurface;
700                projectionTransform = &localTransformFromProjectionSurface;
701            }
702            child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
703        }
704    }
705#endif
706}
707
708class DeferOperationHandler {
709public:
710    DeferOperationHandler(DeferStateStruct& deferStruct, int level)
711        : mDeferStruct(deferStruct), mLevel(level) {}
712    inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
713        operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
714    }
715    inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
716    inline void startMark(const char* name) {} // do nothing
717    inline void endMark() {}
718    inline int level() { return mLevel; }
719    inline int replayFlags() { return mDeferStruct.mReplayFlags; }
720    inline SkPath* allocPathForFrame() { return mDeferStruct.allocPathForFrame(); }
721
722private:
723    DeferStateStruct& mDeferStruct;
724    const int mLevel;
725};
726
727void RenderNode::defer(DeferStateStruct& deferStruct, const int level) {
728    DeferOperationHandler handler(deferStruct, level);
729    issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
730}
731
732class ReplayOperationHandler {
733public:
734    ReplayOperationHandler(ReplayStateStruct& replayStruct, int level)
735        : mReplayStruct(replayStruct), mLevel(level) {}
736    inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
737#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
738        mReplayStruct.mRenderer.eventMark(operation->name());
739#endif
740        operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
741    }
742    inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
743    inline void startMark(const char* name) {
744        mReplayStruct.mRenderer.startMark(name);
745    }
746    inline void endMark() {
747        mReplayStruct.mRenderer.endMark();
748    }
749    inline int level() { return mLevel; }
750    inline int replayFlags() { return mReplayStruct.mReplayFlags; }
751    inline SkPath* allocPathForFrame() { return mReplayStruct.allocPathForFrame(); }
752
753private:
754    ReplayStateStruct& mReplayStruct;
755    const int mLevel;
756};
757
758void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) {
759    ReplayOperationHandler handler(replayStruct, level);
760    issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
761}
762
763void RenderNode::buildZSortedChildList(const DisplayList::Chunk& chunk,
764        std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes) {
765#if !HWUI_NEW_OPS
766    if (chunk.beginChildIndex == chunk.endChildIndex) return;
767
768    for (unsigned int i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
769        DrawRenderNodeOp* childOp = mDisplayList->getChildren()[i];
770        RenderNode* child = childOp->renderNode;
771        float childZ = child->properties().getZ();
772
773        if (!MathUtils::isZero(childZ) && chunk.reorderChildren) {
774            zTranslatedNodes.push_back(ZDrawRenderNodeOpPair(childZ, childOp));
775            childOp->mSkipInOrderDraw = true;
776        } else if (!child->properties().getProjectBackwards()) {
777            // regular, in order drawing DisplayList
778            childOp->mSkipInOrderDraw = false;
779        }
780    }
781
782    // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order)
783    std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end());
784#endif
785}
786
787template <class T>
788void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler) {
789    if (properties().getAlpha() <= 0.0f
790            || properties().getOutline().getAlpha() <= 0.0f
791            || !properties().getOutline().getPath()
792            || properties().getScaleX() == 0
793            || properties().getScaleY() == 0) {
794        // no shadow to draw
795        return;
796    }
797
798    mat4 shadowMatrixXY(transformFromParent);
799    applyViewPropertyTransforms(shadowMatrixXY);
800
801    // Z matrix needs actual 3d transformation, so mapped z values will be correct
802    mat4 shadowMatrixZ(transformFromParent);
803    applyViewPropertyTransforms(shadowMatrixZ, true);
804
805    const SkPath* casterOutlinePath = properties().getOutline().getPath();
806    const SkPath* revealClipPath = properties().getRevealClip().getPath();
807    if (revealClipPath && revealClipPath->isEmpty()) return;
808
809    float casterAlpha = properties().getAlpha() * properties().getOutline().getAlpha();
810
811
812    // holds temporary SkPath to store the result of intersections
813    SkPath* frameAllocatedPath = nullptr;
814    const SkPath* outlinePath = casterOutlinePath;
815
816    // intersect the outline with the reveal clip, if present
817    if (revealClipPath) {
818        frameAllocatedPath = handler.allocPathForFrame();
819
820        Op(*outlinePath, *revealClipPath, kIntersect_SkPathOp, frameAllocatedPath);
821        outlinePath = frameAllocatedPath;
822    }
823
824    // intersect the outline with the clipBounds, if present
825    if (properties().getClippingFlags() & CLIP_TO_CLIP_BOUNDS) {
826        if (!frameAllocatedPath) {
827            frameAllocatedPath = handler.allocPathForFrame();
828        }
829
830        Rect clipBounds;
831        properties().getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
832        SkPath clipBoundsPath;
833        clipBoundsPath.addRect(clipBounds.left, clipBounds.top,
834                clipBounds.right, clipBounds.bottom);
835
836        Op(*outlinePath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath);
837        outlinePath = frameAllocatedPath;
838    }
839
840    DisplayListOp* shadowOp  = new (handler.allocator()) DrawShadowOp(
841            shadowMatrixXY, shadowMatrixZ, casterAlpha, outlinePath);
842    handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
843}
844
845#define SHADOW_DELTA 0.1f
846
847template <class T>
848void RenderNode::issueOperationsOf3dChildren(ChildrenSelectMode mode,
849        const Matrix4& initialTransform, const std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes,
850        OpenGLRenderer& renderer, T& handler) {
851    const int size = zTranslatedNodes.size();
852    if (size == 0
853            || (mode == ChildrenSelectMode::NegativeZChildren && zTranslatedNodes[0].key > 0.0f)
854            || (mode == ChildrenSelectMode::PositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) {
855        // no 3d children to draw
856        return;
857    }
858
859    // Apply the base transform of the parent of the 3d children. This isolates
860    // 3d children of the current chunk from transformations made in previous chunks.
861    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
862    renderer.setGlobalMatrix(initialTransform);
863
864    /**
865     * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
866     * with very similar Z heights to draw together.
867     *
868     * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are
869     * underneath both, and neither's shadow is drawn on top of the other.
870     */
871    const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes);
872    size_t drawIndex, shadowIndex, endIndex;
873    if (mode == ChildrenSelectMode::NegativeZChildren) {
874        drawIndex = 0;
875        endIndex = nonNegativeIndex;
876        shadowIndex = endIndex; // draw no shadows
877    } else {
878        drawIndex = nonNegativeIndex;
879        endIndex = size;
880        shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
881    }
882
883    DISPLAY_LIST_LOGD("%*s%d %s 3d children:", (handler.level() + 1) * 2, "",
884            endIndex - drawIndex, mode == kNegativeZChildren ? "negative" : "positive");
885
886    float lastCasterZ = 0.0f;
887    while (shadowIndex < endIndex || drawIndex < endIndex) {
888        if (shadowIndex < endIndex) {
889            DrawRenderNodeOp* casterOp = zTranslatedNodes[shadowIndex].value;
890            RenderNode* caster = casterOp->renderNode;
891            const float casterZ = zTranslatedNodes[shadowIndex].key;
892            // attempt to render the shadow if the caster about to be drawn is its caster,
893            // OR if its caster's Z value is similar to the previous potential caster
894            if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {
895                caster->issueDrawShadowOperation(casterOp->mTransformFromParent, handler);
896
897                lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
898                shadowIndex++;
899                continue;
900            }
901        }
902
903        // only the actual child DL draw needs to be in save/restore,
904        // since it modifies the renderer's matrix
905        int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
906
907        DrawRenderNodeOp* childOp = zTranslatedNodes[drawIndex].value;
908
909        renderer.concatMatrix(childOp->mTransformFromParent);
910        childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
911        handler(childOp, renderer.getSaveCount() - 1, properties().getClipToBounds());
912        childOp->mSkipInOrderDraw = true;
913
914        renderer.restoreToCount(restoreTo);
915        drawIndex++;
916    }
917    renderer.restoreToCount(rootRestoreTo);
918}
919
920template <class T>
921void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) {
922    DISPLAY_LIST_LOGD("%*s%d projected children:", (handler.level() + 1) * 2, "", mProjectedNodes.size());
923    const SkPath* projectionReceiverOutline = properties().getOutline().getPath();
924    int restoreTo = renderer.getSaveCount();
925
926    LinearAllocator& alloc = handler.allocator();
927    handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
928            PROPERTY_SAVECOUNT, properties().getClipToBounds());
929
930    // Transform renderer to match background we're projecting onto
931    // (by offsetting canvas by translationX/Y of background rendernode, since only those are set)
932    const DisplayListOp* op =
933#if HWUI_NEW_OPS
934            nullptr;
935    LOG_ALWAYS_FATAL("unsupported");
936#else
937            (mDisplayList->getOps()[mDisplayList->projectionReceiveIndex]);
938#endif
939    const DrawRenderNodeOp* backgroundOp = reinterpret_cast<const DrawRenderNodeOp*>(op);
940    const RenderProperties& backgroundProps = backgroundOp->renderNode->properties();
941    renderer.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY());
942
943    // If the projection receiver has an outline, we mask projected content to it
944    // (which we know, apriori, are all tessellated paths)
945    renderer.setProjectionPathMask(alloc, projectionReceiverOutline);
946
947    // draw projected nodes
948    for (size_t i = 0; i < mProjectedNodes.size(); i++) {
949        DrawRenderNodeOp* childOp = mProjectedNodes[i];
950
951        // matrix save, concat, and restore can be done safely without allocating operations
952        int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
953        renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
954        childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
955        handler(childOp, renderer.getSaveCount() - 1, properties().getClipToBounds());
956        childOp->mSkipInOrderDraw = true;
957        renderer.restoreToCount(restoreTo);
958    }
959
960    handler(new (alloc) RestoreToCountOp(restoreTo),
961            PROPERTY_SAVECOUNT, properties().getClipToBounds());
962}
963
964/**
965 * This function serves both defer and replay modes, and will organize the displayList's component
966 * operations for a single frame:
967 *
968 * Every 'simple' state operation that affects just the matrix and alpha (or other factors of
969 * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
970 * defer logic) and operations in displayListOps are issued through the 'handler' which handles the
971 * defer vs replay logic, per operation
972 */
973template <class T>
974void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
975    if (mDisplayList->isEmpty()) {
976        DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", handler.level() * 2, "",
977                this, getName());
978        return;
979    }
980
981    const bool drawLayer = (mLayer && (&renderer != mLayer->renderer.get()));
982    // If we are updating the contents of mLayer, we don't want to apply any of
983    // the RenderNode's properties to this issueOperations pass. Those will all
984    // be applied when the layer is drawn, aka when this is true.
985    const bool useViewProperties = (!mLayer || drawLayer);
986    if (useViewProperties) {
987        const Outline& outline = properties().getOutline();
988        if (properties().getAlpha() <= 0
989                || (outline.getShouldClip() && outline.isEmpty())
990                || properties().getScaleX() == 0
991                || properties().getScaleY() == 0) {
992            DISPLAY_LIST_LOGD("%*sRejected display list (%p, %s)", handler.level() * 2, "",
993                    this, getName());
994            return;
995        }
996    }
997
998    handler.startMark(getName());
999
1000#if DEBUG_DISPLAY_LIST
1001    const Rect& clipRect = renderer.getLocalClipBounds();
1002    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), localClipBounds: %.0f, %.0f, %.0f, %.0f",
1003            handler.level() * 2, "", this, getName(),
1004            clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
1005#endif
1006
1007    LinearAllocator& alloc = handler.allocator();
1008    int restoreTo = renderer.getSaveCount();
1009    handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
1010            PROPERTY_SAVECOUNT, properties().getClipToBounds());
1011
1012    DISPLAY_LIST_LOGD("%*sSave %d %d", (handler.level() + 1) * 2, "",
1013            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
1014
1015    if (useViewProperties) {
1016        setViewProperties<T>(renderer, handler);
1017    }
1018
1019#if HWUI_NEW_OPS
1020    LOG_ALWAYS_FATAL("legacy op traversal not supported");
1021#else
1022    bool quickRejected = properties().getClipToBounds()
1023            && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
1024    if (!quickRejected) {
1025        Matrix4 initialTransform(*(renderer.currentTransform()));
1026        renderer.setBaseTransform(initialTransform);
1027
1028        if (drawLayer) {
1029            handler(new (alloc) DrawLayerOp(mLayer),
1030                    renderer.getSaveCount() - 1, properties().getClipToBounds());
1031        } else {
1032            const int saveCountOffset = renderer.getSaveCount() - 1;
1033            const int projectionReceiveIndex = mDisplayList->projectionReceiveIndex;
1034            for (size_t chunkIndex = 0; chunkIndex < mDisplayList->getChunks().size(); chunkIndex++) {
1035                const DisplayList::Chunk& chunk = mDisplayList->getChunks()[chunkIndex];
1036
1037                std::vector<ZDrawRenderNodeOpPair> zTranslatedNodes;
1038                buildZSortedChildList(chunk, zTranslatedNodes);
1039
1040                issueOperationsOf3dChildren(ChildrenSelectMode::NegativeZChildren,
1041                        initialTransform, zTranslatedNodes, renderer, handler);
1042
1043                for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
1044                    DisplayListOp *op = mDisplayList->getOps()[opIndex];
1045#if DEBUG_DISPLAY_LIST
1046                    op->output(handler.level() + 1);
1047#endif
1048                    handler(op, saveCountOffset, properties().getClipToBounds());
1049
1050                    if (CC_UNLIKELY(!mProjectedNodes.empty() && projectionReceiveIndex >= 0 &&
1051                        opIndex == static_cast<size_t>(projectionReceiveIndex))) {
1052                        issueOperationsOfProjectedChildren(renderer, handler);
1053                    }
1054                }
1055
1056                issueOperationsOf3dChildren(ChildrenSelectMode::PositiveZChildren,
1057                        initialTransform, zTranslatedNodes, renderer, handler);
1058            }
1059        }
1060    }
1061#endif
1062
1063    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (handler.level() + 1) * 2, "", restoreTo);
1064    handler(new (alloc) RestoreToCountOp(restoreTo),
1065            PROPERTY_SAVECOUNT, properties().getClipToBounds());
1066
1067    DISPLAY_LIST_LOGD("%*sDone (%p, %s)", handler.level() * 2, "", this, getName());
1068    handler.endMark();
1069}
1070
1071} /* namespace uirenderer */
1072} /* namespace android */
1073