summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/SurfaceView.java33
-rw-r--r--core/java/android/view/ViewRootImpl.java73
-rw-r--r--core/java/android/window/SurfaceSyncer.java23
-rw-r--r--core/jni/android_graphics_BLASTBufferQueue.cpp67
-rw-r--r--graphics/java/android/graphics/BLASTBufferQueue.java50
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerValidatorTestCase.java5
-rw-r--r--tests/SurfaceViewSyncTest/src/com/android/test/SurfaceViewSyncActivity.java73
7 files changed, 201 insertions, 123 deletions
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 6d94de7e1f90..413855639d09 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -51,6 +51,7 @@ import com.android.internal.view.SurfaceCallbackHelper;
import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
/**
* Provides a dedicated drawing surface embedded inside of a view hierarchy.
@@ -390,8 +391,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
}
- private void performDrawFinished(Transaction t) {
- mSyncTransaction.merge(t);
+ private void performDrawFinished(@Nullable Transaction t) {
+ if (t != null) {
+ mSyncTransaction.merge(t);
+ }
if (mPendingReportDraws > 0) {
mDrawFinished = true;
@@ -1038,16 +1041,24 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
callbacks = getSurfaceCallbacks();
}
- final Transaction t = new Transaction();
- if (viewRoot.wasRelayoutRequested()) {
- mBlastBufferQueue.setSyncTransaction(t,
- false /* acquireSingleBuffer */);
+ final boolean wasRelayoutRequested = viewRoot.wasRelayoutRequested();
+ if (wasRelayoutRequested && (mBlastBufferQueue != null)) {
+ mBlastBufferQueue.syncNextTransaction(
+ false /* acquireSingleBuffer */,
+ this::onDrawFinished);
}
mPendingReportDraws++;
viewRoot.drawPending();
SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> {
- mBlastBufferQueue.setSyncTransaction(null);
- onDrawFinished(t);
+ if (mBlastBufferQueue != null) {
+ mBlastBufferQueue.stopContinuousSyncTransaction();
+ }
+ // If relayout was requested, then a callback from BBQ will
+ // be invoked with the sync transaction. onDrawFinished will be
+ // called in there
+ if (!wasRelayoutRequested) {
+ onDrawFinished(null);
+ }
});
sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
}
@@ -1178,7 +1189,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat);
}
- private void onDrawFinished(Transaction t) {
+ private void onDrawFinished(@Nullable Transaction t) {
if (DEBUG) {
Log.i(TAG, System.identityHashCode(this) + " "
+ "finishedDrawing");
@@ -1792,7 +1803,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
/**
* @hide
*/
- public void syncNextFrame(Transaction t) {
- mBlastBufferQueue.setSyncTransaction(t);
+ public void syncNextFrame(Consumer<Transaction> t) {
+ mBlastBufferQueue.syncNextTransaction(t);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 760e021bd4ab..bde761e59620 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -804,15 +804,6 @@ public final class ViewRootImpl implements ViewParent,
}
/**
- * This is only used on the RenderThread when handling a blast sync. Specifically, it's only
- * used when calling {@link BLASTBufferQueue#setSyncTransaction(Transaction)} and then merged
- * with a tmp transaction on the Render Thread. The tmp transaction is then merged into
- * {@link #mSurfaceChangedTransaction} on the UI Thread, avoiding any threading issues.
- */
- private final SurfaceControl.Transaction mRtBLASTSyncTransaction =
- new SurfaceControl.Transaction();
-
- /**
* Keeps track of the last frame number that was attempted to draw. Should only be accessed on
* the RenderThread.
*/
@@ -4175,43 +4166,49 @@ public final class ViewRootImpl implements ViewParent,
+ " didProduceBuffer=" + didProduceBuffer);
}
- final Transaction tmpTransaction = new Transaction();
- tmpTransaction.merge(mRtBLASTSyncTransaction);
-
// 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.
+ final Transaction pendingTransactions;
if (!didProduceBuffer) {
- mBlastBufferQueue.setSyncTransaction(null);
+ mBlastBufferQueue.syncNextTransaction(null);
// Get 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
// it's better to not be sync than to block on a frame that may never come.
- Transaction pendingTransactions = mBlastBufferQueue.gatherPendingTransactions(
+ pendingTransactions = mBlastBufferQueue.gatherPendingTransactions(
mRtLastAttemptedDrawFrameNum);
- tmpTransaction.merge(pendingTransactions);
- }
- if (!useBlastSync && !reportNextDraw) {
- tmpTransaction.apply();
+ if (!useBlastSync && !reportNextDraw) {
+ pendingTransactions.apply();
+ }
+ } else {
+ pendingTransactions = null;
}
-
// 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);
+ if (!didProduceBuffer && useBlastSync) {
+ mSurfaceChangedTransaction.merge(pendingTransactions);
if (blastSyncConsumer != null) {
blastSyncConsumer.accept(mSurfaceChangedTransaction);
}
}
- tmpTransaction.close();
- if (reportNextDraw) {
+ // This is to ensure pendingDrawFinished is only called exactly one time per draw
+ // attempt when reportNextDraw is true. Since, we sometimes create a sync
+ // transaction callback, the callback will handle calling pendingDrawFinished.
+ // However, there are cases where the transaction callback may not be called.
+ // 1. If useBlastSync is false, then we know that a sync transaction callback was
+ // not created so we won't invoke pendingDrawFinished there.
+ // 2. If the draw didn't produce a frame, didProduceBuffer == false, then we know
+ // the sync transaction callback will not be invoked even if one was set up.
+ if (reportNextDraw && (!didProduceBuffer || !useBlastSync)) {
pendingDrawFinished();
}
});
+
};
}
@@ -4294,7 +4291,19 @@ public final class ViewRootImpl implements ViewParent,
// 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);
+ mBlastBufferQueue.syncNextTransaction(
+ t -> {
+ mHandler.postAtFrontOfQueue(() -> {
+ mSurfaceChangedTransaction.merge(t);
+ if (blastSyncConsumer != null) {
+ blastSyncConsumer.accept(mSurfaceChangedTransaction);
+ }
+
+ if (reportNextDraw) {
+ pendingDrawFinished();
+ }
+ });
+ });
}
return createFrameCommitCallbackForSync(useBlastSync, reportNextDraw,
@@ -10928,24 +10937,23 @@ public final class ViewRootImpl implements ViewParent,
+ frame + ".");
}
- final Transaction t = new Transaction();
-
// 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) {
- t.merge(mBlastBufferQueue.gatherPendingTransactions(frame));
- syncBufferCallback.onBufferReady(t);
+ syncBufferCallback.onBufferReady(
+ mBlastBufferQueue.gatherPendingTransactions(frame));
return null;
}
- mBlastBufferQueue.setSyncTransaction(t);
if (DEBUG_BLAST) {
Log.d(mTag, "Setting up sync and frameCommitCallback");
}
+ mBlastBufferQueue.syncNextTransaction(t -> syncBufferCallback.onBufferReady(t));
+
return didProduceBuffer -> {
if (DEBUG_BLAST) {
Log.d(mTag, "Received frameCommittedCallback"
@@ -10957,15 +10965,14 @@ public final class ViewRootImpl implements ViewParent,
// the next draw attempt. The next transaction and transaction complete callback
// were only set for the current draw attempt.
if (!didProduceBuffer) {
- mBlastBufferQueue.setSyncTransaction(null);
+ mBlastBufferQueue.syncNextTransaction(null);
// Gather 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 it's better to not be sync than to block on a frame that
// may never come.
- t.merge(mBlastBufferQueue.gatherPendingTransactions(frame));
+ syncBufferCallback.onBufferReady(
+ mBlastBufferQueue.gatherPendingTransactions(frame));
}
-
- syncBufferCallback.onBufferReady(t);
};
}
});
diff --git a/core/java/android/window/SurfaceSyncer.java b/core/java/android/window/SurfaceSyncer.java
index a5930757cae6..0c32219f79a0 100644
--- a/core/java/android/window/SurfaceSyncer.java
+++ b/core/java/android/window/SurfaceSyncer.java
@@ -343,35 +343,20 @@ public class SurfaceSyncer {
@Override
public void onReadyToSync(SyncBufferCallback syncBufferCallback) {
- Transaction mTransaction = sTransactionFactory.get();
- mFrameCallbackConsumer.accept(new SurfaceViewFrameCallback() {
- @Override
- public void onFrameStarted() {
- mSurfaceView.syncNextFrame(mTransaction);
- }
-
- @Override
- public void onFrameComplete() {
- syncBufferCallback.onBufferReady(mTransaction);
- }
- });
+ mFrameCallbackConsumer.accept(
+ () -> mSurfaceView.syncNextFrame(syncBufferCallback::onBufferReady));
}
}
/**
* A frame callback that is used to synchronize SurfaceViews. The owner of the SurfaceView must
- * implement onFrameStarted and onFrameComplete when trying to sync the SurfaceView. This is to
- * ensure the sync knows when the frame is ready to add to the sync.
+ * implement onFrameStarted when trying to sync the SurfaceView. This is to ensure the sync
+ * knows when the frame is ready to add to the sync.
*/
public interface SurfaceViewFrameCallback {
/**
* Called when the SurfaceView is going to render a frame
*/
void onFrameStarted();
-
- /**
- * Called when the SurfaceView has finished rendering a frame.
- */
- void onFrameComplete();
}
}
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index 3be0eb88a91f..c0f7b41d116d 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -35,6 +35,18 @@ static struct {
jmethodID ctor;
} gTransactionClassInfo;
+struct {
+ jmethodID accept;
+} gTransactionConsumer;
+
+static JNIEnv* getenv(JavaVM* vm) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
+ }
+ return env;
+}
+
static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName,
jboolean updateDestinationFrame) {
ScopedUtfChars name(env, jName);
@@ -55,11 +67,51 @@ static jobject nativeGetSurface(JNIEnv* env, jclass clazz, jlong ptr,
queue->getSurface(includeSurfaceControlHandle));
}
-static void nativeSetSyncTransaction(JNIEnv* env, jclass clazz, jlong ptr, jlong transactionPtr,
- jboolean acquireSingleBuffer) {
+class JGlobalRefHolder {
+public:
+ JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {}
+
+ virtual ~JGlobalRefHolder() {
+ getenv(mVm)->DeleteGlobalRef(mObject);
+ mObject = nullptr;
+ }
+
+ jobject object() { return mObject; }
+ JavaVM* vm() { return mVm; }
+
+private:
+ JGlobalRefHolder(const JGlobalRefHolder&) = delete;
+ void operator=(const JGlobalRefHolder&) = delete;
+
+ JavaVM* mVm;
+ jobject mObject;
+};
+
+static void nativeSyncNextTransaction(JNIEnv* env, jclass clazz, jlong ptr, jobject callback,
+ jboolean acquireSingleBuffer) {
sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
- auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionPtr);
- queue->setSyncTransaction(transaction, acquireSingleBuffer);
+ JavaVM* vm = nullptr;
+ LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
+ if (!callback) {
+ queue->syncNextTransaction(nullptr, acquireSingleBuffer);
+ } else {
+ auto globalCallbackRef =
+ std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(callback));
+ queue->syncNextTransaction(
+ [globalCallbackRef](SurfaceComposerClient::Transaction* t) {
+ JNIEnv* env = getenv(globalCallbackRef->vm());
+ env->CallVoidMethod(globalCallbackRef->object(), gTransactionConsumer.accept,
+ env->NewObject(gTransactionClassInfo.clazz,
+ gTransactionClassInfo.ctor,
+ reinterpret_cast<jlong>(t)));
+ },
+ acquireSingleBuffer);
+ }
+}
+
+static void nativeStopContinuousSyncTransaction(JNIEnv* env, jclass clazz, jlong ptr) {
+ sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
+ queue->stopContinuousSyncTransaction();
}
static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width,
@@ -104,7 +156,8 @@ static const JNINativeMethod gMethods[] = {
{"nativeCreate", "(Ljava/lang/String;Z)J", (void*)nativeCreate},
{"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface},
{"nativeDestroy", "(J)V", (void*)nativeDestroy},
- {"nativeSetSyncTransaction", "(JJZ)V", (void*)nativeSetSyncTransaction},
+ {"nativeSyncNextTransaction", "(JLjava/util/function/Consumer;Z)V", (void*)nativeSyncNextTransaction},
+ {"nativeStopContinuousSyncTransaction", "(J)V", (void*)nativeStopContinuousSyncTransaction},
{"nativeUpdate", "(JJJJI)V", (void*)nativeUpdate},
{"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
{"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum},
@@ -123,6 +176,10 @@ int register_android_graphics_BLASTBufferQueue(JNIEnv* env) {
gTransactionClassInfo.clazz = MakeGlobalRefOrDie(env, transactionClazz);
gTransactionClassInfo.ctor =
GetMethodIDOrDie(env, gTransactionClassInfo.clazz, "<init>", "(J)V");
+
+ jclass consumer = FindClassOrDie(env, "java/util/function/Consumer");
+ gTransactionConsumer.accept =
+ GetMethodIDOrDie(env, consumer, "accept", "(Ljava/lang/Object;)V");
return 0;
}
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 369f20fb52a7..7f70e1cce6f5 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -16,10 +16,11 @@
package android.graphics;
-import android.annotation.Nullable;
import android.view.Surface;
import android.view.SurfaceControl;
+import java.util.function.Consumer;
+
/**
* @hide
*/
@@ -30,8 +31,9 @@ public final class BLASTBufferQueue {
private static native long nativeCreate(String name, boolean updateDestinationFrame);
private static native void nativeDestroy(long ptr);
private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle);
- private static native void nativeSetSyncTransaction(long ptr, long transactionPtr,
- boolean acquireSingleBuffer);
+ private static native void nativeSyncNextTransaction(long ptr,
+ Consumer<SurfaceControl.Transaction> callback, boolean acquireSingleBuffer);
+ private static native void nativeStopContinuousSyncTransaction(long ptr);
private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height,
int format);
private static native void nativeMergeWithNextTransaction(long ptr, long transactionPtr,
@@ -74,25 +76,39 @@ public final class BLASTBufferQueue {
}
/**
- * Send the transaction to BBQ so the next frame can be added and not applied immediately. This
- * gives the caller a chance to apply the transaction when it's ready.
- *
- * @param t The transaction to add the frame to. This can be null to clear the
- * transaction.
+ * Send a callback that accepts a transaction to BBQ. BBQ will acquire buffers into the a
+ * transaction it created and will eventually send the transaction into the callback
+ * when it is ready.
+ * @param callback The callback invoked when the buffer has been added to the transaction. The
+ * callback will contain the transaction with the buffer.
* @param acquireSingleBuffer If true, only acquire a single buffer when processing frames. The
- * transaction will be cleared once a single buffer has been
+ * callback will be cleared once a single buffer has been
* acquired. If false, continue to acquire all buffers into the
- * transaction until setSyncTransaction is called again with a null
- * transaction.
+ * transaction until stopContinuousSyncTransaction is called.
+ */
+ public void syncNextTransaction(boolean acquireSingleBuffer,
+ Consumer<SurfaceControl.Transaction> callback) {
+ nativeSyncNextTransaction(mNativeObject, callback, acquireSingleBuffer);
+ }
+
+ /**
+ * Send a callback that accepts a transaction to BBQ. BBQ will acquire buffers into the a
+ * transaction it created and will eventually send the transaction into the callback
+ * when it is ready.
+ * @param callback The callback invoked when the buffer has been added to the transaction. The
+ * callback will contain the transaction with the buffer.
*/
- public void setSyncTransaction(@Nullable SurfaceControl.Transaction t,
- boolean acquireSingleBuffer) {
- nativeSetSyncTransaction(mNativeObject, t == null ? 0 : t.mNativeObject,
- acquireSingleBuffer);
+ public void syncNextTransaction(Consumer<SurfaceControl.Transaction> callback) {
+ syncNextTransaction(true /* acquireSingleBuffer */, callback);
}
- public void setSyncTransaction(@Nullable SurfaceControl.Transaction t) {
- setSyncTransaction(t, true /* acquireSingleBuffer */);
+ /**
+ * Tell BBQ to stop acquiring buffers into a single transaction. BBQ will send the sync
+ * transaction callback after this has been called. This should only be used when
+ * syncNextTransaction was called with acquireSingleBuffer set to false.
+ */
+ public void stopContinuousSyncTransaction() {
+ nativeStopContinuousSyncTransaction(mNativeObject);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerValidatorTestCase.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerValidatorTestCase.java
index 77a8615e20d6..d65b80ae0700 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerValidatorTestCase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncerValidatorTestCase.java
@@ -179,11 +179,6 @@ public class SurfaceSyncerValidatorTestCase implements ISurfaceValidatorTestCase
mSurfaceHolder.unlockCanvasAndPost(c);
}
- if (mFrameCallback != null) {
- Log.d(TAG, "onFrameComplete");
- mFrameCallback.onFrameComplete();
- }
-
mFrameCallback = null;
}
}
diff --git a/tests/SurfaceViewSyncTest/src/com/android/test/SurfaceViewSyncActivity.java b/tests/SurfaceViewSyncTest/src/com/android/test/SurfaceViewSyncActivity.java
index 06accec09686..ab7f24a8d326 100644
--- a/tests/SurfaceViewSyncTest/src/com/android/test/SurfaceViewSyncActivity.java
+++ b/tests/SurfaceViewSyncTest/src/com/android/test/SurfaceViewSyncActivity.java
@@ -19,6 +19,9 @@ package com.android.test;
import android.annotation.NonNull;
import android.app.Activity;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
@@ -51,6 +54,8 @@ public class SurfaceViewSyncActivity extends Activity implements SurfaceHolder.C
private Button mExpandButton;
private Switch mEnableSyncSwitch;
+ private int mLastSyncId = -1;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -71,6 +76,10 @@ public class SurfaceViewSyncActivity extends Activity implements SurfaceHolder.C
}
private void updateSurfaceViewSize(Rect bounds, View container) {
+ if (mLastSyncId >= 0) {
+ return;
+ }
+
final float height;
if (mLastExpanded) {
height = bounds.height() / 2f;
@@ -82,13 +91,8 @@ public class SurfaceViewSyncActivity extends Activity implements SurfaceHolder.C
mLastExpanded = !mLastExpanded;
if (mEnableSyncSwitch.isChecked()) {
- int syncId = mSurfaceSyncer.setupSync(() -> { });
- mSurfaceSyncer.addToSync(syncId, mSurfaceView, frameCallback ->
- mRenderingThread.setFrameCallback(frameCallback));
- mSurfaceSyncer.addToSync(syncId, container);
- mSurfaceSyncer.markSyncReady(syncId);
- } else {
- mRenderingThread.renderSlow();
+ mLastSyncId = mSurfaceSyncer.setupSync(() -> { });
+ mSurfaceSyncer.addToSync(mLastSyncId, container);
}
ViewGroup.LayoutParams svParams = mSurfaceView.getLayoutParams();
@@ -99,13 +103,26 @@ public class SurfaceViewSyncActivity extends Activity implements SurfaceHolder.C
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
final Canvas canvas = holder.lockCanvas();
- canvas.drawARGB(255, 100, 100, 100);
+ canvas.drawARGB(255, 255, 0, 0);
holder.unlockCanvasAndPost(canvas);
mRenderingThread.startRendering();
+ mRenderingThread.renderFrame(null, mSurfaceView.getWidth(), mSurfaceView.getHeight());
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
+ if (mEnableSyncSwitch.isChecked()) {
+ if (mLastSyncId < 0) {
+ mRenderingThread.renderFrame(null, width, height);
+ return;
+ }
+ mSurfaceSyncer.addToSync(mLastSyncId, mSurfaceView, frameCallback ->
+ mRenderingThread.renderFrame(frameCallback, width, height));
+ mSurfaceSyncer.markSyncReady(mLastSyncId);
+ mLastSyncId = -1;
+ } else {
+ mRenderingThread.renderFrame(null, width, height);
+ }
}
@Override
@@ -117,31 +134,30 @@ public class SurfaceViewSyncActivity extends Activity implements SurfaceHolder.C
private final SurfaceHolder mSurfaceHolder;
private Handler mHandler;
private SurfaceSyncer.SurfaceViewFrameCallback mFrameCallback;
- private boolean mRenderSlow;
+ private final Point mSurfaceSize = new Point();
int mColorValue = 0;
int mColorDelta = 10;
+ private final Paint mPaint = new Paint();
RenderingThread(SurfaceHolder holder) {
super("RenderingThread");
mSurfaceHolder = holder;
+ mPaint.setColor(Color.BLACK);
+ mPaint.setTextSize(100);
}
- public void setFrameCallback(SurfaceSyncer.SurfaceViewFrameCallback frameCallback) {
+ public void renderFrame(SurfaceSyncer.SurfaceViewFrameCallback frameCallback, int width,
+ int height) {
if (mHandler != null) {
mHandler.post(() -> {
mFrameCallback = frameCallback;
- mRenderSlow = true;
+ mSurfaceSize.set(width, height);
+ mRunnable.run();
});
}
}
- public void renderSlow() {
- if (mHandler != null) {
- mHandler.post(() -> mRenderSlow = true);
- }
- }
-
private final Runnable mRunnable = new Runnable() {
@Override
public void run() {
@@ -149,13 +165,10 @@ public class SurfaceViewSyncActivity extends Activity implements SurfaceHolder.C
mFrameCallback.onFrameStarted();
}
- if (mRenderSlow) {
- try {
- // Long delay from start to finish to mimic slow draw
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- }
- mRenderSlow = false;
+ try {
+ // Long delay from start to finish to mimic slow draw
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
}
mColorValue += mColorDelta;
@@ -164,27 +177,21 @@ public class SurfaceViewSyncActivity extends Activity implements SurfaceHolder.C
}
Canvas c = mSurfaceHolder.lockCanvas();
- c.drawRGB(255, mColorValue, 255 - mColorValue);
+ c.drawRGB(255, 0, 0);
+ c.drawText("RENDERED CONTENT", 0, mSurfaceSize.y / 2, mPaint);
mSurfaceHolder.unlockCanvasAndPost(c);
-
- if (mFrameCallback != null) {
- mFrameCallback.onFrameComplete();
- }
mFrameCallback = null;
-
- mHandler.postDelayed(this, 50);
}
};
public void startRendering() {
start();
mHandler = new Handler(getLooper());
- mHandler.post(mRunnable);
}
public void stopRendering() {
if (mHandler != null) {
- mHandler.post(() -> mHandler.removeCallbacks(mRunnable));
+ mHandler.removeCallbacks(mRunnable);
}
}
}