Loading libs/hwui/Android.mk +3 −1 Original line number Original line Diff line number Diff line Loading @@ -276,7 +276,9 @@ LOCAL_MULTILIB := both LOCAL_MODULE_STEM_32 := hwuimicro LOCAL_MODULE_STEM_32 := hwuimicro LOCAL_MODULE_STEM_64 := hwuimicro64 LOCAL_MODULE_STEM_64 := hwuimicro64 LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries) LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries) LOCAL_CFLAGS := $(hwui_cflags) LOCAL_CFLAGS := \ $(hwui_cflags) \ -DHWUI_NULL_GPU LOCAL_C_INCLUDES += bionic/benchmarks/ LOCAL_C_INCLUDES += bionic/benchmarks/ LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static_null_gpu LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static_null_gpu Loading libs/hwui/DisplayList.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -132,7 +132,7 @@ public: DisplayList(); DisplayList(); ~DisplayList(); ~DisplayList(); // index of DisplayListOp restore, after which projected descendents should be drawn // index of DisplayListOp restore, after which projected descendants should be drawn int projectionReceiveIndex; int projectionReceiveIndex; const LsaVector<Chunk>& getChunks() const { return chunks; } const LsaVector<Chunk>& getChunks() const { return chunks; } Loading libs/hwui/DisplayListCanvas.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -55,6 +55,7 @@ class DeferredDisplayList; class DeferredLayerUpdater; class DeferredLayerUpdater; class DisplayListOp; class DisplayListOp; class DrawOp; class DrawOp; class DrawRenderNodeOp; class RenderNode; class RenderNode; class StateOp; class StateOp; Loading libs/hwui/DisplayListOp.h +7 −7 Original line number Original line Diff line number Diff line Loading @@ -1386,19 +1386,19 @@ public: : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr) : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr) , renderNode(renderNode) , renderNode(renderNode) , mRecordedWithPotentialStencilClip(!clipIsSimple || !transformFromParent.isSimple()) , mRecordedWithPotentialStencilClip(!clipIsSimple || !transformFromParent.isSimple()) , mTransformFromParent(transformFromParent) , localMatrix(transformFromParent) , mSkipInOrderDraw(false) {} , skipInOrderDraw(false) {} virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, bool useQuickReject) override { bool useQuickReject) override { if (renderNode->isRenderable() && !mSkipInOrderDraw) { if (renderNode->isRenderable() && !skipInOrderDraw) { renderNode->defer(deferStruct, level + 1); renderNode->defer(deferStruct, level + 1); } } } } virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, bool useQuickReject) override { bool useQuickReject) override { if (renderNode->isRenderable() && !mSkipInOrderDraw) { if (renderNode->isRenderable() && !skipInOrderDraw) { renderNode->replay(replayStruct, level + 1); renderNode->replay(replayStruct, level + 1); } } } } Loading Loading @@ -1439,7 +1439,7 @@ private: /** /** * Records transform vs parent, used for computing total transform without rerunning DL contents * Records transform vs parent, used for computing total transform without rerunning DL contents */ */ const mat4 mTransformFromParent; const mat4 localMatrix; /** /** * Holds the transformation between the projection surface ViewGroup and this RenderNode * Holds the transformation between the projection surface ViewGroup and this RenderNode Loading @@ -1449,8 +1449,8 @@ private: * * * Note: doesn't include transformation within the RenderNode, or its properties. * Note: doesn't include transformation within the RenderNode, or its properties. */ */ mat4 mTransformFromCompositingAncestor; mat4 transformFromCompositingAncestor; bool mSkipInOrderDraw; bool skipInOrderDraw; }; }; /** /** Loading libs/hwui/OpReorderer.cpp +49 −20 Original line number Original line Diff line number Diff line Loading @@ -330,6 +330,7 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, for (int i = layers.entries().size() - 1; i >= 0; i--) { for (int i = layers.entries().size() - 1; i >= 0; i--) { RenderNode* layerNode = layers.entries()[i].renderNode; RenderNode* layerNode = layers.entries()[i].renderNode; const Rect& layerDamage = layers.entries()[i].damage; const Rect& layerDamage = layers.entries()[i].damage; layerNode->computeOrdering(); // map current light center into RenderNode's coordinate space // map current light center into RenderNode's coordinate space Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter(); Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter(); Loading @@ -339,7 +340,7 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, layerDamage, lightCenter, nullptr, layerNode); layerDamage, lightCenter, nullptr, layerNode); if (layerNode->getDisplayList()) { if (layerNode->getDisplayList()) { deferDisplayList(*(layerNode->getDisplayList())); deferNodeOps(*layerNode); } } restoreForLayer(); restoreForLayer(); } } Loading @@ -347,6 +348,7 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, // Defer Fbo0 // Defer Fbo0 for (const sp<RenderNode>& node : nodes) { for (const sp<RenderNode>& node : nodes) { if (node->nothingToDraw()) continue; if (node->nothingToDraw()) continue; node->computeOrdering(); int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); deferNodePropsAndOps(*node); deferNodePropsAndOps(*node); Loading @@ -354,20 +356,6 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, } } } } OpReorderer::OpReorderer(int viewportWidth, int viewportHeight, const DisplayList& displayList, const Vector3& lightCenter) : mCanvasState(*this) { ATRACE_NAME("prepare drawing commands"); // Prepare to defer Fbo0 mLayerReorderers.emplace_back(viewportWidth, viewportHeight, Rect(viewportWidth, viewportHeight)); mLayerStack.push_back(0); mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, 0, 0, viewportWidth, viewportHeight, lightCenter); deferDisplayList(displayList); } void OpReorderer::onViewportInitialized() {} void OpReorderer::onViewportInitialized() {} void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} Loading Loading @@ -462,10 +450,10 @@ void OpReorderer::deferNodePropsAndOps(RenderNode& node) { Matrix4::identity(), Matrix4::identity(), saveLayerBounds, saveLayerBounds, &saveLayerPaint)); &saveLayerPaint)); deferDisplayList(*(node.getDisplayList())); deferNodeOps(node); onEndLayerOp(*new (mAllocator) EndLayerOp()); onEndLayerOp(*new (mAllocator) EndLayerOp()); } else { } else { deferDisplayList(*(node.getDisplayList())); deferNodeOps(node); } } } } } } Loading Loading @@ -610,18 +598,53 @@ void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) { } } } } void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) { const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath(); int count = mCanvasState.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); // can't be null, since DL=null node rejection happens before deferNodePropsAndOps const DisplayList& displayList = *(renderNode.getDisplayList()); const RecordedOp* op = (displayList.getOps()[displayList.projectionReceiveIndex]); const RenderNodeOp* backgroundOp = static_cast<const RenderNodeOp*>(op); const RenderProperties& backgroundProps = backgroundOp->renderNode->properties(); // Transform renderer to match background we're projecting onto // (by offsetting canvas by translationX/Y of background rendernode, since only those are set) mCanvasState.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY()); // If the projection receiver has an outline, we mask projected content to it // (which we know, apriori, are all tessellated paths) mCanvasState.setProjectionPathMask(mAllocator, projectionReceiverOutline); // draw projected nodes for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) { RenderNodeOp* childOp = renderNode.mProjectedNodes[i]; int restoreTo = mCanvasState.save(SkCanvas::kMatrix_SaveFlag); mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor); deferRenderNodeOp(*childOp); mCanvasState.restoreToCount(restoreTo); } mCanvasState.restoreToCount(count); } /** /** * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods. * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods. * * * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. E.g. a * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. * BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&) * E.g. a BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&) */ */ #define OP_RECEIVER(Type) \ #define OP_RECEIVER(Type) \ [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); }, [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); }, void OpReorderer::deferDisplayList(const DisplayList& displayList) { void OpReorderer::deferNodeOps(const RenderNode& renderNode) { static std::function<void(OpReorderer& reorderer, const RecordedOp&)> receivers[] = { static std::function<void(OpReorderer& reorderer, const RecordedOp&)> receivers[] = { MAP_OPS(OP_RECEIVER) MAP_OPS(OP_RECEIVER) }; }; // can't be null, since DL=null node rejection happens before deferNodePropsAndOps const DisplayList& displayList = *(renderNode.getDisplayList()); for (const DisplayList::Chunk& chunk : displayList.getChunks()) { for (const DisplayList::Chunk& chunk : displayList.getChunks()) { FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes; FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes; buildZSortedChildList(&zTranslatedNodes, displayList, chunk); buildZSortedChildList(&zTranslatedNodes, displayList, chunk); Loading @@ -630,6 +653,12 @@ void OpReorderer::deferDisplayList(const DisplayList& displayList) { for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { const RecordedOp* op = displayList.getOps()[opIndex]; const RecordedOp* op = displayList.getOps()[opIndex]; receivers[op->opId](*this, *op); receivers[op->opId](*this, *op); if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty() && displayList.projectionReceiveIndex >= 0 && static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) { deferProjectedChildren(renderNode); } } } defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes); defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes); } } Loading Loading
libs/hwui/Android.mk +3 −1 Original line number Original line Diff line number Diff line Loading @@ -276,7 +276,9 @@ LOCAL_MULTILIB := both LOCAL_MODULE_STEM_32 := hwuimicro LOCAL_MODULE_STEM_32 := hwuimicro LOCAL_MODULE_STEM_64 := hwuimicro64 LOCAL_MODULE_STEM_64 := hwuimicro64 LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries) LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries) LOCAL_CFLAGS := $(hwui_cflags) LOCAL_CFLAGS := \ $(hwui_cflags) \ -DHWUI_NULL_GPU LOCAL_C_INCLUDES += bionic/benchmarks/ LOCAL_C_INCLUDES += bionic/benchmarks/ LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static_null_gpu LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static_null_gpu Loading
libs/hwui/DisplayList.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -132,7 +132,7 @@ public: DisplayList(); DisplayList(); ~DisplayList(); ~DisplayList(); // index of DisplayListOp restore, after which projected descendents should be drawn // index of DisplayListOp restore, after which projected descendants should be drawn int projectionReceiveIndex; int projectionReceiveIndex; const LsaVector<Chunk>& getChunks() const { return chunks; } const LsaVector<Chunk>& getChunks() const { return chunks; } Loading
libs/hwui/DisplayListCanvas.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -55,6 +55,7 @@ class DeferredDisplayList; class DeferredLayerUpdater; class DeferredLayerUpdater; class DisplayListOp; class DisplayListOp; class DrawOp; class DrawOp; class DrawRenderNodeOp; class RenderNode; class RenderNode; class StateOp; class StateOp; Loading
libs/hwui/DisplayListOp.h +7 −7 Original line number Original line Diff line number Diff line Loading @@ -1386,19 +1386,19 @@ public: : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr) : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr) , renderNode(renderNode) , renderNode(renderNode) , mRecordedWithPotentialStencilClip(!clipIsSimple || !transformFromParent.isSimple()) , mRecordedWithPotentialStencilClip(!clipIsSimple || !transformFromParent.isSimple()) , mTransformFromParent(transformFromParent) , localMatrix(transformFromParent) , mSkipInOrderDraw(false) {} , skipInOrderDraw(false) {} virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, bool useQuickReject) override { bool useQuickReject) override { if (renderNode->isRenderable() && !mSkipInOrderDraw) { if (renderNode->isRenderable() && !skipInOrderDraw) { renderNode->defer(deferStruct, level + 1); renderNode->defer(deferStruct, level + 1); } } } } virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, bool useQuickReject) override { bool useQuickReject) override { if (renderNode->isRenderable() && !mSkipInOrderDraw) { if (renderNode->isRenderable() && !skipInOrderDraw) { renderNode->replay(replayStruct, level + 1); renderNode->replay(replayStruct, level + 1); } } } } Loading Loading @@ -1439,7 +1439,7 @@ private: /** /** * Records transform vs parent, used for computing total transform without rerunning DL contents * Records transform vs parent, used for computing total transform without rerunning DL contents */ */ const mat4 mTransformFromParent; const mat4 localMatrix; /** /** * Holds the transformation between the projection surface ViewGroup and this RenderNode * Holds the transformation between the projection surface ViewGroup and this RenderNode Loading @@ -1449,8 +1449,8 @@ private: * * * Note: doesn't include transformation within the RenderNode, or its properties. * Note: doesn't include transformation within the RenderNode, or its properties. */ */ mat4 mTransformFromCompositingAncestor; mat4 transformFromCompositingAncestor; bool mSkipInOrderDraw; bool skipInOrderDraw; }; }; /** /** Loading
libs/hwui/OpReorderer.cpp +49 −20 Original line number Original line Diff line number Diff line Loading @@ -330,6 +330,7 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, for (int i = layers.entries().size() - 1; i >= 0; i--) { for (int i = layers.entries().size() - 1; i >= 0; i--) { RenderNode* layerNode = layers.entries()[i].renderNode; RenderNode* layerNode = layers.entries()[i].renderNode; const Rect& layerDamage = layers.entries()[i].damage; const Rect& layerDamage = layers.entries()[i].damage; layerNode->computeOrdering(); // map current light center into RenderNode's coordinate space // map current light center into RenderNode's coordinate space Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter(); Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter(); Loading @@ -339,7 +340,7 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, layerDamage, lightCenter, nullptr, layerNode); layerDamage, lightCenter, nullptr, layerNode); if (layerNode->getDisplayList()) { if (layerNode->getDisplayList()) { deferDisplayList(*(layerNode->getDisplayList())); deferNodeOps(*layerNode); } } restoreForLayer(); restoreForLayer(); } } Loading @@ -347,6 +348,7 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, // Defer Fbo0 // Defer Fbo0 for (const sp<RenderNode>& node : nodes) { for (const sp<RenderNode>& node : nodes) { if (node->nothingToDraw()) continue; if (node->nothingToDraw()) continue; node->computeOrdering(); int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); deferNodePropsAndOps(*node); deferNodePropsAndOps(*node); Loading @@ -354,20 +356,6 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, } } } } OpReorderer::OpReorderer(int viewportWidth, int viewportHeight, const DisplayList& displayList, const Vector3& lightCenter) : mCanvasState(*this) { ATRACE_NAME("prepare drawing commands"); // Prepare to defer Fbo0 mLayerReorderers.emplace_back(viewportWidth, viewportHeight, Rect(viewportWidth, viewportHeight)); mLayerStack.push_back(0); mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, 0, 0, viewportWidth, viewportHeight, lightCenter); deferDisplayList(displayList); } void OpReorderer::onViewportInitialized() {} void OpReorderer::onViewportInitialized() {} void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} Loading Loading @@ -462,10 +450,10 @@ void OpReorderer::deferNodePropsAndOps(RenderNode& node) { Matrix4::identity(), Matrix4::identity(), saveLayerBounds, saveLayerBounds, &saveLayerPaint)); &saveLayerPaint)); deferDisplayList(*(node.getDisplayList())); deferNodeOps(node); onEndLayerOp(*new (mAllocator) EndLayerOp()); onEndLayerOp(*new (mAllocator) EndLayerOp()); } else { } else { deferDisplayList(*(node.getDisplayList())); deferNodeOps(node); } } } } } } Loading Loading @@ -610,18 +598,53 @@ void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) { } } } } void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) { const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath(); int count = mCanvasState.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); // can't be null, since DL=null node rejection happens before deferNodePropsAndOps const DisplayList& displayList = *(renderNode.getDisplayList()); const RecordedOp* op = (displayList.getOps()[displayList.projectionReceiveIndex]); const RenderNodeOp* backgroundOp = static_cast<const RenderNodeOp*>(op); const RenderProperties& backgroundProps = backgroundOp->renderNode->properties(); // Transform renderer to match background we're projecting onto // (by offsetting canvas by translationX/Y of background rendernode, since only those are set) mCanvasState.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY()); // If the projection receiver has an outline, we mask projected content to it // (which we know, apriori, are all tessellated paths) mCanvasState.setProjectionPathMask(mAllocator, projectionReceiverOutline); // draw projected nodes for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) { RenderNodeOp* childOp = renderNode.mProjectedNodes[i]; int restoreTo = mCanvasState.save(SkCanvas::kMatrix_SaveFlag); mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor); deferRenderNodeOp(*childOp); mCanvasState.restoreToCount(restoreTo); } mCanvasState.restoreToCount(count); } /** /** * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods. * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods. * * * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. E.g. a * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. * BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&) * E.g. a BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&) */ */ #define OP_RECEIVER(Type) \ #define OP_RECEIVER(Type) \ [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); }, [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); }, void OpReorderer::deferDisplayList(const DisplayList& displayList) { void OpReorderer::deferNodeOps(const RenderNode& renderNode) { static std::function<void(OpReorderer& reorderer, const RecordedOp&)> receivers[] = { static std::function<void(OpReorderer& reorderer, const RecordedOp&)> receivers[] = { MAP_OPS(OP_RECEIVER) MAP_OPS(OP_RECEIVER) }; }; // can't be null, since DL=null node rejection happens before deferNodePropsAndOps const DisplayList& displayList = *(renderNode.getDisplayList()); for (const DisplayList::Chunk& chunk : displayList.getChunks()) { for (const DisplayList::Chunk& chunk : displayList.getChunks()) { FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes; FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes; buildZSortedChildList(&zTranslatedNodes, displayList, chunk); buildZSortedChildList(&zTranslatedNodes, displayList, chunk); Loading @@ -630,6 +653,12 @@ void OpReorderer::deferDisplayList(const DisplayList& displayList) { for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { const RecordedOp* op = displayList.getOps()[opIndex]; const RecordedOp* op = displayList.getOps()[opIndex]; receivers[op->opId](*this, *op); receivers[op->opId](*this, *op); if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty() && displayList.projectionReceiveIndex >= 0 && static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) { deferProjectedChildren(renderNode); } } } defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes); defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes); } } Loading