blob: 2c0f5180cc3af2b9e623b389d87d9d519199440d [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// #define LOG_NDEBUG 0
17#include <algorithm>
18
19#include "HdrSdrRatioOverlay.h"
20
21#include <SkSurface.h>
22
23#undef LOG_TAG
24#define LOG_TAG "HdrSdrRatioOverlay"
25
26namespace android {
27
28void HdrSdrRatioOverlay::drawNumber(float number, int left, SkColor color, SkCanvas& canvas) {
29 if (!isfinite(number) || number >= 10.f) return;
30 // We assume that the number range is [1.f, 10.f)
31 // and the decimal places are 2.
32 int value = static_cast<int>(number * 100);
33 SegmentDrawer::drawDigit(value / 100, left, color, canvas);
34
35 left += kDigitWidth + kDigitSpace;
36 SegmentDrawer::drawSegment(SegmentDrawer::Segment::DecimalPoint, left, color, canvas);
37 left += kDigitWidth + kDigitSpace;
38
39 SegmentDrawer::drawDigit((value / 10) % 10, left, color, canvas);
40 left += kDigitWidth + kDigitSpace;
41 SegmentDrawer::drawDigit(value % 10, left, color, canvas);
42}
43
44sp<GraphicBuffer> HdrSdrRatioOverlay::draw(float currentHdrSdrRatio, SkColor color,
45 ui::Transform::RotationFlags rotation) {
46 SkMatrix canvasTransform = SkMatrix();
47 const auto [bufferWidth, bufferHeight] = [&]() -> std::pair<int, int> {
48 switch (rotation) {
49 case ui::Transform::ROT_90:
50 canvasTransform.setTranslate(kBufferHeight, 0);
51 canvasTransform.preRotate(90.f);
52 return {kBufferHeight, kBufferWidth};
53 case ui::Transform::ROT_270:
54 canvasTransform.setRotate(270.f, kBufferWidth / 2.f, kBufferWidth / 2.f);
55 return {kBufferHeight, kBufferWidth};
56 default:
57 return {kBufferWidth, kBufferHeight};
58 }
59 }();
60
61 const auto kUsageFlags = static_cast<uint64_t>(
62 GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE);
63 sp<GraphicBuffer> buffer =
64 sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth),
65 static_cast<uint32_t>(bufferHeight), HAL_PIXEL_FORMAT_RGBA_8888,
66 1u, kUsageFlags, "HdrSdrRatioOverlay");
67
68 const status_t bufferStatus = buffer->initCheck();
69 LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "HdrSdrRatioOverlay: Buffer failed to allocate: %d",
70 bufferStatus);
71
72 sk_sp<SkSurface> surface =
73 SkSurfaces::Raster(SkImageInfo::MakeN32Premul(bufferWidth, bufferHeight));
74 SkCanvas* canvas = surface->getCanvas();
75 canvas->setMatrix(canvasTransform);
76
77 drawNumber(currentHdrSdrRatio, 0, color, *canvas);
78
79 void* pixels = nullptr;
80 buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
81
82 const SkImageInfo& imageInfo = surface->imageInfo();
83 const size_t dstRowBytes = buffer->getStride() * static_cast<size_t>(imageInfo.bytesPerPixel());
84
85 canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0);
86 buffer->unlock();
87 return buffer;
88}
89
90HdrSdrRatioOverlay::HdrSdrRatioOverlay()
91 : mSurfaceControl(
92 SurfaceControlHolder::createSurfaceControlHolder(String8("HdrSdrRatioOverlay"))) {
93 if (!mSurfaceControl) {
94 ALOGE("%s: Failed to create buffer state layer", __func__);
95 return;
96 }
97 SurfaceComposerClient::Transaction()
98 .setLayer(mSurfaceControl->get(), INT32_MAX - 2)
99 .setTrustedOverlay(mSurfaceControl->get(), true)
100 .apply();
101}
102
103void HdrSdrRatioOverlay::changeHdrSdrRatio(float currentHdrSdrRatio) {
104 mCurrentHdrSdrRatio = currentHdrSdrRatio;
105 animate();
106}
107
108void HdrSdrRatioOverlay::setLayerStack(ui::LayerStack stack) {
109 SurfaceComposerClient::Transaction().setLayerStack(mSurfaceControl->get(), stack).apply();
110}
111
112void HdrSdrRatioOverlay::setViewport(ui::Size viewport) {
113 constexpr int32_t kMaxWidth = 1000;
114 const auto width = std::min({kMaxWidth, viewport.width, viewport.height});
115 const auto height = 2 * width;
116 Rect frame((5 * width) >> 4, height >> 5);
117 // set the ratio frame to the top right of the screen
118 frame.offsetBy(viewport.width - frame.width(), height >> 4);
119
120 SurfaceComposerClient::Transaction()
121 .setMatrix(mSurfaceControl->get(), frame.getWidth() / static_cast<float>(kBufferWidth),
122 0, 0, frame.getHeight() / static_cast<float>(kBufferHeight))
123 .setPosition(mSurfaceControl->get(), frame.left, frame.top)
124 .apply();
125}
126
127auto HdrSdrRatioOverlay::getOrCreateBuffers(float currentHdrSdrRatio) -> const sp<GraphicBuffer> {
128 static const sp<GraphicBuffer> kNoBuffer;
129 if (!mSurfaceControl) return kNoBuffer;
130
131 const auto transformHint =
132 static_cast<ui::Transform::RotationFlags>(mSurfaceControl->get()->getTransformHint());
133
134 // Tell SurfaceFlinger about the pre-rotation on the buffer.
135 const auto transform = [&] {
136 switch (transformHint) {
137 case ui::Transform::ROT_90:
138 return ui::Transform::ROT_270;
139 case ui::Transform::ROT_270:
140 return ui::Transform::ROT_90;
141 default:
142 return ui::Transform::ROT_0;
143 }
144 }();
145
146 SurfaceComposerClient::Transaction().setTransform(mSurfaceControl->get(), transform).apply();
147
148 constexpr SkColor kMinRatioColor = SK_ColorBLUE;
149 constexpr SkColor kMaxRatioColor = SK_ColorGREEN;
150 constexpr float kAlpha = 0.8f;
151
152 // 9.f is picked here as ratio range, given that we assume that
153 // hdr/sdr ratio is [1.f, 10.f)
154 const float scale = currentHdrSdrRatio / 9.f;
155
156 SkColor4f colorBase = SkColor4f::FromColor(kMaxRatioColor) * scale;
157 const SkColor4f minRatioColor = SkColor4f::FromColor(kMinRatioColor) * (1 - scale);
158
159 colorBase.fR = colorBase.fR + minRatioColor.fR;
160 colorBase.fG = colorBase.fG + minRatioColor.fG;
161 colorBase.fB = colorBase.fB + minRatioColor.fB;
162 colorBase.fA = kAlpha;
163
164 const SkColor color = colorBase.toSkColor();
165
166 auto buffer = draw(currentHdrSdrRatio, color, transformHint);
167 return buffer;
168}
169
170void HdrSdrRatioOverlay::animate() {
171 if (!std::isfinite(mCurrentHdrSdrRatio) || mCurrentHdrSdrRatio < 1.0f) return;
172
173 SurfaceComposerClient::Transaction()
174 .setBuffer(mSurfaceControl->get(), getOrCreateBuffers(mCurrentHdrSdrRatio))
175 .apply();
176}
177
178} // namespace android