blob: 0ef0be11017f0a62a21ffebd8311c2f8fc879208 [file] [log] [blame]
Sally Qi147581b2023-06-27 11:55:34 -07001/**
2 * Copyright (C) 2023 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// #define LOG_NDEBUG 0
18#pragma once
19
20#include "BackgroundExecutor.h"
21
22#pragma clang diagnostic push
23#pragma clang diagnostic ignored "-Wconversion"
24#include <SkCanvas.h>
25#include <SkPaint.h>
26#pragma clang diagnostic pop
27
28#include <gui/SurfaceComposerClient.h>
29#include <utils/StrongPointer.h>
30
31namespace android {
32
33inline constexpr int kDigitWidth = 64;
34inline constexpr int kDigitHeight = 100;
35inline constexpr int kDigitSpace = 16;
36
37// HdrSdrRatioOverlay re-uses this value though it doesn't really need such amount buffer.
38// for output good-looking and code conciseness.
39inline constexpr int kMaxDigits = /*displayFps*/ 3 + /*renderFps*/ 3 + /*spinner*/ 1;
40inline constexpr int kBufferWidth = kMaxDigits * kDigitWidth + (kMaxDigits - 1) * kDigitSpace;
41inline constexpr int kBufferHeight = kDigitHeight;
42
43class SurfaceControl;
44
45// Helper class to delete the SurfaceControl on a helper thread as
46// SurfaceControl assumes its destruction happens without SurfaceFlinger::mStateLock held.
47class SurfaceControlHolder {
48public:
49 explicit SurfaceControlHolder(sp<SurfaceControl> sc) : mSurfaceControl(std::move(sc)){};
50
51 ~SurfaceControlHolder() {
52 // Hand the sp<SurfaceControl> to the helper thread to release the last
53 // reference. This makes sure that the SurfaceControl is destructed without
54 // SurfaceFlinger::mStateLock held.
55 BackgroundExecutor::getInstance().sendCallbacks(
56 {[sc = std::move(mSurfaceControl)]() mutable { sc.clear(); }});
57 }
58
59 static std::unique_ptr<SurfaceControlHolder> createSurfaceControlHolder(const String8& name) {
60 sp<SurfaceControl> surfaceControl =
61 SurfaceComposerClient::getDefault()
62 ->createSurface(name, kBufferWidth, kBufferHeight, PIXEL_FORMAT_RGBA_8888,
63 ISurfaceComposerClient::eFXSurfaceBufferState);
64 return std::make_unique<SurfaceControlHolder>(std::move(surfaceControl));
65 }
66
67 const sp<SurfaceControl>& get() const { return mSurfaceControl; }
68
69private:
70 sp<SurfaceControl> mSurfaceControl;
71};
72
73// Helper class to draw digit and decimal point.
74class SegmentDrawer {
75public:
76 enum class Segment {
77 Upper,
78 UpperLeft,
79 UpperRight,
80 Middle,
81 LowerLeft,
82 LowerRight,
83 Bottom,
84 DecimalPoint
85 };
86 static void drawSegment(Segment segment, int left, SkColor color, SkCanvas& canvas) {
87 const SkRect rect = [&]() {
88 switch (segment) {
89 case Segment::Upper:
90 return SkRect::MakeLTRB(left, 0, left + kDigitWidth, kDigitSpace);
91 case Segment::UpperLeft:
92 return SkRect::MakeLTRB(left, 0, left + kDigitSpace, kDigitHeight / 2.);
93 case Segment::UpperRight:
94 return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, 0, left + kDigitWidth,
95 kDigitHeight / 2.);
96 case Segment::Middle:
97 return SkRect::MakeLTRB(left, kDigitHeight / 2. - kDigitSpace / 2.,
98 left + kDigitWidth,
99 kDigitHeight / 2. + kDigitSpace / 2.);
100 case Segment::LowerLeft:
101 return SkRect::MakeLTRB(left, kDigitHeight / 2., left + kDigitSpace,
102 kDigitHeight);
103 case Segment::LowerRight:
104 return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, kDigitHeight / 2.,
105 left + kDigitWidth, kDigitHeight);
106 case Segment::Bottom:
107 return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitWidth,
108 kDigitHeight);
109 case Segment::DecimalPoint:
110 return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitSpace,
111 kDigitHeight);
112 }
113 }();
114
115 SkPaint paint;
116 paint.setColor(color);
117 paint.setBlendMode(SkBlendMode::kSrc);
118 canvas.drawRect(rect, paint);
119 }
120
121 static void drawDigit(int digit, int left, SkColor color, SkCanvas& canvas) {
122 if (digit < 0 || digit > 9) return;
123
124 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
125 digit == 8 || digit == 9)
126 drawSegment(Segment::Upper, left, color, canvas);
127 if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
128 drawSegment(Segment::UpperLeft, left, color, canvas);
129 if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
130 digit == 8 || digit == 9)
131 drawSegment(Segment::UpperRight, left, color, canvas);
132 if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
133 digit == 9)
134 drawSegment(Segment::Middle, left, color, canvas);
135 if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
136 drawSegment(Segment::LowerLeft, left, color, canvas);
137 if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
138 digit == 7 || digit == 8 || digit == 9)
139 drawSegment(Segment::LowerRight, left, color, canvas);
140 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
141 digit == 9)
142 drawSegment(Segment::Bottom, left, color, canvas);
143 }
144};
145
146} // namespace android