142 lines
3.2 KiB
C++
142 lines
3.2 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_RDONLY);
|
|
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
|