blob: 81c1566d7142b0f8c4ef1962af5c3ebb974f1b22 [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
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -080017// TODO(b/129481165): remove the #pragma below and fix conversion issues
18#pragma clang diagnostic push
19#pragma clang diagnostic ignored "-Wconversion"
Marin Shalamanovbed7fd32020-12-21 20:02:20 +010020#pragma clang diagnostic ignored "-Wextra"
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -080021
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +010022#include <algorithm>
23
Ady Abraham03b02dd2019-03-21 15:40:11 -070024#include "RefreshRateOverlay.h"
25#include "Client.h"
26#include "Layer.h"
27
rnlee756005b2021-05-27 10:46:36 -070028#include <SkBlendMode.h>
29#include <SkPaint.h>
30#include <SkRect.h>
31#include <SkSurface.h>
Ady Abraham2cb8b622019-12-02 18:55:33 -080032#include <gui/IProducerListener.h>
chaviw70aa7572021-09-22 12:27:57 -050033#include <gui/SurfaceComposerClient.h>
34#include <gui/SurfaceControl.h>
Ady Abraham2cb8b622019-12-02 18:55:33 -080035
36#undef LOG_TAG
37#define LOG_TAG "RefreshRateOverlay"
38
Ady Abraham03b02dd2019-03-21 15:40:11 -070039namespace android {
40
rnlee756005b2021-05-27 10:46:36 -070041void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor& color,
42 SkCanvas& canvas) {
43 const SkRect rect = [&]() {
Ady Abraham2cb8b622019-12-02 18:55:33 -080044 switch (segment) {
45 case Segment::Upper:
rnlee756005b2021-05-27 10:46:36 -070046 return SkRect::MakeLTRB(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
Ady Abraham2cb8b622019-12-02 18:55:33 -080047 case Segment::UpperLeft:
rnlee756005b2021-05-27 10:46:36 -070048 return SkRect::MakeLTRB(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
Ady Abraham2cb8b622019-12-02 18:55:33 -080049 case Segment::UpperRight:
rnlee756005b2021-05-27 10:46:36 -070050 return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
51 DIGIT_HEIGHT / 2);
Ady Abraham2cb8b622019-12-02 18:55:33 -080052 case Segment::Middle:
rnlee756005b2021-05-27 10:46:36 -070053 return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2,
54 left + DIGIT_WIDTH, DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
Ady Abraham2cb8b622019-12-02 18:55:33 -080055 case Segment::LowerLeft:
rnlee756005b2021-05-27 10:46:36 -070056 return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
Ady Abraham2cb8b622019-12-02 18:55:33 -080057 case Segment::LowerRight:
rnlee756005b2021-05-27 10:46:36 -070058 return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2,
59 left + DIGIT_WIDTH, DIGIT_HEIGHT);
60 case Segment::Bottom:
61 return SkRect::MakeLTRB(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH,
62 DIGIT_HEIGHT);
Ady Abraham2cb8b622019-12-02 18:55:33 -080063 }
64 }();
65
rnlee756005b2021-05-27 10:46:36 -070066 SkPaint paint;
67 paint.setColor(color);
68 paint.setBlendMode(SkBlendMode::kSrc);
69 canvas.drawRect(rect, paint);
Ady Abraham2cb8b622019-12-02 18:55:33 -080070}
71
rnlee756005b2021-05-27 10:46:36 -070072void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor& color,
73 SkCanvas& canvas) {
Ady Abraham2cb8b622019-12-02 18:55:33 -080074 if (digit < 0 || digit > 9) return;
75
76 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
77 digit == 8 || digit == 9)
rnlee756005b2021-05-27 10:46:36 -070078 drawSegment(Segment::Upper, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080079 if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
rnlee756005b2021-05-27 10:46:36 -070080 drawSegment(Segment::UpperLeft, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080081 if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
82 digit == 8 || digit == 9)
rnlee756005b2021-05-27 10:46:36 -070083 drawSegment(Segment::UpperRight, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080084 if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
85 digit == 9)
rnlee756005b2021-05-27 10:46:36 -070086 drawSegment(Segment::Middle, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080087 if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
rnlee756005b2021-05-27 10:46:36 -070088 drawSegment(Segment::LowerLeft, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080089 if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
90 digit == 7 || digit == 8 || digit == 9)
rnlee756005b2021-05-27 10:46:36 -070091 drawSegment(Segment::LowerRight, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080092 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
93 digit == 9)
rnlee756005b2021-05-27 10:46:36 -070094 drawSegment(Segment::Bottom, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080095}
96
rnlee756005b2021-05-27 10:46:36 -070097std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::draw(
98 int number, SkColor& color, ui::Transform::RotationFlags rotation, bool showSpinner) {
Ady Abraham29d0da32020-07-16 18:39:33 -070099 if (number < 0 || number > 1000) return {};
Ady Abraham2cb8b622019-12-02 18:55:33 -0800100
101 const auto hundreds = number / 100;
102 const auto tens = (number / 10) % 10;
103 const auto ones = number % 10;
104
Ady Abraham29d0da32020-07-16 18:39:33 -0700105 std::vector<sp<GraphicBuffer>> buffers;
106 const auto loopCount = showSpinner ? 6 : 1;
107 for (int i = 0; i < loopCount; i++) {
rnlee756005b2021-05-27 10:46:36 -0700108 // Pre-rotate the buffer before it reaches SurfaceFlinger.
109 SkMatrix canvasTransform = SkMatrix();
110 auto [bufferWidth, bufferHeight] = [&] {
111 switch (rotation) {
112 case ui::Transform::ROT_90:
113 canvasTransform.setTranslate(BUFFER_HEIGHT, 0);
114 canvasTransform.preRotate(90);
115 return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH);
116 case ui::Transform::ROT_270:
117 canvasTransform.setRotate(270, BUFFER_WIDTH / 2.0, BUFFER_WIDTH / 2.0);
118 return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH);
119 default:
120 return std::make_tuple(BUFFER_WIDTH, BUFFER_HEIGHT);
121 }
122 }();
Ady Abraham29d0da32020-07-16 18:39:33 -0700123 sp<GraphicBuffer> buffer =
rnlee756005b2021-05-27 10:46:36 -0700124 new GraphicBuffer(bufferWidth, bufferHeight, HAL_PIXEL_FORMAT_RGBA_8888, 1,
Ady Abraham29d0da32020-07-16 18:39:33 -0700125 GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
126 GRALLOC_USAGE_HW_TEXTURE,
127 "RefreshRateOverlayBuffer");
Alec Mouri7013b6f2021-02-12 11:16:54 -0800128 const status_t bufferStatus = buffer->initCheck();
129 LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
130 bufferStatus);
rnlee756005b2021-05-27 10:46:36 -0700131
132 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(bufferWidth, bufferHeight);
133 SkCanvas* canvas = surface->getCanvas();
134 canvas->setMatrix(canvasTransform);
135
Ady Abraham29d0da32020-07-16 18:39:33 -0700136 int left = 0;
137 if (hundreds != 0) {
rnlee756005b2021-05-27 10:46:36 -0700138 drawDigit(hundreds, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700139 }
Ady Abraham2cb8b622019-12-02 18:55:33 -0800140 left += DIGIT_WIDTH + DIGIT_SPACE;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800141
Ady Abraham29d0da32020-07-16 18:39:33 -0700142 if (tens != 0) {
rnlee756005b2021-05-27 10:46:36 -0700143 drawDigit(tens, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700144 }
Ady Abraham2cb8b622019-12-02 18:55:33 -0800145 left += DIGIT_WIDTH + DIGIT_SPACE;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800146
rnlee756005b2021-05-27 10:46:36 -0700147 drawDigit(ones, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700148 left += DIGIT_WIDTH + DIGIT_SPACE;
149
150 if (showSpinner) {
151 switch (i) {
152 case 0:
rnlee756005b2021-05-27 10:46:36 -0700153 drawSegment(Segment::Upper, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700154 break;
155 case 1:
rnlee756005b2021-05-27 10:46:36 -0700156 drawSegment(Segment::UpperRight, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700157 break;
158 case 2:
rnlee756005b2021-05-27 10:46:36 -0700159 drawSegment(Segment::LowerRight, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700160 break;
161 case 3:
rnlee756005b2021-05-27 10:46:36 -0700162 drawSegment(Segment::Bottom, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700163 break;
164 case 4:
rnlee756005b2021-05-27 10:46:36 -0700165 drawSegment(Segment::LowerLeft, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700166 break;
167 case 5:
rnlee756005b2021-05-27 10:46:36 -0700168 drawSegment(Segment::UpperLeft, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700169 break;
170 }
171 }
172
rnlee756005b2021-05-27 10:46:36 -0700173 void* pixels = nullptr;
174 buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
175 const SkImageInfo& imageInfo = surface->imageInfo();
176 size_t dstRowBytes = buffer->getStride() * imageInfo.bytesPerPixel();
177 canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0);
Ady Abraham29d0da32020-07-16 18:39:33 -0700178 buffer->unlock();
179 buffers.emplace_back(buffer);
180 }
181 return buffers;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800182}
183
Ady Abraham1b11bc62021-06-03 19:51:19 -0700184RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, uint32_t lowFps, uint32_t highFps,
185 bool showSpinner)
186 : mFlinger(flinger),
187 mClient(new Client(&mFlinger)),
188 mShowSpinner(showSpinner),
189 mLowFps(lowFps),
190 mHighFps(highFps) {
Ady Abraham03b02dd2019-03-21 15:40:11 -0700191 createLayer();
192}
193
194bool RefreshRateOverlay::createLayer() {
chaviw70aa7572021-09-22 12:27:57 -0500195 mSurfaceControl =
196 SurfaceComposerClient::getDefault()
197 ->createSurface(String8("RefreshRateOverlay"), SevenSegmentDrawer::getWidth(),
198 SevenSegmentDrawer::getHeight(), PIXEL_FORMAT_RGBA_8888,
199 ISurfaceComposerClient::eFXSurfaceBufferState);
200
201 if (!mSurfaceControl) {
Ady Abraham2cb8b622019-12-02 18:55:33 -0800202 ALOGE("failed to create buffer state layer");
Ady Abraham03b02dd2019-03-21 15:40:11 -0700203 return false;
204 }
205
Ady Abraham78c4a242021-11-30 17:49:44 -0800206 SurfaceComposerClient::Transaction()
207 .setFrameRate(mSurfaceControl, 0.0f,
208 static_cast<int8_t>(Layer::FrameRateCompatibility::NoVote),
209 static_cast<int8_t>(scheduler::Seamlessness::OnlySeamless))
210 .setLayer(mSurfaceControl, INT32_MAX - 2)
211 .setTrustedOverlay(mSurfaceControl, true)
212 .apply();
Ady Abraham03b02dd2019-03-21 15:40:11 -0700213
214 return true;
215}
216
chaviw70aa7572021-09-22 12:27:57 -0500217const std::vector<sp<GraphicBuffer>>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
218 ui::Transform::RotationFlags transformHint =
219 static_cast<ui::Transform::RotationFlags>(mSurfaceControl->getTransformHint());
rnlee756005b2021-05-27 10:46:36 -0700220 // Tell SurfaceFlinger about the pre-rotation on the buffer.
221 const auto transform = [&] {
222 switch (transformHint) {
223 case ui::Transform::ROT_90:
224 return ui::Transform::ROT_270;
225 case ui::Transform::ROT_270:
226 return ui::Transform::ROT_90;
227 default:
228 return ui::Transform::ROT_0;
229 }
230 }();
chaviw70aa7572021-09-22 12:27:57 -0500231
232 SurfaceComposerClient::Transaction t;
233 t.setTransform(mSurfaceControl, transform);
234 t.apply();
rnlee756005b2021-05-27 10:46:36 -0700235
236 if (mBufferCache.find(transformHint) == mBufferCache.end() ||
237 mBufferCache.at(transformHint).find(fps) == mBufferCache.at(transformHint).end()) {
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100238 // Ensure the range is > 0, so we don't divide by 0.
239 const auto rangeLength = std::max(1u, mHighFps - mLowFps);
240 // Clip values outside the range [mLowFps, mHighFps]. The current fps may be outside
241 // of this range if the display has changed its set of supported refresh rates.
242 fps = std::max(fps, mLowFps);
243 fps = std::min(fps, mHighFps);
244 const auto fpsScale = static_cast<float>(fps - mLowFps) / rangeLength;
rnlee756005b2021-05-27 10:46:36 -0700245 SkColor4f colorBase = SkColor4f::FromColor(HIGH_FPS_COLOR) * fpsScale;
246 SkColor4f lowFpsColor = SkColor4f::FromColor(LOW_FPS_COLOR) * (1 - fpsScale);
247 colorBase.fR = colorBase.fR + lowFpsColor.fR;
248 colorBase.fG = colorBase.fG + lowFpsColor.fG;
249 colorBase.fB = colorBase.fB + lowFpsColor.fB;
250 colorBase.fA = ALPHA;
251 SkColor color = colorBase.toSkColor();
252 auto buffers = SevenSegmentDrawer::draw(fps, color, transformHint, mShowSpinner);
chaviw70aa7572021-09-22 12:27:57 -0500253 mBufferCache[transformHint].emplace(fps, buffers);
Ady Abraham2cb8b622019-12-02 18:55:33 -0800254 }
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100255
rnlee756005b2021-05-27 10:46:36 -0700256 return mBufferCache[transformHint][fps];
Ady Abraham2cb8b622019-12-02 18:55:33 -0800257}
258
Dominik Laskowski20134642020-04-20 22:36:44 -0700259void RefreshRateOverlay::setViewport(ui::Size viewport) {
Ady Abrahamcba8d6c2021-06-03 18:05:04 -0700260 constexpr int32_t kMaxWidth = 1000;
261 const auto width = std::min(kMaxWidth, std::min(viewport.width, viewport.height));
262 const auto height = 2 * width;
263 Rect frame((3 * width) >> 4, height >> 5);
264 frame.offsetBy(width >> 5, height >> 4);
Ady Abraham2cb8b622019-12-02 18:55:33 -0800265
chaviw70aa7572021-09-22 12:27:57 -0500266 SurfaceComposerClient::Transaction t;
267 t.setMatrix(mSurfaceControl,
268 frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth()), 0, 0,
269 frame.getHeight() / static_cast<float>(SevenSegmentDrawer::getHeight()));
270 t.setPosition(mSurfaceControl, frame.left, frame.top);
271 t.apply();
Ady Abraham03b02dd2019-03-21 15:40:11 -0700272}
273
Dominik Laskowski29fa1462021-04-27 15:51:50 -0700274void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
chaviw70aa7572021-09-22 12:27:57 -0500275 SurfaceComposerClient::Transaction t;
276 t.setLayerStack(mSurfaceControl, stack);
277 t.apply();
Ady Abraham1b11bc62021-06-03 19:51:19 -0700278}
279
Dominik Laskowskif6b4ba62021-11-09 12:46:10 -0800280void RefreshRateOverlay::changeRefreshRate(Fps fps) {
Marin Shalamanoveadf2e72020-12-10 15:35:28 +0100281 mCurrentFps = fps.getIntValue();
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100282 auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
chaviw70aa7572021-09-22 12:27:57 -0500283 SurfaceComposerClient::Transaction t;
284 t.setBuffer(mSurfaceControl, buffer);
285 t.apply();
Ady Abraham29d0da32020-07-16 18:39:33 -0700286}
287
Dominik Laskowskie0e0cde2021-07-30 10:42:05 -0700288void RefreshRateOverlay::animate() {
Ady Abraham29d0da32020-07-16 18:39:33 -0700289 if (!mCurrentFps.has_value()) return;
290
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100291 const auto& buffers = getOrCreateBuffers(*mCurrentFps);
Ady Abraham29d0da32020-07-16 18:39:33 -0700292 mFrame = (mFrame + 1) % buffers.size();
293 auto buffer = buffers[mFrame];
chaviw70aa7572021-09-22 12:27:57 -0500294 SurfaceComposerClient::Transaction t;
295 t.setBuffer(mSurfaceControl, buffer);
296 t.apply();
Dominik Laskowski20134642020-04-20 22:36:44 -0700297}
298
299} // namespace android
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -0800300
301// TODO(b/129481165): remove the #pragma below and fix conversion issues
Marin Shalamanovbed7fd32020-12-21 20:02:20 +0100302#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"