/* * Copyright © 2020 Collabora, Ltd. * Author: Antonio Caggiano * Author: Rohan Garg * Author: Robert Beckett * * SPDX-License-Identifier: MIT */ #include "pps_device.h" #include #include #include #include #include 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(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 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::create_all() { std::vector 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::create(int32_t gpu_num) { std::optional 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