1 /*
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
17 #include <algorithm>
18
19 #include "BackgroundExecutor.h"
20 #include "Client.h"
21 #include "Layer.h"
22 #include "RefreshRateOverlay.h"
23
24 #pragma clang diagnostic push
25 #pragma clang diagnostic ignored "-Wconversion"
26 #include <SkCanvas.h>
27 #include <SkPaint.h>
28 #pragma clang diagnostic pop
29 #include <SkBlendMode.h>
30 #include <SkRect.h>
31 #include <SkSurface.h>
32 #include <gui/SurfaceComposerClient.h>
33 #include <gui/SurfaceControl.h>
34
35 #undef LOG_TAG
36 #define LOG_TAG "RefreshRateOverlay"
37
38 namespace android {
39 namespace {
40
41 constexpr int kDigitWidth = 64;
42 constexpr int kDigitHeight = 100;
43 constexpr int kDigitSpace = 16;
44
45 // Layout is digit, space, digit, space, digit, space, spinner.
46 constexpr int kBufferWidth = 4 * kDigitWidth + 3 * kDigitSpace;
47 constexpr int kBufferHeight = kDigitHeight;
48
createTransaction(const sp<SurfaceControl> & surface)49 SurfaceComposerClient::Transaction createTransaction(const sp<SurfaceControl>& surface) {
50 constexpr float kFrameRate = 0.f;
51 constexpr int8_t kCompatibility = ANATIVEWINDOW_FRAME_RATE_NO_VOTE;
52 constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
53
54 return SurfaceComposerClient::Transaction().setFrameRate(surface, kFrameRate, kCompatibility,
55 kSeamlessness);
56 }
57
58 } // namespace
59
~SurfaceControlHolder()60 SurfaceControlHolder::~SurfaceControlHolder() {
61 // Hand the sp<SurfaceControl> to the helper thread to release the last
62 // reference. This makes sure that the SurfaceControl is destructed without
63 // SurfaceFlinger::mStateLock held.
64 BackgroundExecutor::getInstance().sendCallbacks(
65 {[sc = std::move(mSurfaceControl)]() mutable { sc.clear(); }});
66 }
67
drawSegment(Segment segment,int left,SkColor color,SkCanvas & canvas)68 void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color,
69 SkCanvas& canvas) {
70 const SkRect rect = [&]() {
71 switch (segment) {
72 case Segment::Upper:
73 return SkRect::MakeLTRB(left, 0, left + kDigitWidth, kDigitSpace);
74 case Segment::UpperLeft:
75 return SkRect::MakeLTRB(left, 0, left + kDigitSpace, kDigitHeight / 2);
76 case Segment::UpperRight:
77 return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, 0, left + kDigitWidth,
78 kDigitHeight / 2);
79 case Segment::Middle:
80 return SkRect::MakeLTRB(left, kDigitHeight / 2 - kDigitSpace / 2,
81 left + kDigitWidth, kDigitHeight / 2 + kDigitSpace / 2);
82 case Segment::LowerLeft:
83 return SkRect::MakeLTRB(left, kDigitHeight / 2, left + kDigitSpace, kDigitHeight);
84 case Segment::LowerRight:
85 return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, kDigitHeight / 2,
86 left + kDigitWidth, kDigitHeight);
87 case Segment::Bottom:
88 return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitWidth,
89 kDigitHeight);
90 }
91 }();
92
93 SkPaint paint;
94 paint.setColor(color);
95 paint.setBlendMode(SkBlendMode::kSrc);
96 canvas.drawRect(rect, paint);
97 }
98
drawDigit(int digit,int left,SkColor color,SkCanvas & canvas)99 void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor color,
100 SkCanvas& canvas) {
101 if (digit < 0 || digit > 9) return;
102
103 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
104 digit == 8 || digit == 9)
105 drawSegment(Segment::Upper, left, color, canvas);
106 if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
107 drawSegment(Segment::UpperLeft, left, color, canvas);
108 if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
109 digit == 8 || digit == 9)
110 drawSegment(Segment::UpperRight, left, color, canvas);
111 if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
112 digit == 9)
113 drawSegment(Segment::Middle, left, color, canvas);
114 if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
115 drawSegment(Segment::LowerLeft, left, color, canvas);
116 if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
117 digit == 7 || digit == 8 || digit == 9)
118 drawSegment(Segment::LowerRight, left, color, canvas);
119 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
120 digit == 9)
121 drawSegment(Segment::Bottom, left, color, canvas);
122 }
123
draw(int number,SkColor color,ui::Transform::RotationFlags rotation,bool showSpinner)124 auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color,
125 ui::Transform::RotationFlags rotation,
126 bool showSpinner) -> Buffers {
127 if (number < 0 || number > 1000) return {};
128
129 const auto hundreds = number / 100;
130 const auto tens = (number / 10) % 10;
131 const auto ones = number % 10;
132
133 const size_t loopCount = showSpinner ? 6 : 1;
134
135 Buffers buffers;
136 buffers.reserve(loopCount);
137
138 for (size_t i = 0; i < loopCount; i++) {
139 // Pre-rotate the buffer before it reaches SurfaceFlinger.
140 SkMatrix canvasTransform = SkMatrix();
141 const auto [bufferWidth, bufferHeight] = [&]() -> std::pair<int, int> {
142 switch (rotation) {
143 case ui::Transform::ROT_90:
144 canvasTransform.setTranslate(kBufferHeight, 0);
145 canvasTransform.preRotate(90.f);
146 return {kBufferHeight, kBufferWidth};
147 case ui::Transform::ROT_270:
148 canvasTransform.setRotate(270.f, kBufferWidth / 2.f, kBufferWidth / 2.f);
149 return {kBufferHeight, kBufferWidth};
150 default:
151 return {kBufferWidth, kBufferHeight};
152 }
153 }();
154
155 sp<GraphicBuffer> buffer =
156 new GraphicBuffer(static_cast<uint32_t>(bufferWidth),
157 static_cast<uint32_t>(bufferHeight), HAL_PIXEL_FORMAT_RGBA_8888,
158 1,
159 GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
160 GRALLOC_USAGE_HW_TEXTURE,
161 "RefreshRateOverlayBuffer");
162
163 const status_t bufferStatus = buffer->initCheck();
164 LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
165 bufferStatus);
166
167 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(bufferWidth, bufferHeight);
168 SkCanvas* canvas = surface->getCanvas();
169 canvas->setMatrix(canvasTransform);
170
171 int left = 0;
172 if (hundreds != 0) {
173 drawDigit(hundreds, left, color, *canvas);
174 }
175 left += kDigitWidth + kDigitSpace;
176
177 if (tens != 0) {
178 drawDigit(tens, left, color, *canvas);
179 }
180 left += kDigitWidth + kDigitSpace;
181
182 drawDigit(ones, left, color, *canvas);
183 left += kDigitWidth + kDigitSpace;
184
185 if (showSpinner) {
186 switch (i) {
187 case 0:
188 drawSegment(Segment::Upper, left, color, *canvas);
189 break;
190 case 1:
191 drawSegment(Segment::UpperRight, left, color, *canvas);
192 break;
193 case 2:
194 drawSegment(Segment::LowerRight, left, color, *canvas);
195 break;
196 case 3:
197 drawSegment(Segment::Bottom, left, color, *canvas);
198 break;
199 case 4:
200 drawSegment(Segment::LowerLeft, left, color, *canvas);
201 break;
202 case 5:
203 drawSegment(Segment::UpperLeft, left, color, *canvas);
204 break;
205 }
206 }
207
208 void* pixels = nullptr;
209 buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
210
211 const SkImageInfo& imageInfo = surface->imageInfo();
212 const size_t dstRowBytes =
213 buffer->getStride() * static_cast<size_t>(imageInfo.bytesPerPixel());
214
215 canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0);
216 buffer->unlock();
217 buffers.push_back(std::move(buffer));
218 }
219 return buffers;
220 }
221
createSurfaceControlHolder()222 std::unique_ptr<SurfaceControlHolder> createSurfaceControlHolder() {
223 sp<SurfaceControl> surfaceControl =
224 SurfaceComposerClient::getDefault()
225 ->createSurface(String8("RefreshRateOverlay"), kBufferWidth, kBufferHeight,
226 PIXEL_FORMAT_RGBA_8888,
227 ISurfaceComposerClient::eFXSurfaceBufferState);
228 return std::make_unique<SurfaceControlHolder>(std::move(surfaceControl));
229 }
230
RefreshRateOverlay(FpsRange fpsRange,bool showSpinner)231 RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner)
232 : mFpsRange(fpsRange),
233 mShowSpinner(showSpinner),
234 mSurfaceControl(createSurfaceControlHolder()) {
235 if (!mSurfaceControl) {
236 ALOGE("%s: Failed to create buffer state layer", __func__);
237 return;
238 }
239
240 createTransaction(mSurfaceControl->get())
241 .setLayer(mSurfaceControl->get(), INT32_MAX - 2)
242 .setTrustedOverlay(mSurfaceControl->get(), true)
243 .apply();
244 }
245
getOrCreateBuffers(Fps fps)246 auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& {
247 static const Buffers kNoBuffers;
248 if (!mSurfaceControl) return kNoBuffers;
249
250 const auto transformHint =
251 static_cast<ui::Transform::RotationFlags>(mSurfaceControl->get()->getTransformHint());
252
253 // Tell SurfaceFlinger about the pre-rotation on the buffer.
254 const auto transform = [&] {
255 switch (transformHint) {
256 case ui::Transform::ROT_90:
257 return ui::Transform::ROT_270;
258 case ui::Transform::ROT_270:
259 return ui::Transform::ROT_90;
260 default:
261 return ui::Transform::ROT_0;
262 }
263 }();
264
265 createTransaction(mSurfaceControl->get())
266 .setTransform(mSurfaceControl->get(), transform)
267 .apply();
268
269 BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint});
270 if (it == mBufferCache.end()) {
271 const int minFps = mFpsRange.min.getIntValue();
272 const int maxFps = mFpsRange.max.getIntValue();
273
274 // Clamp to the range. The current fps may be outside of this range if the display has
275 // changed its set of supported refresh rates.
276 const int intFps = std::clamp(fps.getIntValue(), minFps, maxFps);
277
278 // Ensure non-zero range to avoid division by zero.
279 const float fpsScale = static_cast<float>(intFps - minFps) / std::max(1, maxFps - minFps);
280
281 constexpr SkColor kMinFpsColor = SK_ColorRED;
282 constexpr SkColor kMaxFpsColor = SK_ColorGREEN;
283 constexpr float kAlpha = 0.8f;
284
285 SkColor4f colorBase = SkColor4f::FromColor(kMaxFpsColor) * fpsScale;
286 const SkColor4f minFpsColor = SkColor4f::FromColor(kMinFpsColor) * (1 - fpsScale);
287
288 colorBase.fR = colorBase.fR + minFpsColor.fR;
289 colorBase.fG = colorBase.fG + minFpsColor.fG;
290 colorBase.fB = colorBase.fB + minFpsColor.fB;
291 colorBase.fA = kAlpha;
292
293 const SkColor color = colorBase.toSkColor();
294
295 auto buffers = SevenSegmentDrawer::draw(intFps, color, transformHint, mShowSpinner);
296 it = mBufferCache.try_emplace({intFps, transformHint}, std::move(buffers)).first;
297 }
298
299 return it->second;
300 }
301
setViewport(ui::Size viewport)302 void RefreshRateOverlay::setViewport(ui::Size viewport) {
303 constexpr int32_t kMaxWidth = 1000;
304 const auto width = std::min({kMaxWidth, viewport.width, viewport.height});
305 const auto height = 2 * width;
306 Rect frame((3 * width) >> 4, height >> 5);
307 frame.offsetBy(width >> 5, height >> 4);
308
309 createTransaction(mSurfaceControl->get())
310 .setMatrix(mSurfaceControl->get(), frame.getWidth() / static_cast<float>(kBufferWidth),
311 0, 0, frame.getHeight() / static_cast<float>(kBufferHeight))
312 .setPosition(mSurfaceControl->get(), frame.left, frame.top)
313 .apply();
314 }
315
setLayerStack(ui::LayerStack stack)316 void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
317 createTransaction(mSurfaceControl->get()).setLayerStack(mSurfaceControl->get(), stack).apply();
318 }
319
changeRefreshRate(Fps fps)320 void RefreshRateOverlay::changeRefreshRate(Fps fps) {
321 mCurrentFps = fps;
322 const auto buffer = getOrCreateBuffers(fps)[mFrame];
323 createTransaction(mSurfaceControl->get()).setBuffer(mSurfaceControl->get(), buffer).apply();
324 }
325
animate()326 void RefreshRateOverlay::animate() {
327 if (!mShowSpinner || !mCurrentFps) return;
328
329 const auto& buffers = getOrCreateBuffers(*mCurrentFps);
330 mFrame = (mFrame + 1) % buffers.size();
331 const auto buffer = buffers[mFrame];
332 createTransaction(mSurfaceControl->get()).setBuffer(mSurfaceControl->get(), buffer).apply();
333 }
334
335 } // namespace android
336