1/*
2 * Copyright (C) 2016 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 "SkiaDisplayList.h"
18
19#include "renderthread/CanvasContext.h"
20#include "VectorDrawable.h"
21#include "DumpOpsCanvas.h"
22#include "SkiaPipeline.h"
23
24#include <SkImagePriv.h>
25
26
27namespace android {
28namespace uirenderer {
29namespace skiapipeline {
30
31void SkiaDisplayList::syncContents() {
32    for (auto& functor : mChildFunctors) {
33        functor.syncFunctor();
34    }
35    for (auto& vectorDrawable : mVectorDrawables) {
36        vectorDrawable->syncProperties();
37    }
38}
39
40bool SkiaDisplayList::reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) {
41    reset();
42    node->attachAvailableList(this);
43    return true;
44}
45
46void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) {
47    for (auto& child : mChildNodes) {
48        updateFn(child.getRenderNode());
49    }
50}
51
52bool SkiaDisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& info,
53        bool functorsNeedLayer,
54        std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
55    // If the prepare tree is triggered by the UI thread and no previous call to
56    // pinImages has failed then we must pin all mutable images in the GPU cache
57    // until the next UI thread draw.
58    if (info.prepareTextures && !info.canvasContext.pinImages(mMutableImages)) {
59        // In the event that pinning failed we prevent future pinImage calls for the
60        // remainder of this tree traversal and also unpin any currently pinned images
61        // to free up GPU resources.
62        info.prepareTextures = false;
63        info.canvasContext.unpinImages();
64    }
65
66    bool hasBackwardProjectedNodesHere = false;
67    bool hasBackwardProjectedNodesSubtree= false;
68
69    for (auto& child : mChildNodes) {
70        hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards();
71        RenderNode* childNode = child.getRenderNode();
72        Matrix4 mat4(child.getRecordedMatrix());
73        info.damageAccumulator->pushTransform(&mat4);
74        // TODO: a layer is needed if the canvas is rotated or has a non-rect clip
75        info.hasBackwardProjectedNodes = false;
76        childFn(childNode, observer, info, functorsNeedLayer);
77        hasBackwardProjectedNodesSubtree |= info.hasBackwardProjectedNodes;
78        info.damageAccumulator->popTransform();
79    }
80
81    //The purpose of next block of code is to reset projected display list if there are no
82    //backward projected nodes. This speeds up drawing, by avoiding an extra walk of the tree
83    if (mProjectionReceiver) {
84        mProjectionReceiver->setProjectedDisplayList(hasBackwardProjectedNodesSubtree ? this : nullptr);
85        info.hasBackwardProjectedNodes = hasBackwardProjectedNodesHere;
86    } else {
87        info.hasBackwardProjectedNodes = hasBackwardProjectedNodesSubtree
88                || hasBackwardProjectedNodesHere;
89    }
90
91    bool isDirty = false;
92    for (auto& vectorDrawable : mVectorDrawables) {
93        // If any vector drawable in the display list needs update, damage the node.
94        if (vectorDrawable->isDirty()) {
95            isDirty = true;
96            static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline())
97                ->getVectorDrawables()->push_back(vectorDrawable);
98        }
99        vectorDrawable->setPropertyChangeWillBeConsumed(true);
100    }
101    return isDirty;
102}
103
104void SkiaDisplayList::reset() {
105    mProjectionReceiver = nullptr;
106
107    mDisplayList.reset();
108
109    mMutableImages.clear();
110    mVectorDrawables.clear();
111    mChildFunctors.clear();
112    mChildNodes.clear();
113
114    projectionReceiveIndex = -1;
115    allocator.~LinearAllocator();
116    new (&allocator) LinearAllocator();
117}
118
119void SkiaDisplayList::output(std::ostream& output, uint32_t level) {
120    DumpOpsCanvas canvas(output, level, *this);
121    mDisplayList.draw(&canvas);
122}
123
124}; // namespace skiapipeline
125}; // namespace uirenderer
126}; // namespace android
127