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