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

Commit 1f6fc70a authored by Dominik Laskowski's avatar Dominik Laskowski
Browse files

SF: Fix feedback loop with refresh rate overlay

RefreshRateOverlay was refactored to use transactions instead of APIs
internal to SF. A side effect is that the overlay layer feeds back into
the frame rate detection and idle heuristics, which causes oscillation
that trends to the high refresh rate.

The transaction to setFrameRate failed to apply, as the NoVote argument
was invalid. Make it valid, such that LayerHistory::summarize skips the
overlay layer.

Do not reset the idle timer for solely NO_VOTE transactions.

Bug: 221081400
Test: flame is not stuck at 90 Hz when overlay is enabled.
Test: Same with sf.debug.show_refresh_rate_overlay_spinner
Test: SetFrameRateTest
Change-Id: I6322c1c487672b602a0f974e8ecf445633dcc3a1
parent 3f6ac9e0
Loading
Loading
Loading
Loading
+6 −5
Original line number Original line Diff line number Diff line
@@ -16,8 +16,8 @@


#define LOG_TAG "LayerState"
#define LOG_TAG "LayerState"


#include <apex/window.h>
#include <cinttypes>
#include <inttypes.h>
#include <cmath>


#include <android/native_window.h>
#include <android/native_window.h>
#include <binder/Parcel.h>
#include <binder/Parcel.h>
@@ -25,10 +25,9 @@
#include <gui/ISurfaceComposerClient.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
#include <gui/LayerState.h>
#include <private/gui/ParcelUtils.h>
#include <private/gui/ParcelUtils.h>
#include <system/window.h>
#include <utils/Errors.h>
#include <utils/Errors.h>


#include <cmath>

namespace android {
namespace android {


using gui::FocusRequest;
using gui::FocusRequest;
@@ -679,7 +678,9 @@ bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrame


    if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
    if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
        compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE &&
        compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE &&
        (!privileged || compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT)) {
        (!privileged ||
         (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT &&
          compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) {
        ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName,
        ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName,
              compatibility, privileged ? "yes" : "no");
              compatibility, privileged ? "yes" : "no");
        return false;
        return false;
+0 −13
Original line number Original line Diff line number Diff line
@@ -39,19 +39,6 @@ enum ANativeWindowPerform {
    // clang-format on
    // clang-format on
};
};


/*
 * Internal extension of compatibility value for ANativeWindow_setFrameRate. */
enum ANativeWindow_FrameRateCompatibilityInternal {
    /**
     * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
     * to operate at the exact frame rate.
     *
     * This is used internally by the platform and should not be used by apps.
     * @hide
     */
    ANATIVEWINDOW_FRAME_RATE_EXACT = 100,
};

/**
/**
 * Prototype of the function that an ANativeWindow implementation would call
 * Prototype of the function that an ANativeWindow implementation would call
 * when ANativeWindow_cancelBuffer is called.
 * when ANativeWindow_cancelBuffer is called.
+18 −0
Original line number Original line Diff line number Diff line
@@ -1018,6 +1018,24 @@ static inline int native_window_set_auto_prerotation(struct ANativeWindow* windo
    return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation);
    return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation);
}
}


/*
 * Internal extension of ANativeWindow_FrameRateCompatibility.
 */
enum {
    /**
     * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
     * to operate at the exact frame rate.
     *
     * Keep in sync with Surface.java constant.
     */
    ANATIVEWINDOW_FRAME_RATE_EXACT = 100,

    /**
     * This surface is ignored while choosing the refresh rate.
     */
    ANATIVEWINDOW_FRAME_RATE_NO_VOTE,
};

static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate,
static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate,
                                        int8_t compatibility, int8_t changeFrameRateStrategy) {
                                        int8_t compatibility, int8_t changeFrameRateStrategy) {
    return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate,
    return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate,
+2 −0
Original line number Original line Diff line number Diff line
@@ -2596,6 +2596,8 @@ Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t comp
            return FrameRateCompatibility::ExactOrMultiple;
            return FrameRateCompatibility::ExactOrMultiple;
        case ANATIVEWINDOW_FRAME_RATE_EXACT:
        case ANATIVEWINDOW_FRAME_RATE_EXACT:
            return FrameRateCompatibility::Exact;
            return FrameRateCompatibility::Exact;
        case ANATIVEWINDOW_FRAME_RATE_NO_VOTE:
            return FrameRateCompatibility::NoVote;
        default:
        default:
            LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility);
            LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility);
            return FrameRateCompatibility::Default;
            return FrameRateCompatibility::Default;
