xref: /aosp_15_r20/external/mesa3d/src/tool/pps/pps_device.cc (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2020 Collabora, Ltd.
3  * Author: Antonio Caggiano <[email protected]>
4  * Author: Rohan Garg <[email protected]>
5  * Author: Robert Beckett <[email protected]>
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    const char *dri_prime = getenv("DRI_PRIME");
59    if (dri_prime != NULL) {
60       drmDevicePtr drm_device;
61       uint16_t vendor_id, device_id;
62       bool prime_is_vid_did =
63          sscanf(dri_prime, "%hx:%hx", &vendor_id, &device_id) == 2;
64 
65       if (prime_is_vid_did && drmGetDevice2(fd, 0, &drm_device) == 0) {
66          if (drm_device->bustype == DRM_BUS_PCI &&
67              (drm_device->deviceinfo.pci->vendor_id != vendor_id ||
68               drm_device->deviceinfo.pci->device_id != device_id))
69             return std::nullopt;
70       }
71    }
72 
73    auto ret = DrmDevice();
74    ret.fd = fd;
75    ret.gpu_num = gpu_num;
76    ret.name = name;
77    return ret;
78 }
79 
create_all()80 std::vector<DrmDevice> DrmDevice::create_all()
81 {
82    std::vector<DrmDevice> ret = {};
83 
84    drmDevicePtr devices[MAX_DRM_DEVICES] = {};
85    int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
86    if (num_devices <= 0) {
87       return ret;
88    }
89 
90    for (int32_t gpu_num = 0; gpu_num < num_devices; gpu_num++) {
91       drmDevicePtr device = devices[gpu_num];
92       if ((device->available_nodes & (1 << DRM_NODE_RENDER))) {
93          int fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR);
94 
95          // If it can create a device, push it into the vector
96          if (auto drm_device = create_drm_device(fd, gpu_num)) {
97             ret.emplace_back(std::move(drm_device.value()));
98          }
99       }
100    }
101 
102    drmFreeDevices(devices, num_devices);
103    return ret;
104 }
105 
create(int32_t gpu_num)106 std::optional<DrmDevice> DrmDevice::create(int32_t gpu_num)
107 {
108    std::optional<DrmDevice> ret = std::nullopt;
109 
110    if (gpu_num < 0) {
111       return ret;
112    }
113 
114    drmDevicePtr devices[MAX_DRM_DEVICES] = {};
115    int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
116 
117    if (num_devices > 0 && gpu_num < num_devices) {
118       drmDevicePtr device = devices[gpu_num];
119       int fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR);
120       ret = create_drm_device(fd, gpu_num);
121    }
122 
123    drmFreeDevices(devices, num_devices);
124    return ret;
125 }
126 
DrmDevice(DrmDevice && other)127 DrmDevice::DrmDevice(DrmDevice &&other)
128    : fd {other.fd}
129    , gpu_num {other.gpu_num}
130    , name {std::move(other.name)}
131 {
132    other.fd = -1;
133    other.gpu_num = -1;
134 }
135 
operator =(DrmDevice && other)136 DrmDevice &DrmDevice::operator=(DrmDevice &&other)
137 {
138    std::swap(fd, other.fd);
139    std::swap(gpu_num, other.gpu_num);
140    std::swap(name, other.name);
141    return *this;
142 }
143 
~DrmDevice()144 DrmDevice::~DrmDevice()
145 {
146    if (fd >= 0) {
147       close(fd);
148    }
149 }
150 
operator bool() const151 DrmDevice::operator bool() const
152 {
153    return !name.empty();
154 }
155 
156 } // namespace pps
157