• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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