Add new SF backdoor option: hdr/sdr ratio overlay
- follow how RefreshRateOverlay did in general.
- 1043 as new opcode to enable hdr/sdr ratio overlay.
- decouple SevenSegmentDrawer and SurfaceControlHandle helper classes
from RefreshRateOverlay.
- add corresponding SF backdoor test for validation.
- for non-HDR-supported device, we don't reject them to use SF backdoor
but 1.00 will be always shown on the screen if enabling.
Test: adb shell call service call SurfaceFlinger 1043 1; atest
SurfaceFlinger_test
Bug: 277957056
Change-Id: Ifce2d435f127b53ab9d01aba4e24ffd4fdb010a7
diff --git a/services/surfaceflinger/Utils/OverlayUtils.h b/services/surfaceflinger/Utils/OverlayUtils.h
new file mode 100644
index 0000000..0ef0be1
--- /dev/null
+++ b/services/surfaceflinger/Utils/OverlayUtils.h
@@ -0,0 +1,146 @@
+/**
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#pragma once
+
+#include "BackgroundExecutor.h"
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#include <SkCanvas.h>
+#include <SkPaint.h>
+#pragma clang diagnostic pop
+
+#include <gui/SurfaceComposerClient.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+inline constexpr int kDigitWidth = 64;
+inline constexpr int kDigitHeight = 100;
+inline constexpr int kDigitSpace = 16;
+
+// HdrSdrRatioOverlay re-uses this value though it doesn't really need such amount buffer.
+// for output good-looking and code conciseness.
+inline constexpr int kMaxDigits = /*displayFps*/ 3 + /*renderFps*/ 3 + /*spinner*/ 1;
+inline constexpr int kBufferWidth = kMaxDigits * kDigitWidth + (kMaxDigits - 1) * kDigitSpace;
+inline constexpr int kBufferHeight = kDigitHeight;
+
+class SurfaceControl;
+
+// Helper class to delete the SurfaceControl on a helper thread as
+// SurfaceControl assumes its destruction happens without SurfaceFlinger::mStateLock held.
+class SurfaceControlHolder {
+public:
+ explicit SurfaceControlHolder(sp<SurfaceControl> sc) : mSurfaceControl(std::move(sc)){};
+
+ ~SurfaceControlHolder() {
+ // Hand the sp<SurfaceControl> to the helper thread to release the last
+ // reference. This makes sure that the SurfaceControl is destructed without
+ // SurfaceFlinger::mStateLock held.
+ BackgroundExecutor::getInstance().sendCallbacks(
+ {[sc = std::move(mSurfaceControl)]() mutable { sc.clear(); }});
+ }
+
+ static std::unique_ptr<SurfaceControlHolder> createSurfaceControlHolder(const String8& name) {
+ sp<SurfaceControl> surfaceControl =
+ SurfaceComposerClient::getDefault()
+ ->createSurface(name, kBufferWidth, kBufferHeight, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+ return std::make_unique<SurfaceControlHolder>(std::move(surfaceControl));
+ }
+
+ const sp<SurfaceControl>& get() const { return mSurfaceControl; }
+
+private:
+ sp<SurfaceControl> mSurfaceControl;
+};
+
+// Helper class to draw digit and decimal point.
+class SegmentDrawer {
+public:
+ enum class Segment {
+ Upper,
+ UpperLeft,
+ UpperRight,
+ Middle,
+ LowerLeft,
+ LowerRight,
+ Bottom,
+ DecimalPoint
+ };
+ static void drawSegment(Segment segment, int left, SkColor color, SkCanvas& canvas) {
+ const SkRect rect = [&]() {
+ switch (segment) {
+ case Segment::Upper:
+ return SkRect::MakeLTRB(left, 0, left + kDigitWidth, kDigitSpace);
+ case Segment::UpperLeft:
+ return SkRect::MakeLTRB(left, 0, left + kDigitSpace, kDigitHeight / 2.);
+ case Segment::UpperRight:
+ return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, 0, left + kDigitWidth,
+ kDigitHeight / 2.);
+ case Segment::Middle:
+ return SkRect::MakeLTRB(left, kDigitHeight / 2. - kDigitSpace / 2.,
+ left + kDigitWidth,
+ kDigitHeight / 2. + kDigitSpace / 2.);
+ case Segment::LowerLeft:
+ return SkRect::MakeLTRB(left, kDigitHeight / 2., left + kDigitSpace,
+ kDigitHeight);
+ case Segment::LowerRight:
+ return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, kDigitHeight / 2.,
+ left + kDigitWidth, kDigitHeight);
+ case Segment::Bottom:
+ return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitWidth,
+ kDigitHeight);
+ case Segment::DecimalPoint:
+ return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitSpace,
+ kDigitHeight);
+ }
+ }();
+
+ SkPaint paint;
+ paint.setColor(color);
+ paint.setBlendMode(SkBlendMode::kSrc);
+ canvas.drawRect(rect, paint);
+ }
+
+ static void drawDigit(int digit, int left, SkColor color, SkCanvas& canvas) {
+ 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, canvas);
+ if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
+ drawSegment(Segment::UpperLeft, left, color, canvas);
+ if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
+ digit == 8 || digit == 9)
+ drawSegment(Segment::UpperRight, left, color, canvas);
+ if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
+ digit == 9)
+ drawSegment(Segment::Middle, left, color, canvas);
+ if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
+ drawSegment(Segment::LowerLeft, left, color, canvas);
+ if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
+ digit == 7 || digit == 8 || digit == 9)
+ drawSegment(Segment::LowerRight, left, color, canvas);
+ if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
+ digit == 9)
+ drawSegment(Segment::Bottom, left, color, canvas);
+ }
+};
+
+} // namespace android