blob: c291b7f2e0d6fdf173536ecf45c6aa5cd5e6609e [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"
20
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +010021#include <algorithm>
22
Ady Abraham03b02dd2019-03-21 15:40:11 -070023#include "RefreshRateOverlay.h"
24#include "Client.h"
25#include "Layer.h"
26
Ady Abraham2cb8b622019-12-02 18:55:33 -080027#include <gui/IProducerListener.h>
28
29#undef LOG_TAG
30#define LOG_TAG "RefreshRateOverlay"
31
Ady Abraham03b02dd2019-03-21 15:40:11 -070032namespace android {
33
Ady Abraham2cb8b622019-12-02 18:55:33 -080034void RefreshRateOverlay::SevenSegmentDrawer::drawRect(const Rect& r, const half4& color,
35 const sp<GraphicBuffer>& buffer,
36 uint8_t* pixels) {
37 for (int32_t j = r.top; j < r.bottom; j++) {
38 if (j >= buffer->getHeight()) {
39 break;
40 }
41
42 for (int32_t i = r.left; i < r.right; i++) {
43 if (i >= buffer->getWidth()) {
44 break;
45 }
46
47 uint8_t* iter = pixels + 4 * (i + (buffer->getStride() * j));
48 iter[0] = uint8_t(color.r * 255);
49 iter[1] = uint8_t(color.g * 255);
50 iter[2] = uint8_t(color.b * 255);
51 iter[3] = uint8_t(color.a * 255);
52 }
53 }
54}
55
56void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left,
57 const half4& color,
58 const sp<GraphicBuffer>& buffer,
59 uint8_t* pixels) {
60 const Rect rect = [&]() {
61 switch (segment) {
62 case Segment::Upper:
63 return Rect(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
64 case Segment::UpperLeft:
65 return Rect(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
66 case Segment::UpperRight:
67 return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
68 DIGIT_HEIGHT / 2);
69 case Segment::Middle:
70 return Rect(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2, left + DIGIT_WIDTH,
71 DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
72 case Segment::LowerLeft:
73 return Rect(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
74 case Segment::LowerRight:
75 return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2, left + DIGIT_WIDTH,
76 DIGIT_HEIGHT);
77 case Segment::Buttom:
78 return Rect(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH, DIGIT_HEIGHT);
79 }
80 }();
81
82 drawRect(rect, color, buffer, pixels);
83}
84
85void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, const half4& color,
86 const sp<GraphicBuffer>& buffer,
87 uint8_t* pixels) {
88 if (digit < 0 || digit > 9) return;
89
90 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
91 digit == 8 || digit == 9)
92 drawSegment(Segment::Upper, left, color, buffer, pixels);
93 if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
94 drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
95 if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
96 digit == 8 || digit == 9)
97 drawSegment(Segment::UpperRight, left, color, buffer, pixels);
98 if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
99 digit == 9)
100 drawSegment(Segment::Middle, left, color, buffer, pixels);
101 if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
102 drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
103 if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
104 digit == 7 || digit == 8 || digit == 9)
105 drawSegment(Segment::LowerRight, left, color, buffer, pixels);
106 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
107 digit == 9)
108 drawSegment(Segment::Buttom, left, color, buffer, pixels);
109}
110
Ady Abraham29d0da32020-07-16 18:39:33 -0700111std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(
112 int number, const half4& color, bool showSpinner) {
113 if (number < 0 || number > 1000) return {};
Ady Abraham2cb8b622019-12-02 18:55:33 -0800114
115 const auto hundreds = number / 100;
116 const auto tens = (number / 10) % 10;
117 const auto ones = number % 10;
118
Ady Abraham29d0da32020-07-16 18:39:33 -0700119 std::vector<sp<GraphicBuffer>> buffers;
120 const auto loopCount = showSpinner ? 6 : 1;
121 for (int i = 0; i < loopCount; i++) {
122 sp<GraphicBuffer> buffer =
123 new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1,
124 GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
125 GRALLOC_USAGE_HW_TEXTURE,
126 "RefreshRateOverlayBuffer");
127 uint8_t* pixels;
128 buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
129 // Clear buffer content
130 drawRect(Rect(BUFFER_WIDTH, BUFFER_HEIGHT), half4(0), buffer, pixels);
131 int left = 0;
132 if (hundreds != 0) {
133 drawDigit(hundreds, left, color, buffer, pixels);
134 }
Ady Abraham2cb8b622019-12-02 18:55:33 -0800135 left += DIGIT_WIDTH + DIGIT_SPACE;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800136
Ady Abraham29d0da32020-07-16 18:39:33 -0700137 if (tens != 0) {
138 drawDigit(tens, left, color, buffer, pixels);
139 }
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 drawDigit(ones, left, color, buffer, pixels);
143 left += DIGIT_WIDTH + DIGIT_SPACE;
144
145 if (showSpinner) {
146 switch (i) {
147 case 0:
148 drawSegment(Segment::Upper, left, color, buffer, pixels);
149 break;
150 case 1:
151 drawSegment(Segment::UpperRight, left, color, buffer, pixels);
152 break;
153 case 2:
154 drawSegment(Segment::LowerRight, left, color, buffer, pixels);
155 break;
156 case 3:
157 drawSegment(Segment::Buttom, left, color, buffer, pixels);
158 break;
159 case 4:
160 drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
161 break;
162 case 5:
163 drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
164 break;
165 }
166 }
167
168 buffer->unlock();
169 buffers.emplace_back(buffer);
170 }
171 return buffers;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800172}
173
Ady Abraham29d0da32020-07-16 18:39:33 -0700174RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, bool showSpinner)
175 : mFlinger(flinger), mClient(new Client(&mFlinger)), mShowSpinner(showSpinner) {
Ady Abraham03b02dd2019-03-21 15:40:11 -0700176 createLayer();
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100177 reset();
Ady Abraham03b02dd2019-03-21 15:40:11 -0700178}
179
180bool RefreshRateOverlay::createLayer() {
Ady Abraham9f0a4002020-10-05 15:47:26 -0700181 int32_t layerId;
Ady Abraham03b02dd2019-03-21 15:40:11 -0700182 const status_t ret =
Ady Abraham2cb8b622019-12-02 18:55:33 -0800183 mFlinger.createLayer(String8("RefreshRateOverlay"), mClient,
184 SevenSegmentDrawer::getWidth(), SevenSegmentDrawer::getHeight(),
185 PIXEL_FORMAT_RGBA_8888,
186 ISurfaceComposerClient::eFXSurfaceBufferState, LayerMetadata(),
Ady Abraham9f0a4002020-10-05 15:47:26 -0700187 &mIBinder, &mGbp, nullptr, &layerId);
Ady Abraham03b02dd2019-03-21 15:40:11 -0700188 if (ret) {
Ady Abraham2cb8b622019-12-02 18:55:33 -0800189 ALOGE("failed to create buffer state layer");
Ady Abraham03b02dd2019-03-21 15:40:11 -0700190 return false;
191 }
192
Ady Abrahamfed164b2019-05-10 17:12:54 -0700193 Mutex::Autolock _l(mFlinger.mStateLock);
Ady Abraham03b02dd2019-03-21 15:40:11 -0700194 mLayer = mClient->getLayerUser(mIBinder);
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100195 mLayer->setFrameRate(Layer::FrameRate(Fps(0.0f), Layer::FrameRateCompatibility::NoVote));
Ady Abrahamfed164b2019-05-10 17:12:54 -0700196
197 // setting Layer's Z requires resorting layersSortedByZ
198 ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
199 if (mLayer->setLayer(INT32_MAX - 2) && idx >= 0) {
200 mFlinger.mCurrentState.layersSortedByZ.removeAt(idx);
201 mFlinger.mCurrentState.layersSortedByZ.add(mLayer);
202 }
Ady Abraham03b02dd2019-03-21 15:40:11 -0700203
204 return true;
205}
206
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100207const std::vector<sp<GraphicBuffer>>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
208 if (mBufferCache.find(fps) == mBufferCache.end()) {
209 // Ensure the range is > 0, so we don't divide by 0.
210 const auto rangeLength = std::max(1u, mHighFps - mLowFps);
211 // Clip values outside the range [mLowFps, mHighFps]. The current fps may be outside
212 // of this range if the display has changed its set of supported refresh rates.
213 fps = std::max(fps, mLowFps);
214 fps = std::min(fps, mHighFps);
215 const auto fpsScale = static_cast<float>(fps - mLowFps) / rangeLength;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800216 half4 color;
217 color.r = HIGH_FPS_COLOR.r * fpsScale + LOW_FPS_COLOR.r * (1 - fpsScale);
218 color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale);
219 color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale);
220 color.a = ALPHA;
Ady Abraham29d0da32020-07-16 18:39:33 -0700221 mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner));
Ady Abraham2cb8b622019-12-02 18:55:33 -0800222 }
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100223
224 return mBufferCache[fps];
Ady Abraham2cb8b622019-12-02 18:55:33 -0800225}
226
Dominik Laskowski20134642020-04-20 22:36:44 -0700227void RefreshRateOverlay::setViewport(ui::Size viewport) {
Ady Abraham29d0da32020-07-16 18:39:33 -0700228 Rect frame((3 * viewport.width) >> 4, viewport.height >> 5);
Dominik Laskowski20134642020-04-20 22:36:44 -0700229 frame.offsetBy(viewport.width >> 5, viewport.height >> 4);
230 mLayer->setFrame(frame);
Ady Abraham2cb8b622019-12-02 18:55:33 -0800231
Ady Abrahamfe57b762019-04-17 20:06:14 -0700232 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
Ady Abraham03b02dd2019-03-21 15:40:11 -0700233}
234
Dominik Laskowski20134642020-04-20 22:36:44 -0700235void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100236 mCurrentFps = refreshRate.getFps().getIntValue();
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100237 auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
Ady Abrahamf0c56492020-12-17 18:04:15 -0800238 mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
Vishnu Nair6b7c5c92020-09-29 17:27:05 -0700239 mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */));
Ady Abraham29d0da32020-07-16 18:39:33 -0700240
241 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
242}
243
244void RefreshRateOverlay::onInvalidate() {
245 if (!mCurrentFps.has_value()) return;
246
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100247 const auto& buffers = getOrCreateBuffers(*mCurrentFps);
Ady Abraham29d0da32020-07-16 18:39:33 -0700248 mFrame = (mFrame + 1) % buffers.size();
249 auto buffer = buffers[mFrame];
Ady Abrahamf0c56492020-12-17 18:04:15 -0800250 mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
Vishnu Nair6b7c5c92020-09-29 17:27:05 -0700251 mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */));
Dominik Laskowski20134642020-04-20 22:36:44 -0700252
253 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
254}
255
Marin Shalamanovf7f6b3c2020-12-09 13:19:38 +0100256void RefreshRateOverlay::reset() {
257 mBufferCache.clear();
258 mLowFps = mFlinger.mRefreshRateConfigs->getMinRefreshRate().getFps().getIntValue();
259 mHighFps = mFlinger.mRefreshRateConfigs->getMaxRefreshRate().getFps().getIntValue();
260}
261
Dominik Laskowski20134642020-04-20 22:36:44 -0700262} // namespace android
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -0800263
264// TODO(b/129481165): remove the #pragma below and fix conversion issues
265#pragma clang diagnostic pop // ignored "-Wconversion"