blob: 0789e8dcb4b9b09df0bd49431245e273a6bab78c [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>
33
34#undef LOG_TAG
35#define LOG_TAG "RefreshRateOverlay"
36
Ady Abraham03b02dd2019-03-21 15:40:11 -070037namespace android {
38
rnlee756005b2021-05-27 10:46:36 -070039void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor& color,
40 SkCanvas& canvas) {
41 const SkRect rect = [&]() {
Ady Abraham2cb8b622019-12-02 18:55:33 -080042 switch (segment) {
43 case Segment::Upper:
rnlee756005b2021-05-27 10:46:36 -070044 return SkRect::MakeLTRB(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
Ady Abraham2cb8b622019-12-02 18:55:33 -080045 case Segment::UpperLeft:
rnlee756005b2021-05-27 10:46:36 -070046 return SkRect::MakeLTRB(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
Ady Abraham2cb8b622019-12-02 18:55:33 -080047 case Segment::UpperRight:
rnlee756005b2021-05-27 10:46:36 -070048 return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
49 DIGIT_HEIGHT / 2);
Ady Abraham2cb8b622019-12-02 18:55:33 -080050 case Segment::Middle:
rnlee756005b2021-05-27 10:46:36 -070051 return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2,
52 left + DIGIT_WIDTH, DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
Ady Abraham2cb8b622019-12-02 18:55:33 -080053 case Segment::LowerLeft:
rnlee756005b2021-05-27 10:46:36 -070054 return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
Ady Abraham2cb8b622019-12-02 18:55:33 -080055 case Segment::LowerRight:
rnlee756005b2021-05-27 10:46:36 -070056 return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2,
57 left + DIGIT_WIDTH, DIGIT_HEIGHT);
58 case Segment::Bottom:
59 return SkRect::MakeLTRB(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH,
60 DIGIT_HEIGHT);
Ady Abraham2cb8b622019-12-02 18:55:33 -080061 }
62 }();
63
rnlee756005b2021-05-27 10:46:36 -070064 SkPaint paint;
65 paint.setColor(color);
66 paint.setBlendMode(SkBlendMode::kSrc);
67 canvas.drawRect(rect, paint);
Ady Abraham2cb8b622019-12-02 18:55:33 -080068}
69
rnlee756005b2021-05-27 10:46:36 -070070void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor& color,
71 SkCanvas& canvas) {
Ady Abraham2cb8b622019-12-02 18:55:33 -080072 if (digit < 0 || digit > 9) return;
73
74 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
75 digit == 8 || digit == 9)
rnlee756005b2021-05-27 10:46:36 -070076 drawSegment(Segment::Upper, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080077 if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
rnlee756005b2021-05-27 10:46:36 -070078 drawSegment(Segment::UpperLeft, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080079 if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
80 digit == 8 || digit == 9)
rnlee756005b2021-05-27 10:46:36 -070081 drawSegment(Segment::UpperRight, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080082 if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
83 digit == 9)
rnlee756005b2021-05-27 10:46:36 -070084 drawSegment(Segment::Middle, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080085 if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
rnlee756005b2021-05-27 10:46:36 -070086 drawSegment(Segment::LowerLeft, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080087 if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
88 digit == 7 || digit == 8 || digit == 9)
rnlee756005b2021-05-27 10:46:36 -070089 drawSegment(Segment::LowerRight, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080090 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
91 digit == 9)
rnlee756005b2021-05-27 10:46:36 -070092 drawSegment(Segment::Bottom, left, color, canvas);
Ady Abraham2cb8b622019-12-02 18:55:33 -080093}
94
rnlee756005b2021-05-27 10:46:36 -070095std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::draw(
96 int number, SkColor& color, ui::Transform::RotationFlags rotation, bool showSpinner) {
Ady Abraham29d0da32020-07-16 18:39:33 -070097 if (number < 0 || number > 1000) return {};
Ady Abraham2cb8b622019-12-02 18:55:33 -080098
99 const auto hundreds = number / 100;
100 const auto tens = (number / 10) % 10;
101 const auto ones = number % 10;
102
Ady Abraham29d0da32020-07-16 18:39:33 -0700103 std::vector<sp<GraphicBuffer>> buffers;
104 const auto loopCount = showSpinner ? 6 : 1;
105 for (int i = 0; i < loopCount; i++) {
rnlee756005b2021-05-27 10:46:36 -0700106 // Pre-rotate the buffer before it reaches SurfaceFlinger.
107 SkMatrix canvasTransform = SkMatrix();
108 auto [bufferWidth, bufferHeight] = [&] {
109 switch (rotation) {
110 case ui::Transform::ROT_90:
111 canvasTransform.setTranslate(BUFFER_HEIGHT, 0);
112 canvasTransform.preRotate(90);
113 return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH);
114 case ui::Transform::ROT_270:
115 canvasTransform.setRotate(270, BUFFER_WIDTH / 2.0, BUFFER_WIDTH / 2.0);
116 return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH);
117 default:
118 return std::make_tuple(BUFFER_WIDTH, BUFFER_HEIGHT);
119 }
120 }();
Ady Abraham29d0da32020-07-16 18:39:33 -0700121 sp<GraphicBuffer> buffer =
rnlee756005b2021-05-27 10:46:36 -0700122 new GraphicBuffer(bufferWidth, bufferHeight, HAL_PIXEL_FORMAT_RGBA_8888, 1,
Ady Abraham29d0da32020-07-16 18:39:33 -0700123 GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
124 GRALLOC_USAGE_HW_TEXTURE,
125 "RefreshRateOverlayBuffer");
Alec Mouri7013b6f2021-02-12 11:16:54 -0800126 const status_t bufferStatus = buffer->initCheck();
127 LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
128 bufferStatus);
rnlee756005b2021-05-27 10:46:36 -0700129
130 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(bufferWidth, bufferHeight);
131 SkCanvas* canvas = surface->getCanvas();
132 canvas->setMatrix(canvasTransform);
133
Ady Abraham29d0da32020-07-16 18:39:33 -0700134 int left = 0;
135 if (hundreds != 0) {
rnlee756005b2021-05-27 10:46:36 -0700136 drawDigit(hundreds, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700137 }
Ady Abraham2cb8b622019-12-02 18:55:33 -0800138 left += DIGIT_WIDTH + DIGIT_SPACE;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800139
Ady Abraham29d0da32020-07-16 18:39:33 -0700140 if (tens != 0) {
rnlee756005b2021-05-27 10:46:36 -0700141 drawDigit(tens, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700142 }
Ady Abraham2cb8b622019-12-02 18:55:33 -0800143 left += DIGIT_WIDTH + DIGIT_SPACE;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800144
rnlee756005b2021-05-27 10:46:36 -0700145 drawDigit(ones, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700146 left += DIGIT_WIDTH + DIGIT_SPACE;
147
148 if (showSpinner) {
149 switch (i) {
150 case 0:
rnlee756005b2021-05-27 10:46:36 -0700151 drawSegment(Segment::Upper, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700152 break;
153 case 1:
rnlee756005b2021-05-27 10:46:36 -0700154 drawSegment(Segment::UpperRight, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700155 break;
156 case 2:
rnlee756005b2021-05-27 10:46:36 -0700157 drawSegment(Segment::LowerRight, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700158 break;
159 case 3:
rnlee756005b2021-05-27 10:46:36 -0700160 drawSegment(Segment::Bottom, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700161 break;
162 case 4:
rnlee756005b2021-05-27 10:46:36 -0700163 drawSegment(Segment::LowerLeft, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700164 break;
165 case 5:
rnlee756005b2021-05-27 10:46:36 -0700166 drawSegment(Segment::UpperLeft, left, color, *canvas);
Ady Abraham29d0da32020-07-16 18:39:33 -0700167 break;
168 }
169 }
170
rnlee756005b2021-05-27 10:46:36 -0700171 void* pixels = nullptr;
172 buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
173 const SkImageInfo& imageInfo = surface->imageInfo();
174 size_t dstRowBytes = buffer->getStride() * imageInfo.bytesPerPixel();
175 canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0);
Ady Abraham29d0da32020-07-16 18:39:33 -0700176 buffer->unlock();
177 buffers.emplace_back(buffer);
178 }
179 return buffers;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800180}
181
Ady Abraham1b11bc62021-06-03 19:51:19 -0700182RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, uint32_t lowFps, uint32_t highFps,
183 bool showSpinner)
184 : mFlinger(flinger),
185 mClient(new Client(&mFlinger)),
186 mShowSpinner(showSpinner),
187 mLowFps(lowFps),
188 mHighFps(highFps) {
Ady Abraham03b02dd2019-03-21 15:40:11 -0700189 createLayer();
190}
191
192bool RefreshRateOverlay::createLayer() {
Ady Abraham9f0a4002020-10-05 15:47:26 -0700193 int32_t layerId;
Ady Abraham03b02dd2019-03-21 15:40:11 -0700194 const status_t ret =
Ady Abraham2cb8b622019-12-02 18:55:33 -0800195 mFlinger.createLayer(String8("RefreshRateOverlay"), mClient,
196 SevenSegmentDrawer::getWidth(), SevenSegmentDrawer::getHeight(),
197 PIXEL_FORMAT_RGBA_8888,
198 ISurfaceComposerClient::eFXSurfaceBufferState, LayerMetadata(),
Ady Abraham9f0a4002020-10-05 15:47:26 -0700199 &mIBinder, &mGbp, nullptr, &layerId);
Ady Abraham03b02dd2019-03-21 15:40:11 -0700200 if (ret) {
Ady Abraham2cb8b622019-12-02 18:55:33 -0800201 ALOGE("failed to create buffer state layer");
Ady Abraham03b02dd2019-03-21 15:40:11 -0700202 return false;
203 }
204
205 mLayer = mClient->getLayerUser(mIBinder);
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100206 mLayer->setFrameRate(Layer::FrameRate(Fps(0.0f), Layer::FrameRateCompatibility::NoVote));
Vishnu Nair14d218b2021-07-13 13:57:39 -0700207 mLayer->setIsAtRoot(true);
Ady Abrahamfed164b2019-05-10 17:12:54 -0700208
209 // setting Layer's Z requires resorting layersSortedByZ
Robert Carr6a160312021-05-17 12:08:20 -0700210 ssize_t idx = mFlinger.mDrawingState.layersSortedByZ.indexOf(mLayer);
Ady Abrahamfed164b2019-05-10 17:12:54 -0700211 if (mLayer->setLayer(INT32_MAX - 2) && idx >= 0) {
Robert Carr6a160312021-05-17 12:08:20 -0700212 mFlinger.mDrawingState.layersSortedByZ.removeAt(idx);
213 mFlinger.mDrawingState.layersSortedByZ.add(mLayer);
Ady Abrahamfed164b2019-05-10 17:12:54 -0700214 }
Ady Abraham03b02dd2019-03-21 15:40:11 -0700215
216 return true;
217}
218
Alec Mouria90a5702021-04-16 16:36:21 +0000219const std::vector<std::shared_ptr<renderengine::ExternalTexture>>&
220RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
rnlee756005b2021-05-27 10:46:36 -0700221 ui::Transform::RotationFlags transformHint = mLayer->getTransformHint();
222 // Tell SurfaceFlinger about the pre-rotation on the buffer.
223 const auto transform = [&] {
224 switch (transformHint) {
225 case ui::Transform::ROT_90:
226 return ui::Transform::ROT_270;
227 case ui::Transform::ROT_270:
228 return ui::Transform::ROT_90;
229 default:
230 return ui::Transform::ROT_0;
231 }
232 }();
233 mLayer->setTransform(transform);
234
235 if (mBufferCache.find(transformHint) == mBufferCache.end() ||
236 mBufferCache.at(transformHint).find(fps) == mBufferCache.at(transformHint).end()) {
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100237 // Ensure the range is > 0, so we don't divide by 0.
238 const auto rangeLength = std::max(1u, mHighFps - mLowFps);
239 // Clip values outside the range [mLowFps, mHighFps]. The current fps may be outside
240 // of this range if the display has changed its set of supported refresh rates.
241 fps = std::max(fps, mLowFps);
242 fps = std::min(fps, mHighFps);
243 const auto fpsScale = static_cast<float>(fps - mLowFps) / rangeLength;
rnlee756005b2021-05-27 10:46:36 -0700244 SkColor4f colorBase = SkColor4f::FromColor(HIGH_FPS_COLOR) * fpsScale;
245 SkColor4f lowFpsColor = SkColor4f::FromColor(LOW_FPS_COLOR) * (1 - fpsScale);
246 colorBase.fR = colorBase.fR + lowFpsColor.fR;
247 colorBase.fG = colorBase.fG + lowFpsColor.fG;
248 colorBase.fB = colorBase.fB + lowFpsColor.fB;
249 colorBase.fA = ALPHA;
250 SkColor color = colorBase.toSkColor();
251 auto buffers = SevenSegmentDrawer::draw(fps, color, transformHint, mShowSpinner);
Alec Mouria90a5702021-04-16 16:36:21 +0000252 std::vector<std::shared_ptr<renderengine::ExternalTexture>> textures;
253 std::transform(buffers.begin(), buffers.end(), std::back_inserter(textures),
254 [&](const auto& buffer) -> std::shared_ptr<renderengine::ExternalTexture> {
255 return std::make_shared<
256 renderengine::ExternalTexture>(buffer,
257 mFlinger.getRenderEngine(),
258 renderengine::ExternalTexture::
259 Usage::READABLE);
260 });
rnlee756005b2021-05-27 10:46:36 -0700261 mBufferCache[transformHint].emplace(fps, textures);
Ady Abraham2cb8b622019-12-02 18:55:33 -0800262 }
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100263
rnlee756005b2021-05-27 10:46:36 -0700264 return mBufferCache[transformHint][fps];
Ady Abraham2cb8b622019-12-02 18:55:33 -0800265}
266
Dominik Laskowski20134642020-04-20 22:36:44 -0700267void RefreshRateOverlay::setViewport(ui::Size viewport) {
Ady Abrahamcba8d6c2021-06-03 18:05:04 -0700268 constexpr int32_t kMaxWidth = 1000;
269 const auto width = std::min(kMaxWidth, std::min(viewport.width, viewport.height));
270 const auto height = 2 * width;
271 Rect frame((3 * width) >> 4, height >> 5);
272 frame.offsetBy(width >> 5, height >> 4);
Ady Abraham2cb8b622019-12-02 18:55:33 -0800273
Chavi Weingartena5aedbd2021-04-09 13:37:33 +0000274 layer_state_t::matrix22_t matrix;
275 matrix.dsdx = frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth());
276 matrix.dtdx = 0;
277 matrix.dtdy = 0;
278 matrix.dsdy = frame.getHeight() / static_cast<float>(SevenSegmentDrawer::getHeight());
279 mLayer->setMatrix(matrix, true);
280 mLayer->setPosition(frame.left, frame.top);
Ady Abrahamfe57b762019-04-17 20:06:14 -0700281 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
Ady Abraham03b02dd2019-03-21 15:40:11 -0700282}
283
Dominik Laskowski29fa1462021-04-27 15:51:50 -0700284void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
Ady Abraham1b11bc62021-06-03 19:51:19 -0700285 mLayer->setLayerStack(stack);
286 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
287}
288
Marin Shalamanoveadf2e72020-12-10 15:35:28 +0100289void RefreshRateOverlay::changeRefreshRate(const Fps& fps) {
290 mCurrentFps = fps.getIntValue();
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100291 auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
Ady Abrahamf0c56492020-12-17 18:04:15 -0800292 mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
Vishnu Nairadf632b2021-01-07 14:05:08 -0800293 mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
Vishnu Nair1506b182021-02-22 14:35:15 -0800294 std::nullopt /* dequeueTime */, FrameTimelineInfo{},
chaviw0b06a8d2021-08-06 11:49:08 -0500295 nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */);
Ady Abraham29d0da32020-07-16 18:39:33 -0700296
297 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
298}
299
300void RefreshRateOverlay::onInvalidate() {
301 if (!mCurrentFps.has_value()) return;
302
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100303 const auto& buffers = getOrCreateBuffers(*mCurrentFps);
Ady Abraham29d0da32020-07-16 18:39:33 -0700304 mFrame = (mFrame + 1) % buffers.size();
305 auto buffer = buffers[mFrame];
Ady Abrahamf0c56492020-12-17 18:04:15 -0800306 mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
Vishnu Nairadf632b2021-01-07 14:05:08 -0800307 mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
Vishnu Nair1506b182021-02-22 14:35:15 -0800308 std::nullopt /* dequeueTime */, FrameTimelineInfo{},
chaviw0b06a8d2021-08-06 11:49:08 -0500309 nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */);
Dominik Laskowski20134642020-04-20 22:36:44 -0700310
311 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
312}
313
314} // namespace android
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -0800315
316// TODO(b/129481165): remove the #pragma below and fix conversion issues
Marin Shalamanovbed7fd32020-12-21 20:02:20 +0100317#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"