summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Robert Carr <racarr@google.com> 2016-11-16 13:24:09 -0800
committer Robert Carr <racarr@google.com> 2017-01-09 10:44:58 -0800
commit25cfa134835e3791bdb6572f5e25cf4599015678 (patch)
tree11e3a4ef30dca52c893bde1275b639f675453131
parent50e0a9a396ec05ed6a73d3c09f95244038f8d8e3 (diff)
Provide non-blocking SurfaceView draw notification path.
SurfaceView needs to notify the window manager that drawing has been completed, so that animations and such can begin. Currently this is implemented through having the SurfaceView user block in surfaceRedrawNeeded (called from UI thread) until a frame has been completed. This blocking can be unnecessary serialization during startup, and also clumsy to implement for some users. Test: GLSurfaceView and takeSurface API Demos, android.server.cts.SurfaceViewTests Bug: 31850030 Change-Id: Idda02098a635f25cf392f2d59a3abbe54a1d64d4
-rw-r--r--api/current.txt3
-rw-r--r--api/system-current.txt3
-rw-r--r--api/test-current.txt3
-rw-r--r--core/java/android/view/SurfaceHolder.java27
-rw-r--r--core/java/android/view/SurfaceView.java16
-rw-r--r--core/java/android/view/ViewRootImpl.java31
-rw-r--r--core/java/com/android/internal/view/BaseSurfaceHolder.java2
-rw-r--r--core/java/com/android/internal/view/SurfaceCallbackHelper.java77
-rw-r--r--opengl/java/android/opengl/GLSurfaceView.java41
9 files changed, 157 insertions, 46 deletions
diff --git a/api/current.txt b/api/current.txt
index ec16f5a5f56b..196b5f2483fb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28553,7 +28553,7 @@ package android.opengl {
method public void surfaceChanged(android.view.SurfaceHolder, int, int, int);
method public void surfaceCreated(android.view.SurfaceHolder);
method public void surfaceDestroyed(android.view.SurfaceHolder);
- method public void surfaceRedrawNeeded(android.view.SurfaceHolder);
+ method public deprecated void surfaceRedrawNeeded(android.view.SurfaceHolder);
field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1
field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2
field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1
@@ -43035,6 +43035,7 @@ package android.view {
public static abstract interface SurfaceHolder.Callback2 implements android.view.SurfaceHolder.Callback {
method public abstract void surfaceRedrawNeeded(android.view.SurfaceHolder);
+ method public default void surfaceRedrawNeededAsync(android.view.SurfaceHolder, java.lang.Runnable);
}
public class SurfaceView extends android.view.View {
diff --git a/api/system-current.txt b/api/system-current.txt
index 4bba111f9392..5a1f88019ad4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -31091,7 +31091,7 @@ package android.opengl {
method public void surfaceChanged(android.view.SurfaceHolder, int, int, int);
method public void surfaceCreated(android.view.SurfaceHolder);
method public void surfaceDestroyed(android.view.SurfaceHolder);
- method public void surfaceRedrawNeeded(android.view.SurfaceHolder);
+ method public deprecated void surfaceRedrawNeeded(android.view.SurfaceHolder);
field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1
field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2
field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1
@@ -46227,6 +46227,7 @@ package android.view {
public static abstract interface SurfaceHolder.Callback2 implements android.view.SurfaceHolder.Callback {
method public abstract void surfaceRedrawNeeded(android.view.SurfaceHolder);
+ method public default void surfaceRedrawNeededAsync(android.view.SurfaceHolder, java.lang.Runnable);
}
public class SurfaceView extends android.view.View {
diff --git a/api/test-current.txt b/api/test-current.txt
index d4fb027bcb4d..e67f2ced13b1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -28640,7 +28640,7 @@ package android.opengl {
method public void surfaceChanged(android.view.SurfaceHolder, int, int, int);
method public void surfaceCreated(android.view.SurfaceHolder);
method public void surfaceDestroyed(android.view.SurfaceHolder);
- method public void surfaceRedrawNeeded(android.view.SurfaceHolder);
+ method public deprecated void surfaceRedrawNeeded(android.view.SurfaceHolder);
field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1
field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2
field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1
@@ -43324,6 +43324,7 @@ package android.view {
public static abstract interface SurfaceHolder.Callback2 implements android.view.SurfaceHolder.Callback {
method public abstract void surfaceRedrawNeeded(android.view.SurfaceHolder);
+ method public default void surfaceRedrawNeededAsync(android.view.SurfaceHolder, java.lang.Runnable);
}
public class SurfaceView extends android.view.View {
diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java
index a3e8312c0a64..2fd2e966dc38 100644
--- a/core/java/android/view/SurfaceHolder.java
+++ b/core/java/android/view/SurfaceHolder.java
@@ -116,9 +116,34 @@ public interface SurfaceHolder {
* size before it has been correctly drawn that way). This will
* typically be preceeded by a call to {@link #surfaceChanged}.
*
+ * As of O, {@link #surfaceRedrawNeededAsync} may be implemented
+ * to provide a non-blocking implementation. If {@link #surfaceRedrawNeededAsync}
+ * is not implemented, then this will be called instead.
+ *
* @param holder The SurfaceHolder whose surface has changed.
*/
- public void surfaceRedrawNeeded(SurfaceHolder holder);
+ void surfaceRedrawNeeded(SurfaceHolder holder);
+
+ /**
+ * An alternative to surfaceRedrawNeeded where it is not required to block
+ * until the redraw is complete. You should initiate the redraw, and return,
+ * later invoking drawingFinished when your redraw is complete.
+ *
+ * This can be useful to avoid blocking your main application thread on rendering.
+ *
+ * As of O, if this is implemented {@link #surfaceRedrawNeeded} will not be called.
+ * However it is still recommended to implement {@link #surfaceRedrawNeeded} for
+ * compatibility with older versions of the platform.
+ *
+ * @param holder The SurfaceHolder which needs redrawing.
+ * @param drawingFinished A runnable to signal completion. This may be invoked
+ * from any thread.
+ *
+ */
+ default void surfaceRedrawNeededAsync(SurfaceHolder holder, Runnable drawingFinished) {
+ surfaceRedrawNeeded(holder);
+ drawingFinished.run();
+ }
}
/**
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d46910c2139c..018be866cd8b 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -33,6 +33,7 @@ import android.util.AttributeSet;
import android.util.Log;
import com.android.internal.view.BaseIWindow;
+import com.android.internal.view.SurfaceCallbackHelper;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -639,21 +640,13 @@ public class SurfaceView extends View {
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
- for (SurfaceHolder.Callback c : callbacks) {
- if (c instanceof SurfaceHolder.Callback2) {
- ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
- mSurfaceHolder);
- }
- }
+ SurfaceCallbackHelper sch =
+ new SurfaceCallbackHelper(mSession, mWindow);
+ sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
}
}
} finally {
mIsCreating = false;
- if (redrawNeeded) {
- if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
- + "finishedDrawing");
- mSession.finishDrawing(mWindow);
- }
mSession.performDeferredDestroy(mWindow);
}
} catch (RemoteException ex) {
@@ -876,7 +869,6 @@ public class SurfaceView extends View {
}
private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
-
private static final String LOG_TAG = "SurfaceHolder";
@Override
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4f2020311ff4..69464fc06e8f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -93,6 +93,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.policy.PhoneFallbackEventHandler;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.RootViewSurfaceTaker;
+import com.android.internal.view.SurfaceCallbackHelper;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -525,11 +526,17 @@ public final class ViewRootImpl implements ViewParent,
*/
public void notifyChildRebuilt() {
if (mView instanceof RootViewSurfaceTaker) {
+ if (mSurfaceHolderCallback != null) {
+ mSurfaceHolder.removeCallback(mSurfaceHolderCallback);
+ }
+
mSurfaceHolderCallback =
((RootViewSurfaceTaker)mView).willYouTakeTheSurface();
+
if (mSurfaceHolderCallback != null) {
mSurfaceHolder = new TakenSurfaceHolder();
mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
+ mSurfaceHolder.addCallback(mSurfaceHolderCallback);
} else {
mSurfaceHolder = null;
}
@@ -578,6 +585,7 @@ public final class ViewRootImpl implements ViewParent,
if (mSurfaceHolderCallback != null) {
mSurfaceHolder = new TakenSurfaceHolder();
mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
+ mSurfaceHolder.addCallback(mSurfaceHolderCallback);
}
}
@@ -1954,7 +1962,6 @@ public final class ViewRootImpl implements ViewParent,
mSurfaceHolder.ungetCallbacks();
mIsCreating = true;
- mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder);
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
if (callbacks != null) {
for (SurfaceHolder.Callback c : callbacks) {
@@ -1964,8 +1971,6 @@ public final class ViewRootImpl implements ViewParent,
surfaceChanged = true;
}
if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
- mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
- lp.format, mWidth, mHeight);
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
if (callbacks != null) {
for (SurfaceHolder.Callback c : callbacks) {
@@ -1978,7 +1983,6 @@ public final class ViewRootImpl implements ViewParent,
} else if (hadSurface) {
mSurfaceHolder.ungetCallbacks();
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
- mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
if (callbacks != null) {
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceDestroyed(mSurfaceHolder);
@@ -2643,21 +2647,18 @@ public final class ViewRootImpl implements ViewParent,
if (LOCAL_LOGV) {
Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
}
+
if (mSurfaceHolder != null && mSurface.isValid()) {
- mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
+ SurfaceCallbackHelper sch = new SurfaceCallbackHelper(mWindowSession, mWindow);
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
- if (callbacks != null) {
- for (SurfaceHolder.Callback c : callbacks) {
- if (c instanceof SurfaceHolder.Callback2) {
- ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(mSurfaceHolder);
- }
- }
+
+ sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
+ } else {
+ try {
+ mWindowSession.finishDrawing(mWindow);
+ } catch (RemoteException e) {
}
}
- try {
- mWindowSession.finishDrawing(mWindow);
- } catch (RemoteException e) {
- }
}
}
diff --git a/core/java/com/android/internal/view/BaseSurfaceHolder.java b/core/java/com/android/internal/view/BaseSurfaceHolder.java
index b41ef297a5be..32ce0fe1282b 100644
--- a/core/java/com/android/internal/view/BaseSurfaceHolder.java
+++ b/core/java/com/android/internal/view/BaseSurfaceHolder.java
@@ -86,7 +86,7 @@ public abstract class BaseSurfaceHolder implements SurfaceHolder {
mCallbacks.remove(callback);
}
}
-
+
public SurfaceHolder.Callback[] getCallbacks() {
if (mHaveGottenCallbacks) {
return mGottenCallbacks;
diff --git a/core/java/com/android/internal/view/SurfaceCallbackHelper.java b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
new file mode 100644
index 000000000000..5b6a82cf1c43
--- /dev/null
+++ b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view;
+
+import android.os.RemoteException;
+import android.view.IWindow;
+import android.view.IWindowSession;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+public class SurfaceCallbackHelper {
+ IWindowSession mSession;
+ IWindow.Stub mWindow;
+
+ int mFinishDrawingCollected = 0;
+ int mFinishDrawingExpected = 0;
+
+ private Runnable mFinishDrawingRunnable = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (SurfaceCallbackHelper.this) {
+ mFinishDrawingCollected++;
+ if (mFinishDrawingCollected < mFinishDrawingExpected) {
+ return;
+ }
+ try {
+ mSession.finishDrawing(mWindow);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ };
+
+ public SurfaceCallbackHelper(IWindowSession session,
+ IWindow.Stub window) {
+ mSession = session;
+ mWindow = window;
+ }
+
+ public void dispatchSurfaceRedrawNeededAsync(SurfaceHolder holder, SurfaceHolder.Callback callbacks[]) {
+ if (callbacks == null || callbacks.length == 0) {
+ try {
+ mSession.finishDrawing(mWindow);
+ } catch (RemoteException e) {
+ }
+ return;
+ }
+
+ synchronized (this) {
+ mFinishDrawingExpected = callbacks.length;
+ mFinishDrawingCollected = 0;
+ }
+
+ for (SurfaceHolder.Callback c : callbacks) {
+ if (c instanceof SurfaceHolder.Callback2) {
+ ((SurfaceHolder.Callback2) c).surfaceRedrawNeededAsync(
+ holder, mFinishDrawingRunnable);
+ } else {
+ mFinishDrawingRunnable.run();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 4154ef02772b..329514c0b7fc 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -542,16 +542,27 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
/**
- * This method is part of the SurfaceHolder.Callback interface, and is
+ * This method is part of the SurfaceHolder.Callback2 interface, and is
* not normally called or subclassed by clients of GLSurfaceView.
*/
@Override
- public void surfaceRedrawNeeded(SurfaceHolder holder) {
+ public void surfaceRedrawNeededAsync(SurfaceHolder holder, Runnable finishDrawing) {
if (mGLThread != null) {
- mGLThread.requestRenderAndWait();
+ mGLThread.requestRenderAndNotify(finishDrawing);
}
}
+ /**
+ * This method is part of the SurfaceHolder.Callback2 interface, and is
+ * not normally called or subclassed by clients of GLSurfaceView.
+ */
+ @Deprecated
+ @Override
+ public void surfaceRedrawNeeded(SurfaceHolder holder) {
+ // Since we are part of the framework we know only surfaceRedrawNeededAsync
+ // will be called.
+ }
+
/**
* Pause the rendering thread, optionally tearing down the EGL context
@@ -1305,6 +1316,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
int w = 0;
int h = 0;
Runnable event = null;
+ Runnable finishDrawingRunnable = null;
while (true) {
synchronized (sGLThreadManager) {
@@ -1400,6 +1412,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
sGLThreadManager.notifyAll();
}
+ if (mFinishDrawingRunnable != null) {
+ finishDrawingRunnable = mFinishDrawingRunnable;
+ mFinishDrawingRunnable = null;
+ }
+
// Ready to draw?
if (readyToDraw()) {
@@ -1453,7 +1470,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
break;
}
}
-
// By design, this is the only place in a GLThread thread where we wait().
if (LOG_THREADS) {
Log.i("GLThread", "waiting tid=" + getId()
@@ -1546,6 +1562,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onDrawFrame");
view.mRenderer.onDrawFrame(gl);
+ if (finishDrawingRunnable != null) {
+ finishDrawingRunnable.run();
+ finishDrawingRunnable = null;
+ }
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
@@ -1625,7 +1645,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
}
- public void requestRenderAndWait() {
+ public void requestRenderAndNotify(Runnable finishDrawing) {
synchronized(sGLThreadManager) {
// If we are already on the GL thread, this means a client callback
// has caused reentrancy, for example via updating the SurfaceView parameters.
@@ -1638,17 +1658,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
mWantRenderNotification = true;
mRequestRender = true;
mRenderComplete = false;
+ mFinishDrawingRunnable = finishDrawing;
sGLThreadManager.notifyAll();
-
- while (!mExited && !mPaused && !mRenderComplete && ableToDraw()) {
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
- }
-
}
}
@@ -1821,6 +1833,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private boolean mRenderComplete;
private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();
private boolean mSizeChanged = true;
+ private Runnable mFinishDrawingRunnable = null;
// End of member variables protected by the sGLThreadManager monitor.