blob: 9527a997df8710b7f7403f1bdd6cae9d857647e9 [file] [log] [blame]
Ady Abraham03b02dd2019-03-21 15:40:11 -07001/*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +010017#include <algorithm>
18
Alec Mouri9b133ca2023-11-14 19:00:01 +000019#include <common/FlagManager.h>
Ady Abraham03b02dd2019-03-21 15:40:11 -070020#include "Client.h"
21#include "Layer.h"
Ady Abraham3649ea82022-07-08 16:04:02 -070022#include "RefreshRateOverlay.h"
Ady Abraham03b02dd2019-03-21 15:40:11 -070023
rnlee756005b2021-05-27 10:46:36 -070024#include <SkSurface.h>
Ady Abraham2cb8b622019-12-02 18:55:33 -080025
26#undef LOG_TAG
27#define LOG_TAG "RefreshRateOverlay"
28
Ady Abraham03b02dd2019-03-21 15:40:11 -070029namespace android {
30
Ying Wei22d59cc2024-05-11 02:41:08 +000031auto RefreshRateOverlay::draw(int refreshRate, int renderFps, SkColor color,
Sally Qi147581b2023-06-27 11:55:34 -070032 ui::Transform::RotationFlags rotation, ftl::Flags<Features> features)
33 -> Buffers {
Ady Abraham0aa373a2022-11-22 13:56:50 -080034 const size_t loopCount = features.test(Features::Spinner) ? 6 : 1;
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070035
36 Buffers buffers;
37 buffers.reserve(loopCount);
38
39 for (size_t i = 0; i < loopCount; i++) {
rnlee756005b2021-05-27 10:46:36 -070040 // Pre-rotate the buffer before it reaches SurfaceFlinger.
41 SkMatrix canvasTransform = SkMatrix();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070042 const auto [bufferWidth, bufferHeight] = [&]() -> std::pair<int, int> {
rnlee756005b2021-05-27 10:46:36 -070043 switch (rotation) {
44 case ui::Transform::ROT_90:
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070045 canvasTransform.setTranslate(kBufferHeight, 0);
46 canvasTransform.preRotate(90.f);
47 return {kBufferHeight, kBufferWidth};
rnlee756005b2021-05-27 10:46:36 -070048 case ui::Transform::ROT_270:
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070049 canvasTransform.setRotate(270.f, kBufferWidth / 2.f, kBufferWidth / 2.f);
50 return {kBufferHeight, kBufferWidth};
rnlee756005b2021-05-27 10:46:36 -070051 default:
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070052 return {kBufferWidth, kBufferHeight};
rnlee756005b2021-05-27 10:46:36 -070053 }
54 }();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070055
Ady Abrahamd11bade2022-08-01 16:18:03 -070056 const auto kUsageFlags =
57 static_cast<uint64_t>(GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
58 GRALLOC_USAGE_HW_TEXTURE);
59 sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth),
60 static_cast<uint32_t>(bufferHeight),
61 HAL_PIXEL_FORMAT_RGBA_8888, 1u,
62 kUsageFlags, "RefreshRateOverlayBuffer");
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070063
Alec Mouri7013b6f2021-02-12 11:16:54 -080064 const status_t bufferStatus = buffer->initCheck();
65 LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
66 bufferStatus);
rnlee756005b2021-05-27 10:46:36 -070067
Kevin Lubick00bec722023-05-12 19:26:03 +000068 sk_sp<SkSurface> surface = SkSurfaces::Raster(
69 SkImageInfo::MakeN32Premul(bufferWidth, bufferHeight));
rnlee756005b2021-05-27 10:46:36 -070070 SkCanvas* canvas = surface->getCanvas();
71 canvas->setMatrix(canvasTransform);
72
Ady Abraham29d0da32020-07-16 18:39:33 -070073 int left = 0;
Ying Wei22d59cc2024-05-11 02:41:08 +000074 drawNumber(refreshRate, left, color, *canvas);
Ady Abraham0aa373a2022-11-22 13:56:50 -080075 left += 3 * (kDigitWidth + kDigitSpace);
76 if (features.test(Features::Spinner)) {
Ady Abraham29d0da32020-07-16 18:39:33 -070077 switch (i) {
78 case 0:
Sally Qi147581b2023-06-27 11:55:34 -070079 SegmentDrawer::drawSegment(SegmentDrawer::Segment::Upper, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -070080 break;
81 case 1:
Sally Qi147581b2023-06-27 11:55:34 -070082 SegmentDrawer::drawSegment(SegmentDrawer::Segment::UpperRight, left, color,
83 *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -070084 break;
85 case 2:
Sally Qi147581b2023-06-27 11:55:34 -070086 SegmentDrawer::drawSegment(SegmentDrawer::Segment::LowerRight, left, color,
87 *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -070088 break;
89 case 3:
Sally Qi147581b2023-06-27 11:55:34 -070090 SegmentDrawer::drawSegment(SegmentDrawer::Segment::Bottom, left, color,
91 *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -070092 break;
93 case 4:
Sally Qi147581b2023-06-27 11:55:34 -070094 SegmentDrawer::drawSegment(SegmentDrawer::Segment::LowerLeft, left, color,
95 *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -070096 break;
97 case 5:
Sally Qi147581b2023-06-27 11:55:34 -070098 SegmentDrawer::drawSegment(SegmentDrawer::Segment::UpperLeft, left, color,
99 *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700100 break;
101 }
102 }
103
Ady Abraham0aa373a2022-11-22 13:56:50 -0800104 left += kDigitWidth + kDigitSpace;
105
106 if (features.test(Features::RenderRate)) {
107 drawNumber(renderFps, left, color, *canvas);
108 }
109 left += 3 * (kDigitWidth + kDigitSpace);
110
rnlee756005b2021-05-27 10:46:36 -0700111 void* pixels = nullptr;
112 buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700113
rnlee756005b2021-05-27 10:46:36 -0700114 const SkImageInfo& imageInfo = surface->imageInfo();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700115 const size_t dstRowBytes =
116 buffer->getStride() * static_cast<size_t>(imageInfo.bytesPerPixel());
117
rnlee756005b2021-05-27 10:46:36 -0700118 canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0);
Ady Abraham29d0da32020-07-16 18:39:33 -0700119 buffer->unlock();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700120 buffers.push_back(std::move(buffer));
Ady Abraham29d0da32020-07-16 18:39:33 -0700121 }
122 return buffers;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800123}
124
Sally Qi147581b2023-06-27 11:55:34 -0700125void RefreshRateOverlay::drawNumber(int number, int left, SkColor color, SkCanvas& canvas) {
Ady Abraham0aa373a2022-11-22 13:56:50 -0800126 if (number < 0 || number >= 1000) return;
127
128 if (number >= 100) {
Sally Qi147581b2023-06-27 11:55:34 -0700129 SegmentDrawer::drawDigit(number / 100, left, color, canvas);
Ady Abraham0aa373a2022-11-22 13:56:50 -0800130 }
131 left += kDigitWidth + kDigitSpace;
132
133 if (number >= 10) {
Sally Qi147581b2023-06-27 11:55:34 -0700134 SegmentDrawer::drawDigit((number / 10) % 10, left, color, canvas);
Ady Abraham0aa373a2022-11-22 13:56:50 -0800135 }
136 left += kDigitWidth + kDigitSpace;
137
Sally Qi147581b2023-06-27 11:55:34 -0700138 SegmentDrawer::drawDigit(number % 10, left, color, canvas);
Ady Abraham3649ea82022-07-08 16:04:02 -0700139}
140
Ady Abrahamddba9342023-10-02 16:28:03 -0700141std::unique_ptr<RefreshRateOverlay> RefreshRateOverlay::create(FpsRange range,
142 ftl::Flags<Features> features) {
143 std::unique_ptr<RefreshRateOverlay> overlay =
144 std::make_unique<RefreshRateOverlay>(ConstructorTag{}, range, features);
145 if (overlay->initCheck()) {
146 return overlay;
147 }
148
149 ALOGE("%s: Failed to create RefreshRateOverlay", __func__);
150 return {};
151}
152
153RefreshRateOverlay::RefreshRateOverlay(ConstructorTag, FpsRange fpsRange,
154 ftl::Flags<Features> features)
Sally Qi147581b2023-06-27 11:55:34 -0700155 : mFpsRange(fpsRange),
156 mFeatures(features),
157 mSurfaceControl(
158 SurfaceControlHolder::createSurfaceControlHolder(String8("RefreshRateOverlay"))) {
chaviw70aa7572021-09-22 12:27:57 -0500159 if (!mSurfaceControl) {
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700160 ALOGE("%s: Failed to create buffer state layer", __func__);
161 return;
Ady Abraham03b02dd2019-03-21 15:40:11 -0700162 }
163
ramindanib2158ee2023-02-13 20:29:59 -0800164 createTransaction()
Ady Abraham3649ea82022-07-08 16:04:02 -0700165 .setLayer(mSurfaceControl->get(), INT32_MAX - 2)
166 .setTrustedOverlay(mSurfaceControl->get(), true)
Ady Abraham78c4a242021-11-30 17:49:44 -0800167 .apply();
Ady Abraham03b02dd2019-03-21 15:40:11 -0700168}
169
Ady Abrahamddba9342023-10-02 16:28:03 -0700170bool RefreshRateOverlay::initCheck() const {
171 return mSurfaceControl != nullptr;
172}
173
Ying Wei22d59cc2024-05-11 02:41:08 +0000174auto RefreshRateOverlay::getOrCreateBuffers(Fps refreshRate, Fps renderFps) -> const Buffers& {
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700175 static const Buffers kNoBuffers;
176 if (!mSurfaceControl) return kNoBuffers;
177
Ady Abraham0aa373a2022-11-22 13:56:50 -0800178 // avoid caching different render rates if RenderRate is anyway not visible
179 if (!mFeatures.test(Features::RenderRate)) {
180 renderFps = 0_Hz;
181 }
182
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700183 const auto transformHint =
Ady Abraham3649ea82022-07-08 16:04:02 -0700184 static_cast<ui::Transform::RotationFlags>(mSurfaceControl->get()->getTransformHint());
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700185
rnlee756005b2021-05-27 10:46:36 -0700186 // Tell SurfaceFlinger about the pre-rotation on the buffer.
187 const auto transform = [&] {
188 switch (transformHint) {
189 case ui::Transform::ROT_90:
190 return ui::Transform::ROT_270;
191 case ui::Transform::ROT_270:
192 return ui::Transform::ROT_90;
193 default:
194 return ui::Transform::ROT_0;
195 }
196 }();
chaviw70aa7572021-09-22 12:27:57 -0500197
ramindanib2158ee2023-02-13 20:29:59 -0800198 createTransaction().setTransform(mSurfaceControl->get(), transform).apply();
rnlee756005b2021-05-27 10:46:36 -0700199
Ady Abraham0aa373a2022-11-22 13:56:50 -0800200 BufferCache::const_iterator it =
Ying Wei22d59cc2024-05-11 02:41:08 +0000201 mBufferCache.find({refreshRate.getIntValue(), renderFps.getIntValue(), transformHint});
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700202 if (it == mBufferCache.end()) {
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700203 const int maxFps = mFpsRange.max.getIntValue();
204
ramindanic6e522e2024-05-07 16:42:51 -0700205 // Clamp to supported refresh rate range: the current refresh rate may be outside of this
206 // range if the display has changed its set of supported refresh rates.
207 const int refreshIntFps = std::clamp(refreshRate.getIntValue(), 0, maxFps);
Ady Abraham0aa373a2022-11-22 13:56:50 -0800208 const int renderIntFps = renderFps.getIntValue();
ramindanic6e522e2024-05-07 16:42:51 -0700209 const float fpsScale = static_cast<float>(refreshIntFps) / maxFps;
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700210
211 constexpr SkColor kMinFpsColor = SK_ColorRED;
212 constexpr SkColor kMaxFpsColor = SK_ColorGREEN;
213 constexpr float kAlpha = 0.8f;
214
215 SkColor4f colorBase = SkColor4f::FromColor(kMaxFpsColor) * fpsScale;
216 const SkColor4f minFpsColor = SkColor4f::FromColor(kMinFpsColor) * (1 - fpsScale);
217
218 colorBase.fR = colorBase.fR + minFpsColor.fR;
219 colorBase.fG = colorBase.fG + minFpsColor.fG;
220 colorBase.fB = colorBase.fB + minFpsColor.fB;
221 colorBase.fA = kAlpha;
222
223 const SkColor color = colorBase.toSkColor();
224
ramindanic6e522e2024-05-07 16:42:51 -0700225 auto buffers = draw(refreshIntFps, renderIntFps, color, transformHint, mFeatures);
Ady Abraham0aa373a2022-11-22 13:56:50 -0800226 it = mBufferCache
ramindanic6e522e2024-05-07 16:42:51 -0700227 .try_emplace({refreshIntFps, renderIntFps, transformHint}, std::move(buffers))
Ady Abraham0aa373a2022-11-22 13:56:50 -0800228 .first;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800229 }
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100230
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700231 return it->second;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800232}
233
Dominik Laskowski20134642020-04-20 22:36:44 -0700234void RefreshRateOverlay::setViewport(ui::Size viewport) {
Ady Abrahamcba8d6c2021-06-03 18:05:04 -0700235 constexpr int32_t kMaxWidth = 1000;
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700236 const auto width = std::min({kMaxWidth, viewport.width, viewport.height});
Ady Abrahamcba8d6c2021-06-03 18:05:04 -0700237 const auto height = 2 * width;
Ady Abraham0aa373a2022-11-22 13:56:50 -0800238 Rect frame((5 * width) >> 4, height >> 5);
Yifei Zhangcfb7bb32023-01-12 16:17:14 -0800239
240 if (!mFeatures.test(Features::ShowInMiddle)) {
241 frame.offsetBy(width >> 5, height >> 4);
242 } else {
243 frame.offsetBy(width >> 1, height >> 4);
244 }
Ady Abraham2cb8b622019-12-02 18:55:33 -0800245
ramindanib2158ee2023-02-13 20:29:59 -0800246 createTransaction()
Ady Abraham3649ea82022-07-08 16:04:02 -0700247 .setMatrix(mSurfaceControl->get(), frame.getWidth() / static_cast<float>(kBufferWidth),
248 0, 0, frame.getHeight() / static_cast<float>(kBufferHeight))
249 .setPosition(mSurfaceControl->get(), frame.left, frame.top)
Dominik Laskowski1f6fc702022-03-21 08:34:50 -0700250 .apply();
Ady Abraham03b02dd2019-03-21 15:40:11 -0700251}
252
Dominik Laskowski29fa1462021-04-27 15:51:50 -0700253void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
ramindanib2158ee2023-02-13 20:29:59 -0800254 createTransaction().setLayerStack(mSurfaceControl->get(), stack).apply();
Ady Abraham1b11bc62021-06-03 19:51:19 -0700255}
256
Ying Wei22d59cc2024-05-11 02:41:08 +0000257void RefreshRateOverlay::changeRefreshRate(Fps refreshRate, Fps renderFps) {
258 mRefreshRate = refreshRate;
Ady Abraham0aa373a2022-11-22 13:56:50 -0800259 mRenderFps = renderFps;
Ying Wei22d59cc2024-05-11 02:41:08 +0000260 const auto buffer = getOrCreateBuffers(refreshRate, renderFps)[mFrame];
ramindanib2158ee2023-02-13 20:29:59 -0800261 createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
Ady Abraham29d0da32020-07-16 18:39:33 -0700262}
263
ramindani3faf5742023-09-21 13:45:12 -0700264void RefreshRateOverlay::changeRenderRate(Fps renderFps) {
Ying Wei22d59cc2024-05-11 02:41:08 +0000265 if (mFeatures.test(Features::RenderRate) && mRefreshRate &&
266 FlagManager::getInstance().misc1()) {
ramindani3faf5742023-09-21 13:45:12 -0700267 mRenderFps = renderFps;
Ying Wei22d59cc2024-05-11 02:41:08 +0000268 const auto buffer = getOrCreateBuffers(*mRefreshRate, renderFps)[mFrame];
ramindani3faf5742023-09-21 13:45:12 -0700269 createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
270 }
271}
272
Dominik Laskowskie0e0cde2021-07-30 10:42:05 -0700273void RefreshRateOverlay::animate() {
Ying Wei22d59cc2024-05-11 02:41:08 +0000274 if (!mFeatures.test(Features::Spinner) || !mRefreshRate) return;
Ady Abraham29d0da32020-07-16 18:39:33 -0700275
Ying Wei22d59cc2024-05-11 02:41:08 +0000276 const auto& buffers = getOrCreateBuffers(*mRefreshRate, *mRenderFps);
Ady Abraham29d0da32020-07-16 18:39:33 -0700277 mFrame = (mFrame + 1) % buffers.size();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700278 const auto buffer = buffers[mFrame];
ramindanib2158ee2023-02-13 20:29:59 -0800279 createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
280}
281
282SurfaceComposerClient::Transaction RefreshRateOverlay::createTransaction() const {
283 constexpr float kFrameRate = 0.f;
284 constexpr int8_t kCompatibility = ANATIVEWINDOW_FRAME_RATE_NO_VOTE;
285 constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
286
287 const sp<SurfaceControl>& surface = mSurfaceControl->get();
288
289 SurfaceComposerClient::Transaction transaction;
290 if (isSetByHwc()) {
291 transaction.setFlags(surface, layer_state_t::eLayerIsRefreshRateIndicator,
292 layer_state_t::eLayerIsRefreshRateIndicator);
ramindania3816ab2023-04-25 18:41:16 -0700293 // Disable overlay layer caching when refresh rate is updated by the HWC.
294 transaction.setCachingHint(surface, gui::CachingHint::Disabled);
ramindanib2158ee2023-02-13 20:29:59 -0800295 }
296 transaction.setFrameRate(surface, kFrameRate, kCompatibility, kSeamlessness);
297 return transaction;
Dominik Laskowski20134642020-04-20 22:36:44 -0700298}
299
300} // namespace android