Merge "Rework blast sync callback model" into sc-v2-dev

This commit is contained in:
Rob Carr
2021-11-29 18:43:00 +00:00
committed by Android (Google) Code Review
11 changed files with 215 additions and 101 deletions

View File

@@ -767,6 +767,12 @@ public final class ViewRootImpl implements ViewParent,
*/
private boolean mWaitForBlastSyncComplete = false;
/**
* Keeps track of the last frame number that was attempted to draw. Should only be accessed on
* the RenderThread.
*/
private long mRtLastAttemptedDrawFrameNum = 0;
/**
* Keeps track of whether a traverse was triggered while the UI thread was paused. This can
* occur when the client is waiting on another process to submit the transaction that
@@ -4051,40 +4057,19 @@ public final class ViewRootImpl implements ViewParent,
}
/**
* The callback will run on the render thread.
* Only call this on the UI Thread.
*/
private HardwareRenderer.FrameCompleteCallback createFrameCompleteCallback(Handler handler,
boolean reportNextDraw, ArrayList<Runnable> commitCallbacks) {
final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer;
mBLASTDrawConsumer = null;
return frameNr -> {
if (DEBUG_BLAST) {
Log.d(mTag, "Received frameCompleteCallback frameNum=" + frameNr);
}
handler.postAtFrontOfQueue(() -> {
if (mNextDrawUseBlastSync) {
// We don't need to synchronize mRtBLASTSyncTransaction here since we're
// guaranteed that this is called after onFrameDraw and mNextDrawUseBlastSync
// is only true when the UI thread is paused. Therefore, no one should be
// modifying this object until the next vsync.
mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction);
if (blastSyncConsumer != null) {
blastSyncConsumer.accept(mSurfaceChangedTransaction);
}
}
if (reportNextDraw) {
// TODO: Use the frame number
pendingDrawFinished();
}
if (commitCallbacks != null) {
for (int i = 0; i < commitCallbacks.size(); i++) {
commitCallbacks.get(i).run();
}
}
});
};
void clearBlastSync() {
mNextDrawUseBlastSync = false;
mWaitForBlastSyncComplete = false;
if (DEBUG_BLAST) {
Log.d(mTag, "Scheduling a traversal=" + mRequestedTraverseWhilePaused
+ " due to a previous skipped traversal.");
}
if (mRequestedTraverseWhilePaused) {
mRequestedTraverseWhilePaused = false;
scheduleTraversals();
}
}
/**
@@ -4094,30 +4079,90 @@ public final class ViewRootImpl implements ViewParent,
return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled();
}
private boolean addFrameCompleteCallbackIfNeeded() {
private boolean addFrameCompleteCallbackIfNeeded(boolean reportNextDraw) {
if (!isHardwareEnabled()) {
return false;
}
if (!mNextDrawUseBlastSync && !reportNextDraw) {
return false;
}
if (DEBUG_BLAST) {
Log.d(mTag, "Creating frameCompleteCallback");
}
mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(() -> {
long frameNr = mBlastBufferQueue.getLastAcquiredFrameNum();
if (DEBUG_BLAST) {
Log.d(mTag, "Received frameCompleteCallback "
+ " lastAcquiredFrameNum=" + frameNr
+ " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum);
}
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) {
mBlastBufferQueue.setNextTransaction(null);
mBlastBufferQueue.setTransactionCompleteCallback(mRtLastAttemptedDrawFrameNum,
null);
}
mHandler.postAtFrontOfQueue(() -> {
if (mNextDrawUseBlastSync) {
// We don't need to synchronize mRtBLASTSyncTransaction here since we're
// guaranteed that this is called after onFrameDraw and mNextDrawUseBlastSync
// is only true when the UI thread is paused. Therefore, no one should be
// modifying this object until the next vsync.
mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction);
if (mBLASTDrawConsumer != null) {
mBLASTDrawConsumer.accept(mSurfaceChangedTransaction);
}
mBLASTDrawConsumer = null;
}
if (reportNextDraw) {
pendingDrawFinished();
}
if (frameWasNotDrawn) {
clearBlastSync();
}
});
});
return true;
}
private void addFrameCommitCallbackIfNeeded() {
if (!isHardwareEnabled()) {
return;
}
ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
.captureFrameCommitCallbacks();
final boolean needFrameCompleteCallback =
mNextDrawUseBlastSync || mReportNextDraw
|| (commitCallbacks != null && commitCallbacks.size() > 0);
if (needFrameCompleteCallback) {
if (DEBUG_BLAST) {
Log.d(mTag, "Creating frameCompleteCallback"
+ " mNextDrawUseBlastSync=" + mNextDrawUseBlastSync
+ " mReportNextDraw=" + mReportNextDraw
+ " commitCallbacks size="
+ (commitCallbacks == null ? 0 : commitCallbacks.size()));
}
mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(
createFrameCompleteCallback(mAttachInfo.mHandler, mReportNextDraw,
commitCallbacks));
return true;
final boolean needFrameCommitCallback =
(commitCallbacks != null && commitCallbacks.size() > 0);
if (!needFrameCommitCallback) {
return;
}
return false;
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();
}
});
});
}
private void addFrameCallbackIfNeeded() {
@@ -4147,6 +4192,8 @@ public final class ViewRootImpl implements ViewParent,
+ " Creating transactionCompleteCallback=" + nextDrawUseBlastSync);
}
mRtLastAttemptedDrawFrameNum = frame;
if (needsCallbackForBlur) {
mBlurRegionAggregator
.dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates);
@@ -4169,18 +4216,7 @@ public final class ViewRootImpl implements ViewParent,
if (DEBUG_BLAST) {
Log.d(mTag, "Received transactionCompleteCallback frameNum=" + frame);
}
mHandler.postAtFrontOfQueue(() -> {
mNextDrawUseBlastSync = false;
mWaitForBlastSyncComplete = false;
if (DEBUG_BLAST) {
Log.d(mTag, "Scheduling a traversal=" + mRequestedTraverseWhilePaused
+ " due to a previous skipped traversal.");
}
if (mRequestedTraverseWhilePaused) {
mRequestedTraverseWhilePaused = false;
scheduleTraversals();
}
});
mHandler.postAtFrontOfQueue(this::clearBlastSync);
});
}
};
@@ -4201,8 +4237,9 @@ public final class ViewRootImpl implements ViewParent,
mIsDrawing = true;
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded();
addFrameCallbackIfNeeded();
addFrameCommitCallbackIfNeeded();
boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded(mReportNextDraw);
try {
boolean canUseAsync = draw(fullRedrawNeeded);

View File

@@ -134,6 +134,11 @@ static void nativeSetTransactionCompleteCallback(JNIEnv* env, jclass clazz, jlon
}
}
static jlong nativeGetLastAcquiredFrameNum(JNIEnv* env, jclass clazz, jlong ptr) {
sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
return queue->getLastAcquiredFrameNum();
}
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
// clang-format off
@@ -145,7 +150,8 @@ static const JNINativeMethod gMethods[] = {
{"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
{"nativeSetTransactionCompleteCallback",
"(JJLandroid/graphics/BLASTBufferQueue$TransactionCompleteCallback;)V",
(void*)nativeSetTransactionCompleteCallback}
(void*)nativeSetTransactionCompleteCallback},
{"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum},
// clang-format on
};

View File

@@ -38,6 +38,7 @@ public final class BLASTBufferQueue {
long frameNumber);
private static native void nativeSetTransactionCompleteCallback(long ptr, long frameNumber,
TransactionCompleteCallback callback);
private static native long nativeGetLastAcquiredFrameNum(long ptr);
/**
* Callback sent to {@link #setTransactionCompleteCallback(long, TransactionCompleteCallback)}
@@ -140,4 +141,7 @@ public final class BLASTBufferQueue {
nativeMergeWithNextTransaction(mNativeObject, nativeTransaction, frameNumber);
}
public long getLastAcquiredFrameNum() {
return nativeGetLastAcquiredFrameNum(mNativeObject);
}
}

View File

@@ -388,7 +388,8 @@ public class HardwareRenderer {
*/
public @NonNull FrameRenderRequest setFrameCommitCallback(@NonNull Executor executor,
@NonNull Runnable frameCommitCallback) {
setFrameCompleteCallback(frameNr -> executor.execute(frameCommitCallback));
nSetFrameCommitCallback(mNativeProxy,
didProduceBuffer -> executor.execute(frameCommitCallback));
return this;
}
@@ -608,6 +609,11 @@ public class HardwareRenderer {
return mOpaque;
}
/** @hide */
public void setFrameCommitCallback(FrameCommitCallback callback) {
nSetFrameCommitCallback(mNativeProxy, callback);
}
/** @hide */
public void setFrameCompleteCallback(FrameCompleteCallback callback) {
nSetFrameCompleteCallback(mNativeProxy, callback);
@@ -904,13 +910,27 @@ public class HardwareRenderer {
*
* @hide
*/
public interface FrameCommitCallback {
/**
* Invoked after a new frame was drawn
*
* @param didProduceBuffer The draw successfully produced a new buffer.
*/
void onFrameCommit(boolean didProduceBuffer);
}
/**
* Interface used to be notified when RenderThread has finished an attempt to draw. This doesn't
* mean a new frame has drawn, specifically if there's nothing new to draw, but only that
* RenderThread had a chance to draw a frame.
*
* @hide
*/
public interface FrameCompleteCallback {
/**
* Invoked after a frame draw
*
* @param frameNr The id of the frame that was drawn.
* Invoked after a frame draw was attempted.
*/
void onFrameComplete(long frameNr);
void onFrameComplete();
}
/**
@@ -1362,6 +1382,9 @@ public class HardwareRenderer {
private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback);
private static native void nSetFrameCommitCallback(long nativeProxy,
FrameCommitCallback callback);
private static native void nSetFrameCompleteCallback(long nativeProxy,
FrameCompleteCallback callback);

View File

@@ -72,6 +72,10 @@ struct {
jmethodID onFrameDraw;
} gFrameDrawingCallback;
struct {
jmethodID onFrameCommit;
} gFrameCommitCallback;
struct {
jmethodID onFrameComplete;
} gFrameCompleteCallback;
@@ -101,22 +105,21 @@ private:
JavaVM* mVm;
};
class FrameCompleteWrapper : public LightRefBase<FrameCompleteWrapper> {
class FrameCommitWrapper : public LightRefBase<FrameCommitWrapper> {
public:
explicit FrameCompleteWrapper(JNIEnv* env, jobject jobject) {
explicit FrameCommitWrapper(JNIEnv* env, jobject jobject) {
env->GetJavaVM(&mVm);
mObject = env->NewGlobalRef(jobject);
LOG_ALWAYS_FATAL_IF(!mObject, "Failed to make global ref");
}
~FrameCompleteWrapper() {
releaseObject();
}
~FrameCommitWrapper() { releaseObject(); }
void onFrameComplete(int64_t frameNr) {
void onFrameCommit(bool didProduceBuffer) {
if (mObject) {
ATRACE_FORMAT("frameComplete %" PRId64, frameNr);
getenv(mVm)->CallVoidMethod(mObject, gFrameCompleteCallback.onFrameComplete, frameNr);
ATRACE_FORMAT("frameCommit success=%d", didProduceBuffer);
getenv(mVm)->CallVoidMethod(mObject, gFrameCommitCallback.onFrameCommit,
didProduceBuffer);
releaseObject();
}
}
@@ -637,15 +640,33 @@ static void android_view_ThreadedRenderer_setFrameCallback(JNIEnv* env,
}
}
static void android_view_ThreadedRenderer_setFrameCommitCallback(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject callback) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
if (!callback) {
proxy->setFrameCommitCallback(nullptr);
} else {
sp<FrameCommitWrapper> wrapper = new FrameCommitWrapper{env, callback};
proxy->setFrameCommitCallback(
[wrapper](bool didProduceBuffer) { wrapper->onFrameCommit(didProduceBuffer); });
}
}
static void android_view_ThreadedRenderer_setFrameCompleteCallback(JNIEnv* env,
jobject clazz, jlong proxyPtr, jobject callback) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
if (!callback) {
proxy->setFrameCompleteCallback(nullptr);
} else {
sp<FrameCompleteWrapper> wrapper = new FrameCompleteWrapper{env, callback};
proxy->setFrameCompleteCallback([wrapper](int64_t frameNr) {
wrapper->onFrameComplete(frameNr);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
JavaVM* vm = nullptr;
LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
auto globalCallbackRef =
std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(callback));
proxy->setFrameCompleteCallback([globalCallbackRef]() {
JNIEnv* env = getenv(globalCallbackRef->vm());
env->CallVoidMethod(globalCallbackRef->object(),
gFrameCompleteCallback.onFrameComplete);
});
}
}
@@ -929,6 +950,8 @@ static const JNINativeMethod gMethods[] = {
(void*)android_view_ThreadedRenderer_setPrepareSurfaceControlForWebviewCallback},
{"nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V",
(void*)android_view_ThreadedRenderer_setFrameCallback},
{"nSetFrameCommitCallback", "(JLandroid/graphics/HardwareRenderer$FrameCommitCallback;)V",
(void*)android_view_ThreadedRenderer_setFrameCommitCallback},
{"nSetFrameCompleteCallback",
"(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V",
(void*)android_view_ThreadedRenderer_setFrameCompleteCallback},
@@ -994,10 +1017,15 @@ int register_android_view_ThreadedRenderer(JNIEnv* env) {
gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,
"onFrameDraw", "(J)V");
jclass frameCommitClass =
FindClassOrDie(env, "android/graphics/HardwareRenderer$FrameCommitCallback");
gFrameCommitCallback.onFrameCommit =
GetMethodIDOrDie(env, frameCommitClass, "onFrameCommit", "(Z)V");
jclass frameCompleteClass = FindClassOrDie(env,
"android/graphics/HardwareRenderer$FrameCompleteCallback");
gFrameCompleteCallback.onFrameComplete = GetMethodIDOrDie(env, frameCompleteClass,
"onFrameComplete", "(J)V");
gFrameCompleteCallback.onFrameComplete =
GetMethodIDOrDie(env, frameCompleteClass, "onFrameComplete", "()V");
void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
fromSurface = (ANW_fromSurface)dlsym(handle_, "ANativeWindow_fromSurface");

View File

@@ -491,10 +491,10 @@ nsecs_t CanvasContext::draw() {
// Notify the callbacks, even if there's nothing to draw so they aren't waiting
// indefinitely
waitOnFences();
for (auto& func : mFrameCompleteCallbacks) {
std::invoke(func, mFrameNumber);
for (auto& func : mFrameCommitCallbacks) {
std::invoke(func, false /* didProduceBuffer */);
}
mFrameCompleteCallbacks.clear();
mFrameCommitCallbacks.clear();
return 0;
}
@@ -603,10 +603,10 @@ nsecs_t CanvasContext::draw() {
#endif
if (didSwap) {
for (auto& func : mFrameCompleteCallbacks) {
std::invoke(func, frameCompleteNr);
for (auto& func : mFrameCommitCallbacks) {
std::invoke(func, true /* didProduceBuffer */);
}
mFrameCompleteCallbacks.clear();
mFrameCommitCallbacks.clear();
}
if (requireSwap) {

View File

@@ -187,8 +187,8 @@ public:
IRenderPipeline* getRenderPipeline() { return mRenderPipeline.get(); }
void addFrameCompleteListener(std::function<void(int64_t)>&& func) {
mFrameCompleteCallbacks.push_back(std::move(func));
void addFrameCommitListener(std::function<void(bool)>&& func) {
mFrameCommitCallbacks.push_back(std::move(func));
}
void setPictureCapturedCallback(const std::function<void(sk_sp<SkPicture>&&)>& callback) {
@@ -320,7 +320,7 @@ private:
std::vector<std::future<void>> mFrameFences;
std::unique_ptr<IRenderPipeline> mRenderPipeline;
std::vector<std::function<void(int64_t)>> mFrameCompleteCallbacks;
std::vector<std::function<void(bool)>> mFrameCommitCallbacks;
// If set to true, we expect that callbacks into onSurfaceStatsAvailable
bool mExpectSurfaceStats = false;

View File

@@ -150,16 +150,18 @@ void DrawFrameTask::run() {
canUnblockUiThread = syncFrameState(info);
canDrawThisFrame = info.out.canDrawThisFrame;
if (mFrameCompleteCallback) {
mContext->addFrameCompleteListener(std::move(mFrameCompleteCallback));
mFrameCompleteCallback = nullptr;
if (mFrameCommitCallback) {
mContext->addFrameCommitListener(std::move(mFrameCommitCallback));
mFrameCommitCallback = nullptr;
}
}
// Grab a copy of everything we need
CanvasContext* context = mContext;
std::function<void(int64_t)> callback = std::move(mFrameCallback);
std::function<void(int64_t)> frameCallback = std::move(mFrameCallback);
std::function<void()> frameCompleteCallback = std::move(mFrameCompleteCallback);
mFrameCallback = nullptr;
mFrameCompleteCallback = nullptr;
int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)];
int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)];
int64_t frameStartTime = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameStartTime)];
@@ -170,9 +172,9 @@ void DrawFrameTask::run() {
}
// Even if we aren't drawing this vsync pulse the next frame number will still be accurate
if (CC_UNLIKELY(callback)) {
if (CC_UNLIKELY(frameCallback)) {
context->enqueueFrameWork(
[callback, frameNr = context->getFrameNumber()]() { callback(frameNr); });
[frameCallback, frameNr = context->getFrameNumber()]() { frameCallback(frameNr); });
}
nsecs_t dequeueBufferDuration = 0;
@@ -189,6 +191,10 @@ void DrawFrameTask::run() {
context->waitOnFences();
}
if (CC_UNLIKELY(frameCompleteCallback)) {
std::invoke(frameCompleteCallback);
}
if (!canUnblockUiThread) {
unblockUiThread();
}

