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

Commit 147581b1 authored by Sally Qi's avatar Sally Qi
Browse files

Add new SF backdoor option: hdr/sdr ratio overlay

 - follow how RefreshRateOverlay did in general.
 - 1043 as new opcode to enable hdr/sdr ratio overlay.
 - decouple SevenSegmentDrawer and SurfaceControlHandle helper classes
   from RefreshRateOverlay.
 - add corresponding SF backdoor test for validation.
 - for non-HDR-supported device, we don't reject them to use SF backdoor
   but 1.00 will be always shown on the screen if enabling.

Test: adb shell call service call SurfaceFlinger 1043 1; atest
SurfaceFlinger_test
Bug: 277957056

Change-Id: Ifce2d435f127b53ab9d01aba4e24ffd4fdb010a7
parent 1160ecdf
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -168,6 +168,7 @@ filegroup {
        "FrameTracer/FrameTracer.cpp",
        "FrameTracer/FrameTracer.cpp",
        "FrameTracker.cpp",
        "FrameTracker.cpp",
        "HdrLayerInfoReporter.cpp",
        "HdrLayerInfoReporter.cpp",
        "HdrSdrRatioOverlay.cpp",
        "WindowInfosListenerInvoker.cpp",
        "WindowInfosListenerInvoker.cpp",
        "Layer.cpp",
        "Layer.cpp",
        "LayerFE.cpp",
        "LayerFE.cpp",
+42 −2
Original line number Original line Diff line number Diff line
@@ -37,11 +37,11 @@
#include <configstore/Utils.h>
#include <configstore/Utils.h>
#include <log/log.h>
#include <log/log.h>
#include <system/window.h>
#include <system/window.h>
#include <ui/GraphicTypes.h>


#include "Display/DisplaySnapshot.h"
#include "Display/DisplaySnapshot.h"
#include "DisplayDevice.h"
#include "DisplayDevice.h"
#include "FrontEnd/DisplayInfo.h"
#include "FrontEnd/DisplayInfo.h"
#include "HdrSdrRatioOverlay.h"
#include "Layer.h"
#include "Layer.h"
#include "RefreshRateOverlay.h"
#include "RefreshRateOverlay.h"
#include "SurfaceFlinger.h"
#include "SurfaceFlinger.h"
@@ -261,6 +261,9 @@ void DisplayDevice::setLayerFilter(ui::LayerFilter filter) {
    if (mRefreshRateOverlay) {
    if (mRefreshRateOverlay) {
        mRefreshRateOverlay->setLayerStack(filter.layerStack);
        mRefreshRateOverlay->setLayerStack(filter.layerStack);
    }
    }
    if (mHdrSdrRatioOverlay) {
        mHdrSdrRatioOverlay->setLayerStack(filter.layerStack);
    }
}
}


void DisplayDevice::setFlags(uint32_t flags) {
void DisplayDevice::setFlags(uint32_t flags) {
@@ -274,10 +277,14 @@ void DisplayDevice::setDisplaySize(int width, int height) {
    if (mRefreshRateOverlay) {
    if (mRefreshRateOverlay) {
        mRefreshRateOverlay->setViewport(size);
        mRefreshRateOverlay->setViewport(size);
    }
    }
    if (mHdrSdrRatioOverlay) {
        mHdrSdrRatioOverlay->setViewport(size);
    }
}
}


void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpaceRect,
void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpaceRect,
                                  Rect orientedDisplaySpaceRect) {
                                  Rect orientedDisplaySpaceRect) {
    mIsOrientationChanged = mOrientation != orientation;
    mOrientation = orientation;
    mOrientation = orientation;


    // We need to take care of display rotation for globalTransform for case if the panel is not
    // We need to take care of display rotation for globalTransform for case if the panel is not
@@ -411,6 +418,26 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const {
                           capabilities.getDesiredMinLuminance());
                           capabilities.getDesiredMinLuminance());
}
}


