| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h" |
| |
| #include "ui/display/types/gamma_ramp_rgb_entry.h" |
| #include "ui/ozone/common/display_util.h" |
| #include "ui/ozone/platform/drm/common/drm_util.h" |
| #include "ui/ozone/platform/drm/gpu/drm_device.h" |
| #include "ui/ozone/platform/drm/gpu/drm_device_manager.h" |
| #include "ui/ozone/platform/drm/gpu/drm_display.h" |
| #include "ui/ozone/platform/drm/gpu/screen_manager.h" |
| |
| namespace ui { |
| |
| namespace { |
| |
| class DisplayComparator { |
| public: |
| explicit DisplayComparator(const DrmDisplay* display) |
| : drm_(display->drm()), |
| crtc_(display->crtc()), |
| connector_(display->connector()) {} |
| |
| DisplayComparator(const scoped_refptr<DrmDevice>& drm, |
| uint32_t crtc, |
| uint32_t connector) |
| : drm_(drm), crtc_(crtc), connector_(connector) {} |
| |
| bool operator()(const DrmDisplay* other) const { |
| return drm_ == other->drm() && connector_ == other->connector() && |
| crtc_ == other->crtc(); |
| } |
| |
| private: |
| scoped_refptr<DrmDevice> drm_; |
| uint32_t crtc_; |
| uint32_t connector_; |
| }; |
| |
| bool FindMatchingMode(const std::vector<drmModeModeInfo> modes, |
| const DisplayMode_Params& mode_params, |
| drmModeModeInfo* mode) { |
| for (const drmModeModeInfo& m : modes) { |
| DisplayMode_Params params = CreateDisplayModeParams(m); |
| if (mode_params.size == params.size && |
| mode_params.refresh_rate == params.refresh_rate && |
| mode_params.is_interlaced == params.is_interlaced) { |
| *mode = m; |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| } // namespace |
| |
| DrmGpuDisplayManager::DrmGpuDisplayManager(ScreenManager* screen_manager, |
| DrmDeviceManager* drm_device_manager) |
| : screen_manager_(screen_manager), drm_device_manager_(drm_device_manager) { |
| } |
| |
| DrmGpuDisplayManager::~DrmGpuDisplayManager() { |
| } |
| |
| std::vector<DisplaySnapshot_Params> DrmGpuDisplayManager::GetDisplays() { |
| ScopedVector<DrmDisplay> old_displays(displays_.Pass()); |
| std::vector<DisplaySnapshot_Params> params_list; |
| |
| const DrmDeviceVector& devices = drm_device_manager_->GetDrmDevices(); |
| // Unique identifier used to create the display id. |
| size_t index = 0; |
| for (const auto& drm : devices) { |
| ScopedVector<HardwareDisplayControllerInfo> display_infos = |
| GetAvailableDisplayControllerInfos(drm->get_fd()); |
| for (auto* display_info : display_infos) { |
| auto it = std::find_if( |
| old_displays.begin(), old_displays.end(), |
| DisplayComparator(drm, display_info->crtc()->crtc_id, |
| display_info->connector()->connector_id)); |
| if (it != old_displays.end()) { |
| displays_.push_back(*it); |
| old_displays.weak_erase(it); |
| } else { |
| displays_.push_back(new DrmDisplay(screen_manager_, drm)); |
| } |
| |
| params_list.push_back(displays_.back()->Update(display_info, index++)); |
| } |
| } |
| |
| NotifyScreenManager(displays_.get(), old_displays.get()); |
| return params_list; |
| } |
| |
| bool DrmGpuDisplayManager::TakeDisplayControl() { |
| const DrmDeviceVector& devices = drm_device_manager_->GetDrmDevices(); |
| bool status = true; |
| for (const auto& drm : devices) |
| status &= drm->SetMaster(); |
| |
| // Roll-back any successful operation. |
| if (!status) { |
| LOG(ERROR) << "Failed to take control of the display"; |
| RelinquishDisplayControl(); |
| } |
| |
| return status; |
| } |
| |
| void DrmGpuDisplayManager::RelinquishDisplayControl() { |
| const DrmDeviceVector& devices = drm_device_manager_->GetDrmDevices(); |
| for (const auto& drm : devices) |
| drm->DropMaster(); |
| } |
| |
| bool DrmGpuDisplayManager::ConfigureDisplay( |
| int64_t display_id, |
| const DisplayMode_Params& mode_param, |
| const gfx::Point& origin) { |
| DrmDisplay* display = FindDisplay(display_id); |
| if (!display) { |
| LOG(ERROR) << "There is no display with ID " << display_id; |
| return false; |
| } |
| |
| drmModeModeInfo mode; |
| bool mode_found = FindMatchingMode(display->modes(), mode_param, &mode); |
| if (!mode_found) { |
| // If the display doesn't have the mode natively, then lookup the mode from |
| // other displays and try using it on the current display (some displays |
| // support panel fitting and they can use different modes even if the mode |
| // isn't explicitly declared). |
| for (DrmDisplay* other : displays_) { |
| mode_found = FindMatchingMode(other->modes(), mode_param, &mode); |
| if (mode_found) |
| break; |
| } |
| } |
| |
| if (!mode_found) { |
| LOG(ERROR) << "Failed to find mode: size=" << mode_param.size.ToString() |
| << " is_interlaced=" << mode_param.is_interlaced |
| << " refresh_rate=" << mode_param.refresh_rate; |
| return false; |
| } |
| |
| return display->Configure(&mode, origin); |
| } |
| |
| bool DrmGpuDisplayManager::DisableDisplay(int64_t display_id) { |
| DrmDisplay* display = FindDisplay(display_id); |
| if (!display) { |
| LOG(ERROR) << "There is no display with ID " << display_id; |
| return false; |
| } |
| |
| return display->Configure(nullptr, gfx::Point()); |
| } |
| |
| bool DrmGpuDisplayManager::GetHDCPState(int64_t display_id, HDCPState* state) { |
| DrmDisplay* display = FindDisplay(display_id); |
| if (!display) { |
| LOG(ERROR) << "There is no display with ID " << display_id; |
| return false; |
| } |
| |
| return display->GetHDCPState(state); |
| } |
| |
| bool DrmGpuDisplayManager::SetHDCPState(int64_t display_id, HDCPState state) { |
| DrmDisplay* display = FindDisplay(display_id); |
| if (!display) { |
| LOG(ERROR) << "There is no display with ID " << display_id; |
| return false; |
| } |
| |
| return display->SetHDCPState(state); |
| } |
| |
| void DrmGpuDisplayManager::SetGammaRamp( |
| int64_t display_id, |
| const std::vector<GammaRampRGBEntry>& lut) { |
| DrmDisplay* display = FindDisplay(display_id); |
| if (!display) { |
| LOG(ERROR) << "There is no display with ID " << display_id; |
| return; |
| } |
| |
| display->SetGammaRamp(lut); |
| } |
| |
| DrmDisplay* DrmGpuDisplayManager::FindDisplay(int64_t display_id) { |
| for (DrmDisplay* display : displays_) |
| if (display->display_id() == display_id) |
| return display; |
| |
| return nullptr; |
| } |
| |
| void DrmGpuDisplayManager::NotifyScreenManager( |
| const std::vector<DrmDisplay*>& new_displays, |
| const std::vector<DrmDisplay*>& old_displays) const { |
| for (size_t i = 0; i < old_displays.size(); ++i) { |
| const std::vector<DrmDisplay*>::const_iterator it = |
| std::find_if(new_displays.begin(), new_displays.end(), |
| DisplayComparator(old_displays[i])); |
| |
| if (it == new_displays.end()) { |
| screen_manager_->RemoveDisplayController(old_displays[i]->drm(), |
| old_displays[i]->crtc()); |
| } |
| } |
| |
| for (size_t i = 0; i < new_displays.size(); ++i) { |
| const std::vector<DrmDisplay*>::const_iterator it = |
| std::find_if(old_displays.begin(), old_displays.end(), |
| DisplayComparator(new_displays[i])); |
| |
| if (it == old_displays.end()) { |
| screen_manager_->AddDisplayController(new_displays[i]->drm(), |
| new_displays[i]->crtc(), |
| new_displays[i]->connector()); |
| } |
| } |
| } |
| |
| } // namespace ui |