blob: f99d54ac53927800adcd747b2dee8123d3d7a8da [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
Ady Abraham03b02dd2019-03-21 15:40:11 -070021#include "RefreshRateOverlay.h"
22#include "Client.h"
23#include "Layer.h"
24
Ady Abraham2cb8b622019-12-02 18:55:33 -080025#include <gui/IProducerListener.h>
26
27#undef LOG_TAG
28#define LOG_TAG "RefreshRateOverlay"
29
Ady Abraham03b02dd2019-03-21 15:40:11 -070030namespace android {
31
Ady Abraham2cb8b622019-12-02 18:55:33 -080032void RefreshRateOverlay::SevenSegmentDrawer::drawRect(const Rect& r, const half4& color,
33 const sp<GraphicBuffer>& buffer,
34 uint8_t* pixels) {
35 for (int32_t j = r.top; j < r.bottom; j++) {
36 if (j >= buffer->getHeight()) {
37 break;
38 }
39
40 for (int32_t i = r.left; i < r.right; i++) {
41 if (i >= buffer->getWidth()) {
42 break;
43 }
44
45 uint8_t* iter = pixels + 4 * (i + (buffer->getStride() * j));
46 iter[0] = uint8_t(color.r * 255);
47 iter[1] = uint8_t(color.g * 255);
48 iter[2] = uint8_t(color.b * 255);
49 iter[3] = uint8_t(color.a * 255);
50 }
51 }
52}
53
54void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left,
55 const half4& color,
56 const sp<GraphicBuffer>& buffer,
57 uint8_t* pixels) {
58 const Rect rect = [&]() {
59 switch (segment) {
60 case Segment::Upper:
61 return Rect(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
62 case Segment::UpperLeft:
63 return Rect(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
64 case Segment::UpperRight:
65 return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
66 DIGIT_HEIGHT / 2);
67 case Segment::Middle:
68 return Rect(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2, left + DIGIT_WIDTH,
69 DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
70 case Segment::LowerLeft:
71 return Rect(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
72 case Segment::LowerRight:
73 return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2, left + DIGIT_WIDTH,
74 DIGIT_HEIGHT);
75 case Segment::Buttom:
76 return Rect(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH, DIGIT_HEIGHT);
77 }
78 }();
79
80 drawRect(rect, color, buffer, pixels);
81}
82
83void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, const half4& color,
84 const sp<GraphicBuffer>& buffer,
85 uint8_t* pixels) {
86 if (digit < 0 || digit > 9) return;
87
88 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
89 digit == 8 || digit == 9)
90 drawSegment(Segment::Upper, left, color, buffer, pixels);
91 if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
92 drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
93 if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
94 digit == 8 || digit == 9)
95 drawSegment(Segment::UpperRight, left, color, buffer, pixels);
96 if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
97 digit == 9)
98 drawSegment(Segment::Middle, left, color, buffer, pixels);
99 if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
100 drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
101 if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
102 digit == 7 || digit == 8 || digit == 9)
103 drawSegment(Segment::LowerRight, left, color, buffer, pixels);
104 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
105 digit == 9)
106 drawSegment(Segment::Buttom, left, color, buffer, pixels);
107}
108
Ady Abraham29d0da32020-07-16 18:39:33 -0700109std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(
110 int number, const half4& color, bool showSpinner) {
111 if (number < 0 || number > 1000) return {};
Ady Abraham2cb8b622019-12-02 18:55:33 -0800112
113 const auto hundreds = number / 100;
114 const auto tens = (number / 10) % 10;
115 const auto ones = number % 10;
116
Ady Abraham29d0da32020-07-16 18:39:33 -0700117 std::vector<sp<GraphicBuffer>> buffers;
118 const auto loopCount = showSpinner ? 6 : 1;
119 for (int i = 0; i < loopCount; i++) {
120 sp<GraphicBuffer> buffer =
121 new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1,
122 GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
123 GRALLOC_USAGE_HW_TEXTURE,
124 "RefreshRateOverlayBuffer");
125 uint8_t* pixels;
126 buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
127 // Clear buffer content
128 drawRect(Rect(BUFFER_WIDTH, BUFFER_HEIGHT), half4(0), buffer, pixels);
129 int left = 0;
130 if (hundreds != 0) {
131 drawDigit(hundreds, left, color, buffer, pixels);
132 }
Ady Abraham2cb8b622019-12-02 18:55:33 -0800133 left += DIGIT_WIDTH + DIGIT_SPACE;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800134
Ady Abraham29d0da32020-07-16 18:39:33 -0700135 if (tens != 0) {
136 drawDigit(tens, left, color, buffer, pixels);
137 }
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 drawDigit(ones, left, color, buffer, pixels);
141 left += DIGIT_WIDTH + DIGIT_SPACE;
142
143 if (showSpinner) {
144 switch (i) {
145 case 0:
146 drawSegment(Segment::Upper, left, color, buffer, pixels);
147 break;
148 case 1:
149 drawSegment(Segment::UpperRight, left, color, buffer, pixels);
150 break;
151 case 2:
152 drawSegment(Segment::LowerRight, left, color, buffer, pixels);
153 break;
154 case 3:
155 drawSegment(Segment::Buttom, left, color, buffer, pixels);
156 break;
157 case 4:
158 drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
159 break;
160 case 5:
161 drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
162 break;
163 }
164 }
165
166 buffer->unlock();
167 buffers.emplace_back(buffer);
168 }
169 return buffers;
Ady Abraham2cb8b622019-12-02 18:55:33 -0800170}
171
Ady Abraham29d0da32020-07-16 18:39:33 -0700172RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, bool showSpinner)
173 : mFlinger(flinger), mClient(new Client(&mFlinger)), mShowSpinner(showSpinner) {
Ady Abraham03b02dd2019-03-21 15:40:11 -0700174 createLayer();
Ady Abraham2cb8b622019-12-02 18:55:33 -0800175 primeCache();
Ady Abraham03b02dd2019-03-21 15:40:11 -0700176}
177
178bool RefreshRateOverlay::createLayer() {
Ady Abraham9f0a4002020-10-05 15:47:26 -0700179 int32_t layerId;
Ady Abraham03b02dd2019-03-21 15:40:11 -0700180 const status_t ret =
Ady Abraham2cb8b622019-12-02 18:55:33 -0800181 mFlinger.createLayer(String8("RefreshRateOverlay"), mClient,
182 SevenSegmentDrawer::getWidth(), SevenSegmentDrawer::getHeight(),
183 PIXEL_FORMAT_RGBA_8888,
184 ISurfaceComposerClient::eFXSurfaceBufferState, LayerMetadata(),
Ady Abraham9f0a4002020-10-05 15:47:26 -0700185 &mIBinder, &mGbp, nullptr, &layerId);
Ady Abraham03b02dd2019-03-21 15:40:11 -0700186 if (ret) {
Ady Abraham2cb8b622019-12-02 18:55:33 -0800187 ALOGE("failed to create buffer state layer");
Ady Abraham03b02dd2019-03-21 15:40:11 -0700188 return false;
189 }
190
Ady Abrahamfed164b2019-05-10 17:12:54 -0700191 Mutex::Autolock _l(mFlinger.mStateLock);
Ady Abraham03b02dd2019-03-21 15:40:11 -0700192 mLayer = mClient->getLayerUser(mIBinder);
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100193 mLayer->setFrameRate(Layer::FrameRate(Fps(0.0f), Layer::FrameRateCompatibility::NoVote));
Ady Abrahamfed164b2019-05-10 17:12:54 -0700194
195 // setting Layer's Z requires resorting layersSortedByZ
196 ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
197 if (mLayer->setLayer(INT32_MAX - 2) && idx >= 0) {
198 mFlinger.mCurrentState.layersSortedByZ.removeAt(idx);
199 mFlinger.mCurrentState.layersSortedByZ.add(mLayer);
200 }
Ady Abraham03b02dd2019-03-21 15:40:11 -0700201
202 return true;
203}
204
Ady Abraham2cb8b622019-12-02 18:55:33 -0800205void RefreshRateOverlay::primeCache() {
Ady Abraham2e1dd892020-03-05 13:48:36 -0800206 auto& allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates();
Ady Abraham2cb8b622019-12-02 18:55:33 -0800207 if (allRefreshRates.size() == 1) {
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100208 int fps = allRefreshRates.begin()->second->getFps().getIntValue();
Ady Abraham2cb8b622019-12-02 18:55:33 -0800209 half4 color = {LOW_FPS_COLOR, ALPHA};
Ady Abraham29d0da32020-07-16 18:39:33 -0700210 mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner));
Ady Abraham2cb8b622019-12-02 18:55:33 -0800211 return;
212 }
213
214 std::vector<uint32_t> supportedFps;
215 supportedFps.reserve(allRefreshRates.size());
Ady Abraham2e1dd892020-03-05 13:48:36 -0800216 for (auto& [ignored, refreshRate] : allRefreshRates) {
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100217 supportedFps.push_back(refreshRate->getFps().getIntValue());
Ady Abraham2cb8b622019-12-02 18:55:33 -0800218 }
219
220 std::sort(supportedFps.begin(), supportedFps.end());
221 const auto mLowFps = supportedFps[0];
222 const auto mHighFps = supportedFps[supportedFps.size() - 1];
223 for (auto fps : supportedFps) {
224 const auto fpsScale = float(fps - mLowFps) / (mHighFps - mLowFps);
225 half4 color;
226 color.r = HIGH_FPS_COLOR.r * fpsScale + LOW_FPS_COLOR.r * (1 - fpsScale);
227 color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale);
228 color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale);
229 color.a = ALPHA;
Ady Abraham29d0da32020-07-16 18:39:33 -0700230 mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner));
Ady Abraham2cb8b622019-12-02 18:55:33 -0800231 }
232}
233
Dominik Laskowski20134642020-04-20 22:36:44 -0700234void RefreshRateOverlay::setViewport(ui::Size viewport) {
Ady Abraham29d0da32020-07-16 18:39:33 -0700235 Rect frame((3 * viewport.width) >> 4, viewport.height >> 5);
Dominik Laskowski20134642020-04-20 22:36:44 -0700236 frame.offsetBy(viewport.width >> 5, viewport.height >> 4);
237 mLayer->setFrame(frame);
Ady Abraham2cb8b622019-12-02 18:55:33 -0800238
Ady Abrahamfe57b762019-04-17 20:06:14 -0700239 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
Ady Abraham03b02dd2019-03-21 15:40:11 -0700240}
241
Dominik Laskowski20134642020-04-20 22:36:44 -0700242void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
Marin Shalamanove8a663d2020-11-24 17:48:00 +0100243 mCurrentFps = refreshRate.getFps().getIntValue();
Ady Abraham29d0da32020-07-16 18:39:33 -0700244 auto buffer = mBufferCache[*mCurrentFps][mFrame];
Vishnu Nair6b7c5c92020-09-29 17:27:05 -0700245 mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {},
246 mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */));
Ady Abraham29d0da32020-07-16 18:39:33 -0700247
248 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
249}
250
251void RefreshRateOverlay::onInvalidate() {
252 if (!mCurrentFps.has_value()) return;
253
254 const auto& buffers = mBufferCache[*mCurrentFps];
255 mFrame = (mFrame + 1) % buffers.size();
256 auto buffer = buffers[mFrame];
Vishnu Nair6b7c5c92020-09-29 17:27:05 -0700257 mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {},
258 mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */));
Dominik Laskowski20134642020-04-20 22:36:44 -0700259
260 mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
261}
262
263} // namespace android
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -0800264
265// TODO(b/129481165): remove the #pragma below and fix conversion issues
266#pragma clang diagnostic pop // ignored "-Wconversion"