为什么删除缓冲区会导致错误,而重新创建则不会? (伏尔甘)

问题描述 投票:0回答:1

我想添加功能,该功能将从场景中删除网格,因此我尝试在场景运行时删除 vk::Buffer 和 vk::Memory 。每当顶点数据为 nullptr 时,缓冲区的重新创建会导致错误:“无法在命令缓冲区当前正在使用的 VkDeviceMemory 上调用 vkFreeMemory。”。但是,当顶点数据包含某些内容时,就不会出现错误。只有当我在重新创建之前调用transferQueue.waitIdle()或device.waitIdle()时,错误才会消失。

娱乐伪代码:

auto temp = m_Buffer;

m_Buffer = Buffer(...);

temp.Cleanup(...);

缓冲区代码:


    void CopyBuffer(

        const vk::Buffer& srcBuffer,

        const vk::Buffer& dstBuffer,

        const vk::DeviceSize& size,

        const vk::Device& device,

        const vk::CommandPool& transferPool,

        const vk::Queue& transferQueue

    )

    {

        const vk::CommandBufferAllocateInfo allocInfo(

            transferPool,

            vk::CommandBufferLevel::ePrimary,

            1

        );



        const auto cBuffer = device.allocateCommandBuffers(allocInfo)[0];



        const vk::CommandBufferBeginInfo beginInfo{vk::CommandBufferUsageFlagBits::eOneTimeSubmit};

        GE_ASSERT_FN(cBuffer.begin(&beginInfo) == vk::Result::eSuccess, "cannot begin command buffer when copying buffer");



        const vk::BufferCopy copy{0, 0, size};

        cBuffer.copyBuffer(srcBuffer, dstBuffer, 1, &copy);

        cBuffer.end();



        vk::SubmitInfo submitInfo{};

        submitInfo.commandBufferCount = 1;

        submitInfo.pCommandBuffers = &cBuffer;



        GE_ASSERT_FN(transferQueue.submit(1, &submitInfo, nullptr) == vk::Result::eSuccess, "cannot submit on transfer queue");

        transferQueue.waitIdle();



        device.freeCommandBuffers(transferPool, 1, &cBuffer);

    }

    VertexBuffer::VertexBuffer(

        const vk::Device& device,

        const vk::PhysicalDevice& physicalDevice,

        const QueueFamilyIndices& queueFamilyIndices,

        const vk::CommandPool& transferPool,

        const vk::Queue& transferQueue,

        const void* data,

        const uint& sizeOfAllData

    )

    {

        m_Size = sizeOfAllData;

        if(m_Size)

        {

            vk::BufferCreateInfo info{ vk::BufferCreateFlagBits(),

                sizeOfAllData,

                vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eTransferDst

            };



            if(queueFamilyIndices.GetGraphicsFamily() != queueFamilyIndices.GetTransferFamily())

            {

                const uint uniqueIndices[] = { queueFamilyIndices.GetGraphicsFamily(), queueFamilyIndices.GetTransferFamily() };

                info.queueFamilyIndexCount = 2;

                info.pQueueFamilyIndices = uniqueIndices;

                info.sharingMode = vk::SharingMode::eConcurrent;

            }

            else

                info.sharingMode = vk::SharingMode::eExclusive;



            m_Buffer = device.createBuffer(info);



            const auto memRequirements = device.getBufferMemoryRequirements(m_Buffer);



            vk::MemoryAllocateInfo allocInfo{

                memRequirements.size,

                    IBuffer::FindMemoryType(

                        physicalDevice,

                        memRequirements.memoryTypeBits,

                        vk::MemoryPropertyFlagBits::eDeviceLocal

                    )

            };



            m_BufferMemory = device.allocateMemory(allocInfo);

            device.bindBufferMemory(m_Buffer, m_BufferMemory, 0);



            const auto stagingBuffer = StagingBuffer(device, physicalDevice, queueFamilyIndices, data, sizeOfAllData);

            CopyBuffer(stagingBuffer.GetBuffer(), m_Buffer, m_Size, device, transferPool, transferQueue);

            stagingBuffer.Cleanup(device);

        }

    }

暂存缓冲区代码:

    class StagingBuffer : public IBuffer
    {
    public:
        StagingBuffer(const vk::Device& device, const vk::PhysicalDevice& physicalDevice, const QueueFamilyIndices& indices, const void* data, const uint& sizeOfAllData)
        {
            m_Size = sizeOfAllData;
            if(m_Size)
            {
                vk::BufferCreateInfo info{vk::BufferCreateFlagBits(),
                    m_Size,
                    vk::BufferUsageFlagBits::eTransferSrc
                };

                if(indices.GetGraphicsFamily() != indices.GetTransferFamily())
                {
                    const uint uniqueIndices[] = { indices.GetGraphicsFamily(), indices.GetTransferFamily() };
                    info.queueFamilyIndexCount = 2;
                    info.pQueueFamilyIndices = uniqueIndices;
                    info.sharingMode = vk::SharingMode::eConcurrent;
                }
                else
                    info.sharingMode = vk::SharingMode::eExclusive;

                m_Buffer = device.createBuffer(info);

                const auto memRequirements = device.getBufferMemoryRequirements(m_Buffer);

                const vk::MemoryAllocateInfo allocInfo{
                    memRequirements.size,
                        IBuffer::FindMemoryType(
                            physicalDevice,
                            memRequirements.memoryTypeBits,
                            vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent
                        )
                };

                m_BufferMemory = device.allocateMemory(allocInfo);
                device.bindBufferMemory(m_Buffer, m_BufferMemory, 0);

                void* memdata = device.mapMemory(m_BufferMemory, 0, info.size);
                memcpy(memdata, data, info.size);
                device.unmapMemory(m_BufferMemory);
            }
        }
        StagingBuffer(const StagingBuffer& other)
        {
            m_Buffer = other.m_Buffer;
            m_BufferMemory = other.m_BufferMemory;
            m_Size = other.m_Size;
        }
        StagingBuffer& operator=(const StagingBuffer& other)
        {
            if(this == &other)
                return *this;

            m_Buffer = other.m_Buffer;
            m_BufferMemory = other.m_BufferMemory;
            m_Size = other.m_Size;

            return *this;
        }
        StagingBuffer(StagingBuffer&& other) noexcept
        {
            m_Buffer = other.m_Buffer;
            m_BufferMemory = other.m_BufferMemory;
            m_Size = other.m_Size;

            other.Reset();
        }
        StagingBuffer& operator=(StagingBuffer&& other) noexcept
        {
            m_Buffer = other.m_Buffer;
            m_BufferMemory = other.m_BufferMemory;
            m_Size = other.m_Size;

            other.Reset();

            return *this;
        }
    };

那么,为什么只有当顶点数据为 nullptr 时才会抛出错误?

c++ vulkan
1个回答
0
投票

验证错误表明您正在删除正在使用的 vkBuffer。

所以我认为正确的方法是在记录命令缓冲区之后或之前删除 vkBuffer,无论您的缓冲区数据是什么。

只要把事情说清楚即可。

© www.soinside.com 2019 - 2024. All rights reserved.