1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright 2019 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker #include <algorithm>
18*38e8c45fSAndroid Build Coastguard Worker
19*38e8c45fSAndroid Build Coastguard Worker #include <common/FlagManager.h>
20*38e8c45fSAndroid Build Coastguard Worker #include "Client.h"
21*38e8c45fSAndroid Build Coastguard Worker #include "Layer.h"
22*38e8c45fSAndroid Build Coastguard Worker #include "RefreshRateOverlay.h"
23*38e8c45fSAndroid Build Coastguard Worker
24*38e8c45fSAndroid Build Coastguard Worker #include <SkSurface.h>
25*38e8c45fSAndroid Build Coastguard Worker
26*38e8c45fSAndroid Build Coastguard Worker #undef LOG_TAG
27*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "RefreshRateOverlay"
28*38e8c45fSAndroid Build Coastguard Worker
29*38e8c45fSAndroid Build Coastguard Worker namespace android {
30*38e8c45fSAndroid Build Coastguard Worker
draw(int refreshRate,int renderFps,bool idle,SkColor color,ui::Transform::RotationFlags rotation,ftl::Flags<Features> features)31*38e8c45fSAndroid Build Coastguard Worker auto RefreshRateOverlay::draw(int refreshRate, int renderFps, bool idle, SkColor color,
32*38e8c45fSAndroid Build Coastguard Worker ui::Transform::RotationFlags rotation, ftl::Flags<Features> features)
33*38e8c45fSAndroid Build Coastguard Worker -> Buffers {
34*38e8c45fSAndroid Build Coastguard Worker const size_t loopCount = features.test(Features::Spinner) ? 6 : 1;
35*38e8c45fSAndroid Build Coastguard Worker const bool isSetByHwc = features.test(Features::SetByHwc);
36*38e8c45fSAndroid Build Coastguard Worker
37*38e8c45fSAndroid Build Coastguard Worker Buffers buffers;
38*38e8c45fSAndroid Build Coastguard Worker buffers.reserve(loopCount);
39*38e8c45fSAndroid Build Coastguard Worker
40*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < loopCount; i++) {
41*38e8c45fSAndroid Build Coastguard Worker // Pre-rotate the buffer before it reaches SurfaceFlinger.
42*38e8c45fSAndroid Build Coastguard Worker SkMatrix canvasTransform = SkMatrix();
43*38e8c45fSAndroid Build Coastguard Worker const auto [bufferWidth, bufferHeight] = [&]() -> std::pair<int, int> {
44*38e8c45fSAndroid Build Coastguard Worker switch (rotation) {
45*38e8c45fSAndroid Build Coastguard Worker case ui::Transform::ROT_90:
46*38e8c45fSAndroid Build Coastguard Worker canvasTransform.setTranslate(kBufferHeight, 0);
47*38e8c45fSAndroid Build Coastguard Worker canvasTransform.preRotate(90.f);
48*38e8c45fSAndroid Build Coastguard Worker return {kBufferHeight, kBufferWidth};
49*38e8c45fSAndroid Build Coastguard Worker case ui::Transform::ROT_270:
50*38e8c45fSAndroid Build Coastguard Worker canvasTransform.setRotate(270.f, kBufferWidth / 2.f, kBufferWidth / 2.f);
51*38e8c45fSAndroid Build Coastguard Worker return {kBufferHeight, kBufferWidth};
52*38e8c45fSAndroid Build Coastguard Worker default:
53*38e8c45fSAndroid Build Coastguard Worker return {kBufferWidth, kBufferHeight};
54*38e8c45fSAndroid Build Coastguard Worker }
55*38e8c45fSAndroid Build Coastguard Worker }();
56*38e8c45fSAndroid Build Coastguard Worker
57*38e8c45fSAndroid Build Coastguard Worker const auto kUsageFlags =
58*38e8c45fSAndroid Build Coastguard Worker static_cast<uint64_t>(GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
59*38e8c45fSAndroid Build Coastguard Worker GRALLOC_USAGE_HW_TEXTURE);
60*38e8c45fSAndroid Build Coastguard Worker sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth),
61*38e8c45fSAndroid Build Coastguard Worker static_cast<uint32_t>(bufferHeight),
62*38e8c45fSAndroid Build Coastguard Worker HAL_PIXEL_FORMAT_RGBA_8888, 1u,
63*38e8c45fSAndroid Build Coastguard Worker kUsageFlags, "RefreshRateOverlayBuffer");
64*38e8c45fSAndroid Build Coastguard Worker
65*38e8c45fSAndroid Build Coastguard Worker const status_t bufferStatus = buffer->initCheck();
66*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
67*38e8c45fSAndroid Build Coastguard Worker bufferStatus);
68*38e8c45fSAndroid Build Coastguard Worker
69*38e8c45fSAndroid Build Coastguard Worker sk_sp<SkSurface> surface = SkSurfaces::Raster(
70*38e8c45fSAndroid Build Coastguard Worker SkImageInfo::MakeN32Premul(bufferWidth, bufferHeight));
71*38e8c45fSAndroid Build Coastguard Worker SkCanvas* canvas = surface->getCanvas();
72*38e8c45fSAndroid Build Coastguard Worker canvas->setMatrix(canvasTransform);
73*38e8c45fSAndroid Build Coastguard Worker
74*38e8c45fSAndroid Build Coastguard Worker int left = 0;
75*38e8c45fSAndroid Build Coastguard Worker if (idle && !isSetByHwc) {
76*38e8c45fSAndroid Build Coastguard Worker drawDash(left, *canvas);
77*38e8c45fSAndroid Build Coastguard Worker } else {
78*38e8c45fSAndroid Build Coastguard Worker drawNumber(refreshRate, left, color, *canvas);
79*38e8c45fSAndroid Build Coastguard Worker }
80*38e8c45fSAndroid Build Coastguard Worker left += 3 * (kDigitWidth + kDigitSpace);
81*38e8c45fSAndroid Build Coastguard Worker if (features.test(Features::Spinner)) {
82*38e8c45fSAndroid Build Coastguard Worker switch (i) {
83*38e8c45fSAndroid Build Coastguard Worker case 0:
84*38e8c45fSAndroid Build Coastguard Worker SegmentDrawer::drawSegment(SegmentDrawer::Segment::Upper, left, color, *canvas);
85*38e8c45fSAndroid Build Coastguard Worker break;
86*38e8c45fSAndroid Build Coastguard Worker case 1:
87*38e8c45fSAndroid Build Coastguard Worker SegmentDrawer::drawSegment(SegmentDrawer::Segment::UpperRight, left, color,
88*38e8c45fSAndroid Build Coastguard Worker *canvas);
89*38e8c45fSAndroid Build Coastguard Worker break;
90*38e8c45fSAndroid Build Coastguard Worker case 2:
91*38e8c45fSAndroid Build Coastguard Worker SegmentDrawer::drawSegment(SegmentDrawer::Segment::LowerRight, left, color,
92*38e8c45fSAndroid Build Coastguard Worker *canvas);
93*38e8c45fSAndroid Build Coastguard Worker break;
94*38e8c45fSAndroid Build Coastguard Worker case 3:
95*38e8c45fSAndroid Build Coastguard Worker SegmentDrawer::drawSegment(SegmentDrawer::Segment::Bottom, left, color,
96*38e8c45fSAndroid Build Coastguard Worker *canvas);
97*38e8c45fSAndroid Build Coastguard Worker break;
98*38e8c45fSAndroid Build Coastguard Worker case 4:
99*38e8c45fSAndroid Build Coastguard Worker SegmentDrawer::drawSegment(SegmentDrawer::Segment::LowerLeft, left, color,
100*38e8c45fSAndroid Build Coastguard Worker *canvas);
101*38e8c45fSAndroid Build Coastguard Worker break;
102*38e8c45fSAndroid Build Coastguard Worker case 5:
103*38e8c45fSAndroid Build Coastguard Worker SegmentDrawer::drawSegment(SegmentDrawer::Segment::UpperLeft, left, color,
104*38e8c45fSAndroid Build Coastguard Worker *canvas);
105*38e8c45fSAndroid Build Coastguard Worker break;
106*38e8c45fSAndroid Build Coastguard Worker }
107*38e8c45fSAndroid Build Coastguard Worker }
108*38e8c45fSAndroid Build Coastguard Worker
109*38e8c45fSAndroid Build Coastguard Worker left += kDigitWidth + kDigitSpace;
110*38e8c45fSAndroid Build Coastguard Worker
111*38e8c45fSAndroid Build Coastguard Worker if (features.test(Features::RenderRate)) {
112*38e8c45fSAndroid Build Coastguard Worker if (idle) {
113*38e8c45fSAndroid Build Coastguard Worker drawDash(left, *canvas);
114*38e8c45fSAndroid Build Coastguard Worker } else {
115*38e8c45fSAndroid Build Coastguard Worker drawNumber(renderFps, left, color, *canvas);
116*38e8c45fSAndroid Build Coastguard Worker }
117*38e8c45fSAndroid Build Coastguard Worker }
118*38e8c45fSAndroid Build Coastguard Worker left += 3 * (kDigitWidth + kDigitSpace);
119*38e8c45fSAndroid Build Coastguard Worker
120*38e8c45fSAndroid Build Coastguard Worker void* pixels = nullptr;
121*38e8c45fSAndroid Build Coastguard Worker buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
122*38e8c45fSAndroid Build Coastguard Worker
123*38e8c45fSAndroid Build Coastguard Worker const SkImageInfo& imageInfo = surface->imageInfo();
124*38e8c45fSAndroid Build Coastguard Worker const size_t dstRowBytes =
125*38e8c45fSAndroid Build Coastguard Worker buffer->getStride() * static_cast<size_t>(imageInfo.bytesPerPixel());
126*38e8c45fSAndroid Build Coastguard Worker
127*38e8c45fSAndroid Build Coastguard Worker canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0);
128*38e8c45fSAndroid Build Coastguard Worker buffer->unlock();
129*38e8c45fSAndroid Build Coastguard Worker buffers.push_back(std::move(buffer));
130*38e8c45fSAndroid Build Coastguard Worker }
131*38e8c45fSAndroid Build Coastguard Worker return buffers;
132*38e8c45fSAndroid Build Coastguard Worker }
133*38e8c45fSAndroid Build Coastguard Worker
drawNumber(int number,int left,SkColor color,SkCanvas & canvas)134*38e8c45fSAndroid Build Coastguard Worker void RefreshRateOverlay::drawNumber(int number, int left, SkColor color, SkCanvas& canvas) {
135*38e8c45fSAndroid Build Coastguard Worker if (number < 0 || number >= 1000) return;
136*38e8c45fSAndroid Build Coastguard Worker
137*38e8c45fSAndroid Build Coastguard Worker if (number >= 100) {
138*38e8c45fSAndroid Build Coastguard Worker SegmentDrawer::drawDigit(number / 100, left, color, canvas);
139*38e8c45fSAndroid Build Coastguard Worker }
140*38e8c45fSAndroid Build Coastguard Worker left += kDigitWidth + kDigitSpace;
141*38e8c45fSAndroid Build Coastguard Worker
142*38e8c45fSAndroid Build Coastguard Worker if (number >= 10) {
143*38e8c45fSAndroid Build Coastguard Worker SegmentDrawer::drawDigit((number / 10) % 10, left, color, canvas);
144*38e8c45fSAndroid Build Coastguard Worker }
145*38e8c45fSAndroid Build Coastguard Worker left += kDigitWidth + kDigitSpace;
146*38e8c45fSAndroid Build Coastguard Worker
147*38e8c45fSAndroid Build Coastguard Worker SegmentDrawer::drawDigit(number % 10, left, color, canvas);
148*38e8c45fSAndroid Build Coastguard Worker }
149*38e8c45fSAndroid Build Coastguard Worker
drawDash(int left,SkCanvas & canvas)150*38e8c45fSAndroid Build Coastguard Worker void RefreshRateOverlay::drawDash(int left, SkCanvas& canvas) {
151*38e8c45fSAndroid Build Coastguard Worker left += kDigitWidth + kDigitSpace;
152*38e8c45fSAndroid Build Coastguard Worker SegmentDrawer::drawSegment(SegmentDrawer::Segment::Middle, left, SK_ColorRED, canvas);
153*38e8c45fSAndroid Build Coastguard Worker
154*38e8c45fSAndroid Build Coastguard Worker left += kDigitWidth + kDigitSpace;
155*38e8c45fSAndroid Build Coastguard Worker SegmentDrawer::drawSegment(SegmentDrawer::Segment::Middle, left, SK_ColorRED, canvas);
156*38e8c45fSAndroid Build Coastguard Worker }
157*38e8c45fSAndroid Build Coastguard Worker
create(FpsRange range,ftl::Flags<Features> features)158*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<RefreshRateOverlay> RefreshRateOverlay::create(FpsRange range,
159*38e8c45fSAndroid Build Coastguard Worker ftl::Flags<Features> features) {
160*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<RefreshRateOverlay> overlay =
161*38e8c45fSAndroid Build Coastguard Worker std::make_unique<RefreshRateOverlay>(ConstructorTag{}, range, features);
162*38e8c45fSAndroid Build Coastguard Worker if (overlay->initCheck()) {
163*38e8c45fSAndroid Build Coastguard Worker return overlay;
164*38e8c45fSAndroid Build Coastguard Worker }
165*38e8c45fSAndroid Build Coastguard Worker
166*38e8c45fSAndroid Build Coastguard Worker ALOGE("%s: Failed to create RefreshRateOverlay", __func__);
167*38e8c45fSAndroid Build Coastguard Worker return {};
168*38e8c45fSAndroid Build Coastguard Worker }
169*38e8c45fSAndroid Build Coastguard Worker
RefreshRateOverlay(ConstructorTag,FpsRange fpsRange,ftl::Flags<Features> features)170*38e8c45fSAndroid Build Coastguard Worker RefreshRateOverlay::RefreshRateOverlay(ConstructorTag, FpsRange fpsRange,
171*38e8c45fSAndroid Build Coastguard Worker ftl::Flags<Features> features)
172*38e8c45fSAndroid Build Coastguard Worker : mFpsRange(fpsRange),
173*38e8c45fSAndroid Build Coastguard Worker mFeatures(features),
174*38e8c45fSAndroid Build Coastguard Worker mSurfaceControl(
175*38e8c45fSAndroid Build Coastguard Worker SurfaceControlHolder::createSurfaceControlHolder(String8("RefreshRateOverlay"))) {
176*38e8c45fSAndroid Build Coastguard Worker if (!mSurfaceControl) {
177*38e8c45fSAndroid Build Coastguard Worker ALOGE("%s: Failed to create buffer state layer", __func__);
178*38e8c45fSAndroid Build Coastguard Worker return;
179*38e8c45fSAndroid Build Coastguard Worker }
180*38e8c45fSAndroid Build Coastguard Worker
181*38e8c45fSAndroid Build Coastguard Worker createTransaction()
182*38e8c45fSAndroid Build Coastguard Worker .setLayer(mSurfaceControl->get(), INT32_MAX - 2)
183*38e8c45fSAndroid Build Coastguard Worker .setTrustedOverlay(mSurfaceControl->get(), true)
184*38e8c45fSAndroid Build Coastguard Worker .apply();
185*38e8c45fSAndroid Build Coastguard Worker }
186*38e8c45fSAndroid Build Coastguard Worker
initCheck() const187*38e8c45fSAndroid Build Coastguard Worker bool RefreshRateOverlay::initCheck() const {
188*38e8c45fSAndroid Build Coastguard Worker return mSurfaceControl != nullptr;
189*38e8c45fSAndroid Build Coastguard Worker }
190*38e8c45fSAndroid Build Coastguard Worker
getOrCreateBuffers(Fps refreshRate,Fps renderFps,bool idle)191*38e8c45fSAndroid Build Coastguard Worker auto RefreshRateOverlay::getOrCreateBuffers(Fps refreshRate, Fps renderFps, bool idle)
192*38e8c45fSAndroid Build Coastguard Worker -> const Buffers& {
193*38e8c45fSAndroid Build Coastguard Worker static const Buffers kNoBuffers;
194*38e8c45fSAndroid Build Coastguard Worker if (!mSurfaceControl) return kNoBuffers;
195*38e8c45fSAndroid Build Coastguard Worker
196*38e8c45fSAndroid Build Coastguard Worker // avoid caching different render rates if RenderRate is anyway not visible
197*38e8c45fSAndroid Build Coastguard Worker if (!mFeatures.test(Features::RenderRate)) {
198*38e8c45fSAndroid Build Coastguard Worker renderFps = 0_Hz;
199*38e8c45fSAndroid Build Coastguard Worker }
200*38e8c45fSAndroid Build Coastguard Worker
201*38e8c45fSAndroid Build Coastguard Worker const auto transformHint =
202*38e8c45fSAndroid Build Coastguard Worker static_cast<ui::Transform::RotationFlags>(mSurfaceControl->get()->getTransformHint());
203*38e8c45fSAndroid Build Coastguard Worker
204*38e8c45fSAndroid Build Coastguard Worker // Tell SurfaceFlinger about the pre-rotation on the buffer.
205*38e8c45fSAndroid Build Coastguard Worker const auto transform = [&] {
206*38e8c45fSAndroid Build Coastguard Worker switch (transformHint) {
207*38e8c45fSAndroid Build Coastguard Worker case ui::Transform::ROT_90:
208*38e8c45fSAndroid Build Coastguard Worker return ui::Transform::ROT_270;
209*38e8c45fSAndroid Build Coastguard Worker case ui::Transform::ROT_270:
210*38e8c45fSAndroid Build Coastguard Worker return ui::Transform::ROT_90;
211*38e8c45fSAndroid Build Coastguard Worker default:
212*38e8c45fSAndroid Build Coastguard Worker return ui::Transform::ROT_0;
213*38e8c45fSAndroid Build Coastguard Worker }
214*38e8c45fSAndroid Build Coastguard Worker }();
215*38e8c45fSAndroid Build Coastguard Worker
216*38e8c45fSAndroid Build Coastguard Worker createTransaction().setTransform(mSurfaceControl->get(), transform).apply();
217*38e8c45fSAndroid Build Coastguard Worker
218*38e8c45fSAndroid Build Coastguard Worker BufferCache::const_iterator it = mBufferCache.find(
219*38e8c45fSAndroid Build Coastguard Worker {refreshRate.getIntValue(), renderFps.getIntValue(), transformHint, idle});
220*38e8c45fSAndroid Build Coastguard Worker if (it == mBufferCache.end()) {
221*38e8c45fSAndroid Build Coastguard Worker const int maxFps = mFpsRange.max.getIntValue();
222*38e8c45fSAndroid Build Coastguard Worker
223*38e8c45fSAndroid Build Coastguard Worker // Clamp to supported refresh rate range: the current refresh rate may be outside of this
224*38e8c45fSAndroid Build Coastguard Worker // range if the display has changed its set of supported refresh rates.
225*38e8c45fSAndroid Build Coastguard Worker const int refreshIntFps = std::clamp(refreshRate.getIntValue(), 0, maxFps);
226*38e8c45fSAndroid Build Coastguard Worker const int renderIntFps = renderFps.getIntValue();
227*38e8c45fSAndroid Build Coastguard Worker const float fpsScale = static_cast<float>(refreshIntFps) / maxFps;
228*38e8c45fSAndroid Build Coastguard Worker
229*38e8c45fSAndroid Build Coastguard Worker constexpr SkColor kMinFpsColor = SK_ColorRED;
230*38e8c45fSAndroid Build Coastguard Worker constexpr SkColor kMaxFpsColor = SK_ColorGREEN;
231*38e8c45fSAndroid Build Coastguard Worker constexpr float kAlpha = 0.8f;
232*38e8c45fSAndroid Build Coastguard Worker
233*38e8c45fSAndroid Build Coastguard Worker SkColor4f colorBase = SkColor4f::FromColor(kMaxFpsColor) * fpsScale;
234*38e8c45fSAndroid Build Coastguard Worker const SkColor4f minFpsColor = SkColor4f::FromColor(kMinFpsColor) * (1 - fpsScale);
235*38e8c45fSAndroid Build Coastguard Worker
236*38e8c45fSAndroid Build Coastguard Worker colorBase.fR = colorBase.fR + minFpsColor.fR;
237*38e8c45fSAndroid Build Coastguard Worker colorBase.fG = colorBase.fG + minFpsColor.fG;
238*38e8c45fSAndroid Build Coastguard Worker colorBase.fB = colorBase.fB + minFpsColor.fB;
239*38e8c45fSAndroid Build Coastguard Worker colorBase.fA = kAlpha;
240*38e8c45fSAndroid Build Coastguard Worker
241*38e8c45fSAndroid Build Coastguard Worker const SkColor color = colorBase.toSkColor();
242*38e8c45fSAndroid Build Coastguard Worker
243*38e8c45fSAndroid Build Coastguard Worker auto buffers = draw(refreshIntFps, renderIntFps, idle, color, transformHint, mFeatures);
244*38e8c45fSAndroid Build Coastguard Worker it = mBufferCache
245*38e8c45fSAndroid Build Coastguard Worker .try_emplace({refreshIntFps, renderIntFps, transformHint, idle},
246*38e8c45fSAndroid Build Coastguard Worker std::move(buffers)).first;
247*38e8c45fSAndroid Build Coastguard Worker }
248*38e8c45fSAndroid Build Coastguard Worker
249*38e8c45fSAndroid Build Coastguard Worker return it->second;
250*38e8c45fSAndroid Build Coastguard Worker }
251*38e8c45fSAndroid Build Coastguard Worker
setViewport(ui::Size viewport)252*38e8c45fSAndroid Build Coastguard Worker void RefreshRateOverlay::setViewport(ui::Size viewport) {
253*38e8c45fSAndroid Build Coastguard Worker constexpr int32_t kMaxWidth = 1000;
254*38e8c45fSAndroid Build Coastguard Worker const auto width = std::min({kMaxWidth, viewport.width, viewport.height});
255*38e8c45fSAndroid Build Coastguard Worker const auto height = 2 * width;
256*38e8c45fSAndroid Build Coastguard Worker Rect frame((5 * width) >> 4, height >> 5);
257*38e8c45fSAndroid Build Coastguard Worker
258*38e8c45fSAndroid Build Coastguard Worker if (!mFeatures.test(Features::ShowInMiddle)) {
259*38e8c45fSAndroid Build Coastguard Worker frame.offsetBy(width >> 5, height >> 4);
260*38e8c45fSAndroid Build Coastguard Worker } else {
261*38e8c45fSAndroid Build Coastguard Worker frame.offsetBy(width >> 1, height >> 4);
262*38e8c45fSAndroid Build Coastguard Worker }
263*38e8c45fSAndroid Build Coastguard Worker
264*38e8c45fSAndroid Build Coastguard Worker createTransaction()
265*38e8c45fSAndroid Build Coastguard Worker .setMatrix(mSurfaceControl->get(), frame.getWidth() / static_cast<float>(kBufferWidth),
266*38e8c45fSAndroid Build Coastguard Worker 0, 0, frame.getHeight() / static_cast<float>(kBufferHeight))
267*38e8c45fSAndroid Build Coastguard Worker .setPosition(mSurfaceControl->get(), frame.left, frame.top)
268*38e8c45fSAndroid Build Coastguard Worker .apply();
269*38e8c45fSAndroid Build Coastguard Worker }
270*38e8c45fSAndroid Build Coastguard Worker
setLayerStack(ui::LayerStack stack)271*38e8c45fSAndroid Build Coastguard Worker void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
272*38e8c45fSAndroid Build Coastguard Worker createTransaction().setLayerStack(mSurfaceControl->get(), stack).apply();
273*38e8c45fSAndroid Build Coastguard Worker }
274*38e8c45fSAndroid Build Coastguard Worker
changeRefreshRate(Fps refreshRate,Fps renderFps)275*38e8c45fSAndroid Build Coastguard Worker void RefreshRateOverlay::changeRefreshRate(Fps refreshRate, Fps renderFps) {
276*38e8c45fSAndroid Build Coastguard Worker mRefreshRate = refreshRate;
277*38e8c45fSAndroid Build Coastguard Worker mRenderFps = renderFps;
278*38e8c45fSAndroid Build Coastguard Worker const auto buffer = getOrCreateBuffers(refreshRate, renderFps, mIsVrrIdle)[mFrame];
279*38e8c45fSAndroid Build Coastguard Worker createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
280*38e8c45fSAndroid Build Coastguard Worker }
281*38e8c45fSAndroid Build Coastguard Worker
onVrrIdle(bool idle)282*38e8c45fSAndroid Build Coastguard Worker void RefreshRateOverlay::onVrrIdle(bool idle) {
283*38e8c45fSAndroid Build Coastguard Worker mIsVrrIdle = idle;
284*38e8c45fSAndroid Build Coastguard Worker if (!mRefreshRate || !mRenderFps) return;
285*38e8c45fSAndroid Build Coastguard Worker
286*38e8c45fSAndroid Build Coastguard Worker const auto buffer = getOrCreateBuffers(*mRefreshRate, *mRenderFps, mIsVrrIdle)[mFrame];
287*38e8c45fSAndroid Build Coastguard Worker createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
288*38e8c45fSAndroid Build Coastguard Worker }
289*38e8c45fSAndroid Build Coastguard Worker
changeRenderRate(Fps renderFps)290*38e8c45fSAndroid Build Coastguard Worker void RefreshRateOverlay::changeRenderRate(Fps renderFps) {
291*38e8c45fSAndroid Build Coastguard Worker if (mFeatures.test(Features::RenderRate) && mRefreshRate &&
292*38e8c45fSAndroid Build Coastguard Worker FlagManager::getInstance().misc1()) {
293*38e8c45fSAndroid Build Coastguard Worker mRenderFps = renderFps;
294*38e8c45fSAndroid Build Coastguard Worker const auto buffer = getOrCreateBuffers(*mRefreshRate, renderFps, mIsVrrIdle)[mFrame];
295*38e8c45fSAndroid Build Coastguard Worker createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
296*38e8c45fSAndroid Build Coastguard Worker }
297*38e8c45fSAndroid Build Coastguard Worker }
298*38e8c45fSAndroid Build Coastguard Worker
animate()299*38e8c45fSAndroid Build Coastguard Worker void RefreshRateOverlay::animate() {
300*38e8c45fSAndroid Build Coastguard Worker if (!mFeatures.test(Features::Spinner) || !mRefreshRate) return;
301*38e8c45fSAndroid Build Coastguard Worker
302*38e8c45fSAndroid Build Coastguard Worker const auto& buffers = getOrCreateBuffers(*mRefreshRate, *mRenderFps, mIsVrrIdle);
303*38e8c45fSAndroid Build Coastguard Worker mFrame = (mFrame + 1) % buffers.size();
304*38e8c45fSAndroid Build Coastguard Worker const auto buffer = buffers[mFrame];
305*38e8c45fSAndroid Build Coastguard Worker createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply();
306*38e8c45fSAndroid Build Coastguard Worker }
307*38e8c45fSAndroid Build Coastguard Worker
createTransaction() const308*38e8c45fSAndroid Build Coastguard Worker SurfaceComposerClient::Transaction RefreshRateOverlay::createTransaction() const {
309*38e8c45fSAndroid Build Coastguard Worker constexpr float kFrameRate = 0.f;
310*38e8c45fSAndroid Build Coastguard Worker constexpr int8_t kCompatibility = ANATIVEWINDOW_FRAME_RATE_NO_VOTE;
311*38e8c45fSAndroid Build Coastguard Worker constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS;
312*38e8c45fSAndroid Build Coastguard Worker
313*38e8c45fSAndroid Build Coastguard Worker const sp<SurfaceControl>& surface = mSurfaceControl->get();
314*38e8c45fSAndroid Build Coastguard Worker
315*38e8c45fSAndroid Build Coastguard Worker SurfaceComposerClient::Transaction transaction;
316*38e8c45fSAndroid Build Coastguard Worker if (isSetByHwc()) {
317*38e8c45fSAndroid Build Coastguard Worker transaction.setFlags(surface, layer_state_t::eLayerIsRefreshRateIndicator,
318*38e8c45fSAndroid Build Coastguard Worker layer_state_t::eLayerIsRefreshRateIndicator);
319*38e8c45fSAndroid Build Coastguard Worker // Disable overlay layer caching when refresh rate is updated by the HWC.
320*38e8c45fSAndroid Build Coastguard Worker transaction.setCachingHint(surface, gui::CachingHint::Disabled);
321*38e8c45fSAndroid Build Coastguard Worker }
322*38e8c45fSAndroid Build Coastguard Worker transaction.setFrameRate(surface, kFrameRate, kCompatibility, kSeamlessness);
323*38e8c45fSAndroid Build Coastguard Worker return transaction;
324*38e8c45fSAndroid Build Coastguard Worker }
325*38e8c45fSAndroid Build Coastguard Worker
326*38e8c45fSAndroid Build Coastguard Worker } // namespace android
327