Loading libs/hwui/DisplayListOp.h +1 −0 Original line number Diff line number Diff line Loading @@ -1398,6 +1398,7 @@ class DrawRenderNodeOp : public DrawBoundedOp { friend class RenderNode; // grant RenderNode access to info of child friend class DisplayList; // grant DisplayList access to info of child friend class DisplayListCanvas; friend class TestUtils; public: DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent, bool clipIsSimple) : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr) Loading libs/hwui/OpReorderer.cpp +106 −8 Original line number Diff line number Diff line Loading @@ -16,12 +16,14 @@ #include "OpReorderer.h" #include "utils/PaintUtils.h" #include "RenderNode.h" #include "LayerUpdateQueue.h" #include "RenderNode.h" #include "utils/FatVector.h" #include "utils/PaintUtils.h" #include "SkCanvas.h" #include "utils/Trace.h" #include <SkCanvas.h> #include <utils/Trace.h> #include <utils/TypeHelpers.h> namespace android { namespace uirenderer { Loading Loading @@ -375,6 +377,93 @@ void OpReorderer::deferNodePropsAndOps(RenderNode& node) { } } typedef key_value_pair_t<float, const RenderNodeOp*> ZRenderNodeOpPair; template <typename V> static void buildZSortedChildList(V* zTranslatedNodes, const DisplayList& displayList, const DisplayList::Chunk& chunk) { if (chunk.beginChildIndex == chunk.endChildIndex) return; for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) { RenderNodeOp* childOp = displayList.getChildren()[i]; RenderNode* child = childOp->renderNode; float childZ = child->properties().getZ(); if (!MathUtils::isZero(childZ) && chunk.reorderChildren) { zTranslatedNodes->push_back(ZRenderNodeOpPair(childZ, childOp)); childOp->skipInOrderDraw = true; } else if (!child->properties().getProjectBackwards()) { // regular, in order drawing DisplayList childOp->skipInOrderDraw = false; } } // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order) std::stable_sort(zTranslatedNodes->begin(), zTranslatedNodes->end()); } template <typename V> static size_t findNonNegativeIndex(const V& zTranslatedNodes) { for (size_t i = 0; i < zTranslatedNodes.size(); i++) { if (zTranslatedNodes[i].key >= 0.0f) return i; } return zTranslatedNodes.size(); } template <typename V> void OpReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) { const int size = zTranslatedNodes.size(); if (size == 0 || (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f) || (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) { // no 3d children to draw return; } /** * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters * with very similar Z heights to draw together. * * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are * underneath both, and neither's shadow is drawn on top of the other. */ const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes); size_t drawIndex, shadowIndex, endIndex; if (mode == ChildrenSelectMode::Negative) { drawIndex = 0; endIndex = nonNegativeIndex; shadowIndex = endIndex; // draw no shadows } else { drawIndex = nonNegativeIndex; endIndex = size; shadowIndex = drawIndex; // potentially draw shadow for each pos Z child } float lastCasterZ = 0.0f; while (shadowIndex < endIndex || drawIndex < endIndex) { if (shadowIndex < endIndex) { const RenderNodeOp* casterNodeOp = zTranslatedNodes[shadowIndex].value; const float casterZ = zTranslatedNodes[shadowIndex].key; // attempt to render the shadow if the caster about to be drawn is its caster, // OR if its caster's Z value is similar to the previous potential caster if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) { deferShadow(*casterNodeOp); lastCasterZ = casterZ; // must do this even if current caster not casting a shadow shadowIndex++; continue; } } const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value; deferRenderNodeOp(*childOp); drawIndex++; } } void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) { // TODO } /** * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods. * Loading @@ -388,17 +477,20 @@ void OpReorderer::deferImpl(const DisplayList& displayList) { MAP_OPS(OP_RECEIVER) }; for (const DisplayList::Chunk& chunk : displayList.getChunks()) { FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes; buildZSortedChildList(&zTranslatedNodes, displayList, chunk); defer3dChildren(ChildrenSelectMode::Negative, zTranslatedNodes); for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { const RecordedOp* op = displayList.getOps()[opIndex]; receivers[op->opId](*this, *op); } defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes); } } void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) { if (op.renderNode->nothingToDraw()) { return; } void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) { if (op.renderNode->nothingToDraw()) return; int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); // apply state from RecordedOp Loading @@ -412,6 +504,12 @@ void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) { mCanvasState.restoreToCount(count); } void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) { if (!op.skipInOrderDraw) { deferRenderNodeOp(op); } } static batchid_t tessellatedBatchId(const SkPaint& paint) { return paint.getPathEffect() ? OpBatchType::AlphaMaskTexture Loading libs/hwui/OpReorderer.h +11 −0 Original line number Diff line number Diff line Loading @@ -182,6 +182,10 @@ public: virtual GLuint getTargetFbo() const override { return 0; } private: enum class ChildrenSelectMode { Negative, Positive }; void saveForLayer(uint32_t layerWidth, uint32_t layerHeight, const BeginLayerOp* beginLayerOp, RenderNode* renderNode); void restoreForLayer(); Loading @@ -195,8 +199,15 @@ private: // should always be surrounded by a save/restore pair void deferNodePropsAndOps(RenderNode& node); void deferShadow(const RenderNodeOp& casterOp); void deferImpl(const DisplayList& displayList); template <typename V> void defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes); void deferRenderNodeOp(const RenderNodeOp& op); void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers); /** Loading libs/hwui/RecordedOp.h +1 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,7 @@ struct RenderNodeOp : RecordedOp { : SUPER_PAINTLESS(RenderNodeOp) , renderNode(renderNode) {} RenderNode * renderNode; // not const, since drawing modifies it (somehow...) bool skipInOrderDraw = false; }; struct BitmapOp : RecordedOp { Loading libs/hwui/RecordingCanvas.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -40,7 +40,7 @@ void RecordingCanvas::reset(int width, int height) { mState.initializeSaveStack(width, height, 0, 0, width, height, Vector3()); mDeferredBarrierType = kBarrier_InOrder; mDeferredBarrierType = DeferredBarrierType::InOrder; mState.setDirtyClip(false); mRestoreSaveCount = -1; } Loading Loading @@ -432,17 +432,17 @@ size_t RecordingCanvas::addOp(RecordedOp* op) { // TODO: validate if "addDrawOp" quickrejection logic is useful before adding int insertIndex = mDisplayList->ops.size(); mDisplayList->ops.push_back(op); if (mDeferredBarrierType != kBarrier_None) { if (mDeferredBarrierType != DeferredBarrierType::None) { // op is first in new chunk mDisplayList->chunks.emplace_back(); DisplayList::Chunk& newChunk = mDisplayList->chunks.back(); newChunk.beginOpIndex = insertIndex; newChunk.endOpIndex = insertIndex + 1; newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder); newChunk.reorderChildren = (mDeferredBarrierType == DeferredBarrierType::OutOfOrder); int nextChildIndex = mDisplayList->children.size(); newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex; mDeferredBarrierType = kBarrier_None; mDeferredBarrierType = DeferredBarrierType::None; } else { // standard case - append to existing chunk mDisplayList->chunks.back().endOpIndex = insertIndex + 1; Loading Loading
libs/hwui/DisplayListOp.h +1 −0 Original line number Diff line number Diff line Loading @@ -1398,6 +1398,7 @@ class DrawRenderNodeOp : public DrawBoundedOp { friend class RenderNode; // grant RenderNode access to info of child friend class DisplayList; // grant DisplayList access to info of child friend class DisplayListCanvas; friend class TestUtils; public: DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent, bool clipIsSimple) : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr) Loading
libs/hwui/OpReorderer.cpp +106 −8 Original line number Diff line number Diff line Loading @@ -16,12 +16,14 @@ #include "OpReorderer.h" #include "utils/PaintUtils.h" #include "RenderNode.h" #include "LayerUpdateQueue.h" #include "RenderNode.h" #include "utils/FatVector.h" #include "utils/PaintUtils.h" #include "SkCanvas.h" #include "utils/Trace.h" #include <SkCanvas.h> #include <utils/Trace.h> #include <utils/TypeHelpers.h> namespace android { namespace uirenderer { Loading Loading @@ -375,6 +377,93 @@ void OpReorderer::deferNodePropsAndOps(RenderNode& node) { } } typedef key_value_pair_t<float, const RenderNodeOp*> ZRenderNodeOpPair; template <typename V> static void buildZSortedChildList(V* zTranslatedNodes, const DisplayList& displayList, const DisplayList::Chunk& chunk) { if (chunk.beginChildIndex == chunk.endChildIndex) return; for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) { RenderNodeOp* childOp = displayList.getChildren()[i]; RenderNode* child = childOp->renderNode; float childZ = child->properties().getZ(); if (!MathUtils::isZero(childZ) && chunk.reorderChildren) { zTranslatedNodes->push_back(ZRenderNodeOpPair(childZ, childOp)); childOp->skipInOrderDraw = true; } else if (!child->properties().getProjectBackwards()) { // regular, in order drawing DisplayList childOp->skipInOrderDraw = false; } } // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order) std::stable_sort(zTranslatedNodes->begin(), zTranslatedNodes->end()); } template <typename V> static size_t findNonNegativeIndex(const V& zTranslatedNodes) { for (size_t i = 0; i < zTranslatedNodes.size(); i++) { if (zTranslatedNodes[i].key >= 0.0f) return i; } return zTranslatedNodes.size(); } template <typename V> void OpReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) { const int size = zTranslatedNodes.size(); if (size == 0 || (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f) || (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) { // no 3d children to draw return; } /** * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters * with very similar Z heights to draw together. * * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are * underneath both, and neither's shadow is drawn on top of the other. */ const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes); size_t drawIndex, shadowIndex, endIndex; if (mode == ChildrenSelectMode::Negative) { drawIndex = 0; endIndex = nonNegativeIndex; shadowIndex = endIndex; // draw no shadows } else { drawIndex = nonNegativeIndex; endIndex = size; shadowIndex = drawIndex; // potentially draw shadow for each pos Z child } float lastCasterZ = 0.0f; while (shadowIndex < endIndex || drawIndex < endIndex) { if (shadowIndex < endIndex) { const RenderNodeOp* casterNodeOp = zTranslatedNodes[shadowIndex].value; const float casterZ = zTranslatedNodes[shadowIndex].key; // attempt to render the shadow if the caster about to be drawn is its caster, // OR if its caster's Z value is similar to the previous potential caster if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) { deferShadow(*casterNodeOp); lastCasterZ = casterZ; // must do this even if current caster not casting a shadow shadowIndex++; continue; } } const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value; deferRenderNodeOp(*childOp); drawIndex++; } } void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) { // TODO } /** * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods. * Loading @@ -388,17 +477,20 @@ void OpReorderer::deferImpl(const DisplayList& displayList) { MAP_OPS(OP_RECEIVER) }; for (const DisplayList::Chunk& chunk : displayList.getChunks()) { FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes; buildZSortedChildList(&zTranslatedNodes, displayList, chunk); defer3dChildren(ChildrenSelectMode::Negative, zTranslatedNodes); for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { const RecordedOp* op = displayList.getOps()[opIndex]; receivers[op->opId](*this, *op); } defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes); } } void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) { if (op.renderNode->nothingToDraw()) { return; } void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) { if (op.renderNode->nothingToDraw()) return; int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); // apply state from RecordedOp Loading @@ -412,6 +504,12 @@ void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) { mCanvasState.restoreToCount(count); } void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) { if (!op.skipInOrderDraw) { deferRenderNodeOp(op); } } static batchid_t tessellatedBatchId(const SkPaint& paint) { return paint.getPathEffect() ? OpBatchType::AlphaMaskTexture Loading
libs/hwui/OpReorderer.h +11 −0 Original line number Diff line number Diff line Loading @@ -182,6 +182,10 @@ public: virtual GLuint getTargetFbo() const override { return 0; } private: enum class ChildrenSelectMode { Negative, Positive }; void saveForLayer(uint32_t layerWidth, uint32_t layerHeight, const BeginLayerOp* beginLayerOp, RenderNode* renderNode); void restoreForLayer(); Loading @@ -195,8 +199,15 @@ private: // should always be surrounded by a save/restore pair void deferNodePropsAndOps(RenderNode& node); void deferShadow(const RenderNodeOp& casterOp); void deferImpl(const DisplayList& displayList); template <typename V> void defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes); void deferRenderNodeOp(const RenderNodeOp& op); void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers); /** Loading
libs/hwui/RecordedOp.h +1 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,7 @@ struct RenderNodeOp : RecordedOp { : SUPER_PAINTLESS(RenderNodeOp) , renderNode(renderNode) {} RenderNode * renderNode; // not const, since drawing modifies it (somehow...) bool skipInOrderDraw = false; }; struct BitmapOp : RecordedOp { Loading
libs/hwui/RecordingCanvas.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -40,7 +40,7 @@ void RecordingCanvas::reset(int width, int height) { mState.initializeSaveStack(width, height, 0, 0, width, height, Vector3()); mDeferredBarrierType = kBarrier_InOrder; mDeferredBarrierType = DeferredBarrierType::InOrder; mState.setDirtyClip(false); mRestoreSaveCount = -1; } Loading Loading @@ -432,17 +432,17 @@ size_t RecordingCanvas::addOp(RecordedOp* op) { // TODO: validate if "addDrawOp" quickrejection logic is useful before adding int insertIndex = mDisplayList->ops.size(); mDisplayList->ops.push_back(op); if (mDeferredBarrierType != kBarrier_None) { if (mDeferredBarrierType != DeferredBarrierType::None) { // op is first in new chunk mDisplayList->chunks.emplace_back(); DisplayList::Chunk& newChunk = mDisplayList->chunks.back(); newChunk.beginOpIndex = insertIndex; newChunk.endOpIndex = insertIndex + 1; newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder); newChunk.reorderChildren = (mDeferredBarrierType == DeferredBarrierType::OutOfOrder); int nextChildIndex = mDisplayList->children.size(); newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex; mDeferredBarrierType = kBarrier_None; mDeferredBarrierType = DeferredBarrierType::None; } else { // standard case - append to existing chunk mDisplayList->chunks.back().endOpIndex = insertIndex + 1; Loading