From ff78583d8a73ca35ce65b5d2592570ff6fb9901b Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Fri, 8 Mar 2013 13:12:16 -0800 Subject: Fully deferred displaylist replay bug:8037003 A recursive drawDisplayList call is now entirely deferred before playing back to the screen and issuing GL commands. This way, the entire stream can be inspected, optimized, and batch work (such as uploading textures) before issuing commands. Additionally, this fixes an issue where operations draw could move across restores corresponding to saveLayer(alpha). Those and other similar cases (such as complex clipping, requiring the stencil) are now treated as batching barriers, with the operations that change renderer state in a way that's difficult to defer are just re-issued at flush time. Change-Id: Ie7348166662a5ad89fb9b1e87558334fb826b01e --- libs/hwui/OpenGLRenderer.cpp | 80 +++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 42 deletions(-) (limited to 'libs/hwui/OpenGLRenderer.cpp') diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 7fe0a69274e4..428980e485f1 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -635,38 +635,17 @@ bool OpenGLRenderer::restoreSnapshot() { /////////////////////////////////////////////////////////////////////////////// int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, - SkPaint* p, int flags) { + int alpha, SkXfermode::Mode mode, int flags) { const GLuint previousFbo = mSnapshot->fbo; const int count = saveSnapshot(flags); if (!mSnapshot->isIgnored()) { - int alpha = 255; - SkXfermode::Mode mode; - - if (p) { - alpha = p->getAlpha(); - mode = getXfermode(p->getXfermode()); - } else { - mode = SkXfermode::kSrcOver_Mode; - } - createLayer(left, top, right, bottom, alpha, mode, flags, previousFbo); } return count; } -int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, - int alpha, int flags) { - if (alpha >= 255) { - return saveLayer(left, top, right, bottom, NULL, flags); - } else { - SkPaint paint; - paint.setAlpha(alpha); - return saveLayer(left, top, right, bottom, &paint, flags); - } -} - /** * Layers are viewed by Skia are slightly different than layers in image editing * programs (for instance.) When a layer is created, previously created layers @@ -1225,36 +1204,48 @@ void OpenGLRenderer::clearLayerRegions() { // State Deferral /////////////////////////////////////////////////////////////////////////////// -bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state) { +bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) { const Rect& currentClip = *(mSnapshot->clipRect); const mat4& currentMatrix = *(mSnapshot->transform); - // state only has bounds initialized in local coordinates - if (!state.mBounds.isEmpty()) { - currentMatrix.mapRect(state.mBounds); - if (!state.mBounds.intersect(currentClip)) { - // quick rejected - return true; + if (stateDeferFlags & kStateDeferFlag_Draw) { + // state has bounds initialized in local coordinates + if (!state.mBounds.isEmpty()) { + currentMatrix.mapRect(state.mBounds); + if (!state.mBounds.intersect(currentClip)) { + // quick rejected + return true; + } + } else { + state.mBounds.set(currentClip); } + state.mDrawModifiers = mDrawModifiers; + state.mAlpha = mSnapshot->alpha; + } + + if (stateDeferFlags & kStateDeferFlag_Clip) { + state.mClip.set(currentClip); } else { - state.mBounds.set(currentClip); + state.mClip.setEmpty(); } - state.mClip.set(currentClip); + // transform always deferred state.mMatrix.load(currentMatrix); - state.mDrawModifiers = mDrawModifiers; return false; } -void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state) { +void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, int stateDeferFlags) { currentTransform().load(state.mMatrix); - // NOTE: a clip RECT will be saved and restored, but DeferredDisplayState doesn't support - // complex clips. In the future, we should add support for deferral of operations clipped by - // these. for now, we don't defer with complex clips (see OpenGLRenderer::disallowDeferral()) - mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom); - dirtyClip(); - mDrawModifiers = state.mDrawModifiers; + if (stateDeferFlags & kStateDeferFlag_Draw) { + mDrawModifiers = state.mDrawModifiers; + mSnapshot->alpha = state.mAlpha; + } + + if (!state.mClip.isEmpty()) { //stateDeferFlags & kStateDeferFlag_Clip) { + mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom); + dirtyClip(); + } } /////////////////////////////////////////////////////////////////////////////// @@ -1805,16 +1796,21 @@ void OpenGLRenderer::finishDrawTexture() { // Drawing /////////////////////////////////////////////////////////////////////////////// -status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags) { +status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, + int32_t replayFlags) { // All the usual checks and setup operations (quickReject, setupDraw, etc.) // will be performed by the display list itself if (displayList && displayList->isRenderable()) { if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { - return displayList->replay(*this, dirty, flags, 0); + ReplayStateStruct replayStruct(*this, dirty, replayFlags); + displayList->replay(replayStruct, 0); + return replayStruct.mDrawGlStatus; } DeferredDisplayList deferredList; - return displayList->replay(*this, dirty, flags, 0, &deferredList); + DeferStateStruct deferStruct(deferredList, *this, replayFlags); + displayList->defer(deferStruct, 0); + return deferredList.flush(*this, dirty); } return DrawGlInfo::kStatusDone; -- cgit v1.2.3-59-g8ed1b