Home | History | Annotate | Download | only in chromeos
      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