Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / ozone / platform / drm / common / drm_util.cc
blob845cb413f5e8d4926c6962846cbfe390ccadc3e7
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.
5 #include "ui/ozone/platform/drm/common/drm_util.h"
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <sys/mman.h>
10 #include <xf86drmMode.h>
12 #include "ui/display/util/edid_parser.h"
14 #if !defined(DRM_MODE_CONNECTOR_DSI)
15 #define DRM_MODE_CONNECTOR_DSI 16
16 #endif
18 namespace ui {
20 namespace {
22 bool IsCrtcInUse(uint32_t crtc,
23 const ScopedVector<HardwareDisplayControllerInfo>& displays) {
24 for (size_t i = 0; i < displays.size(); ++i) {
25 if (crtc == displays[i]->crtc()->crtc_id)
26 return true;
29 return false;
32 uint32_t GetCrtc(int fd,
33 drmModeConnector* connector,
34 drmModeRes* resources,
35 const ScopedVector<HardwareDisplayControllerInfo>& displays) {
36 // If the connector already has an encoder try to re-use.
37 if (connector->encoder_id) {
38 ScopedDrmEncoderPtr encoder(drmModeGetEncoder(fd, connector->encoder_id));
39 if (encoder && encoder->crtc_id && !IsCrtcInUse(encoder->crtc_id, displays))
40 return encoder->crtc_id;
43 // Try to find an encoder for the connector.
44 for (int i = 0; i < connector->count_encoders; ++i) {
45 ScopedDrmEncoderPtr encoder(drmModeGetEncoder(fd, connector->encoders[i]));
46 if (!encoder)
47 continue;
49 for (int j = 0; j < resources->count_crtcs; ++j) {
50 // Check if the encoder is compatible with this CRTC
51 if (!(encoder->possible_crtcs & (1 << j)) ||
52 IsCrtcInUse(resources->crtcs[j], displays))
53 continue;
55 return resources->crtcs[j];
59 return 0;
62 // Computes the refresh rate for the specific mode. If we have enough
63 // information use the mode timings to compute a more exact value otherwise
64 // fallback to using the mode's vertical refresh rate (the kernel computes this
65 // the same way, however there is a loss in precision since |vrefresh| is sent
66 // as an integer).
67 float GetRefreshRate(const drmModeModeInfo& mode) {
68 if (!mode.htotal || !mode.vtotal)
69 return mode.vrefresh;
71 float clock = mode.clock;
72 float htotal = mode.htotal;
73 float vtotal = mode.vtotal;
75 return (clock * 1000.0f) / (htotal * vtotal);
78 DisplayConnectionType GetDisplayType(drmModeConnector* connector) {
79 switch (connector->connector_type) {
80 case DRM_MODE_CONNECTOR_VGA:
81 return DISPLAY_CONNECTION_TYPE_VGA;
82 case DRM_MODE_CONNECTOR_DVII:
83 case DRM_MODE_CONNECTOR_DVID:
84 case DRM_MODE_CONNECTOR_DVIA:
85 return DISPLAY_CONNECTION_TYPE_DVI;
86 case DRM_MODE_CONNECTOR_LVDS:
87 case DRM_MODE_CONNECTOR_eDP:
88 case DRM_MODE_CONNECTOR_DSI:
89 return DISPLAY_CONNECTION_TYPE_INTERNAL;
90 case DRM_MODE_CONNECTOR_DisplayPort:
91 return DISPLAY_CONNECTION_TYPE_DISPLAYPORT;
92 case DRM_MODE_CONNECTOR_HDMIA:
93 case DRM_MODE_CONNECTOR_HDMIB:
94 return DISPLAY_CONNECTION_TYPE_HDMI;
95 default:
96 return DISPLAY_CONNECTION_TYPE_UNKNOWN;
100 int GetDrmProperty(int fd,
101 drmModeConnector* connector,
102 const std::string& name,
103 ScopedDrmPropertyPtr* property) {
104 for (int i = 0; i < connector->count_props; ++i) {
105 ScopedDrmPropertyPtr tmp(drmModeGetProperty(fd, connector->props[i]));
106 if (!tmp)
107 continue;
109 if (name == tmp->name) {
110 *property = tmp.Pass();
111 return i;
115 return -1;
118 std::string GetNameForEnumValue(drmModePropertyRes* property, uint32_t value) {
119 for (int i = 0; i < property->count_enums; ++i)
120 if (property->enums[i].value == value)
121 return property->enums[i].name;
123 return std::string();
126 ScopedDrmPropertyBlobPtr GetDrmPropertyBlob(int fd,
127 drmModeConnector* connector,
128 const std::string& name) {
129 ScopedDrmPropertyPtr property;
130 int index = GetDrmProperty(fd, connector, name, &property);
131 if (index < 0)
132 return nullptr;
134 if (property->flags & DRM_MODE_PROP_BLOB) {
135 return ScopedDrmPropertyBlobPtr(
136 drmModeGetPropertyBlob(fd, connector->prop_values[index]));
139 return nullptr;
142 bool IsAspectPreserving(int fd, drmModeConnector* connector) {
143 ScopedDrmPropertyPtr property;
144 int index = GetDrmProperty(fd, connector, "scaling mode", &property);
145 if (index < 0)
146 return false;
148 return (GetNameForEnumValue(property.get(), connector->prop_values[index]) ==
149 "Full aspect");
152 } // namespace
154 HardwareDisplayControllerInfo::HardwareDisplayControllerInfo(
155 ScopedDrmConnectorPtr connector,
156 ScopedDrmCrtcPtr crtc)
157 : connector_(connector.Pass()), crtc_(crtc.Pass()) {
160 HardwareDisplayControllerInfo::~HardwareDisplayControllerInfo() {
163 ScopedVector<HardwareDisplayControllerInfo> GetAvailableDisplayControllerInfos(
164 int fd) {
165 ScopedDrmResourcesPtr resources(drmModeGetResources(fd));
166 DCHECK(resources) << "Failed to get DRM resources";
167 ScopedVector<HardwareDisplayControllerInfo> displays;
169 for (int i = 0; i < resources->count_connectors; ++i) {
170 ScopedDrmConnectorPtr connector(
171 drmModeGetConnector(fd, resources->connectors[i]));
173 if (!connector || connector->connection != DRM_MODE_CONNECTED ||
174 connector->count_modes == 0)
175 continue;
177 uint32_t crtc_id = GetCrtc(fd, connector.get(), resources.get(), displays);
178 if (!crtc_id)
179 continue;
181 ScopedDrmCrtcPtr crtc(drmModeGetCrtc(fd, crtc_id));
182 displays.push_back(
183 new HardwareDisplayControllerInfo(connector.Pass(), crtc.Pass()));
186 return displays.Pass();
189 bool SameMode(const drmModeModeInfo& lhs, const drmModeModeInfo& rhs) {
190 return lhs.clock == rhs.clock && lhs.hdisplay == rhs.hdisplay &&
191 lhs.vdisplay == rhs.vdisplay && lhs.vrefresh == rhs.vrefresh &&
192 lhs.hsync_start == rhs.hsync_start && lhs.hsync_end == rhs.hsync_end &&
193 lhs.htotal == rhs.htotal && lhs.hskew == rhs.hskew &&
194 lhs.vsync_start == rhs.vsync_start && lhs.vsync_end == rhs.vsync_end &&
195 lhs.vtotal == rhs.vtotal && lhs.vscan == rhs.vscan &&
196 lhs.flags == rhs.flags && strcmp(lhs.name, rhs.name) == 0;
199 DisplayMode_Params CreateDisplayModeParams(const drmModeModeInfo& mode) {
200 DisplayMode_Params params;
201 params.size = gfx::Size(mode.hdisplay, mode.vdisplay);
202 params.is_interlaced = mode.flags & DRM_MODE_FLAG_INTERLACE;
203 params.refresh_rate = GetRefreshRate(mode);
205 return params;
208 DisplaySnapshot_Params CreateDisplaySnapshotParams(
209 HardwareDisplayControllerInfo* info,
210 int fd,
211 size_t display_index,
212 const gfx::Point& origin) {
213 DisplaySnapshot_Params params;
214 params.display_id = display_index;
215 params.origin = origin;
216 params.physical_size =
217 gfx::Size(info->connector()->mmWidth, info->connector()->mmHeight);
218 params.type = GetDisplayType(info->connector());
219 params.is_aspect_preserving_scaling =
220 IsAspectPreserving(fd, info->connector());
222 ScopedDrmPropertyBlobPtr edid_blob(
223 GetDrmPropertyBlob(fd, info->connector(), "EDID"));
225 if (edid_blob) {
226 std::vector<uint8_t> edid(
227 static_cast<uint8_t*>(edid_blob->data),
228 static_cast<uint8_t*>(edid_blob->data) + edid_blob->length);
230 if (!GetDisplayIdFromEDID(edid, display_index, &params.display_id,
231 &params.product_id))
232 params.display_id = display_index;
234 ParseOutputDeviceData(edid, nullptr, nullptr, &params.display_name, nullptr,
235 nullptr);
236 ParseOutputOverscanFlag(edid, &params.has_overscan);
237 } else {
238 VLOG(1) << "Failed to get EDID blob for connector "
239 << info->connector()->connector_id;
242 for (int i = 0; i < info->connector()->count_modes; ++i) {
243 const drmModeModeInfo& mode = info->connector()->modes[i];
244 params.modes.push_back(CreateDisplayModeParams(mode));
246 if (info->crtc()->mode_valid && SameMode(info->crtc()->mode, mode)) {
247 params.has_current_mode = true;
248 params.current_mode = params.modes.back();
251 if (mode.type & DRM_MODE_TYPE_PREFERRED) {
252 params.has_native_mode = true;
253 params.native_mode = params.modes.back();
257 // If no preferred mode is found then use the first one. Using the first one
258 // since it should be the best mode.
259 if (!params.has_native_mode && !params.modes.empty()) {
260 params.has_native_mode = true;
261 params.native_mode = params.modes.front();
264 return params;
267 } // namespace ui