17ec681f3Smrg/* 27ec681f3Smrg * Copyright © 2020 Collabora, Ltd. 37ec681f3Smrg * Author: Antonio Caggiano <antonio.caggiano@collabora.com> 47ec681f3Smrg * Author: Rohan Garg <rohan.garg@collabora.com> 57ec681f3Smrg * Author: Robert Beckett <bob.beckett@collabora.com> 67ec681f3Smrg * 77ec681f3Smrg * SPDX-License-Identifier: MIT 87ec681f3Smrg */ 97ec681f3Smrg 107ec681f3Smrg#include "pps_device.h" 117ec681f3Smrg 127ec681f3Smrg#include <cassert> 137ec681f3Smrg#include <fcntl.h> 147ec681f3Smrg#include <memory> 157ec681f3Smrg#include <unistd.h> 167ec681f3Smrg#include <xf86drm.h> 177ec681f3Smrg 187ec681f3Smrgnamespace pps 197ec681f3Smrg{ 207ec681f3Smrg#define MAX_DRM_DEVICES 64 217ec681f3Smrg 227ec681f3Smrguint32_t DrmDevice::device_count() 237ec681f3Smrg{ 247ec681f3Smrg drmDevicePtr devices[MAX_DRM_DEVICES] = {}; 257ec681f3Smrg int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES); 267ec681f3Smrg drmFreeDevices(devices, num_devices); 277ec681f3Smrg return static_cast<uint32_t>(num_devices); 287ec681f3Smrg} 297ec681f3Smrg 307ec681f3Smrg/// @return The name of a DRM device, empty string in case of error 317ec681f3Smrgstd::string query_drm_name(const int fd) 327ec681f3Smrg{ 337ec681f3Smrg assert(fd && "Failed to query DrmDevice: invalid fd"); 347ec681f3Smrg 357ec681f3Smrg std::string name = ""; 367ec681f3Smrg 377ec681f3Smrg if (drmVersionPtr version = drmGetVersion(fd)) { 387ec681f3Smrg name = std::string(version->name, version->name_len); 397ec681f3Smrg drmFreeVersion(version); 407ec681f3Smrg } 417ec681f3Smrg 427ec681f3Smrg return name; 437ec681f3Smrg} 447ec681f3Smrg 457ec681f3Smrg/// @return A DRM device, nullopt in case of error 467ec681f3Smrgstd::optional<DrmDevice> create_drm_device(int fd, int32_t gpu_num) 477ec681f3Smrg{ 487ec681f3Smrg if (fd < 0 || gpu_num < 0) { 497ec681f3Smrg return std::nullopt; 507ec681f3Smrg } 517ec681f3Smrg 527ec681f3Smrg // Try getting the name 537ec681f3Smrg std::string name = query_drm_name(fd); 547ec681f3Smrg if (name.empty()) { 557ec681f3Smrg return std::nullopt; 567ec681f3Smrg } 577ec681f3Smrg 587ec681f3Smrg auto ret = DrmDevice(); 597ec681f3Smrg ret.fd = fd; 607ec681f3Smrg ret.gpu_num = gpu_num; 617ec681f3Smrg ret.name = name; 627ec681f3Smrg return ret; 637ec681f3Smrg} 647ec681f3Smrg 657ec681f3Smrgstd::vector<DrmDevice> DrmDevice::create_all() 667ec681f3Smrg{ 677ec681f3Smrg std::vector<DrmDevice> ret = {}; 687ec681f3Smrg 697ec681f3Smrg drmDevicePtr devices[MAX_DRM_DEVICES] = {}; 707ec681f3Smrg int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES); 717ec681f3Smrg if (num_devices <= 0) { 727ec681f3Smrg return ret; 737ec681f3Smrg } 747ec681f3Smrg 757ec681f3Smrg for (int32_t gpu_num = 0; gpu_num < num_devices; gpu_num++) { 767ec681f3Smrg drmDevicePtr device = devices[gpu_num]; 777ec681f3Smrg if ((device->available_nodes & (1 << DRM_NODE_RENDER))) { 787ec681f3Smrg int fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR); 797ec681f3Smrg 807ec681f3Smrg // If it can create a device, push it into the vector 817ec681f3Smrg if (auto drm_device = create_drm_device(fd, gpu_num)) { 827ec681f3Smrg ret.emplace_back(std::move(drm_device.value())); 837ec681f3Smrg } 847ec681f3Smrg } 857ec681f3Smrg } 867ec681f3Smrg 877ec681f3Smrg drmFreeDevices(devices, num_devices); 887ec681f3Smrg return ret; 897ec681f3Smrg} 907ec681f3Smrg 917ec681f3Smrgstd::optional<DrmDevice> DrmDevice::create(int32_t gpu_num) 927ec681f3Smrg{ 937ec681f3Smrg std::optional<DrmDevice> ret = std::nullopt; 947ec681f3Smrg 957ec681f3Smrg if (gpu_num < 0) { 967ec681f3Smrg return ret; 977ec681f3Smrg } 987ec681f3Smrg 997ec681f3Smrg drmDevicePtr devices[MAX_DRM_DEVICES] = {}; 1007ec681f3Smrg int num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES); 1017ec681f3Smrg 1027ec681f3Smrg if (num_devices > 0 && gpu_num < num_devices) { 1037ec681f3Smrg drmDevicePtr device = devices[gpu_num]; 1047ec681f3Smrg int fd = open(device->nodes[DRM_NODE_RENDER], O_RDONLY); 1057ec681f3Smrg ret = create_drm_device(fd, gpu_num); 1067ec681f3Smrg } 1077ec681f3Smrg 1087ec681f3Smrg drmFreeDevices(devices, num_devices); 1097ec681f3Smrg return ret; 1107ec681f3Smrg} 1117ec681f3Smrg 1127ec681f3SmrgDrmDevice::DrmDevice(DrmDevice &&other) 1137ec681f3Smrg : fd {other.fd} 1147ec681f3Smrg , gpu_num {other.gpu_num} 1157ec681f3Smrg , name {std::move(other.name)} 1167ec681f3Smrg{ 1177ec681f3Smrg other.fd = -1; 1187ec681f3Smrg other.gpu_num = -1; 1197ec681f3Smrg} 1207ec681f3Smrg 1217ec681f3SmrgDrmDevice &DrmDevice::operator=(DrmDevice &&other) 1227ec681f3Smrg{ 1237ec681f3Smrg std::swap(fd, other.fd); 1247ec681f3Smrg std::swap(gpu_num, other.gpu_num); 1257ec681f3Smrg std::swap(name, other.name); 1267ec681f3Smrg return *this; 1277ec681f3Smrg} 1287ec681f3Smrg 1297ec681f3SmrgDrmDevice::~DrmDevice() 1307ec681f3Smrg{ 1317ec681f3Smrg if (fd >= 0) { 1327ec681f3Smrg close(fd); 1337ec681f3Smrg } 1347ec681f3Smrg} 1357ec681f3Smrg 1367ec681f3SmrgDrmDevice::operator bool() const 1377ec681f3Smrg{ 1387ec681f3Smrg return !name.empty(); 1397ec681f3Smrg} 1407ec681f3Smrg 1417ec681f3Smrg} // namespace pps 142