1 /** 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 17 // #define LOG_NDEBUG 0 18 #pragma once 19 20 #include "BackgroundExecutor.h" 21 22 #pragma clang diagnostic push 23 #pragma clang diagnostic ignored "-Wconversion" 24 #include <SkCanvas.h> 25 #include <SkPaint.h> 26 #pragma clang diagnostic pop 27 28 #include <gui/SurfaceComposerClient.h> 29 #include <utils/StrongPointer.h> 30 31 namespace android { 32 33 inline constexpr int kDigitWidth = 64; 34 inline constexpr int kDigitHeight = 100; 35 inline constexpr int kDigitSpace = 16; 36 37 // HdrSdrRatioOverlay re-uses this value though it doesn't really need such amount buffer. 38 // for output good-looking and code conciseness. 39 inline constexpr int kMaxDigits = /*displayFps*/ 3 + /*renderFps*/ 3 + /*spinner*/ 1; 40 inline constexpr int kBufferWidth = kMaxDigits * kDigitWidth + (kMaxDigits - 1) * kDigitSpace; 41 inline constexpr int kBufferHeight = kDigitHeight; 42 43 class SurfaceControl; 44 45 // Helper class to delete the SurfaceControl on a helper thread as 46 // SurfaceControl assumes its destruction happens without SurfaceFlinger::mStateLock held. 47 class SurfaceControlHolder { 48 public: SurfaceControlHolder(sp<SurfaceControl> sc)49 explicit SurfaceControlHolder(sp<SurfaceControl> sc) : mSurfaceControl(std::move(sc)){}; 50 ~SurfaceControlHolder()51 ~SurfaceControlHolder() { 52 // Hand the sp<SurfaceControl> to the helper thread to release the last 53 // reference. This makes sure that the SurfaceControl is destructed without 54 // SurfaceFlinger::mStateLock held. 55 BackgroundExecutor::getInstance().sendCallbacks( 56 {[sc = std::move(mSurfaceControl)]() mutable { sc.clear(); }}); 57 } 58 createSurfaceControlHolder(const String8 & name)59 static std::unique_ptr<SurfaceControlHolder> createSurfaceControlHolder(const String8& name) { 60 sp<SurfaceControl> surfaceControl = 61 SurfaceComposerClient::getDefault() 62 ->createSurface(name, kBufferWidth, kBufferHeight, PIXEL_FORMAT_RGBA_8888, 63 ISurfaceComposerClient::eFXSurfaceBufferState); 64 return std::make_unique<SurfaceControlHolder>(std::move(surfaceControl)); 65 } 66 get()67 const sp<SurfaceControl>& get() const { return mSurfaceControl; } 68 69 private: 70 sp<SurfaceControl> mSurfaceControl; 71 }; 72 73 // Helper class to draw digit and decimal point. 74 class SegmentDrawer { 75 public: 76 enum class Segment { 77 Upper, 78 UpperLeft, 79 UpperRight, 80 Middle, 81 LowerLeft, 82 LowerRight, 83 Bottom, 84 DecimalPoint 85 }; drawSegment(Segment segment,int left,SkColor color,SkCanvas & canvas)86 static void drawSegment(Segment segment, int left, SkColor color, SkCanvas& canvas) { 87 const SkRect rect = [&]() { 88 switch (segment) { 89 case Segment::Upper: 90 return SkRect::MakeLTRB(left, 0, left + kDigitWidth, kDigitSpace); 91 case Segment::UpperLeft: 92 return SkRect::MakeLTRB(left, 0, left + kDigitSpace, kDigitHeight / 2.); 93 case Segment::UpperRight: 94 return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, 0, left + kDigitWidth, 95 kDigitHeight / 2.); 96 case Segment::Middle: 97 return SkRect::MakeLTRB(left, kDigitHeight / 2. - kDigitSpace / 2., 98 left + kDigitWidth, 99 kDigitHeight / 2. + kDigitSpace / 2.); 100 case Segment::LowerLeft: 101 return SkRect::MakeLTRB(left, kDigitHeight / 2., left + kDigitSpace, 102 kDigitHeight); 103 case Segment::LowerRight: 104 return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, kDigitHeight / 2., 105 left + kDigitWidth, kDigitHeight); 106 case Segment::Bottom: 107 return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitWidth, 108 kDigitHeight); 109 case Segment::DecimalPoint: 110 return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitSpace, 111 kDigitHeight); 112 } 113 }(); 114 115 SkPaint paint; 116 paint.setColor(color); 117 paint.setBlendMode(SkBlendMode::kSrc); 118 canvas.drawRect(rect, paint); 119 } 120 drawDigit(int digit,int left,SkColor color,SkCanvas & canvas)121 static void drawDigit(int digit, int left, SkColor color, SkCanvas& canvas) { 122 if (digit < 0 || digit > 9) return; 123 124 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 || 125 digit == 8 || digit == 9) 126 drawSegment(Segment::Upper, left, color, canvas); 127 if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9) 128 drawSegment(Segment::UpperLeft, left, color, canvas); 129 if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 || 130 digit == 8 || digit == 9) 131 drawSegment(Segment::UpperRight, left, color, canvas); 132 if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || 133 digit == 9) 134 drawSegment(Segment::Middle, left, color, canvas); 135 if (digit == 0 || digit == 2 || digit == 6 || digit == 8) 136 drawSegment(Segment::LowerLeft, left, color, canvas); 137 if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || 138 digit == 7 || digit == 8 || digit == 9) 139 drawSegment(Segment::LowerRight, left, color, canvas); 140 if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 || 141 digit == 9) 142 drawSegment(Segment::Bottom, left, color, canvas); 143 } 144 }; 145 146 } // namespace android 147