In my current system vulkan info returns these device specs:
memoryHeaps[0]:
size = 8589934592 (0x200000000) (8.00 GiB)
budget = 7826571264 (0x1d2800000) (7.29 GiB)
usage = 0 (0x00000000) (0.00 B)
flags: count = 1
MEMORY_HEAP_DEVICE_LOCAL_BIT
memoryHeaps[1]:
size = 12453414912 (0x2e6480800) (11.60 GiB)
budget = 12453414912 (0x2e6480800) (11.60 GiB)
usage = 0 (0x00000000) (0.00 B)
flags:
None
memoryHeaps[2]:
size = 257949696 (0x0f600000) (246.00 MiB)
budget = 251068416 (0x0ef70000) (239.44 MiB)
usage = 6881280 (0x00690000) (6.56 MiB)
flags: count = 1
MEMORY_HEAP_DEVICE_LOCAL_BIT
In summary, heap 0 good, heap 2 bad.
I am getting a message that massive texture I am allocating runs out of memory:
Message: Validation Error: [ VUID-vkAllocateMemory-pAllocateInfo-01713 ] Object 0: handle = 0x5562fe1c6760, name = Logical device: NVIDIA GeForce GTX 1070, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xe9a2b96f | vkAllocateMemory: attempting to allocate 268435456 bytes from heap 2,but size of that heap is only 257949696 bytes. The Vulkan spec states: pAllocateInfo->allocationSize must be less than or equal to VkPhysicalDeviceMemoryProperties::memoryHeaps[memindex].size where memindex = VkPhysicalDeviceMemoryProperties::memoryTypes[pAllocateInfo->memoryTypeIndex].heapIndex as returned by vkGetPhysicalDeviceMemoryProperties for the VkPhysicalDevice that device was created from (https://vulkan.lunarg.com/doc/view/1.3.211.0/linux/1.3-extensions/vkspec.html#VUID-vkAllocateMemory-pAllocateInfo-01713)
Severity: VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT
So I want to tell VMA to use heap 0, which does have enough capacity to hold my giga texture.
I am trying to allocate like this:
vk::Device& device = h_interface->GetDevice();
const bool is_3D_image = depth > 0;
// Set image creation information.
vk::ImageCreateInfo image_info = {};
image_info.imageType = is_3D_image ? vk::ImageType::e3D : vk::ImageType::e2D;
image_info.format = format;
image_info.extent = vk::Extent3D(width, height, max(uint32_t(1), depth));
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.samples = vk::SampleCountFlagBits::e1;
image_info.tiling = tiling;
image_info.usage = usage;
image_info.sharingMode = vk::SharingMode::eExclusive;
image_info.initialLayout = initial_layout;
VmaAllocationCreateInfo allocation_info = {};
allocation_info.usage = VMA_MEMORY_USAGE_AUTO;
uint32_t memoryTypeIndex = 0;
allocation_info.memoryTypeBits = 0u << memoryTypeIndex;
VmaAllocation allocation;
vk::Image image;
VkResult result = vmaCreateImage(
vma_allocator,
(VkImageCreateInfo*)&image_info,
&allocation_info,
(VkImage*)&image,
&allocation,
nullptr);
I tried changing allocation_info.usage
, I tried changing allocation_info.memoryTypeBits
. I tried setting the device limits to 0 for all but the first heap when creating the VMA structure.
I read this like 3 times: https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/choosing_memory_type.html
I don;t understand how to tell VMA to please allocate from heap 0.
CodePudding user response:
VMA's VmaAllocationCreateInfo structure has a member called memoryTypeBits
. This allows you to supply a set of memory types from which VMA must select an allocation. So you can get the set of memory types from Vulkan and only specify those which use heap 0.
That being said, the fact that this problem happened at all should make you reconsider VMA. Heap 2 is specifically for doing efficient streaming of data to the GPU from the CPU. This is easy enough to determine, as all of the memory types using it are host-visible.
However, unless the image uses linear tiling, you cannot write to the bytes of an image directly. Therefore, VMA has no business whatsoever using a host-visible memory type when other memory types that aren't host-visible are available (unless one of your other flags requires it). If the image was not linearly tiled, and you didn't tell VMA to make sure the memory was host-visible, its algorithm has a flaw that should make you reconsider using it going forward.