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/gpu/drm_util.h"
12 #include <xf86drmMode.h>
14 #include "base/strings/stringprintf.h"
15 #include "ui/ozone/platform/drm/gpu/drm_device.h"
16 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
22 const char kDefaultGraphicsCardPattern
[] = "/dev/dri/card%d";
24 bool IsCrtcInUse(uint32_t crtc
,
25 const ScopedVector
<HardwareDisplayControllerInfo
>& displays
) {
26 for (size_t i
= 0; i
< displays
.size(); ++i
) {
27 if (crtc
== displays
[i
]->crtc()->crtc_id
)
34 uint32_t GetCrtc(int fd
,
35 drmModeConnector
* connector
,
36 drmModeRes
* resources
,
37 const ScopedVector
<HardwareDisplayControllerInfo
>& displays
) {
38 // If the connector already has an encoder try to re-use.
39 if (connector
->encoder_id
) {
40 ScopedDrmEncoderPtr
encoder(drmModeGetEncoder(fd
, connector
->encoder_id
));
41 if (encoder
&& encoder
->crtc_id
&& !IsCrtcInUse(encoder
->crtc_id
, displays
))
42 return encoder
->crtc_id
;
45 // Try to find an encoder for the connector.
46 for (int i
= 0; i
< connector
->count_encoders
; ++i
) {
47 ScopedDrmEncoderPtr
encoder(drmModeGetEncoder(fd
, connector
->encoders
[i
]));
51 for (int j
= 0; j
< resources
->count_crtcs
; ++j
) {
52 // Check if the encoder is compatible with this CRTC
53 if (!(encoder
->possible_crtcs
& (1 << j
)) ||
54 IsCrtcInUse(resources
->crtcs
[j
], displays
))
57 return resources
->crtcs
[j
];
66 HardwareDisplayControllerInfo::HardwareDisplayControllerInfo(
67 ScopedDrmConnectorPtr connector
,
68 ScopedDrmCrtcPtr crtc
)
69 : connector_(connector
.Pass()), crtc_(crtc
.Pass()) {
72 HardwareDisplayControllerInfo::~HardwareDisplayControllerInfo() {
75 ScopedVector
<HardwareDisplayControllerInfo
> GetAvailableDisplayControllerInfos(
77 ScopedDrmResourcesPtr
resources(drmModeGetResources(fd
));
78 DCHECK(resources
) << "Failed to get DRM resources";
79 ScopedVector
<HardwareDisplayControllerInfo
> displays
;
81 for (int i
= 0; i
< resources
->count_connectors
; ++i
) {
82 ScopedDrmConnectorPtr
connector(
83 drmModeGetConnector(fd
, resources
->connectors
[i
]));
85 if (!connector
|| connector
->connection
!= DRM_MODE_CONNECTED
||
86 connector
->count_modes
== 0)
89 uint32_t crtc_id
= GetCrtc(fd
, connector
.get(), resources
.get(), displays
);
93 ScopedDrmCrtcPtr
crtc(drmModeGetCrtc(fd
, crtc_id
));
95 new HardwareDisplayControllerInfo(connector
.Pass(), crtc
.Pass()));
98 return displays
.Pass();
101 bool SameMode(const drmModeModeInfo
& lhs
, const drmModeModeInfo
& rhs
) {
102 return lhs
.clock
== rhs
.clock
&& lhs
.hdisplay
== rhs
.hdisplay
&&
103 lhs
.vdisplay
== rhs
.vdisplay
&& lhs
.vrefresh
== rhs
.vrefresh
&&
104 lhs
.hsync_start
== rhs
.hsync_start
&& lhs
.hsync_end
== rhs
.hsync_end
&&
105 lhs
.htotal
== rhs
.htotal
&& lhs
.hskew
== rhs
.hskew
&&
106 lhs
.vsync_start
== rhs
.vsync_start
&& lhs
.vsync_end
== rhs
.vsync_end
&&
107 lhs
.vtotal
== rhs
.vtotal
&& lhs
.vscan
== rhs
.vscan
&&
108 lhs
.flags
== rhs
.flags
&& strcmp(lhs
.name
, rhs
.name
) == 0;
111 void ForceInitializationOfPrimaryDisplay(const scoped_refptr
<DrmDevice
>& drm
,
112 ScreenManager
* screen_manager
) {
113 VLOG(2) << "Forcing initialization of primary display.";
114 ScopedVector
<HardwareDisplayControllerInfo
> displays
=
115 GetAvailableDisplayControllerInfos(drm
->get_fd());
117 if (displays
.empty())
120 screen_manager
->AddDisplayController(drm
, displays
[0]->crtc()->crtc_id
,
121 displays
[0]->connector()->connector_id
);
122 screen_manager
->ConfigureDisplayController(
123 drm
, displays
[0]->crtc()->crtc_id
, displays
[0]->connector()->connector_id
,
124 gfx::Point(), displays
[0]->connector()->modes
[0]);
127 base::FilePath
GetPrimaryDisplayCardPath() {
128 struct drm_mode_card_res res
;
129 for (int i
= 0; /* end on first card# that does not exist */; i
++) {
130 std::string card_path
= base::StringPrintf(kDefaultGraphicsCardPattern
, i
);
132 if (access(card_path
.c_str(), F_OK
) != 0)
135 int fd
= open(card_path
.c_str(), O_RDWR
| O_CLOEXEC
);
137 VPLOG(1) << "Failed to open '" << card_path
<< "'";
141 memset(&res
, 0, sizeof(struct drm_mode_card_res
));
142 int ret
= drmIoctl(fd
, DRM_IOCTL_MODE_GETRESOURCES
, &res
);
144 if (ret
== 0 && res
.count_crtcs
> 0) {
145 return base::FilePath(card_path
);
148 VPLOG_IF(1, ret
) << "Failed to get DRM resources for '" << card_path
<< "'";
151 return base::FilePath();