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

Commit 2cb8b62e authored by Ady Abraham's avatar Ady Abraham
Browse files

SurfaceFlinger: show refresh rate instead of color in overlay

Change the RefreshRateOverlay to show the actual refresh rate fps
instead of just a color.

Change-Id: Ifd6e419b1534736de466d67e9e95042e62c730c6
Test: adb shell service call SurfaceFlinger 1034 i32 1
Bug: 129297325
parent 3a77a7b6
Loading
Loading
Loading
Loading
+152 −7
Original line number Diff line number Diff line
@@ -18,26 +18,139 @@
#include "Client.h"
#include "Layer.h"

#include <gui/IProducerListener.h>

#undef LOG_TAG
#define LOG_TAG "RefreshRateOverlay"

namespace android {

void RefreshRateOverlay::SevenSegmentDrawer::drawRect(const Rect& r, const half4& color,
                                                      const sp<GraphicBuffer>& buffer,
                                                      uint8_t* pixels) {
    for (int32_t j = r.top; j < r.bottom; j++) {
        if (j >= buffer->getHeight()) {
            break;
        }

        for (int32_t i = r.left; i < r.right; i++) {
            if (i >= buffer->getWidth()) {
                break;
            }

            uint8_t* iter = pixels + 4 * (i + (buffer->getStride() * j));
            iter[0] = uint8_t(color.r * 255);
            iter[1] = uint8_t(color.g * 255);
            iter[2] = uint8_t(color.b * 255);
            iter[3] = uint8_t(color.a * 255);
        }
    }
}

void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left,
                                                         const half4& color,
                                                         const sp<GraphicBuffer>& buffer,
                                                         uint8_t* pixels) {
    const Rect rect = [&]() {
        switch (segment) {
            case Segment::Upper:
                return Rect(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
            case Segment::UpperLeft:
                return Rect(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
            case Segment::UpperRight:
                return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
                            DIGIT_HEIGHT / 2);
            case Segment::Middle:
                return Rect(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2, left + DIGIT_WIDTH,
                            DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
            case Segment::LowerLeft:
                return Rect(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
            case Segment::LowerRight:
                return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2, left + DIGIT_WIDTH,
                            DIGIT_HEIGHT);
            case Segment::Buttom:
                return Rect(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH, DIGIT_HEIGHT);
        }
    }();

    drawRect(rect, color, buffer, pixels);
}

void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, const half4& color,
                                                       const sp<GraphicBuffer>& buffer,
                                                       uint8_t* pixels) {
    if (digit < 0 || digit > 9) return;

    if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
        digit == 8 || digit == 9)
        drawSegment(Segment::Upper, left, color, buffer, pixels);
    if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
        drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
    if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
        digit == 8 || digit == 9)
        drawSegment(Segment::UpperRight, left, color, buffer, pixels);
    if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
        digit == 9)
        drawSegment(Segment::Middle, left, color, buffer, pixels);
    if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
        drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
    if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
        digit == 7 || digit == 8 || digit == 9)
        drawSegment(Segment::LowerRight, left, color, buffer, pixels);
    if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
        digit == 9)
        drawSegment(Segment::Buttom, left, color, buffer, pixels);
}

sp<GraphicBuffer> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number,
                                                                     const half4& color) {
    if (number < 0 || number > 1000) return nullptr;

    const auto hundreds = number / 100;
    const auto tens = (number / 10) % 10;
    const auto ones = number % 10;

    sp<GraphicBuffer> buffer =
            new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1,
                              GRALLOC_USAGE_SW_WRITE_RARELY, "RefreshRateOverlayBuffer");
    uint8_t* pixels;
    buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
    int left = 0;
    if (hundreds != 0) {
        drawDigit(hundreds, left, color, buffer, pixels);
        left += DIGIT_WIDTH + DIGIT_SPACE;
    }

    if (tens != 0) {
        drawDigit(tens, left, color, buffer, pixels);
        left += DIGIT_WIDTH + DIGIT_SPACE;
    }

    drawDigit(ones, left, color, buffer, pixels);
    buffer->unlock();
    return buffer;
}

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

