Create z reordering boundaries around dispatchDraw

bug:16012254

This means rendernodes with a Z will no longer be drawn at the end of
their parent's DisplayList, but at the end of the associated reorder
region (DisplayListData::Chunk).

Change-Id: Ia033fee9d9a4db567b2a8d5e90fc57a4d0a64544
This commit is contained in:
Chris Craik
2014-08-21 17:41:57 -07:00
parent cc3e5d5cd1
commit 8afd0f245c
11 changed files with 188 additions and 80 deletions

View File

@@ -178,6 +178,18 @@ class GLES20Canvas extends HardwareCanvas {
private static native void nSetHighContrastText(long renderer, boolean highContrastText);
@Override
public void insertReorderBarrier() {
nInsertReorderBarrier(mRenderer, true);
}
@Override
public void insertInorderBarrier() {
nInsertReorderBarrier(mRenderer, false);
}
private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
@Override
public int onPreDraw(Rect dirty) {
if (dirty != null) {

View File

@@ -3072,7 +3072,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
boolean more = false;
final long drawingTime = getDrawingTime();
if (usingRenderNodeProperties) canvas.insertReorderBarrier();
// Only use the preordered list if not HW accelerated, since the HW pipeline will do the
// draw reordering internally
final ArrayList<View> preorderedList = usingRenderNodeProperties
@@ -3099,6 +3099,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
more |= drawChild(canvas, child, drawingTime);
}
}
if (usingRenderNodeProperties) canvas.insertInorderBarrier();
if (debugDraw()) {
onDebugDraw(canvas);

View File

@@ -104,6 +104,12 @@ static void android_view_GLES20Canvas_setHighContrastText(JNIEnv* env, jobject c
renderer->setHighContrastText(highContrastText);
}
static void android_view_GLES20Canvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
jlong rendererPtr, jboolean reorderEnable) {
DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
renderer->insertReorderBarrier(reorderEnable);
}
static int android_view_GLES20Canvas_prepare(JNIEnv* env, jobject clazz,
jlong rendererPtr, jboolean opaque) {
DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
@@ -859,6 +865,7 @@ static JNINativeMethod gMethods[] = {
{ "nDestroyRenderer", "(J)V", (void*) android_view_GLES20Canvas_destroyRenderer },
{ "nSetViewport", "(JII)V", (void*) android_view_GLES20Canvas_setViewport },
{ "nSetHighContrastText","(JZ)V", (void*) android_view_GLES20Canvas_setHighContrastText },
{ "nInsertReorderBarrier","(JZ)V", (void*) android_view_GLES20Canvas_insertReorderBarrier },
{ "nPrepare", "(JZ)I", (void*) android_view_GLES20Canvas_prepare },
{ "nPrepareDirty", "(JIIIIZ)I", (void*) android_view_GLES20Canvas_prepareDirty },
{ "nFinish", "(J)V", (void*) android_view_GLES20Canvas_finish },

View File

@@ -243,6 +243,12 @@ public class Canvas {
/** @hide */
public void setHighContrastText(boolean highContrastText) {}
/** @hide */
public void insertReorderBarrier() {}
/** @hide */
public void insertInorderBarrier() {}
/**
* @hide
*/

View File

@@ -89,11 +89,9 @@ void DisplayListData::cleanupResources() {
layers.clear();
}
void DisplayListData::addChild(DrawRenderNodeOp* op) {
LOG_ALWAYS_FATAL_IF(!op->renderNode(), "DrawRenderNodeOp with no render node!");
mChildren.push(op);
size_t DisplayListData::addChild(DrawRenderNodeOp* op) {
mReferenceHolders.push(op->renderNode());
return mChildren.add(op);
}
}; // namespace uirenderer

View File

@@ -115,13 +115,24 @@ public:
* Data structure that holds the list of commands used in display list stream
*/
class DisplayListData {
friend class DisplayListRenderer;
public:
struct Chunk {
// range of included ops in DLD::displayListOps
size_t beginOpIndex;
size_t endOpIndex;
// range of included children in DLD::mChildren
size_t beginChildIndex;
size_t endChildIndex;
// whether children with non-zero Z in the chunk should be reordered
bool reorderChildren;
};
DisplayListData();
~DisplayListData();
// allocator into which all ops were allocated
LinearAllocator allocator;
// pointers to all ops within display list, pointing into allocator data
Vector<DisplayListOp*> displayListOps;
@@ -138,13 +149,12 @@ public:
Vector<const SkRegion*> regions;
Vector<Layer*> layers;
Vector<Functor*> functors;
bool hasDrawOps;
bool isEmpty() {
return !displayListOps.size();
const Vector<Chunk>& getChunks() const {
return chunks;
}
void addChild(DrawRenderNodeOp* childOp);
size_t addChild(DrawRenderNodeOp* childOp);
const Vector<DrawRenderNodeOp*>& children() { return mChildren; }
void refProperty(CanvasPropertyPrimitive* prop) {
@@ -155,12 +165,25 @@ public:
mReferenceHolders.push(prop);
}
size_t getUsedSize() {
return allocator.usedSize();
}
bool isEmpty() {
return !hasDrawOps;
}
private:
Vector< sp<VirtualLightRefBase> > mReferenceHolders;
// list of children display lists for quick, non-drawing traversal
Vector<DrawRenderNodeOp*> mChildren;
Vector<Chunk> chunks;
// allocator into which all ops were allocated
LinearAllocator allocator;
bool hasDrawOps;
void cleanupResources();
};

View File

@@ -1445,6 +1445,7 @@ private:
class DrawRenderNodeOp : public DrawBoundedOp {
friend class RenderNode; // grant RenderNode access to info of child
friend class DisplayListData; // grant DisplayListData access to info of child
public:
DrawRenderNodeOp(RenderNode* renderNode, int flags, const mat4& transformFromParent)
: DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), 0),
@@ -1452,13 +1453,14 @@ public:
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
bool useQuickReject) {
if (mRenderNode && mRenderNode->isRenderable() && !mSkipInOrderDraw) {
if (mRenderNode->isRenderable() && !mSkipInOrderDraw) {
mRenderNode->defer(deferStruct, level + 1);
}
}
virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
bool useQuickReject) {
if (mRenderNode && mRenderNode->isRenderable() && !mSkipInOrderDraw) {
if (mRenderNode->isRenderable() && !mSkipInOrderDraw) {
mRenderNode->replay(replayStruct, level + 1);
}
}
@@ -1469,7 +1471,7 @@ public:
}
virtual void output(int level, uint32_t logFlags) const {
OP_LOG("Draw Display List %p, flags %#x", mRenderNode, mFlags);
OP_LOG("Draw RenderNode %p %s, flags %#x", mRenderNode, mRenderNode->getName(), mFlags);
if (mRenderNode && (logFlags & kOpLogFlag_Recurse)) {
mRenderNode->output(level + 1);
}

View File

@@ -33,10 +33,10 @@ namespace uirenderer {
DisplayListRenderer::DisplayListRenderer()
: mCaches(Caches::getInstance())
, mDisplayListData(0)
, mDisplayListData(NULL)
, mTranslateX(0.0f)
, mTranslateY(0.0f)
, mHasTranslate(false)
, mDeferredBarrierType(kBarrier_None)
, mHighContrastText(false)
, mRestoreSaveCount(-1) {
}
@@ -68,6 +68,7 @@ status_t DisplayListRenderer::prepareDirty(float left, float top,
initializeSaveStack(0, 0, getWidth(), getHeight(), Vector3());
mDeferredBarrierType = kBarrier_InOrder;
mDirtyClip = opaque;
mRestoreSaveCount = -1;
@@ -75,8 +76,8 @@ status_t DisplayListRenderer::prepareDirty(float left, float top,
}
void DisplayListRenderer::finish() {
insertRestoreToCount();
insertTranslate();
flushRestoreToCount();
flushTranslate();
}
void DisplayListRenderer::interrupt() {
@@ -104,13 +105,13 @@ void DisplayListRenderer::restore() {
}
mRestoreSaveCount--;
insertTranslate();
flushTranslate();
StatefulBaseRenderer::restore();
}
void DisplayListRenderer::restoreToCount(int saveCount) {
mRestoreSaveCount = saveCount;
insertTranslate();
flushTranslate();
StatefulBaseRenderer::restoreToCount(saveCount);
}
@@ -123,10 +124,10 @@ int DisplayListRenderer::saveLayer(float left, float top, float right, float bot
void DisplayListRenderer::translate(float dx, float dy, float dz) {
// ignore dz, not used at defer time
mHasTranslate = true;
mHasDeferredTranslate = true;
mTranslateX += dx;
mTranslateY += dy;
insertRestoreToCount();
flushRestoreToCount();
StatefulBaseRenderer::translate(dx, dy, dz);
}
@@ -174,16 +175,12 @@ bool DisplayListRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
}
status_t DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) {
LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode");
// dirty is an out parameter and should not be recorded,
// it matters only when replaying the display list
DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *currentTransform());
int opIndex = addDrawOp(op);
mDisplayListData->addChild(op);
if (renderNode->stagingProperties().isProjectionReceiver()) {
// use staging property, since recording on UI thread
mDisplayListData->projectionReceiveIndex = opIndex;
}
addRenderNodeOp(op);
return DrawGlInfo::kStatusDone;
}
@@ -428,30 +425,60 @@ void DisplayListRenderer::setupPaintFilter(int clearBits, int setBits) {
addStateOp(new (alloc()) SetupPaintFilterOp(clearBits, setBits));
}
void DisplayListRenderer::insertRestoreToCount() {
void DisplayListRenderer::insertReorderBarrier(bool enableReorder) {
flushRestoreToCount();
flushTranslate();
mDeferredBarrierType = enableReorder ? kBarrier_OutOfOrder : kBarrier_InOrder;
}
void DisplayListRenderer::flushRestoreToCount() {
if (mRestoreSaveCount >= 0) {
DisplayListOp* op = new (alloc()) RestoreToCountOp(mRestoreSaveCount);
mDisplayListData->displayListOps.add(op);
addOpAndUpdateChunk(new (alloc()) RestoreToCountOp(mRestoreSaveCount));
mRestoreSaveCount = -1;
}
}
void DisplayListRenderer::insertTranslate() {
if (mHasTranslate) {
void DisplayListRenderer::flushTranslate() {
if (mHasDeferredTranslate) {
if (mTranslateX != 0.0f || mTranslateY != 0.0f) {
DisplayListOp* op = new (alloc()) TranslateOp(mTranslateX, mTranslateY);
mDisplayListData->displayListOps.add(op);
addOpAndUpdateChunk(new (alloc()) TranslateOp(mTranslateX, mTranslateY));
mTranslateX = mTranslateY = 0.0f;
}
mHasTranslate = false;
mHasDeferredTranslate = false;
}
}
int DisplayListRenderer::addStateOp(StateOp* op) {
return addOpInternal(op);
size_t DisplayListRenderer::addOpAndUpdateChunk(DisplayListOp* op) {
int insertIndex = mDisplayListData->displayListOps.add(op);
if (mDeferredBarrierType != kBarrier_None) {
// op is first in new chunk
mDisplayListData->chunks.push();
DisplayListData::Chunk& newChunk = mDisplayListData->chunks.editTop();
newChunk.beginOpIndex = insertIndex;
newChunk.endOpIndex = insertIndex + 1;
newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder);
int nextChildIndex = mDisplayListData->children().size();
newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex;
mDeferredBarrierType = kBarrier_None;
} else {
// standard case - append to existing chunk
mDisplayListData->chunks.editTop().endOpIndex = insertIndex + 1;
}
return insertIndex;
}
int DisplayListRenderer::addDrawOp(DrawOp* op) {
size_t DisplayListRenderer::flushAndAddOp(DisplayListOp* op) {
flushRestoreToCount();
flushTranslate();
return addOpAndUpdateChunk(op);
}
size_t DisplayListRenderer::addStateOp(StateOp* op) {
return flushAndAddOp(op);
}
size_t DisplayListRenderer::addDrawOp(DrawOp* op) {
Rect localBounds;
if (op->getLocalBounds(localBounds)) {
bool rejected = quickRejectConservative(localBounds.left, localBounds.top,
@@ -460,7 +487,22 @@ int DisplayListRenderer::addDrawOp(DrawOp* op) {
}
mDisplayListData->hasDrawOps = true;
return addOpInternal(op);
return flushAndAddOp(op);
}
size_t DisplayListRenderer::addRenderNodeOp(DrawRenderNodeOp* op) {
int opIndex = addDrawOp(op);
int childIndex = mDisplayListData->addChild(op);
// update the chunk's child indices
DisplayListData::Chunk& chunk = mDisplayListData->chunks.editTop();
chunk.endChildIndex = childIndex + 1;
if (op->renderNode()->stagingProperties().isProjectionReceiver()) {
// use staging property, since recording on UI thread
mDisplayListData->projectionReceiveIndex = opIndex;
}
return opIndex;
}
}; // namespace uirenderer

View File

@@ -57,6 +57,8 @@ public:
DisplayListRenderer();
virtual ~DisplayListRenderer();
void insertReorderBarrier(bool enableReorder);
DisplayListData* finishRecording();
// ----------------------------------------------------------------------------
@@ -154,19 +156,27 @@ public:
mHighContrastText = highContrastText;
}
private:
void insertRestoreToCount();
void insertTranslate();
enum DeferredBarrierType {
kBarrier_None,
kBarrier_InOrder,
kBarrier_OutOfOrder,
};
void flushRestoreToCount();
void flushTranslate();
void flushReorderBarrier();
LinearAllocator& alloc() { return mDisplayListData->allocator; }
// Each method returns final index of op
int addStateOp(StateOp* op);
int addDrawOp(DrawOp* op);
int addOpInternal(DisplayListOp* op) {
insertRestoreToCount();
insertTranslate();
return mDisplayListData->displayListOps.add(op);
}
size_t addOpAndUpdateChunk(DisplayListOp* op);
// flushes any deferred operations, and appends the op
size_t flushAndAddOp(DisplayListOp* op);
size_t addStateOp(StateOp* op);
size_t addDrawOp(DrawOp* op);
size_t addRenderNodeOp(DrawRenderNodeOp* op);
template<class T>
inline const T* refBuffer(const T* srcBuffer, int32_t count) {
@@ -277,7 +287,8 @@ private:
float mTranslateX;
float mTranslateY;
bool mHasTranslate;
bool mHasDeferredTranslate;
DeferredBarrierType mDeferredBarrierType;
bool mHighContrastText;
int mRestoreSaveCount;

View File

@@ -95,6 +95,7 @@ void RenderNode::output(uint32_t level) {
properties().debugOutputProperties(level);
int flags = DisplayListOp::kOpLogFlag_Recurse;
if (mDisplayListData) {
// TODO: consider printing the chunk boundaries here
for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
mDisplayListData->displayListOps[i]->output(level, flags);
}
@@ -106,10 +107,10 @@ void RenderNode::output(uint32_t level) {
int RenderNode::getDebugSize() {
int size = sizeof(RenderNode);
if (mStagingDisplayListData) {
size += mStagingDisplayListData->allocator.usedSize();
size += mStagingDisplayListData->getUsedSize();
}
if (mDisplayListData && mDisplayListData != mStagingDisplayListData) {
size += mDisplayListData->allocator.usedSize();
size += mDisplayListData->getUsedSize();
}
return size;
}
@@ -593,15 +594,16 @@ void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) {
issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
}
void RenderNode::buildZSortedChildList(Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes) {
if (mDisplayListData == NULL || mDisplayListData->children().size() == 0) return;
void RenderNode::buildZSortedChildList(const DisplayListData::Chunk& chunk,
Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes) {
if (chunk.beginChildIndex == chunk.endChildIndex) return;
for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
for (unsigned int i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
RenderNode* child = childOp->mRenderNode;
float childZ = child->properties().getZ();
if (!MathUtils::isZero(childZ)) {
if (!MathUtils::isZero(childZ) && chunk.reorderChildren) {
zTranslatedNodes.add(ZDrawRenderNodeOpPair(childZ, childOp));
childOp->mSkipInOrderDraw = true;
} else if (!child->properties().getProjectBackwards()) {
@@ -610,7 +612,7 @@ void RenderNode::buildZSortedChildList(Vector<ZDrawRenderNodeOpPair>& zTranslate
}
}
// Z sort 3d children (stable-ness makes z compare fall back to standard drawing order)
// Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order)
std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end());
}
@@ -871,32 +873,35 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
renderer.getSaveCount() - 1, properties().getClipToBounds());
} else {
Vector<ZDrawRenderNodeOpPair> zTranslatedNodes;
buildZSortedChildList(zTranslatedNodes);
// for 3d root, draw children with negative z values
int shadowRestoreTo = issueOperationsOfNegZChildren(zTranslatedNodes, renderer, handler);
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
const int saveCountOffset = renderer.getSaveCount() - 1;
const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
const int size = static_cast<int>(mDisplayListData->displayListOps.size());
for (int i = 0; i < size; i++) {
DisplayListOp *op = mDisplayListData->displayListOps[i];
for (size_t chunkIndex = 0; chunkIndex < mDisplayListData->getChunks().size(); chunkIndex++) {
const DisplayListData::Chunk& chunk = mDisplayListData->getChunks()[chunkIndex];
Vector<ZDrawRenderNodeOpPair> zTranslatedNodes;
buildZSortedChildList(chunk, zTranslatedNodes);
// for 3d root, draw children with negative z values
int shadowRestoreTo = issueOperationsOfNegZChildren(zTranslatedNodes,
renderer, handler);
const int saveCountOffset = renderer.getSaveCount() - 1;
const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
for (int opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
DisplayListOp *op = mDisplayListData->displayListOps[opIndex];
#if DEBUG_DISPLAY_LIST
op->output(level + 1);
op->output(level + 1);
#endif
logBuffer.writeCommand(level, op->name());
handler(op, saveCountOffset, properties().getClipToBounds());
logBuffer.writeCommand(level, op->name());
handler(op, saveCountOffset, properties().getClipToBounds());
if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
issueOperationsOfProjectedChildren(renderer, handler);
if (CC_UNLIKELY(!mProjectedNodes.isEmpty() && opIndex == projectionReceiveIndex)) {
issueOperationsOfProjectedChildren(renderer, handler);
}
}
}
// for 3d root, draw children with positive z values
issueOperationsOfPosZChildren(shadowRestoreTo, zTranslatedNodes, renderer, handler);
// for 3d root, draw children with positive z values
issueOperationsOfPosZChildren(shadowRestoreTo, zTranslatedNodes, renderer, handler);
}
}
}

View File

@@ -114,7 +114,7 @@ public:
ANDROID_API int getDebugSize();
bool isRenderable() const {
return mDisplayListData && mDisplayListData->hasDrawOps;
return mDisplayListData && !mDisplayListData->isEmpty();
}
bool hasProjectionReceiver() const {
@@ -199,7 +199,8 @@ private:
template <class T>
inline void setViewProperties(OpenGLRenderer& renderer, T& handler);
void buildZSortedChildList(Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes);
void buildZSortedChildList(const DisplayListData::Chunk& chunk,
Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes);
template<class T>
inline void issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler);