Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0bbf0b41 authored by Romain Guy's avatar Romain Guy
Browse files

Expose shared buffer mode/auto refresh on Surface

These features can be set on a surface to reduce perceived latency
at the expense of visible tearing.

Bug: 63858546
Test: Manual, CTS test coming

Change-Id: Ica3f480bd1cb8f77dff57218d2fa8783433d3396
parent b3d487da
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -45217,11 +45217,15 @@ package android.view {
  public class Surface implements android.os.Parcelable {
    ctor public Surface(android.graphics.SurfaceTexture);
    method public int describeContents();
    method public boolean isAutoRefreshEnabled();
    method public boolean isSharedBufferModeEnabled();
    method public boolean isValid();
    method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
    method public android.graphics.Canvas lockHardwareCanvas();
    method public void readFromParcel(android.os.Parcel);
    method public void release();
    method public void setAutoRefreshEnabled(boolean);
    method public void setSharedBufferModeEnabled(boolean);
    method public deprecated void unlockCanvas(android.graphics.Canvas);
    method public void unlockCanvasAndPost(android.graphics.Canvas);
    method public void writeToParcel(android.os.Parcel, int);
+4 −0
Original line number Diff line number Diff line
@@ -48874,11 +48874,15 @@ package android.view {
  public class Surface implements android.os.Parcelable {
    ctor public Surface(android.graphics.SurfaceTexture);
    method public int describeContents();
    method public boolean isAutoRefreshEnabled();
    method public boolean isSharedBufferModeEnabled();
    method public boolean isValid();
    method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
    method public android.graphics.Canvas lockHardwareCanvas();
    method public void readFromParcel(android.os.Parcel);
    method public void release();
    method public void setAutoRefreshEnabled(boolean);
    method public void setSharedBufferModeEnabled(boolean);
    method public deprecated void unlockCanvas(android.graphics.Canvas);
    method public void unlockCanvasAndPost(android.graphics.Canvas);
    method public void writeToParcel(android.os.Parcel, int);
+4 −0
Original line number Diff line number Diff line
@@ -45622,11 +45622,15 @@ package android.view {
  public class Surface implements android.os.Parcelable {
    ctor public Surface(android.graphics.SurfaceTexture);
    method public int describeContents();
    method public boolean isAutoRefreshEnabled();
    method public boolean isSharedBufferModeEnabled();
    method public boolean isValid();
    method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
    method public android.graphics.Canvas lockHardwareCanvas();
    method public void readFromParcel(android.os.Parcel);
    method public void release();
    method public void setAutoRefreshEnabled(boolean);
    method public void setSharedBufferModeEnabled(boolean);
    method public deprecated void unlockCanvas(android.graphics.Canvas);
    method public void unlockCanvasAndPost(android.graphics.Canvas);
    method public void writeToParcel(android.os.Parcel, int);
+99 −4
Original line number Diff line number Diff line
@@ -73,10 +73,12 @@ public class Surface implements Parcelable {

    private static native long nativeGetNextFrameNumber(long nativeObject);
    private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
    private static native void nativeSetBuffersTransform(long nativeObject, long transform);
    private static native int nativeForceScopedDisconnect(long nativeObject);
    private static native int nativeAttachAndQueueBuffer(long nativeObject, GraphicBuffer buffer);

    private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled);
    private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled);

    public static final Parcelable.Creator<Surface> CREATOR =
            new Parcelable.Creator<Surface>() {
        @Override
@@ -114,6 +116,8 @@ public class Surface implements Parcelable {
    private HwuiContext mHwuiContext;

    private boolean mIsSingleBuffered;
    private boolean mIsSharedBufferModeEnabled;
    private boolean mIsAutoRefreshEnabled;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
@@ -629,6 +633,97 @@ public class Surface implements Parcelable {
        return mIsSingleBuffered;
    }

    /**
     * <p>The shared buffer mode allows both the application and the surface compositor
     * (SurfaceFlinger) to concurrently access this surface's buffer. While the
     * application is still required to issue a present request
     * (see {@link #unlockCanvasAndPost(Canvas)}) to the compositor when an update is required,
     * the compositor may trigger an update at any time. Since the surface's buffer is shared
     * between the application and the compositor, updates triggered by the compositor may
     * cause visible tearing.</p>
     *
     * <p>The shared buffer mode can be used with
     * {@link #setAutoRefreshEnabled(boolean) auto-refresh} to avoid the overhead of
     * issuing present requests.</p>
     *
     * <p>If the application uses the shared buffer mode to reduce latency, it is
     * recommended to use software rendering (see {@link #lockCanvas(Rect)} to ensure
     * the graphics workloads are not affected by other applications and/or the system
     * using the GPU. When using software rendering, the application should update the
     * smallest possible region of the surface required.</p>
     *
     * <p class="note">The shared buffer mode might not be supported by the underlying
     * hardware. Enabling shared buffer mode on hardware that does not support it will
     * not yield an error but the application will not benefit from lower latency (and
     * tearing will not be visible).</p>
     *
     * <p class="note">Depending on how many and what kind of surfaces are visible, the
     * surface compositor may need to copy the shared buffer before it is displayed. When
     * this happens, the latency benefits of shared buffer mode will be reduced.</p>
     *
     * @param enabled True to enable the shared buffer mode on this surface, false otherwise
     *
     * @see #isSharedBufferModeEnabled()
     * @see #setAutoRefreshEnabled(boolean)
     */
    public void setSharedBufferModeEnabled(boolean enabled) {
        if (mIsSharedBufferModeEnabled != enabled) {
            int error = nativeSetSharedBufferModeEnabled(mNativeObject, enabled);
            if (error != 0) {
                throw new RuntimeException(
                        "Failed to set shared buffer mode on Surface (bad object?)");
            } else {
                mIsSharedBufferModeEnabled = enabled;
            }
        }
    }

    /**
     * @return True if shared buffer mode is enabled on this surface, false otherwise
     *
     * @see #setSharedBufferModeEnabled(boolean)
     */
    public boolean isSharedBufferModeEnabled() {
        return mIsSharedBufferModeEnabled;
    }

    /**
     * <p>When auto-refresh is enabled, the surface compositor (SurfaceFlinger)
     * automatically updates the display on a regular refresh cycle. The application
     * can continue to issue present requests but it is not required. Enabling
     * auto-refresh may result in visible tearing.</p>
     *
     * <p>Auto-refresh has no effect if the {@link #setSharedBufferModeEnabled(boolean)
     * shared buffer mode} is not enabled.</p>
     *
     * <p>Because auto-refresh will trigger continuous updates of the display, it is
     * recommended to turn it on only when necessary. For example, in a drawing/painting
     * application auto-refresh should be enabled on finger/pen down and disabled on
     * finger/pen up.</p>
     *
     * @param enabled True to enable auto-refresh on this surface, false otherwise
     *
     * @see #isAutoRefreshEnabled()
     * @see #setSharedBufferModeEnabled(boolean)
     */
    public void setAutoRefreshEnabled(boolean enabled) {
        if (mIsAutoRefreshEnabled != enabled) {
            int error = nativeSetAutoRefreshEnabled(mNativeObject, enabled);
            if (error != 0) {
                throw new RuntimeException("Failed to set auto refresh on Surface (bad object?)");
            } else {
                mIsAutoRefreshEnabled = enabled;
            }
        }
    }

    /**
     * @return True if auto-refresh is enabled on this surface, false otherwise
     */
    public boolean isAutoRefreshEnabled() {
        return mIsAutoRefreshEnabled;
    }

    /**
     * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
     * when a SurfaceTexture could not successfully be allocated.
@@ -656,13 +751,13 @@ public class Surface implements Parcelable {
                return "ROTATION_0";
            }
            case Surface.ROTATION_90: {
                return "ROATATION_90";
                return "ROTATION_90";
            }
            case Surface.ROTATION_180: {
                return "ROATATION_180";
                return "ROTATION_180";
            }
            case Surface.ROTATION_270: {
                return "ROATATION_270";
                return "ROTATION_270";
            }
            default: {
                throw new IllegalArgumentException("Invalid rotation: " + rotation);
+16 −0
Original line number Diff line number Diff line
@@ -537,6 +537,20 @@ static jint nativeAttachAndQueueBuffer(JNIEnv *env, jclass clazz, jlong nativeOb
    return err;
}

static jint nativeSetSharedBufferModeEnabled(JNIEnv* env, jclass clazz, jlong nativeObject,
        jboolean enabled) {
    Surface* surface = reinterpret_cast<Surface*>(nativeObject);
    return ((ANativeWindow*) nativeObject)->perform(surface,
            NATIVE_WINDOW_SET_SHARED_BUFFER_MODE, enabled);
}

static jint nativeSetAutoRefreshEnabled(JNIEnv* env, jclass clazz, jlong nativeObject,
        jboolean enabled) {
    Surface* surface = reinterpret_cast<Surface*>(nativeObject);
    return ((ANativeWindow*) nativeObject)->perform(surface,
            NATIVE_WINDOW_SET_AUTO_REFRESH, enabled);
}

namespace uirenderer {

using namespace android::uirenderer::renderthread;
@@ -618,6 +632,8 @@ static const JNINativeMethod gSurfaceMethods[] = {
    {"nativeSetScalingMode", "(JI)I", (void*)nativeSetScalingMode },
    {"nativeForceScopedDisconnect", "(J)I", (void*)nativeForceScopedDisconnect},
    {"nativeAttachAndQueueBuffer", "(JLandroid/graphics/GraphicBuffer;)I", (void*)nativeAttachAndQueueBuffer},
    {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled},
    {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},

    // HWUI context
    {"nHwuiCreate", "(JJ)J", (void*) hwui::create },