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