1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SkiaDisplayList.h"
#include "DumpOpsCanvas.h"
#include "SkiaPipeline.h"
#include "VectorDrawable.h"
#include "renderthread/CanvasContext.h"
#include <SkImagePriv.h>
#include <SkPathOps.h>
namespace android {
namespace uirenderer {
namespace skiapipeline {
void SkiaDisplayList::syncContents(const WebViewSyncData& data) {
for (auto& functor : mChildFunctors) {
functor->syncFunctor(data);
}
for (auto& animatedImage : mAnimatedImages) {
animatedImage->syncProperties();
}
for (auto& vectorDrawable : mVectorDrawables) {
vectorDrawable.first->syncProperties();
}
}
bool SkiaDisplayList::reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) {
reset();
node->attachAvailableList(this);
return true;
}
void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) {
for (auto& child : mChildNodes) {
updateFn(child.getRenderNode());
}
}
static bool intersects(const SkISize screenSize, const Matrix4& mat, const SkRect& bounds) {
Vector3 points[] = { Vector3 {bounds.fLeft, bounds.fTop, 0},
Vector3 {bounds.fRight, bounds.fTop, 0},
Vector3 {bounds.fRight, bounds.fBottom, 0},
Vector3 {bounds.fLeft, bounds.fBottom, 0}};
float minX, minY, maxX, maxY;
bool first = true;
for (auto& point : points) {
mat.mapPoint3d(point);
if (first) {
minX = maxX = point.x;
minY = maxY = point.y;
first = false;
} else {
minX = std::min(minX, point.x);
minY = std::min(minY, point.y);
maxX = std::max(maxX, point.x);
maxY = std::max(maxY, point.y);
}
}
return SkRect::Make(screenSize).intersects(SkRect::MakeLTRB(minX, minY, maxX, maxY));
}
bool SkiaDisplayList::prepareListAndChildren(
TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
// If the prepare tree is triggered by the UI thread and no previous call to
// pinImages has failed then we must pin all mutable images in the GPU cache
// until the next UI thread draw.
if (info.prepareTextures && !info.canvasContext.pinImages(mMutableImages)) {
// In the event that pinning failed we prevent future pinImage calls for the
// remainder of this tree traversal and also unpin any currently pinned images
// to free up GPU resources.
info.prepareTextures = false;
info.canvasContext.unpinImages();
}
bool hasBackwardProjectedNodesHere = false;
bool hasBackwardProjectedNodesSubtree = false;
for (auto& child : mChildNodes) {
hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards();
RenderNode* childNode = child.getRenderNode();
Matrix4 mat4(child.getRecordedMatrix());
info.damageAccumulator->pushTransform(&mat4);
info.hasBackwardProjectedNodes = false;
childFn(childNode, observer, info, functorsNeedLayer);
hasBackwardProjectedNodesSubtree |= info.hasBackwardProjectedNodes;
info.damageAccumulator->popTransform();
}
// The purpose of next block of code is to reset projected display list if there are no
// backward projected nodes. This speeds up drawing, by avoiding an extra walk of the tree
if (mProjectionReceiver) {
mProjectionReceiver->setProjectedDisplayList(hasBackwardProjectedNodesSubtree ? this
: nullptr);
info.hasBackwardProjectedNodes = hasBackwardProjectedNodesHere;
} else {
info.hasBackwardProjectedNodes =
hasBackwardProjectedNodesSubtree || hasBackwardProjectedNodesHere;
}
bool isDirty = false;
for (auto& animatedImage : mAnimatedImages) {
nsecs_t timeTilNextFrame = TreeInfo::Out::kNoAnimatedImageDelay;
// If any animated image in the display list needs updated, then damage the node.
if (animatedImage->isDirty(&timeTilNextFrame)) {
isDirty = true;
}
if (animatedImage->isRunning() &&
timeTilNextFrame != TreeInfo::Out::kNoAnimatedImageDelay) {
auto& delay = info.out.animatedImageDelay;
if (delay == TreeInfo::Out::kNoAnimatedImageDelay || timeTilNextFrame < delay) {
delay = timeTilNextFrame;
}
}
}
for (auto& vectorDrawablePair : mVectorDrawables) {
// If any vector drawable in the display list needs update, damage the node.
auto& vectorDrawable = vectorDrawablePair.first;
if (vectorDrawable->isDirty()) {
Matrix4 totalMatrix;
info.damageAccumulator->computeCurrentTransform(&totalMatrix);
Matrix4 canvasMatrix(vectorDrawablePair.second);
totalMatrix.multiply(canvasMatrix);
const SkRect& bounds = vectorDrawable->properties().getBounds();
if (intersects(info.screenSize, totalMatrix, bounds)) {
isDirty = true;
static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline())
->getVectorDrawables()
->push_back(vectorDrawable);
vectorDrawable->setPropertyChangeWillBeConsumed(true);
}
}
}
return isDirty;
}
void SkiaDisplayList::reset() {
mProjectionReceiver = nullptr;
mDisplayList.reset();
mMutableImages.clear();
mVectorDrawables.clear();
mAnimatedImages.clear();
mChildFunctors.clear();
mChildNodes.clear();
allocator.~LinearAllocator();
new (&allocator) LinearAllocator();
}
void SkiaDisplayList::output(std::ostream& output, uint32_t level) {
DumpOpsCanvas canvas(output, level, *this);
mDisplayList.draw(&canvas);
}
} // namespace skiapipeline
} // namespace uirenderer
} // namespace android
|