1 // Copyright (C) 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <errno.h>
16 #include <string.h>
17
18 #include "../vulkan_enc/vk_util.h"
19 #include "HostConnection.h"
20 #include "ProcessPipe.h"
21 #include "ResourceTracker.h"
22 #include "VkEncoder.h"
23 #include "gfxstream_vk_entrypoints.h"
24 #include "gfxstream_vk_private.h"
25 #include "vk_alloc.h"
26 #include "vk_device.h"
27 #include "vk_instance.h"
28 #include "vk_sync_dummy.h"
29
30 #define VK_HOST_CONNECTION(ret) \
31 HostConnection* hostCon = HostConnection::getOrCreate(kCapsetGfxStreamVulkan); \
32 gfxstream::vk::VkEncoder* vkEnc = hostCon->vkEncoder(); \
33 if (!vkEnc) { \
34 mesa_loge("vulkan: Failed to get Vulkan encoder\n"); \
35 return ret; \
36 }
37
38 namespace {
39
40 static bool instance_extension_table_initialized = false;
41 static struct vk_instance_extension_table gfxstream_vk_instance_extensions_supported = {};
42
43 // Provided by Mesa components only; never encoded/decoded through gfxstream
44 static const char* const kMesaOnlyInstanceExtension[] = {
45 VK_KHR_SURFACE_EXTENSION_NAME,
46 #if defined(LINUX_GUEST_BUILD)
47 VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
48 #endif
49 VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
50 };
51
52 static const char* const kMesaOnlyDeviceExtensions[] = {
53 VK_KHR_SWAPCHAIN_EXTENSION_NAME,
54 };
55
getConnection(void)56 static HostConnection* getConnection(void) {
57 auto hostCon = HostConnection::getOrCreate(kCapsetGfxStreamVulkan);
58 return hostCon;
59 }
60
getVkEncoder(HostConnection * con)61 static gfxstream::vk::VkEncoder* getVkEncoder(HostConnection* con) { return con->vkEncoder(); }
62
SetupInstanceForProcess(void)63 static VkResult SetupInstanceForProcess(void) {
64 uint32_t noRenderControlEnc = 0;
65 HostConnection* hostCon = getConnection();
66 if (!hostCon) {
67 mesa_loge("vulkan: Failed to get host connection\n");
68 return VK_ERROR_DEVICE_LOST;
69 }
70
71 gfxstream::vk::ResourceTracker::get()->setupCaps(noRenderControlEnc);
72 // Legacy goldfish path: could be deleted once goldfish not used guest-side.
73 if (!noRenderControlEnc) {
74 // Implicitly sets up sequence number
75 ExtendedRCEncoderContext* rcEnc = hostCon->rcEncoder();
76 if (!rcEnc) {
77 mesa_loge("vulkan: Failed to get renderControl encoder context\n");
78 return VK_ERROR_DEVICE_LOST;
79 }
80
81 gfxstream::vk::ResourceTracker::get()->setupFeatures(rcEnc->featureInfo_const());
82 }
83
84 gfxstream::vk::ResourceTracker::get()->setThreadingCallbacks({
85 .hostConnectionGetFunc = getConnection,
86 .vkEncoderGetFunc = getVkEncoder,
87 });
88 gfxstream::vk::ResourceTracker::get()->setSeqnoPtr(getSeqnoPtrForProcess());
89 gfxstream::vk::VkEncoder* vkEnc = getVkEncoder(hostCon);
90 if (!vkEnc) {
91 mesa_loge("vulkan: Failed to get Vulkan encoder\n");
92 return VK_ERROR_DEVICE_LOST;
93 }
94
95 return VK_SUCCESS;
96 }
97
isMesaOnlyInstanceExtension(const char * name)98 static bool isMesaOnlyInstanceExtension(const char* name) {
99 for (auto mesaExt : kMesaOnlyInstanceExtension) {
100 if (!strncmp(mesaExt, name, VK_MAX_EXTENSION_NAME_SIZE)) return true;
101 }
102 return false;
103 }
104
isMesaOnlyDeviceExtension(const char * name)105 static bool isMesaOnlyDeviceExtension(const char* name) {
106 for (auto mesaExt : kMesaOnlyDeviceExtensions) {
107 if (!strncmp(mesaExt, name, VK_MAX_EXTENSION_NAME_SIZE)) return true;
108 }
109 return false;
110 }
111
112 // Filtered extension names for encoding
filteredInstanceExtensionNames(uint32_t count,const char * const * extNames)113 static std::vector<const char*> filteredInstanceExtensionNames(uint32_t count,
114 const char* const* extNames) {
115 std::vector<const char*> retList;
116 for (uint32_t i = 0; i < count; ++i) {
117 auto extName = extNames[i];
118 if (!isMesaOnlyInstanceExtension(extName)) {
119 retList.push_back(extName);
120 }
121 }
122 return retList;
123 }
124
filteredDeviceExtensionNames(uint32_t count,const char * const * extNames)125 static std::vector<const char*> filteredDeviceExtensionNames(uint32_t count,
126 const char* const* extNames) {
127 std::vector<const char*> retList;
128 for (uint32_t i = 0; i < count; ++i) {
129 auto extName = extNames[i];
130 if (!isMesaOnlyDeviceExtension(extName)) {
131 retList.push_back(extName);
132 }
133 }
134 return retList;
135 }
136
get_device_extensions(VkPhysicalDevice physDevInternal,struct vk_device_extension_table * deviceExts)137 static void get_device_extensions(VkPhysicalDevice physDevInternal,
138 struct vk_device_extension_table* deviceExts) {
139 VkResult result = (VkResult)0;
140 auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
141 auto resources = gfxstream::vk::ResourceTracker::get();
142 uint32_t numDeviceExts = 0;
143 result = resources->on_vkEnumerateDeviceExtensionProperties(vkEnc, VK_SUCCESS, physDevInternal,
144 NULL, &numDeviceExts, NULL);
145 if (VK_SUCCESS == result) {
146 std::vector<VkExtensionProperties> extProps(numDeviceExts);
147 result = resources->on_vkEnumerateDeviceExtensionProperties(
148 vkEnc, VK_SUCCESS, physDevInternal, NULL, &numDeviceExts, extProps.data());
149 if (VK_SUCCESS == result) {
150 // device extensions from gfxstream
151 for (uint32_t i = 0; i < numDeviceExts; i++) {
152 for (uint32_t j = 0; j < VK_DEVICE_EXTENSION_COUNT; j++) {
153 if (0 == strncmp(extProps[i].extensionName,
154 vk_device_extensions[j].extensionName,
155 VK_MAX_EXTENSION_NAME_SIZE)) {
156 deviceExts->extensions[j] = true;
157 break;
158 }
159 }
160 }
161 // device extensions from Mesa
162 for (uint32_t j = 0; j < VK_DEVICE_EXTENSION_COUNT; j++) {
163 if (isMesaOnlyDeviceExtension(vk_device_extensions[j].extensionName)) {
164 deviceExts->extensions[j] = true;
165 break;
166 }
167 }
168 }
169 }
170 }
171
gfxstream_vk_physical_device_init(struct gfxstream_vk_physical_device * physical_device,struct gfxstream_vk_instance * instance,VkPhysicalDevice internal_object)172 static VkResult gfxstream_vk_physical_device_init(
173 struct gfxstream_vk_physical_device* physical_device, struct gfxstream_vk_instance* instance,
174 VkPhysicalDevice internal_object) {
175 struct vk_device_extension_table supported_extensions = {};
176 get_device_extensions(internal_object, &supported_extensions);
177
178 struct vk_physical_device_dispatch_table dispatch_table;
179 memset(&dispatch_table, 0, sizeof(struct vk_physical_device_dispatch_table));
180 vk_physical_device_dispatch_table_from_entrypoints(
181 &dispatch_table, &gfxstream_vk_physical_device_entrypoints, false);
182 #if !defined(__Fuchsia__)
183 vk_physical_device_dispatch_table_from_entrypoints(&dispatch_table,
184 &wsi_physical_device_entrypoints, false);
185 #endif
186
187 // Initialize the mesa object
188 VkResult result = vk_physical_device_init(&physical_device->vk, &instance->vk,
189 &supported_extensions, NULL, NULL, &dispatch_table);
190
191 if (VK_SUCCESS == result) {
192 // Set the gfxstream-internal object
193 physical_device->internal_object = internal_object;
194 physical_device->instance = instance;
195 // Note: Must use dummy_sync for correct sync object path in WSI operations
196 physical_device->sync_types[0] = &vk_sync_dummy_type;
197 physical_device->sync_types[1] = NULL;
198 physical_device->vk.supported_sync_types = physical_device->sync_types;
199
200 result = gfxstream_vk_wsi_init(physical_device);
201 }
202
203 return result;
204 }
205
gfxstream_vk_physical_device_finish(struct gfxstream_vk_physical_device * physical_device)206 static void gfxstream_vk_physical_device_finish(
207 struct gfxstream_vk_physical_device* physical_device) {
208 gfxstream_vk_wsi_finish(physical_device);
209
210 vk_physical_device_finish(&physical_device->vk);
211 }
212
gfxstream_vk_destroy_physical_device(struct vk_physical_device * physical_device)213 static void gfxstream_vk_destroy_physical_device(struct vk_physical_device* physical_device) {
214 gfxstream_vk_physical_device_finish((struct gfxstream_vk_physical_device*)physical_device);
215 vk_free(&physical_device->instance->alloc, physical_device);
216 }
217
gfxstream_vk_enumerate_devices(struct vk_instance * vk_instance)218 static VkResult gfxstream_vk_enumerate_devices(struct vk_instance* vk_instance) {
219 VkResult result = VK_SUCCESS;
220 gfxstream_vk_instance* gfxstream_instance = (gfxstream_vk_instance*)vk_instance;
221 uint32_t deviceCount = 0;
222 auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
223 auto resources = gfxstream::vk::ResourceTracker::get();
224 result = resources->on_vkEnumeratePhysicalDevices(
225 vkEnc, VK_SUCCESS, gfxstream_instance->internal_object, &deviceCount, NULL);
226 if (VK_SUCCESS != result) return result;
227 std::vector<VkPhysicalDevice> internal_list(deviceCount);
228 result = resources->on_vkEnumeratePhysicalDevices(
229 vkEnc, VK_SUCCESS, gfxstream_instance->internal_object, &deviceCount, internal_list.data());
230
231 if (VK_SUCCESS == result) {
232 for (uint32_t i = 0; i < deviceCount; i++) {
233 struct gfxstream_vk_physical_device* gfxstream_physicalDevice =
234 (struct gfxstream_vk_physical_device*)vk_zalloc(
235 &gfxstream_instance->vk.alloc, sizeof(struct gfxstream_vk_physical_device), 8,
236 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
237 if (!gfxstream_physicalDevice) {
238 result = VK_ERROR_OUT_OF_HOST_MEMORY;
239 break;
240 }
241 result = gfxstream_vk_physical_device_init(gfxstream_physicalDevice, gfxstream_instance,
242 internal_list[i]);
243 if (VK_SUCCESS == result) {
244 list_addtail(&gfxstream_physicalDevice->vk.link,
245 &gfxstream_instance->vk.physical_devices.list);
246 } else {
247 vk_free(&gfxstream_instance->vk.alloc, gfxstream_physicalDevice);
248 break;
249 }
250 }
251 }
252
253 return result;
254 }
255
get_instance_extensions()256 static struct vk_instance_extension_table* get_instance_extensions() {
257 struct vk_instance_extension_table* const retTablePtr =
258 &gfxstream_vk_instance_extensions_supported;
259 if (!instance_extension_table_initialized) {
260 VkResult result = SetupInstanceForProcess();
261 if (VK_SUCCESS == result) {
262 VK_HOST_CONNECTION(retTablePtr)
263 auto resources = gfxstream::vk::ResourceTracker::get();
264 uint32_t numInstanceExts = 0;
265 result = resources->on_vkEnumerateInstanceExtensionProperties(vkEnc, VK_SUCCESS, NULL,
266 &numInstanceExts, NULL);
267 if (VK_SUCCESS == result) {
268 std::vector<VkExtensionProperties> extProps(numInstanceExts);
269 result = resources->on_vkEnumerateInstanceExtensionProperties(
270 vkEnc, VK_SUCCESS, NULL, &numInstanceExts, extProps.data());
271 if (VK_SUCCESS == result) {
272 // instance extensions from gfxstream
273 for (uint32_t i = 0; i < numInstanceExts; i++) {
274 for (uint32_t j = 0; j < VK_INSTANCE_EXTENSION_COUNT; j++) {
275 if (0 == strncmp(extProps[i].extensionName,
276 vk_instance_extensions[j].extensionName,
277 VK_MAX_EXTENSION_NAME_SIZE)) {
278 gfxstream_vk_instance_extensions_supported.extensions[j] = true;
279 break;
280 }
281 }
282 }
283 // instance extensions from Mesa
284 for (uint32_t j = 0; j < VK_INSTANCE_EXTENSION_COUNT; j++) {
285 if (isMesaOnlyInstanceExtension(vk_instance_extensions[j].extensionName)) {
286 gfxstream_vk_instance_extensions_supported.extensions[j] = true;
287 }
288 }
289 instance_extension_table_initialized = true;
290 }
291 }
292 }
293 }
294 return retTablePtr;
295 }
296
297 } // namespace
298
gfxstream_vk_CreateInstance(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * pInstance)299 VkResult gfxstream_vk_CreateInstance(const VkInstanceCreateInfo* pCreateInfo,
300 const VkAllocationCallbacks* pAllocator,
301 VkInstance* pInstance) {
302 AEMU_SCOPED_TRACE("vkCreateInstance");
303
304 struct gfxstream_vk_instance* instance;
305
306 pAllocator = pAllocator ?: vk_default_allocator();
307 instance = (struct gfxstream_vk_instance*)vk_zalloc(pAllocator, sizeof(*instance), 8,
308 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
309 if (NULL == instance) {
310 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
311 }
312
313 VkResult result = VK_SUCCESS;
314 /* Encoder call */
315 {
316 ALOGV("calling setup instance internally");
317 result = SetupInstanceForProcess();
318 if (VK_SUCCESS != result) {
319 return vk_error(NULL, result);
320 }
321 uint32_t initialEnabledExtensionCount = pCreateInfo->enabledExtensionCount;
322 const char* const* initialPpEnabledExtensionNames = pCreateInfo->ppEnabledExtensionNames;
323 std::vector<const char*> filteredExts = filteredInstanceExtensionNames(
324 pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
325 // Temporarily modify createInfo for the encoder call
326 VkInstanceCreateInfo* mutableCreateInfo = (VkInstanceCreateInfo*)pCreateInfo;
327 mutableCreateInfo->enabledExtensionCount = static_cast<uint32_t>(filteredExts.size());
328 mutableCreateInfo->ppEnabledExtensionNames = filteredExts.data();
329
330 VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST);
331 result = vkEnc->vkCreateInstance(pCreateInfo, nullptr, &instance->internal_object,
332 true /* do lock */);
333 if (VK_SUCCESS != result) {
334 return vk_error(NULL, result);
335 }
336 // Revert the createInfo the user-set data
337 mutableCreateInfo->enabledExtensionCount = initialEnabledExtensionCount;
338 mutableCreateInfo->ppEnabledExtensionNames = initialPpEnabledExtensionNames;
339 }
340
341 struct vk_instance_dispatch_table dispatch_table;
342 memset(&dispatch_table, 0, sizeof(struct vk_instance_dispatch_table));
343 vk_instance_dispatch_table_from_entrypoints(&dispatch_table, &gfxstream_vk_instance_entrypoints,
344 false);
345 #if !defined(__Fuchsia__)
346 vk_instance_dispatch_table_from_entrypoints(&dispatch_table, &wsi_instance_entrypoints, false);
347 #endif
348
349 result = vk_instance_init(&instance->vk, get_instance_extensions(), &dispatch_table,
350 pCreateInfo, pAllocator);
351
352 if (result != VK_SUCCESS) {
353 vk_free(pAllocator, instance);
354 return vk_error(NULL, result);
355 }
356
357 instance->vk.physical_devices.enumerate = gfxstream_vk_enumerate_devices;
358 instance->vk.physical_devices.destroy = gfxstream_vk_destroy_physical_device;
359 // TODO: instance->vk.physical_devices.try_create_for_drm (?)
360
361 *pInstance = gfxstream_vk_instance_to_handle(instance);
362 return VK_SUCCESS;
363 }
364
gfxstream_vk_DestroyInstance(VkInstance _instance,const VkAllocationCallbacks * pAllocator)365 void gfxstream_vk_DestroyInstance(VkInstance _instance, const VkAllocationCallbacks* pAllocator) {
366 AEMU_SCOPED_TRACE("vkDestroyInstance");
367 if (VK_NULL_HANDLE == _instance) return;
368
369 VK_FROM_HANDLE(gfxstream_vk_instance, instance, _instance);
370
371 VK_HOST_CONNECTION()
372 vkEnc->vkDestroyInstance(instance->internal_object, pAllocator, true /* do lock */);
373
374 vk_instance_finish(&instance->vk);
375 vk_free(&instance->vk.alloc, instance);
376
377 // To make End2EndTests happy, since now the host connection is statically linked to
378 // libvulkan_ranchu.so [separate HostConnections now].
379 #if defined(END2END_TESTS)
380 hostCon->exit();
381 processPipeRestart();
382 #endif
383 }
384
gfxstream_vk_EnumerateInstanceExtensionProperties(const char * pLayerName,uint32_t * pPropertyCount,VkExtensionProperties * pProperties)385 VkResult gfxstream_vk_EnumerateInstanceExtensionProperties(const char* pLayerName,
386 uint32_t* pPropertyCount,
387 VkExtensionProperties* pProperties) {
388 AEMU_SCOPED_TRACE("vkvkEnumerateInstanceExtensionProperties");
389 (void)pLayerName;
390
391 return vk_enumerate_instance_extension_properties(get_instance_extensions(), pPropertyCount,
392 pProperties);
393 }
394
gfxstream_vk_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,const char * pLayerName,uint32_t * pPropertyCount,VkExtensionProperties * pProperties)395 VkResult gfxstream_vk_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
396 const char* pLayerName,
397 uint32_t* pPropertyCount,
398 VkExtensionProperties* pProperties) {
399 AEMU_SCOPED_TRACE("vkEnumerateDeviceExtensionProperties");
400 (void)pLayerName;
401 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
402
403 VK_OUTARRAY_MAKE_TYPED(VkExtensionProperties, out, pProperties, pPropertyCount);
404
405 for (int i = 0; i < VK_DEVICE_EXTENSION_COUNT; i++) {
406 if (!pdevice->supported_extensions.extensions[i]) continue;
407
408 vk_outarray_append_typed(VkExtensionProperties, &out, prop) {
409 *prop = vk_device_extensions[i];
410 }
411 }
412
413 return vk_outarray_status(&out);
414 }
415
gfxstream_vk_CreateDevice(VkPhysicalDevice physicalDevice,const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDevice * pDevice)416 VkResult gfxstream_vk_CreateDevice(VkPhysicalDevice physicalDevice,
417 const VkDeviceCreateInfo* pCreateInfo,
418 const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) {
419 AEMU_SCOPED_TRACE("vkCreateDevice");
420 VK_FROM_HANDLE(gfxstream_vk_physical_device, gfxstream_physicalDevice, physicalDevice);
421 VkResult result = (VkResult)0;
422
423 /*
424 * Android's libvulkan implements VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT, but
425 * passes it to the underlying driver anyways. See:
426 *
427 * https://android-review.googlesource.com/c/platform/hardware/google/gfxstream/+/2839438
428 *
429 * and associated bugs. Mesa VK runtime also checks this, so we have to filter out before
430 * reaches it.
431 */
432 VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT* swapchainMaintenance1Features =
433 (VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT*)vk_find_struct<VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT>(pCreateInfo);
434 if (swapchainMaintenance1Features) {
435 swapchainMaintenance1Features->swapchainMaintenance1 = VK_FALSE;
436 }
437
438 const VkAllocationCallbacks* pMesaAllocator =
439 pAllocator ?: &gfxstream_physicalDevice->instance->vk.alloc;
440 struct gfxstream_vk_device* gfxstream_device = (struct gfxstream_vk_device*)vk_zalloc(
441 pMesaAllocator, sizeof(struct gfxstream_vk_device), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
442 result = gfxstream_device ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY;
443 if (VK_SUCCESS == result) {
444 uint32_t initialEnabledExtensionCount = pCreateInfo->enabledExtensionCount;
445 const char* const* initialPpEnabledExtensionNames = pCreateInfo->ppEnabledExtensionNames;
446 std::vector<const char*> filteredExts = filteredDeviceExtensionNames(
447 pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
448 // Temporarily modify createInfo for the encoder call
449 VkDeviceCreateInfo* mutableCreateInfo = (VkDeviceCreateInfo*)pCreateInfo;
450 mutableCreateInfo->enabledExtensionCount = static_cast<uint32_t>(filteredExts.size());
451 mutableCreateInfo->ppEnabledExtensionNames = filteredExts.data();
452
453 /* pNext = VkPhysicalDeviceGroupProperties */
454 std::vector<VkPhysicalDevice> initialPhysicalDeviceList;
455 VkPhysicalDeviceGroupProperties* mutablePhysicalDeviceGroupProperties =
456 (VkPhysicalDeviceGroupProperties*)vk_find_struct<VkPhysicalDeviceGroupProperties>(
457 pCreateInfo);
458 if (mutablePhysicalDeviceGroupProperties) {
459 // Temporarily modify the VkPhysicalDeviceGroupProperties structure to use translated
460 // VkPhysicalDevice references for the encoder call
461 for (int physDev = 0;
462 physDev < mutablePhysicalDeviceGroupProperties->physicalDeviceCount; physDev++) {
463 initialPhysicalDeviceList.push_back(
464 mutablePhysicalDeviceGroupProperties->physicalDevices[physDev]);
465 VK_FROM_HANDLE(gfxstream_vk_physical_device, gfxstream_physicalDevice,
466 mutablePhysicalDeviceGroupProperties->physicalDevices[physDev]);
467 mutablePhysicalDeviceGroupProperties->physicalDevices[physDev] =
468 gfxstream_physicalDevice->internal_object;
469 }
470 }
471
472 auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
473 result = vkEnc->vkCreateDevice(gfxstream_physicalDevice->internal_object, pCreateInfo,
474 pAllocator, &gfxstream_device->internal_object,
475 true /* do lock */);
476 // Revert the createInfo the user-set data
477 mutableCreateInfo->enabledExtensionCount = initialEnabledExtensionCount;
478 mutableCreateInfo->ppEnabledExtensionNames = initialPpEnabledExtensionNames;
479 if (mutablePhysicalDeviceGroupProperties) {
480 // Revert the physicalDevice list in VkPhysicalDeviceGroupProperties to the user-set
481 // data
482 for (int physDev = 0;
483 physDev < mutablePhysicalDeviceGroupProperties->physicalDeviceCount; physDev++) {
484 initialPhysicalDeviceList.push_back(
485 mutablePhysicalDeviceGroupProperties->physicalDevices[physDev]);
486 mutablePhysicalDeviceGroupProperties->physicalDevices[physDev] =
487 initialPhysicalDeviceList[physDev];
488 }
489 }
490 }
491 if (VK_SUCCESS == result) {
492 struct vk_device_dispatch_table dispatch_table;
493 memset(&dispatch_table, 0, sizeof(struct vk_device_dispatch_table));
494 vk_device_dispatch_table_from_entrypoints(&dispatch_table, &gfxstream_vk_device_entrypoints,
495 false);
496 #if !defined(__Fuchsia__)
497 vk_device_dispatch_table_from_entrypoints(&dispatch_table, &wsi_device_entrypoints, false);
498 #endif
499
500 result = vk_device_init(&gfxstream_device->vk, &gfxstream_physicalDevice->vk,
501 &dispatch_table, pCreateInfo, pMesaAllocator);
502 }
503 if (VK_SUCCESS == result) {
504 gfxstream_device->physical_device = gfxstream_physicalDevice;
505 // TODO: Initialize cmd_dispatch for emulated secondary command buffer support?
506 gfxstream_device->vk.command_dispatch_table = &gfxstream_device->cmd_dispatch;
507 *pDevice = gfxstream_vk_device_to_handle(gfxstream_device);
508 } else {
509 vk_free(pMesaAllocator, gfxstream_device);
510 }
511
512 return result;
513 }
514
gfxstream_vk_DestroyDevice(VkDevice device,const VkAllocationCallbacks * pAllocator)515 void gfxstream_vk_DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
516 AEMU_SCOPED_TRACE("vkDestroyDevice");
517 VK_FROM_HANDLE(gfxstream_vk_device, gfxstream_device, device);
518 if (VK_NULL_HANDLE == device) return;
519
520 auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
521 vkEnc->vkDestroyDevice(gfxstream_device->internal_object, pAllocator, true /* do lock */);
522
523 /* Must destroy device queues manually */
524 vk_foreach_queue_safe(queue, &gfxstream_device->vk) {
525 vk_queue_finish(queue);
526 vk_free(&gfxstream_device->vk.alloc, queue);
527 }
528 vk_device_finish(&gfxstream_device->vk);
529 vk_free(&gfxstream_device->vk.alloc, gfxstream_device);
530 }
531
gfxstream_vk_GetDeviceQueue(VkDevice device,uint32_t queueFamilyIndex,uint32_t queueIndex,VkQueue * pQueue)532 void gfxstream_vk_GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex,
533 VkQueue* pQueue) {
534 AEMU_SCOPED_TRACE("vkGetDeviceQueue");
535 VK_FROM_HANDLE(gfxstream_vk_device, gfxstream_device, device);
536 struct gfxstream_vk_queue* gfxstream_queue = (struct gfxstream_vk_queue*)vk_zalloc(
537 &gfxstream_device->vk.alloc, sizeof(struct gfxstream_vk_queue), 8,
538 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
539 VkResult result = gfxstream_queue ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY;
540 if (VK_SUCCESS == result) {
541 VkDeviceQueueCreateInfo createInfo = {
542 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
543 .pNext = NULL,
544 .flags = 0,
545 .queueFamilyIndex = queueFamilyIndex,
546 .queueCount = 1,
547 .pQueuePriorities = NULL,
548 };
549 result =
550 vk_queue_init(&gfxstream_queue->vk, &gfxstream_device->vk, &createInfo, queueIndex);
551 }
552 if (VK_SUCCESS == result) {
553 auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
554 vkEnc->vkGetDeviceQueue(gfxstream_device->internal_object, queueFamilyIndex, queueIndex,
555 &gfxstream_queue->internal_object, true /* do lock */);
556
557 gfxstream_queue->device = gfxstream_device;
558 *pQueue = gfxstream_vk_queue_to_handle(gfxstream_queue);
559 } else {
560 *pQueue = VK_NULL_HANDLE;
561 }
562 }
563
gfxstream_vk_GetDeviceQueue2(VkDevice device,const VkDeviceQueueInfo2 * pQueueInfo,VkQueue * pQueue)564 void gfxstream_vk_GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo,
565 VkQueue* pQueue) {
566 AEMU_SCOPED_TRACE("vkGetDeviceQueue2");
567 VK_FROM_HANDLE(gfxstream_vk_device, gfxstream_device, device);
568 struct gfxstream_vk_queue* gfxstream_queue = (struct gfxstream_vk_queue*)vk_zalloc(
569 &gfxstream_device->vk.alloc, sizeof(struct gfxstream_vk_queue), 8,
570 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
571 VkResult result = gfxstream_queue ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY;
572 if (VK_SUCCESS == result) {
573 VkDeviceQueueCreateInfo createInfo = {
574 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
575 .pNext = NULL,
576 .flags = pQueueInfo->flags,
577 .queueFamilyIndex = pQueueInfo->queueFamilyIndex,
578 .queueCount = 1,
579 .pQueuePriorities = NULL,
580 };
581 result = vk_queue_init(&gfxstream_queue->vk, &gfxstream_device->vk, &createInfo,
582 pQueueInfo->queueIndex);
583 }
584 if (VK_SUCCESS == result) {
585 auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
586 vkEnc->vkGetDeviceQueue2(gfxstream_device->internal_object, pQueueInfo,
587 &gfxstream_queue->internal_object, true /* do lock */);
588
589 gfxstream_queue->device = gfxstream_device;
590 *pQueue = gfxstream_vk_queue_to_handle(gfxstream_queue);
591 } else {
592 *pQueue = VK_NULL_HANDLE;
593 }
594 }
595
596 /* The loader wants us to expose a second GetInstanceProcAddr function
597 * to work around certain LD_PRELOAD issues seen in apps.
598 */
599 extern "C" PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
600 vk_icdGetInstanceProcAddr(VkInstance instance, const char* pName);
601
602 extern "C" PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
vk_icdGetInstanceProcAddr(VkInstance instance,const char * pName)603 vk_icdGetInstanceProcAddr(VkInstance instance, const char* pName) {
604 return gfxstream_vk_GetInstanceProcAddr(instance, pName);
605 }
606
607 /* vk_icd.h does not declare this function, so we declare it here to
608 * suppress Wmissing-prototypes.
609 */
610 extern "C" PUBLIC VKAPI_ATTR VkResult VKAPI_CALL
611 vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion);
612
613 extern "C" PUBLIC VKAPI_ATTR VkResult VKAPI_CALL
vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t * pSupportedVersion)614 vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion) {
615 *pSupportedVersion = std::min(*pSupportedVersion, 3u);
616 return VK_SUCCESS;
617 }
618
619 /* With version 4+ of the loader interface the ICD should expose
620 * vk_icdGetPhysicalDeviceProcAddr()
621 */
622 extern "C" PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
623 vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance, const char* pName);
624
vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,const char * pName)625 PFN_vkVoidFunction vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance, const char* pName) {
626 VK_FROM_HANDLE(gfxstream_vk_instance, instance, _instance);
627
628 return vk_instance_get_physical_device_proc_addr(&instance->vk, pName);
629 }
630
gfxstream_vk_GetInstanceProcAddr(VkInstance _instance,const char * pName)631 PFN_vkVoidFunction gfxstream_vk_GetInstanceProcAddr(VkInstance _instance, const char* pName) {
632 VK_FROM_HANDLE(gfxstream_vk_instance, instance, _instance);
633 return vk_instance_get_proc_addr(&instance->vk, &gfxstream_vk_instance_entrypoints, pName);
634 }
635
gfxstream_vk_GetDeviceProcAddr(VkDevice _device,const char * pName)636 PFN_vkVoidFunction gfxstream_vk_GetDeviceProcAddr(VkDevice _device, const char* pName) {
637 AEMU_SCOPED_TRACE("vkGetDeviceProcAddr");
638 VK_FROM_HANDLE(gfxstream_vk_device, device, _device);
639 return vk_device_get_proc_addr(&device->vk, pName);
640 }
641
gfxstream_vk_AllocateMemory(VkDevice device,const VkMemoryAllocateInfo * pAllocateInfo,const VkAllocationCallbacks * pAllocator,VkDeviceMemory * pMemory)642 VkResult gfxstream_vk_AllocateMemory(VkDevice device, const VkMemoryAllocateInfo* pAllocateInfo,
643 const VkAllocationCallbacks* pAllocator,
644 VkDeviceMemory* pMemory) {
645 AEMU_SCOPED_TRACE("vkAllocateMemory");
646 VK_FROM_HANDLE(gfxstream_vk_device, gfxstream_device, device);
647 VkResult vkAllocateMemory_VkResult_return = (VkResult)0;
648 /* VkMemoryDedicatedAllocateInfo */
649 VkMemoryDedicatedAllocateInfo* dedicatedAllocInfoPtr =
650 (VkMemoryDedicatedAllocateInfo*)vk_find_struct<VkMemoryDedicatedAllocateInfo>(
651 pAllocateInfo);
652 if (dedicatedAllocInfoPtr) {
653 if (dedicatedAllocInfoPtr->buffer) {
654 VK_FROM_HANDLE(gfxstream_vk_buffer, gfxstream_buffer, dedicatedAllocInfoPtr->buffer);
655 dedicatedAllocInfoPtr->buffer = gfxstream_buffer->internal_object;
656 }
657 }
658 {
659 auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
660 auto resources = gfxstream::vk::ResourceTracker::get();
661 vkAllocateMemory_VkResult_return =
662 resources->on_vkAllocateMemory(vkEnc, VK_SUCCESS, gfxstream_device->internal_object,
663 pAllocateInfo, pAllocator, pMemory);
664 }
665 return vkAllocateMemory_VkResult_return;
666 }
667
gfxstream_vk_EnumerateInstanceLayerProperties(uint32_t * pPropertyCount,VkLayerProperties * pProperties)668 VkResult gfxstream_vk_EnumerateInstanceLayerProperties(uint32_t* pPropertyCount,
669 VkLayerProperties* pProperties) {
670 AEMU_SCOPED_TRACE("vkEnumerateInstanceLayerProperties");
671 auto result = SetupInstanceForProcess();
672 if (VK_SUCCESS != result) {
673 return vk_error(NULL, result);
674 }
675
676 VkResult vkEnumerateInstanceLayerProperties_VkResult_return = (VkResult)0;
677 {
678 auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
679 vkEnumerateInstanceLayerProperties_VkResult_return =
680 vkEnc->vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties,
681 true /* do lock */);
682 }
683 return vkEnumerateInstanceLayerProperties_VkResult_return;
684 }
685
gfxstream_vk_EnumerateInstanceVersion(uint32_t * pApiVersion)686 VkResult gfxstream_vk_EnumerateInstanceVersion(uint32_t* pApiVersion) {
687 AEMU_SCOPED_TRACE("vkEnumerateInstanceVersion");
688 auto result = SetupInstanceForProcess();
689 if (VK_SUCCESS != result) {
690 return vk_error(NULL, result);
691 }
692
693 VkResult vkEnumerateInstanceVersion_VkResult_return = (VkResult)0;
694 {
695 auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
696 vkEnumerateInstanceVersion_VkResult_return =
697 vkEnc->vkEnumerateInstanceVersion(pApiVersion, true /* do lock */);
698 }
699 return vkEnumerateInstanceVersion_VkResult_return;
700 }
701
transformDescriptorSetList(const VkWriteDescriptorSet * pDescriptorSets,uint32_t descriptorSetCount,std::vector<std::vector<VkDescriptorBufferInfo>> & bufferInfos)702 static std::vector<VkWriteDescriptorSet> transformDescriptorSetList(
703 const VkWriteDescriptorSet* pDescriptorSets, uint32_t descriptorSetCount,
704 std::vector<std::vector<VkDescriptorBufferInfo>>& bufferInfos) {
705 std::vector<VkWriteDescriptorSet> outDescriptorSets(descriptorSetCount);
706 for (uint32_t i = 0; i < descriptorSetCount; ++i) {
707 const auto& srcDescriptorSet = pDescriptorSets[i];
708 const uint32_t descriptorCount = srcDescriptorSet.descriptorCount;
709
710 VkWriteDescriptorSet& outDescriptorSet = outDescriptorSets[i];
711 outDescriptorSet = srcDescriptorSet;
712
713 bufferInfos.push_back(std::vector<VkDescriptorBufferInfo>());
714 bufferInfos[i].reserve(descriptorCount);
715 memset(&bufferInfos[i][0], 0, sizeof(VkDescriptorBufferInfo) * descriptorCount);
716 for (uint32_t j = 0; j < descriptorCount; ++j) {
717 const auto* srcBufferInfo = srcDescriptorSet.pBufferInfo;
718 if (srcBufferInfo) {
719 bufferInfos[i][j] = srcBufferInfo[j];
720 bufferInfos[i][j].buffer = VK_NULL_HANDLE;
721 if (vk_descriptor_type_has_descriptor_buffer(srcDescriptorSet.descriptorType) &&
722 srcBufferInfo[j].buffer) {
723 VK_FROM_HANDLE(gfxstream_vk_buffer, gfxstreamBuffer, srcBufferInfo[j].buffer);
724 bufferInfos[i][j].buffer = gfxstreamBuffer->internal_object;
725 }
726 }
727 }
728 outDescriptorSet.pBufferInfo = bufferInfos[i].data();
729 }
730 return outDescriptorSets;
731 }
732
gfxstream_vk_UpdateDescriptorSets(VkDevice device,uint32_t descriptorWriteCount,const VkWriteDescriptorSet * pDescriptorWrites,uint32_t descriptorCopyCount,const VkCopyDescriptorSet * pDescriptorCopies)733 void gfxstream_vk_UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
734 const VkWriteDescriptorSet* pDescriptorWrites,
735 uint32_t descriptorCopyCount,
736 const VkCopyDescriptorSet* pDescriptorCopies) {
737 AEMU_SCOPED_TRACE("vkUpdateDescriptorSets");
738 VK_FROM_HANDLE(gfxstream_vk_device, gfxstream_device, device);
739 {
740 auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
741 std::vector<std::vector<VkDescriptorBufferInfo>> descriptorBufferInfoStorage;
742 std::vector<VkWriteDescriptorSet> internal_pDescriptorWrites = transformDescriptorSetList(
743 pDescriptorWrites, descriptorWriteCount, descriptorBufferInfoStorage);
744 auto resources = gfxstream::vk::ResourceTracker::get();
745 resources->on_vkUpdateDescriptorSets(
746 vkEnc, gfxstream_device->internal_object, descriptorWriteCount,
747 internal_pDescriptorWrites.data(), descriptorCopyCount, pDescriptorCopies);
748 }
749 }
750