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

Commit 5722cd9a authored by Ady Abraham's avatar Ady Abraham Committed by Android (Google) Code Review
Browse files

Merge changes from topic "setframerate_tv" into main

* changes:
  Plumb setFrameRate to TexureView
  Introduce SurfaceTextureListener
parents 72b14ed1 6f488f30
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.view;

import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -30,8 +31,10 @@ import android.graphics.SurfaceTexture;
import android.graphics.TextureLayer;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
import android.view.flags.Flags;

/**
 * <p>A TextureView can be used to display a content stream, such as that
@@ -194,6 +197,9 @@ public class TextureView extends View {
    private Canvas mCanvas;
    private int mSaveCount;

    @FloatRange(from = 0.0) float mFrameRate;
    @Surface.FrameRateCompatibility int mFrameRateCompatibility;

    private final Object[] mNativeWindowLock = new Object[0];
    // Set by native code, do not write!
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -465,6 +471,16 @@ public class TextureView extends View {
            mLayer.setSurfaceTexture(mSurface);
            mSurface.setDefaultBufferSize(getWidth(), getHeight());
            mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
            if (Flags.toolkitSetFrameRate()) {
                mSurface.setOnSetFrameRateListener(
                        (surfaceTexture, frameRate, compatibility, strategy) -> {
                            if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                                Trace.instant(Trace.TRACE_TAG_VIEW, "setFrameRate: " + frameRate);
                            }
                            mFrameRate = frameRate;
                            mFrameRateCompatibility = compatibility;
                        }, mAttachInfo.mHandler);
            }

            if (mListener != null && createNewSurface) {
                mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
+1 −0
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ cc_library_shared_for_libandroid_runtime {
    static_libs: [
        "libnativehelper_lazy",
        "libziparchive_for_incfs",
        "libguiflags",
    ],

    export_include_dirs: [
+93 −58
Original line number Diff line number Diff line
@@ -17,27 +17,24 @@
#undef LOG_TAG
#define LOG_TAG "SurfaceTexture"

#include <stdio.h>

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include <com_android_graphics_libgui_flags.h>
#include <cutils/atomic.h>
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <stdio.h>
#include <surfacetexture/SurfaceTexture.h>
#include <surfacetexture/surface_texture_platform.h>

#include "core_jni_helpers.h"

#include <cutils/atomic.h>
#include <utils/Log.h>
#include <utils/misc.h>

#include "core_jni_helpers.h"
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>

// ----------------------------------------------------------------------------

@@ -55,6 +52,7 @@ struct fields_t {
    jfieldID  producer;
    jfieldID  frameAvailableListener;
    jmethodID postEvent;
    jmethodID postOnSetFrameRateEvent;
};
static fields_t fields;

@@ -139,31 +137,35 @@ bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) {

// ----------------------------------------------------------------------------

class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
{
class JNISurfaceTextureContextCommon {
public:
    JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
    virtual ~JNISurfaceTextureContext();
    virtual void onFrameAvailable(const BufferItem& item);
    JNISurfaceTextureContextCommon(JNIEnv* env, jobject weakThiz, jclass clazz)
          : mWeakThiz(env->NewGlobalRef(weakThiz)), mClazz((jclass)env->NewGlobalRef(clazz)) {}

private:
    static JNIEnv* getJNIEnv();

    jobject mWeakThiz;
    jclass mClazz;
};
    virtual ~JNISurfaceTextureContextCommon() {
        JNIEnv* env = getJNIEnv();
        if (env != NULL) {
            env->DeleteGlobalRef(mWeakThiz);
            env->DeleteGlobalRef(mClazz);
        } else {
            ALOGW("leaking JNI object references");
        }
    }

JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env,
        jobject weakThiz, jclass clazz) :
    mWeakThiz(env->NewGlobalRef(weakThiz)),
    mClazz((jclass)env->NewGlobalRef(clazz))
{}
    void onFrameAvailable(const BufferItem& item) {
        JNIEnv* env = getJNIEnv();
        if (env != NULL) {
            env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
        } else {
            ALOGW("onFrameAvailable event will not posted");
        }
    }

JNIEnv* JNISurfaceTextureContext::getJNIEnv() {
protected:
    static JNIEnv* getJNIEnv() {
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        if (env == NULL) {
        JavaVMAttachArgs args = {
            JNI_VERSION_1_4, "JNISurfaceTextureContext", NULL };
            JavaVMAttachArgs args = {JNI_VERSION_1_4, "JNISurfaceTextureContext", NULL};
            JavaVM* vm = AndroidRuntime::getJavaVM();
            int result = vm->AttachCurrentThreadAsDaemon(&env, (void*)&args);
            if (result != JNI_OK) {
@@ -174,26 +176,42 @@ JNIEnv* JNISurfaceTextureContext::getJNIEnv() {
        return env;
    }

JNISurfaceTextureContext::~JNISurfaceTextureContext()
{
    JNIEnv* env = getJNIEnv();
    if (env != NULL) {
        env->DeleteGlobalRef(mWeakThiz);
        env->DeleteGlobalRef(mClazz);
    } else {
        ALOGW("leaking JNI object references");
    jobject mWeakThiz;
    jclass mClazz;
};

class JNISurfaceTextureContextFrameAvailableListener
      : public JNISurfaceTextureContextCommon,
        public SurfaceTexture::FrameAvailableListener {
public:
    JNISurfaceTextureContextFrameAvailableListener(JNIEnv* env, jobject weakThiz, jclass clazz)
          : JNISurfaceTextureContextCommon(env, weakThiz, clazz) {}
    void onFrameAvailable(const BufferItem& item) override {
        JNISurfaceTextureContextCommon::onFrameAvailable(item);
    }
};

class JNISurfaceTextureContextListener : public JNISurfaceTextureContextCommon,
                                         public SurfaceTexture::SurfaceTextureListener {
public:
    JNISurfaceTextureContextListener(JNIEnv* env, jobject weakThiz, jclass clazz)
          : JNISurfaceTextureContextCommon(env, weakThiz, clazz) {}

    void onFrameAvailable(const BufferItem& item) override {
        JNISurfaceTextureContextCommon::onFrameAvailable(item);
    }

void JNISurfaceTextureContext::onFrameAvailable(const BufferItem& /* item */)
{
    void onSetFrameRate(float frameRate, int8_t compatibility,
                        int8_t changeFrameRateStrategy) override {
        JNIEnv* env = getJNIEnv();
        if (env != NULL) {
        env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
            env->CallStaticVoidMethod(mClazz, fields.postOnSetFrameRateEvent, mWeakThiz, frameRate,
                                      compatibility, changeFrameRateStrategy);
        } else {
        ALOGW("onFrameAvailable event will not posted");
            ALOGW("onSetFrameRate event will not posted");
        }
    }
};

