blob: be04c09fa343360dcea23df0d998e2b5e5c678f2 [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"
ramindani3faf5742023-09-21 13:45:12 -070022#include "Utils/FlagUtils.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
ramindania04b8a52023-08-07 18:49:47 -070031auto RefreshRateOverlay::draw(int vsyncRate, 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;
ramindania04b8a52023-08-07 18:49:47 -070074 drawNumber(vsyncRate, 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 Abraham0aa373a2022-11-22 13:56:50 -0800141RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, ftl::Flags<Features> features)
Sally Qi147581b2023-06-27 11:55:34 -0700142 : mFpsRange(fpsRange),
143 mFeatures(features),
144 mSurfaceControl(
145 SurfaceControlHolder::createSurfaceControlHolder(String8("RefreshRateOverlay"))) {
chaviw70aa7572021-09-22 12:27:57 -0500146 if (!mSurfaceControl) {
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700147 ALOGE("%s: Failed to create buffer state layer", __func__);
148 return;
Ady Abraham03b02dd2019-03-21 15:40:11 -0700149 }
150
ramindanib2158ee2023-02-13 20:29:59 -0800151 createTransaction()
Ady Abraham3649ea82022-07-08 16:04:02 -0700152 .setLayer(mSurfaceControl->get(), INT32_MAX - 2)
153 .setTrustedOverlay(mSurfaceControl->get(), true)
Ady Abraham78c4a242021-11-30 17:49:44 -0800154 .apply();
Ady Abraham03b02dd2019-03-21 15:40:11 -0700155}
156
ramindania04b8a52023-08-07 18:49:47 -0700157auto RefreshRateOverlay::getOrCreateBuffers(Fps vsyncRate, Fps renderFps) -> const Buffers& {
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700158 static const Buffers kNoBuffers;
159 if (!mSurfaceControl) return kNoBuffers;
160
Ady Abraham0aa373a2022-11-22 13:56:50 -0800161 // avoid caching different render rates if RenderRate is anyway not visible
162 if (!mFeatures.test(Features::RenderRate)) {
163 renderFps = 0_Hz;
164 }
165
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700166 const auto transformHint =
Ady Abraham3649ea82022-07-08 16:04:02 -0700167 static_cast<ui::Transform::RotationFlags>(mSurfaceControl->get()->getTransformHint());
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700168
rnlee756005b2021-05-27 10:46:36 -0700169 // Tell SurfaceFlinger about the pre-rotation on the buffer.
170 const auto transform = [&] {
171 switch (transformHint) {
172 case ui::Transform::ROT_90:
173 return ui::Transform::ROT_270;
174 case ui::Transform::ROT_270:
175 return ui::Transform::ROT_90;
176 default:
177 return ui::Transform::ROT_0;
178 }
179 }();
chaviw70aa7572021-09-22 12:27:57 -0500180
ramindanib2158ee2023-02-13 20:29:59 -0800181 createTransaction().setTransform(mSurfaceControl->get(), transform).apply();
rnlee756005b2021-05-27 10:46:36 -0700182
Ady Abraham0aa373a2022-11-22 13:56:50 -0800183 BufferCache::const_iterator it =
ramindania04b8a52023-08-07 18:49:47 -0700184 mBufferCache.find({vsyncRate.getIntValue(), renderFps.getIntValue(), transformHint});
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700185 if (it == mBufferCache.end()) {
ramindanib2158ee2023-02-13 20:29:59 -0800186 // HWC minFps is not known by the framework in order
187 // to consider lower rates we set minFps to 0.
188 const int minFps = isSetByHwc() ? 0 : mFpsRange.min.getIntValue();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700189 const int maxFps = mFpsRange.max.getIntValue();
190
ramindania04b8a52023-08-07 18:49:47 -0700191 // Clamp to the range. The current vsyncRate may be outside of this range if the display
Ady Abraham0aa373a2022-11-22 13:56:50 -0800192 // has changed its set of supported refresh rates.
ramindania04b8a52023-08-07 18:49:47 -0700193 const int displayIntFps = std::clamp(vsyncRate.getIntValue(), minFps, maxFps);
Ady Abraham0aa373a2022-11-22 13:56:50 -0800194 const int renderIntFps = renderFps.getIntValue();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700195
196 // Ensure non-zero range to avoid division by zero.
Ady Abraham0aa373a2022-11-22 13:56:50 -0800197 const float fpsScale =
198 static_cast<float>(displayIntFps - minFps) / std::max(1, maxFps - minFps);
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700199
200 constexpr SkColor kMinFpsColor = SK_ColorRED;
201 constexpr SkColor kMaxFpsColor = SK_ColorGREEN;
202 constexpr float kAlpha = 0.8f;
203
204 SkColor4f colorBase = SkColor4f::FromColor(kMaxFpsColor) * fpsScale;
205 const SkColor4f minFpsColor = SkColor4f::FromColor(kMinFpsColor) * (1 - fpsScale);
206
207 colorBase.fR = colorBase.fR + minFpsColor.fR;
208 colorBase.fG = colorBase.fG + minFpsColor.fG;
209 colorBase.fB = colorBase.fB + minFpsColor.fB;
210 colorBase.fA = kAlpha;
211
212 const SkColor color = colorBase.toSkColor();
213
Sally Qi147581b2023-06-27 11:55:34 -0700214 auto buffers = draw(displayIntFps, renderIntFps, color, transformHint, mFeatures);
Ady Abraham0aa373a2022-11-22 13:56:50 -0800215 it = mBufferCache
216 .try_emplace({displayIntFps, renderIntFps, transformHint}, std::move(buffers))
217 .first;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800218 }
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100219
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700220 return it->second;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800221}
222
Dominik Laskowski20134642020-04-20 22:36:44 -0700223void RefreshRateOverlay::setViewport(ui::Size viewport) {
Ady Abrahamcba8d6c2021-06-03 18:05:04 -0700224 constexpr int32_t kMaxWidth = 1000;
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700225 const auto width = std::min({kMaxWidth, viewport.width, viewport.height});
Ady Abrahamcba8d6c2021-06-03 18:05:04 -0700226 const auto height = 2 * width;
Ady Abraham0aa373a2022-11-22 13:56:50 -0800227 Rect frame((5 * width) >> 4, height >> 5);
Yifei Zhangcfb7bb32023-01-12 16:17:14 -0800228
229 if (!mFeatures.test(Features::ShowInMiddle)) {
230 frame.offsetBy(width >> 5, height >> 4);
231 } else {
232 frame.offsetBy(width >> 1, height >> 4);
233 }
Ady Abraham2cb8b622019-12-02 18:55:33 -0800234
ramindanib2158ee2023-02-13 20:29:59 -0800235 createTransaction()
Ady Abraham3649ea82022-07-08 16:04:02 -0700236 .setMatrix(mSurfaceControl->get(), frame.getWidth() / static_cast<float>(kBufferWidth),
237 0, 0, frame.getHeight() / static_cast<float>(kBufferHeight))
238 .setPosition(mSurfaceControl->get(), frame.left, frame.top)
Dominik Laskowski1f6fc702022-03-21 08:34:50 -0700239 .apply();
Ady Abraham03b02dd2019-03-21 15:40:11 -0700240}
241
Dominik Laskowski29fa1462021-04-27 15:51:50 -0700242void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
ramindanib2158ee2023-02-13 20:29:59 -0800243 createTransaction().setLayerStack(mSurfaceControl->get(), stack).apply();
Ady Abraham1b11bc62021-06-03 19:51:19 -0700244}
245
ramindania04b8a52023-08-07 18:49:47 -0700246void RefreshRateOverlay::changeRefreshRate(Fps vsyncRate, Fps renderFps) {
247 mVsyncRate = vsyncRate;
Ady Abraham0aa373a2022-11-22 13:56:50 -0800248 mRenderFps = renderFps;
ramindania04b8a52023-08-07 18:49:47 -0700249 const auto buffer = getOrCreateBuffers(vsyncRate, renderFps)[mFrame];
ramindanib2158ee2023-02-13 20:29:59 -0800250 createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
Ady Abraham29d0da32020-07-16 18:39:33 -0700251}
252
ramindani3faf5742023-09-21 13:45:12 -0700253void RefreshRateOverlay::changeRenderRate(Fps renderFps) {
254 if (mFeatures.test(Features::RenderRate) && mVsyncRate && flagutils::vrrConfigEnabled()) {
255 mRenderFps = renderFps;
256 const auto buffer = getOrCreateBuffers(*mVsyncRate, renderFps)[mFrame];
257 createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
258 }
259}
260
Dominik Laskowskie0e0cde2021-07-30 10:42:05 -0700261void RefreshRateOverlay::animate() {
ramindania04b8a52023-08-07 18:49:47 -0700262 if (!mFeatures.test(Features::Spinner) || !mVsyncRate) return;
Ady Abraham29d0da32020-07-16 18:39:33 -0700263
ramindania04b8a52023-08-07 18:49:47 -0700264 const auto& buffers = getOrCreateBuffers(*mVsyncRate, *mRenderFps);
Ady Abraham29d0da32020-07-16 18:39:33 -0700265 mFrame = (mFrame + 1) % buffers.size();
Dominik Laskowski8c4356c2022-03-21 08:19:54 -0700266 const auto buffer = buffers[mFrame];
ramindanib2158ee2023-02-13 20:29:59 -0800267 createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
268}
269
270SurfaceComposerClient::Transaction RefreshRateOverlay::createTransaction() const {
271 constexpr float kFrameRate = 0.f;
272 constexpr int8_t kCompatibility = ANATIVEWINDOW_FRAME_RATE_NO_VOTE;
273 constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
274
275 const sp<SurfaceControl>& surface = mSurfaceControl->get();
276
277 SurfaceComposerClient::Transaction transaction;
278 if (isSetByHwc()) {
279 transaction.setFlags(surface, layer_state_t::eLayerIsRefreshRateIndicator,
280 layer_state_t::eLayerIsRefreshRateIndicator);
ramindania3816ab2023-04-25 18:41:16 -0700281 // Disable overlay layer caching when refresh rate is updated by the HWC.
282 transaction.setCachingHint(surface, gui::CachingHint::Disabled);
ramindanib2158ee2023-02-13 20:29:59 -0800283 }
284 transaction.setFrameRate(surface, kFrameRate, kCompatibility, kSeamlessness);
285 return transaction;
Dominik Laskowski20134642020-04-20 22:36:44 -0700286}
287
288} // namespace android