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