• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #pragma once
18 
19 #include <SkCamera.h>
20 #include <SkMatrix.h>
21 
22 #include <utils/LinearAllocator.h>
23 #include <utils/RefBase.h>
24 #include <utils/String8.h>
25 
26 #include <cutils/compiler.h>
27 
28 #include <androidfw/ResourceTypes.h>
29 
30 #include <ui/FatVector.h>
31 
32 #include "AnimatorManager.h"
33 #include "CanvasTransform.h"
34 #include "Debug.h"
35 #include "DisplayList.h"
36 #include "Matrix.h"
37 #include "RenderProperties.h"
38 #include "pipeline/skia/HolePunch.h"
39 #include "pipeline/skia/SkiaDisplayList.h"
40 #include "pipeline/skia/SkiaLayer.h"
41 
42 #include <vector>
43 #include <pipeline/skia/StretchMask.h>
44 
45 class SkBitmap;
46 class SkPaint;
47 class SkPath;
48 class SkRegion;
49 class SkSurface;
50 
51 namespace android {
52 namespace uirenderer {
53 
54 class CanvasState;
55 class Rect;
56 class SkiaShader;
57 struct RenderNodeOp;
58 
59 class TreeInfo;
60 class TreeObserver;
61 
62 namespace proto {
63 class RenderNode;
64 }
65 
66 /**
67  * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display
68  * properties.
69  *
70  * Recording of canvas commands is somewhat similar to SkPicture, except the canvas-recording
71  * functionality is split between RecordingCanvas (which manages the recording), DisplayList
72  * (which holds the actual data), and RenderNode (which holds properties used for render playback).
73  *
74  * Note that DisplayList is swapped out from beneath an individual RenderNode when a view's
75  * recorded stream of canvas operations is refreshed. The RenderNode (and its properties) stay
76  * attached.
77  */
78 class RenderNode : public VirtualLightRefBase {
79     friend class TestUtils;  // allow TestUtils to access syncDisplayList / syncProperties
80 
81 public:
82     enum DirtyPropertyMask {
83         GENERIC = 1 << 1,
84         TRANSLATION_X = 1 << 2,
85         TRANSLATION_Y = 1 << 3,
86         TRANSLATION_Z = 1 << 4,
87         SCALE_X = 1 << 5,
88         SCALE_Y = 1 << 6,
89         ROTATION = 1 << 7,
90         ROTATION_X = 1 << 8,
91         ROTATION_Y = 1 << 9,
92         X = 1 << 10,
93         Y = 1 << 11,
94         Z = 1 << 12,
95         ALPHA = 1 << 13,
96         DISPLAY_LIST = 1 << 14,
97     };
98 
99     RenderNode();
100     virtual ~RenderNode();
101 
102     // See flags defined in DisplayList.java
103     enum ReplayFlag { kReplayFlag_ClipChildren = 0x1 };
104 
105     void setStagingDisplayList(DisplayList&& newData);
106     void discardStagingDisplayList();
107 
108     void output();
109     int getUsageSize();
110     int getAllocatedSize();
111 
isRenderable()112     bool isRenderable() const { return mDisplayList.hasContent(); }
113 
hasProjectionReceiver()114     bool hasProjectionReceiver() const {
115         return mDisplayList.containsProjectionReceiver();
116     }
117 
getName()118     const char* getName() const { return mName.string(); }
119 
setName(const char * name)120     void setName(const char* name) {
121         if (name) {
122             const char* lastPeriod = strrchr(name, '.');
123             if (lastPeriod) {
124                 mName.setTo(lastPeriod + 1);
125             } else {
126                 mName.setTo(name);
127             }
128         }
129     }
130 
getStretchMask()131     StretchMask& getStretchMask() { return mStretchMask; }
132 
getUserContext()133     VirtualLightRefBase* getUserContext() const { return mUserContext.get(); }
134 
setUserContext(VirtualLightRefBase * context)135     void setUserContext(VirtualLightRefBase* context) { mUserContext = context; }
136 
isPropertyFieldDirty(DirtyPropertyMask field)137     bool isPropertyFieldDirty(DirtyPropertyMask field) const {
138         return mDirtyPropertyFields & field;
139     }
140 
setPropertyFieldsDirty(uint32_t fields)141     void setPropertyFieldsDirty(uint32_t fields) { mDirtyPropertyFields |= fields; }
142 
properties()143     const RenderProperties& properties() const { return mProperties; }
144 
animatorProperties()145     RenderProperties& animatorProperties() { return mProperties; }
146 
stagingProperties()147     const RenderProperties& stagingProperties() { return mStagingProperties; }
148 
mutateStagingProperties()149     RenderProperties& mutateStagingProperties() { return mStagingProperties; }
150 
isValid()151     bool isValid() { return mValid; }
152 
getWidth()153     int getWidth() const { return properties().getWidth(); }
154 
getHeight()155     int getHeight() const { return properties().getHeight(); }
156 
157     virtual void prepareTree(TreeInfo& info);
158     void destroyHardwareResources(TreeInfo* info = nullptr);
159     void destroyLayers();
160 
161     // UI thread only!
162     void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
163     void removeAnimator(const sp<BaseRenderNodeAnimator>& animator);
164 
165     // This can only happen during pushStaging()
onAnimatorTargetChanged(BaseRenderNodeAnimator * animator)166     void onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
167         mAnimatorManager.onAnimatorTargetChanged(animator);
168     }
169 
animators()170     AnimatorManager& animators() { return mAnimatorManager; }
171 
172     void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false) const;
173 
nothingToDraw()174     bool nothingToDraw() const {
175         const Outline& outline = properties().getOutline();
176         return !mDisplayList.isValid() || properties().getAlpha() <= 0 ||
177                (outline.getShouldClip() && outline.isEmpty()) || properties().getScaleX() == 0 ||
178                properties().getScaleY() == 0;
179     }
180 
getDisplayList()181     const DisplayList& getDisplayList() const { return mDisplayList; }
182     // TODO: can this be cleaned up?
getDisplayList()183     DisplayList& getDisplayList() { return mDisplayList; }
184 
185     // Note: The position callbacks are relying on the listener using
186     // the frameNumber to appropriately batch/synchronize these transactions.
187     // There is no other filtering/batching to ensure that only the "final"
188     // state called once per frame.
189     class PositionListener : public VirtualLightRefBase {
190     public:
~PositionListener()191         virtual ~PositionListener() {}
192         // Called when the RenderNode's position changes
193         virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) = 0;
194         // Called when the RenderNode no longer has a position. As in, it's
195         // no longer being drawn.
196         // Note, tree info might be null
197         virtual void onPositionLost(RenderNode& node, const TreeInfo* info) = 0;
198     };
199 
setPositionListener(PositionListener * listener)200     void setPositionListener(PositionListener* listener) {
201         mStagingPositionListener = listener;
202         mPositionListenerDirty = true;
203     }
204 
205     // This is only modified in MODE_FULL, so it can be safely accessed
206     // on the UI thread.
hasParents()207     bool hasParents() { return mParentCount; }
208 
209     void onRemovedFromTree(TreeInfo* info);
210 
211     // Called by CanvasContext to promote a RenderNode to be a root node
makeRoot()212     void makeRoot() { incParentRefCount(); }
213 
214     // Called by CanvasContext when it drops a RenderNode from being a root node
215     void clearRoot();
216 
217     void output(std::ostream& output, uint32_t level);
218 
setUsageHint(UsageHint usageHint)219     void setUsageHint(UsageHint usageHint) { mUsageHint = usageHint; }
220 
usageHint()221     UsageHint usageHint() const { return mUsageHint; }
222 
uniqueId()223     int64_t uniqueId() const { return mUniqueId; }
224 
225     void markDrawStart(SkCanvas& canvas);
226     void markDrawEnd(SkCanvas& canvas);
227 
228 private:
229     void computeOrderingImpl(RenderNodeOp* opState,
230                              std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface,
231                              const mat4* transformFromProjectionSurface);
232 
233     void syncProperties();
234     void syncDisplayList(TreeObserver& observer, TreeInfo* info);
235     void handleForceDark(TreeInfo* info);
236 
237     void prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer);
238     void pushStagingPropertiesChanges(TreeInfo& info);
239     void pushStagingDisplayListChanges(TreeObserver& observer, TreeInfo& info);
240     void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
241     void pushLayerUpdate(TreeInfo& info);
242     void deleteDisplayList(TreeObserver& observer, TreeInfo* info = nullptr);
243     void damageSelf(TreeInfo& info);
244 
incParentRefCount()245     void incParentRefCount() { mParentCount++; }
246     void decParentRefCount(TreeObserver& observer, TreeInfo* info = nullptr);
247 
248     const int64_t mUniqueId;
249     String8 mName;
250     sp<VirtualLightRefBase> mUserContext;
251 
252     uint32_t mDirtyPropertyFields;
253     RenderProperties mProperties;
254     RenderProperties mStagingProperties;
255 
256     // Owned by UI. Set when DL is set, cleared when DL cleared or when node detached
257     // (likely by parent re-record/removal)
258     bool mValid = false;
259 
260     bool mNeedsDisplayListSync;
261     // WARNING: Do not delete this directly, you must go through deleteDisplayList()!
262     DisplayList mDisplayList;
263     DisplayList mStagingDisplayList;
264 
265     int64_t mDamageGenerationId;
266 
267     friend class AnimatorManager;
268     AnimatorManager mAnimatorManager;
269 
270     /**
271      * Draw time state - these properties are only set and used during rendering
272      */
273 
274     // for projection surfaces, contains a list of all children items
275     std::vector<RenderNodeOp*> mProjectedNodes;
276 
277     // How many references our parent(s) have to us. Typically this should alternate
278     // between 2 and 1 (when a staging push happens we inc first then dec)
279     // When this hits 0 we are no longer in the tree, so any hardware resources
280     // (specifically Layers) should be released.
281     // This is *NOT* thread-safe, and should therefore only be tracking
282     // mDisplayList, not mStagingDisplayList.
283     uint32_t mParentCount;
284 
285     bool mPositionListenerDirty = false;
286     sp<PositionListener> mStagingPositionListener;
287     sp<PositionListener> mPositionListener;
288 
289     UsageHint mUsageHint = UsageHint::Unknown;
290 
291     bool mHasHolePunches;
292     StretchMask mStretchMask;
293 
294     // METHODS & FIELDS ONLY USED BY THE SKIA RENDERER
295 public:
296     /**
297      * Detach and transfer ownership of an already allocated displayList for use
298      * in recording updated content for this renderNode
299      */
detachAvailableList()300     std::unique_ptr<skiapipeline::SkiaDisplayList> detachAvailableList() {
301         return std::move(mAvailableDisplayList);
302     }
303 
hasHolePunches()304     bool hasHolePunches() { return mHasHolePunches; }
305 
306     /**
307      * Attach unused displayList to this node for potential future reuse.
308      */
attachAvailableList(skiapipeline::SkiaDisplayList * skiaDisplayList)309     void attachAvailableList(skiapipeline::SkiaDisplayList* skiaDisplayList) {
310         mAvailableDisplayList.reset(skiaDisplayList);
311     }
312 
313     /**
314      * Returns true if an offscreen layer from any renderPipeline is attached
315      * to this node.
316      */
hasLayer()317     bool hasLayer() const { return mSkiaLayer.get(); }
318 
319     /**
320      * Used by the RenderPipeline to attach an offscreen surface to the RenderNode.
321      * The surface is then will be used to store the contents of a layer.
322      */
setLayerSurface(sk_sp<SkSurface> layer)323     void setLayerSurface(sk_sp<SkSurface> layer) {
324         if (layer.get()) {
325             if (!mSkiaLayer.get()) {
326                 mSkiaLayer = std::make_unique<skiapipeline::SkiaLayer>();
327             }
328             mSkiaLayer->layerSurface = std::move(layer);
329             mSkiaLayer->inverseTransformInWindow.loadIdentity();
330         } else {
331             mSkiaLayer.reset();
332         }
333 
334         mProperties.mutateLayerProperties().mutableStretchEffect().clear();
335         mStretchMask.clear();
336         // Clear out the previous snapshot and the image filter the previous
337         // snapshot was created with whenever the layer changes.
338         mSnapshotResult.snapshot = nullptr;
339         mTargetImageFilter = nullptr;
340     }
341 
342     /**
343      * If the RenderNode is of type LayerType::RenderLayer then this method will
344      * return the an offscreen rendering surface that is used to both render into
345      * the layer and composite the layer into its parent.  If the type is not
346      * LayerType::RenderLayer then it will return a nullptr.
347      *
348      * NOTE: this function is only guaranteed to return accurate results after
349      *       prepareTree has been run for this RenderNode
350      */
getLayerSurface()351     SkSurface* getLayerSurface() const {
352         return mSkiaLayer.get() ? mSkiaLayer->layerSurface.get() : nullptr;
353     }
354 
355     struct SnapshotResult {
356         sk_sp<SkImage> snapshot;
357         SkIRect outSubset;
358         SkIPoint outOffset;
359     };
360 
361     std::optional<SnapshotResult> updateSnapshotIfRequired(GrRecordingContext* context,
362                                             const SkImageFilter* imageFilter,
363                                             const SkIRect& clipBounds);
364 
getSkiaLayer()365     skiapipeline::SkiaLayer* getSkiaLayer() const { return mSkiaLayer.get(); }
366 
367     /**
368      * Returns the path that represents the outline of RenderNode intersected with
369      * the provided rect.  This call will internally cache the resulting path in
370      * order to potentially return that path for subsequent calls to this method.
371      * By reusing the same path we get better performance on the GPU backends since
372      * those resources are cached in the hardware based on the path's genID.
373      *
374      * The returned path is only guaranteed to be valid until this function is called
375      * again or the RenderNode's outline is mutated.
376      */
377     const SkPath* getClippedOutline(const SkRect& clipRect) const;
378 
379 private:
380     /**
381      * If this RenderNode has been used in a previous frame then the SkiaDisplayList
382      * from that frame is cached here until one of the following conditions is met:
383      *  1) The RenderNode is deleted (causing this to be deleted)
384      *  2) It is replaced with the displayList from the next completed frame
385      *  3) It is detached and used to to record a new displayList for a later frame
386      */
387     std::unique_ptr<skiapipeline::SkiaDisplayList> mAvailableDisplayList;
388 
389     /**
390      * An offscreen rendering target used to contain the contents this RenderNode
391      * when it has been set to draw as a LayerType::RenderLayer.
392      */
393     std::unique_ptr<skiapipeline::SkiaLayer> mSkiaLayer;
394 
395     /**
396      * SkImageFilter used to create the mSnapshotResult
397      */
398     sk_sp<SkImageFilter> mTargetImageFilter;
399     uint32_t mTargetImageFilterLayerSurfaceGenerationId = 0;
400 
401     /**
402      * Clip bounds used to create the mSnapshotResult
403      */
404     SkIRect mImageFilterClipBounds;
405 
406     /**
407      * Result of the most recent snapshot with additional metadata used to
408      * determine how to draw the contents
409      */
410     SnapshotResult mSnapshotResult;
411 
412     struct ClippedOutlineCache {
413         // keys
414         uint32_t outlineID = 0;
415         SkRect clipRect;
416 
417         // value
418         SkPath clippedOutline;
419     };
420     mutable ClippedOutlineCache mClippedOutlineCache;
421 };  // class RenderNode
422 
423 class MarkAndSweepRemoved : public TreeObserver {
424     PREVENT_COPY_AND_ASSIGN(MarkAndSweepRemoved);
425 
426 public:
MarkAndSweepRemoved(TreeInfo * info)427     explicit MarkAndSweepRemoved(TreeInfo* info) : mTreeInfo(info) {}
428 
onMaybeRemovedFromTree(RenderNode * node)429     void onMaybeRemovedFromTree(RenderNode* node) override { mMarked.emplace_back(node); }
430 
~MarkAndSweepRemoved()431     ~MarkAndSweepRemoved() {
432         for (auto& node : mMarked) {
433             if (!node->hasParents()) {
434                 node->onRemovedFromTree(mTreeInfo);
435             }
436         }
437     }
438 
439 private:
440     FatVector<sp<RenderNode>, 10> mMarked;
441     TreeInfo* mTreeInfo;
442 };
443 
444 } /* namespace uirenderer */
445 } /* namespace android */
446