blob: b0d76e678b034ddf016f976b848c9429d7f4167c [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
Ady Abraham2cb8b622019-12-02 18:55:33 -080028#include <gui/IProducerListener.h>
29
30#undef LOG_TAG
31#define LOG_TAG "RefreshRateOverlay"
32
Ady Abraham03b02dd2019-03-21 15:40:11 -070033namespace android {
34
Ady Abraham2cb8b622019-12-02 18:55:33 -080035void RefreshRateOverlay::SevenSegmentDrawer::drawRect(const Rect& r, const half4& color,
36 const sp<GraphicBuffer>& buffer,
37 uint8_t* pixels) {
38 for (int32_t j = r.top; j < r.bottom; j++) {
39 if (j >= buffer->getHeight()) {
40 break;
41 }
42
43 for (int32_t i = r.left; i < r.right; i++) {
44 if (i >= buffer->getWidth()) {
45 break;
46 }
47
48 uint8_t* iter = pixels + 4 * (i + (buffer->getStride() * j));
49 iter[0] = uint8_t(color.r * 255);
50 iter[1] = uint8_t(color.g * 255);
51 iter[2] = uint8_t(color.b * 255);
52 iter[3] = uint8_t(color.a * 255);
53 }
54 }
55}
56
57void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left,
58 const half4& color,
59 const sp<GraphicBuffer>& buffer,
60 uint8_t* pixels) {
61 const Rect rect = [&]() {
62 switch (segment) {
63 case Segment::Upper:
64 return Rect(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
65 case Segment::UpperLeft:
66 return Rect(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
67 case Segment::UpperRight:
68 return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
69 DIGIT_HEIGHT / 2);
70 case Segment::Middle:
71 return Rect(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2, left + DIGIT_WIDTH,
72 DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
73 case Segment::LowerLeft:
74 return Rect(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
75 case Segment::LowerRight:
76 return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2, left + DIGIT_WIDTH,
77 DIGIT_HEIGHT);
78 case Segment::Buttom:
79 return Rect(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH, DIGIT_HEIGHT);
80 }
81 }();
82
83 drawRect(rect, color, buffer, pixels);
84}
85
86void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, const half4& color,
87 const sp<GraphicBuffer>& buffer,
88 uint8_t* pixels) {
89 if (digit < 0 || digit > 9) return;
90
91 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
92 digit == 8 || digit == 9)
93 drawSegment(Segment::Upper, left, color, buffer, pixels);
94 if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
95 drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
96 if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
97 digit == 8 || digit == 9)
98 drawSegment(Segment::UpperRight, left, color, buffer, pixels);
99 if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
100 digit == 9)
101 drawSegment(Segment::Middle, left, color, buffer, pixels);
102 if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
103 drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
104 if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
105 digit == 7 || digit == 8 || digit == 9)
106 drawSegment(Segment::LowerRight, left, color, buffer, pixels);
107 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
108 digit == 9)
109 drawSegment(Segment::Buttom, left, color, buffer, pixels);
110}
111
Ady Abraham29d0da32020-07-16 18:39:33 -0700112std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(
113 int number, const half4& color, bool showSpinner) {
114 if (number < 0 || number > 1000) return {};
Ady Abraham2cb8b622019-12-02 18:55:33 -0800115
116 const auto hundreds = number / 100;
117 const auto tens = (number / 10) % 10;
118 const auto ones = number % 10;
119
Ady Abraham29d0da32020-07-16 18:39:33 -0700120 std::vector<sp<GraphicBuffer>> buffers;
121 const auto loopCount = showSpinner ? 6 : 1;
122 for (int i = 0; i < loopCount; i++) {
123 sp<GraphicBuffer> buffer =
124 new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1,
125 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);
Ady Abraham29d0da32020-07-16 18:39:33 -0700131 uint8_t* pixels;
132 buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
133 // Clear buffer content
134 drawRect(Rect(BUFFER_WIDTH, BUFFER_HEIGHT), half4(0), buffer, pixels);
135 int left = 0;
136 if (hundreds != 0) {
137 drawDigit(hundreds, left, color, buffer, pixels);
138 }
Ady Abraham2cb8b622019-12-02 18:55:33 -0800139 left += DIGIT_WIDTH + DIGIT_SPACE;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800140
Ady Abraham29d0da32020-07-16 18:39:33 -0700141 if (tens != 0) {
142 drawDigit(tens, left, color, buffer, pixels);
143 }
Ady Abraham2cb8b622019-12-02 18:55:33 -0800144 left += DIGIT_WIDTH + DIGIT_SPACE;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800145
Ady Abraham29d0da32020-07-16 18:39:33 -0700146 drawDigit(ones, left, color, buffer, pixels);
147 left += DIGIT_WIDTH + DIGIT_SPACE;
148
149 if (showSpinner) {
150 switch (i) {
151 case 0:
152 drawSegment(Segment::Upper, left, color, buffer, pixels);
153 break;
154 case 1:
155 drawSegment(Segment::UpperRight, left, color, buffer, pixels);
156 break;
157 case 2:
158 drawSegment(Segment::LowerRight, left, color, buffer, pixels);
159 break;
160 case 3:
161 drawSegment(Segment::Buttom, left, color, buffer, pixels);
162 break;
163 case 4:
164 drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
165 break;
166 case 5:
167 drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
168 break;
169 }
170 }
171
172 buffer->unlock();
173 buffers.emplace_back(buffer);
174 }
175 return buffers;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800176}
177
Ady Abraham1b11bc62021-06-03 19:51:19 -0700178RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, uint32_t lowFps, uint32_t highFps,
179 bool showSpinner)
180 : mFlinger(flinger),
181 mClient(new Client(&mFlinger)),
182 mShowSpinner(showSpinner),
183 mLowFps(lowFps),
184 mHighFps(highFps) {
Ady Abraham03b02dd2019-03-21 15:40:11 -0700185 createLayer();
186}
187
188bool RefreshRateOverlay::createLayer() {
Ady Abraham9f0a4002020-10-05 15:47:26 -0700189 int32_t layerId;
Ady Abraham03b02dd2019-03-21 15:40:11 -0700190 const status_t ret =
Ady Abraham2cb8b622019-12-02 18:55:33 -0800191 mFlinger.createLayer(String8("RefreshRateOverlay"), mClient,
192 SevenSegmentDrawer::getWidth(), SevenSegmentDrawer::getHeight(),
193 PIXEL_FORMAT_RGBA_8888,
194 ISurfaceComposerClient::eFXSurfaceBufferState, LayerMetadata(),
Ady Abraham9f0a4002020-10-05 15:47:26 -0700195 &mIBinder, &mGbp, nullptr, &layerId);
Ady Abraham03b02dd2019-03-21 15:40:11 -0700196 if (ret) {
Ady Abraham2cb8b622019-12-02 18:55:33 -0800197 ALOGE("failed to create buffer state layer");
Ady Abraham03b02dd2019-03-21 15:40:11 -0700198 return false;
199 }
200
201 mLayer = mClient->getLayerUser(mIBinder);
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100202 mLayer->setFrameRate(Layer::FrameRate(Fps(0.0f), Layer::FrameRateCompatibility::NoVote));
Ady Abrahamfed164b2019-05-10 17:12:54 -0700203
204 // setting Layer's Z requires resorting layersSortedByZ
Robert Carr6a160312021-05-17 12:08:20 -0700205 ssize_t idx = mFlinger.mDrawingState.layersSortedByZ.indexOf(mLayer);
Ady Abrahamfed164b2019-05-10 17:12:54 -0700206 if (mLayer->setLayer(INT32_MAX - 2) && idx >= 0) {
Robert Carr6a160312021-05-17 12:08:20 -0700207 mFlinger.mDrawingState.layersSortedByZ.removeAt(idx);
208 mFlinger.mDrawingState.layersSortedByZ.add(mLayer);
Ady Abrahamfed164b2019-05-10 17:12:54 -0700209 }
Ady Abraham03b02dd2019-03-21 15:40:11 -0700210
211 return true;
212}
213
Alec Mouria90a5702021-04-16 16:36:21 +0000214const std::vector<std::shared_ptr<renderengine::ExternalTexture>>&
215RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100216 if (mBufferCache.find(fps) == mBufferCache.end()) {
217 // Ensure the range is > 0, so we don't divide by 0.
218 const auto rangeLength = std::max(1u, mHighFps - mLowFps);
219 // Clip values outside the range [mLowFps, mHighFps]. The current fps may be outside
220 // of this range if the display has changed its set of supported refresh rates.
221 fps = std::max(fps, mLowFps);
222 fps = std::min(fps, mHighFps);
223 const auto fpsScale = static_cast<float>(fps - mLowFps) / rangeLength;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800224 half4 color;
225 color.r = HIGH_FPS_COLOR.r * fpsScale + LOW_FPS_COLOR.r * (1 - fpsScale);
226 color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale);
227 color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale);
228 color.a = ALPHA;
Alec Mouria90a5702021-04-16 16:36:21 +0000229 auto buffers = SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner);
230 std::vector<std::shared_ptr<renderengine::ExternalTexture>> textures;
231 std::transform(buffers.begin(), buffers.end(), std::back_inserter(textures),
232 [&](const auto& buffer) -> std::shared_ptr<renderengine::ExternalTexture> {
233 return std::make_shared<
234 renderengine::ExternalTexture>(buffer,
235 mFlinger.getRenderEngine(),
236 renderengine::ExternalTexture::
237 Usage::READABLE);
238 });
239 mBufferCache.emplace(fps, textures);
Ady Abraham2cb8b622019-12-02 18:55:33 -0800240 }
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100241
242 return mBufferCache[fps];
Ady Abraham2cb8b622019-12-02 18:55:33 -0800243}
244
Dominik Laskowski20134642020-04-20 22:36:44 -0700245void RefreshRateOverlay::setViewport(ui::Size viewport) {
Ady Abrahamcba8d6c2021-06-03 18:05:04 -0700246 constexpr int32_t kMaxWidth = 1000;
247 const auto width = std::min(kMaxWidth, std::min(viewport.width, viewport.height));
248 const auto height = 2 * width;
249 Rect frame((3 * width) >> 4, height >> 5);
250 frame.offsetBy(width >> 5, height >> 4);
Ady Abraham2cb8b622019-12-02 18:55:33 -0800251
Chavi Weingartena5aedbd2021-04-09 13:37:33 +0000252 layer_state_t::matrix22_t matrix;
253 matrix.dsdx = frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth());
254 matrix.dtdx = 0;
255 matrix.dtdy = 0;
256 matrix.dsdy = frame.getHeight() / static_cast<float>(SevenSegmentDrawer::getHeight());
257 mLayer->setMatrix(matrix, true);
258 mLayer->setPosition(frame.left, frame.top);
Ady Abrahamfe57b762019-04-17 20:06:14 -0700259 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
Ady Abraham03b02dd2019-03-21 15:40:11 -0700260}
261
Ady Abraham1b11bc62021-06-03 19:51:19 -0700262void RefreshRateOverlay::setLayerStack(uint32_t stack) {
263 mLayer->setLayerStack(stack);
264 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
265}
266
Marin Shalamanoveadf2e72020-12-10 15:35:28 +0100267void RefreshRateOverlay::changeRefreshRate(const Fps& fps) {
268 mCurrentFps = fps.getIntValue();
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100269 auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
Ady Abrahamf0c56492020-12-17 18:04:15 -0800270 mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
Vishnu Nairadf632b2021-01-07 14:05:08 -0800271 mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
Vishnu Nair1506b182021-02-22 14:35:15 -0800272 std::nullopt /* dequeueTime */, FrameTimelineInfo{},
273 nullptr /* releaseBufferListener */);
Ady Abraham29d0da32020-07-16 18:39:33 -0700274
275 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
276}
277
278void RefreshRateOverlay::onInvalidate() {
279 if (!mCurrentFps.has_value()) return;
280
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100281 const auto& buffers = getOrCreateBuffers(*mCurrentFps);
Ady Abraham29d0da32020-07-16 18:39:33 -0700282 mFrame = (mFrame + 1) % buffers.size();
283 auto buffer = buffers[mFrame];
Ady Abrahamf0c56492020-12-17 18:04:15 -0800284 mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
Vishnu Nairadf632b2021-01-07 14:05:08 -0800285 mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
Vishnu Nair1506b182021-02-22 14:35:15 -0800286 std::nullopt /* dequeueTime */, FrameTimelineInfo{},
287 nullptr /* releaseBufferListener */);
Dominik Laskowski20134642020-04-20 22:36:44 -0700288
289 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
290}
291
292} // namespace android
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -0800293
294// TODO(b/129481165): remove the #pragma below and fix conversion issues
Marin Shalamanovbed7fd32020-12-21 20:02:20 +0100295#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"