• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // VulkanHelper.cpp : Helper for allocating & managing vulkan external objects.
8 
9 #include "test_utils/VulkanHelper.h"
10 
11 #include <vector>
12 
13 #include "common/bitset_utils.h"
14 #include "common/debug.h"
15 #include "common/system_utils.h"
16 #include "common/vulkan/vulkan_icd.h"
17 #include "test_utils/ANGLETest.h"
18 
19 namespace angle
20 {
21 
22 namespace
23 {
24 
EnumerateInstanceExtensionProperties(const char * layerName)25 std::vector<VkExtensionProperties> EnumerateInstanceExtensionProperties(const char *layerName)
26 {
27     uint32_t instanceExtensionCount;
28     VkResult result =
29         vkEnumerateInstanceExtensionProperties(layerName, &instanceExtensionCount, nullptr);
30     ASSERT(result == VK_SUCCESS);
31     std::vector<VkExtensionProperties> instanceExtensionProperties(instanceExtensionCount);
32     result = vkEnumerateInstanceExtensionProperties(layerName, &instanceExtensionCount,
33                                                     instanceExtensionProperties.data());
34     ASSERT(result == VK_SUCCESS);
35     return instanceExtensionProperties;
36 }
37 
EnumeratePhysicalDevices(VkInstance instance)38 std::vector<VkPhysicalDevice> EnumeratePhysicalDevices(VkInstance instance)
39 {
40     uint32_t physicalDeviceCount;
41     VkResult result = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr);
42     ASSERT(result == VK_SUCCESS);
43     std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
44     result = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data());
45     return physicalDevices;
46 }
47 
EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,const char * layerName)48 std::vector<VkExtensionProperties> EnumerateDeviceExtensionProperties(
49     VkPhysicalDevice physicalDevice,
50     const char *layerName)
51 {
52     uint32_t deviceExtensionCount;
53     VkResult result = vkEnumerateDeviceExtensionProperties(physicalDevice, layerName,
54                                                            &deviceExtensionCount, nullptr);
55     ASSERT(result == VK_SUCCESS);
56     std::vector<VkExtensionProperties> deviceExtensionProperties(deviceExtensionCount);
57     result = vkEnumerateDeviceExtensionProperties(physicalDevice, layerName, &deviceExtensionCount,
58                                                   deviceExtensionProperties.data());
59     ASSERT(result == VK_SUCCESS);
60     return deviceExtensionProperties;
61 }
62 
GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice)63 std::vector<VkQueueFamilyProperties> GetPhysicalDeviceQueueFamilyProperties(
64     VkPhysicalDevice physicalDevice)
65 {
66     uint32_t queueFamilyPropertyCount;
67     vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertyCount, nullptr);
68     std::vector<VkQueueFamilyProperties> physicalDeviceQueueFamilyProperties(
69         queueFamilyPropertyCount);
70     vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertyCount,
71                                              physicalDeviceQueueFamilyProperties.data());
72     return physicalDeviceQueueFamilyProperties;
73 }
74 
HasExtension(const std::vector<VkExtensionProperties> instanceExtensions,const char * extensionName)75 bool HasExtension(const std::vector<VkExtensionProperties> instanceExtensions,
76                   const char *extensionName)
77 {
78     for (const auto &extensionProperties : instanceExtensions)
79     {
80         if (!strcmp(extensionProperties.extensionName, extensionName))
81             return true;
82     }
83 
84     return false;
85 }
86 
HasExtension(const std::vector<const char * > enabledExtensions,const char * extensionName)87 bool HasExtension(const std::vector<const char *> enabledExtensions, const char *extensionName)
88 {
89     for (const char *enabledExtension : enabledExtensions)
90     {
91         if (!strcmp(enabledExtension, extensionName))
92             return true;
93     }
94 
95     return false;
96 }
97 
FindMemoryType(const VkPhysicalDeviceMemoryProperties & memoryProperties,uint32_t memoryTypeBits,VkMemoryPropertyFlags requiredMemoryPropertyFlags)98 uint32_t FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProperties,
99                         uint32_t memoryTypeBits,
100                         VkMemoryPropertyFlags requiredMemoryPropertyFlags)
101 {
102     for (size_t memoryIndex : angle::BitSet32<32>(memoryTypeBits))
103     {
104         ASSERT(memoryIndex < memoryProperties.memoryTypeCount);
105 
106         if ((memoryProperties.memoryTypes[memoryIndex].propertyFlags &
107              requiredMemoryPropertyFlags) == requiredMemoryPropertyFlags)
108         {
109             return static_cast<uint32_t>(memoryIndex);
110         }
111     }
112 
113     return UINT32_MAX;
114 }
115 
ImageMemoryBarrier(VkCommandBuffer commandBuffer,VkImage image,uint32_t srcQueueFamilyIndex,uint32_t dstQueueFamilyIndex,VkImageLayout oldLayout,VkImageLayout newLayout)116 void ImageMemoryBarrier(VkCommandBuffer commandBuffer,
117                         VkImage image,
118                         uint32_t srcQueueFamilyIndex,
119                         uint32_t dstQueueFamilyIndex,
120                         VkImageLayout oldLayout,
121                         VkImageLayout newLayout)
122 {
123     const VkImageMemoryBarrier imageMemoryBarriers[] = {
124         /* [0] = */ {/* .sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
125                      /* .pNext = */ nullptr,
126                      /* .srcAccessMask = */ VK_ACCESS_MEMORY_WRITE_BIT,
127                      /* .dstAccessMask = */ VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
128                      /* .oldLayout = */ oldLayout,
129                      /* .newLayout = */ newLayout,
130                      /* .srcQueueFamilyIndex = */ srcQueueFamilyIndex,
131                      /* .dstQueueFamilyIndex = */ dstQueueFamilyIndex,
132                      /* .image = */ image,
133                      /* .subresourceRange = */
134                      {
135                          /* .aspectMask = */ VK_IMAGE_ASPECT_COLOR_BIT,
136                          /* .basicMiplevel = */ 0,
137                          /* .levelCount = */ 1,
138                          /* .baseArrayLayer = */ 0,
139                          /* .layerCount = */ 1,
140                      }}};
141     const uint32_t imageMemoryBarrierCount = std::extent<decltype(imageMemoryBarriers)>();
142 
143     constexpr VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
144     constexpr VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
145     const VkDependencyFlags dependencyFlags     = 0;
146 
147     vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, 0, nullptr, 0,
148                          nullptr, imageMemoryBarrierCount, imageMemoryBarriers);
149 }
150 
151 }  // namespace
152 
VulkanHelper()153 VulkanHelper::VulkanHelper() {}
154 
~VulkanHelper()155 VulkanHelper::~VulkanHelper()
156 {
157     if (mDevice != VK_NULL_HANDLE)
158     {
159         vkDeviceWaitIdle(mDevice);
160     }
161 
162     if (mCommandPool != VK_NULL_HANDLE)
163     {
164         vkDestroyCommandPool(mDevice, mCommandPool, nullptr);
165     }
166 
167     if (!mInitializedFromANGLE)
168     {
169         if (mDevice != VK_NULL_HANDLE)
170         {
171             vkDestroyDevice(mDevice, nullptr);
172 
173             mDevice        = VK_NULL_HANDLE;
174             mGraphicsQueue = VK_NULL_HANDLE;
175         }
176 
177         if (mInstance != VK_NULL_HANDLE)
178         {
179             vkDestroyInstance(mInstance, nullptr);
180 
181             mInstance = VK_NULL_HANDLE;
182         }
183     }
184 }
185 
initialize(bool useSwiftshader,bool enableValidationLayers)186 void VulkanHelper::initialize(bool useSwiftshader, bool enableValidationLayers)
187 {
188     bool enableValidationLayersOverride = enableValidationLayers;
189 #if !defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS)
190     enableValidationLayersOverride = false;
191 #endif
192 
193     vk::ICD icd = useSwiftshader ? vk::ICD::SwiftShader : vk::ICD::Default;
194 
195     vk::ScopedVkLoaderEnvironment scopedEnvironment(enableValidationLayersOverride, icd);
196 
197     ASSERT(mInstance == VK_NULL_HANDLE);
198     VkResult result = VK_SUCCESS;
199 #if ANGLE_SHARED_LIBVULKAN
200     result = volkInitialize();
201     ASSERT(result == VK_SUCCESS);
202 #endif  // ANGLE_SHARED_LIBVULKAN
203     std::vector<VkExtensionProperties> instanceExtensionProperties =
204         EnumerateInstanceExtensionProperties(nullptr);
205 
206     std::vector<const char *> requestedInstanceExtensions = {
207         VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
208         VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
209         VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME};
210 
211     std::vector<const char *> enabledInstanceExtensions;
212 
213     for (const char *extensionName : requestedInstanceExtensions)
214     {
215         if (HasExtension(instanceExtensionProperties, extensionName))
216         {
217             enabledInstanceExtensions.push_back(extensionName);
218         }
219     }
220 
221     VkApplicationInfo applicationInfo = {
222         /* .sType = */ VK_STRUCTURE_TYPE_APPLICATION_INFO,
223         /* .pNext = */ nullptr,
224         /* .pApplicationName = */ "ANGLE Tests",
225         /* .applicationVersion = */ 1,
226         /* .pEngineName = */ nullptr,
227         /* .engineVersion = */ 0,
228         /* .apiVersion = */ VK_API_VERSION_1_0,
229     };
230 
231     uint32_t enabledInstanceExtensionCount =
232         static_cast<uint32_t>(enabledInstanceExtensions.size());
233 
234     std::vector<const char *> enabledLayerNames;
235     if (enableValidationLayersOverride)
236     {
237         enabledLayerNames.push_back("VK_LAYER_KHRONOS_validation");
238     }
239 
240     VkInstanceCreateInfo instanceCreateInfo = {
241         /* .sType = */ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
242         /* .pNext = */ nullptr,
243         /* .flags = */ 0,
244         /* .pApplicationInfo = */ &applicationInfo,
245         /* .enabledLayerCount = */ static_cast<uint32_t>(enabledLayerNames.size()),
246         /* .ppEnabledLayerNames = */ enabledLayerNames.data(),
247         /* .enabledExtensionCount = */ enabledInstanceExtensionCount,
248         /* .ppEnabledExtensionName = */ enabledInstanceExtensions.data(),
249     };
250 
251     result = vkCreateInstance(&instanceCreateInfo, nullptr, &mInstance);
252     ASSERT(result == VK_SUCCESS);
253     ASSERT(mInstance != VK_NULL_HANDLE);
254 #if ANGLE_SHARED_LIBVULKAN
255     volkLoadInstance(mInstance);
256 #endif  // ANGLE_SHARED_LIBVULKAN
257 
258     std::vector<VkPhysicalDevice> physicalDevices = EnumeratePhysicalDevices(mInstance);
259 
260     ASSERT(physicalDevices.size() > 0);
261 
262     VkPhysicalDeviceProperties physicalDeviceProperties;
263     ChoosePhysicalDevice(vkGetPhysicalDeviceProperties, physicalDevices, icd, &mPhysicalDevice,
264                          &physicalDeviceProperties);
265 
266     vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &mMemoryProperties);
267 
268     std::vector<VkExtensionProperties> deviceExtensionProperties =
269         EnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr);
270 
271     std::vector<const char *> requestedDeviceExtensions = {
272         VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,   VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
273         VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,      VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
274         VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME,  VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
275         VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME,    VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
276         VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
277     };
278 
279     std::vector<const char *> enabledDeviceExtensions;
280 
281     for (const char *extensionName : requestedDeviceExtensions)
282     {
283         if (HasExtension(deviceExtensionProperties, extensionName))
284         {
285             enabledDeviceExtensions.push_back(extensionName);
286         }
287     }
288 
289     std::vector<VkQueueFamilyProperties> queueFamilyProperties =
290         GetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice);
291 
292     for (uint32_t i = 0; i < queueFamilyProperties.size(); ++i)
293     {
294         if (queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
295         {
296             mGraphicsQueueFamilyIndex = i;
297         }
298     }
299     ASSERT(mGraphicsQueueFamilyIndex != UINT32_MAX);
300 
301     constexpr uint32_t kQueueCreateInfoCount           = 1;
302     constexpr uint32_t kGraphicsQueueCount             = 1;
303     float graphicsQueuePriorities[kGraphicsQueueCount] = {0.f};
304 
305     VkDeviceQueueCreateInfo queueCreateInfos[kQueueCreateInfoCount] = {
306         /* [0] = */ {
307             /* .sType = */ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
308             /* .pNext = */ nullptr,
309             /* .flags = */ 0,
310             /* .queueFamilyIndex = */ mGraphicsQueueFamilyIndex,
311             /* .queueCount = */ 1,
312             /* .pQueuePriorities = */ graphicsQueuePriorities,
313         },
314     };
315 
316     uint32_t enabledDeviceExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size());
317 
318     VkDeviceCreateInfo deviceCreateInfo = {
319         /* .sType = */ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
320         /* .pNext = */ nullptr,
321         /* .flags = */ 0,
322         /* .queueCreateInfoCount = */ kQueueCreateInfoCount,
323         /* .pQueueCreateInfos = */ queueCreateInfos,
324         /* .enabledLayerCount = */ 0,
325         /* .ppEnabledLayerNames = */ nullptr,
326         /* .enabledExtensionCount = */ enabledDeviceExtensionCount,
327         /* .ppEnabledExtensionName = */ enabledDeviceExtensions.data(),
328         /* .pEnabledFeatures = */ nullptr,
329     };
330 
331     result = vkCreateDevice(mPhysicalDevice, &deviceCreateInfo, nullptr, &mDevice);
332     ASSERT(result == VK_SUCCESS);
333     ASSERT(mDevice != VK_NULL_HANDLE);
334 #if ANGLE_SHARED_LIBVULKAN
335     volkLoadDevice(mDevice);
336 #endif  // ANGLE_SHARED_LIBVULKAN
337 
338     constexpr uint32_t kGraphicsQueueIndex = 0;
339     static_assert(kGraphicsQueueIndex < kGraphicsQueueCount, "must be in range");
340     vkGetDeviceQueue(mDevice, mGraphicsQueueFamilyIndex, kGraphicsQueueIndex, &mGraphicsQueue);
341     ASSERT(mGraphicsQueue != VK_NULL_HANDLE);
342 
343     VkCommandPoolCreateInfo commandPoolCreateInfo = {
344         /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
345         /* .pNext = */ nullptr,
346         /* .flags = */ 0,
347         /* .queueFamilyIndex = */ mGraphicsQueueFamilyIndex,
348     };
349     result = vkCreateCommandPool(mDevice, &commandPoolCreateInfo, nullptr, &mCommandPool);
350     ASSERT(result == VK_SUCCESS);
351 
352     mHasExternalMemoryFd =
353         HasExtension(enabledDeviceExtensions, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
354     mHasExternalSemaphoreFd =
355         HasExtension(enabledDeviceExtensions, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME);
356     mHasExternalMemoryFuchsia =
357         HasExtension(enabledDeviceExtensions, VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME);
358     mHasExternalSemaphoreFuchsia =
359         HasExtension(enabledDeviceExtensions, VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME);
360 
361     vkGetPhysicalDeviceImageFormatProperties2 =
362         reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(
363             vkGetInstanceProcAddr(mInstance, "vkGetPhysicalDeviceImageFormatProperties2"));
364     vkGetMemoryFdKHR = reinterpret_cast<PFN_vkGetMemoryFdKHR>(
365         vkGetInstanceProcAddr(mInstance, "vkGetMemoryFdKHR"));
366     ASSERT(!mHasExternalMemoryFd || vkGetMemoryFdKHR);
367     vkGetSemaphoreFdKHR = reinterpret_cast<PFN_vkGetSemaphoreFdKHR>(
368         vkGetInstanceProcAddr(mInstance, "vkGetSemaphoreFdKHR"));
369     ASSERT(!mHasExternalSemaphoreFd || vkGetSemaphoreFdKHR);
370     vkGetPhysicalDeviceExternalSemaphorePropertiesKHR =
371         reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR>(
372             vkGetInstanceProcAddr(mInstance, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"));
373     vkGetMemoryZirconHandleFUCHSIA = reinterpret_cast<PFN_vkGetMemoryZirconHandleFUCHSIA>(
374         vkGetInstanceProcAddr(mInstance, "vkGetMemoryZirconHandleFUCHSIA"));
375     ASSERT(!mHasExternalMemoryFuchsia || vkGetMemoryZirconHandleFUCHSIA);
376     vkGetSemaphoreZirconHandleFUCHSIA = reinterpret_cast<PFN_vkGetSemaphoreZirconHandleFUCHSIA>(
377         vkGetInstanceProcAddr(mInstance, "vkGetSemaphoreZirconHandleFUCHSIA"));
378     ASSERT(!mHasExternalSemaphoreFuchsia || vkGetSemaphoreZirconHandleFUCHSIA);
379 }
380 
initializeFromANGLE()381 void VulkanHelper::initializeFromANGLE()
382 {
383     mInitializedFromANGLE = true;
384     VkResult vkResult     = VK_SUCCESS;
385 
386     EXPECT_TRUE(IsEGLClientExtensionEnabled("EGL_EXT_device_query"));
387     EGLDisplay display = eglGetCurrentDisplay();
388 
389     EGLAttrib result = 0;
390     EXPECT_EGL_TRUE(eglQueryDisplayAttribEXT(display, EGL_DEVICE_EXT, &result));
391 
392     EGLDeviceEXT device = reinterpret_cast<EGLDeviceEXT>(result);
393     EXPECT_NE(EGL_NO_DEVICE_EXT, device);
394     EXPECT_TRUE(IsEGLDeviceExtensionEnabled(device, "EGL_ANGLE_device_vulkan"));
395 
396     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_GET_INSTANCE_PROC_ADDR, &result));
397     PFN_vkGetInstanceProcAddr getInstanceProcAddr =
398         reinterpret_cast<PFN_vkGetInstanceProcAddr>(result);
399     EXPECT_NE(getInstanceProcAddr, nullptr);
400 #if ANGLE_SHARED_LIBVULKAN
401     volkInitializeCustom(getInstanceProcAddr);
402 #endif  // ANGLE_SHARED_LIBVULKAN
403 
404     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_INSTANCE_ANGLE, &result));
405     mInstance = reinterpret_cast<VkInstance>(result);
406     EXPECT_NE(mInstance, static_cast<VkInstance>(VK_NULL_HANDLE));
407 
408 #if ANGLE_SHARED_LIBVULKAN
409     volkLoadInstance(mInstance);
410 #endif  // ANGLE_SHARED_LIBVULKAN
411 
412     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_PHYSICAL_DEVICE_ANGLE, &result));
413     mPhysicalDevice = reinterpret_cast<VkPhysicalDevice>(result);
414     EXPECT_NE(mPhysicalDevice, static_cast<VkPhysicalDevice>(VK_NULL_HANDLE));
415 
416     vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &mMemoryProperties);
417 
418     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_DEVICE_ANGLE, &result));
419     mDevice = reinterpret_cast<VkDevice>(result);
420     EXPECT_NE(mDevice, static_cast<VkDevice>(VK_NULL_HANDLE));
421 
422     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_QUEUE_ANGLE, &result));
423     mGraphicsQueue = reinterpret_cast<VkQueue>(result);
424     EXPECT_NE(mGraphicsQueue, static_cast<VkQueue>(VK_NULL_HANDLE));
425 
426     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_QUEUE_FAMILIY_INDEX_ANGLE, &result));
427     mGraphicsQueueFamilyIndex = static_cast<uint32_t>(result);
428 
429 #if ANGLE_SHARED_LIBVULKAN
430     volkLoadDevice(mDevice);
431 #endif  // ANGLE_SHARED_LIBVULKAN
432 
433     VkCommandPoolCreateInfo commandPoolCreateInfo = {
434         /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
435         /* .pNext = */ nullptr,
436         /* .flags = */ 0,
437         /* .queueFamilyIndex = */ mGraphicsQueueFamilyIndex,
438     };
439     vkResult = vkCreateCommandPool(mDevice, &commandPoolCreateInfo, nullptr, &mCommandPool);
440     ASSERT(vkResult == VK_SUCCESS);
441 
442     vkGetPhysicalDeviceImageFormatProperties2 =
443         reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(
444             vkGetInstanceProcAddr(mInstance, "vkGetPhysicalDeviceImageFormatProperties2"));
445     ASSERT(vkGetPhysicalDeviceImageFormatProperties2);
446 
447     vkGetMemoryFdKHR = reinterpret_cast<PFN_vkGetMemoryFdKHR>(
448         vkGetInstanceProcAddr(mInstance, "vkGetMemoryFdKHR"));
449     ASSERT(!mHasExternalMemoryFd || vkGetMemoryFdKHR);
450     vkGetSemaphoreFdKHR = reinterpret_cast<PFN_vkGetSemaphoreFdKHR>(
451         vkGetInstanceProcAddr(mInstance, "vkGetSemaphoreFdKHR"));
452     ASSERT(!mHasExternalSemaphoreFd || vkGetSemaphoreFdKHR);
453     vkGetPhysicalDeviceExternalSemaphorePropertiesKHR =
454         reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR>(
455             vkGetInstanceProcAddr(mInstance, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"));
456     vkGetMemoryZirconHandleFUCHSIA = reinterpret_cast<PFN_vkGetMemoryZirconHandleFUCHSIA>(
457         vkGetInstanceProcAddr(mInstance, "vkGetMemoryZirconHandleFUCHSIA"));
458     ASSERT(!mHasExternalMemoryFuchsia || vkGetMemoryZirconHandleFUCHSIA);
459     vkGetSemaphoreZirconHandleFUCHSIA = reinterpret_cast<PFN_vkGetSemaphoreZirconHandleFUCHSIA>(
460         vkGetInstanceProcAddr(mInstance, "vkGetSemaphoreZirconHandleFUCHSIA"));
461     ASSERT(!mHasExternalSemaphoreFuchsia || vkGetSemaphoreZirconHandleFUCHSIA);
462 }
463 
canCreateImageExternal(VkFormat format,VkImageType type,VkImageTiling tiling,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags,VkExternalMemoryHandleTypeFlagBits handleType) const464 bool VulkanHelper::canCreateImageExternal(VkFormat format,
465                                           VkImageType type,
466                                           VkImageTiling tiling,
467                                           VkImageCreateFlags createFlags,
468                                           VkImageUsageFlags usageFlags,
469                                           VkExternalMemoryHandleTypeFlagBits handleType) const
470 {
471     VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo = {
472         /* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
473         /* .pNext = */ nullptr,
474         /* .handleType = */ handleType,
475     };
476 
477     VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {
478         /* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
479         /* .pNext = */ &externalImageFormatInfo,
480         /* .format = */ format,
481         /* .type = */ type,
482         /* .tiling = */ tiling,
483         /* .usage = */ usageFlags,
484         /* .flags = */ createFlags,
485     };
486 
487     VkExternalImageFormatProperties externalImageFormatProperties = {
488         /* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
489         /* .pNext = */ nullptr,
490     };
491 
492     VkImageFormatProperties2 imageFormatProperties = {
493         /* .sType = */ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
494         /* .pNext = */ &externalImageFormatProperties};
495 
496     VkResult result = vkGetPhysicalDeviceImageFormatProperties2(mPhysicalDevice, &imageFormatInfo,
497                                                                 &imageFormatProperties);
498     if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
499     {
500         return false;
501     }
502 
503     ASSERT(result == VK_SUCCESS);
504 
505     constexpr VkExternalMemoryFeatureFlags kRequiredFeatures =
506         VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
507     if ((externalImageFormatProperties.externalMemoryProperties.externalMemoryFeatures &
508          kRequiredFeatures) != kRequiredFeatures)
509     {
510         return false;
511     }
512 
513     return true;
514 }
515 
createImage2DExternal(VkFormat format,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags,const void * imageCreateInfoPNext,VkExtent3D extent,VkExternalMemoryHandleTypeFlags handleTypes,VkImage * imageOut,VkDeviceMemory * deviceMemoryOut,VkDeviceSize * deviceMemorySizeOut)516 VkResult VulkanHelper::createImage2DExternal(VkFormat format,
517                                              VkImageCreateFlags createFlags,
518                                              VkImageUsageFlags usageFlags,
519                                              const void *imageCreateInfoPNext,
520                                              VkExtent3D extent,
521                                              VkExternalMemoryHandleTypeFlags handleTypes,
522                                              VkImage *imageOut,
523                                              VkDeviceMemory *deviceMemoryOut,
524                                              VkDeviceSize *deviceMemorySizeOut)
525 {
526     VkExternalMemoryImageCreateInfoKHR externalMemoryImageCreateInfo = {
527         /* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
528         /* .pNext = */ imageCreateInfoPNext,
529         /* .handleTypes = */ handleTypes,
530     };
531 
532     VkImageCreateInfo imageCreateInfo = {
533         /* .sType = */ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
534         /* .pNext = */ &externalMemoryImageCreateInfo,
535         /* .flags = */ createFlags,
536         /* .imageType = */ VK_IMAGE_TYPE_2D,
537         /* .format = */ format,
538         /* .extent = */ extent,
539         /* .mipLevels = */ 1,
540         /* .arrayLayers = */ 1,
541         /* .samples = */ VK_SAMPLE_COUNT_1_BIT,
542         /* .tiling = */ VK_IMAGE_TILING_OPTIMAL,
543         /* .usage = */ usageFlags,
544         /* .sharingMode = */ VK_SHARING_MODE_EXCLUSIVE,
545         /* .queueFamilyIndexCount = */ 0,
546         /* .pQueueFamilyIndices = */ nullptr,
547         /* initialLayout = */ VK_IMAGE_LAYOUT_UNDEFINED,
548     };
549 
550     VkImage image   = VK_NULL_HANDLE;
551     VkResult result = vkCreateImage(mDevice, &imageCreateInfo, nullptr, &image);
552     if (result != VK_SUCCESS)
553     {
554         return result;
555     }
556 
557     VkMemoryPropertyFlags requestedMemoryPropertyFlags = 0;
558     VkMemoryRequirements memoryRequirements;
559     vkGetImageMemoryRequirements(mDevice, image, &memoryRequirements);
560     uint32_t memoryTypeIndex = FindMemoryType(mMemoryProperties, memoryRequirements.memoryTypeBits,
561                                               requestedMemoryPropertyFlags);
562     ASSERT(memoryTypeIndex != UINT32_MAX);
563     VkDeviceSize deviceMemorySize = memoryRequirements.size;
564 
565     VkExportMemoryAllocateInfo exportMemoryAllocateInfo = {
566         /* .sType = */ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
567         /* .pNext = */ nullptr,
568         /* .handleTypes = */ handleTypes,
569     };
570     VkMemoryDedicatedAllocateInfoKHR memoryDedicatedAllocateInfo = {
571         /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
572         /* .pNext = */ &exportMemoryAllocateInfo,
573         /* .image = */ image,
574     };
575     VkMemoryAllocateInfo memoryAllocateInfo = {
576         /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
577         /* .pNext = */ &memoryDedicatedAllocateInfo,
578         /* .allocationSize = */ deviceMemorySize,
579         /* .memoryTypeIndex = */ memoryTypeIndex,
580     };
581 
582     VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
583     result = vkAllocateMemory(mDevice, &memoryAllocateInfo, nullptr, &deviceMemory);
584     if (result != VK_SUCCESS)
585     {
586         vkDestroyImage(mDevice, image, nullptr);
587         return result;
588     }
589 
590     VkDeviceSize memoryOffset = 0;
591     result                    = vkBindImageMemory(mDevice, image, deviceMemory, memoryOffset);
592     if (result != VK_SUCCESS)
593     {
594         vkFreeMemory(mDevice, deviceMemory, nullptr);
595         vkDestroyImage(mDevice, image, nullptr);
596         return result;
597     }
598 
599     *imageOut            = image;
600     *deviceMemoryOut     = deviceMemory;
601     *deviceMemorySizeOut = deviceMemorySize;
602 
603     return VK_SUCCESS;
604 }
605 
canCreateImageOpaqueFd(VkFormat format,VkImageType type,VkImageTiling tiling,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags) const606 bool VulkanHelper::canCreateImageOpaqueFd(VkFormat format,
607                                           VkImageType type,
608                                           VkImageTiling tiling,
609                                           VkImageCreateFlags createFlags,
610                                           VkImageUsageFlags usageFlags) const
611 {
612     if (!mHasExternalMemoryFd)
613     {
614         return false;
615     }
616 
617     return canCreateImageExternal(format, type, tiling, createFlags, usageFlags,
618                                   VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
619 }
620 
createImage2DOpaqueFd(VkFormat format,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags,const void * imageCreateInfoPNext,VkExtent3D extent,VkImage * imageOut,VkDeviceMemory * deviceMemoryOut,VkDeviceSize * deviceMemorySizeOut)621 VkResult VulkanHelper::createImage2DOpaqueFd(VkFormat format,
622                                              VkImageCreateFlags createFlags,
623                                              VkImageUsageFlags usageFlags,
624                                              const void *imageCreateInfoPNext,
625                                              VkExtent3D extent,
626                                              VkImage *imageOut,
627                                              VkDeviceMemory *deviceMemoryOut,
628                                              VkDeviceSize *deviceMemorySizeOut)
629 {
630     return createImage2DExternal(format, createFlags, usageFlags, imageCreateInfoPNext, extent,
631                                  VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, imageOut,
632                                  deviceMemoryOut, deviceMemorySizeOut);
633 }
634 
exportMemoryOpaqueFd(VkDeviceMemory deviceMemory,int * fd)635 VkResult VulkanHelper::exportMemoryOpaqueFd(VkDeviceMemory deviceMemory, int *fd)
636 {
637     VkMemoryGetFdInfoKHR memoryGetFdInfo = {
638         /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
639         /* .pNext = */ nullptr,
640         /* .memory = */ deviceMemory,
641         /* .handleType = */ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
642     };
643 
644     return vkGetMemoryFdKHR(mDevice, &memoryGetFdInfo, fd);
645 }
646 
canCreateImageZirconVmo(VkFormat format,VkImageType type,VkImageTiling tiling,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags) const647 bool VulkanHelper::canCreateImageZirconVmo(VkFormat format,
648                                            VkImageType type,
649                                            VkImageTiling tiling,
650                                            VkImageCreateFlags createFlags,
651                                            VkImageUsageFlags usageFlags) const
652 {
653     if (!mHasExternalMemoryFuchsia)
654     {
655         return false;
656     }
657 
658     return canCreateImageExternal(format, type, tiling, createFlags, usageFlags,
659                                   VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA);
660 }
661 
createImage2DZirconVmo(VkFormat format,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags,const void * imageCreateInfoPNext,VkExtent3D extent,VkImage * imageOut,VkDeviceMemory * deviceMemoryOut,VkDeviceSize * deviceMemorySizeOut)662 VkResult VulkanHelper::createImage2DZirconVmo(VkFormat format,
663                                               VkImageCreateFlags createFlags,
664                                               VkImageUsageFlags usageFlags,
665                                               const void *imageCreateInfoPNext,
666                                               VkExtent3D extent,
667                                               VkImage *imageOut,
668                                               VkDeviceMemory *deviceMemoryOut,
669                                               VkDeviceSize *deviceMemorySizeOut)
670 {
671     return createImage2DExternal(format, createFlags, usageFlags, imageCreateInfoPNext, extent,
672                                  VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA, imageOut,
673                                  deviceMemoryOut, deviceMemorySizeOut);
674 }
675 
exportMemoryZirconVmo(VkDeviceMemory deviceMemory,zx_handle_t * vmo)676 VkResult VulkanHelper::exportMemoryZirconVmo(VkDeviceMemory deviceMemory, zx_handle_t *vmo)
677 {
678     VkMemoryGetZirconHandleInfoFUCHSIA memoryGetZirconHandleInfo = {
679         /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA,
680         /* .pNext = */ nullptr,
681         /* .memory = */ deviceMemory,
682         /* .handleType = */ VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA,
683     };
684 
685     return vkGetMemoryZirconHandleFUCHSIA(mDevice, &memoryGetZirconHandleInfo, vmo);
686 }
687 
canCreateSemaphoreOpaqueFd() const688 bool VulkanHelper::canCreateSemaphoreOpaqueFd() const
689 {
690     if (!mHasExternalSemaphoreFd || !vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)
691     {
692         return false;
693     }
694 
695     VkPhysicalDeviceExternalSemaphoreInfo externalSemaphoreInfo = {
696         /* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
697         /* .pNext = */ nullptr,
698         /* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
699     };
700 
701     VkExternalSemaphoreProperties externalSemaphoreProperties = {
702         /* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,
703     };
704     vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(mPhysicalDevice, &externalSemaphoreInfo,
705                                                       &externalSemaphoreProperties);
706 
707     constexpr VkExternalSemaphoreFeatureFlags kRequiredFeatures =
708         VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
709 
710     if ((externalSemaphoreProperties.externalSemaphoreFeatures & kRequiredFeatures) !=
711         kRequiredFeatures)
712     {
713         return false;
714     }
715 
716     return true;
717 }
718 
createSemaphoreOpaqueFd(VkSemaphore * semaphore)719 VkResult VulkanHelper::createSemaphoreOpaqueFd(VkSemaphore *semaphore)
720 {
721     VkExportSemaphoreCreateInfo exportSemaphoreCreateInfo = {
722         /* .sType = */ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
723         /* .pNext = */ nullptr,
724         /* .handleTypes = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
725     };
726 
727     VkSemaphoreCreateInfo semaphoreCreateInfo = {
728         /* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
729         /* .pNext = */ &exportSemaphoreCreateInfo,
730         /* .flags = */ 0,
731     };
732 
733     return vkCreateSemaphore(mDevice, &semaphoreCreateInfo, nullptr, semaphore);
734 }
735 
exportSemaphoreOpaqueFd(VkSemaphore semaphore,int * fd)736 VkResult VulkanHelper::exportSemaphoreOpaqueFd(VkSemaphore semaphore, int *fd)
737 {
738     VkSemaphoreGetFdInfoKHR semaphoreGetFdInfo = {
739         /* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
740         /* .pNext = */ nullptr,
741         /* .semaphore = */ semaphore,
742         /* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
743     };
744 
745     return vkGetSemaphoreFdKHR(mDevice, &semaphoreGetFdInfo, fd);
746 }
747 
canCreateSemaphoreZirconEvent() const748 bool VulkanHelper::canCreateSemaphoreZirconEvent() const
749 {
750     if (!mHasExternalSemaphoreFuchsia || !vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)
751     {
752         return false;
753     }
754 
755     VkPhysicalDeviceExternalSemaphoreInfo externalSemaphoreInfo = {
756         /* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
757         /* .pNext = */ nullptr,
758         /* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,
759     };
760 
761     VkExternalSemaphoreProperties externalSemaphoreProperties = {
762         /* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,
763     };
764     vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(mPhysicalDevice, &externalSemaphoreInfo,
765                                                       &externalSemaphoreProperties);
766 
767     constexpr VkExternalSemaphoreFeatureFlags kRequiredFeatures =
768         VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
769 
770     if ((externalSemaphoreProperties.externalSemaphoreFeatures & kRequiredFeatures) !=
771         kRequiredFeatures)
772     {
773         return false;
774     }
775 
776     return true;
777 }
778 
createSemaphoreZirconEvent(VkSemaphore * semaphore)779 VkResult VulkanHelper::createSemaphoreZirconEvent(VkSemaphore *semaphore)
780 {
781     VkExportSemaphoreCreateInfo exportSemaphoreCreateInfo = {
782         /* .sType = */ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
783         /* .pNext = */ nullptr,
784         /* .handleTypes = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,
785     };
786 
787     VkSemaphoreCreateInfo semaphoreCreateInfo = {
788         /* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
789         /* .pNext = */ &exportSemaphoreCreateInfo,
790         /* .flags = */ 0,
791     };
792 
793     return vkCreateSemaphore(mDevice, &semaphoreCreateInfo, nullptr, semaphore);
794 }
795 
exportSemaphoreZirconEvent(VkSemaphore semaphore,zx_handle_t * event)796 VkResult VulkanHelper::exportSemaphoreZirconEvent(VkSemaphore semaphore, zx_handle_t *event)
797 {
798     VkSemaphoreGetZirconHandleInfoFUCHSIA semaphoreGetZirconHandleInfo = {
799         /* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA,
800         /* .pNext = */ nullptr,
801         /* .semaphore = */ semaphore,
802         /* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,
803     };
804 
805     return vkGetSemaphoreZirconHandleFUCHSIA(mDevice, &semaphoreGetZirconHandleInfo, event);
806 }
807 
releaseImageAndSignalSemaphore(VkImage image,VkImageLayout oldLayout,VkImageLayout newLayout,VkSemaphore semaphore)808 void VulkanHelper::releaseImageAndSignalSemaphore(VkImage image,
809                                                   VkImageLayout oldLayout,
810                                                   VkImageLayout newLayout,
811                                                   VkSemaphore semaphore)
812 {
813     VkResult result;
814 
815     VkCommandBuffer commandBuffers[]                      = {VK_NULL_HANDLE};
816     constexpr uint32_t commandBufferCount                 = std::extent<decltype(commandBuffers)>();
817     VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
818         /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
819         /* .pNext = */ nullptr,
820         /* .commandPool = */ mCommandPool,
821         /* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
822         /* .commandBufferCount = */ commandBufferCount,
823     };
824 
825     result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);
826     ASSERT(result == VK_SUCCESS);
827 
828     VkCommandBufferBeginInfo commandBufferBeginInfo = {
829         /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
830         /* .pNext = */ nullptr,
831         /* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
832         /* .pInheritanceInfo = */ nullptr,
833     };
834     result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);
835     ASSERT(result == VK_SUCCESS);
836 
837     ImageMemoryBarrier(commandBuffers[0], image, mGraphicsQueueFamilyIndex,
838                        VK_QUEUE_FAMILY_EXTERNAL, oldLayout, newLayout);
839 
840     result = vkEndCommandBuffer(commandBuffers[0]);
841     ASSERT(result == VK_SUCCESS);
842 
843     const VkSemaphore signalSemaphores[] = {
844         semaphore,
845     };
846     constexpr uint32_t signalSemaphoreCount = std::extent<decltype(signalSemaphores)>();
847 
848     const VkSubmitInfo submits[] = {
849         /* [0] = */ {
850             /* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,
851             /* .pNext = */ nullptr,
852             /* .waitSemaphoreCount = */ 0,
853             /* .pWaitSemaphores = */ nullptr,
854             /* .pWaitDstStageMask = */ nullptr,
855             /* .commandBufferCount = */ commandBufferCount,
856             /* .pCommandBuffers = */ commandBuffers,
857             /* .signalSemaphoreCount = */ signalSemaphoreCount,
858             /* .pSignalSemaphores = */ signalSemaphores,
859         },
860     };
861     constexpr uint32_t submitCount = std::extent<decltype(submits)>();
862 
863     const VkFence fence = VK_NULL_HANDLE;
864     result              = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);
865     ASSERT(result == VK_SUCCESS);
866 }
867 
waitSemaphoreAndAcquireImage(VkImage image,VkImageLayout oldLayout,VkImageLayout newLayout,VkSemaphore semaphore)868 void VulkanHelper::waitSemaphoreAndAcquireImage(VkImage image,
869                                                 VkImageLayout oldLayout,
870                                                 VkImageLayout newLayout,
871                                                 VkSemaphore semaphore)
872 {
873     VkResult result;
874 
875     VkCommandBuffer commandBuffers[]                      = {VK_NULL_HANDLE};
876     constexpr uint32_t commandBufferCount                 = std::extent<decltype(commandBuffers)>();
877     VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
878         /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
879         /* .pNext = */ nullptr,
880         /* .commandPool = */ mCommandPool,
881         /* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
882         /* .commandBufferCount = */ commandBufferCount,
883     };
884 
885     result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);
886     ASSERT(result == VK_SUCCESS);
887 
888     VkCommandBufferBeginInfo commandBufferBeginInfo = {
889         /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
890         /* .pNext = */ nullptr,
891         /* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
892         /* .pInheritanceInfo = */ nullptr,
893     };
894     result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);
895     ASSERT(result == VK_SUCCESS);
896 
897     ImageMemoryBarrier(commandBuffers[0], image, VK_QUEUE_FAMILY_EXTERNAL,
898                        mGraphicsQueueFamilyIndex, oldLayout, newLayout);
899 
900     result = vkEndCommandBuffer(commandBuffers[0]);
901     ASSERT(result == VK_SUCCESS);
902 
903     const VkSemaphore waitSemaphores[] = {
904         semaphore,
905     };
906     const VkPipelineStageFlags waitDstStageMasks[] = {
907         VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
908     };
909     constexpr uint32_t waitSemaphoreCount    = std::extent<decltype(waitSemaphores)>();
910     constexpr uint32_t waitDstStageMaskCount = std::extent<decltype(waitDstStageMasks)>();
911     static_assert(waitSemaphoreCount == waitDstStageMaskCount,
912                   "waitSemaphores and waitDstStageMasks must be the same length");
913 
914     const VkSubmitInfo submits[] = {
915         /* [0] = */ {
916             /* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,
917             /* .pNext = */ nullptr,
918             /* .waitSemaphoreCount = */ waitSemaphoreCount,
919             /* .pWaitSemaphores = */ waitSemaphores,
920             /* .pWaitDstStageMask = */ waitDstStageMasks,
921             /* .commandBufferCount = */ commandBufferCount,
922             /* .pCommandBuffers = */ commandBuffers,
923             /* .signalSemaphoreCount = */ 0,
924             /* .pSignalSemaphores = */ nullptr,
925         },
926     };
927     constexpr uint32_t submitCount = std::extent<decltype(submits)>();
928 
929     const VkFence fence = VK_NULL_HANDLE;
930     result              = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);
931     ASSERT(result == VK_SUCCESS);
932 }
933 
readPixels(VkImage srcImage,VkImageLayout srcImageLayout,VkFormat srcImageFormat,VkOffset3D imageOffset,VkExtent3D imageExtent,void * pixels,size_t pixelsSize)934 void VulkanHelper::readPixels(VkImage srcImage,
935                               VkImageLayout srcImageLayout,
936                               VkFormat srcImageFormat,
937                               VkOffset3D imageOffset,
938                               VkExtent3D imageExtent,
939                               void *pixels,
940                               size_t pixelsSize)
941 {
942     ASSERT(srcImageFormat == VK_FORMAT_B8G8R8A8_UNORM ||
943            srcImageFormat == VK_FORMAT_R8G8B8A8_UNORM);
944     ASSERT(imageExtent.depth == 1);
945     ASSERT(pixelsSize == 4 * imageExtent.width * imageExtent.height);
946 
947     VkBufferCreateInfo bufferCreateInfo = {
948         /* .sType = */ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
949         /* .pNext = */ nullptr,
950         /* .flags = */ 0,
951         /* .size = */ pixelsSize,
952         /* .usage = */ VK_BUFFER_USAGE_TRANSFER_DST_BIT,
953         /* .sharingMode = */ VK_SHARING_MODE_EXCLUSIVE,
954         /* .queueFamilyIndexCount = */ 0,
955         /* .pQueueFamilyIndices = */ nullptr,
956     };
957     VkBuffer stagingBuffer = VK_NULL_HANDLE;
958     VkResult result        = vkCreateBuffer(mDevice, &bufferCreateInfo, nullptr, &stagingBuffer);
959     ASSERT(result == VK_SUCCESS);
960 
961     VkMemoryPropertyFlags requestedMemoryPropertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
962     VkMemoryRequirements memoryRequirements;
963     vkGetBufferMemoryRequirements(mDevice, stagingBuffer, &memoryRequirements);
964     uint32_t memoryTypeIndex = FindMemoryType(mMemoryProperties, memoryRequirements.memoryTypeBits,
965                                               requestedMemoryPropertyFlags);
966     ASSERT(memoryTypeIndex != UINT32_MAX);
967     VkDeviceSize deviceMemorySize = memoryRequirements.size;
968 
969     VkMemoryDedicatedAllocateInfoKHR memoryDedicatedAllocateInfo = {
970         /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
971         /* .pNext = */ nullptr,
972         /* .image = */ VK_NULL_HANDLE,
973         /* .buffer = */ stagingBuffer,
974     };
975     VkMemoryAllocateInfo memoryAllocateInfo = {
976         /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
977         /* .pNext = */ &memoryDedicatedAllocateInfo,
978         /* .allocationSize = */ deviceMemorySize,
979         /* .memoryTypeIndex = */ memoryTypeIndex,
980     };
981 
982     VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
983     result = vkAllocateMemory(mDevice, &memoryAllocateInfo, nullptr, &deviceMemory);
984     ASSERT(result == VK_SUCCESS);
985 
986     result = vkBindBufferMemory(mDevice, stagingBuffer, deviceMemory, 0 /* memoryOffset */);
987     ASSERT(result == VK_SUCCESS);
988 
989     VkCommandBuffer commandBuffers[]                      = {VK_NULL_HANDLE};
990     constexpr uint32_t commandBufferCount                 = std::extent<decltype(commandBuffers)>();
991     VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
992         /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
993         /* .pNext = */ nullptr,
994         /* .commandPool = */ mCommandPool,
995         /* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
996         /* .commandBufferCount = */ commandBufferCount,
997     };
998 
999     result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);
1000     ASSERT(result == VK_SUCCESS);
1001 
1002     VkCommandBufferBeginInfo commandBufferBeginInfo = {
1003         /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1004         /* .pNext = */ nullptr,
1005         /* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
1006         /* .pInheritanceInfo = */ nullptr,
1007     };
1008     result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);
1009     ASSERT(result == VK_SUCCESS);
1010 
1011     VkBufferImageCopy bufferImageCopies[] = {
1012         /* [0] = */ {
1013             /* .bufferOffset = */ 0,
1014             /* .bufferRowLength = */ 0,
1015             /* .bufferImageHeight = */ 0,
1016             /* .imageSubresources = */
1017             {
1018                 /* .aspectMask = */ VK_IMAGE_ASPECT_COLOR_BIT,
1019                 /* .mipLevel = */ 0,
1020                 /* .baseArrayLayer = */ 0,
1021                 /* .layerCount = */ 1,
1022             },
1023             /* .imageOffset = */ imageOffset,
1024             /* .imageExtent = */ imageExtent,
1025         },
1026     };
1027     constexpr uint32_t bufferImageCopyCount = std::extent<decltype(bufferImageCopies)>();
1028 
1029     if (srcImageLayout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
1030     {
1031         VkImageMemoryBarrier imageMemoryBarriers = {
1032             /* .sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1033             /* .pNext = */ nullptr,
1034             /* .srcAccessMask = */ VK_ACCESS_TRANSFER_WRITE_BIT,
1035             /* .dstAccessMask = */ VK_ACCESS_TRANSFER_READ_BIT,
1036             /* .oldLayout = */ srcImageLayout,
1037             /* .newLayout = */ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1038             /* .srcQueueFamilyIndex = */ mGraphicsQueueFamilyIndex,
1039             /* .dstQueueFamilyIndex = */ mGraphicsQueueFamilyIndex,
1040             /* .image = */ srcImage,
1041             /* .subresourceRange = */
1042             {
1043                 /* .aspectMask = */ VK_IMAGE_ASPECT_COLOR_BIT,
1044                 /* .baseMipLevel = */ 0,
1045                 /* .levelCount = */ 1,
1046                 /* .baseArrayLayer = */ 0,
1047                 /* .layerCount = */ 1,
1048             },
1049 
1050         };
1051         vkCmdPipelineBarrier(commandBuffers[0], VK_PIPELINE_STAGE_TRANSFER_BIT,
1052                              VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
1053                              &imageMemoryBarriers);
1054         srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
1055     }
1056 
1057     vkCmdCopyImageToBuffer(commandBuffers[0], srcImage, srcImageLayout, stagingBuffer,
1058                            bufferImageCopyCount, bufferImageCopies);
1059 
1060     VkMemoryBarrier memoryBarriers[] = {
1061         /* [0] = */ {/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_BARRIER,
1062                      /* .pNext = */ nullptr,
1063                      /* .srcAccessMask = */ VK_ACCESS_MEMORY_WRITE_BIT,
1064                      /* .dstAccessMask = */ VK_ACCESS_HOST_READ_BIT},
1065     };
1066     constexpr uint32_t memoryBarrierCount = std::extent<decltype(memoryBarriers)>();
1067     vkCmdPipelineBarrier(commandBuffers[0], VK_PIPELINE_STAGE_TRANSFER_BIT,
1068                          VK_PIPELINE_STAGE_HOST_BIT, 0 /* dependencyFlags */, memoryBarrierCount,
1069                          memoryBarriers, 0, nullptr, 0, nullptr);
1070 
1071     result = vkEndCommandBuffer(commandBuffers[0]);
1072     ASSERT(result == VK_SUCCESS);
1073 
1074     const VkSubmitInfo submits[] = {
1075         /* [0] = */ {
1076             /* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,
1077             /* .pNext = */ nullptr,
1078             /* .waitSemaphoreCount = */ 0,
1079             /* .pWaitSemaphores = */ nullptr,
1080             /* .pWaitDstStageMask = */ nullptr,
1081             /* .commandBufferCount = */ commandBufferCount,
1082             /* .pCommandBuffers = */ commandBuffers,
1083             /* .signalSemaphoreCount = */ 0,
1084             /* .pSignalSemaphores = */ nullptr,
1085         },
1086     };
1087     constexpr uint32_t submitCount = std::extent<decltype(submits)>();
1088 
1089     const VkFence fence = VK_NULL_HANDLE;
1090     result              = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);
1091     ASSERT(result == VK_SUCCESS);
1092 
1093     result = vkQueueWaitIdle(mGraphicsQueue);
1094     ASSERT(result == VK_SUCCESS);
1095 
1096     vkFreeCommandBuffers(mDevice, mCommandPool, commandBufferCount, commandBuffers);
1097 
1098     void *stagingMemory = nullptr;
1099     result = vkMapMemory(mDevice, deviceMemory, 0 /* offset */, deviceMemorySize, 0 /* flags */,
1100                          &stagingMemory);
1101     ASSERT(result == VK_SUCCESS);
1102 
1103     VkMappedMemoryRange memoryRanges[] = {
1104         /* [0] = */ {
1105             /* .sType = */ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
1106             /* .pNext = */ nullptr,
1107             /* .memory = */ deviceMemory,
1108             /* .offset = */ 0,
1109             /* .size = */ deviceMemorySize,
1110         },
1111     };
1112     constexpr uint32_t memoryRangeCount = std::extent<decltype(memoryRanges)>();
1113 
1114     result = vkInvalidateMappedMemoryRanges(mDevice, memoryRangeCount, memoryRanges);
1115     ASSERT(result == VK_SUCCESS);
1116 
1117     memcpy(pixels, stagingMemory, pixelsSize);
1118 
1119     vkDestroyBuffer(mDevice, stagingBuffer, nullptr);
1120 
1121     vkUnmapMemory(mDevice, deviceMemory);
1122     vkFreeMemory(mDevice, deviceMemory, nullptr);
1123 }
1124 
1125 }  // namespace angle
1126