VkWriteDescriptorSet内存堆释放问题

Vulkan更新描述符集信息时需要填写VkWriteDescriptorSet结构体,然后调用vkUpdateDescriptorSets将其推送到GPU端。

创建VkWriteDescriptorSet时,一定要确保该VkWriteDescriptorSet与vkUpdateDescriptorSets调用位于同一个作用域!!

这里的同一个作用域,是指位于同一个函数作用域!!存在类成员变量中都不可以!!

举个例子:

假设有一个VulkanDescriptorFactory的工厂类,里面缓存了VkWriteDescriptorSet成员变量,假如在Add函数中添加对应的VkWriteDescriptorSet,在Build函数中构建DescriptorSet:

class VulkanDescriptorFactory
{
    std::vector<VkWriteDescriptorSet> mWrite{ };   
public:
    void Add()
    {
        VkWriteDescriptorSet newWrite{};
        // ...
        mWrite.push_back(newWtire);
    }
    
    void Build()
    {
        // ...
        vkUpdateDescriptorSets(*mAllocator->device,static_cast<uint32_t>(mWrite.size()),mWrite.data(),0,nullptr);
    }
}

理论上看上去没什么毛病,但实际运行起来,Visual Studio会把mWrite中除了最后一项的所有VkWriteDescriptorSet中的Buffer Pointer数据都释放掉!也就是说,调用Build时mWrite中除了最后一项,前面的imgeInfo和BufferInfo全部堆内存地址都为0xdddddddddd。

正确的做法应该是在Add的时候用一个中间结构体Cache住VkWriteDescriptorSet的信息,在vkUpdateDescriptorSets前才构建VkWriteDescriptorSet,这样就不会有堆释放的问题了:

struct DescriptorWriteContainer
{
	VkDescriptorImageInfo imgInfo;
	VkDescriptorBufferInfo bufInfo;
	uint32 binding;
	VkDescriptorType type;
	bool isImg = false;
};

void Add()
{
    // ...
    DescriptorWriteContainer descriptorWrite{};
    descriptorWrite.isImg = false;
    descriptorWrite.bufInfo = *bufferInfo;
    descriptorWrite.type = type;
    descriptorWrite.binding = binding;
    mDescriptorWriteBufInfos.push_back(descriptorWrite);
    
    // ...
}

void Build()
{
	std::vector<VkWriteDescriptorSet> writes{};
    for(auto& dc : mDescriptorWriteBufInfos)
    {
        VkWriteDescriptorSet newWrite{};
        newWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
        newWrite.pNext = nullptr;
        newWrite.descriptorCount = 1;

        newWrite.descriptorType = dc.type;

        if(dc.isImg)
            newWrite.pImageInfo = &dc.imgInfo;
        else
            newWrite.pBufferInfo = &dc.bufInfo;

        newWrite.dstBinding = dc.binding;
        newWrite.dstSet = *set;
        writes.push_back(newWrite);
    }

    vkUpdateDescriptorSets(*mAllocator->device,static_cast<uint32_t>(writes.size()),writes.data(),0,nullptr);
    return true;
}
© - 2024 · 月光下的旅行。 禁止转载