summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/RefreshRateOverlay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/RefreshRateOverlay.cpp')
-rw-r--r--services/surfaceflinger/RefreshRateOverlay.cpp185
1 files changed, 128 insertions, 57 deletions
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index f602412930..27a1c280fb 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -17,6 +17,9 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
+
+#include <algorithm>
#include "RefreshRateOverlay.h"
#include "Client.h"
@@ -106,52 +109,86 @@ void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, cons
drawSegment(Segment::Buttom, left, color, buffer, pixels);
}
-sp<GraphicBuffer> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number,
- const half4& color) {
- if (number < 0 || number > 1000) return nullptr;
+std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(
+ int number, const half4& color, bool showSpinner) {
+ if (number < 0 || number > 1000) return {};
const auto hundreds = number / 100;
const auto tens = (number / 10) % 10;
const auto ones = number % 10;
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
- GRALLOC_USAGE_HW_TEXTURE,
- "RefreshRateOverlayBuffer");
- uint8_t* pixels;
- buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
- // Clear buffer content
- drawRect(Rect(BUFFER_WIDTH, BUFFER_HEIGHT), half4(0), buffer, pixels);
- int left = 0;
- if (hundreds != 0) {
- drawDigit(hundreds, left, color, buffer, pixels);
+ std::vector<sp<GraphicBuffer>> buffers;
+ const auto loopCount = showSpinner ? 6 : 1;
+ for (int i = 0; i < loopCount; i++) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "RefreshRateOverlayBuffer");
+ const status_t bufferStatus = buffer->initCheck();
+ LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
+ bufferStatus);
+ uint8_t* pixels;
+ buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
+ // Clear buffer content
+ drawRect(Rect(BUFFER_WIDTH, BUFFER_HEIGHT), half4(0), buffer, pixels);
+ int left = 0;
+ if (hundreds != 0) {
+ drawDigit(hundreds, left, color, buffer, pixels);
+ }
left += DIGIT_WIDTH + DIGIT_SPACE;
- }
- if (tens != 0) {
- drawDigit(tens, left, color, buffer, pixels);
+ if (tens != 0) {
+ drawDigit(tens, left, color, buffer, pixels);
+ }
left += DIGIT_WIDTH + DIGIT_SPACE;
- }
- drawDigit(ones, left, color, buffer, pixels);
- buffer->unlock();
- return buffer;
+ drawDigit(ones, left, color, buffer, pixels);
+ left += DIGIT_WIDTH + DIGIT_SPACE;
+
+ if (showSpinner) {
+ switch (i) {
+ case 0:
+ drawSegment(Segment::Upper, left, color, buffer, pixels);
+ break;
+ case 1:
+ drawSegment(Segment::UpperRight, left, color, buffer, pixels);
+ break;
+ case 2:
+ drawSegment(Segment::LowerRight, left, color, buffer, pixels);
+ break;
+ case 3:
+ drawSegment(Segment::Buttom, left, color, buffer, pixels);
+ break;
+ case 4:
+ drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
+ break;
+ case 5:
+ drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
+ break;
+ }
+ }
+
+ buffer->unlock();
+ buffers.emplace_back(buffer);
+ }
+ return buffers;
}
-RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger)
- : mFlinger(flinger), mClient(new Client(&mFlinger)) {
+RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, bool showSpinner)
+ : mFlinger(flinger), mClient(new Client(&mFlinger)), mShowSpinner(showSpinner) {
createLayer();
- primeCache();
+ reset();
}
bool RefreshRateOverlay::createLayer() {
+ int32_t layerId;
const status_t ret =
mFlinger.createLayer(String8("RefreshRateOverlay"), mClient,
SevenSegmentDrawer::getWidth(), SevenSegmentDrawer::getHeight(),
PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceBufferState, LayerMetadata(),
- &mIBinder, &mGbp, nullptr);
+ &mIBinder, &mGbp, nullptr, &layerId);
if (ret) {
ALOGE("failed to create buffer state layer");
return false;
@@ -159,63 +196,97 @@ bool RefreshRateOverlay::createLayer() {
Mutex::Autolock _l(mFlinger.mStateLock);
mLayer = mClient->getLayerUser(mIBinder);
- mLayer->setFrameRate(Layer::FrameRate(0, Layer::FrameRateCompatibility::NoVote));
+ mLayer->setFrameRate(Layer::FrameRate(Fps(0.0f), Layer::FrameRateCompatibility::NoVote));
+ mLayer->setIsAtRoot(true);
// setting Layer's Z requires resorting layersSortedByZ
- ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
+ ssize_t idx = mFlinger.mDrawingState.layersSortedByZ.indexOf(mLayer);
if (mLayer->setLayer(INT32_MAX - 2) && idx >= 0) {
- mFlinger.mCurrentState.layersSortedByZ.removeAt(idx);
- mFlinger.mCurrentState.layersSortedByZ.add(mLayer);
+ mFlinger.mDrawingState.layersSortedByZ.removeAt(idx);
+ mFlinger.mDrawingState.layersSortedByZ.add(mLayer);
}
return true;
}
-void RefreshRateOverlay::primeCache() {
- auto& allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates();
- if (allRefreshRates.size() == 1) {
- auto fps = allRefreshRates.begin()->second->getFps();
- half4 color = {LOW_FPS_COLOR, ALPHA};
- mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
- return;
- }
-
- std::vector<uint32_t> supportedFps;
- supportedFps.reserve(allRefreshRates.size());
- for (auto& [ignored, refreshRate] : allRefreshRates) {
- supportedFps.push_back(refreshRate->getFps());
- }
-
- std::sort(supportedFps.begin(), supportedFps.end());
- const auto mLowFps = supportedFps[0];
- const auto mHighFps = supportedFps[supportedFps.size() - 1];
- for (auto fps : supportedFps) {
- const auto fpsScale = float(fps - mLowFps) / (mHighFps - mLowFps);
+const std::vector<std::shared_ptr<renderengine::ExternalTexture>>&
+RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
+ if (mBufferCache.find(fps) == mBufferCache.end()) {
+ // Ensure the range is > 0, so we don't divide by 0.
+ const auto rangeLength = std::max(1u, mHighFps - mLowFps);
+ // Clip values outside the range [mLowFps, mHighFps]. The current fps may be outside
+ // of this range if the display has changed its set of supported refresh rates.
+ fps = std::max(fps, mLowFps);
+ fps = std::min(fps, mHighFps);
+ const auto fpsScale = static_cast<float>(fps - mLowFps) / rangeLength;
half4 color;
color.r = HIGH_FPS_COLOR.r * fpsScale + LOW_FPS_COLOR.r * (1 - fpsScale);
color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale);
color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale);
color.a = ALPHA;
- mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
+ auto buffers = SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner);
+ std::vector<std::shared_ptr<renderengine::ExternalTexture>> textures;
+ std::transform(buffers.begin(), buffers.end(), std::back_inserter(textures),
+ [&](const auto& buffer) -> std::shared_ptr<renderengine::ExternalTexture> {
+ return std::make_shared<
+ renderengine::ExternalTexture>(buffer,
+ mFlinger.getRenderEngine(),
+ renderengine::ExternalTexture::
+ Usage::READABLE);
+ });
+ mBufferCache.emplace(fps, textures);
}
+
+ return mBufferCache[fps];
}
void RefreshRateOverlay::setViewport(ui::Size viewport) {
- Rect frame(viewport.width >> 3, viewport.height >> 5);
+ Rect frame((3 * viewport.width) >> 4, viewport.height >> 5);
frame.offsetBy(viewport.width >> 5, viewport.height >> 4);
- mLayer->setFrame(frame);
+ layer_state_t::matrix22_t matrix;
+ matrix.dsdx = frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth());
+ matrix.dtdx = 0;
+ matrix.dtdy = 0;
+ matrix.dsdy = frame.getHeight() / static_cast<float>(SevenSegmentDrawer::getHeight());
+ mLayer->setMatrix(matrix, true);
+ mLayer->setPosition(frame.left, frame.top);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
-void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
- auto buffer = mBufferCache[refreshRate.getFps()];
- mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {});
+void RefreshRateOverlay::changeRefreshRate(const Fps& fps) {
+ mCurrentFps = fps.getIntValue();
+ auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
+ mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
+ mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
+ std::nullopt /* dequeueTime */, FrameTimelineInfo{},
+ nullptr /* releaseBufferListener */);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
+void RefreshRateOverlay::onInvalidate() {
+ if (!mCurrentFps.has_value()) return;
+
+ const auto& buffers = getOrCreateBuffers(*mCurrentFps);
+ mFrame = (mFrame + 1) % buffers.size();
+ auto buffer = buffers[mFrame];
+ mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
+ mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
+ std::nullopt /* dequeueTime */, FrameTimelineInfo{},
+ nullptr /* releaseBufferListener */);
+
+ mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
+}
+
+void RefreshRateOverlay::reset() {
+ mBufferCache.clear();
+ const auto range = mFlinger.mRefreshRateConfigs->getSupportedRefreshRateRange();
+ mLowFps = range.min.getIntValue();
+ mHighFps = range.max.getIntValue();
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"