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 // TODO(b/129481165): remove the #pragma below and fix conversion issues
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wconversion"
20 
21 #include "RefreshRateOverlay.h"
22 #include "Client.h"
23 #include "Layer.h"
24 
25 #include <gui/IProducerListener.h>
26 
27 #undef LOG_TAG
28 #define LOG_TAG "RefreshRateOverlay"
29 
30 namespace android {
31 
drawRect(const Rect & r,const half4 & color,const sp<GraphicBuffer> & buffer,uint8_t * pixels)32 void 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 
drawSegment(Segment segment,int left,const half4 & color,const sp<GraphicBuffer> & buffer,uint8_t * pixels)54 void 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 
drawDigit(int digit,int left,const half4 & color,const sp<GraphicBuffer> & buffer,uint8_t * pixels)83 void 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 
drawNumber(int number,const half4 & color)109 sp<GraphicBuffer> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number,
110                                                                      const half4& color) {
111     if (number < 0 || number > 1000) return nullptr;
112 
113     const auto hundreds = number / 100;
114     const auto tens = (number / 10) % 10;
115     const auto ones = number % 10;
116 
117     sp<GraphicBuffer> buffer =
118             new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1,
119                               GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
120                                       GRALLOC_USAGE_HW_TEXTURE,
121                               "RefreshRateOverlayBuffer");
122     uint8_t* pixels;
123     buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
124     // Clear buffer content
125     drawRect(Rect(BUFFER_WIDTH, BUFFER_HEIGHT), half4(0), buffer, pixels);
126     int left = 0;
127     if (hundreds != 0) {
128         drawDigit(hundreds, left, color, buffer, pixels);
129         left += DIGIT_WIDTH + DIGIT_SPACE;
130     }
131 
132     if (tens != 0) {
133         drawDigit(tens, left, color, buffer, pixels);
134         left += DIGIT_WIDTH + DIGIT_SPACE;
135     }
136 
137     drawDigit(ones, left, color, buffer, pixels);
138     buffer->unlock();
139     return buffer;
140 }
141 
RefreshRateOverlay(SurfaceFlinger & flinger)142 RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger)
143       : mFlinger(flinger), mClient(new Client(&mFlinger)) {
144     createLayer();
145     primeCache();
146 }
147 
createLayer()148 bool RefreshRateOverlay::createLayer() {
149     const status_t ret =
150             mFlinger.createLayer(String8("RefreshRateOverlay"), mClient,
151                                  SevenSegmentDrawer::getWidth(), SevenSegmentDrawer::getHeight(),
152                                  PIXEL_FORMAT_RGBA_8888,
153                                  ISurfaceComposerClient::eFXSurfaceBufferState, LayerMetadata(),
154                                  &mIBinder, &mGbp, nullptr);
155     if (ret) {
156         ALOGE("failed to create buffer state layer");
157         return false;
158     }
159 
160     Mutex::Autolock _l(mFlinger.mStateLock);
161     mLayer = mClient->getLayerUser(mIBinder);
162     mLayer->setFrameRate(Layer::FrameRate(0, Layer::FrameRateCompatibility::NoVote));
163 
164     // setting Layer's Z requires resorting layersSortedByZ
165     ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
166     if (mLayer->setLayer(INT32_MAX - 2) && idx >= 0) {
167         mFlinger.mCurrentState.layersSortedByZ.removeAt(idx);
168         mFlinger.mCurrentState.layersSortedByZ.add(mLayer);
169     }
170 
171     return true;
172 }
173 
primeCache()174 void RefreshRateOverlay::primeCache() {
175     auto& allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates();
176     if (allRefreshRates.size() == 1) {
177         auto fps = allRefreshRates.begin()->second->getFps();
178         half4 color = {LOW_FPS_COLOR, ALPHA};
179         mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
180         return;
181     }
182 
183     std::vector<uint32_t> supportedFps;
184     supportedFps.reserve(allRefreshRates.size());
185     for (auto& [ignored, refreshRate] : allRefreshRates) {
186         supportedFps.push_back(refreshRate->getFps());
187     }
188 
189     std::sort(supportedFps.begin(), supportedFps.end());
190     const auto mLowFps = supportedFps[0];
191     const auto mHighFps = supportedFps[supportedFps.size() - 1];
192     for (auto fps : supportedFps) {
193         const auto fpsScale = float(fps - mLowFps) / (mHighFps - mLowFps);
194         half4 color;
195         color.r = HIGH_FPS_COLOR.r * fpsScale + LOW_FPS_COLOR.r * (1 - fpsScale);
196         color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale);
197         color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale);
198         color.a = ALPHA;
199         mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
200     }
201 }
202 
setViewport(ui::Size viewport)203 void RefreshRateOverlay::setViewport(ui::Size viewport) {
204     Rect frame(viewport.width >> 3, viewport.height >> 5);
205     frame.offsetBy(viewport.width >> 5, viewport.height >> 4);
206     mLayer->setFrame(frame);
207 
208     mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
209 }
210 
changeRefreshRate(const RefreshRate & refreshRate)211 void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
212     auto buffer = mBufferCache[refreshRate.getFps()];
213     mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {});
214 
215     mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
216 }
217 
218 } // namespace android
219 
220 // TODO(b/129481165): remove the #pragma below and fix conversion issues
221 #pragma clang diagnostic pop // ignored "-Wconversion"
222