Initial commit of new Canvas operation recording / replay
Done:
- drawRect, drawBitmap, drawColor, drawPaint, drawRenderNode, drawRegion
- Recording with new DisplayList format
- batching & reordering
- Stateless op reorder
- Stateless op rendering
- Frame lifecycle (clear, geterror, cleanup)
Not done:
- SaveLayer (clipped and unclipped)
- HW layers
- Complex clipping
- Ripple projection
- Z reordering
- Z shadows
- onDefer prefetching (text + task kickoff)
- round rect clip
- linear allocation for std collections
- AssetAtlas support
Change-Id: Iaf98c1a3aeab5fa47cc8f9c6d964420abc0e7691
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index bf1b4d0..d122a55 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -25,6 +25,9 @@
#include "DamageAccumulator.h"
#include "Debug.h"
+#if HWUI_NEW_OPS
+#include "RecordedOp.h"
+#endif
#include "DisplayListOp.h"
#include "LayerRenderer.h"
#include "OpenGLRenderer.h"
@@ -47,7 +50,7 @@
}
if (mDisplayListData) {
for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
- mDisplayListData->children()[i]->mRenderNode->debugDumpLayers(prefix);
+ mDisplayListData->children()[i]->renderNode->debugDumpLayers(prefix);
}
}
}
@@ -172,7 +175,7 @@
pnode->clear_children();
if (mDisplayListData) {
for (auto&& child : mDisplayListData->children()) {
- child->mRenderNode->copyTo(pnode->add_children());
+ child->renderNode->copyTo(pnode->add_children());
}
}
}
@@ -332,6 +335,10 @@
info.damageAccumulator->popTransform();
}
+void RenderNode::syncProperties() {
+ mProperties = mStagingProperties;
+}
+
void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
// Push the animators first so that setupStartValueIfNecessary() is called
// before properties() is trampled by stagingProperties(), as they are
@@ -343,7 +350,7 @@
mDirtyPropertyFields = 0;
damageSelf(info);
info.damageAccumulator->popTransform();
- mProperties = mStagingProperties;
+ syncProperties();
applyLayerPropertiesToLayer(info);
// We could try to be clever and only re-damage if the matrix changed.
// However, we don't need to worry about that. The cost of over-damaging
@@ -364,35 +371,39 @@
mLayer->setBlend(props.needsBlending());
}
+void RenderNode::syncDisplayList() {
+ // Make sure we inc first so that we don't fluctuate between 0 and 1,
+ // which would thrash the layer cache
+ if (mStagingDisplayListData) {
+ for (auto&& child : mStagingDisplayListData->children()) {
+ child->renderNode->incParentRefCount();
+ }
+ }
+ deleteDisplayListData();
+ mDisplayListData = mStagingDisplayListData;
+ mStagingDisplayListData = nullptr;
+ if (mDisplayListData) {
+ for (size_t i = 0; i < mDisplayListData->functors.size(); i++) {
+ (*mDisplayListData->functors[i])(DrawGlInfo::kModeSync, nullptr);
+ }
+ }
+}
+
void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
if (mNeedsDisplayListDataSync) {
mNeedsDisplayListDataSync = false;
- // Make sure we inc first so that we don't fluctuate between 0 and 1,
- // which would thrash the layer cache
- if (mStagingDisplayListData) {
- for (size_t i = 0; i < mStagingDisplayListData->children().size(); i++) {
- mStagingDisplayListData->children()[i]->mRenderNode->incParentRefCount();
- }
- }
// Damage with the old display list first then the new one to catch any
// changes in isRenderable or, in the future, bounds
damageSelf(info);
- deleteDisplayListData();
- mDisplayListData = mStagingDisplayListData;
- mStagingDisplayListData = nullptr;
- if (mDisplayListData) {
- for (size_t i = 0; i < mDisplayListData->functors.size(); i++) {
- (*mDisplayListData->functors[i])(DrawGlInfo::kModeSync, nullptr);
- }
- }
+ syncDisplayList();
damageSelf(info);
}
}
void RenderNode::deleteDisplayListData() {
if (mDisplayListData) {
- for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
- mDisplayListData->children()[i]->mRenderNode->decParentRefCount();
+ for (auto&& child : mDisplayListData->children()) {
+ child->renderNode->decParentRefCount();
}
}
delete mDisplayListData;
@@ -407,13 +418,17 @@
info.prepareTextures = cache.prefetchAndMarkInUse(
info.canvasContext, subtree->bitmapResources[i]);
}
- for (size_t i = 0; i < subtree->children().size(); i++) {
- DrawRenderNodeOp* op = subtree->children()[i];
- RenderNode* childNode = op->mRenderNode;
+ for (auto&& op : subtree->children()) {
+ RenderNode* childNode = op->renderNode;
+#if HWUI_NEW_OPS
+ info.damageAccumulator->pushTransform(&op->localMatrix);
+ bool childFunctorsNeedLayer = functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
+#else
info.damageAccumulator->pushTransform(&op->mTransformFromParent);
bool childFunctorsNeedLayer = functorsNeedLayer
// Recorded with non-rect clip, or canvas-rotated by parent
|| op->mRecordedWithPotentialStencilClip;
+#endif
childNode->prepareTreeImpl(info, childFunctorsNeedLayer);
info.damageAccumulator->popTransform();
}
@@ -426,8 +441,8 @@
mLayer = nullptr;
}
if (mDisplayListData) {
- for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
- mDisplayListData->children()[i]->mRenderNode->destroyHardwareResources();
+ for (auto&& child : mDisplayListData->children()) {
+ child->renderNode->destroyHardwareResources();
}
if (mNeedsDisplayListDataSync) {
// Next prepare tree we are going to push a new display list, so we can
@@ -449,6 +464,34 @@
}
}
+bool RenderNode::applyViewProperties(CanvasState& canvasState) const {
+ const Outline& outline = properties().getOutline();
+ if (properties().getAlpha() <= 0
+ || (outline.getShouldClip() && outline.isEmpty())
+ || properties().getScaleX() == 0
+ || properties().getScaleY() == 0) {
+ return false; // rejected
+ }
+
+ if (properties().getLeft() != 0 || properties().getTop() != 0) {
+ canvasState.translate(properties().getLeft(), properties().getTop());
+ }
+ if (properties().getStaticMatrix()) {
+ canvasState.concatMatrix(*properties().getStaticMatrix());
+ } else if (properties().getAnimationMatrix()) {
+ canvasState.concatMatrix(*properties().getAnimationMatrix());
+ }
+ if (properties().hasTransformMatrix()) {
+ if (properties().isTransformTranslateOnly()) {
+ canvasState.translate(properties().getTranslationX(), properties().getTranslationY());
+ } else {
+ canvasState.concatMatrix(*properties().getTransformMatrix());
+ }
+ }
+ return !canvasState.quickRejectConservative(
+ 0, 0, properties().getWidth(), properties().getHeight());
+}
+
/*
* For property operations, we pass a savecount of 0, since the operations aren't part of the
* displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
@@ -580,6 +623,7 @@
* which are flagged to not draw in the standard draw loop.
*/
void RenderNode::computeOrdering() {
+#if !HWUI_NEW_OPS
ATRACE_CALL();
mProjectedNodes.clear();
@@ -588,14 +632,16 @@
if (mDisplayListData == nullptr) return;
for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
- childOp->mRenderNode->computeOrderingImpl(childOp, &mProjectedNodes, &mat4::identity());
+ childOp->renderNode->computeOrderingImpl(childOp, &mProjectedNodes, &mat4::identity());
}
+#endif
}
void RenderNode::computeOrderingImpl(
DrawRenderNodeOp* opState,
std::vector<DrawRenderNodeOp*>* compositedChildrenOfProjectionSurface,
const mat4* transformFromProjectionSurface) {
+#if !HWUI_NEW_OPS
mProjectedNodes.clear();
if (mDisplayListData == nullptr || mDisplayListData->isEmpty()) return;
@@ -619,7 +665,7 @@
bool haveAppliedPropertiesToProjection = false;
for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
- RenderNode* child = childOp->mRenderNode;
+ RenderNode* child = childOp->renderNode;
std::vector<DrawRenderNodeOp*>* projectionChildren = nullptr;
const mat4* projectionTransform = nullptr;
@@ -642,6 +688,7 @@
child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
}
}
+#endif
}
class DeferOperationHandler {
@@ -701,11 +748,12 @@
void RenderNode::buildZSortedChildList(const DisplayListData::Chunk& chunk,
std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes) {
+#if !HWUI_NEW_OPS
if (chunk.beginChildIndex == chunk.endChildIndex) return;
for (unsigned int i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
- RenderNode* child = childOp->mRenderNode;
+ RenderNode* child = childOp->renderNode;
float childZ = child->properties().getZ();
if (!MathUtils::isZero(childZ) && chunk.reorderChildren) {
@@ -719,6 +767,7 @@
// Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order)
std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end());
+#endif
}
template <class T>
@@ -824,7 +873,7 @@
while (shadowIndex < endIndex || drawIndex < endIndex) {
if (shadowIndex < endIndex) {
DrawRenderNodeOp* casterOp = zTranslatedNodes[shadowIndex].value;
- RenderNode* caster = casterOp->mRenderNode;
+ RenderNode* caster = casterOp->renderNode;
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
@@ -869,7 +918,7 @@
const DisplayListOp* op =
(mDisplayListData->displayListOps[mDisplayListData->projectionReceiveIndex]);
const DrawRenderNodeOp* backgroundOp = reinterpret_cast<const DrawRenderNodeOp*>(op);
- const RenderProperties& backgroundProps = backgroundOp->mRenderNode->properties();
+ const RenderProperties& backgroundProps = backgroundOp->renderNode->properties();
renderer.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY());
// If the projection reciever has an outline, we mask projected content to it