blob: e918dc9045d8a28ccbc8c80afc7b5096136dc158 [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
Ady Abraham03b02dd2019-03-21 15:40:11 -070019#include "Client.h"
20#include "Layer.h"
Ady Abraham3649ea82022-07-08 16:04:02 -070021#include "RefreshRateOverlay.h"
Ady Abraham03b02dd2019-03-21 15:40:11 -070022
rnlee756005b2021-05-27 10:46:36 -070023#include <SkSurface.h>
Ady Abraham2cb8b622019-12-02 18:55:33 -080024
25#undef LOG_TAG
26#define LOG_TAG "RefreshRateOverlay"
27
Ady Abraham03b02dd2019-03-21 15:40:11 -070028namespace android {
29
ramindania04b8a52023-08-07 18:49:47 -070030auto RefreshRateOverlay::draw(int vsyncRate, int renderFps, SkColor color,
Sally Qi147581b2023-06-27 11:55:34 -070031 ui::Transform::RotationFlags rotation, ftl::Flags<Features> features)
32 -> Buffers {
Ady Abraham0aa373a2022-11-22 13:56:50 -080033 const size_t loopCount = features.test(Features::Spinner) ? 6 : 1;
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070034
35 Buffers buffers;
36 buffers.reserve(loopCount);
37
38 for (size_t i = 0; i < loopCount; i++) {
rnlee756005b2021-05-27 10:46:36 -070039 // Pre-rotate the buffer before it reaches SurfaceFlinger.
40 SkMatrix canvasTransform = SkMatrix();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070041 const auto [bufferWidth, bufferHeight] = [&]() -> std::pair<int, int> {
rnlee756005b2021-05-27 10:46:36 -070042 switch (rotation) {
43 case ui::Transform::ROT_90:
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070044 canvasTransform.setTranslate(kBufferHeight, 0);
45 canvasTransform.preRotate(90.f);
46 return {kBufferHeight, kBufferWidth};
rnlee756005b2021-05-27 10:46:36 -070047 case ui::Transform::ROT_270:
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070048 canvasTransform.setRotate(270.f, kBufferWidth / 2.f, kBufferWidth / 2.f);
49 return {kBufferHeight, kBufferWidth};
rnlee756005b2021-05-27 10:46:36 -070050 default:
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070051 return {kBufferWidth, kBufferHeight};
rnlee756005b2021-05-27 10:46:36 -070052 }
53 }();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070054
Ady Abrahamd11bade2022-08-01 16:18:03 -070055 const auto kUsageFlags =
56 static_cast<uint64_t>(GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
57 GRALLOC_USAGE_HW_TEXTURE);
58 sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth),
59 static_cast<uint32_t>(bufferHeight),
60 HAL_PIXEL_FORMAT_RGBA_8888, 1u,
61 kUsageFlags, "RefreshRateOverlayBuffer");
Dominik Laskowski8c4356c2022-03-21 08:19:54 -070062
Alec Mouri7013b6f2021-02-12 11:16:54 -080063 const status_t bufferStatus = buffer->initCheck();
64 LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
65 bufferStatus);
rnlee756005b2021-05-27 10:46:36 -070066
Kevin Lubick00bec722023-05-12 19:26:03 +000067 sk_sp<SkSurface> surface = SkSurfaces::Raster(
68 SkImageInfo::MakeN32Premul(bufferWidth, bufferHeight));
rnlee756005b2021-05-27 10:46:36 -070069 SkCanvas* canvas = surface->getCanvas();
70 canvas->setMatrix(canvasTransform);
71
Ady Abraham29d0da32020-07-16 18:39:33 -070072 int left = 0;
ramindania04b8a52023-08-07 18:49:47 -070073 drawNumber(vsyncRate, left, color, *canvas);
Ady Abraham0aa373a2022-11-22 13:56:50 -080074 left += 3 * (kDigitWidth + kDigitSpace);
75 if (features.test(Features::Spinner)) {
Ady Abraham29d0da32020-07-16 18:39:33 -070076 switch (i) {
77 case 0:
Sally Qi147581b2023-06-27 11:55:34 -070078 SegmentDrawer::drawSegment(SegmentDrawer::Segment::Upper, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -070079 break;
80 case 1:
Sally Qi147581b2023-06-27 11:55:34 -070081 SegmentDrawer::drawSegment(SegmentDrawer::Segment::UpperRight, left, color,
82 *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -070083 break;
84 case 2:
Sally Qi147581b2023-06-27 11:55:34 -070085 SegmentDrawer::drawSegment(SegmentDrawer::Segment::LowerRight, left, color,
86 *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -070087 break;
88 case 3:
Sally Qi147581b2023-06-27 11:55:34 -070089 SegmentDrawer::drawSegment(SegmentDrawer::Segment::Bottom, left, color,
90 *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -070091 break;
92 case 4:
Sally Qi147581b2023-06-27 11:55:34 -070093 SegmentDrawer::drawSegment(SegmentDrawer::Segment::LowerLeft, left, color,
94 *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -070095 break;
96 case 5:
Sally Qi147581b2023-06-27 11:55:34 -070097 SegmentDrawer::drawSegment(SegmentDrawer::Segment::UpperLeft, left, color,
98 *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -070099 break;
100 }
101 }
102
Ady Abraham0aa373a2022-11-22 13:56:50 -0800103 left += kDigitWidth + kDigitSpace;
104
105 if (features.test(Features::RenderRate)) {
106 drawNumber(renderFps, left, color, *canvas);
107 }
108 left += 3 * (kDigitWidth + kDigitSpace);
109
rnlee756005b2021-05-27 10:46:36 -0700110 void* pixels = nullptr;
111 buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700112
rnlee756005b2021-05-27 10:46:36 -0700113 const SkImageInfo& imageInfo = surface->imageInfo();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700114 const size_t dstRowBytes =
115 buffer->getStride() * static_cast<size_t>(imageInfo.bytesPerPixel());
116
rnlee756005b2021-05-27 10:46:36 -0700117 canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0);
Ady Abraham29d0da32020-07-16 18:39:33 -0700118 buffer->unlock();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700119 buffers.push_back(std::move(buffer));
Ady Abraham29d0da32020-07-16 18:39:33 -0700120 }
121 return buffers;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800122}
123
Sally Qi147581b2023-06-27 11:55:34 -0700124void RefreshRateOverlay::drawNumber(int number, int left, SkColor color, SkCanvas& canvas) {
Ady Abraham0aa373a2022-11-22 13:56:50 -0800125 if (number < 0 || number >= 1000) return;
126
127 if (number >= 100) {
Sally Qi147581b2023-06-27 11:55:34 -0700128 SegmentDrawer::drawDigit(number / 100, left, color, canvas);
Ady Abraham0aa373a2022-11-22 13:56:50 -0800129 }
130 left += kDigitWidth + kDigitSpace;
131
132 if (number >= 10) {
Sally Qi147581b2023-06-27 11:55:34 -0700133 SegmentDrawer::drawDigit((number / 10) % 10, left, color, canvas);
Ady Abraham0aa373a2022-11-22 13:56:50 -0800134 }
135 left += kDigitWidth + kDigitSpace;
136
Sally Qi147581b2023-06-27 11:55:34 -0700137 SegmentDrawer::drawDigit(number % 10, left, color, canvas);
Ady Abraham3649ea82022-07-08 16:04:02 -0700138}
139
Ady Abraham0aa373a2022-11-22 13:56:50 -0800140RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, ftl::Flags<Features> features)
Sally Qi147581b2023-06-27 11:55:34 -0700141 : mFpsRange(fpsRange),
142 mFeatures(features),
143 mSurfaceControl(
144 SurfaceControlHolder::createSurfaceControlHolder(String8("RefreshRateOverlay"))) {
chaviw70aa7572021-09-22 12:27:57 -0500145 if (!mSurfaceControl) {
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700146 ALOGE("%s: Failed to create buffer state layer", __func__);
147 return;
Ady Abraham03b02dd2019-03-21 15:40:11 -0700148 }
149
ramindanib2158ee2023-02-13 20:29:59 -0800150 createTransaction()
Ady Abraham3649ea82022-07-08 16:04:02 -0700151 .setLayer(mSurfaceControl->get(), INT32_MAX - 2)
152 .setTrustedOverlay(mSurfaceControl->get(), true)
Ady Abraham78c4a242021-11-30 17:49:44 -0800153 .apply();
Ady Abraham03b02dd2019-03-21 15:40:11 -0700154}
155
ramindania04b8a52023-08-07 18:49:47 -0700156auto RefreshRateOverlay::getOrCreateBuffers(Fps vsyncRate, Fps renderFps) -> const Buffers& {
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700157 static const Buffers kNoBuffers;
158 if (!mSurfaceControl) return kNoBuffers;
159
Ady Abraham0aa373a2022-11-22 13:56:50 -0800160 // avoid caching different render rates if RenderRate is anyway not visible
161 if (!mFeatures.test(Features::RenderRate)) {
162 renderFps = 0_Hz;
163 }
164
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700165 const auto transformHint =
Ady Abraham3649ea82022-07-08 16:04:02 -0700166 static_cast<ui::Transform::RotationFlags>(mSurfaceControl->get()->getTransformHint());
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700167
rnlee756005b2021-05-27 10:46:36 -0700168 // Tell SurfaceFlinger about the pre-rotation on the buffer.
169 const auto transform = [&] {
170 switch (transformHint) {
171 case ui::Transform::ROT_90:
172 return ui::Transform::ROT_270;
173 case ui::Transform::ROT_270:
174 return ui::Transform::ROT_90;
175 default:
176 return ui::Transform::ROT_0;
177 }
178 }();
chaviw70aa7572021-09-22 12:27:57 -0500179
ramindanib2158ee2023-02-13 20:29:59 -0800180 createTransaction().setTransform(mSurfaceControl->get(), transform).apply();
rnlee756005b2021-05-27 10:46:36 -0700181
Ady Abraham0aa373a2022-11-22 13:56:50 -0800182 BufferCache::const_iterator it =
ramindania04b8a52023-08-07 18:49:47 -0700183 mBufferCache.find({vsyncRate.getIntValue(), renderFps.getIntValue(), transformHint});
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700184 if (it == mBufferCache.end()) {
ramindanib2158ee2023-02-13 20:29:59 -0800185 // HWC minFps is not known by the framework in order
186 // to consider lower rates we set minFps to 0.
187 const int minFps = isSetByHwc() ? 0 : mFpsRange.min.getIntValue();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700188 const int maxFps = mFpsRange.max.getIntValue();
189
ramindania04b8a52023-08-07 18:49:47 -0700190 // Clamp to the range. The current vsyncRate may be outside of this range if the display
Ady Abraham0aa373a2022-11-22 13:56:50 -0800191 // has changed its set of supported refresh rates.
ramindania04b8a52023-08-07 18:49:47 -0700192 const int displayIntFps = std::clamp(vsyncRate.getIntValue(), minFps, maxFps);
Ady Abraham0aa373a2022-11-22 13:56:50 -0800193 const int renderIntFps = renderFps.getIntValue();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700194
195 // Ensure non-zero range to avoid division by zero.
Ady Abraham0aa373a2022-11-22 13:56:50 -0800196 const float fpsScale =
197 static_cast<float>(displayIntFps - minFps) / std::max(1, maxFps - minFps);
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700198
199 constexpr SkColor kMinFpsColor = SK_ColorRED;
200 constexpr SkColor kMaxFpsColor = SK_ColorGREEN;
201 constexpr float kAlpha = 0.8f;
202
203 SkColor4f colorBase = SkColor4f::FromColor(kMaxFpsColor) * fpsScale;
204 const SkColor4f minFpsColor = SkColor4f::FromColor(kMinFpsColor) * (1 - fpsScale);
205
206 colorBase.fR = colorBase.fR + minFpsColor.fR;
207 colorBase.fG = colorBase.fG + minFpsColor.fG;
208 colorBase.fB = colorBase.fB + minFpsColor.fB;
209 colorBase.fA = kAlpha;
210
211 const SkColor color = colorBase.toSkColor();
212
Sally Qi147581b2023-06-27 11:55:34 -0700213 auto buffers = draw(displayIntFps, renderIntFps, color, transformHint, mFeatures);
Ady Abraham0aa373a2022-11-22 13:56:50 -0800214 it = mBufferCache
215 .try_emplace({displayIntFps, renderIntFps, transformHint}, std::move(buffers))
216 .first;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800217 }
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100218
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700219 return it->second;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800220}
221
Dominik Laskowski20134642020-04-20 22:36:44 -0700222void RefreshRateOverlay::setViewport(ui::Size viewport) {
Ady Abrahamcba8d6c2021-06-03 18:05:04 -0700223 constexpr int32_t kMaxWidth = 1000;
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700224 const auto width = std::min({kMaxWidth, viewport.width, viewport.height});
Ady Abrahamcba8d6c2021-06-03 18:05:04 -0700225 const auto height = 2 * width;
Ady Abraham0aa373a2022-11-22 13:56:50 -0800226 Rect frame((5 * width) >> 4, height >> 5);
Yifei Zhangcfb7bb32023-01-12 16:17:14 -0800227
228 if (!mFeatures.test(Features::ShowInMiddle)) {
229 frame.offsetBy(width >> 5, height >> 4);
230 } else {
231 frame.offsetBy(width >> 1, height >> 4);
232 }
Ady Abraham2cb8b622019-12-02 18:55:33 -0800233
ramindanib2158ee2023-02-13 20:29:59 -0800234 createTransaction()
Ady Abraham3649ea82022-07-08 16:04:02 -0700235 .setMatrix(mSurfaceControl->get(), frame.getWidth() / static_cast<float>(kBufferWidth),
236 0, 0, frame.getHeight() / static_cast<float>(kBufferHeight))
237 .setPosition(mSurfaceControl->get(), frame.left, frame.top)
Dominik Laskowski1f6fc702022-03-21 08:34:50 -0700238 .apply();
Ady Abraham03b02dd2019-03-21 15:40:11 -0700239}
240
Dominik Laskowski29fa1462021-04-27 15:51:50 -0700241void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
ramindanib2158ee2023-02-13 20:29:59 -0800242 createTransaction().setLayerStack(mSurfaceControl->get(), stack).apply();
Ady Abraham1b11bc62021-06-03 19:51:19 -0700243}
244
ramindania04b8a52023-08-07 18:49:47 -0700245void RefreshRateOverlay::changeRefreshRate(Fps vsyncRate, Fps renderFps) {
246 mVsyncRate = vsyncRate;
Ady Abraham0aa373a2022-11-22 13:56:50 -0800247 mRenderFps = renderFps;
ramindania04b8a52023-08-07 18:49:47 -0700248 const auto buffer = getOrCreateBuffers(vsyncRate, renderFps)[mFrame];
ramindanib2158ee2023-02-13 20:29:59 -0800249 createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
Ady Abraham29d0da32020-07-16 18:39:33 -0700250}
251
Dominik Laskowskie0e0cde2021-07-30 10:42:05 -0700252void RefreshRateOverlay::animate() {
ramindania04b8a52023-08-07 18:49:47 -0700253 if (!mFeatures.test(Features::Spinner) || !mVsyncRate) return;
Ady Abraham29d0da32020-07-16 18:39:33 -0700254
ramindania04b8a52023-08-07 18:49:47 -0700255 const auto& buffers = getOrCreateBuffers(*mVsyncRate, *mRenderFps);
Ady Abraham29d0da32020-07-16 18:39:33 -0700256 mFrame = (mFrame + 1) % buffers.size();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700257 const auto buffer = buffers[mFrame];
ramindanib2158ee2023-02-13 20:29:59 -0800258 createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
259}
260
261SurfaceComposerClient::Transaction RefreshRateOverlay::createTransaction() const {
262 constexpr float kFrameRate = 0.f;
263 constexpr int8_t kCompatibility = ANATIVEWINDOW_FRAME_RATE_NO_VOTE;
264 constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
265
266 const sp<SurfaceControl>& surface = mSurfaceControl->get();
267
268 SurfaceComposerClient::Transaction transaction;
269 if (isSetByHwc()) {
270 transaction.setFlags(surface, layer_state_t::eLayerIsRefreshRateIndicator,
271 layer_state_t::eLayerIsRefreshRateIndicator);
ramindania3816ab2023-04-25 18:41:16 -0700272 // Disable overlay layer caching when refresh rate is updated by the HWC.
273 transaction.setCachingHint(surface, gui::CachingHint::Disabled);
ramindanib2158ee2023-02-13 20:29:59 -0800274 }
275 transaction.setFrameRate(surface, kFrameRate, kCompatibility, kSeamlessness);
276 return transaction;
Dominik Laskowski20134642020-04-20 22:36:44 -0700277}
278
279} // namespace android