• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2020 Collabora, Ltd.
3  * Author: Antonio Caggiano <antonio.caggiano@collabora.com>
4  * Author: Rohan Garg <rohan.garg@collabora.com>
5  * Author: Robert Beckett <bob.beckett@collabora.com>
6  *
7  * SPDX-License-Identifier: MIT
8  */
9 
10 #include "pps_device.h"
11 
12 #include <cassert>
13 #include <fcntl.h>
14 #include <memory>
15 #include <unistd.h>
16 #include <xf86drm.h>
17 
18 namespace pps
19 {
20 #define MAX_DRM_DEVICES 64
21 
device_count()22 uint32_t DrmDevice::device_count()
23 {
24    drmDevicePtr devices[MAX_DRM_DEVICES] = {};
25    int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
26    drmFreeDevices(devices, num_devices);
27    return static_cast<uint32_t>(num_devices);
28 }
29 
30 /// @return The name of a DRM device, empty string in case of error
query_drm_name(const int fd)31 std::string query_drm_name(const int fd)
32 {
33    assert(fd && "Failed to query DrmDevice: invalid fd");
34 
35    std::string name = "";
36 
37    if (drmVersionPtr version = drmGetVersion(fd)) {
38       name = std::string(version->name, version->name_len);
39       drmFreeVersion(version);
40    }
41 
42    return name;
43 }
44 
45 /// @return A DRM device, nullopt in case of error
create_drm_device(int fd,int32_t gpu_num)46 std::optional<DrmDevice> create_drm_device(int fd, int32_t gpu_num)
47 {
48    if (fd < 0 || gpu_num < 0) {
49       return std::nullopt;
50    }
51 
52    // Try getting the name
53    std::string name = query_drm_name(fd);
54    if (name.empty()) {
55       return std::nullopt;
56    }
57 
58    auto ret = DrmDevice();
59    ret.fd = fd;
60    ret.gpu_num = gpu_num;
61    ret.name = name;
62    return ret;
63 }
64 
create_all()65 std::vector<DrmDevice> DrmDevice::create_all()
66 {
67    std::vector<DrmDevice> ret = {};
68 
69    drmDevicePtr devices[MAX_DRM_DEVICES] = {};
70    int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
71    if (num_devices <= 0) {
72       return ret;
73    }
74 
75    for (int32_t gpu_num = 0; gpu_num < num_devices; gpu_num++) {
76       drmDevicePtr device = devices[gpu_num];
77       if ((device->available_nodes & (1 << DRM_NODE_RENDER))) {
78          int fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR);
79 
80          // If it can create a device, push it into the vector
81          if (auto drm_device = create_drm_device(fd, gpu_num)) {
82             ret.emplace_back(std::move(drm_device.value()));
83          }
84       }
85    }
86 
87    drmFreeDevices(devices, num_devices);
88    return ret;
89 }
90 
create(int32_t gpu_num)91 std::optional<DrmDevice> DrmDevice::create(int32_t gpu_num)
92 {
93    std::optional<DrmDevice> ret = std::nullopt;
94 
95    if (gpu_num < 0) {
96       return ret;
97    }
98 
99    drmDevicePtr devices[MAX_DRM_DEVICES] = {};
100    int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
101 
102    if (num_devices > 0 && gpu_num < num_devices) {
103       drmDevicePtr device = devices[gpu_num];
104       int fd = open(device->nodes[DRM_NODE_RENDER], O_RDONLY);
105       ret = create_drm_device(fd, gpu_num);
106    }
107 
108    drmFreeDevices(devices, num_devices);
109    return ret;
110 }
111 
DrmDevice(DrmDevice && other)112 DrmDevice::DrmDevice(DrmDevice &&other)
113    : fd {other.fd}
114    , gpu_num {other.gpu_num}
115    , name {std::move(other.name)}
116 {
117    other.fd = -1;
118    other.gpu_num = -1;
119 }
120 
operator =(DrmDevice && other)121 DrmDevice &DrmDevice::operator=(DrmDevice &&other)
122 {
123    std::swap(fd, other.fd);
124    std::swap(gpu_num, other.gpu_num);
125    std::swap(name, other.name);
126    return *this;
127 }
128 
~DrmDevice()129 DrmDevice::~DrmDevice()
130 {
131    if (fd >= 0) {
132       close(fd);
133    }
134 }
135 
operator bool() const136 DrmDevice::operator bool() const
137 {
138    return !name.empty();
139 }
140 
141 } // namespace pps
142