【问题标题】:How do you create one buffer to store multiple textures of different sizes in Vulkan如何在 Vulkan 中创建一个缓冲区来存储多个不同大小的纹理
【发布时间】:2020-12-12 21:56:02
【问题描述】:

在我的 Vulkan 应用程序中,我想要一个内存缓冲区来存储多个不同大小的纹理。然后,我想要一个VkImageView 对应于缓冲区中的每个纹理。我不确定如何创建这样的缓冲区,这就是我想出的:

// Create images
VkImage images[TEXTURE_COUNT];
for (int i = 0; i < TEXTURE_COUNT, i++) {
    VkImageCreateInfo imageCreateInfo{};

    // Specific to texture i
    imageCreateInfo.extent.width  = ...
    iamgeCreateInfo.extent.height = ...
    
    // Other imageCreateInfo properties are constant across all textures
    ...

    VkCreateImage(device, &imageCreateInfo, nullptr, &images[i]);
}

// Find total size of memory buffer & image offsets
int totalSize = 0;
int offsets[TEXTURE_COUNT];
for (int i = 0; i < TEXTURE_COUNT; i++) {
    VkMemoryRequirements memoryRequirements;
    vkGetImageMemoryRequirements(device, images[i], &memoryRequirements);
    offsets[i] = totalSize;
    totalSize += memoryRequirements.size;
}

// Get memory type index of memory buffer
VkMemoryRequirements firstImageMemoryRequirements;
vkGetImageMemoryRequirements(device, images[0], &firstImageMemoryRequirements);
int memoryTypeIndex = ... // Get memory type index using firstImageMemoryRequirements.memoryTypeBits

// Allocate memory
VkMemoryAllocateInfo memoryAllocateInfo{};
memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memoryAllocateInfo.allocationSize = totalSize;
memoryAllocateInfo.memoryTypeIndex = memoryTypeIndex;
VkMemory memory;
vkAllocateMemory(device, &memoryAllocateInfo, nullptr, &memory)

// Bind images to memory at corresponding offset
VkBindImageMemoryInfo bindImageMemoryInfos[TEXTURE_COUNT];
for (int i = 0; i < TEXTURE_COUNT, i++) {
    VkBindImageMemoryInfo bindImageMemoryInfo{};
    bindImageMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
    bindImageMemoryInfo.image = images[i];
    bindImageMemoryInfo.memory = memory;
    bindImageMemoryInfo.memoryOffset = offsets[i];
    bindImageMemoryInfos[i] = bindImageMemoryInfo;
}
vkBindImageMemory2(device, TEXTURE_COUNT, &bindImageMemoryInfos);

// Create image views
VkImageView imageViews[TEXTURE_COUNT];
for (int i = 0; i < TEXTURE_COUNT; i++) {
    VkImageViewCreateInfo imageViewCreateInfo{};
    imageViewCreateInfo.image = images[i];
    ...

    VkCreateImageView(device, &imageViewCreateInfo, nullptr, &imageViews[i]);
}

// Now I have a bunch of image views tied to each texture,
// where each texture is stored in one memory buffer at a certain offset.

这看起来是否合理,或者这不是正确的方法?对我来说似乎有点奇怪的一件事是当我获取内存缓冲区的内存类型索引时。为了得到这个,你需要一张我有TEXTURE_COUNT的图像,所以我只选择第一张图像。每个纹理的唯一图像属性是范围宽度和高度,所以我希望这不会影响每个图像的内存类型位。我假设每个图像都将具有相同的内存类型位,因此我可以使用第一个图像的内存类型位来获取内存类型索引。对这个假设的想法也很好。

【问题讨论】:

  • 1.我建议至少检查每个图像是否具有相同的内存类型,只是为了捕捉愚蠢的错误,例如意外在数组中包含不同类型的图像。 2.肯定应该累积偏移数组吗?即offsets[i] = memoryRequirements.size; 行对于第一个元素应该为零,对于第二个元素,该图像的大小,等等?
  • @stridecolossus 对,我的偏移量错了。我已将其更改为offsets[i] = totalSize;,您对检查内存类型以捕获错误提出了很好的意见。
  • 仅供参考:将内存分配称为“缓冲区”并不是一个好主意,因为“缓冲区”一词在 Vulkan 中已经具有非常具体(并且不同)的含义.

标签: memory-management vulkan


【解决方案1】:

对于您使用的每个VkImage,它必须存储在适合该特定VkImage 对象的内存中。这意味着偏移量/大小必须与该图像对象的对齐方式和大小匹配,并且它绑定到的内存类型必须是图像可以使用的内存类型之一。

对于您使用的每个 VkImage 对象,必须独立地查询此内容。或者通常;两个相同的VkImage 对象(即:从相同的VkImageCreateInfo 结构创建)将具有相同的要求,因此如果您重复创建相同的VkImages,则无需再次查询它们的要求。还有一些其他情况允许具有不同创建参数的图像具有相同的要求,因此如果您想利用这一点,您需要查看详细信息。

如果您在一个可以控制图像的大小、格式、使用和其他创建参数的环境中操作,那么您可以提前弄清楚这几种图像的要求是什么,然后工作在这些限制范围内。否则,您将不得不为图像查询需求信息, 分配它们的内存,然后在确切知道需要什么后为它们分配内存。

或者,您可以根据需要在大型平板中分配内存。也就是说,如果您需要为特定的VkImage 分配新的内存(因为最后一个slab 已满或图像需要新的内存类型),那么您分配它的一大块,然后您可以将以后的图像放入相同的存储。这需要您跟踪您在哪些内存块中放入了哪些内容。

您的代码的一个问题是您没有考虑图像的内存对齐要求 (VkMemoryRequirements::alignment)。您也没有考虑并非所有图像都可以共享相同分配的可能性;你假设他们都可以使用相同的内存类型。

因此您需要相应地更改您的代码。

话虽如此,Vulkan 对VkImage 内存要求的实现施加的限制包括一个声明,该声明有效地表示图像所需的内存类型对于所有颜色格式都是相同的,假设许多其他创建参数是一样的。因此,您不应该仅仅因为改变图像大小或拥有不同格式的图像而担心不同的内存类型。

可能会促使您使用不同内存类型的主要是使用参数(以及颜色与深度格式)。打算用作渲染目标的图像可以有自己的内存类型。

【讨论】:

  • “您也没有考虑并非所有图像都可以共享相同分配的可能性;您假设它们都可以使用相同的内存类型。” - 我在代码 sn-p 中有一条评论:“其他 imageCreateInfo 属性在所有纹理中都是不变的”,这意味着所有图像都具有相同的要求,即格式、平铺、用法等。图像是宽度和高度,所以我相信这不是问题,从您的回答来看,它们可以共享相同的内存类型。我本可以更好地传达这一点。感谢您的全面回答。
猜你喜欢
  • 1970-01-01
  • 2019-01-06
  • 2018-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-18
  • 2019-09-22
相关资源
最近更新 更多