1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/ozone/platform/dri/chromeos/native_display_delegate_dri.h" 6 7 #include "base/bind.h" 8 #include "third_party/skia/include/core/SkCanvas.h" 9 #include "ui/display/types/native_display_observer.h" 10 #include "ui/events/ozone/device/device_event.h" 11 #include "ui/events/ozone/device/device_manager.h" 12 #include "ui/ozone/platform/dri/chromeos/display_mode_dri.h" 13 #include "ui/ozone/platform/dri/chromeos/display_snapshot_dri.h" 14 #include "ui/ozone/platform/dri/dri_console_buffer.h" 15 #include "ui/ozone/platform/dri/dri_util.h" 16 #include "ui/ozone/platform/dri/dri_wrapper.h" 17 #include "ui/ozone/platform/dri/screen_manager.h" 18 19 namespace ui { 20 21 namespace { 22 23 const size_t kMaxDisplayCount = 2; 24 25 const char kContentProtection[] = "Content Protection"; 26 27 struct ContentProtectionMapping { 28 const char* name; 29 HDCPState state; 30 }; 31 32 const ContentProtectionMapping kContentProtectionStates[] = { 33 {"Undesired", HDCP_STATE_UNDESIRED}, 34 {"Desired", HDCP_STATE_DESIRED}, 35 {"Enabled", HDCP_STATE_ENABLED}}; 36 37 uint32_t GetContentProtectionValue(drmModePropertyRes* property, 38 HDCPState state) { 39 std::string name; 40 for (size_t i = 0; i < arraysize(kContentProtectionStates); ++i) { 41 if (kContentProtectionStates[i].state == state) { 42 name = kContentProtectionStates[i].name; 43 break; 44 } 45 } 46 47 for (int i = 0; i < property->count_enums; ++i) 48 if (name == property->enums[i].name) 49 return i; 50 51 NOTREACHED(); 52 return 0; 53 } 54 55 class DisplaySnapshotComparator { 56 public: 57 DisplaySnapshotComparator(const DisplaySnapshotDri* snapshot) 58 : snapshot_(snapshot) {} 59 60 bool operator()(const DisplaySnapshotDri* other) const { 61 if (snapshot_->connector() == other->connector() && 62 snapshot_->crtc() == other->crtc()) 63 return true; 64 65 return false; 66 } 67 68 private: 69 const DisplaySnapshotDri* snapshot_; 70 }; 71 72 } // namespace 73 74 NativeDisplayDelegateDri::NativeDisplayDelegateDri( 75 DriWrapper* dri, 76 ScreenManager* screen_manager, 77 DeviceManager* device_manager) 78 : dri_(dri), 79 screen_manager_(screen_manager), 80 device_manager_(device_manager) { 81 // TODO(dnicoara): Remove when async display configuration is supported. 82 screen_manager_->ForceInitializationOfPrimaryDisplay(); 83 } 84 85 NativeDisplayDelegateDri::~NativeDisplayDelegateDri() { 86 if (device_manager_) 87 device_manager_->RemoveObserver(this); 88 } 89 90 DisplaySnapshot* NativeDisplayDelegateDri::FindDisplaySnapshot(int64_t id) { 91 for (size_t i = 0; i < cached_displays_.size(); ++i) 92 if (cached_displays_[i]->display_id() == id) 93 return cached_displays_[i]; 94 95 return NULL; 96 } 97 98 const DisplayMode* NativeDisplayDelegateDri::FindDisplayMode( 99 const gfx::Size& size, 100 bool is_interlaced, 101 float refresh_rate) { 102 for (size_t i = 0; i < cached_modes_.size(); ++i) 103 if (cached_modes_[i]->size() == size && 104 cached_modes_[i]->is_interlaced() == is_interlaced && 105 cached_modes_[i]->refresh_rate() == refresh_rate) 106 return cached_modes_[i]; 107 108 return NULL; 109 } 110 111 void NativeDisplayDelegateDri::Initialize() { 112 if (device_manager_) 113 device_manager_->AddObserver(this); 114 115 ScopedVector<HardwareDisplayControllerInfo> displays = 116 GetAvailableDisplayControllerInfos(dri_->get_fd()); 117 118 // By default all displays show the same console buffer. 119 console_buffer_.reset( 120 new DriConsoleBuffer(dri_, displays[0]->crtc()->buffer_id)); 121 if (!console_buffer_->Initialize()) { 122 VLOG(1) << "Failed to initialize console buffer"; 123 console_buffer_.reset(); 124 } else { 125 // Clear the console buffer such that restarting Chrome will show a 126 // predetermined background. 127 // 128 // Black was chosen since Chrome's first buffer paints start with a black 129 // background. 130 console_buffer_->canvas()->clear(SK_ColorBLACK); 131 } 132 } 133 134 void NativeDisplayDelegateDri::GrabServer() {} 135 136 void NativeDisplayDelegateDri::UngrabServer() {} 137 138 void NativeDisplayDelegateDri::SyncWithServer() {} 139 140 void NativeDisplayDelegateDri::SetBackgroundColor(uint32_t color_argb) { 141 if (console_buffer_) 142 console_buffer_->canvas()->clear(color_argb); 143 } 144 145 void NativeDisplayDelegateDri::ForceDPMSOn() { 146 for (size_t i = 0; i < cached_displays_.size(); ++i) { 147 DisplaySnapshotDri* dri_output = cached_displays_[i]; 148 if (dri_output->dpms_property()) 149 dri_->SetProperty(dri_output->connector(), 150 dri_output->dpms_property()->prop_id, 151 DRM_MODE_DPMS_ON); 152 } 153 } 154 155 std::vector<DisplaySnapshot*> NativeDisplayDelegateDri::GetDisplays() { 156 ScopedVector<DisplaySnapshotDri> old_displays(cached_displays_.Pass()); 157 cached_modes_.clear(); 158 159 ScopedVector<HardwareDisplayControllerInfo> displays = 160 GetAvailableDisplayControllerInfos(dri_->get_fd()); 161 for (size_t i = 0; 162 i < displays.size() && cached_displays_.size() < kMaxDisplayCount; ++i) { 163 DisplaySnapshotDri* display = new DisplaySnapshotDri( 164 dri_, displays[i]->connector(), displays[i]->crtc(), i); 165 cached_displays_.push_back(display); 166 cached_modes_.insert(cached_modes_.end(), 167 display->modes().begin(), 168 display->modes().end()); 169 } 170 171 NotifyScreenManager(cached_displays_.get(), old_displays.get()); 172 173 std::vector<DisplaySnapshot*> generic_displays(cached_displays_.begin(), 174 cached_displays_.end()); 175 return generic_displays; 176 } 177 178 void NativeDisplayDelegateDri::AddMode(const DisplaySnapshot& output, 179 const DisplayMode* mode) {} 180 181 bool NativeDisplayDelegateDri::Configure(const DisplaySnapshot& output, 182 const DisplayMode* mode, 183 const gfx::Point& origin) { 184 const DisplaySnapshotDri& dri_output = 185 static_cast<const DisplaySnapshotDri&>(output); 186 187 VLOG(1) << "DRM configuring: crtc=" << dri_output.crtc() 188 << " connector=" << dri_output.connector() 189 << " origin=" << origin.ToString() 190 << " size=" << (mode ? mode->size().ToString() : "0x0"); 191 192 if (mode) { 193 if (!screen_manager_->ConfigureDisplayController( 194 dri_output.crtc(), 195 dri_output.connector(), 196 origin, 197 static_cast<const DisplayModeDri*>(mode)->mode_info())) { 198 VLOG(1) << "Failed to configure: crtc=" << dri_output.crtc() 199 << " connector=" << dri_output.connector(); 200 return false; 201 } 202 } else { 203 if (!screen_manager_->DisableDisplayController(dri_output.crtc())) { 204 VLOG(1) << "Failed to disable crtc=" << dri_output.crtc(); 205 return false; 206 } 207 } 208 209 return true; 210 } 211 212 void NativeDisplayDelegateDri::CreateFrameBuffer(const gfx::Size& size) {} 213 214 bool NativeDisplayDelegateDri::GetHDCPState(const DisplaySnapshot& output, 215 HDCPState* state) { 216 const DisplaySnapshotDri& dri_output = 217 static_cast<const DisplaySnapshotDri&>(output); 218 219 ScopedDrmConnectorPtr connector(dri_->GetConnector(dri_output.connector())); 220 if (!connector) { 221 LOG(ERROR) << "Failed to get connector " << dri_output.connector(); 222 return false; 223 } 224 225 ScopedDrmPropertyPtr hdcp_property( 226 dri_->GetProperty(connector.get(), kContentProtection)); 227 if (!hdcp_property) { 228 LOG(ERROR) << "'" << kContentProtection << "' property doesn't exist."; 229 return false; 230 } 231 232 DCHECK_LT(static_cast<int>(hdcp_property->prop_id), connector->count_props); 233 int hdcp_state_idx = connector->prop_values[hdcp_property->prop_id]; 234 DCHECK_LT(hdcp_state_idx, hdcp_property->count_enums); 235 236 std::string name(hdcp_property->enums[hdcp_state_idx].name); 237 for (size_t i = 0; i < arraysize(kContentProtectionStates); ++i) { 238 if (name == kContentProtectionStates[i].name) { 239 *state = kContentProtectionStates[i].state; 240 VLOG(3) << "HDCP state: " << *state << " (" << name << ")"; 241 return true; 242 } 243 } 244 245 LOG(ERROR) << "Unknown content protection value '" << name << "'"; 246 return false; 247 } 248 249 bool NativeDisplayDelegateDri::SetHDCPState(const DisplaySnapshot& output, 250 HDCPState state) { 251 const DisplaySnapshotDri& dri_output = 252 static_cast<const DisplaySnapshotDri&>(output); 253 254 ScopedDrmConnectorPtr connector(dri_->GetConnector(dri_output.connector())); 255 if (!connector) { 256 LOG(ERROR) << "Failed to get connector " << dri_output.connector(); 257 return false; 258 } 259 260 ScopedDrmPropertyPtr hdcp_property( 261 dri_->GetProperty(connector.get(), kContentProtection)); 262 if (!hdcp_property) { 263 LOG(ERROR) << "'" << kContentProtection << "' property doesn't exist."; 264 return false; 265 } 266 267 return dri_->SetProperty( 268 dri_output.connector(), 269 hdcp_property->prop_id, 270 GetContentProtectionValue(hdcp_property.get(), state)); 271 } 272 273 std::vector<ui::ColorCalibrationProfile> 274 NativeDisplayDelegateDri::GetAvailableColorCalibrationProfiles( 275 const ui::DisplaySnapshot& output) { 276 NOTIMPLEMENTED(); 277 return std::vector<ui::ColorCalibrationProfile>(); 278 } 279 280 bool NativeDisplayDelegateDri::SetColorCalibrationProfile( 281 const ui::DisplaySnapshot& output, 282 ui::ColorCalibrationProfile new_profile) { 283 NOTIMPLEMENTED(); 284 return false; 285 } 286 287 void NativeDisplayDelegateDri::AddObserver(NativeDisplayObserver* observer) { 288 observers_.AddObserver(observer); 289 } 290 291 void NativeDisplayDelegateDri::RemoveObserver(NativeDisplayObserver* observer) { 292 observers_.RemoveObserver(observer); 293 } 294 295 void NativeDisplayDelegateDri::OnDeviceEvent(const DeviceEvent& event) { 296 if (event.device_type() != DeviceEvent::DISPLAY) 297 return; 298 299 if (event.action_type() == DeviceEvent::CHANGE) { 300 VLOG(1) << "Got display changed event"; 301 FOR_EACH_OBSERVER( 302 NativeDisplayObserver, observers_, OnConfigurationChanged()); 303 } 304 } 305 306 void NativeDisplayDelegateDri::NotifyScreenManager( 307 const std::vector<DisplaySnapshotDri*>& new_displays, 308 const std::vector<DisplaySnapshotDri*>& old_displays) const { 309 for (size_t i = 0; i < old_displays.size(); ++i) { 310 const std::vector<DisplaySnapshotDri*>::const_iterator it = 311 std::find_if(new_displays.begin(), 312 new_displays.end(), 313 DisplaySnapshotComparator(old_displays[i])); 314 315 if (it == new_displays.end()) 316 screen_manager_->RemoveDisplayController(old_displays[i]->crtc()); 317 } 318 319 for (size_t i = 0; i < new_displays.size(); ++i) { 320 const std::vector<DisplaySnapshotDri*>::const_iterator it = 321 std::find_if(old_displays.begin(), 322 old_displays.end(), 323 DisplaySnapshotComparator(new_displays[i])); 324 325 if (it == old_displays.end()) 326 screen_manager_->AddDisplayController(new_displays[i]->crtc(), 327 new_displays[i]->connector()); 328 } 329 } 330 331 } // namespace ui 332