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
This commit is contained in:
Chris Craik
2015-10-05 13:00:52 -07:00
parent b08949151f
commit b565df13a9
29 changed files with 2482 additions and 78 deletions

View File

@ -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 @@ void RenderNode::debugDumpLayers(const char* prefix) {
}
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 @@ void RenderNode::copyTo(proto::RenderNode *pnode) {
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 @@ void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) {
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 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
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 @@ void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) {
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 @@ void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayL
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 @@ void RenderNode::destroyHardwareResources() {
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 @@ void RenderNode::decParentRefCount() {
}
}
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 @@ void RenderNode::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform)
* 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 @@ void RenderNode::computeOrdering() {
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 @@ void RenderNode::computeOrderingImpl(
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 @@ void RenderNode::computeOrderingImpl(
child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
}
}
#endif
}
class DeferOperationHandler {
@ -701,11 +748,12 @@ void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) {
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 @@ void RenderNode::buildZSortedChildList(const DisplayListData::Chunk& chunk,
// 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 @@ void RenderNode::issueOperationsOf3dChildren(ChildrenSelectMode mode,
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 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T&
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