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

Commit 03b02dda authored by Ady Abraham's avatar Ady Abraham
Browse files

SurfaceFlinger: add Refresh Rate overlay

Add an overlay to indicate what is the current refresh rate.
Currently it is implemented by a ColorLayer:
 - Red - Default refresh rate
 - Green - Performance refresh rate

To enable the overlay:
adb shell service call SurfaceFlinger 1034 i32 1
To disable the overlay:
adb shell service call SurfaceFlinger 1034 i32 0

Test: manual
Change-Id: I851f2530e7accacd2cac446b30aa2e0b6d431a92
parent de3b67ba
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -138,8 +138,9 @@ filegroup {
        "LayerVector.cpp",
        "LayerVector.cpp",
        "MonitoredProducer.cpp",
        "MonitoredProducer.cpp",
        "NativeWindowSurface.cpp",
        "NativeWindowSurface.cpp",
        "RenderArea.cpp",
        "RefreshRateOverlay.cpp",
        "RegionSamplingThread.cpp",
        "RegionSamplingThread.cpp",
        "RenderArea.cpp",
        "Scheduler/DispSync.cpp",
        "Scheduler/DispSync.cpp",
        "Scheduler/DispSyncSource.cpp",
        "Scheduler/DispSyncSource.cpp",
        "Scheduler/EventControlThread.cpp",
        "Scheduler/EventControlThread.cpp",
+53 −0
Original line number Original line 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 "RefreshRateOverlay.h"
#include "Client.h"
#include "Layer.h"

namespace android {

using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;

RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger)
      : mFlinger(flinger), mClient(new Client(&mFlinger)) {
    createLayer();
}

bool RefreshRateOverlay::createLayer() {
    const status_t ret =
            mFlinger.createLayer(String8("RefreshRateOverlay"), mClient, 0, 0,
                                 PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor,
                                 LayerMetadata(), &mIBinder, &mGbp, &mLayer);
    if (ret) {
        ALOGE("failed to color layer");
        return false;
    }

    mLayer = mClient->getLayerUser(mIBinder);
    mLayer->setCrop_legacy(Rect(0, 0, 200, 100), true);
    mLayer->setLayer(INT32_MAX - 2);

    return true;
}

void RefreshRateOverlay::changeRefreshRate(RefreshRateType type) {
    const half3& color = (type == RefreshRateType::PERFORMANCE) ? GREEN : RED;
    mLayer->setColor(color);
    mFlinger.setTransactionFlags(eTransactionMask);
}

}; // namespace android
+43 −0
Original line number Original line 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 "SurfaceFlinger.h"

namespace android {

using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;

class RefreshRateOverlay {
public:
    RefreshRateOverlay(SurfaceFlinger& flinger);

    void changeRefreshRate(RefreshRateType type);

private:
    bool createLayer();

    SurfaceFlinger& mFlinger;
    sp<Client> mClient;
    sp<Layer> mLayer;
    sp<IBinder> mIBinder;
    sp<IGraphicBufferProducer> mGbp;

    const half3 RED = half3(1.0f, 0.0f, 0.0f);
    const half3 GREEN = half3(0.0f, 1.0f, 0.0f);
};

}; // namespace android
+30 −15
Original line number Original line Diff line number Diff line
@@ -84,6 +84,7 @@
#include "LayerVector.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
#include "MonitoredProducer.h"
#include "NativeWindowSurface.h"
#include "NativeWindowSurface.h"
#include "RefreshRateOverlay.h"
#include "StartPropertySetThread.h"
#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
#include "SurfaceFlinger.h"
#include "SurfaceInterceptor.h"
#include "SurfaceInterceptor.h"
@@ -128,8 +129,6 @@ using ui::DisplayPrimaries;
using ui::Hdr;
using ui::Hdr;
using ui::RenderIntent;
using ui::RenderIntent;


using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;

namespace {
namespace {


#pragma clang diagnostic push
#pragma clang diagnostic push
@@ -942,19 +941,18 @@ int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) {
    return display->getActiveConfig();
    return display->getActiveConfig();
}
}


