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