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