| /* | 
 |  * Copyright 2020 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. | 
 |  */ | 
 |  | 
 | #pragma once | 
 |  | 
 | #include "DisplayHardware/Hal.h" | 
 | #include "Fps.h" | 
 | #include "Scheduler/StrongTyping.h" | 
 |  | 
 | #include <android-base/stringprintf.h> | 
 | #include <android/configuration.h> | 
 | #include <ui/DisplayMode.h> | 
 | #include <ui/Size.h> | 
 | #include <utils/Timers.h> | 
 |  | 
 | #include <cstddef> | 
 | #include <memory> | 
 | #include <vector> | 
 |  | 
 | namespace android { | 
 |  | 
 | namespace hal = android::hardware::graphics::composer::hal; | 
 |  | 
 | class DisplayMode; | 
 | using DisplayModePtr = std::shared_ptr<const DisplayMode>; | 
 | using DisplayModes = std::vector<DisplayModePtr>; | 
 | using DisplayModeId = StrongTyping<ui::DisplayModeId, struct DisplayModeIdTag, Compare, Hash>; | 
 |  | 
 | class DisplayMode { | 
 | public: | 
 |     class Builder { | 
 |     public: | 
 |         explicit Builder(hal::HWConfigId id) : mDisplayMode(new DisplayMode(id)) {} | 
 |  | 
 |         DisplayModePtr build() { | 
 |             return std::const_pointer_cast<const DisplayMode>(std::move(mDisplayMode)); | 
 |         } | 
 |  | 
 |         Builder& setId(DisplayModeId id) { | 
 |             mDisplayMode->mId = id; | 
 |             return *this; | 
 |         } | 
 |  | 
 |         Builder& setWidth(int32_t width) { | 
 |             mDisplayMode->mWidth = width; | 
 |             return *this; | 
 |         } | 
 |  | 
 |         Builder& setHeight(int32_t height) { | 
 |             mDisplayMode->mHeight = height; | 
 |             return *this; | 
 |         } | 
 |  | 
 |         Builder& setVsyncPeriod(int32_t vsyncPeriod) { | 
 |             mDisplayMode->mFps = Fps::fromPeriodNsecs(vsyncPeriod); | 
 |             return *this; | 
 |         } | 
 |  | 
 |         Builder& setDpiX(int32_t dpiX) { | 
 |             if (dpiX == -1) { | 
 |                 mDisplayMode->mDpiX = getDefaultDensity(); | 
 |             } else { | 
 |                 mDisplayMode->mDpiX = dpiX / 1000.0f; | 
 |             } | 
 |             return *this; | 
 |         } | 
 |  | 
 |         Builder& setDpiY(int32_t dpiY) { | 
 |             if (dpiY == -1) { | 
 |                 mDisplayMode->mDpiY = getDefaultDensity(); | 
 |             } else { | 
 |                 mDisplayMode->mDpiY = dpiY / 1000.0f; | 
 |             } | 
 |             return *this; | 
 |         } | 
 |  | 
 |         Builder& setGroup(int32_t group) { | 
 |             mDisplayMode->mGroup = group; | 
 |             return *this; | 
 |         } | 
 |  | 
 |     private: | 
 |         float getDefaultDensity() { | 
 |             // Default density is based on TVs: 1080p displays get XHIGH density, lower- | 
 |             // resolution displays get TV density. Maybe eventually we'll need to update | 
 |             // it for 4k displays, though hopefully those will just report accurate DPI | 
 |             // information to begin with. This is also used for virtual displays and | 
 |             // older HWC implementations, so be careful about orientation. | 
 |  | 
 |             auto longDimension = std::max(mDisplayMode->mWidth, mDisplayMode->mHeight); | 
 |             if (longDimension >= 1080) { | 
 |                 return ACONFIGURATION_DENSITY_XHIGH; | 
 |             } else { | 
 |                 return ACONFIGURATION_DENSITY_TV; | 
 |             } | 
 |         } | 
 |         std::shared_ptr<DisplayMode> mDisplayMode; | 
 |     }; | 
 |  | 
 |     DisplayModeId getId() const { return mId; } | 
 |     hal::HWConfigId getHwcId() const { return mHwcId; } | 
 |  | 
 |     int32_t getWidth() const { return mWidth; } | 
 |     int32_t getHeight() const { return mHeight; } | 
 |     ui::Size getSize() const { return {mWidth, mHeight}; } | 
 |     Fps getFps() const { return mFps; } | 
 |     nsecs_t getVsyncPeriod() const { return mFps.getPeriodNsecs(); } | 
 |     float getDpiX() const { return mDpiX; } | 
 |     float getDpiY() const { return mDpiY; } | 
 |  | 
 |     // Switches between modes in the same group are seamless, i.e. | 
 |     // without visual interruptions such as a black screen. | 
 |     int32_t getGroup() const { return mGroup; } | 
 |  | 
 |     bool equalsExceptDisplayModeId(const DisplayModePtr& other) const { | 
 |         return mHwcId == other->mHwcId && mWidth == other->mWidth && mHeight == other->mHeight && | 
 |                 getVsyncPeriod() == other->getVsyncPeriod() && mDpiX == other->mDpiX && | 
 |                 mDpiY == other->mDpiY && mGroup == other->mGroup; | 
 |     } | 
 |  | 
 | private: | 
 |     explicit DisplayMode(hal::HWConfigId id) : mHwcId(id) {} | 
 |  | 
 |     hal::HWConfigId mHwcId; | 
 |     DisplayModeId mId; | 
 |  | 
 |     int32_t mWidth = -1; | 
 |     int32_t mHeight = -1; | 
 |     Fps mFps; | 
 |     float mDpiX = -1; | 
 |     float mDpiY = -1; | 
 |     int32_t mGroup = -1; | 
 | }; | 
 |  | 
 | inline std::string to_string(const DisplayMode& mode) { | 
 |     return base::StringPrintf("{id=%d, hwcId=%d, width=%d, height=%d, refreshRate=%s, " | 
 |                               "dpiX=%.2f, dpiY=%.2f, group=%d}", | 
 |                               mode.getId().value(), mode.getHwcId(), mode.getWidth(), | 
 |                               mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpiX(), | 
 |                               mode.getDpiY(), mode.getGroup()); | 
 | } | 
 |  | 
 | } // namespace android |