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

Commit 757f63aa authored by Ana Krulec's avatar Ana Krulec
Browse files

SF: Offsets should be dependend on the refresh rate.

When switching to 90Hz, the time between vsync pulses is only 11ms, so it
doesn't make sense to have 6msec offsets. Adding the flags will allow us
to experiment with different offsets in the later stages through device.mk
file for two different refresh rates. Eventually, the refresh rates should
be coupled with the configs that indicate the refresh rate.

Bug: 122905996
Test: Added Fake class to inject into tests to keep consistant results.
Change-Id: Iffe7eb9dae6cd655c83e5b576306e3883ef1a56d
parent a71e1c3c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -152,6 +152,7 @@ filegroup {
        "Scheduler/MessageQueue.cpp",
        "Scheduler/Scheduler.cpp",
        "Scheduler/SchedulerUtils.cpp",
        "Scheduler/PhaseOffsets.cpp",
        "StartPropertySetThread.cpp",
        "SurfaceFlinger.cpp",
        "SurfaceInterceptor.cpp",
+1 −12
Original line number Diff line number Diff line
@@ -757,18 +757,7 @@ nsecs_t DispSync::expectedPresentTime() {
    const uint32_t hwcLatency = 0;

    // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
    const nsecs_t nextRefresh = computeNextRefresh(hwcLatency);

    // The DispSync time is already adjusted for the difference between
    // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
    // we don't need to factor that in here.  Pad a little to avoid
    // weird effects if apps might be requesting times right on the edge.
    nsecs_t extraPadding = 0;
    if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
        extraPadding = 1000000; // 1ms (6% of 60Hz)
    }

    return nextRefresh + extraPadding;
    return computeNextRefresh(hwcLatency);
}

} // namespace impl
+117 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 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.
 */

#include "PhaseOffsets.h"

#include <cutils/properties.h>

#include "SurfaceFlingerProperties.h"

namespace android {
using namespace android::sysprop;

namespace scheduler {

PhaseOffsets::~PhaseOffsets() = default;

namespace impl {
PhaseOffsets::PhaseOffsets() {
    int64_t vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000);

    int64_t sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000);

    char value[PROPERTY_VALUE_MAX];
    property_get("debug.sf.early_phase_offset_ns", value, "-1");
    const int earlySfOffsetNs = atoi(value);

    property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
    const int earlyGlSfOffsetNs = atoi(value);

    property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
    const int earlyAppOffsetNs = atoi(value);

    property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
    const int earlyGlAppOffsetNs = atoi(value);

    property_get("debug.sf.high_fps_early_phase_offset_ns", value, "-1");
    const int highFpsEarlySfOffsetNs = atoi(value);

    property_get("debug.sf.high_fps_early_gl_phase_offset_ns", value, "-1");
    const int highFpsEarlyGlSfOffsetNs = atoi(value);

    property_get("debug.sf.high_fps_early_app_phase_offset_ns", value, "-1");
    const int highFpsEarlyAppOffsetNs = atoi(value);

    property_get("debug.sf.high_fps_early_gl_app_phase_offset_ns", value, "-1");
    const int highFpsEarlyGlAppOffsetNs = atoi(value);

    // TODO(b/122905996): Define these in device.mk.
    property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "1000000");
    const int highFpsLateAppOffsetNs = atoi(value);

    property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "8000000");
    const int highFpsLateSfOffsetNs = atoi(value);

    mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs
                                                              : sfVsyncPhaseOffsetNs,
                                        earlyAppOffsetNs != -1 ? earlyAppOffsetNs
                                                               : vsyncPhaseOffsetNs};
    mDefaultRefreshRateOffsets.earlyGl = {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs
                                                                  : sfVsyncPhaseOffsetNs,
                                          earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs
                                                                   : vsyncPhaseOffsetNs};
    mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};

    mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
                                                                  : highFpsLateAppOffsetNs,
                                     highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
                                                                   : highFpsLateSfOffsetNs};
    mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
                                                                      : highFpsLateAppOffsetNs,
                                       highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
                                                                       : highFpsLateSfOffsetNs};
    mHighRefreshRateOffsets.late = {highFpsLateAppOffsetNs, highFpsLateSfOffsetNs};
}

PhaseOffsets::Offsets PhaseOffsets::getCurrentOffsets() const {
    switch (mRefreshRateType) {
        case RefreshRateConfigs::RefreshRateType::PERFORMANCE:
            return mHighRefreshRateOffsets;
        default:
            return mDefaultRefreshRateOffsets;
    }
}

void PhaseOffsets::dump(std::string& result) const {
    const auto [early, earlyGl, late] = getCurrentOffsets();
    base::StringAppendF(&result,
                        "         app phase: %9" PRId64 " ns\t         SF phase: %9" PRId64 " ns\n"
                        "   early app phase: %9" PRId64 " ns\t   early SF phase: %9" PRId64 " ns\n"
                        "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n",
                        late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf);
}

nsecs_t PhaseOffsets::getCurrentAppOffset() {
    return getCurrentOffsets().late.app;
}

nsecs_t PhaseOffsets::getCurrentSfOffset() {
    return getCurrentOffsets().late.sf;
}

} // namespace impl
} // namespace scheduler
} // namespace android
+83 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 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.
 */

#pragma once

#include <cinttypes>

#include "RefreshRateConfigs.h"
#include "VSyncModulator.h"

namespace android {
namespace scheduler {

/*
 * This class encapsulates offsets for different refresh rates. Depending
 * on what refresh rate we are using, and wheter we are composing in GL,
 * different offsets will help us with latency. This class keeps track of
 * which mode the device is on, and returns approprate offsets when needed.
 */
class PhaseOffsets {
public:
    struct Offsets {
        VSyncModulator::Offsets early;
        VSyncModulator::Offsets earlyGl;
        VSyncModulator::Offsets late;
    };

    virtual ~PhaseOffsets();

    virtual nsecs_t getCurrentAppOffset() = 0;
    virtual nsecs_t getCurrentSfOffset() = 0;
    virtual Offsets getCurrentOffsets() const = 0;
    virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0;
    virtual void dump(std::string& result) const = 0;
};

namespace impl {
class PhaseOffsets : public scheduler::PhaseOffsets {
public:
    PhaseOffsets();

    nsecs_t getCurrentAppOffset() override;
    nsecs_t getCurrentSfOffset() override;

    // Returns early, early GL, and late offsets for Apps and SF.
    Offsets getCurrentOffsets() const override;

    // This function should be called when the device is switching between different
    // refresh rates, to properly update the offsets.
    void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) override {
        mRefreshRateType = refreshRateType;
    }

    // Returns current offsets in human friendly format.
    void dump(std::string& result) const override;

private:
    Offsets getmDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; }
    Offsets getmHighRefreshRateOffsets() { return mHighRefreshRateOffsets; }

    std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
            RefreshRateConfigs::RefreshRateType::DEFAULT;

    Offsets mDefaultRefreshRateOffsets;
    Offsets mHighRefreshRateOffsets;
};
} // namespace impl

} // namespace scheduler
} // namespace android
+1 −1
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function)
    mEventControlThread = std::make_unique<impl::EventControlThread>(function);

    char value[PROPERTY_VALUE_MAX];
    property_get("debug.sf.set_idle_timer_ms", value, "0");
    property_get("debug.sf.set_idle_timer_ms", value, "30");
    mSetIdleTimerMs = atoi(value);

    if (mSetIdleTimerMs > 0) {
Loading