mesa/src/tool/pps/pps_device.cc

142 lines
3.1 KiB
C++

/*
* Copyright © 2020 Collabora, Ltd.
* Author: Antonio Caggiano <antonio.caggiano@collabora.com>
* Author: Rohan Garg <rohan.garg@collabora.com>
* Author: Robert Beckett <bob.beckett@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include "pps_device.h"
#include <cassert>
#include <fcntl.h>
#include <memory>
#include <unistd.h>
#include <xf86drm.h>
namespace pps
{
#define MAX_DRM_DEVICES 64
uint32_t DrmDevice::device_count()
{
drmDevicePtr devices[MAX_DRM_DEVICES] = {};
int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
drmFreeDevices(devices, num_devices);
return static_cast<uint32_t>(num_devices);
}
/// @return The name of a DRM device, empty string in case of error
std::string query_drm_name(const int fd)
{
assert(fd && "Failed to query DrmDevice: invalid fd");
std::string name = "";
if (drmVersionPtr version = drmGetVersion(fd)) {
name = std::string(version->name, version->name_len);
drmFreeVersion(version);
}
return name;
}
/// @return A DRM device, nullopt in case of error
std::optional<DrmDevice> create_drm_device(int fd, int32_t gpu_num)
{
if (fd < 0 || gpu_num < 0) {
return std::nullopt;
}
// Try getting the name
std::string name = query_drm_name(fd);
if (name.empty()) {
return std::nullopt;
}
auto ret = DrmDevice();
ret.fd = fd;
ret.gpu_num = gpu_num;
ret.name = name;
return ret;
}
std::vector<DrmDevice> DrmDevice::create_all()
{
std::vector<DrmDevice> ret = {};
drmDevicePtr devices[MAX_DRM_DEVICES] = {};
int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
if (num_devices <= 0) {
return ret;
}
for (int32_t gpu_num = 0; gpu_num < num_devices; gpu_num++) {
drmDevicePtr device = devices[gpu_num];
if ((device->available_nodes & (1 << DRM_NODE_RENDER))) {
int fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR);
// If it can create a device, push it into the vector
if (auto drm_device = create_drm_device(fd, gpu_num)) {
ret.emplace_back(std::move(drm_device.value()));
}
}
}
drmFreeDevices(devices, num_devices);
return ret;
}
std::optional<DrmDevice> DrmDevice::create(int32_t gpu_num)
{
std::optional<DrmDevice> ret = std::nullopt;
if (gpu_num < 0) {
return ret;
}
drmDevicePtr devices[MAX_DRM_DEVICES] = {};
int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
if (num_devices > 0 && gpu_num < num_devices) {
drmDevicePtr device = devices[gpu_num];
int fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR);
ret = create_drm_device(fd, gpu_num);
}
drmFreeDevices(devices, num_devices);
return ret;
}
DrmDevice::DrmDevice(DrmDevice &&other)
: fd {other.fd}
, gpu_num {other.gpu_num}
, name {std::move(other.name)}
{
other.fd = -1;
other.gpu_num = -1;
}
DrmDevice &DrmDevice::operator=(DrmDevice &&other)
{
std::swap(fd, other.fd);
std::swap(gpu_num, other.gpu_num);
std::swap(name, other.name);
return *this;
}
DrmDevice::~DrmDevice()
{
if (fd >= 0) {
close(fd);
}
}
DrmDevice::operator bool() const
{
return !name.empty();
}
} // namespace pps