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
EnumerateInstanceExtensionProperties(const char * layerName)24 std::vector<VkExtensionProperties> EnumerateInstanceExtensionProperties(const char *layerName)
25 {
26 uint32_t instanceExtensionCount;
27 VkResult result =
28 vkEnumerateInstanceExtensionProperties(layerName, &instanceExtensionCount, nullptr);
29 ASSERT(result == VK_SUCCESS);
30 std::vector<VkExtensionProperties> instanceExtensionProperties(instanceExtensionCount);
31 result = vkEnumerateInstanceExtensionProperties(layerName, &instanceExtensionCount,
32 instanceExtensionProperties.data());
33 ASSERT(result == VK_SUCCESS);
34 return instanceExtensionProperties;
35 }
36
EnumeratePhysicalDevices(VkInstance instance)37 std::vector<VkPhysicalDevice> EnumeratePhysicalDevices(VkInstance instance)
38 {
39 uint32_t physicalDeviceCount;
40 VkResult result = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr);
41 ASSERT(result == VK_SUCCESS);
42 std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
43 result = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data());
44 return physicalDevices;
45 }
46
EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,const char * layerName)47 std::vector<VkExtensionProperties> EnumerateDeviceExtensionProperties(
48 VkPhysicalDevice physicalDevice,
49 const char *layerName)
50 {
51 uint32_t deviceExtensionCount;
52 VkResult result = vkEnumerateDeviceExtensionProperties(physicalDevice, layerName,
53 &deviceExtensionCount, nullptr);
54 ASSERT(result == VK_SUCCESS);
55 std::vector<VkExtensionProperties> deviceExtensionProperties(deviceExtensionCount);
56 result = vkEnumerateDeviceExtensionProperties(physicalDevice, layerName, &deviceExtensionCount,
57 deviceExtensionProperties.data());
58 ASSERT(result == VK_SUCCESS);
59 return deviceExtensionProperties;
60 }
61
GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice)62 std::vector<VkQueueFamilyProperties> GetPhysicalDeviceQueueFamilyProperties(
63 VkPhysicalDevice physicalDevice)
64 {
65 uint32_t queueFamilyPropertyCount;
66 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertyCount, nullptr);
67 std::vector<VkQueueFamilyProperties> physicalDeviceQueueFamilyProperties(
68 queueFamilyPropertyCount);
69 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertyCount,
70 physicalDeviceQueueFamilyProperties.data());
71 return physicalDeviceQueueFamilyProperties;
72 }
73
HasExtension(const std::vector<VkExtensionProperties> instanceExtensions,const char * extensionName)74 bool HasExtension(const std::vector<VkExtensionProperties> instanceExtensions,
75 const char *extensionName)
76 {
77 for (const auto &extensionProperties : instanceExtensions)
78 {
79 if (!strcmp(extensionProperties.extensionName, extensionName))
80 return true;
81 }
82
83 return false;
84 }
85
HasExtension(const std::vector<const char * > enabledExtensions,const char * extensionName)86 bool HasExtension(const std::vector<const char *> enabledExtensions, const char *extensionName)
87 {
88 for (const char *enabledExtension : enabledExtensions)
89 {
90 if (!strcmp(enabledExtension, extensionName))
91 return true;
92 }
93
94 return false;
95 }
96
FindMemoryType(const VkPhysicalDeviceMemoryProperties & memoryProperties,uint32_t memoryTypeBits,VkMemoryPropertyFlags requiredMemoryPropertyFlags)97 uint32_t FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProperties,
98 uint32_t memoryTypeBits,
99 VkMemoryPropertyFlags requiredMemoryPropertyFlags)
100 {
101 for (size_t memoryIndex : angle::BitSet32<32>(memoryTypeBits))
102 {
103 ASSERT(memoryIndex < memoryProperties.memoryTypeCount);
104
105 if ((memoryProperties.memoryTypes[memoryIndex].propertyFlags &
106 requiredMemoryPropertyFlags) == requiredMemoryPropertyFlags)
107 {
108 return static_cast<uint32_t>(memoryIndex);
109 }
110 }
111
112 return UINT32_MAX;
113 }
114
ImageMemoryBarrier(VkCommandBuffer commandBuffer,VkImage image,uint32_t srcQueueFamilyIndex,uint32_t dstQueueFamilyIndex,VkImageLayout oldLayout,VkImageLayout newLayout)115 void ImageMemoryBarrier(VkCommandBuffer commandBuffer,
116 VkImage image,
117 uint32_t srcQueueFamilyIndex,
118 uint32_t dstQueueFamilyIndex,
119 VkImageLayout oldLayout,
120 VkImageLayout newLayout)
121 {
122 const VkImageMemoryBarrier imageMemoryBarriers[] = {
123 /* [0] = */ {/* .sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
124 /* .pNext = */ nullptr,
125 /* .srcAccessMask = */ VK_ACCESS_MEMORY_WRITE_BIT,
126 /* .dstAccessMask = */ VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
127 /* .oldLayout = */ oldLayout,
128 /* .newLayout = */ newLayout,
129 /* .srcQueueFamilyIndex = */ srcQueueFamilyIndex,
130 /* .dstQueueFamilyIndex = */ dstQueueFamilyIndex,
131 /* .image = */ image,
132 /* .subresourceRange = */
133 {
134 /* .aspectMask = */ VK_IMAGE_ASPECT_COLOR_BIT,
135 /* .basicMiplevel = */ 0,
136 /* .levelCount = */ 1,
137 /* .baseArrayLayer = */ 0,
138 /* .layerCount = */ 1,
139 }}};
140 const uint32_t imageMemoryBarrierCount = std::extent<decltype(imageMemoryBarriers)>();
141
142 constexpr VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
143 constexpr VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
144 const VkDependencyFlags dependencyFlags = 0;
145
146 vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, 0, nullptr, 0,
147 nullptr, imageMemoryBarrierCount, imageMemoryBarriers);
148 }
149
150 } // namespace
151
VulkanExternalHelper()152 VulkanExternalHelper::VulkanExternalHelper() {}
153
~VulkanExternalHelper()154 VulkanExternalHelper::~VulkanExternalHelper()
155 {
156 if (mDevice != VK_NULL_HANDLE)
157 {
158 vkDeviceWaitIdle(mDevice);
159 }
160
161 if (mCommandPool != VK_NULL_HANDLE)
162 {
163 vkDestroyCommandPool(mDevice, mCommandPool, nullptr);
164 }
165
166 if (mDevice != VK_NULL_HANDLE)
167 {
168 vkDestroyDevice(mDevice, nullptr);
169
170 mDevice = VK_NULL_HANDLE;
171 mGraphicsQueue = VK_NULL_HANDLE;
172 }
173
174 if (mInstance != VK_NULL_HANDLE)
175 {
176 vkDestroyInstance(mInstance, nullptr);
177
178 mInstance = VK_NULL_HANDLE;
179 }
180 }
181
initialize(bool useSwiftshader,bool enableValidationLayers)182 void VulkanExternalHelper::initialize(bool useSwiftshader, bool enableValidationLayers)
183 {
184 bool enableValidationLayersOverride = enableValidationLayers;
185 #if !defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS)
186 enableValidationLayersOverride = false;
187 #endif
188
189 vk::ICD icd = useSwiftshader ? vk::ICD::SwiftShader : vk::ICD::Default;
190
191 vk::ScopedVkLoaderEnvironment scopedEnvironment(enableValidationLayersOverride, 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 (enableValidationLayersOverride)
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 = */ static_cast<uint32_t>(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,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags,VkExternalMemoryHandleTypeFlagBits handleType) const374 bool VulkanExternalHelper::canCreateImageExternal(
375 VkFormat format,
376 VkImageType type,
377 VkImageTiling tiling,
378 VkImageCreateFlags createFlags,
379 VkImageUsageFlags usageFlags,
380 VkExternalMemoryHandleTypeFlagBits handleType) const
381 {
382 VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo = {
383 /* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
384 /* .pNext = */ nullptr,
385 /* .handleType = */ handleType,
386 };
387
388 VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {
389 /* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
390 /* .pNext = */ &externalImageFormatInfo,
391 /* .format = */ format,
392 /* .type = */ type,
393 /* .tiling = */ tiling,
394 /* .usage = */ usageFlags,
395 /* .flags = */ createFlags,
396 };
397
398 VkExternalImageFormatProperties externalImageFormatProperties = {
399 /* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
400 /* .pNext = */ nullptr,
401 };
402
403 VkImageFormatProperties2 imageFormatProperties = {
404 /* .sType = */ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
405 /* .pNext = */ &externalImageFormatProperties};
406
407 VkResult result = vkGetPhysicalDeviceImageFormatProperties2(mPhysicalDevice, &imageFormatInfo,
408 &imageFormatProperties);
409 if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
410 {
411 return false;
412 }
413
414 ASSERT(result == VK_SUCCESS);
415
416 constexpr VkExternalMemoryFeatureFlags kRequiredFeatures =
417 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
418 if ((externalImageFormatProperties.externalMemoryProperties.externalMemoryFeatures &
419 kRequiredFeatures) != kRequiredFeatures)
420 {
421 return false;
422 }
423
424 return true;
425 }
426
createImage2DExternal(VkFormat format,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags,VkExtent3D extent,VkExternalMemoryHandleTypeFlags handleTypes,VkImage * imageOut,VkDeviceMemory * deviceMemoryOut,VkDeviceSize * deviceMemorySizeOut)427 VkResult VulkanExternalHelper::createImage2DExternal(VkFormat format,
428 VkImageCreateFlags createFlags,
429 VkImageUsageFlags usageFlags,
430 VkExtent3D extent,
431 VkExternalMemoryHandleTypeFlags handleTypes,
432 VkImage *imageOut,
433 VkDeviceMemory *deviceMemoryOut,
434 VkDeviceSize *deviceMemorySizeOut)
435 {
436 VkExternalMemoryImageCreateInfoKHR externalMemoryImageCreateInfo = {
437 /* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
438 /* .pNext = */ nullptr,
439 /* .handleTypes = */ handleTypes,
440 };
441
442 VkImageCreateInfo imageCreateInfo = {
443 /* .sType = */ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
444 /* .pNext = */ &externalMemoryImageCreateInfo,
445 /* .flags = */ createFlags,
446 /* .imageType = */ VK_IMAGE_TYPE_2D,
447 /* .format = */ format,
448 /* .extent = */ extent,
449 /* .mipLevels = */ 1,
450 /* .arrayLayers = */ 1,
451 /* .samples = */ VK_SAMPLE_COUNT_1_BIT,
452 /* .tiling = */ VK_IMAGE_TILING_OPTIMAL,
453 /* .usage = */ usageFlags,
454 /* .sharingMode = */ VK_SHARING_MODE_EXCLUSIVE,
455 /* .queueFamilyIndexCount = */ 0,
456 /* .pQueueFamilyIndices = */ nullptr,
457 /* initialLayout = */ VK_IMAGE_LAYOUT_UNDEFINED,
458 };
459
460 VkImage image = VK_NULL_HANDLE;
461 VkResult result = vkCreateImage(mDevice, &imageCreateInfo, nullptr, &image);
462 if (result != VK_SUCCESS)
463 {
464 return result;
465 }
466
467 VkMemoryPropertyFlags requestedMemoryPropertyFlags = 0;
468 VkMemoryRequirements memoryRequirements;
469 vkGetImageMemoryRequirements(mDevice, image, &memoryRequirements);
470 uint32_t memoryTypeIndex = FindMemoryType(mMemoryProperties, memoryRequirements.memoryTypeBits,
471 requestedMemoryPropertyFlags);
472 ASSERT(memoryTypeIndex != UINT32_MAX);
473 VkDeviceSize deviceMemorySize = memoryRequirements.size;
474
475 VkExportMemoryAllocateInfo exportMemoryAllocateInfo = {
476 /* .sType = */ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
477 /* .pNext = */ nullptr,
478 /* .handleTypes = */ handleTypes,
479 };
480 VkMemoryDedicatedAllocateInfoKHR memoryDedicatedAllocateInfo = {
481 /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
482 /* .pNext = */ &exportMemoryAllocateInfo,
483 /* .image = */ image,
484 };
485 VkMemoryAllocateInfo memoryAllocateInfo = {
486 /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
487 /* .pNext = */ &memoryDedicatedAllocateInfo,
488 /* .allocationSize = */ deviceMemorySize,
489 /* .memoryTypeIndex = */ memoryTypeIndex,
490 };
491
492 VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
493 result = vkAllocateMemory(mDevice, &memoryAllocateInfo, nullptr, &deviceMemory);
494 if (result != VK_SUCCESS)
495 {
496 vkDestroyImage(mDevice, image, nullptr);
497 return result;
498 }
499
500 VkDeviceSize memoryOffset = 0;
501 result = vkBindImageMemory(mDevice, image, deviceMemory, memoryOffset);
502 if (result != VK_SUCCESS)
503 {
504 vkFreeMemory(mDevice, deviceMemory, nullptr);
505 vkDestroyImage(mDevice, image, nullptr);
506 return result;
507 }
508
509 *imageOut = image;
510 *deviceMemoryOut = deviceMemory;
511 *deviceMemorySizeOut = deviceMemorySize;
512
513 return VK_SUCCESS;
514 }
515
canCreateImageOpaqueFd(VkFormat format,VkImageType type,VkImageTiling tiling,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags) const516 bool VulkanExternalHelper::canCreateImageOpaqueFd(VkFormat format,
517 VkImageType type,
518 VkImageTiling tiling,
519 VkImageCreateFlags createFlags,
520 VkImageUsageFlags usageFlags) const
521 {
522 if (!mHasExternalMemoryFd)
523 {
524 return false;
525 }
526
527 return canCreateImageExternal(format, type, tiling, createFlags, usageFlags,
528 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
529 }
530
createImage2DOpaqueFd(VkFormat format,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags,VkExtent3D extent,VkImage * imageOut,VkDeviceMemory * deviceMemoryOut,VkDeviceSize * deviceMemorySizeOut)531 VkResult VulkanExternalHelper::createImage2DOpaqueFd(VkFormat format,
532 VkImageCreateFlags createFlags,
533 VkImageUsageFlags usageFlags,
534 VkExtent3D extent,
535 VkImage *imageOut,
536 VkDeviceMemory *deviceMemoryOut,
537 VkDeviceSize *deviceMemorySizeOut)
538 {
539 return createImage2DExternal(format, createFlags, usageFlags, extent,
540 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, imageOut,
541 deviceMemoryOut, deviceMemorySizeOut);
542 }
543
exportMemoryOpaqueFd(VkDeviceMemory deviceMemory,int * fd)544 VkResult VulkanExternalHelper::exportMemoryOpaqueFd(VkDeviceMemory deviceMemory, int *fd)
545 {
546 VkMemoryGetFdInfoKHR memoryGetFdInfo = {
547 /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
548 /* .pNext = */ nullptr,
549 /* .memory = */ deviceMemory,
550 /* .handleType = */ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
551 };
552
553 return vkGetMemoryFdKHR(mDevice, &memoryGetFdInfo, fd);
554 }
555
canCreateImageZirconVmo(VkFormat format,VkImageType type,VkImageTiling tiling,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags) const556 bool VulkanExternalHelper::canCreateImageZirconVmo(VkFormat format,
557 VkImageType type,
558 VkImageTiling tiling,
559 VkImageCreateFlags createFlags,
560 VkImageUsageFlags usageFlags) const
561 {
562 if (!mHasExternalMemoryFuchsia)
563 {
564 return false;
565 }
566
567 return canCreateImageExternal(format, type, tiling, createFlags, usageFlags,
568 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA);
569 }
570
createImage2DZirconVmo(VkFormat format,VkImageCreateFlags createFlags,VkImageUsageFlags usageFlags,VkExtent3D extent,VkImage * imageOut,VkDeviceMemory * deviceMemoryOut,VkDeviceSize * deviceMemorySizeOut)571 VkResult VulkanExternalHelper::createImage2DZirconVmo(VkFormat format,
572 VkImageCreateFlags createFlags,
573 VkImageUsageFlags usageFlags,
574 VkExtent3D extent,
575 VkImage *imageOut,
576 VkDeviceMemory *deviceMemoryOut,
577 VkDeviceSize *deviceMemorySizeOut)
578 {
579 return createImage2DExternal(format, createFlags, usageFlags, extent,
580 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA, imageOut,
581 deviceMemoryOut, deviceMemorySizeOut);
582 }
583
exportMemoryZirconVmo(VkDeviceMemory deviceMemory,zx_handle_t * vmo)584 VkResult VulkanExternalHelper::exportMemoryZirconVmo(VkDeviceMemory deviceMemory, zx_handle_t *vmo)
585 {
586 VkMemoryGetZirconHandleInfoFUCHSIA memoryGetZirconHandleInfo = {
587 /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA,
588 /* .pNext = */ nullptr,
589 /* .memory = */ deviceMemory,
590 /* .handleType = */ VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA,
591 };
592
593 return vkGetMemoryZirconHandleFUCHSIA(mDevice, &memoryGetZirconHandleInfo, vmo);
594 }
595
canCreateSemaphoreOpaqueFd() const596 bool VulkanExternalHelper::canCreateSemaphoreOpaqueFd() const
597 {
598 if (!mHasExternalSemaphoreFd || !vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)
599 {
600 return false;
601 }
602
603 VkPhysicalDeviceExternalSemaphoreInfo externalSemaphoreInfo = {
604 /* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
605 /* .pNext = */ nullptr,
606 /* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
607 };
608
609 VkExternalSemaphoreProperties externalSemaphoreProperties = {
610 /* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,
611 };
612 vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(mPhysicalDevice, &externalSemaphoreInfo,
613 &externalSemaphoreProperties);
614
615 constexpr VkExternalSemaphoreFeatureFlags kRequiredFeatures =
616 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
617
618 if ((externalSemaphoreProperties.externalSemaphoreFeatures & kRequiredFeatures) !=
619 kRequiredFeatures)
620 {
621 return false;
622 }
623
624 return true;
625 }
626
createSemaphoreOpaqueFd(VkSemaphore * semaphore)627 VkResult VulkanExternalHelper::createSemaphoreOpaqueFd(VkSemaphore *semaphore)
628 {
629 VkExportSemaphoreCreateInfo exportSemaphoreCreateInfo = {
630 /* .sType = */ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
631 /* .pNext = */ nullptr,
632 /* .handleTypes = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
633 };
634
635 VkSemaphoreCreateInfo semaphoreCreateInfo = {
636 /* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
637 /* .pNext = */ &exportSemaphoreCreateInfo,
638 /* .flags = */ 0,
639 };
640
641 return vkCreateSemaphore(mDevice, &semaphoreCreateInfo, nullptr, semaphore);
642 }
643
exportSemaphoreOpaqueFd(VkSemaphore semaphore,int * fd)644 VkResult VulkanExternalHelper::exportSemaphoreOpaqueFd(VkSemaphore semaphore, int *fd)
645 {
646 VkSemaphoreGetFdInfoKHR semaphoreGetFdInfo = {
647 /* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
648 /* .pNext = */ nullptr,
649 /* .semaphore = */ semaphore,
650 /* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
651 };
652
653 return vkGetSemaphoreFdKHR(mDevice, &semaphoreGetFdInfo, fd);
654 }
655
canCreateSemaphoreZirconEvent() const656 bool VulkanExternalHelper::canCreateSemaphoreZirconEvent() const
657 {
658 if (!mHasExternalSemaphoreFuchsia || !vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)
659 {
660 return false;
661 }
662
663 VkPhysicalDeviceExternalSemaphoreInfo externalSemaphoreInfo = {
664 /* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
665 /* .pNext = */ nullptr,
666 /* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,
667 };
668
669 VkExternalSemaphoreProperties externalSemaphoreProperties = {
670 /* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,
671 };
672 vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(mPhysicalDevice, &externalSemaphoreInfo,
673 &externalSemaphoreProperties);
674
675 constexpr VkExternalSemaphoreFeatureFlags kRequiredFeatures =
676 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
677
678 if ((externalSemaphoreProperties.externalSemaphoreFeatures & kRequiredFeatures) !=
679 kRequiredFeatures)
680 {
681 return false;
682 }
683
684 return true;
685 }
686
createSemaphoreZirconEvent(VkSemaphore * semaphore)687 VkResult VulkanExternalHelper::createSemaphoreZirconEvent(VkSemaphore *semaphore)
688 {
689 VkExportSemaphoreCreateInfo exportSemaphoreCreateInfo = {
690 /* .sType = */ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
691 /* .pNext = */ nullptr,
692 /* .handleTypes = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,
693 };
694
695 VkSemaphoreCreateInfo semaphoreCreateInfo = {
696 /* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
697 /* .pNext = */ &exportSemaphoreCreateInfo,
698 /* .flags = */ 0,
699 };
700
701 return vkCreateSemaphore(mDevice, &semaphoreCreateInfo, nullptr, semaphore);
702 }
703
exportSemaphoreZirconEvent(VkSemaphore semaphore,zx_handle_t * event)704 VkResult VulkanExternalHelper::exportSemaphoreZirconEvent(VkSemaphore semaphore, zx_handle_t *event)
705 {
706 VkSemaphoreGetZirconHandleInfoFUCHSIA semaphoreGetZirconHandleInfo = {
707 /* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA,
708 /* .pNext = */ nullptr,
709 /* .semaphore = */ semaphore,
710 /* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,
711 };
712
713 return vkGetSemaphoreZirconHandleFUCHSIA(mDevice, &semaphoreGetZirconHandleInfo, event);
714 }
715
releaseImageAndSignalSemaphore(VkImage image,VkImageLayout oldLayout,VkImageLayout newLayout,VkSemaphore semaphore)716 void VulkanExternalHelper::releaseImageAndSignalSemaphore(VkImage image,
717 VkImageLayout oldLayout,
718 VkImageLayout newLayout,
719 VkSemaphore semaphore)
720 {
721 VkResult result;
722
723 VkCommandBuffer commandBuffers[] = {VK_NULL_HANDLE};
724 constexpr uint32_t commandBufferCount = std::extent<decltype(commandBuffers)>();
725 VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
726 /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
727 /* .pNext = */ nullptr,
728 /* .commandPool = */ mCommandPool,
729 /* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
730 /* .commandBufferCount = */ commandBufferCount,
731 };
732
733 result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);
734 ASSERT(result == VK_SUCCESS);
735
736 VkCommandBufferBeginInfo commandBufferBeginInfo = {
737 /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
738 /* .pNext = */ nullptr,
739 /* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
740 /* .pInheritanceInfo = */ nullptr,
741 };
742 result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);
743 ASSERT(result == VK_SUCCESS);
744
745 ImageMemoryBarrier(commandBuffers[0], image, mGraphicsQueueFamilyIndex,
746 VK_QUEUE_FAMILY_EXTERNAL, oldLayout, newLayout);
747
748 result = vkEndCommandBuffer(commandBuffers[0]);
749 ASSERT(result == VK_SUCCESS);
750
751 const VkSemaphore signalSemaphores[] = {
752 semaphore,
753 };
754 constexpr uint32_t signalSemaphoreCount = std::extent<decltype(signalSemaphores)>();
755
756 const VkSubmitInfo submits[] = {
757 /* [0] = */ {
758 /* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,
759 /* .pNext = */ nullptr,
760 /* .waitSemaphoreCount = */ 0,
761 /* .pWaitSemaphores = */ nullptr,
762 /* .pWaitDstStageMask = */ nullptr,
763 /* .commandBufferCount = */ commandBufferCount,
764 /* .pCommandBuffers = */ commandBuffers,
765 /* .signalSemaphoreCount = */ signalSemaphoreCount,
766 /* .pSignalSemaphores = */ signalSemaphores,
767 },
768 };
769 constexpr uint32_t submitCount = std::extent<decltype(submits)>();
770
771 const VkFence fence = VK_NULL_HANDLE;
772 result = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);
773 ASSERT(result == VK_SUCCESS);
774 }
775
waitSemaphoreAndAcquireImage(VkImage image,VkImageLayout oldLayout,VkImageLayout newLayout,VkSemaphore semaphore)776 void VulkanExternalHelper::waitSemaphoreAndAcquireImage(VkImage image,
777 VkImageLayout oldLayout,
778 VkImageLayout newLayout,
779 VkSemaphore semaphore)
780 {
781 VkResult result;
782
783 VkCommandBuffer commandBuffers[] = {VK_NULL_HANDLE};
784 constexpr uint32_t commandBufferCount = std::extent<decltype(commandBuffers)>();
785 VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
786 /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
787 /* .pNext = */ nullptr,
788 /* .commandPool = */ mCommandPool,
789 /* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
790 /* .commandBufferCount = */ commandBufferCount,
791 };
792
793 result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);
794 ASSERT(result == VK_SUCCESS);
795
796 VkCommandBufferBeginInfo commandBufferBeginInfo = {
797 /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
798 /* .pNext = */ nullptr,
799 /* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
800 /* .pInheritanceInfo = */ nullptr,
801 };
802 result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);
803 ASSERT(result == VK_SUCCESS);
804
805 ImageMemoryBarrier(commandBuffers[0], image, VK_QUEUE_FAMILY_EXTERNAL,
806 mGraphicsQueueFamilyIndex, oldLayout, newLayout);
807
808 result = vkEndCommandBuffer(commandBuffers[0]);
809 ASSERT(result == VK_SUCCESS);
810
811 const VkSemaphore waitSemaphores[] = {
812 semaphore,
813 };
814 const VkPipelineStageFlags waitDstStageMasks[] = {
815 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
816 };
817 constexpr uint32_t waitSemaphoreCount = std::extent<decltype(waitSemaphores)>();
818 constexpr uint32_t waitDstStageMaskCount = std::extent<decltype(waitDstStageMasks)>();
819 static_assert(waitSemaphoreCount == waitDstStageMaskCount,
820 "waitSemaphores and waitDstStageMasks must be the same length");
821
822 const VkSubmitInfo submits[] = {
823 /* [0] = */ {
824 /* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,
825 /* .pNext = */ nullptr,
826 /* .waitSemaphoreCount = */ waitSemaphoreCount,
827 /* .pWaitSemaphores = */ waitSemaphores,
828 /* .pWaitDstStageMask = */ waitDstStageMasks,
829 /* .commandBufferCount = */ commandBufferCount,
830 /* .pCommandBuffers = */ commandBuffers,
831 /* .signalSemaphoreCount = */ 0,
832 /* .pSignalSemaphores = */ nullptr,
833 },
834 };
835 constexpr uint32_t submitCount = std::extent<decltype(submits)>();
836
837 const VkFence fence = VK_NULL_HANDLE;
838 result = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);
839 ASSERT(result == VK_SUCCESS);
840 }
841
readPixels(VkImage srcImage,VkImageLayout srcImageLayout,VkFormat srcImageFormat,VkOffset3D imageOffset,VkExtent3D imageExtent,void * pixels,size_t pixelsSize)842 void VulkanExternalHelper::readPixels(VkImage srcImage,
843 VkImageLayout srcImageLayout,
844 VkFormat srcImageFormat,
845 VkOffset3D imageOffset,
846 VkExtent3D imageExtent,
847 void *pixels,
848 size_t pixelsSize)
849 {
850 ASSERT(srcImageFormat == VK_FORMAT_B8G8R8A8_UNORM ||
851 srcImageFormat == VK_FORMAT_R8G8B8A8_UNORM);
852 ASSERT(imageExtent.depth == 1);
853 ASSERT(pixelsSize == 4 * imageExtent.width * imageExtent.height);
854
855 VkBufferCreateInfo bufferCreateInfo = {
856 /* .sType = */ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
857 /* .pNext = */ nullptr,
858 /* .flags = */ 0,
859 /* .size = */ pixelsSize,
860 /* .usage = */ VK_BUFFER_USAGE_TRANSFER_DST_BIT,
861 /* .sharingMode = */ VK_SHARING_MODE_EXCLUSIVE,
862 /* .queueFamilyIndexCount = */ 0,
863 /* .pQueueFamilyIndices = */ nullptr,
864 };
865 VkBuffer stagingBuffer = VK_NULL_HANDLE;
866 VkResult result = vkCreateBuffer(mDevice, &bufferCreateInfo, nullptr, &stagingBuffer);
867 ASSERT(result == VK_SUCCESS);
868
869 VkMemoryPropertyFlags requestedMemoryPropertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
870 VkMemoryRequirements memoryRequirements;
871 vkGetBufferMemoryRequirements(mDevice, stagingBuffer, &memoryRequirements);
872 uint32_t memoryTypeIndex = FindMemoryType(mMemoryProperties, memoryRequirements.memoryTypeBits,
873 requestedMemoryPropertyFlags);
874 ASSERT(memoryTypeIndex != UINT32_MAX);
875 VkDeviceSize deviceMemorySize = memoryRequirements.size;
876
877 VkMemoryDedicatedAllocateInfoKHR memoryDedicatedAllocateInfo = {
878 /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
879 /* .pNext = */ nullptr,
880 /* .image = */ VK_NULL_HANDLE,
881 /* .buffer = */ stagingBuffer,
882 };
883 VkMemoryAllocateInfo memoryAllocateInfo = {
884 /* .sType = */ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
885 /* .pNext = */ &memoryDedicatedAllocateInfo,
886 /* .allocationSize = */ deviceMemorySize,
887 /* .memoryTypeIndex = */ memoryTypeIndex,
888 };
889
890 VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
891 result = vkAllocateMemory(mDevice, &memoryAllocateInfo, nullptr, &deviceMemory);
892 ASSERT(result == VK_SUCCESS);
893
894 result = vkBindBufferMemory(mDevice, stagingBuffer, deviceMemory, 0 /* memoryOffset */);
895 ASSERT(result == VK_SUCCESS);
896
897 VkCommandBuffer commandBuffers[] = {VK_NULL_HANDLE};
898 constexpr uint32_t commandBufferCount = std::extent<decltype(commandBuffers)>();
899 VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
900 /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
901 /* .pNext = */ nullptr,
902 /* .commandPool = */ mCommandPool,
903 /* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
904 /* .commandBufferCount = */ commandBufferCount,
905 };
906
907 result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);
908 ASSERT(result == VK_SUCCESS);
909
910 VkCommandBufferBeginInfo commandBufferBeginInfo = {
911 /* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
912 /* .pNext = */ nullptr,
913 /* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
914 /* .pInheritanceInfo = */ nullptr,
915 };
916 result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);
917 ASSERT(result == VK_SUCCESS);
918
919 VkBufferImageCopy bufferImageCopies[] = {
920 /* [0] = */ {
921 /* .bufferOffset = */ 0,
922 /* .bufferRowLength = */ 0,
923 /* .bufferImageHeight = */ 0,
924 /* .imageSubresources = */
925 {
926 /* .aspectMask = */ VK_IMAGE_ASPECT_COLOR_BIT,
927 /* .mipLevel = */ 0,
928 /* .baseArrayLayer = */ 0,
929 /* .layerCount = */ 1,
930 },
931 /* .imageOffset = */ imageOffset,
932 /* .imageExtent = */ imageExtent,
933 },
934 };
935 constexpr uint32_t bufferImageCopyCount = std::extent<decltype(bufferImageCopies)>();
936
937 vkCmdCopyImageToBuffer(commandBuffers[0], srcImage, srcImageLayout, stagingBuffer,
938 bufferImageCopyCount, bufferImageCopies);
939
940 VkMemoryBarrier memoryBarriers[] = {
941 /* [0] = */ {/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_BARRIER,
942 /* .pNext = */ nullptr,
943 /* .srcAccessMask = */ VK_ACCESS_MEMORY_WRITE_BIT,
944 /* .dstAccessMask = */ VK_ACCESS_HOST_READ_BIT},
945 };
946 constexpr uint32_t memoryBarrierCount = std::extent<decltype(memoryBarriers)>();
947 vkCmdPipelineBarrier(commandBuffers[0], VK_PIPELINE_STAGE_TRANSFER_BIT,
948 VK_PIPELINE_STAGE_HOST_BIT, 0 /* dependencyFlags */, memoryBarrierCount,
949 memoryBarriers, 0, nullptr, 0, nullptr);
950
951 result = vkEndCommandBuffer(commandBuffers[0]);
952 ASSERT(result == VK_SUCCESS);
953
954 const VkSubmitInfo submits[] = {
955 /* [0] = */ {
956 /* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,
957 /* .pNext = */ nullptr,
958 /* .waitSemaphoreCount = */ 0,
959 /* .pWaitSemaphores = */ nullptr,
960 /* .pWaitDstStageMask = */ nullptr,
961 /* .commandBufferCount = */ commandBufferCount,
962 /* .pCommandBuffers = */ commandBuffers,
963 /* .signalSemaphoreCount = */ 0,
964 /* .pSignalSemaphores = */ nullptr,
965 },
966 };
967 constexpr uint32_t submitCount = std::extent<decltype(submits)>();
968
969 const VkFence fence = VK_NULL_HANDLE;
970 result = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);
971 ASSERT(result == VK_SUCCESS);
972
973 result = vkQueueWaitIdle(mGraphicsQueue);
974 ASSERT(result == VK_SUCCESS);
975
976 vkFreeCommandBuffers(mDevice, mCommandPool, commandBufferCount, commandBuffers);
977
978 void *stagingMemory = nullptr;
979 result = vkMapMemory(mDevice, deviceMemory, 0 /* offset */, pixelsSize, 0 /* flags */,
980 &stagingMemory);
981 ASSERT(result == VK_SUCCESS);
982
983 VkMappedMemoryRange memoryRanges[] = {
984 /* [0] = */ {
985 /* .sType = */ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
986 /* .pNext = */ nullptr,
987 /* .memory = */ deviceMemory,
988 /* .offset = */ 0,
989 /* .size = */ pixelsSize,
990 },
991 };
992 constexpr uint32_t memoryRangeCount = std::extent<decltype(memoryRanges)>();
993
994 result = vkInvalidateMappedMemoryRanges(mDevice, memoryRangeCount, memoryRanges);
995 ASSERT(result == VK_SUCCESS);
996
997 memcpy(pixels, stagingMemory, pixelsSize);
998
999 vkUnmapMemory(mDevice, deviceMemory);
1000 vkFreeMemory(mDevice, deviceMemory, nullptr);
1001 vkDestroyBuffer(mDevice, stagingBuffer, nullptr);
1002 }
1003
1004 } // namespace angle
1005