| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright 2020 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 | #pragma once | 
 | 18 |  | 
| Dominik Laskowski | f6b4ba6 | 2021-11-09 12:46:10 -0800 | [diff] [blame] | 19 | #include <cstddef> | 
 | 20 | #include <memory> | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 21 |  | 
| Marin Shalamanov | 5801c94 | 2020-12-17 17:00:13 +0100 | [diff] [blame] | 22 | #include <android-base/stringprintf.h> | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 23 | #include <android/configuration.h> | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 24 | #include <ftl/small_map.h> | 
| Ady Abraham | 5e7ee86 | 2021-06-23 17:43:41 -0700 | [diff] [blame] | 25 | #include <ui/DisplayId.h> | 
| Marin Shalamanov | 228f46b | 2021-01-28 21:11:45 +0100 | [diff] [blame] | 26 | #include <ui/DisplayMode.h> | 
| Marin Shalamanov | 045b700 | 2021-01-07 16:56:24 +0100 | [diff] [blame] | 27 | #include <ui/Size.h> | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 28 | #include <utils/Timers.h> | 
 | 29 |  | 
| Dominik Laskowski | f6b4ba6 | 2021-11-09 12:46:10 -0800 | [diff] [blame] | 30 | #include <scheduler/Fps.h> | 
 | 31 |  | 
 | 32 | #include "DisplayHardware/Hal.h" | 
 | 33 | #include "Scheduler/StrongTyping.h" | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 34 |  | 
 | 35 | namespace android { | 
 | 36 |  | 
 | 37 | namespace hal = android::hardware::graphics::composer::hal; | 
 | 38 |  | 
 | 39 | class DisplayMode; | 
 | 40 | using DisplayModePtr = std::shared_ptr<const DisplayMode>; | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 41 |  | 
 | 42 | // Prevent confusion with fps_approx_ops on the underlying Fps. | 
 | 43 | bool operator<(const DisplayModePtr&, const DisplayModePtr&) = delete; | 
 | 44 | bool operator>(const DisplayModePtr&, const DisplayModePtr&) = delete; | 
 | 45 | bool operator<=(const DisplayModePtr&, const DisplayModePtr&) = delete; | 
 | 46 | bool operator>=(const DisplayModePtr&, const DisplayModePtr&) = delete; | 
 | 47 |  | 
 | 48 | using DisplayModeId = StrongTyping<ui::DisplayModeId, struct DisplayModeIdTag, Compare>; | 
 | 49 |  | 
 | 50 | using DisplayModes = ftl::SmallMap<DisplayModeId, DisplayModePtr, 3>; | 
 | 51 | using DisplayModeIterator = DisplayModes::const_iterator; | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 52 |  | 
 | 53 | class DisplayMode { | 
 | 54 | public: | 
 | 55 |     class Builder { | 
 | 56 |     public: | 
 | 57 |         explicit Builder(hal::HWConfigId id) : mDisplayMode(new DisplayMode(id)) {} | 
 | 58 |  | 
 | 59 |         DisplayModePtr build() { | 
 | 60 |             return std::const_pointer_cast<const DisplayMode>(std::move(mDisplayMode)); | 
 | 61 |         } | 
 | 62 |  | 
| Marin Shalamanov | 23c4420 | 2020-12-22 19:09:20 +0100 | [diff] [blame] | 63 |         Builder& setId(DisplayModeId id) { | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 64 |             mDisplayMode->mId = id; | 
 | 65 |             return *this; | 
 | 66 |         } | 
 | 67 |  | 
| Ady Abraham | 5e7ee86 | 2021-06-23 17:43:41 -0700 | [diff] [blame] | 68 |         Builder& setPhysicalDisplayId(PhysicalDisplayId id) { | 
 | 69 |             mDisplayMode->mPhysicalDisplayId = id; | 
 | 70 |             return *this; | 
 | 71 |         } | 
 | 72 |  | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 73 |         Builder& setResolution(ui::Size resolution) { | 
 | 74 |             mDisplayMode->mResolution = resolution; | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 75 |             return *this; | 
 | 76 |         } | 
 | 77 |  | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 78 |         Builder& setVsyncPeriod(nsecs_t vsyncPeriod) { | 
| Marin Shalamanov | 5801c94 | 2020-12-17 17:00:13 +0100 | [diff] [blame] | 79 |             mDisplayMode->mFps = Fps::fromPeriodNsecs(vsyncPeriod); | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 80 |             return *this; | 
 | 81 |         } | 
 | 82 |  | 
 | 83 |         Builder& setDpiX(int32_t dpiX) { | 
 | 84 |             if (dpiX == -1) { | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 85 |                 mDisplayMode->mDpi.x = getDefaultDensity(); | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 86 |             } else { | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 87 |                 mDisplayMode->mDpi.x = dpiX / 1000.f; | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 88 |             } | 
 | 89 |             return *this; | 
 | 90 |         } | 
 | 91 |  | 
 | 92 |         Builder& setDpiY(int32_t dpiY) { | 
 | 93 |             if (dpiY == -1) { | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 94 |                 mDisplayMode->mDpi.y = getDefaultDensity(); | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 95 |             } else { | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 96 |                 mDisplayMode->mDpi.y = dpiY / 1000.f; | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 97 |             } | 
 | 98 |             return *this; | 
 | 99 |         } | 
 | 100 |  | 
| Marin Shalamanov | a7fe304 | 2021-01-29 21:02:08 +0100 | [diff] [blame] | 101 |         Builder& setGroup(int32_t group) { | 
 | 102 |             mDisplayMode->mGroup = group; | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 103 |             return *this; | 
 | 104 |         } | 
 | 105 |  | 
 | 106 |     private: | 
 | 107 |         float getDefaultDensity() { | 
 | 108 |             // Default density is based on TVs: 1080p displays get XHIGH density, lower- | 
 | 109 |             // resolution displays get TV density. Maybe eventually we'll need to update | 
 | 110 |             // it for 4k displays, though hopefully those will just report accurate DPI | 
 | 111 |             // information to begin with. This is also used for virtual displays and | 
 | 112 |             // older HWC implementations, so be careful about orientation. | 
 | 113 |  | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 114 |             if (std::max(mDisplayMode->getWidth(), mDisplayMode->getHeight()) >= 1080) { | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 115 |                 return ACONFIGURATION_DENSITY_XHIGH; | 
 | 116 |             } else { | 
 | 117 |                 return ACONFIGURATION_DENSITY_TV; | 
 | 118 |             } | 
 | 119 |         } | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 120 |  | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 121 |         std::shared_ptr<DisplayMode> mDisplayMode; | 
 | 122 |     }; | 
 | 123 |  | 
| Marin Shalamanov | 23c4420 | 2020-12-22 19:09:20 +0100 | [diff] [blame] | 124 |     DisplayModeId getId() const { return mId; } | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 125 |  | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 126 |     hal::HWConfigId getHwcId() const { return mHwcId; } | 
| Ady Abraham | 5e7ee86 | 2021-06-23 17:43:41 -0700 | [diff] [blame] | 127 |     PhysicalDisplayId getPhysicalDisplayId() const { return mPhysicalDisplayId; } | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 128 |  | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 129 |     ui::Size getResolution() const { return mResolution; } | 
 | 130 |     int32_t getWidth() const { return mResolution.getWidth(); } | 
 | 131 |     int32_t getHeight() const { return mResolution.getHeight(); } | 
 | 132 |  | 
| Marin Shalamanov | 5801c94 | 2020-12-17 17:00:13 +0100 | [diff] [blame] | 133 |     Fps getFps() const { return mFps; } | 
 | 134 |     nsecs_t getVsyncPeriod() const { return mFps.getPeriodNsecs(); } | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 135 |  | 
 | 136 |     struct Dpi { | 
 | 137 |         float x = -1; | 
 | 138 |         float y = -1; | 
 | 139 |  | 
 | 140 |         bool operator==(Dpi other) const { return x == other.x && y == other.y; } | 
 | 141 |     }; | 
 | 142 |  | 
 | 143 |     Dpi getDpi() const { return mDpi; } | 
| Marin Shalamanov | a7fe304 | 2021-01-29 21:02:08 +0100 | [diff] [blame] | 144 |  | 
 | 145 |     // Switches between modes in the same group are seamless, i.e. | 
 | 146 |     // without visual interruptions such as a black screen. | 
 | 147 |     int32_t getGroup() const { return mGroup; } | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 148 |  | 
 | 149 | private: | 
 | 150 |     explicit DisplayMode(hal::HWConfigId id) : mHwcId(id) {} | 
 | 151 |  | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 152 |     const hal::HWConfigId mHwcId; | 
| Marin Shalamanov | 23c4420 | 2020-12-22 19:09:20 +0100 | [diff] [blame] | 153 |     DisplayModeId mId; | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 154 |  | 
| Ady Abraham | 5e7ee86 | 2021-06-23 17:43:41 -0700 | [diff] [blame] | 155 |     PhysicalDisplayId mPhysicalDisplayId; | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 156 |  | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 157 |     ui::Size mResolution; | 
| Marin Shalamanov | 5801c94 | 2020-12-17 17:00:13 +0100 | [diff] [blame] | 158 |     Fps mFps; | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 159 |     Dpi mDpi; | 
| Marin Shalamanov | a7fe304 | 2021-01-29 21:02:08 +0100 | [diff] [blame] | 160 |     int32_t mGroup = -1; | 
| Marin Shalamanov | 3ea1d60 | 2020-12-16 19:59:39 +0100 | [diff] [blame] | 161 | }; | 
 | 162 |  | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 163 | inline bool equalsExceptDisplayModeId(const DisplayMode& lhs, const DisplayMode& rhs) { | 
 | 164 |     return lhs.getHwcId() == rhs.getHwcId() && lhs.getResolution() == rhs.getResolution() && | 
 | 165 |             lhs.getVsyncPeriod() == rhs.getVsyncPeriod() && lhs.getDpi() == rhs.getDpi() && | 
 | 166 |             lhs.getGroup() == rhs.getGroup(); | 
 | 167 | } | 
 | 168 |  | 
| Marin Shalamanov | 5801c94 | 2020-12-17 17:00:13 +0100 | [diff] [blame] | 169 | inline std::string to_string(const DisplayMode& mode) { | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 170 |     return base::StringPrintf("{id=%d, hwcId=%d, resolution=%dx%d, refreshRate=%s, " | 
 | 171 |                               "dpi=%.2fx%.2f, group=%d}", | 
| Marin Shalamanov | 5801c94 | 2020-12-17 17:00:13 +0100 | [diff] [blame] | 172 |                               mode.getId().value(), mode.getHwcId(), mode.getWidth(), | 
| Dominik Laskowski | b0054a2 | 2022-03-03 09:03:06 -0800 | [diff] [blame] | 173 |                               mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpi().x, | 
 | 174 |                               mode.getDpi().y, mode.getGroup()); | 
 | 175 | } | 
 | 176 |  | 
 | 177 | template <typename... DisplayModePtrs> | 
 | 178 | inline DisplayModes makeModes(const DisplayModePtrs&... modePtrs) { | 
 | 179 |     DisplayModes modes; | 
 | 180 |     // Note: The omission of std::move(modePtrs) is intentional, because order of evaluation for | 
 | 181 |     // arguments is unspecified. | 
 | 182 |     (modes.try_emplace(modePtrs->getId(), modePtrs), ...); | 
 | 183 |     return modes; | 
| Marin Shalamanov | 5801c94 | 2020-12-17 17:00:13 +0100 | [diff] [blame] | 184 | } | 
 | 185 |  | 
| Dominik Laskowski | f6b4ba6 | 2021-11-09 12:46:10 -0800 | [diff] [blame] | 186 | } // namespace android |