| /* |
| * Copyright 2021 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. |
| */ |
| |
| #include "DisplayConfig.h" |
| |
| #include <unordered_map> |
| |
| namespace { |
| |
| template <class T> |
| inline void hashCombine(size_t& hash, const T& value) { |
| std::hash<T> hasher; |
| hash ^= hasher(value) + 0x9e3779b9 + (hash << 6) + (hash >> 2); |
| } |
| |
| } // namespace |
| |
| void DisplayConfig::setAttribute(HWC2::Attribute attribute, int32_t value) { |
| if (attribute == HWC2::Attribute::Width) { |
| mWidth = value; |
| } |
| if (attribute == HWC2::Attribute::Height) { |
| mHeight = value; |
| } |
| if (attribute == HWC2::Attribute::DpiX) { |
| mDpiX = value; |
| } |
| if (attribute == HWC2::Attribute::DpiY) { |
| mDpiY = value; |
| } |
| if (attribute == HWC2::Attribute::VsyncPeriod) { |
| mVsyncPeriodNanos = value; |
| } |
| if (attribute == HWC2::Attribute::ConfigGroup) { |
| mConfigGroup = value; |
| } |
| } |
| |
| int32_t DisplayConfig::getAttribute(HWC2::Attribute attribute) const { |
| if (attribute == HWC2::Attribute::Width) { |
| return mWidth; |
| } |
| if (attribute == HWC2::Attribute::Height) { |
| return mHeight; |
| } |
| if (attribute == HWC2::Attribute::DpiX) { |
| // From hwcomposer2.h, HWC2_ATTRIBUTE_DPI_X returns "Dots per thousand |
| // inches (DPI * 1000)". |
| return getDotsPerThousandInchesX(); |
| } |
| if (attribute == HWC2::Attribute::DpiY) { |
| // From hwcomposer2.h, HWC2_ATTRIBUTE_DPI_Y returns "Dots per thousand |
| // inches (DPI * 1000)" |
| return getDotsPerThousandInchesY(); |
| } |
| if (attribute == HWC2::Attribute::VsyncPeriod) { |
| return mVsyncPeriodNanos; |
| } |
| if (attribute == HWC2::Attribute::ConfigGroup) { |
| return mConfigGroup; |
| } |
| return -1; |
| } |
| |
| std::string DisplayConfig::toString() const { |
| std::string output; |
| output += " w:" + std::to_string(mWidth); |
| output += " h:" + std::to_string(mHeight); |
| output += " dpi-x:" + std::to_string(mDpiX); |
| output += " dpi-y:" + std::to_string(mDpiY); |
| output += " vsync:" + std::to_string(1e9 / mVsyncPeriodNanos); |
| output += " config-group:" + std::to_string(mConfigGroup); |
| return output; |
| } |
| |
| /*static*/ |
| void DisplayConfig::addConfigGroups(std::vector<DisplayConfig>* configs) { |
| // From /hardware/interfaces/graphics/composer/2.4/IComposerClient.hal: |
| // "Configurations which share the same config group are similar in all |
| // attributes except for the vsync period." |
| struct ConfigForGroupHash { |
| size_t operator()(const DisplayConfig& config) const { |
| size_t hash = 0; |
| hashCombine(hash, config.mWidth); |
| hashCombine(hash, config.mHeight); |
| hashCombine(hash, config.mDpiX); |
| hashCombine(hash, config.mDpiY); |
| return hash; |
| } |
| }; |
| struct ConfigForGroupEq { |
| size_t operator()(const DisplayConfig& a, const DisplayConfig& b) const { |
| if (a.mWidth != b.mWidth) { |
| return a.mWidth < b.mWidth; |
| } |
| if (a.mHeight != b.mHeight) { |
| return a.mHeight < b.mHeight; |
| } |
| if (a.mDpiX != b.mDpiX) { |
| return a.mDpiX < b.mDpiX; |
| } |
| return a.mDpiY < b.mDpiY; |
| } |
| }; |
| |
| std::unordered_map<DisplayConfig, int32_t, ConfigForGroupHash, |
| ConfigForGroupEq> |
| configToConfigGroup; |
| |
| for (auto& config : *configs) { |
| auto [it, inserted] = |
| configToConfigGroup.try_emplace(config, configToConfigGroup.size()); |
| config.setConfigGroup(it->second); |
| } |
| } |