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