diff options
| author | Chavi Weingarten <chaviw@google.com> | 2021-12-28 21:17:00 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2021-12-28 21:17:00 +0000 |
| commit | 6489e997ac4fd9761da3b54bbbedc778eec66887 (patch) | |
| tree | 32cd75f28efaec78f663990e45ca917826af5b8f /core/java/android | |
| parent | cb60d919701814624f0704d837ae79a5357ed0ae (diff) | |
| parent | b680371f7703b3ae60c77efc25939cba1be78439 (diff) | |
Merge "Send syncStatus and return FrameCommitCallback in FrameCallback"
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 41 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 197 |
2 files changed, 157 insertions, 81 deletions
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 00754af6a853..1566f9e50f66 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -478,6 +478,19 @@ public final class ThreadedRenderer extends HardwareRenderer { } /** + * Remove a frame drawing callback that was added via + * {@link #registerRtFrameCallback(FrameDrawingCallback)} + * + * @param callback The callback to unregister. + */ + void unregisterRtFrameCallback(@NonNull FrameDrawingCallback callback) { + if (mNextRtFrameCallbacks == null) { + return; + } + mNextRtFrameCallbacks.remove(callback); + } + + /** * Destroys all hardware rendering resources associated with the specified * view hierarchy. * @@ -679,9 +692,31 @@ public final class ThreadedRenderer extends HardwareRenderer { if (mNextRtFrameCallbacks != null) { final ArrayList<FrameDrawingCallback> frameCallbacks = mNextRtFrameCallbacks; mNextRtFrameCallbacks = null; - setFrameCallback(frame -> { - for (int i = 0; i < frameCallbacks.size(); ++i) { - frameCallbacks.get(i).onFrameDraw(frame); + setFrameCallback(new FrameDrawingCallback() { + @Override + public void onFrameDraw(long frame) { + } + + @Override + public FrameCommitCallback onFrameDraw(int syncResult, long frame) { + ArrayList<FrameCommitCallback> frameCommitCallbacks = new ArrayList<>(); + for (int i = 0; i < frameCallbacks.size(); ++i) { + FrameCommitCallback frameCommitCallback = frameCallbacks.get(i) + .onFrameDraw(syncResult, frame); + if (frameCommitCallback != null) { + frameCommitCallbacks.add(frameCommitCallback); + } + } + + if (frameCommitCallbacks.isEmpty()) { + return null; + } + + return didProduceBuffer -> { + for (int i = 0; i < frameCommitCallbacks.size(); ++i) { + frameCommitCallbacks.get(i).onFrameCommit(didProduceBuffer); + } + }; } }); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index af496dcea8e3..1fdbf0e204da 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -16,6 +16,8 @@ package android.view; +import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED; +import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND; import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; @@ -1392,11 +1394,20 @@ public final class ViewRootImpl implements ViewParent, */ public void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) { if (mAttachInfo.mThreadedRenderer != null) { - mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frame -> { - try { - callback.onFrameDraw(frame); - } catch (Exception e) { - Log.e(TAG, "Exception while executing onFrameDraw", e); + mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() { + @Override + public void onFrameDraw(long frame) { + } + + @Override + public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, + long frame) { + try { + return callback.onFrameDraw(syncResult, frame); + } catch (Exception e) { + Log.e(TAG, "Exception while executing onFrameDraw", e); + } + return null; } }); } @@ -4020,36 +4031,49 @@ public final class ViewRootImpl implements ViewParent, return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled(); } - private boolean addFrameCompleteCallbackIfNeeded(boolean useBlastSync, - boolean reportNextDraw) { + private void addFrameCommitCallbackIfNeeded() { if (!isHardwareEnabled()) { - return false; + return; } - if (!useBlastSync && !reportNextDraw) { - return false; + ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver + .captureFrameCommitCallbacks(); + final boolean needFrameCommitCallback = + (commitCallbacks != null && commitCallbacks.size() > 0); + if (!needFrameCommitCallback) { + return; } - if (DEBUG_BLAST) { - Log.d(mTag, "Creating frameCompleteCallback"); + if (DEBUG_DRAW) { + Log.d(mTag, "Creating frameCommitCallback" + + " commitCallbacks size=" + commitCallbacks.size()); } + mAttachInfo.mThreadedRenderer.setFrameCommitCallback(didProduceBuffer -> { + if (DEBUG_DRAW) { + Log.d(mTag, "Received frameCommitCallback didProduceBuffer=" + didProduceBuffer); + } - final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer; - mBLASTDrawConsumer = null; + mHandler.postAtFrontOfQueue(() -> { + for (int i = 0; i < commitCallbacks.size(); i++) { + commitCallbacks.get(i).run(); + } + }); + }); + } - mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(() -> { - long frameNr = mBlastBufferQueue.getLastAcquiredFrameNum(); + private HardwareRenderer.FrameCommitCallback createFrameCommitCallbackForSync( + boolean useBlastSync, boolean reportNextDraw, Consumer<Transaction> blastSyncConsumer) { + return didProduceBuffer -> { if (DEBUG_BLAST) { - Log.d(mTag, "Received frameCompleteCallback " - + " lastAcquiredFrameNum=" + frameNr - + " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum); + Log.d(mTag, "Received frameCommittedCallback " + + " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum + + " didProduceBuffer=" + didProduceBuffer); } - boolean frameWasNotDrawn = frameNr != mRtLastAttemptedDrawFrameNum; // If frame wasn't drawn, clear out the next transaction so it doesn't affect the next // draw attempt. The next transaction and transaction complete callback were only set // for the current draw attempt. - if (frameWasNotDrawn) { + if (!didProduceBuffer) { mBlastBufferQueue.setSyncTransaction(null); // Apply the transactions that were sent to mergeWithNextTransaction since the // frame didn't draw on this vsync. It's possible the frame will draw later, but @@ -4059,6 +4083,11 @@ public final class ViewRootImpl implements ViewParent, Transaction tmpTransaction = new Transaction(); tmpTransaction.merge(mRtBLASTSyncTransaction); + // Post at front of queue so the buffer can be processed immediately and allow RT + // to continue processing new buffers. If RT tries to process buffers before the sync + // buffer is applied, the new buffers will not get acquired and could result in a + // deadlock. UI thread would wait on RT, but RT would be blocked waiting for a free + // buffer. mHandler.postAtFrontOfQueue(() -> { if (useBlastSync) { mSurfaceChangedTransaction.merge(tmpTransaction); @@ -4071,85 +4100,92 @@ public final class ViewRootImpl implements ViewParent, pendingDrawFinished(); } }); - }); - return true; + }; } - private void addFrameCommitCallbackIfNeeded() { + @Nullable + private FrameDrawingCallback createFrameDrawingCallbackIfNeeded(boolean useBlastSync, + boolean reportNextDraw) { if (!isHardwareEnabled()) { - return; - } - - ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver - .captureFrameCommitCallbacks(); - final boolean needFrameCommitCallback = - (commitCallbacks != null && commitCallbacks.size() > 0); - if (!needFrameCommitCallback) { - return; - } - - if (DEBUG_DRAW) { - Log.d(mTag, "Creating frameCommitCallback" - + " commitCallbacks size=" + commitCallbacks.size()); + return null; } - mAttachInfo.mThreadedRenderer.setFrameCommitCallback(didProduceBuffer -> { - if (DEBUG_DRAW) { - Log.d(mTag, "Received frameCommitCallback didProduceBuffer=" + didProduceBuffer); - } - - mHandler.postAtFrontOfQueue(() -> { - for (int i = 0; i < commitCallbacks.size(); i++) { - commitCallbacks.get(i).run(); - } - }); - }); - } - - private void addFrameCallbackIfNeeded(boolean useBlastSync) { final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates(); final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions(); - if (!useBlastSync && !needsCallbackForBlur) { - return; + if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw) { + return null; } + final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer; + mBLASTDrawConsumer = null; + if (DEBUG_BLAST) { Log.d(mTag, "Creating frameDrawingCallback" + " nextDrawUseBlastSync=" + useBlastSync - + " hasBlurUpdates=" + hasBlurUpdates); + + " reportNextDraw=" + reportNextDraw + + " hasBlurUpdates=" + hasBlurUpdates + + " hasBlastSyncConsumer=" + (blastSyncConsumer != null)); } + final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame = needsCallbackForBlur ? mBlurRegionAggregator.getBlurRegionsCopyForRT() : null; // The callback will run on the render thread. - HardwareRenderer.FrameDrawingCallback frameDrawingCallback = frame -> { - if (DEBUG_BLAST) { - Log.d(mTag, "Received frameDrawingCallback frameNum=" + frame + "." - + " Creating transactionCompleteCallback=" + useBlastSync); + return new FrameDrawingCallback() { + @Override + public void onFrameDraw(long frame) { } - mRtLastAttemptedDrawFrameNum = frame; + @Override + public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { + if (DEBUG_BLAST) { + Log.d(mTag, + "Received frameDrawingCallback syncResult=" + syncResult + " frameNum=" + + frame + "."); + } - if (needsCallbackForBlur) { - mBlurRegionAggregator - .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates); - } + mRtLastAttemptedDrawFrameNum = frame; - if (mBlastBufferQueue == null) { - return; - } + if (needsCallbackForBlur) { + mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame, + blurRegionsForFrame, hasBlurUpdates); + } - if (useBlastSync) { - // Frame callbacks will always occur after submitting draw requests and before - // the draw actually occurs. This will ensure that we set the next transaction - // for the frame that's about to get drawn and not on a previous frame that. + if (mBlastBufferQueue == null) { + return null; + } - // We don't need to synchronize mRtBLASTSyncTransaction here since it's not - // being modified and only sent to BlastBufferQueue. - mBlastBufferQueue.setSyncTransaction(mRtBLASTSyncTransaction); + if (!useBlastSync && !reportNextDraw) { + return null; + } + + // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or + // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up + // any blast sync or commit callback, and the code should directly call + // pendingDrawFinished. + if ((syncResult + & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) { + if (reportNextDraw) { + mHandler.postAtFrontOfQueue(() -> pendingDrawFinished()); + } + return null; + } + + if (DEBUG_BLAST) { + Log.d(mTag, "Setting up sync and frameCommitCallback"); + } + + if (useBlastSync) { + // Frame callbacks will always occur after submitting draw requests and before + // the draw actually occurs. This will ensure that we set the next transaction + // for the frame that's about to get drawn and not on a previous frame. + mBlastBufferQueue.setSyncTransaction(mRtBLASTSyncTransaction); + } + + return createFrameCommitCallbackForSync(useBlastSync, reportNextDraw, + blastSyncConsumer); } }; - registerRtFrameCallback(frameDrawingCallback); } private void performDraw(boolean useBlastSync) { @@ -4165,15 +4201,20 @@ public final class ViewRootImpl implements ViewParent, mIsDrawing = true; Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw"); - addFrameCallbackIfNeeded(useBlastSync); + FrameDrawingCallback frameDrawingCallback = createFrameDrawingCallbackIfNeeded(useBlastSync, + mReportNextDraw); + if (frameDrawingCallback != null) { + mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frameDrawingCallback); + } addFrameCommitCallbackIfNeeded(); - boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded(useBlastSync, mReportNextDraw); + boolean usingAsyncReport = isHardwareEnabled() && (useBlastSync || mReportNextDraw); try { boolean canUseAsync = draw(fullRedrawNeeded); if (usingAsyncReport && !canUseAsync) { - mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null); + mAttachInfo.mThreadedRenderer.setFrameCallback(null); usingAsyncReport = false; + mAttachInfo.mThreadedRenderer.unregisterRtFrameCallback(frameDrawingCallback); } } finally { mIsDrawing = false; |