// ----------------------------------------------------------------------------

@@ -229,6 +247,13 @@ static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
    if (fields.postEvent == NULL) {
        ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
    }

    fields.postOnSetFrameRateEvent =
            env->GetStaticMethodID(clazz, "postOnSetFrameRateEventFromNative",
                                   "(Ljava/lang/ref/WeakReference;FII)V");
    if (fields.postOnSetFrameRateEvent == NULL) {
        ALOGE("can't find android/graphics/SurfaceTexture.postOnSetFrameRateEventFromNative");
    }
}

static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
@@ -274,17 +299,27 @@ static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
        return;
    }

    sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
            clazz));
    if (com::android::graphics::libgui::flags::bq_setframerate()) {
        sp<JNISurfaceTextureContextListener> ctx(
                new JNISurfaceTextureContextListener(env, weakThiz, clazz));
        surfaceTexture->setSurfaceTextureListener(ctx);
    } else {
        sp<JNISurfaceTextureContextFrameAvailableListener> ctx(
                new JNISurfaceTextureContextFrameAvailableListener(env, weakThiz, clazz));
        surfaceTexture->setFrameAvailableListener(ctx);
        SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);
    }
}

static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
{
    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
    if (com::android::graphics::libgui::flags::bq_setframerate()) {
        surfaceTexture->setSurfaceTextureListener(0);
    } else {
        surfaceTexture->setFrameAvailableListener(0);
        SurfaceTexture_setFrameAvailableListener(env, thiz, 0);
    }
    SurfaceTexture_setSurfaceTexture(env, thiz, 0);
    SurfaceTexture_setProducer(env, thiz, 0);
}
+90 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.graphics;

