xref: /aosp_15_r20/external/mesa3d/src/gfxstream/guest/platform/kumquat/VirtGpuKumquatDevice.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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