void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
                                            Scheduler::ConfigEvent event) {
    ATRACE_CALL();
    ATRACE_CALL();


    // Lock is acquired by setRefreshRateTo.
    // Lock is acquired by setRefreshRateTo.
    const auto display = getDisplayDeviceLocked(displayToken);
    const auto display = getDisplayDeviceLocked(info.displayToken);
    if (!display) {
    if (!display) {
        ALOGE("Attempt to set active config %d for invalid display token %p", mode,
        ALOGE("Attempt to set active config %d for invalid display token %p", info.configId,
              displayToken.get());
              info.displayToken.get());
        return;
        return;
    }
    }
    if (display->isVirtual()) {
    if (display->isVirtual()) {
        ALOGW("Attempt to set active config %d for virtual display", mode);
        ALOGW("Attempt to set active config %d for virtual display", info.configId);
        return;
        return;
    }
    }
    int currentDisplayPowerMode = display->getPowerMode();
    int currentDisplayPowerMode = display->getPowerMode();
@@ -967,8 +965,9 @@ void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int
    // config twice. However event generation config might have changed so we need to update it
    // config twice. However event generation config might have changed so we need to update it
    // accordingly
    // accordingly
    std::lock_guard<std::mutex> lock(mActiveConfigLock);
    std::lock_guard<std::mutex> lock(mActiveConfigLock);
    const Scheduler::ConfigEvent desiredConfig = mDesiredActiveConfig.event | event;
    const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event;
    mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, desiredConfig};
    mDesiredActiveConfig = info;
    mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;


    if (!mDesiredActiveConfigChanged) {
    if (!mDesiredActiveConfigChanged) {
        // This is the first time we set the desired
        // This is the first time we set the desired
@@ -979,6 +978,10 @@ void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int
    }
    }
    mDesiredActiveConfigChanged = true;
    mDesiredActiveConfigChanged = true;
    ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
    ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);

    if (mRefreshRateOverlay) {
        mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
    }
}
}


status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
@@ -1492,7 +1495,7 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co
    }
    }


    mPhaseOffsets->setRefreshRateType(refreshRate);
    mPhaseOffsets->setRefreshRateType(refreshRate);
    setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
    setDesiredActiveConfig({refreshRate, desiredConfigId, getInternalDisplayTokenLocked(), event});
}
}


void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -5021,9 +5024,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
        code == IBinder::SYSPROPS_TRANSACTION) {
        code == IBinder::SYSPROPS_TRANSACTION) {
        return OK;
        return OK;
    }
    }
    // Numbers from 1000 to 1033 are currently used for backdoors. The code
    // Numbers from 1000 to 1034 are currently used for backdoors. The code
    // in onTransact verifies that the user is root, and has access to use SF.
    // in onTransact verifies that the user is root, and has access to use SF.
    if (code >= 1000 && code <= 1033) {
    if (code >= 1000 && code <= 1034) {
        ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
        ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
        return OK;
        return OK;
    }
    }
@@ -5339,6 +5342,18 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
                reply->writeInt32(NO_ERROR);
                reply->writeInt32(NO_ERROR);
                return NO_ERROR;
                return NO_ERROR;
            }
            }
            case 1034: {
                // TODO(b/129297325): expose this via developer menu option
                n = data.readInt32();
                if (n && !mRefreshRateOverlay) {
                    std::lock_guard<std::mutex> lock(mActiveConfigLock);
                    mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
                    mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
                } else if (!n) {
                    mRefreshRateOverlay.reset();
                }
                return NO_ERROR;
            }
        }
        }
    }
    }
    return err;
    return err;
@@ -5811,8 +5826,8 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal(
    for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
    for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
        if (iter->second && isConfigAllowed(*displayId, iter->second->configId)) {
        if (iter->second && isConfigAllowed(*displayId, iter->second->configId)) {
            ALOGV("switching to config %d", iter->second->configId);
            ALOGV("switching to config %d", iter->second->configId);
            setDesiredActiveConfig(displayToken, iter->second->configId,
            setDesiredActiveConfig({iter->first, iter->second->configId, displayToken,
                                   Scheduler::ConfigEvent::Changed);
                                    Scheduler::ConfigEvent::Changed});
            break;
            break;
        }
        }
    }
    }