void DisplayDevice::enableHdrSdrRatioOverlay(bool enable) {
    if (!enable) {
        mHdrSdrRatioOverlay.reset();
        return;
    }

    mHdrSdrRatioOverlay = std::make_unique<HdrSdrRatioOverlay>();
    mHdrSdrRatioOverlay->setLayerStack(getLayerStack());
    mHdrSdrRatioOverlay->setViewport(getSize());
    updateHdrSdrRatioOverlayRatio(mHdrSdrRatio);
}

void DisplayDevice::updateHdrSdrRatioOverlayRatio(float currentHdrSdrRatio) {
    ATRACE_CALL();
    mHdrSdrRatio = currentHdrSdrRatio;
    if (mHdrSdrRatioOverlay) {
        mHdrSdrRatioOverlay->changeHdrSdrRatio(currentHdrSdrRatio);
    }
}

void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner,
void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner,
                                             bool showRenderRate, bool showInMiddle) {
                                             bool showRenderRate, bool showInMiddle) {
    if (!enable) {
    if (!enable) {
@@ -463,10 +490,23 @@ bool DisplayDevice::onKernelTimerChanged(std::optional<DisplayModeId> desiredMod
    return false;
    return false;
}
}


void DisplayDevice::animateRefreshRateOverlay() {
void DisplayDevice::animateOverlay() {
    if (mRefreshRateOverlay) {
    if (mRefreshRateOverlay) {
        mRefreshRateOverlay->animate();
        mRefreshRateOverlay->animate();
    }
    }
    if (mHdrSdrRatioOverlay) {
        // hdr sdr ratio is designed to be on the top right of the screen,
        // therefore, we need to re-calculate the display's width and height
        if (mIsOrientationChanged) {
            auto width = getWidth();
            auto height = getHeight();
            if (mOrientation == ui::ROTATION_90 || mOrientation == ui::ROTATION_270) {
                std::swap(width, height);
            }
            mHdrSdrRatioOverlay->setViewport({width, height});
        }
        mHdrSdrRatioOverlay->animate();
    }
}
}


auto DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info, bool force)
auto DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info, bool force)
+12 −1
Original line number Original line Diff line number Diff line
@@ -55,6 +55,7 @@ namespace android {


class Fence;
class Fence;
class HWComposer;
class HWComposer;
class HdrSdrRatioOverlay;
class IGraphicBufferProducer;
class IGraphicBufferProducer;
class Layer;
class Layer;
class RefreshRateOverlay;
class RefreshRateOverlay;
@@ -235,13 +236,19 @@ public:
        return mRefreshRateSelector;
        return mRefreshRateSelector;
    }
    }


    void animateOverlay();

    // Enables an overlay to be displayed with the current refresh rate
    // Enables an overlay to be displayed with the current refresh rate
    void enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, bool showRenderRate,
    void enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, bool showRenderRate,
                                  bool showInMiddle) REQUIRES(kMainThreadContext);
                                  bool showInMiddle) REQUIRES(kMainThreadContext);
    void updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc = false);
    void updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc = false);
    bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; }
    bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; }
    bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired);
    bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired);
    void animateRefreshRateOverlay();

    // Enables an overlay to be display with the hdr/sdr ratio
    void enableHdrSdrRatioOverlay(bool enable) REQUIRES(kMainThreadContext);
    void updateHdrSdrRatioOverlayRatio(float currentHdrSdrRatio);
    bool isHdrSdrRatioOverlayEnabled() const { return mHdrSdrRatioOverlay != nullptr; }


    nsecs_t getVsyncPeriodFromHWC() const;
    nsecs_t getVsyncPeriodFromHWC() const;


@@ -271,6 +278,7 @@ private:


    const ui::Rotation mPhysicalOrientation;
    const ui::Rotation mPhysicalOrientation;
    ui::Rotation mOrientation = ui::ROTATION_0;
    ui::Rotation mOrientation = ui::ROTATION_0;
    bool mIsOrientationChanged = false;


    // Allow nullopt as initial power mode.
    // Allow nullopt as initial power mode.
    using TracedPowerMode = TracedOrdinal<hardware::graphics::composer::hal::PowerMode>;
    using TracedPowerMode = TracedOrdinal<hardware::graphics::composer::hal::PowerMode>;
