1 /*
2 * Copyright 2023 Google LLC
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include <lib/zx/vmo.h>
7 #include <msd-virtio-gpu/magma-virtio-gpu-defs.h>
8 #include <os_dirent.h>
9 #include <services/service_connector.h>
10
11 #include <climits>
12 #include <cstdio>
13 #include <cstdlib>
14
15 #include "FuchsiaVirtGpu.h"
16 #include "Sync.h"
17 #include "util/log.h"
18
FuchsiaVirtGpuDevice(enum VirtGpuCapset capset,magma_device_t device)19 FuchsiaVirtGpuDevice::FuchsiaVirtGpuDevice(enum VirtGpuCapset capset, magma_device_t device)
20 : VirtGpuDevice(capset), device_(device) {
21 memset(&mCaps, 0, sizeof(struct VirtGpuCaps));
22
23 // Hard-coded values that may be assumed on Fuchsia.
24 mCaps.params[kParam3D] = 1;
25 mCaps.params[kParamCapsetFix] = 1;
26 mCaps.params[kParamResourceBlob] = 1;
27 mCaps.params[kParamHostVisible] = 1;
28 mCaps.params[kParamCrossDevice] = 0;
29 mCaps.params[kParamContextInit] = 1;
30 mCaps.params[kParamSupportedCapsetIds] = 0;
31 mCaps.params[kParamExplicitDebugName] = 0;
32 mCaps.params[kParamCreateGuestHandle] = 0;
33
34 if (capset == kCapsetGfxStreamVulkan) {
35 uint64_t query_id = kMagmaVirtioGpuQueryCapset;
36 query_id |= static_cast<uint64_t>(kCapsetGfxStreamVulkan) << 32;
37 constexpr uint16_t kVersion = 0;
38 query_id |= static_cast<uint64_t>(kVersion) << 16;
39
40 magma_handle_t buffer;
41 magma_status_t status = magma_device_query(device_, query_id, &buffer, nullptr);
42 if (status == MAGMA_STATUS_OK) {
43 zx::vmo capset_info(buffer);
44 zx_status_t status =
45 capset_info.read(&mCaps.vulkanCapset, /*offset=*/0, sizeof(struct vulkanCapset));
46 mesa_logi("Got capset result, read status %d", status);
47 } else {
48 mesa_loge("Query(%lu) failed: status %d, expected buffer result", query_id, status);
49 }
50
51 // We always need an ASG blob in some cases, so always define blobAlignment
52 if (!mCaps.vulkanCapset.blobAlignment) {
53 mCaps.vulkanCapset.blobAlignment = 4096;
54 }
55 }
56 }
57
~FuchsiaVirtGpuDevice()58 FuchsiaVirtGpuDevice::~FuchsiaVirtGpuDevice() { magma_device_release(device_); }
59
getDeviceHandle(void)60 int64_t FuchsiaVirtGpuDevice::getDeviceHandle(void) { return device_; }
61
createBlob(const struct VirtGpuCreateBlob & blobCreate)62 VirtGpuResourcePtr FuchsiaVirtGpuDevice::createBlob(const struct VirtGpuCreateBlob& blobCreate) {
63 mesa_loge("%s: unimplemented", __func__);
64 return nullptr;
65 }
66
createResource(uint32_t width,uint32_t height,uint32_t stride,uint32_t size,uint32_t virglFormat,uint32_t target,uint32_t bind)67 VirtGpuResourcePtr FuchsiaVirtGpuDevice::createResource(uint32_t width, uint32_t height,
68 uint32_t stride, uint32_t size,
69 uint32_t virglFormat, uint32_t target,
70 uint32_t bind) {
71 mesa_loge("%s: unimplemented", __func__);
72 return nullptr;
73 }
74
importBlob(const struct VirtGpuExternalHandle & handle)75 VirtGpuResourcePtr FuchsiaVirtGpuDevice::importBlob(const struct VirtGpuExternalHandle& handle) {
76 mesa_loge("%s: unimplemented", __func__);
77 return nullptr;
78 }
79
execBuffer(struct VirtGpuExecBuffer & execbuffer,const VirtGpuResource * blob)80 int FuchsiaVirtGpuDevice::execBuffer(struct VirtGpuExecBuffer& execbuffer,
81 const VirtGpuResource* blob) {
82 mesa_loge("%s: unimplemented", __func__);
83 return 0;
84 }
85
getCaps(void)86 struct VirtGpuCaps FuchsiaVirtGpuDevice::getCaps(void) { return {}; }
87
osCreateVirtGpuDevice(enum VirtGpuCapset capset,int32_t descriptor)88 VirtGpuDevice* osCreateVirtGpuDevice(enum VirtGpuCapset capset, int32_t descriptor) {
89 // We don't handle the VirtioGpuPipeStream case.
90 if (descriptor >= 0) {
91 mesa_loge("Fuchsia: fd not handled");
92 return nullptr;
93 }
94
95 const char kDevGpu[] = "/loader-gpu-devices/class/gpu";
96
97 struct os_dirent* de;
98 os_dir_t* dir = os_opendir(kDevGpu);
99 if (!dir) {
100 mesa_loge("Error opening %s", kDevGpu);
101 return nullptr;
102 }
103
104 mesa_logi("Opened dir %s", kDevGpu);
105
106 VirtGpuDevice* gpu_device = nullptr;
107
108 while ((de = os_readdir(dir)) != NULL) {
109 mesa_logi("Got name %s", de->d_name);
110
111 if (strcmp(de->d_name, ".") == 0) {
112 continue;
113 }
114 // extra +1 ensures space for null termination
115 char name[sizeof(kDevGpu) + sizeof('/') + sizeof(de->d_name) + 1];
116 snprintf(name, sizeof(name), "%s/%s", kDevGpu, de->d_name);
117
118 zx_handle_t device_channel = GetConnectToServiceFunction()(name);
119 if (device_channel == ZX_HANDLE_INVALID) {
120 mesa_loge("Failed to open device: %s", name);
121 continue;
122 }
123
124 magma_device_t magma_device;
125 magma_status_t status = magma_device_import(device_channel, &magma_device);
126 if (status != MAGMA_STATUS_OK) {
127 mesa_loge("magma_device_import failed: %d", status);
128 continue;
129 }
130
131 gpu_device = new FuchsiaVirtGpuDevice(capset, magma_device);
132 break;
133 }
134 os_closedir(dir);
135
136 return gpu_device;
137 }
138
139 namespace gfxstream {
140
osCreateSyncHelper()141 SyncHelper* osCreateSyncHelper() { return nullptr; }
142
143 } // namespace gfxstream
144