Loading services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -168,6 +168,7 @@ filegroup { "FrameTracer/FrameTracer.cpp", "FrameTracker.cpp", "HdrLayerInfoReporter.cpp", "HdrSdrRatioOverlay.cpp", "WindowInfosListenerInvoker.cpp", "Layer.cpp", "LayerFE.cpp", Loading services/surfaceflinger/DisplayDevice.cpp +42 −2 Original line number Diff line number Diff line Loading @@ -37,11 +37,11 @@ #include <configstore/Utils.h> #include <log/log.h> #include <system/window.h> #include <ui/GraphicTypes.h> #include "Display/DisplaySnapshot.h" #include "DisplayDevice.h" #include "FrontEnd/DisplayInfo.h" #include "HdrSdrRatioOverlay.h" #include "Layer.h" #include "RefreshRateOverlay.h" #include "SurfaceFlinger.h" Loading Loading @@ -261,6 +261,9 @@ void DisplayDevice::setLayerFilter(ui::LayerFilter filter) { if (mRefreshRateOverlay) { mRefreshRateOverlay->setLayerStack(filter.layerStack); } if (mHdrSdrRatioOverlay) { mHdrSdrRatioOverlay->setLayerStack(filter.layerStack); } } void DisplayDevice::setFlags(uint32_t flags) { Loading @@ -274,10 +277,14 @@ void DisplayDevice::setDisplaySize(int width, int height) { if (mRefreshRateOverlay) { mRefreshRateOverlay->setViewport(size); } if (mHdrSdrRatioOverlay) { mHdrSdrRatioOverlay->setViewport(size); } } void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpaceRect, Rect orientedDisplaySpaceRect) { mIsOrientationChanged = mOrientation != orientation; mOrientation = orientation; // We need to take care of display rotation for globalTransform for case if the panel is not Loading Loading @@ -411,6 +418,26 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const { 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, bool showRenderRate, bool showInMiddle) { if (!enable) { Loading Loading @@ -463,10 +490,23 @@ bool DisplayDevice::onKernelTimerChanged(std::optional<DisplayModeId> desiredMod return false; } void DisplayDevice::animateRefreshRateOverlay() { void DisplayDevice::animateOverlay() { if (mRefreshRateOverlay) { 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) Loading services/surfaceflinger/DisplayDevice.h +12 −1 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ namespace android { class Fence; class HWComposer; class HdrSdrRatioOverlay; class IGraphicBufferProducer; class Layer; class RefreshRateOverlay; Loading Loading @@ -235,13 +236,19 @@ public: return mRefreshRateSelector; } void animateOverlay(); // Enables an overlay to be displayed with the current refresh rate void enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, bool showRenderRate, bool showInMiddle) REQUIRES(kMainThreadContext); void updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc = false); bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; } 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; Loading Loading @@ -271,6 +278,7 @@ private: const ui::Rotation mPhysicalOrientation; ui::Rotation mOrientation = ui::ROTATION_0; bool mIsOrientationChanged = false; // Allow nullopt as initial power mode. using TracedPowerMode = TracedOrdinal<hardware::graphics::composer::hal::PowerMode>; Loading @@ -297,6 +305,9 @@ private: std::shared_ptr<scheduler::RefreshRateSelector> mRefreshRateSelector; 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; ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock); Loading services/surfaceflinger/HdrSdrRatioOverlay.cpp 0 → 100644 +178 −0 Original line number 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 services/surfaceflinger/HdrSdrRatioOverlay.h 0 → 100644 +45 −0 Original line number 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
services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -168,6 +168,7 @@ filegroup { "FrameTracer/FrameTracer.cpp", "FrameTracker.cpp", "HdrLayerInfoReporter.cpp", "HdrSdrRatioOverlay.cpp", "WindowInfosListenerInvoker.cpp", "Layer.cpp", "LayerFE.cpp", Loading
services/surfaceflinger/DisplayDevice.cpp +42 −2 Original line number Diff line number Diff line Loading @@ -37,11 +37,11 @@ #include <configstore/Utils.h> #include <log/log.h> #include <system/window.h> #include <ui/GraphicTypes.h> #include "Display/DisplaySnapshot.h" #include "DisplayDevice.h" #include "FrontEnd/DisplayInfo.h" #include "HdrSdrRatioOverlay.h" #include "Layer.h" #include "RefreshRateOverlay.h" #include "SurfaceFlinger.h" Loading Loading @@ -261,6 +261,9 @@ void DisplayDevice::setLayerFilter(ui::LayerFilter filter) { if (mRefreshRateOverlay) { mRefreshRateOverlay->setLayerStack(filter.layerStack); } if (mHdrSdrRatioOverlay) { mHdrSdrRatioOverlay->setLayerStack(filter.layerStack); } } void DisplayDevice::setFlags(uint32_t flags) { Loading @@ -274,10 +277,14 @@ void DisplayDevice::setDisplaySize(int width, int height) { if (mRefreshRateOverlay) { mRefreshRateOverlay->setViewport(size); } if (mHdrSdrRatioOverlay) { mHdrSdrRatioOverlay->setViewport(size); } } void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpaceRect, Rect orientedDisplaySpaceRect) { mIsOrientationChanged = mOrientation != orientation; mOrientation = orientation; // We need to take care of display rotation for globalTransform for case if the panel is not Loading Loading @@ -411,6 +418,26 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const { 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, bool showRenderRate, bool showInMiddle) { if (!enable) { Loading Loading @@ -463,10 +490,23 @@ bool DisplayDevice::onKernelTimerChanged(std::optional<DisplayModeId> desiredMod return false; } void DisplayDevice::animateRefreshRateOverlay() { void DisplayDevice::animateOverlay() { if (mRefreshRateOverlay) { 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) Loading
services/surfaceflinger/DisplayDevice.h +12 −1 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ namespace android { class Fence; class HWComposer; class HdrSdrRatioOverlay; class IGraphicBufferProducer; class Layer; class RefreshRateOverlay; Loading Loading @@ -235,13 +236,19 @@ public: return mRefreshRateSelector; } void animateOverlay(); // Enables an overlay to be displayed with the current refresh rate void enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, bool showRenderRate, bool showInMiddle) REQUIRES(kMainThreadContext); void updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc = false); bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; } 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; Loading Loading @@ -271,6 +278,7 @@ private: const ui::Rotation mPhysicalOrientation; ui::Rotation mOrientation = ui::ROTATION_0; bool mIsOrientationChanged = false; // Allow nullopt as initial power mode. using TracedPowerMode = TracedOrdinal<hardware::graphics::composer::hal::PowerMode>; Loading @@ -297,6 +305,9 @@ private: std::shared_ptr<scheduler::RefreshRateSelector> mRefreshRateSelector; 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; ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock); Loading
services/surfaceflinger/HdrSdrRatioOverlay.cpp 0 → 100644 +178 −0 Original line number 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
services/surfaceflinger/HdrSdrRatioOverlay.h 0 → 100644 +45 −0 Original line number 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