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