std::pair VulkanUtil::allocate()

in Cthulhu/src/VulkanUtil.cpp [266:349]


std::pair<uint64_t, uint32_t> VulkanUtil::allocate(uint32_t nrBytes, bool deviceLocal) {
#ifdef CTHULHU_HAS_VULKAN
  if (!isActive_) {
    return {0, 0};
  }

  // Create a buffer, just to get memory requirements
  VkBufferCreateInfo bufferCreateInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
  bufferCreateInfo.size = nrBytes;
  bufferCreateInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;

  // Enable export
  VkExternalMemoryBufferCreateInfo infoEx{VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO};
#ifdef _WIN32
  infoEx.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
#else
  infoEx.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
#endif
  bufferCreateInfo.pNext = &infoEx;

  VkBuffer buffer;
  if (vkCreateBuffer(state_->device, &bufferCreateInfo, nullptr, &buffer) != VK_SUCCESS) {
    XR_LOGW("Failed to allocate Vulkan buffer");
    return {0, 0};
  }

  // Require host visible, coherent memory
  VkMemoryRequirements memReqs;
  vkGetBufferMemoryRequirements(state_->device, buffer, &memReqs);
  VkExportMemoryAllocateInfoKHR vulkanExportMemoryAllocateInfoKHR = {};
  vulkanExportMemoryAllocateInfoKHR.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
  vulkanExportMemoryAllocateInfoKHR.pNext = nullptr;
#ifdef _WIN32
  vulkanExportMemoryAllocateInfoKHR.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
#else
  vulkanExportMemoryAllocateInfoKHR.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
#endif

  VkMemoryAllocateInfo allocateInfo = {};
  allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  allocateInfo.pNext = &vulkanExportMemoryAllocateInfoKHR;
  allocateInfo.allocationSize = memReqs.size;
  VkFlags required, preferred, preferredNot;
  if (deviceLocal) {
    required = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
    preferred = 0;
    preferredNot = 0;
  } else {
    required = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
    preferred = VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
    preferredNot = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
  }
  allocateInfo.memoryTypeIndex = findMemoryTypeIndex(
      state_->memoryProperties, memReqs.memoryTypeBits, required, preferred, preferredNot);

  // Allocate the memory
  VkDeviceMemory bufferMemory;
  if (vkAllocateMemory(state_->device, &allocateInfo, nullptr, &bufferMemory) != VK_SUCCESS) {
    XR_LOGW("Failed to allocate Vulkan buffer memory!");
    return {0, 0};
  }

  // We no longer need the buffer
  vkDestroyBuffer(state_->device, buffer, nullptr);

#ifdef _WIN32
  VkMemoryGetWin32HandleInfoKHR info = {VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR};
  HANDLE handle{};
  info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
  info.memory = bufferMemory;
  vkGetMemoryWin32HandleKHR(state_->device, &info, &handle);
#else
  VkMemoryGetFdInfoKHR info = {VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR};
  int handle{};
  info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
  info.memory = bufferMemory;
  vkGetMemoryFdKHR(state_->device, &info, &handle);
#endif

  return {(uint64_t)handle, allocateInfo.memoryTypeIndex};
#endif // CTHULHU_HAS_VULKAN
  XR_LOGW("Failed to allocate GPU buffer. Vulkan support was not included in build.");
  return {0, 0};
}