1 /*
2 * Copyright 2022 Google
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include <pthread.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9
10 #include <cerrno>
11 #include <cstring>
12 #include <fstream>
13 #include <string>
14
15 #include "VirtGpuKumquat.h"
16 #include "util/log.h"
17 #include "virtgpu_gfxstream_protocol.h"
18
19 #define PARAM(x) \
20 (struct VirtGpuParam) { x, #x, 0 }
21
align_up(uint32_t n,uint32_t a)22 static inline uint32_t align_up(uint32_t n, uint32_t a) { return ((n + a - 1) / a) * a; }
23
VirtGpuKumquatDevice(enum VirtGpuCapset capset,int32_t descriptor)24 VirtGpuKumquatDevice::VirtGpuKumquatDevice(enum VirtGpuCapset capset, int32_t descriptor)
25 : VirtGpuDevice(capset) {
26 struct VirtGpuParam params[] = {
27 PARAM(VIRTGPU_KUMQUAT_PARAM_3D_FEATURES),
28 PARAM(VIRTGPU_KUMQUAT_PARAM_CAPSET_QUERY_FIX),
29 PARAM(VIRTGPU_KUMQUAT_PARAM_RESOURCE_BLOB),
30 PARAM(VIRTGPU_KUMQUAT_PARAM_HOST_VISIBLE),
31 PARAM(VIRTGPU_KUMQUAT_PARAM_CROSS_DEVICE),
32 PARAM(VIRTGPU_KUMQUAT_PARAM_CONTEXT_INIT),
33 PARAM(VIRTGPU_KUMQUAT_PARAM_SUPPORTED_CAPSET_IDs),
34 PARAM(VIRTGPU_KUMQUAT_PARAM_EXPLICIT_DEBUG_NAME),
35 PARAM(VIRTGPU_KUMQUAT_PARAM_FENCE_PASSING),
36 PARAM(VIRTGPU_KUMQUAT_PARAM_CREATE_GUEST_HANDLE),
37 };
38
39 int ret;
40 struct drm_kumquat_get_caps get_caps = {0};
41 struct drm_kumquat_context_init init = {0};
42 struct drm_kumquat_context_set_param ctx_set_params[3] = {{0}};
43 const char* processName = nullptr;
44 std::string gpu_socket_path = "/tmp/kumquat-gpu-";
45
46 memset(&mCaps, 0, sizeof(struct VirtGpuCaps));
47
48 #ifdef __ANDROID__
49 processName = getprogname();
50 #endif
51
52 if (descriptor >= 0) {
53 gpu_socket_path.append(std::to_string(descriptor));
54 mDescriptor = descriptor;
55 } else {
56 gpu_socket_path.append("0");
57 }
58
59 ret = virtgpu_kumquat_init(&mVirtGpu, gpu_socket_path.c_str());
60 if (ret) {
61 mesa_logi("Failed to init virtgpu kumquat");
62 return;
63 }
64
65 for (uint32_t i = 0; i < kParamMax; i++) {
66 struct drm_kumquat_getparam get_param = {0};
67 get_param.param = params[i].param;
68
69 ret = virtgpu_kumquat_get_param(mVirtGpu, &get_param);
70 if (ret) {
71 mesa_logi("virtgpu backend not enabling %s", params[i].name);
72 continue;
73 }
74
75 mCaps.params[i] = get_param.value;
76 }
77
78 get_caps.cap_set_id = static_cast<uint32_t>(capset);
79 switch (capset) {
80 case kCapsetGfxStreamVulkan:
81 get_caps.size = sizeof(struct vulkanCapset);
82 get_caps.addr = (unsigned long long)&mCaps.vulkanCapset;
83 break;
84 case kCapsetGfxStreamMagma:
85 get_caps.size = sizeof(struct magmaCapset);
86 get_caps.addr = (unsigned long long)&mCaps.magmaCapset;
87 break;
88 case kCapsetGfxStreamGles:
89 get_caps.size = sizeof(struct vulkanCapset);
90 get_caps.addr = (unsigned long long)&mCaps.glesCapset;
91 break;
92 case kCapsetGfxStreamComposer:
93 get_caps.size = sizeof(struct vulkanCapset);
94 get_caps.addr = (unsigned long long)&mCaps.composerCapset;
95 break;
96 default:
97 get_caps.size = 0;
98 }
99
100 ret = virtgpu_kumquat_get_caps(mVirtGpu, &get_caps);
101 if (ret) {
102 // Don't fail get capabilities just yet, AEMU doesn't use this API
103 // yet (b/272121235);
104 mesa_loge("DRM_IOCTL_VIRTGPU_KUMQUAT_GET_CAPS failed with %s", strerror(errno));
105 }
106
107 // We always need an ASG blob in some cases, so always define blobAlignment
108 if (!mCaps.vulkanCapset.blobAlignment) {
109 mCaps.vulkanCapset.blobAlignment = 4096;
110 }
111
112 ctx_set_params[0].param = VIRTGPU_KUMQUAT_CONTEXT_PARAM_NUM_RINGS;
113 ctx_set_params[0].value = 2;
114 init.num_params = 1;
115
116 if (capset != kCapsetNone) {
117 ctx_set_params[init.num_params].param = VIRTGPU_KUMQUAT_CONTEXT_PARAM_CAPSET_ID;
118 ctx_set_params[init.num_params].value = static_cast<uint32_t>(capset);
119 init.num_params++;
120 }
121
122 if (mCaps.params[kParamExplicitDebugName] && processName) {
123 ctx_set_params[init.num_params].param = VIRTGPU_KUMQUAT_CONTEXT_PARAM_DEBUG_NAME;
124 ctx_set_params[init.num_params].value = reinterpret_cast<uint64_t>(processName);
125 init.num_params++;
126 }
127
128 init.ctx_set_params = (unsigned long long)&ctx_set_params[0];
129 ret = virtgpu_kumquat_context_init(mVirtGpu, &init);
130 if (ret) {
131 mesa_loge(
132 "DRM_IOCTL_VIRTGPU_KUMQUAT_CONTEXT_INIT failed with %s, continuing without context...",
133 strerror(errno));
134 }
135 }
136
~VirtGpuKumquatDevice()137 VirtGpuKumquatDevice::~VirtGpuKumquatDevice() { virtgpu_kumquat_finish(&mVirtGpu); }
138
getCaps(void)139 struct VirtGpuCaps VirtGpuKumquatDevice::getCaps(void) { return mCaps; }
140
getDeviceHandle(void)141 int64_t VirtGpuKumquatDevice::getDeviceHandle(void) { return mDescriptor; }
142
createResource(uint32_t width,uint32_t height,uint32_t stride,uint32_t size,uint32_t virglFormat,uint32_t target,uint32_t bind)143 VirtGpuResourcePtr VirtGpuKumquatDevice::createResource(uint32_t width, uint32_t height,
144 uint32_t stride, uint32_t size,
145 uint32_t virglFormat, uint32_t target,
146 uint32_t bind) {
147 struct drm_kumquat_resource_create_3d create = {
148 .target = target,
149 .format = virglFormat,
150 .bind = bind,
151 .width = width,
152 .height = height,
153 .depth = 1U,
154 .array_size = 1U,
155 .last_level = 0,
156 .nr_samples = 0,
157 .size = size,
158 .stride = stride,
159 };
160
161 int ret = virtgpu_kumquat_resource_create_3d(mVirtGpu, &create);
162 if (ret) {
163 mesa_loge("DRM_IOCTL_VIRTGPU_KUMQUAT_RESOURCE_CREATE failed with %s", strerror(errno));
164 return nullptr;
165 }
166
167 return std::make_shared<VirtGpuKumquatResource>(mVirtGpu, create.bo_handle, create.res_handle,
168 static_cast<uint64_t>(create.size));
169 }
170
createBlob(const struct VirtGpuCreateBlob & blobCreate)171 VirtGpuResourcePtr VirtGpuKumquatDevice::createBlob(const struct VirtGpuCreateBlob& blobCreate) {
172 int ret;
173 struct drm_kumquat_resource_create_blob create = {0};
174
175 create.size = blobCreate.size;
176 create.blob_mem = blobCreate.blobMem;
177 create.blob_flags = blobCreate.flags;
178 create.blob_id = blobCreate.blobId;
179 create.cmd = (uint64_t)(uintptr_t)blobCreate.blobCmd;
180 create.cmd_size = blobCreate.blobCmdSize;
181
182 ret = virtgpu_kumquat_resource_create_blob(mVirtGpu, &create);
183 if (ret < 0) {
184 mesa_loge("DRM_VIRTGPU_KUMQUAT_RESOURCE_CREATE_BLOB failed with %s", strerror(errno));
185 return nullptr;
186 }
187
188 return std::make_shared<VirtGpuKumquatResource>(mVirtGpu, create.bo_handle, create.res_handle,
189 blobCreate.size);
190 }
191
importBlob(const struct VirtGpuExternalHandle & handle)192 VirtGpuResourcePtr VirtGpuKumquatDevice::importBlob(const struct VirtGpuExternalHandle& handle) {
193 int ret;
194 struct drm_kumquat_resource_import resource_import = {0};
195
196 resource_import.os_handle = static_cast<uint64_t>(handle.osHandle);
197 resource_import.handle_type = static_cast<uint32_t>(handle.type);
198
199 ret = virtgpu_kumquat_resource_import(mVirtGpu, &resource_import);
200 if (ret < 0) {
201 mesa_loge("DRM_VIRTGPU_KUMQUAT_RESOURCE_IMPORT failed with %s", strerror(errno));
202 return nullptr;
203 }
204
205 return std::make_shared<VirtGpuKumquatResource>(
206 mVirtGpu, resource_import.bo_handle, resource_import.res_handle, resource_import.size);
207 }
208
execBuffer(struct VirtGpuExecBuffer & execbuffer,const VirtGpuResource * blob)209 int VirtGpuKumquatDevice::execBuffer(struct VirtGpuExecBuffer& execbuffer,
210 const VirtGpuResource* blob) {
211 int ret;
212 struct drm_kumquat_execbuffer exec = {0};
213 uint32_t blobHandle;
214
215 exec.flags = execbuffer.flags;
216 exec.size = execbuffer.command_size;
217 exec.ring_idx = execbuffer.ring_idx;
218 exec.command = (uint64_t)(uintptr_t)(execbuffer.command);
219 exec.fence_handle = -1;
220
221 if (blob) {
222 blobHandle = blob->getBlobHandle();
223 exec.bo_handles = (uint64_t)(uintptr_t)(&blobHandle);
224 exec.num_bo_handles = 1;
225 }
226
227 ret = virtgpu_kumquat_execbuffer(mVirtGpu, &exec);
228 if (ret) {
229 mesa_loge("DRM_IOCTL_VIRTGPU_KUMQUAT_EXECBUFFER failed: %s", strerror(errno));
230 return ret;
231 }
232
233 if (execbuffer.flags & kFenceOut) {
234 execbuffer.handle.osHandle = exec.fence_handle;
235 execbuffer.handle.type = kFenceHandleSyncFd;
236 }
237
238 return 0;
239 }
240
kumquatCreateVirtGpuDevice(enum VirtGpuCapset capset,int32_t descriptor)241 VirtGpuDevice* kumquatCreateVirtGpuDevice(enum VirtGpuCapset capset, int32_t descriptor) {
242 return new VirtGpuKumquatDevice(capset, descriptor);
243 }
244