bool RefreshRateOverlay::createLayer() {
    const status_t ret =
            mFlinger.createLayer(String8("RefreshRateOverlay"), mClient, 0, 0,
                                 PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor,
                                 LayerMetadata(), &mIBinder, &mGbp, nullptr);
            mFlinger.createLayer(String8("RefreshRateOverlay"), mClient,
                                 SevenSegmentDrawer::getWidth(), SevenSegmentDrawer::getHeight(),
                                 PIXEL_FORMAT_RGBA_8888,
                                 ISurfaceComposerClient::eFXSurfaceBufferState, LayerMetadata(),
                                 &mIBinder, &mGbp, nullptr);
    if (ret) {
        ALOGE("failed to create color layer");
        ALOGE("failed to create buffer state layer");
        return false;
    }

    Mutex::Autolock _l(mFlinger.mStateLock);
    mLayer = mClient->getLayerUser(mIBinder);
    mLayer->setCrop_legacy(Rect(50, 70, 200, 100));

    // setting Layer's Z requires resorting layersSortedByZ
    ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
@@ -49,9 +162,41 @@ bool RefreshRateOverlay::createLayer() {
    return true;
}

void RefreshRateOverlay::primeCache() {
    auto allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates();
    if (allRefreshRates.size() == 1) {
        auto fps = allRefreshRates.begin()->second.fps;
        half4 color = {LOW_FPS_COLOR, ALPHA};
        mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
        return;
    }

    std::vector<uint32_t> supportedFps;
    supportedFps.reserve(allRefreshRates.size());
    for (auto [ignored, refreshRate] : allRefreshRates) {
        supportedFps.push_back(refreshRate.fps);
    }

    std::sort(supportedFps.begin(), supportedFps.end());
    const auto mLowFps = supportedFps[0];
    const auto mHighFps = supportedFps[supportedFps.size() - 1];
    for (auto fps : supportedFps) {
        const auto fpsScale = float(fps - mLowFps) / (mHighFps - mLowFps);
        half4 color;
        color.r = HIGH_FPS_COLOR.r * fpsScale + LOW_FPS_COLOR.r * (1 - fpsScale);
        color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale);
        color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale);
        color.a = ALPHA;
        mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
    }
}

void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
    const half3& color = (refreshRate.fps > 65.0f) ? GREEN : RED;
    mLayer->setColor(color);
    auto buffer = mBufferCache[refreshRate.fps];
    mLayer->setBuffer(buffer, 0, 0, {});
    mLayer->setFrame(Rect(20, 120, 20 + SevenSegmentDrawer::getWidth(),
                          120 + SevenSegmentDrawer::getHeight()));

    mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}

+30 −2
Original line number Diff line number Diff line
@@ -28,7 +28,32 @@ public:
    void changeRefreshRate(const RefreshRate& refreshRate);

private:
    class SevenSegmentDrawer {
    public:
        static sp<GraphicBuffer> drawNumber(int number, const half4& color);
        static uint32_t getHeight() { return BUFFER_HEIGHT; }
        static uint32_t getWidth() { return BUFFER_WIDTH; }

    private:
        enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Buttom };

        static void drawRect(const Rect& r, const half4& color, const sp<GraphicBuffer>& buffer,
                             uint8_t* pixels);
        static void drawSegment(Segment segment, int left, const half4& color,
                                const sp<GraphicBuffer>& buffer, uint8_t* pixels);
        static void drawDigit(int digit, int left, const half4& color,
                              const sp<GraphicBuffer>& buffer, uint8_t* pixels);

        static constexpr uint32_t DIGIT_HEIGHT = 100;
        static constexpr uint32_t DIGIT_WIDTH = 64;
        static constexpr uint32_t DIGIT_SPACE = 16;
        static constexpr uint32_t BUFFER_HEIGHT = DIGIT_HEIGHT;
        static constexpr uint32_t BUFFER_WIDTH =
                3 * DIGIT_WIDTH + 2 * DIGIT_SPACE; // Digit|Space|Digit|Space|Digit
    };

    bool createLayer();
    void primeCache();

    SurfaceFlinger& mFlinger;
    sp<Client> mClient;
@@ -36,8 +61,11 @@ private:
    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);
    std::unordered_map<int, sp<GraphicBuffer>> mBufferCache;

    static constexpr float ALPHA = 0.8f;
    const half3 LOW_FPS_COLOR = half3(1.0f, 0.0f, 0.0f);
    const half3 HIGH_FPS_COLOR = half3(0.0f, 1.0f, 0.0f);
};

}; // namespace android
+4 −4
Original line number Diff line number Diff line
@@ -4831,15 +4831,15 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
                return NO_ERROR;
            }
            case 1034: {
                // TODO(b/129297325): expose this via developer menu option
                n = data.readInt32();
                if (n && !mRefreshRateOverlay &&
                    mRefreshRateConfigs->refreshRateSwitchingSupported()) {
                if (n == 1 && !mRefreshRateOverlay) {
                    mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
                    auto current = mRefreshRateConfigs->getCurrentRefreshRate();
                    mRefreshRateOverlay->changeRefreshRate(current);
                } else if (!n) {
                } else if (n == 0) {
                    mRefreshRateOverlay.reset();
                } else {
                    reply->writeBool(mRefreshRateOverlay != nullptr);
                }
                return NO_ERROR;
            }