@@ -297,6 +305,9 @@ private:


    std::shared_ptr<scheduler::RefreshRateSelector> mRefreshRateSelector;
    std::shared_ptr<scheduler::RefreshRateSelector> mRefreshRateSelector;
    std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
    std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
    std::unique_ptr<HdrSdrRatioOverlay> mHdrSdrRatioOverlay;
    // This parameter is only used for hdr/sdr ratio overlay
    float mHdrSdrRatio = 1.0f;


    mutable std::mutex mActiveModeLock;
    mutable std::mutex mActiveModeLock;
    ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
    ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
+178 −0
Original line number Original line Diff line number Diff line
/**
 * Copyright (C) 2023 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.
 */
// #define LOG_NDEBUG 0
#include <algorithm>

#include "HdrSdrRatioOverlay.h"

#include <SkSurface.h>

#undef LOG_TAG
#define LOG_TAG "HdrSdrRatioOverlay"

namespace android {

void HdrSdrRatioOverlay::drawNumber(float number, int left, SkColor color, SkCanvas& canvas) {
    if (!isfinite(number) || number >= 10.f) return;
    // We assume that the number range is [1.f, 10.f)
    // and the decimal places are 2.
    int value = static_cast<int>(number * 100);
    SegmentDrawer::drawDigit(value / 100, left, color, canvas);

    left += kDigitWidth + kDigitSpace;
    SegmentDrawer::drawSegment(SegmentDrawer::Segment::DecimalPoint, left, color, canvas);
    left += kDigitWidth + kDigitSpace;

    SegmentDrawer::drawDigit((value / 10) % 10, left, color, canvas);
    left += kDigitWidth + kDigitSpace;
    SegmentDrawer::drawDigit(value % 10, left, color, canvas);
}

sp<GraphicBuffer> HdrSdrRatioOverlay::draw(float currentHdrSdrRatio, SkColor color,
                                           ui::Transform::RotationFlags rotation) {
    SkMatrix canvasTransform = SkMatrix();
    const auto [bufferWidth, bufferHeight] = [&]() -> std::pair<int, int> {
        switch (rotation) {
            case ui::Transform::ROT_90:
                canvasTransform.setTranslate(kBufferHeight, 0);
                canvasTransform.preRotate(90.f);
                return {kBufferHeight, kBufferWidth};
            case ui::Transform::ROT_270:
                canvasTransform.setRotate(270.f, kBufferWidth / 2.f, kBufferWidth / 2.f);
                return {kBufferHeight, kBufferWidth};
            default:
                return {kBufferWidth, kBufferHeight};
        }
    }();

    const auto kUsageFlags = static_cast<uint64_t>(
            GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE);
    sp<GraphicBuffer> buffer =
            sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth),
                                    static_cast<uint32_t>(bufferHeight), HAL_PIXEL_FORMAT_RGBA_8888,
                                    1u, kUsageFlags, "HdrSdrRatioOverlay");

    const status_t bufferStatus = buffer->initCheck();
    LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "HdrSdrRatioOverlay: Buffer failed to allocate: %d",
                        bufferStatus);

    sk_sp<SkSurface> surface =
            SkSurfaces::Raster(SkImageInfo::MakeN32Premul(bufferWidth, bufferHeight));
    SkCanvas* canvas = surface->getCanvas();
    canvas->setMatrix(canvasTransform);

    drawNumber(currentHdrSdrRatio, 0, color, *canvas);

    void* pixels = nullptr;
    buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));

    const SkImageInfo& imageInfo = surface->imageInfo();
    const size_t dstRowBytes = buffer->getStride() * static_cast<size_t>(imageInfo.bytesPerPixel());

    canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0);
    buffer->unlock();
    return buffer;
}

HdrSdrRatioOverlay::HdrSdrRatioOverlay()
      : mSurfaceControl(
                SurfaceControlHolder::createSurfaceControlHolder(String8("HdrSdrRatioOverlay"))) {
    if (!mSurfaceControl) {
        ALOGE("%s: Failed to create buffer state layer", __func__);
        return;
    }
    SurfaceComposerClient::Transaction()
            .setLayer(mSurfaceControl->get(), INT32_MAX - 2)
            .setTrustedOverlay(mSurfaceControl->get(), true)
            .apply();
}

