Path: blob/main_old/src/tests/test_utils/VulkanExternalHelper.cpp
1693 views
//1// Copyright 2019 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//56// VulkanExternalHelper.cpp : Helper for allocating & managing vulkan external objects.78#include "test_utils/VulkanExternalHelper.h"910#include <vector>1112#include "common/bitset_utils.h"13#include "common/debug.h"14#include "common/system_utils.h"15#include "common/vulkan/vulkan_icd.h"1617namespace angle18{1920namespace21{2223std::vector<VkExtensionProperties> EnumerateInstanceExtensionProperties(const char *layerName)24{25uint32_t instanceExtensionCount;26VkResult result =27vkEnumerateInstanceExtensionProperties(layerName, &instanceExtensionCount, nullptr);28ASSERT(result == VK_SUCCESS);29std::vector<VkExtensionProperties> instanceExtensionProperties(instanceExtensionCount);30result = vkEnumerateInstanceExtensionProperties(layerName, &instanceExtensionCount,31instanceExtensionProperties.data());32ASSERT(result == VK_SUCCESS);33return instanceExtensionProperties;34}3536std::vector<VkPhysicalDevice> EnumeratePhysicalDevices(VkInstance instance)37{38uint32_t physicalDeviceCount;39VkResult result = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr);40ASSERT(result == VK_SUCCESS);41std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);42result = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data());43return physicalDevices;44}4546std::vector<VkExtensionProperties> EnumerateDeviceExtensionProperties(47VkPhysicalDevice physicalDevice,48const char *layerName)49{50uint32_t deviceExtensionCount;51VkResult result = vkEnumerateDeviceExtensionProperties(physicalDevice, layerName,52&deviceExtensionCount, nullptr);53ASSERT(result == VK_SUCCESS);54std::vector<VkExtensionProperties> deviceExtensionProperties(deviceExtensionCount);55result = vkEnumerateDeviceExtensionProperties(physicalDevice, layerName, &deviceExtensionCount,56deviceExtensionProperties.data());57ASSERT(result == VK_SUCCESS);58return deviceExtensionProperties;59}6061std::vector<VkQueueFamilyProperties> GetPhysicalDeviceQueueFamilyProperties(62VkPhysicalDevice physicalDevice)63{64uint32_t queueFamilyPropertyCount;65vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertyCount, nullptr);66std::vector<VkQueueFamilyProperties> physicalDeviceQueueFamilyProperties(67queueFamilyPropertyCount);68vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertyCount,69physicalDeviceQueueFamilyProperties.data());70return physicalDeviceQueueFamilyProperties;71}7273bool HasExtension(const std::vector<VkExtensionProperties> instanceExtensions,74const char *extensionName)75{76for (const auto &extensionProperties : instanceExtensions)77{78if (!strcmp(extensionProperties.extensionName, extensionName))79return true;80}8182return false;83}8485bool HasExtension(const std::vector<const char *> enabledExtensions, const char *extensionName)86{87for (const char *enabledExtension : enabledExtensions)88{89if (!strcmp(enabledExtension, extensionName))90return true;91}9293return false;94}9596uint32_t FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProperties,97uint32_t memoryTypeBits,98VkMemoryPropertyFlags requiredMemoryPropertyFlags)99{100for (size_t memoryIndex : angle::BitSet32<32>(memoryTypeBits))101{102ASSERT(memoryIndex < memoryProperties.memoryTypeCount);103104if ((memoryProperties.memoryTypes[memoryIndex].propertyFlags &105requiredMemoryPropertyFlags) == requiredMemoryPropertyFlags)106{107return static_cast<uint32_t>(memoryIndex);108}109}110111return UINT32_MAX;112}113114void ImageMemoryBarrier(VkCommandBuffer commandBuffer,115VkImage image,116uint32_t srcQueueFamilyIndex,117uint32_t dstQueueFamilyIndex,118VkImageLayout oldLayout,119VkImageLayout newLayout)120{121const VkImageMemoryBarrier imageMemoryBarriers[] = {122/* [0] = */ {/* .sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,123/* .pNext = */ nullptr,124/* .srcAccessMask = */ VK_ACCESS_MEMORY_WRITE_BIT,125/* .dstAccessMask = */ VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,126/* .oldLayout = */ oldLayout,127/* .newLayout = */ newLayout,128/* .srcQueueFamilyIndex = */ srcQueueFamilyIndex,129/* .dstQueueFamilyIndex = */ dstQueueFamilyIndex,130/* .image = */ image,131/* .subresourceRange = */132{133/* .aspectMask = */ VK_IMAGE_ASPECT_COLOR_BIT,134/* .basicMiplevel = */ 0,135/* .levelCount = */ 1,136/* .baseArrayLayer = */ 0,137/* .layerCount = */ 1,138}}};139const uint32_t imageMemoryBarrierCount = std::extent<decltype(imageMemoryBarriers)>();140141constexpr VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;142constexpr VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;143const VkDependencyFlags dependencyFlags = 0;144145vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, 0, nullptr, 0,146nullptr, imageMemoryBarrierCount, imageMemoryBarriers);147}148149} // namespace150151VulkanExternalHelper::VulkanExternalHelper() {}152153VulkanExternalHelper::~VulkanExternalHelper()154{155if (mDevice != VK_NULL_HANDLE)156{157vkDeviceWaitIdle(mDevice);158}159160if (mCommandPool != VK_NULL_HANDLE)161{162vkDestroyCommandPool(mDevice, mCommandPool, nullptr);163}164165if (mDevice != VK_NULL_HANDLE)166{167vkDestroyDevice(mDevice, nullptr);168169mDevice = VK_NULL_HANDLE;170mGraphicsQueue = VK_NULL_HANDLE;171}172173if (mInstance != VK_NULL_HANDLE)174{175vkDestroyInstance(mInstance, nullptr);176177mInstance = VK_NULL_HANDLE;178}179}180181void VulkanExternalHelper::initialize(bool useSwiftshader, bool enableValidationLayers)182{183bool enableValidationLayersOverride = enableValidationLayers;184#if !defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS)185enableValidationLayersOverride = false;186#endif187188vk::ICD icd = useSwiftshader ? vk::ICD::SwiftShader : vk::ICD::Default;189190vk::ScopedVkLoaderEnvironment scopedEnvironment(enableValidationLayersOverride, icd);191192ASSERT(mInstance == VK_NULL_HANDLE);193VkResult result = VK_SUCCESS;194#if ANGLE_SHARED_LIBVULKAN195result = volkInitialize();196ASSERT(result == VK_SUCCESS);197#endif // ANGLE_SHARED_LIBVULKAN198std::vector<VkExtensionProperties> instanceExtensionProperties =199EnumerateInstanceExtensionProperties(nullptr);200201std::vector<const char *> requestedInstanceExtensions = {202VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,203VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,204VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME};205206std::vector<const char *> enabledInstanceExtensions;207208for (const char *extensionName : requestedInstanceExtensions)209{210if (HasExtension(instanceExtensionProperties, extensionName))211{212enabledInstanceExtensions.push_back(extensionName);213}214}215216VkApplicationInfo applicationInfo = {217/* .sType = */ VK_STRUCTURE_TYPE_APPLICATION_INFO,218/* .pNext = */ nullptr,219/* .pApplicationName = */ "ANGLE Tests",220/* .applicationVersion = */ 1,221/* .pEngineName = */ nullptr,222/* .engineVersion = */ 0,223/* .apiVersion = */ VK_API_VERSION_1_0,224};225226uint32_t enabledInstanceExtensionCount =227static_cast<uint32_t>(enabledInstanceExtensions.size());228229std::vector<const char *> enabledLayerNames;230if (enableValidationLayersOverride)231{232enabledLayerNames.push_back("VK_LAYER_KHRONOS_validation");233}234235VkInstanceCreateInfo instanceCreateInfo = {236/* .sType = */ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,237/* .pNext = */ nullptr,238/* .flags = */ 0,239/* .pApplicationInfo = */ &applicationInfo,240/* .enabledLayerCount = */ static_cast<uint32_t>(enabledLayerNames.size()),241/* .ppEnabledLayerNames = */ enabledLayerNames.data(),242/* .enabledExtensionCount = */ enabledInstanceExtensionCount,243/* .ppEnabledExtensionName = */ enabledInstanceExtensions.data(),244};245246result = vkCreateInstance(&instanceCreateInfo, nullptr, &mInstance);247ASSERT(result == VK_SUCCESS);248ASSERT(mInstance != VK_NULL_HANDLE);249#if ANGLE_SHARED_LIBVULKAN250volkLoadInstance(mInstance);251#endif // ANGLE_SHARED_LIBVULKAN252253std::vector<VkPhysicalDevice> physicalDevices = EnumeratePhysicalDevices(mInstance);254255ASSERT(physicalDevices.size() > 0);256257VkPhysicalDeviceProperties physicalDeviceProperties;258ChoosePhysicalDevice(physicalDevices, icd, &mPhysicalDevice, &physicalDeviceProperties);259260vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &mMemoryProperties);261262std::vector<VkExtensionProperties> deviceExtensionProperties =263EnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr);264265std::vector<const char *> requestedDeviceExtensions = {266VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,267VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,268VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME, VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME,269};270271std::vector<const char *> enabledDeviceExtensions;272273for (const char *extensionName : requestedDeviceExtensions)274{275if (HasExtension(deviceExtensionProperties, extensionName))276{277enabledDeviceExtensions.push_back(extensionName);278}279}280281std::vector<VkQueueFamilyProperties> queueFamilyProperties =282GetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice);283284for (uint32_t i = 0; i < queueFamilyProperties.size(); ++i)285{286if (queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)287{288mGraphicsQueueFamilyIndex = i;289}290}291ASSERT(mGraphicsQueueFamilyIndex != UINT32_MAX);292293constexpr uint32_t kQueueCreateInfoCount = 1;294constexpr uint32_t kGraphicsQueueCount = 1;295float graphicsQueuePriorities[kGraphicsQueueCount] = {0.f};296297VkDeviceQueueCreateInfo queueCreateInfos[kQueueCreateInfoCount] = {298/* [0] = */ {299/* .sType = */ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,300/* .pNext = */ nullptr,301/* .flags = */ 0,302/* .queueFamilyIndex = */ mGraphicsQueueFamilyIndex,303/* .queueCount = */ 1,304/* .pQueuePriorities = */ graphicsQueuePriorities,305},306};307308uint32_t enabledDeviceExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size());309310VkDeviceCreateInfo deviceCreateInfo = {311/* .sType = */ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,312/* .pNext = */ nullptr,313/* .flags = */ 0,314/* .queueCreateInfoCount = */ kQueueCreateInfoCount,315/* .pQueueCreateInfos = */ queueCreateInfos,316/* .enabledLayerCount = */ 0,317/* .ppEnabledLayerNames = */ nullptr,318/* .enabledExtensionCount = */ enabledDeviceExtensionCount,319/* .ppEnabledExtensionName = */ enabledDeviceExtensions.data(),320/* .pEnabledFeatures = */ nullptr,321};322323result = vkCreateDevice(mPhysicalDevice, &deviceCreateInfo, nullptr, &mDevice);324ASSERT(result == VK_SUCCESS);325ASSERT(mDevice != VK_NULL_HANDLE);326#if ANGLE_SHARED_LIBVULKAN327volkLoadDevice(mDevice);328#endif // ANGLE_SHARED_LIBVULKAN329330constexpr uint32_t kGraphicsQueueIndex = 0;331static_assert(kGraphicsQueueIndex < kGraphicsQueueCount, "must be in range");332vkGetDeviceQueue(mDevice, mGraphicsQueueFamilyIndex, kGraphicsQueueIndex, &mGraphicsQueue);333ASSERT(mGraphicsQueue != VK_NULL_HANDLE);334335VkCommandPoolCreateInfo commandPoolCreateInfo = {336/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,337/* .pNext = */ nullptr,338/* .flags = */ 0,339/* .queueFamilyIndex = */ mGraphicsQueueFamilyIndex,340};341result = vkCreateCommandPool(mDevice, &commandPoolCreateInfo, nullptr, &mCommandPool);342ASSERT(result == VK_SUCCESS);343344mHasExternalMemoryFd =345HasExtension(enabledDeviceExtensions, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);346mHasExternalSemaphoreFd =347HasExtension(enabledDeviceExtensions, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME);348mHasExternalMemoryFuchsia =349HasExtension(enabledDeviceExtensions, VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME);350mHasExternalSemaphoreFuchsia =351HasExtension(enabledDeviceExtensions, VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME);352353vkGetPhysicalDeviceImageFormatProperties2 =354reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2>(355vkGetInstanceProcAddr(mInstance, "vkGetPhysicalDeviceImageFormatProperties2"));356vkGetMemoryFdKHR = reinterpret_cast<PFN_vkGetMemoryFdKHR>(357vkGetInstanceProcAddr(mInstance, "vkGetMemoryFdKHR"));358ASSERT(!mHasExternalMemoryFd || vkGetMemoryFdKHR);359vkGetSemaphoreFdKHR = reinterpret_cast<PFN_vkGetSemaphoreFdKHR>(360vkGetInstanceProcAddr(mInstance, "vkGetSemaphoreFdKHR"));361ASSERT(!mHasExternalSemaphoreFd || vkGetSemaphoreFdKHR);362vkGetPhysicalDeviceExternalSemaphorePropertiesKHR =363reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR>(364vkGetInstanceProcAddr(mInstance, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"));365vkGetMemoryZirconHandleFUCHSIA = reinterpret_cast<PFN_vkGetMemoryZirconHandleFUCHSIA>(366vkGetInstanceProcAddr(mInstance, "vkGetMemoryZirconHandleFUCHSIA"));367ASSERT(!mHasExternalMemoryFuchsia || vkGetMemoryZirconHandleFUCHSIA);368vkGetSemaphoreZirconHandleFUCHSIA = reinterpret_cast<PFN_vkGetSemaphoreZirconHandleFUCHSIA>(369vkGetInstanceProcAddr(mInstance, "vkGetSemaphoreZirconHandleFUCHSIA"));370ASSERT(!mHasExternalSemaphoreFuchsia || vkGetSemaphoreZirconHandleFUCHSIA);371}372373bool VulkanExternalHelper::canCreateImageExternal(374VkFormat format,375VkImageType type,376VkImageTiling tiling,377VkImageCreateFlags createFlags,378VkImageUsageFlags usageFlags,379VkExternalMemoryHandleTypeFlagBits handleType) const380{381VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo = {382/* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,383/* .pNext = */ nullptr,384/* .handleType = */ handleType,385};386387VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {388/* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,389/* .pNext = */ &externalImageFormatInfo,390/* .format = */ format,391/* .type = */ type,392/* .tiling = */ tiling,393/* .usage = */ usageFlags,394/* .flags = */ createFlags,395};396397VkExternalImageFormatProperties externalImageFormatProperties = {398/* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,399/* .pNext = */ nullptr,400};401402VkImageFormatProperties2 imageFormatProperties = {403/* .sType = */ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,404/* .pNext = */ &externalImageFormatProperties};405406VkResult result = vkGetPhysicalDeviceImageFormatProperties2(mPhysicalDevice, &imageFormatInfo,407&imageFormatProperties);408if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)409{410return false;411}412413ASSERT(result == VK_SUCCESS);414415constexpr VkExternalMemoryFeatureFlags kRequiredFeatures =416VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;417if ((externalImageFormatProperties.externalMemoryProperties.externalMemoryFeatures &418kRequiredFeatures) != kRequiredFeatures)419{420return false;421}422423return true;424}425426// TODO: Deduplicate function from renderer_utils http://anglebug.com/5281427VkFormat ConvertToSRGB(VkFormat format)428{429switch (format)430{431case VK_FORMAT_R8G8B8A8_UNORM:432return VK_FORMAT_R8G8B8A8_SRGB;433case VK_FORMAT_B8G8R8A8_UNORM:434return VK_FORMAT_B8G8R8A8_SRGB;435case VK_FORMAT_R8_UNORM:436return VK_FORMAT_R8_SRGB;437case VK_FORMAT_R8G8_UNORM:438return VK_FORMAT_R8G8_SRGB;439default:440return VK_FORMAT_UNDEFINED;441}442}443444// TODO: Deduplicate function from RendererVk http://anglebug.com/5281445bool HaveSameFormatFeatureBits(VkPhysicalDevice physicalDevice, VkFormat format1, VkFormat format2)446{447if (format1 == VK_FORMAT_UNDEFINED || format2 == VK_FORMAT_UNDEFINED)448{449return false;450}451452constexpr VkFormatFeatureFlags kImageUsageFeatureBits =453VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |454VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;455456VkFormatProperties format1Properties = {};457vkGetPhysicalDeviceFormatProperties(physicalDevice, format1, &format1Properties);458459VkFormatProperties format2Properties = {};460vkGetPhysicalDeviceFormatProperties(physicalDevice, format2, &format2Properties);461462VkFormatFeatureFlags fmt1LinearFeatureBits =463format1Properties.linearTilingFeatures & kImageUsageFeatureBits;464VkFormatFeatureFlags fmt2LinearFeatureBits =465format2Properties.linearTilingFeatures & fmt1LinearFeatureBits;466bool sameLinearBits = (fmt2LinearFeatureBits & fmt1LinearFeatureBits) == fmt1LinearFeatureBits;467468VkFormatFeatureFlags fmt1OptimalFeatureBits =469format1Properties.optimalTilingFeatures & kImageUsageFeatureBits;470VkFormatFeatureFlags fmt2OptimalFeatureBits =471format2Properties.optimalTilingFeatures & fmt1OptimalFeatureBits;472bool sameOptimalBits =473(fmt2OptimalFeatureBits & fmt1OptimalFeatureBits) == fmt1OptimalFeatureBits;474475return sameLinearBits && sameOptimalBits;476}477478VkResult VulkanExternalHelper::createImage2DExternal(VkFormat format,479VkImageCreateFlags createFlags,480VkImageUsageFlags usageFlags,481VkExtent3D extent,482VkExternalMemoryHandleTypeFlags handleTypes,483VkImage *imageOut,484VkDeviceMemory *deviceMemoryOut,485VkDeviceSize *deviceMemorySizeOut)486{487VkExternalMemoryImageCreateInfoKHR externalMemoryImageCreateInfo = {488/* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,489/* .pNext = */ nullptr,490/* .handleTypes = */ handleTypes,491};492493// Use the VK_KHR_image_format_list extension to match VkImageCreateInfo in vk_helpers494constexpr uint32_t kImageListFormatCount = 2;495VkFormat imageListFormats[kImageListFormatCount] = {format, ConvertToSRGB(format)};496bool imageFormatListEnabled = false;497VkImageFormatListCreateInfoKHR imageFormatListInfo = {};498499if (HaveSameFormatFeatureBits(mPhysicalDevice, format, ConvertToSRGB(format)))500{501imageFormatListEnabled = true;502503// Add VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT to VkImage create flag504createFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;505506// There is just 1 additional format we might use to create a VkImageView for this507// VkImage508imageFormatListInfo.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;509imageFormatListInfo.pNext = &externalMemoryImageCreateInfo;510imageFormatListInfo.viewFormatCount = kImageListFormatCount;511imageFormatListInfo.pViewFormats = imageListFormats;512}513514VkImageCreateInfo imageCreateInfo = {515/* .sType = */ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,516/* .pNext = */517(imageFormatListEnabled) ? static_cast<const void *>(&imageFormatListInfo)518: static_cast<const void *>(&externalMemoryImageCreateInfo),519/* .flags = */ createFlags,520/* .imageType = */ VK_IMAGE_TYPE_2D,521/* .format = */ format,522/* .extent = */ extent,523/* .mipLevels = */ 1,524/* .arrayLayers = */ 1,525/* .samples = */ VK_SAMPLE_COUNT_1_BIT,526/* .tiling = */ VK_IMAGE_TILING_OPTIMAL,527/* .usage = */ usageFlags,528/* .sharingMode = */ VK_SHARING_MODE_EXCLUSIVE,529/* .queueFamilyIndexCount = */ 0,530/* .pQueueFamilyIndices = */ nullptr,531/* initialLayout = */ VK_IMAGE_LAYOUT_UNDEFINED,532};533534VkImage image = VK_NULL_HANDLE;535VkResult result = vkCreateImage(mDevice, &imageCreateInfo, nullptr, &image);536if (result != VK_SUCCESS)537{538return result;539}540541VkMemoryPropertyFlags requestedMemoryPropertyFlags = 0;542VkMemoryRequirements memoryRequirements;543vkGetImageMemoryRequirements(mDevice, image, &memoryRequirements);544uint32_t memoryTypeIndex = FindMemoryType(mMemoryProperties, memoryRequirements.memoryTypeBits,545requestedMemoryPropertyFlags);546ASSERT(memoryTypeIndex != UINT32_MAX);547VkDeviceSize deviceMemorySize = memoryRequirements.size;548549VkExportMemoryAllocateInfo exportMemoryAllocateInfo = {550/* .sType = */ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,551/* .pNext = */ nullptr,552/* .handleTypes = */ handleTypes,553};554VkMemoryDedicatedAllocateInfoKHR memoryDedicatedAllocateInfo = {555/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,556/* .pNext = */ &exportMemoryAllocateInfo,557/* .image = */ image,558};559VkMemoryAllocateInfo memoryAllocateInfo = {560/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,561/* .pNext = */ &memoryDedicatedAllocateInfo,562/* .allocationSize = */ deviceMemorySize,563/* .memoryTypeIndex = */ memoryTypeIndex,564};565566VkDeviceMemory deviceMemory = VK_NULL_HANDLE;567result = vkAllocateMemory(mDevice, &memoryAllocateInfo, nullptr, &deviceMemory);568if (result != VK_SUCCESS)569{570vkDestroyImage(mDevice, image, nullptr);571return result;572}573574VkDeviceSize memoryOffset = 0;575result = vkBindImageMemory(mDevice, image, deviceMemory, memoryOffset);576if (result != VK_SUCCESS)577{578vkFreeMemory(mDevice, deviceMemory, nullptr);579vkDestroyImage(mDevice, image, nullptr);580return result;581}582583*imageOut = image;584*deviceMemoryOut = deviceMemory;585*deviceMemorySizeOut = deviceMemorySize;586587return VK_SUCCESS;588}589590bool VulkanExternalHelper::canCreateImageOpaqueFd(VkFormat format,591VkImageType type,592VkImageTiling tiling,593VkImageCreateFlags createFlags,594VkImageUsageFlags usageFlags) const595{596if (!mHasExternalMemoryFd)597{598return false;599}600601return canCreateImageExternal(format, type, tiling, createFlags, usageFlags,602VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);603}604605VkResult VulkanExternalHelper::createImage2DOpaqueFd(VkFormat format,606VkImageCreateFlags createFlags,607VkImageUsageFlags usageFlags,608VkExtent3D extent,609VkImage *imageOut,610VkDeviceMemory *deviceMemoryOut,611VkDeviceSize *deviceMemorySizeOut)612{613return createImage2DExternal(format, createFlags, usageFlags, extent,614VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, imageOut,615deviceMemoryOut, deviceMemorySizeOut);616}617618VkResult VulkanExternalHelper::exportMemoryOpaqueFd(VkDeviceMemory deviceMemory, int *fd)619{620VkMemoryGetFdInfoKHR memoryGetFdInfo = {621/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,622/* .pNext = */ nullptr,623/* .memory = */ deviceMemory,624/* .handleType = */ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,625};626627return vkGetMemoryFdKHR(mDevice, &memoryGetFdInfo, fd);628}629630bool VulkanExternalHelper::canCreateImageZirconVmo(VkFormat format,631VkImageType type,632VkImageTiling tiling,633VkImageCreateFlags createFlags,634VkImageUsageFlags usageFlags) const635{636if (!mHasExternalMemoryFuchsia)637{638return false;639}640641return canCreateImageExternal(format, type, tiling, createFlags, usageFlags,642VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA);643}644645VkResult VulkanExternalHelper::createImage2DZirconVmo(VkFormat format,646VkImageCreateFlags createFlags,647VkImageUsageFlags usageFlags,648VkExtent3D extent,649VkImage *imageOut,650VkDeviceMemory *deviceMemoryOut,651VkDeviceSize *deviceMemorySizeOut)652{653return createImage2DExternal(format, createFlags, usageFlags, extent,654VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA, imageOut,655deviceMemoryOut, deviceMemorySizeOut);656}657658VkResult VulkanExternalHelper::exportMemoryZirconVmo(VkDeviceMemory deviceMemory, zx_handle_t *vmo)659{660VkMemoryGetZirconHandleInfoFUCHSIA memoryGetZirconHandleInfo = {661/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA,662/* .pNext = */ nullptr,663/* .memory = */ deviceMemory,664/* .handleType = */ VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA,665};666667return vkGetMemoryZirconHandleFUCHSIA(mDevice, &memoryGetZirconHandleInfo, vmo);668}669670bool VulkanExternalHelper::canCreateSemaphoreOpaqueFd() const671{672if (!mHasExternalSemaphoreFd || !vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)673{674return false;675}676677VkPhysicalDeviceExternalSemaphoreInfo externalSemaphoreInfo = {678/* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,679/* .pNext = */ nullptr,680/* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,681};682683VkExternalSemaphoreProperties externalSemaphoreProperties = {684/* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,685};686vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(mPhysicalDevice, &externalSemaphoreInfo,687&externalSemaphoreProperties);688689constexpr VkExternalSemaphoreFeatureFlags kRequiredFeatures =690VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;691692if ((externalSemaphoreProperties.externalSemaphoreFeatures & kRequiredFeatures) !=693kRequiredFeatures)694{695return false;696}697698return true;699}700701VkResult VulkanExternalHelper::createSemaphoreOpaqueFd(VkSemaphore *semaphore)702{703VkExportSemaphoreCreateInfo exportSemaphoreCreateInfo = {704/* .sType = */ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,705/* .pNext = */ nullptr,706/* .handleTypes = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,707};708709VkSemaphoreCreateInfo semaphoreCreateInfo = {710/* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,711/* .pNext = */ &exportSemaphoreCreateInfo,712/* .flags = */ 0,713};714715return vkCreateSemaphore(mDevice, &semaphoreCreateInfo, nullptr, semaphore);716}717718VkResult VulkanExternalHelper::exportSemaphoreOpaqueFd(VkSemaphore semaphore, int *fd)719{720VkSemaphoreGetFdInfoKHR semaphoreGetFdInfo = {721/* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,722/* .pNext = */ nullptr,723/* .semaphore = */ semaphore,724/* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,725};726727return vkGetSemaphoreFdKHR(mDevice, &semaphoreGetFdInfo, fd);728}729730bool VulkanExternalHelper::canCreateSemaphoreZirconEvent() const731{732if (!mHasExternalSemaphoreFuchsia || !vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)733{734return false;735}736737VkPhysicalDeviceExternalSemaphoreInfo externalSemaphoreInfo = {738/* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,739/* .pNext = */ nullptr,740/* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,741};742743VkExternalSemaphoreProperties externalSemaphoreProperties = {744/* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,745};746vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(mPhysicalDevice, &externalSemaphoreInfo,747&externalSemaphoreProperties);748749constexpr VkExternalSemaphoreFeatureFlags kRequiredFeatures =750VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;751752if ((externalSemaphoreProperties.externalSemaphoreFeatures & kRequiredFeatures) !=753kRequiredFeatures)754{755return false;756}757758return true;759}760761VkResult VulkanExternalHelper::createSemaphoreZirconEvent(VkSemaphore *semaphore)762{763VkExportSemaphoreCreateInfo exportSemaphoreCreateInfo = {764/* .sType = */ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,765/* .pNext = */ nullptr,766/* .handleTypes = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,767};768769VkSemaphoreCreateInfo semaphoreCreateInfo = {770/* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,771/* .pNext = */ &exportSemaphoreCreateInfo,772/* .flags = */ 0,773};774775return vkCreateSemaphore(mDevice, &semaphoreCreateInfo, nullptr, semaphore);776}777778VkResult VulkanExternalHelper::exportSemaphoreZirconEvent(VkSemaphore semaphore, zx_handle_t *event)779{780VkSemaphoreGetZirconHandleInfoFUCHSIA semaphoreGetZirconHandleInfo = {781/* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA,782/* .pNext = */ nullptr,783/* .semaphore = */ semaphore,784/* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA,785};786787return vkGetSemaphoreZirconHandleFUCHSIA(mDevice, &semaphoreGetZirconHandleInfo, event);788}789790void VulkanExternalHelper::releaseImageAndSignalSemaphore(VkImage image,791VkImageLayout oldLayout,792VkImageLayout newLayout,793VkSemaphore semaphore)794{795VkResult result;796797VkCommandBuffer commandBuffers[] = {VK_NULL_HANDLE};798constexpr uint32_t commandBufferCount = std::extent<decltype(commandBuffers)>();799VkCommandBufferAllocateInfo commandBufferAllocateInfo = {800/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,801/* .pNext = */ nullptr,802/* .commandPool = */ mCommandPool,803/* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,804/* .commandBufferCount = */ commandBufferCount,805};806807result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);808ASSERT(result == VK_SUCCESS);809810VkCommandBufferBeginInfo commandBufferBeginInfo = {811/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,812/* .pNext = */ nullptr,813/* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,814/* .pInheritanceInfo = */ nullptr,815};816result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);817ASSERT(result == VK_SUCCESS);818819ImageMemoryBarrier(commandBuffers[0], image, mGraphicsQueueFamilyIndex,820VK_QUEUE_FAMILY_EXTERNAL, oldLayout, newLayout);821822result = vkEndCommandBuffer(commandBuffers[0]);823ASSERT(result == VK_SUCCESS);824825const VkSemaphore signalSemaphores[] = {826semaphore,827};828constexpr uint32_t signalSemaphoreCount = std::extent<decltype(signalSemaphores)>();829830const VkSubmitInfo submits[] = {831/* [0] = */ {832/* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,833/* .pNext = */ nullptr,834/* .waitSemaphoreCount = */ 0,835/* .pWaitSemaphores = */ nullptr,836/* .pWaitDstStageMask = */ nullptr,837/* .commandBufferCount = */ commandBufferCount,838/* .pCommandBuffers = */ commandBuffers,839/* .signalSemaphoreCount = */ signalSemaphoreCount,840/* .pSignalSemaphores = */ signalSemaphores,841},842};843constexpr uint32_t submitCount = std::extent<decltype(submits)>();844845const VkFence fence = VK_NULL_HANDLE;846result = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);847ASSERT(result == VK_SUCCESS);848}849850void VulkanExternalHelper::waitSemaphoreAndAcquireImage(VkImage image,851VkImageLayout oldLayout,852VkImageLayout newLayout,853VkSemaphore semaphore)854{855VkResult result;856857VkCommandBuffer commandBuffers[] = {VK_NULL_HANDLE};858constexpr uint32_t commandBufferCount = std::extent<decltype(commandBuffers)>();859VkCommandBufferAllocateInfo commandBufferAllocateInfo = {860/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,861/* .pNext = */ nullptr,862/* .commandPool = */ mCommandPool,863/* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,864/* .commandBufferCount = */ commandBufferCount,865};866867result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);868ASSERT(result == VK_SUCCESS);869870VkCommandBufferBeginInfo commandBufferBeginInfo = {871/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,872/* .pNext = */ nullptr,873/* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,874/* .pInheritanceInfo = */ nullptr,875};876result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);877ASSERT(result == VK_SUCCESS);878879ImageMemoryBarrier(commandBuffers[0], image, VK_QUEUE_FAMILY_EXTERNAL,880mGraphicsQueueFamilyIndex, oldLayout, newLayout);881882result = vkEndCommandBuffer(commandBuffers[0]);883ASSERT(result == VK_SUCCESS);884885const VkSemaphore waitSemaphores[] = {886semaphore,887};888const VkPipelineStageFlags waitDstStageMasks[] = {889VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,890};891constexpr uint32_t waitSemaphoreCount = std::extent<decltype(waitSemaphores)>();892constexpr uint32_t waitDstStageMaskCount = std::extent<decltype(waitDstStageMasks)>();893static_assert(waitSemaphoreCount == waitDstStageMaskCount,894"waitSemaphores and waitDstStageMasks must be the same length");895896const VkSubmitInfo submits[] = {897/* [0] = */ {898/* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,899/* .pNext = */ nullptr,900/* .waitSemaphoreCount = */ waitSemaphoreCount,901/* .pWaitSemaphores = */ waitSemaphores,902/* .pWaitDstStageMask = */ waitDstStageMasks,903/* .commandBufferCount = */ commandBufferCount,904/* .pCommandBuffers = */ commandBuffers,905/* .signalSemaphoreCount = */ 0,906/* .pSignalSemaphores = */ nullptr,907},908};909constexpr uint32_t submitCount = std::extent<decltype(submits)>();910911const VkFence fence = VK_NULL_HANDLE;912result = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);913ASSERT(result == VK_SUCCESS);914}915916void VulkanExternalHelper::readPixels(VkImage srcImage,917VkImageLayout srcImageLayout,918VkFormat srcImageFormat,919VkOffset3D imageOffset,920VkExtent3D imageExtent,921void *pixels,922size_t pixelsSize)923{924ASSERT(srcImageFormat == VK_FORMAT_B8G8R8A8_UNORM ||925srcImageFormat == VK_FORMAT_R8G8B8A8_UNORM);926ASSERT(imageExtent.depth == 1);927ASSERT(pixelsSize == 4 * imageExtent.width * imageExtent.height);928929VkBufferCreateInfo bufferCreateInfo = {930/* .sType = */ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,931/* .pNext = */ nullptr,932/* .flags = */ 0,933/* .size = */ pixelsSize,934/* .usage = */ VK_BUFFER_USAGE_TRANSFER_DST_BIT,935/* .sharingMode = */ VK_SHARING_MODE_EXCLUSIVE,936/* .queueFamilyIndexCount = */ 0,937/* .pQueueFamilyIndices = */ nullptr,938};939VkBuffer stagingBuffer = VK_NULL_HANDLE;940VkResult result = vkCreateBuffer(mDevice, &bufferCreateInfo, nullptr, &stagingBuffer);941ASSERT(result == VK_SUCCESS);942943VkMemoryPropertyFlags requestedMemoryPropertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;944VkMemoryRequirements memoryRequirements;945vkGetBufferMemoryRequirements(mDevice, stagingBuffer, &memoryRequirements);946uint32_t memoryTypeIndex = FindMemoryType(mMemoryProperties, memoryRequirements.memoryTypeBits,947requestedMemoryPropertyFlags);948ASSERT(memoryTypeIndex != UINT32_MAX);949VkDeviceSize deviceMemorySize = memoryRequirements.size;950951VkMemoryDedicatedAllocateInfoKHR memoryDedicatedAllocateInfo = {952/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,953/* .pNext = */ nullptr,954/* .image = */ VK_NULL_HANDLE,955/* .buffer = */ stagingBuffer,956};957VkMemoryAllocateInfo memoryAllocateInfo = {958/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,959/* .pNext = */ &memoryDedicatedAllocateInfo,960/* .allocationSize = */ deviceMemorySize,961/* .memoryTypeIndex = */ memoryTypeIndex,962};963964VkDeviceMemory deviceMemory = VK_NULL_HANDLE;965result = vkAllocateMemory(mDevice, &memoryAllocateInfo, nullptr, &deviceMemory);966ASSERT(result == VK_SUCCESS);967968result = vkBindBufferMemory(mDevice, stagingBuffer, deviceMemory, 0 /* memoryOffset */);969ASSERT(result == VK_SUCCESS);970971VkCommandBuffer commandBuffers[] = {VK_NULL_HANDLE};972constexpr uint32_t commandBufferCount = std::extent<decltype(commandBuffers)>();973VkCommandBufferAllocateInfo commandBufferAllocateInfo = {974/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,975/* .pNext = */ nullptr,976/* .commandPool = */ mCommandPool,977/* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,978/* .commandBufferCount = */ commandBufferCount,979};980981result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);982ASSERT(result == VK_SUCCESS);983984VkCommandBufferBeginInfo commandBufferBeginInfo = {985/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,986/* .pNext = */ nullptr,987/* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,988/* .pInheritanceInfo = */ nullptr,989};990result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);991ASSERT(result == VK_SUCCESS);992993VkBufferImageCopy bufferImageCopies[] = {994/* [0] = */ {995/* .bufferOffset = */ 0,996/* .bufferRowLength = */ 0,997/* .bufferImageHeight = */ 0,998/* .imageSubresources = */999{1000/* .aspectMask = */ VK_IMAGE_ASPECT_COLOR_BIT,1001/* .mipLevel = */ 0,1002/* .baseArrayLayer = */ 0,1003/* .layerCount = */ 1,1004},1005/* .imageOffset = */ imageOffset,1006/* .imageExtent = */ imageExtent,1007},1008};1009constexpr uint32_t bufferImageCopyCount = std::extent<decltype(bufferImageCopies)>();10101011vkCmdCopyImageToBuffer(commandBuffers[0], srcImage, srcImageLayout, stagingBuffer,1012bufferImageCopyCount, bufferImageCopies);10131014VkMemoryBarrier memoryBarriers[] = {1015/* [0] = */ {/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_BARRIER,1016/* .pNext = */ nullptr,1017/* .srcAccessMask = */ VK_ACCESS_MEMORY_WRITE_BIT,1018/* .dstAccessMask = */ VK_ACCESS_HOST_READ_BIT},1019};1020constexpr uint32_t memoryBarrierCount = std::extent<decltype(memoryBarriers)>();1021vkCmdPipelineBarrier(commandBuffers[0], VK_PIPELINE_STAGE_TRANSFER_BIT,1022VK_PIPELINE_STAGE_HOST_BIT, 0 /* dependencyFlags */, memoryBarrierCount,1023memoryBarriers, 0, nullptr, 0, nullptr);10241025result = vkEndCommandBuffer(commandBuffers[0]);1026ASSERT(result == VK_SUCCESS);10271028const VkSubmitInfo submits[] = {1029/* [0] = */ {1030/* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,1031/* .pNext = */ nullptr,1032/* .waitSemaphoreCount = */ 0,1033/* .pWaitSemaphores = */ nullptr,1034/* .pWaitDstStageMask = */ nullptr,1035/* .commandBufferCount = */ commandBufferCount,1036/* .pCommandBuffers = */ commandBuffers,1037/* .signalSemaphoreCount = */ 0,1038/* .pSignalSemaphores = */ nullptr,1039},1040};1041constexpr uint32_t submitCount = std::extent<decltype(submits)>();10421043const VkFence fence = VK_NULL_HANDLE;1044result = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);1045ASSERT(result == VK_SUCCESS);10461047result = vkQueueWaitIdle(mGraphicsQueue);1048ASSERT(result == VK_SUCCESS);10491050vkFreeCommandBuffers(mDevice, mCommandPool, commandBufferCount, commandBuffers);10511052void *stagingMemory = nullptr;1053result = vkMapMemory(mDevice, deviceMemory, 0 /* offset */, deviceMemorySize, 0 /* flags */,1054&stagingMemory);1055ASSERT(result == VK_SUCCESS);10561057VkMappedMemoryRange memoryRanges[] = {1058/* [0] = */ {1059/* .sType = */ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,1060/* .pNext = */ nullptr,1061/* .memory = */ deviceMemory,1062/* .offset = */ 0,1063/* .size = */ deviceMemorySize,1064},1065};1066constexpr uint32_t memoryRangeCount = std::extent<decltype(memoryRanges)>();10671068result = vkInvalidateMappedMemoryRanges(mDevice, memoryRangeCount, memoryRanges);1069ASSERT(result == VK_SUCCESS);10701071memcpy(pixels, stagingMemory, pixelsSize);10721073vkUnmapMemory(mDevice, deviceMemory);1074vkFreeMemory(mDevice, deviceMemory, nullptr);1075vkDestroyBuffer(mDevice, stagingBuffer, nullptr);1076}10771078} // namespace angle107910801081