+28 −16
Original line number Original line Diff line number Diff line
@@ -90,6 +90,8 @@ using namespace android::surfaceflinger;


namespace android {
namespace android {


using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;

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


class Client;
class Client;
@@ -102,6 +104,7 @@ class IGraphicBufferProducer;
class IInputFlinger;
class IInputFlinger;
class InjectVSyncSource;
class InjectVSyncSource;
class Layer;
class Layer;
class RefreshRateOverlay;
class Surface;
class Surface;
class SurfaceFlingerBE;
class SurfaceFlingerBE;
class TimeStats;
class TimeStats;
@@ -366,6 +369,7 @@ private:
    friend class BufferQueueLayer;
    friend class BufferQueueLayer;
    friend class BufferStateLayer;
    friend class BufferStateLayer;
    friend class MonitoredProducer;
    friend class MonitoredProducer;
    friend class RefreshRateOverlay;
    friend class RegionSamplingThread;
    friend class RegionSamplingThread;
    friend class SurfaceTracing;
    friend class SurfaceTracing;


@@ -528,11 +532,30 @@ private:
    void signalLayerUpdate();
    void signalLayerUpdate();
    void signalRefresh();
    void signalRefresh();


    struct ActiveConfigInfo {
        RefreshRateType type;
        int configId;
        sp<IBinder> displayToken;
        Scheduler::ConfigEvent event;

        bool operator!=(const ActiveConfigInfo& other) const {
            if (type != other.type) {
                return true;
            }
            if (configId != other.configId) {
                return true;
            }
            if (displayToken != other.displayToken) {
                return true;
            }
            return (event != other.event);
        }
    };

    // called on the main thread in response to initializeDisplays()
    // called on the main thread in response to initializeDisplays()
    void onInitializeDisplays() REQUIRES(mStateLock);
    void onInitializeDisplays() REQUIRES(mStateLock);
    // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
    // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
    void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
    void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
                                Scheduler::ConfigEvent event) REQUIRES(mStateLock);
    // Once HWC has returned the present fence, this sets the active config and a new refresh
    // Once HWC has returned the present fence, this sets the active config and a new refresh
    // rate in SF. It also triggers HWC vsync.
    // rate in SF. It also triggers HWC vsync.
    void setActiveConfigInternal() REQUIRES(mStateLock);
    void setActiveConfigInternal() REQUIRES(mStateLock);
@@ -815,8 +838,7 @@ private:


    // Sets the refresh rate by switching active configs, if they are available for
    // Sets the refresh rate by switching active configs, if they are available for
    // the desired refresh rate.
    // the desired refresh rate.
    void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType,
    void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock);
                          Scheduler::ConfigEvent event) REQUIRES(mStateLock);


    bool isConfigAllowed(const DisplayId& displayId, int32_t config);
    bool isConfigAllowed(const DisplayId& displayId, int32_t config);


@@ -1134,18 +1156,6 @@ private:
    std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
    std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
            GUARDED_BY(mAllowedConfigsLock);
            GUARDED_BY(mAllowedConfigsLock);


    struct ActiveConfigInfo {
        int configId;
        sp<IBinder> displayToken;
        Scheduler::ConfigEvent event;

        bool operator!=(const ActiveConfigInfo& other) const {
            if (configId != other.configId) {
                return true;
            }
            return (displayToken != other.displayToken);
        }
    };
    std::mutex mActiveConfigLock;
    std::mutex mActiveConfigLock;
    // This bit is set once we start setting the config. We read from this bit during the
    // This bit is set once we start setting the config. We read from this bit during the
    // process. If at the end, this bit is different than mDesiredActiveConfig, we restart
    // process. If at the end, this bit is different than mDesiredActiveConfig, we restart
@@ -1172,6 +1182,8 @@ private:
    sp<SetInputWindowsListener> mSetInputWindowsListener;
    sp<SetInputWindowsListener> mSetInputWindowsListener;
    bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
    bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
    Hwc2::impl::PowerAdvisor mPowerAdvisor;
    Hwc2::impl::PowerAdvisor mPowerAdvisor;

    std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
};
};
}; // namespace android
}; // namespace android