xref: /third_party/mesa3d/src/tool/pps/pps_device.cc (revision bf215546)
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
18namespace pps
19{
20#define MAX_DRM_DEVICES 64
21
22uint32_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
31std::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
46std::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
65std::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
91std::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_RDWR);
105      ret = create_drm_device(fd, gpu_num);
106   }
107
108   drmFreeDevices(devices, num_devices);
109   return ret;
110}
111
112DrmDevice::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
121DrmDevice &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
129DrmDevice::~DrmDevice()
130{
131   if (fd >= 0) {
132      close(fd);
133   }
134}
135
136DrmDevice::operator bool() const
137{
138   return !name.empty();
139}
140
141} // namespace pps
142