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