void HdrSdrRatioOverlay::changeHdrSdrRatio(float currentHdrSdrRatio) {
    mCurrentHdrSdrRatio = currentHdrSdrRatio;
    animate();
}

void HdrSdrRatioOverlay::setLayerStack(ui::LayerStack stack) {
    SurfaceComposerClient::Transaction().setLayerStack(mSurfaceControl->get(), stack).apply();
}

void HdrSdrRatioOverlay::setViewport(ui::Size viewport) {
    constexpr int32_t kMaxWidth = 1000;
    const auto width = std::min({kMaxWidth, viewport.width, viewport.height});
    const auto height = 2 * width;
    Rect frame((5 * width) >> 4, height >> 5);
    // set the ratio frame to the top right of the screen
    frame.offsetBy(viewport.width - frame.width(), height >> 4);

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

auto HdrSdrRatioOverlay::getOrCreateBuffers(float currentHdrSdrRatio) -> const sp<GraphicBuffer> {
    static const sp<GraphicBuffer> kNoBuffer;
    if (!mSurfaceControl) return kNoBuffer;

    const auto transformHint =
            static_cast<ui::Transform::RotationFlags>(mSurfaceControl->get()->getTransformHint());

    // Tell SurfaceFlinger about the pre-rotation on the buffer.
    const auto transform = [&] {
        switch (transformHint) {
            case ui::Transform::ROT_90:
                return ui::Transform::ROT_270;
            case ui::Transform::ROT_270:
                return ui::Transform::ROT_90;
            default:
                return ui::Transform::ROT_0;
        }
    }();

    SurfaceComposerClient::Transaction().setTransform(mSurfaceControl->get(), transform).apply();

    constexpr SkColor kMinRatioColor = SK_ColorBLUE;
    constexpr SkColor kMaxRatioColor = SK_ColorGREEN;
    constexpr float kAlpha = 0.8f;

    // 9.f is picked here as ratio range, given that we assume that
    // hdr/sdr ratio is [1.f, 10.f)
    const float scale = currentHdrSdrRatio / 9.f;

    SkColor4f colorBase = SkColor4f::FromColor(kMaxRatioColor) * scale;
    const SkColor4f minRatioColor = SkColor4f::FromColor(kMinRatioColor) * (1 - scale);

    colorBase.fR = colorBase.fR + minRatioColor.fR;
    colorBase.fG = colorBase.fG + minRatioColor.fG;
    colorBase.fB = colorBase.fB + minRatioColor.fB;
    colorBase.fA = kAlpha;

    const SkColor color = colorBase.toSkColor();

    auto buffer = draw(currentHdrSdrRatio, color, transformHint);
    return buffer;
}

void HdrSdrRatioOverlay::animate() {
    if (!std::isfinite(mCurrentHdrSdrRatio) || mCurrentHdrSdrRatio < 1.0f) return;

    SurfaceComposerClient::Transaction()
            .setBuffer(mSurfaceControl->get(), getOrCreateBuffers(mCurrentHdrSdrRatio))
            .apply();
}

} // namespace android
 No newline at end of file
+45 −0
Original line number Original line Diff line number Diff line
/**
 * Copyright (C) 2023 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 "Utils/OverlayUtils.h"

#include <ui/Size.h>
#include <utils/StrongPointer.h>

class SkCanvas;

namespace android {
class HdrSdrRatioOverlay {
public:
    HdrSdrRatioOverlay();
    void setLayerStack(ui::LayerStack);
    void setViewport(ui::Size);
    void animate();
    void changeHdrSdrRatio(float currentRatio);

private:
    float mCurrentHdrSdrRatio = 1.f;

    static sp<GraphicBuffer> draw(float currentHdrSdrRatio, SkColor, ui::Transform::RotationFlags);
    static void drawNumber(float number, int left, SkColor, SkCanvas&);

    const sp<GraphicBuffer> getOrCreateBuffers(float currentHdrSdrRatio);

    const std::unique_ptr<SurfaceControlHolder> mSurfaceControl;
};
} // namespace android
Loading