diff options
Diffstat (limited to 'services/surfaceflinger/RefreshRateOverlay.cpp')
| -rw-r--r-- | services/surfaceflinger/RefreshRateOverlay.cpp | 181 |
1 files changed, 171 insertions, 10 deletions
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 5b4bec96ea..f602412930 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -14,32 +14,152 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + #include "RefreshRateOverlay.h" #include "Client.h" #include "Layer.h" +#include <gui/IProducerListener.h> + +#undef LOG_TAG +#define LOG_TAG "RefreshRateOverlay" + namespace android { -using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; +void RefreshRateOverlay::SevenSegmentDrawer::drawRect(const Rect& r, const half4& color, + const sp<GraphicBuffer>& buffer, + uint8_t* pixels) { + for (int32_t j = r.top; j < r.bottom; j++) { + if (j >= buffer->getHeight()) { + break; + } + + for (int32_t i = r.left; i < r.right; i++) { + if (i >= buffer->getWidth()) { + break; + } + + uint8_t* iter = pixels + 4 * (i + (buffer->getStride() * j)); + iter[0] = uint8_t(color.r * 255); + iter[1] = uint8_t(color.g * 255); + iter[2] = uint8_t(color.b * 255); + iter[3] = uint8_t(color.a * 255); + } + } +} + +void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, + const half4& color, + const sp<GraphicBuffer>& buffer, + uint8_t* pixels) { + const Rect rect = [&]() { + switch (segment) { + case Segment::Upper: + return Rect(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE); + case Segment::UpperLeft: + return Rect(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2); + case Segment::UpperRight: + return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH, + DIGIT_HEIGHT / 2); + case Segment::Middle: + return Rect(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2, left + DIGIT_WIDTH, + DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2); + case Segment::LowerLeft: + return Rect(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT); + case Segment::LowerRight: + return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2, left + DIGIT_WIDTH, + DIGIT_HEIGHT); + case Segment::Buttom: + return Rect(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH, DIGIT_HEIGHT); + } + }(); + + drawRect(rect, color, buffer, pixels); +} + +void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, const half4& color, + const sp<GraphicBuffer>& buffer, + uint8_t* pixels) { + if (digit < 0 || digit > 9) return; + + if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 || + digit == 8 || digit == 9) + drawSegment(Segment::Upper, left, color, buffer, pixels); + if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9) + drawSegment(Segment::UpperLeft, left, color, buffer, pixels); + if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 || + digit == 8 || digit == 9) + drawSegment(Segment::UpperRight, left, color, buffer, pixels); + if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || + digit == 9) + drawSegment(Segment::Middle, left, color, buffer, pixels); + if (digit == 0 || digit == 2 || digit == 6 || digit == 8) + drawSegment(Segment::LowerLeft, left, color, buffer, pixels); + if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || + digit == 7 || digit == 8 || digit == 9) + drawSegment(Segment::LowerRight, left, color, buffer, pixels); + if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 || + digit == 9) + drawSegment(Segment::Buttom, left, color, buffer, pixels); +} + +sp<GraphicBuffer> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number, + const half4& color) { + if (number < 0 || number > 1000) return nullptr; + + 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); + left += DIGIT_WIDTH + DIGIT_SPACE; + } + + if (tens != 0) { + drawDigit(tens, left, color, buffer, pixels); + left += DIGIT_WIDTH + DIGIT_SPACE; + } + + drawDigit(ones, left, color, buffer, pixels); + buffer->unlock(); + return buffer; +} RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger) : mFlinger(flinger), mClient(new Client(&mFlinger)) { createLayer(); + primeCache(); } bool RefreshRateOverlay::createLayer() { const status_t ret = - mFlinger.createLayer(String8("RefreshRateOverlay"), mClient, 0, 0, - PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor, - LayerMetadata(), &mIBinder, &mGbp, nullptr); + mFlinger.createLayer(String8("RefreshRateOverlay"), mClient, + SevenSegmentDrawer::getWidth(), SevenSegmentDrawer::getHeight(), + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, LayerMetadata(), + &mIBinder, &mGbp, nullptr); if (ret) { - ALOGE("failed to create color layer"); + ALOGE("failed to create buffer state layer"); return false; } Mutex::Autolock _l(mFlinger.mStateLock); mLayer = mClient->getLayerUser(mIBinder); - mLayer->setCrop_legacy(Rect(50, 70, 200, 100), true); + mLayer->setFrameRate(Layer::FrameRate(0, Layer::FrameRateCompatibility::NoVote)); // setting Layer's Z requires resorting layersSortedByZ ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer); @@ -51,10 +171,51 @@ bool RefreshRateOverlay::createLayer() { return true; } -void RefreshRateOverlay::changeRefreshRate(RefreshRateType type) { - const half3& color = (type == RefreshRateType::PERFORMANCE) ? GREEN : RED; - mLayer->setColor(color); +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); + 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)); + } +} + +void RefreshRateOverlay::setViewport(ui::Size viewport) { + Rect frame(viewport.width >> 3, viewport.height >> 5); + frame.offsetBy(viewport.width >> 5, viewport.height >> 4); + mLayer->setFrame(frame); + + mFlinger.mTransactionFlags.fetch_or(eTransactionMask); +} + +void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) { + auto buffer = mBufferCache[refreshRate.getFps()]; + mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {}); + mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } -}; // namespace android +} // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" |