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