View File

@@ -81,7 +81,11 @@ public:
mFrameCallback = std::move(callback);
}
void setFrameCompleteCallback(std::function<void(int64_t)>&& callback) {
void setFrameCommitCallback(std::function<void(bool)>&& callback) {
mFrameCommitCallback = std::move(callback);
}
void setFrameCompleteCallback(std::function<void()>&& callback) {
mFrameCompleteCallback = std::move(callback);
}
@@ -123,7 +127,8 @@ private:
int64_t mFrameInfo[UI_THREAD_FRAME_INFO_SIZE];
std::function<void(int64_t)> mFrameCallback;
std::function<void(int64_t)> mFrameCompleteCallback;
std::function<void(bool)> mFrameCommitCallback;
std::function<void()> mFrameCompleteCallback;
nsecs_t mLastDequeueBufferDuration = 0;
nsecs_t mLastTargetWorkDuration = 0;

View File

@@ -326,7 +326,11 @@ void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) {
mDrawFrameTask.setFrameCallback(std::move(callback));
}
void RenderProxy::setFrameCompleteCallback(std::function<void(int64_t)>&& callback) {
void RenderProxy::setFrameCommitCallback(std::function<void(bool)>&& callback) {
mDrawFrameTask.setFrameCommitCallback(std::move(callback));
}
void RenderProxy::setFrameCompleteCallback(std::function<void()>&& callback) {
mDrawFrameTask.setFrameCompleteCallback(std::move(callback));
}

View File

@@ -124,7 +124,8 @@ public:
const std::function<bool(int64_t, int64_t, int64_t)>& callback);
void setPrepareSurfaceControlForWebviewCallback(const std::function<void()>& callback);
void setFrameCallback(std::function<void(int64_t)>&& callback);
void setFrameCompleteCallback(std::function<void(int64_t)>&& callback);
void setFrameCommitCallback(std::function<void(bool)>&& callback);
void setFrameCompleteCallback(std::function<void()>&& callback);
void addFrameMetricsObserver(FrameMetricsObserver* observer);
void removeFrameMetricsObserver(FrameMetricsObserver* observer);