+19 −23
Original line number Original line Diff line number Diff line
@@ -45,6 +45,15 @@ constexpr int kDigitSpace = 16;
constexpr int kBufferWidth = 4 * kDigitWidth + 3 * kDigitSpace;
constexpr int kBufferWidth = 4 * kDigitWidth + 3 * kDigitSpace;
constexpr int kBufferHeight = kDigitHeight;
constexpr int kBufferHeight = kDigitHeight;


SurfaceComposerClient::Transaction createTransaction(const sp<SurfaceControl>& surface) {
    constexpr float kFrameRate = 0.f;
    constexpr int8_t kCompatibility = ANATIVEWINDOW_FRAME_RATE_NO_VOTE;
    constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;

    return SurfaceComposerClient::Transaction().setFrameRate(surface, kFrameRate, kCompatibility,
                                                             kSeamlessness);
}

} // namespace
} // namespace


void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color,
void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color,
@@ -213,12 +222,7 @@ RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner)
        return;
        return;
    }
    }


    constexpr float kFrameRate = 0.f;
    createTransaction(mSurfaceControl)
    constexpr int8_t kCompatibility = static_cast<int8_t>(Layer::FrameRateCompatibility::NoVote);
    constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;

    SurfaceComposerClient::Transaction()
            .setFrameRate(mSurfaceControl, kFrameRate, kCompatibility, kSeamlessness)
            .setLayer(mSurfaceControl, INT32_MAX - 2)
            .setLayer(mSurfaceControl, INT32_MAX - 2)
            .setTrustedOverlay(mSurfaceControl, true)
            .setTrustedOverlay(mSurfaceControl, true)
            .apply();
            .apply();
@@ -243,9 +247,7 @@ auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& {
        }
        }
    }();
    }();


    SurfaceComposerClient::Transaction t;
    createTransaction(mSurfaceControl).setTransform(mSurfaceControl, transform).apply();
    t.setTransform(mSurfaceControl, transform);
    t.apply();


    BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint});
    BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint});
    if (it == mBufferCache.end()) {
    if (it == mBufferCache.end()) {
@@ -287,25 +289,21 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) {
    Rect frame((3 * width) >> 4, height >> 5);
    Rect frame((3 * width) >> 4, height >> 5);
    frame.offsetBy(width >> 5, height >> 4);
    frame.offsetBy(width >> 5, height >> 4);


    SurfaceComposerClient::Transaction t;
    createTransaction(mSurfaceControl)
    t.setMatrix(mSurfaceControl, frame.getWidth() / static_cast<float>(kBufferWidth), 0, 0,
            .setMatrix(mSurfaceControl, frame.getWidth() / static_cast<float>(kBufferWidth), 0, 0,
                frame.getHeight() / static_cast<float>(kBufferHeight));
                       frame.getHeight() / static_cast<float>(kBufferHeight))
    t.setPosition(mSurfaceControl, frame.left, frame.top);
            .setPosition(mSurfaceControl, frame.left, frame.top)
    t.apply();
            .apply();
}
}


void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
    SurfaceComposerClient::Transaction t;
    createTransaction(mSurfaceControl).setLayerStack(mSurfaceControl, stack).apply();
    t.setLayerStack(mSurfaceControl, stack);
    t.apply();
}
}


void RefreshRateOverlay::changeRefreshRate(Fps fps) {
void RefreshRateOverlay::changeRefreshRate(Fps fps) {
    mCurrentFps = fps;
    mCurrentFps = fps;
    const auto buffer = getOrCreateBuffers(fps)[mFrame];
    const auto buffer = getOrCreateBuffers(fps)[mFrame];
    SurfaceComposerClient::Transaction t;
    createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
    t.setBuffer(mSurfaceControl, buffer);
    t.apply();
}
}


void RefreshRateOverlay::animate() {
void RefreshRateOverlay::animate() {
@@ -314,9 +312,7 @@ void RefreshRateOverlay::animate() {
    const auto& buffers = getOrCreateBuffers(*mCurrentFps);
    const auto& buffers = getOrCreateBuffers(*mCurrentFps);
    mFrame = (mFrame + 1) % buffers.size();
    mFrame = (mFrame + 1) % buffers.size();
    const auto buffer = buffers[mFrame];
    const auto buffer = buffers[mFrame];
    SurfaceComposerClient::Transaction t;
    createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply();
    t.setBuffer(mSurfaceControl, buffer);
    t.apply();
}
}


} // namespace android
} // namespace android
Loading