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