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