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