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