// 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 #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& drm, uint32_t crtc, uint32_t connector) : drm_(drm), crtc_(crtc), connector_(connector) {} bool operator()(const scoped_ptr& other) const { return drm_ == other->drm() && connector_ == other->connector() && crtc_ == other->crtc(); } private: scoped_refptr drm_; uint32_t crtc_; uint32_t connector_; }; bool FindMatchingMode(const std::vector 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 DrmGpuDisplayManager::GetDisplays() { std::vector> old_displays; old_displays.swap(displays_); std::vector params_list; const DrmDeviceVector& devices = drm_device_manager_->GetDrmDevices(); size_t device_index = 0; for (const auto& drm : devices) { ScopedVector 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(std::move(*it)); old_displays.erase(it); } else { displays_.push_back( make_scoped_ptr(new DrmDisplay(screen_manager_, drm))); } params_list.push_back( displays_.back()->Update(display_info, device_index)); } device_index++; } NotifyScreenManager(displays_, old_displays); return params_list; } void DrmGpuDisplayManager::GetScanoutFormats( gfx::AcceleratedWidget widget, std::vector* scanout_formats) { const std::vector& fourcc_formats = drm_device_manager_->GetDrmDevice(widget) ->plane_manager() ->GetSupportedFormats(); for (auto& fourcc : fourcc_formats) scanout_formats->push_back(GetBufferFormatFromFourCCFormat(fourcc)); } 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 (const auto& other_display : displays_) { mode_found = FindMatchingMode(other_display->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& 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 (const auto& display : displays_) { if (display->display_id() == display_id) return display.get(); } return nullptr; } void DrmGpuDisplayManager::NotifyScreenManager( const std::vector>& new_displays, const std::vector>& old_displays) const { for (const auto& old_display : old_displays) { auto it = std::find_if(new_displays.begin(), new_displays.end(), DisplayComparator(old_display.get())); if (it == new_displays.end()) { screen_manager_->RemoveDisplayController(old_display->drm(), old_display->crtc()); } } for (const auto& new_display : new_displays) { auto it = std::find_if(old_displays.begin(), old_displays.end(), DisplayComparator(new_display.get())); if (it == old_displays.end()) { screen_manager_->AddDisplayController( new_display->drm(), new_display->crtc(), new_display->connector()); } } } } // namespace ui