import android.annotation.FloatRange;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
@@ -24,8 +25,10 @@ import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Trace;
import android.view.Surface;
import android.view.TextureView;
import android.view.flags.Flags;

import java.lang.ref.WeakReference;

@@ -79,6 +82,7 @@ public class SurfaceTexture {
    private final Looper mCreatorLooper;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private Handler mOnFrameAvailableHandler;
    private Handler mOnSetFrameRateHandler;

    /**
     * These fields are used by native code, do not access or modify.
@@ -99,6 +103,21 @@ public class SurfaceTexture {
        void onFrameAvailable(SurfaceTexture surfaceTexture);
    }

    /**
     * Callback interface for being notified that a producer set a frame rate
     * @hide
     */
    public interface OnSetFrameRateListener {
        /**
         * Called when the producer sets a frame rate
         * @hide
         */
        void onSetFrameRate(SurfaceTexture surfaceTexture,
                            @FloatRange(from = 0.0) float frameRate,
                                 @Surface.FrameRateCompatibility int compatibility,
                                 @Surface.ChangeFrameRateStrategy int changeFrameRateStrategy);
    }

    /**
     * Exception thrown when a SurfaceTexture couldn't be created or resized.
     *
@@ -224,6 +243,48 @@ public class SurfaceTexture {
        }
    }

    private static class SetFrameRateArgs {
        SetFrameRateArgs(@FloatRange(from = 0.0) float frameRate,
                                @Surface.FrameRateCompatibility int compatibility,
                   @Surface.ChangeFrameRateStrategy int changeFrameRateStrategy) {
            this.mFrameRate = frameRate;
            this.mCompatibility = compatibility;
            this.mChangeFrameRateStrategy = changeFrameRateStrategy;
        }
        final float mFrameRate;
        final int mCompatibility;
        final int mChangeFrameRateStrategy;
    }

    /**
     * Register a callback to be invoked when the producer sets a frame rate using
     * Surface.setFrameRate.
     * @hide
     */
    public void setOnSetFrameRateListener(@Nullable final OnSetFrameRateListener listener,
                                            @Nullable Handler handler) {
        if (listener != null) {
            Looper looper = handler != null ? handler.getLooper() :
                    mCreatorLooper != null ? mCreatorLooper : Looper.getMainLooper();
            mOnSetFrameRateHandler = new Handler(looper, null, true /*async*/) {
                @Override
                public void handleMessage(Message msg) {
                    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSetFrameRateHandler");
                    try {
                        SetFrameRateArgs args = (SetFrameRateArgs) msg.obj;
                        listener.onSetFrameRate(SurfaceTexture.this,
                                args.mFrameRate, args.mCompatibility,
                                args.mChangeFrameRateStrategy);
                    } finally {
                        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                    }
                }
            };
        } else {
            mOnSetFrameRateHandler = null;
        }
    }

    /**
     * Set the default size of the image buffers.  The image producer may override the buffer size,
     * in which case the producer-set buffer size will be used, not the default size set by this
@@ -417,6 +478,35 @@ public class SurfaceTexture {
        }
    }

    /**
     * This method is invoked from native code only.
     * @hide
     */
    @SuppressWarnings({"UnusedDeclaration"})
    private static void postOnSetFrameRateEventFromNative(WeakReference<SurfaceTexture> weakSelf,
            @FloatRange(from = 0.0) float frameRate,
            @Surface.FrameRateCompatibility int compatibility,
            @Surface.ChangeFrameRateStrategy int changeFrameRateStrategy) {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "postOnSetFrameRateEventFromNative");
        try {
            if (Flags.toolkitSetFrameRate()) {
                SurfaceTexture st = weakSelf.get();
                if (st != null) {
                    Handler handler = st.mOnSetFrameRateHandler;
                    if (handler != null) {
                        Message msg = new Message();
                        msg.obj = new SetFrameRateArgs(frameRate, compatibility,
                                changeFrameRateStrategy);
                        handler.sendMessage(msg);
                    }
                }
            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }

    }

    /**
     * Returns {@code true} if the SurfaceTexture is single-buffered.
     * @hide