Loading core/java/android/view/ThreadedRenderer.java +38 −3 Original line number Diff line number Diff line Loading @@ -477,6 +477,19 @@ public final class ThreadedRenderer extends HardwareRenderer { mNextRtFrameCallbacks.add(callback); } /** * 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. Loading Loading @@ -679,9 +692,31 @@ public final class ThreadedRenderer extends HardwareRenderer { if (mNextRtFrameCallbacks != null) { final ArrayList<FrameDrawingCallback> frameCallbacks = mNextRtFrameCallbacks; mNextRtFrameCallbacks = null; setFrameCallback(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) { frameCallbacks.get(i).onFrameDraw(frame); 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); } }; } }); } Loading core/java/android/view/ViewRootImpl.java +119 −78 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -1392,12 +1394,21 @@ public final class ViewRootImpl implements ViewParent, */ public void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) { if (mAttachInfo.mThreadedRenderer != null) { mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frame -> { mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() { @Override public void onFrameDraw(long frame) { } @Override public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { try { callback.onFrameDraw(frame); return callback.onFrameDraw(syncResult, frame); } catch (Exception e) { Log.e(TAG, "Exception while executing onFrameDraw", e); } return null; } }); } } Loading Loading @@ -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 Loading @@ -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); Loading @@ -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()); } 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(); } }); }); return null; } 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 -> { return new FrameDrawingCallback() { @Override public void onFrameDraw(long frame) { } @Override public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { if (DEBUG_BLAST) { Log.d(mTag, "Received frameDrawingCallback frameNum=" + frame + "." + " Creating transactionCompleteCallback=" + useBlastSync); Log.d(mTag, "Received frameDrawingCallback syncResult=" + syncResult + " frameNum=" + frame + "."); } mRtLastAttemptedDrawFrameNum = frame; if (needsCallbackForBlur) { mBlurRegionAggregator .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates); mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates); } if (mBlastBufferQueue == null) { return; return null; } 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 that. // We don't need to synchronize mRtBLASTSyncTransaction here since it's not // being modified and only sent to BlastBufferQueue. // 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) { Loading @@ -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; Loading graphics/java/android/graphics/HardwareRenderer.java +14 −0 Original line number Diff line number Diff line Loading @@ -902,6 +902,20 @@ public class HardwareRenderer { * @param frame The id of the frame being drawn. */ void onFrameDraw(long frame); /** * Invoked during a frame drawing. * * @param syncResult The result of the draw. Should be a value or a combination of values * from {@link SyncAndDrawResult} * @param frame The id of the frame being drawn. * * @return A {@link FrameCommitCallback} that will report back if the current vsync draws. */ default FrameCommitCallback onFrameDraw(@SyncAndDrawResult int syncResult, long frame) { onFrameDraw(frame); return null; } } /** Loading libs/hwui/jni/android_graphics_HardwareRenderer.cpp +16 −6 Original line number Diff line number Diff line Loading @@ -609,10 +609,19 @@ static void android_view_ThreadedRenderer_setFrameCallback(JNIEnv* env, LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM"); auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(frameCallback)); proxy->setFrameCallback([globalCallbackRef](int64_t frameNr) { proxy->setFrameCallback([globalCallbackRef](int32_t syncResult, int64_t frameNr) -> std::function<void(bool)> { JNIEnv* env = getenv(globalCallbackRef->vm()); env->CallVoidMethod(globalCallbackRef->object(), gFrameDrawingCallback.onFrameDraw, static_cast<jlong>(frameNr)); ScopedLocalRef<jobject> frameCommitCallback( env, env->CallObjectMethod( globalCallbackRef->object(), gFrameDrawingCallback.onFrameDraw, static_cast<jint>(syncResult), static_cast<jlong>(frameNr))); if (frameCommitCallback == nullptr) { return nullptr; } sp<FrameCommitWrapper> wrapper = sp<FrameCommitWrapper>::make(env, frameCommitCallback.get()); return [wrapper](bool didProduceBuffer) { wrapper->onFrameCommit(didProduceBuffer); }; }); } } Loading @@ -623,7 +632,7 @@ static void android_view_ThreadedRenderer_setFrameCommitCallback(JNIEnv* env, jo if (!callback) { proxy->setFrameCommitCallback(nullptr); } else { sp<FrameCommitWrapper> wrapper = new FrameCommitWrapper{env, callback}; sp<FrameCommitWrapper> wrapper = sp<FrameCommitWrapper>::make(env, callback); proxy->setFrameCommitCallback( [wrapper](bool didProduceBuffer) { wrapper->onFrameCommit(didProduceBuffer); }); } Loading Loading @@ -1003,8 +1012,9 @@ int register_android_view_ThreadedRenderer(JNIEnv* env) { jclass frameCallbackClass = FindClassOrDie(env, "android/graphics/HardwareRenderer$FrameDrawingCallback"); gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass, "onFrameDraw", "(J)V"); gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass, "onFrameDraw", "(IJ)Landroid/graphics/HardwareRenderer$FrameCommitCallback;"); jclass frameCommitClass = FindClassOrDie(env, "android/graphics/HardwareRenderer$FrameCommitCallback"); Loading libs/hwui/renderthread/DrawFrameTask.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -158,7 +158,8 @@ void DrawFrameTask::run() { // Grab a copy of everything we need CanvasContext* context = mContext; std::function<void(int64_t)> frameCallback = std::move(mFrameCallback); std::function<std::function<void(bool)>(int32_t, int64_t)> frameCallback = std::move(mFrameCallback); std::function<void()> frameCompleteCallback = std::move(mFrameCompleteCallback); mFrameCallback = nullptr; mFrameCompleteCallback = nullptr; Loading @@ -173,8 +174,13 @@ void DrawFrameTask::run() { // Even if we aren't drawing this vsync pulse the next frame number will still be accurate if (CC_UNLIKELY(frameCallback)) { context->enqueueFrameWork( [frameCallback, frameNr = context->getFrameNumber()]() { frameCallback(frameNr); }); context->enqueueFrameWork([frameCallback, context, syncResult = mSyncResult, frameNr = context->getFrameNumber()]() { auto frameCommitCallback = std::move(frameCallback(syncResult, frameNr)); if (frameCommitCallback) { context->addFrameCommitListener(std::move(frameCommitCallback)); } }); } nsecs_t dequeueBufferDuration = 0; Loading Loading
core/java/android/view/ThreadedRenderer.java +38 −3 Original line number Diff line number Diff line Loading @@ -477,6 +477,19 @@ public final class ThreadedRenderer extends HardwareRenderer { mNextRtFrameCallbacks.add(callback); } /** * 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. Loading Loading @@ -679,9 +692,31 @@ public final class ThreadedRenderer extends HardwareRenderer { if (mNextRtFrameCallbacks != null) { final ArrayList<FrameDrawingCallback> frameCallbacks = mNextRtFrameCallbacks; mNextRtFrameCallbacks = null; setFrameCallback(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) { frameCallbacks.get(i).onFrameDraw(frame); 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); } }; } }); } Loading
core/java/android/view/ViewRootImpl.java +119 −78 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -1392,12 +1394,21 @@ public final class ViewRootImpl implements ViewParent, */ public void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) { if (mAttachInfo.mThreadedRenderer != null) { mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frame -> { mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() { @Override public void onFrameDraw(long frame) { } @Override public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { try { callback.onFrameDraw(frame); return callback.onFrameDraw(syncResult, frame); } catch (Exception e) { Log.e(TAG, "Exception while executing onFrameDraw", e); } return null; } }); } } Loading Loading @@ -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 Loading @@ -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); Loading @@ -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()); } 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(); } }); }); return null; } 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 -> { return new FrameDrawingCallback() { @Override public void onFrameDraw(long frame) { } @Override public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { if (DEBUG_BLAST) { Log.d(mTag, "Received frameDrawingCallback frameNum=" + frame + "." + " Creating transactionCompleteCallback=" + useBlastSync); Log.d(mTag, "Received frameDrawingCallback syncResult=" + syncResult + " frameNum=" + frame + "."); } mRtLastAttemptedDrawFrameNum = frame; if (needsCallbackForBlur) { mBlurRegionAggregator .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates); mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates); } if (mBlastBufferQueue == null) { return; return null; } 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 that. // We don't need to synchronize mRtBLASTSyncTransaction here since it's not // being modified and only sent to BlastBufferQueue. // 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) { Loading @@ -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; Loading
graphics/java/android/graphics/HardwareRenderer.java +14 −0 Original line number Diff line number Diff line Loading @@ -902,6 +902,20 @@ public class HardwareRenderer { * @param frame The id of the frame being drawn. */ void onFrameDraw(long frame); /** * Invoked during a frame drawing. * * @param syncResult The result of the draw. Should be a value or a combination of values * from {@link SyncAndDrawResult} * @param frame The id of the frame being drawn. * * @return A {@link FrameCommitCallback} that will report back if the current vsync draws. */ default FrameCommitCallback onFrameDraw(@SyncAndDrawResult int syncResult, long frame) { onFrameDraw(frame); return null; } } /** Loading
libs/hwui/jni/android_graphics_HardwareRenderer.cpp +16 −6 Original line number Diff line number Diff line Loading @@ -609,10 +609,19 @@ static void android_view_ThreadedRenderer_setFrameCallback(JNIEnv* env, LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM"); auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(frameCallback)); proxy->setFrameCallback([globalCallbackRef](int64_t frameNr) { proxy->setFrameCallback([globalCallbackRef](int32_t syncResult, int64_t frameNr) -> std::function<void(bool)> { JNIEnv* env = getenv(globalCallbackRef->vm()); env->CallVoidMethod(globalCallbackRef->object(), gFrameDrawingCallback.onFrameDraw, static_cast<jlong>(frameNr)); ScopedLocalRef<jobject> frameCommitCallback( env, env->CallObjectMethod( globalCallbackRef->object(), gFrameDrawingCallback.onFrameDraw, static_cast<jint>(syncResult), static_cast<jlong>(frameNr))); if (frameCommitCallback == nullptr) { return nullptr; } sp<FrameCommitWrapper> wrapper = sp<FrameCommitWrapper>::make(env, frameCommitCallback.get()); return [wrapper](bool didProduceBuffer) { wrapper->onFrameCommit(didProduceBuffer); }; }); } } Loading @@ -623,7 +632,7 @@ static void android_view_ThreadedRenderer_setFrameCommitCallback(JNIEnv* env, jo if (!callback) { proxy->setFrameCommitCallback(nullptr); } else { sp<FrameCommitWrapper> wrapper = new FrameCommitWrapper{env, callback}; sp<FrameCommitWrapper> wrapper = sp<FrameCommitWrapper>::make(env, callback); proxy->setFrameCommitCallback( [wrapper](bool didProduceBuffer) { wrapper->onFrameCommit(didProduceBuffer); }); } Loading Loading @@ -1003,8 +1012,9 @@ int register_android_view_ThreadedRenderer(JNIEnv* env) { jclass frameCallbackClass = FindClassOrDie(env, "android/graphics/HardwareRenderer$FrameDrawingCallback"); gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass, "onFrameDraw", "(J)V"); gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass, "onFrameDraw", "(IJ)Landroid/graphics/HardwareRenderer$FrameCommitCallback;"); jclass frameCommitClass = FindClassOrDie(env, "android/graphics/HardwareRenderer$FrameCommitCallback"); Loading
libs/hwui/renderthread/DrawFrameTask.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -158,7 +158,8 @@ void DrawFrameTask::run() { // Grab a copy of everything we need CanvasContext* context = mContext; std::function<void(int64_t)> frameCallback = std::move(mFrameCallback); std::function<std::function<void(bool)>(int32_t, int64_t)> frameCallback = std::move(mFrameCallback); std::function<void()> frameCompleteCallback = std::move(mFrameCompleteCallback); mFrameCallback = nullptr; mFrameCompleteCallback = nullptr; Loading @@ -173,8 +174,13 @@ void DrawFrameTask::run() { // Even if we aren't drawing this vsync pulse the next frame number will still be accurate if (CC_UNLIKELY(frameCallback)) { context->enqueueFrameWork( [frameCallback, frameNr = context->getFrameNumber()]() { frameCallback(frameNr); }); context->enqueueFrameWork([frameCallback, context, syncResult = mSyncResult, frameNr = context->getFrameNumber()]() { auto frameCommitCallback = std::move(frameCallback(syncResult, frameNr)); if (frameCommitCallback) { context->addFrameCommitListener(std::move(frameCommitCallback)); } }); } nsecs_t dequeueBufferDuration = 0; Loading