Vulkan:呈现

时间:2016-06-28 13:37:36

标签: c++ memory-leaks vulkan

我正在使用vulkan进行简单程序,只是为了开始。我清除背面颜色,这就是它。问题是程序分配越来越多的内存的每一帧,我不知道来自哪里。

bool VulkanRenderer::Update()
{
    PrepareFrame(); ///--- < Commenting this
    SubmitFrame();  ///--- <  and this avoids memory leak
}//Update

这是另外两个函数,当它们未被调用时,程序的内存保持不变。

void VulkanRenderer::PrepareFrame()
{
    ///--- Reset command buffers
    vkResetCommandPool(m_pDevice, m_pCoreCommandPool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);

    VkResult iRes;
    // Get the index of the next available swapchain image:
    iRes=m_oSwapChain.AcquireNextImage(m_oSemaphorePresentReady, &m_uSwapChainImage);
    if(iRes!=VK_SUCCESS){
        CheckVulkanError(iRes);
    }

    ///---------------------------------
    /// Convert image to drawable
    ///---------------------------------
    VkCommandBufferBeginInfo oCmdBegin={};
    oCmdBegin.sType=VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;

    ///---------------------------------
    /// Prepare primary command buffer
    ///---------------------------------
    //vkFreeCommandBuffers(m_pDevice, m_pCoreCommandPool, 1, &m_oPrimaryCmd);
    //m_oPrimaryCmd=CreateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
    vkBeginCommandBuffer(m_oPrimaryCmd, &oCmdBegin);

    {///--- Convert image to drawable
        VkImageMemoryBarrier postPresentBarrier={};
        postPresentBarrier.sType=VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
        postPresentBarrier.srcAccessMask=VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
        postPresentBarrier.dstAccessMask=VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
        postPresentBarrier.oldLayout=VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
        postPresentBarrier.newLayout=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
        postPresentBarrier.srcQueueFamilyIndex=VK_QUEUE_FAMILY_IGNORED;
        postPresentBarrier.dstQueueFamilyIndex=VK_QUEUE_FAMILY_IGNORED;
        postPresentBarrier.subresourceRange={VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
        postPresentBarrier.image=m_oSwapChain.images()[m_uSwapChainImage];
        vkCmdPipelineBarrier(m_oPrimaryCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &postPresentBarrier);
    }

    {///--- Render pass
        VkClearValue clearValues[2];
        clearValues[0].color={{1.0f, 0.0f, 0.2f, 0.0f}};
        clearValues[1].depthStencil={1.0f, 0};

        VkRenderPassBeginInfo renderPassBeginInfo={};
        renderPassBeginInfo.sType=VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
        renderPassBeginInfo.renderPass=m_pRenderPass;
        renderPassBeginInfo.renderArea.offset.x=0;
        renderPassBeginInfo.renderArea.offset.y=0;
        renderPassBeginInfo.renderArea.extent.width=m_uSwapchainWidth;
        renderPassBeginInfo.renderArea.extent.height=m_uSwapchainHeight;
        renderPassBeginInfo.clearValueCount=2;
        renderPassBeginInfo.pClearValues=clearValues;
        renderPassBeginInfo.framebuffer=m_pFrameBuffers[m_uSwapChainImage];

        vkCmdBeginRenderPass(m_oPrimaryCmd, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
        vkCmdEndRenderPass(m_oPrimaryCmd);
    }
}//PrepareFrame

void VulkanRenderer::SubmitFrame()
{
    ///---------------------------------
    /// Executed submited secondary commands
    ///---------------------------------
    vkCmdExecuteCommands(m_oPrimaryCmd, 0, nullptr);
    ///---------------------------------
    /// Convert image to presentable
    ///---------------------------------
    {
        VkImageMemoryBarrier prePresentBarrier={};
        prePresentBarrier.sType=VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
        prePresentBarrier.srcAccessMask=VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
        prePresentBarrier.dstAccessMask=VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
        prePresentBarrier.oldLayout=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
        prePresentBarrier.newLayout=VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
        prePresentBarrier.srcQueueFamilyIndex=VK_QUEUE_FAMILY_IGNORED;
        prePresentBarrier.dstQueueFamilyIndex=VK_QUEUE_FAMILY_IGNORED;
        prePresentBarrier.subresourceRange={VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
        prePresentBarrier.image=m_oSwapChain.images()[m_uSwapChainImage];
        vkCmdPipelineBarrier(m_oPrimaryCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &prePresentBarrier);
    }
    vkEndCommandBuffer(m_oPrimaryCmd);

    ///--- Submit
    VkPipelineStageFlags wait_dst_stage_mask=VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
    VkSubmitInfo submit_info={
        VK_STRUCTURE_TYPE_SUBMIT_INFO,              // VkStructureType              sType
        nullptr,                                    // const void                  *pNext
        1,                                          // uint32_t                     waitSemaphoreCount
        &m_oSemaphorePresentReady,                  // const VkSemaphore           *pWaitSemaphores
        &wait_dst_stage_mask,                       // const VkPipelineStageFlags  *pWaitDstStageMask;
        1,                                          // uint32_t                     commandBufferCount
        &m_oPrimaryCmd,                             // const VkCommandBuffer       *pCommandBuffers
        1,                                          // uint32_t                     signalSemaphoreCount
        &m_oSemaphoreRenderComplete                 // const VkSemaphore           *pSignalSemaphores
    };
    vkQueueSubmit(m_pDeviceQueue, 1, &submit_info, VK_NULL_HANDLE);

    ///--- Present queue
    VkResult iRes;
    iRes=m_oSwapChain.QueuePresent(m_pDeviceQueue, m_uSwapChainImage, m_oSemaphoreRenderComplete);
    CheckVulkanError(iRes);

    ///--- Flush device
    vkQueueWaitIdle(m_pDeviceQueue);
}//SubmitFrame

其他:

VkResult VulkanSwapchain::AcquireNextImage(VkSemaphore oPresentCompleteSemaphore, uint32_t* pCurrentBuffer)
{
    ///---------------------------------
    /// Acquires next image in the swap chain
    ///---------------------------------
    if(!m_fpAcquireNextImageKHR){
        XLOG("%s:%d: m_fpAcquireNextImageKHR", __FUNCTION__, __LINE__);
        return VkResult::VK_INCOMPLETE;
    }
    VkResult iRes=VkResult::VK_SUCCESS;
    iRes=m_fpAcquireNextImageKHR(m_pDevice, m_pSwapChain, UINT64_MAX, oPresentCompleteSemaphore, (VkFence)nullptr, pCurrentBuffer);
    return iRes;
}//AcquireNextImage

一开始我认为这是我分配的一些Vulkan资源而不是解除分配,但这就是Vulkan Debug Layer提供的:

INFORMATION: [MEM] Code 0 : Details of Memory Object list (of size 1 elements)
INFORMATION: [MEM] Code 0 : =============================
INFORMATION: [MEM] Code 0 :     ===MemObjInfo at 0000000003BD6E58===
INFORMATION: [MEM] Code 0 :     Mem object: 0x3bd6ac0
INFORMATION: [MEM] Code 0 :     Ref Count: 1
INFORMATION: [MEM] Code 0 :     Mem Alloc info:
MEM(INFO):         sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
MEM(INFO):         pNext = 0000000000000000
MEM(INFO):         allocationSize = 2621440
MEM(INFO):         memoryTypeIndex = 1

INFORMATION: [MEM] Code 0 :     VK OBJECT Binding list of size 1 elements:
INFORMATION: [MEM] Code 0 :        VK OBJECT 62742624
INFORMATION: [MEM] Code 0 :     VK Command Buffer (CB) binding list of size 0 elements
INFORMATION: [MEM] Code 0 : Details of CB list (of size 1 elements)
INFORMATION: [MEM] Code 0 : ==================
INFORMATION: [MEM] Code 0 :     CB Info (0000000003BB4228) has CB 0000000003BB2AD0, fenceId a3, and fence 0

每一帧似乎只存在2个内部资源。 我还重载了new / new [] / delete / delete []运算符,并且在循环期间不会调用它们。

我一直在寻找的示例几乎一样,我尝试删除并创建每个帧的主命令缓冲区,仍然得到相同的结果。

不调用PrepareFrame()和SubmitFrame()可以解决问题。为什么?

这种分配来自哪里?我怎么能追捕这种分配?

2 个答案:

答案 0 :(得分:4)

正如krOoze所提到的,尝试更新到最新的SDK,或者(更好)从源构建层以始终获取最新的层。 Afaik关于正确的内存检查,层仍然存在一个未解决的问题,因此它们实际上可能导致内存泄漏。从您上传的来源中的验证图层名称判断,您没有使用最新的名称,例如VK_LAYER_LUNARG_threading最近已重命名为VK_LAYER_GOOGLE_threading。

在我的示例中使用当前图层,我无法重现任何内存泄漏。

但是我在你的来源中注意到了一件事:

    int iUsedLayers=0;
    const char* ppLayers[64]={};
    if(bExtraLayers){
        ppLayers[iUsedLayers++]="VK_LAYER_LUNARG_standard_validation";
#if VKMEMDBG
        ppLayers[iUsedLayers++]="VK_LAYER_LUNARG_mem_tracker";
#endif
        ppLayers[iUsedLayers++]="VK_LAYER_LUNARG_threading";
        ppLayers[iUsedLayers++]="VK_LAYER_LUNARG_object_tracker";
        ppLayers[iUsedLayers++]="VK_LAYER_LUNARG_draw_state";
        ppLayers[iUsedLayers++]="VK_LAYER_LUNARG_param_checker";
        ppLayers[iUsedLayers++]="VK_LAYER_LUNARG_swapchain";
        ppLayers[iUsedLayers++]="VK_LAYER_LUNARG_device_limits";
        ppLayers[iUsedLayers++]="VK_LAYER_LUNARG_image";
        ppLayers[iUsedLayers++]="VK_LAYER_GOOGLE_unique_objects";
    }

虽然它不会造成任何伤害,但实际上你需要两次添加所有图层(mem_tracker除了取决于定义)。 VK_LAYER_LUNARG_standard_validation元图层已经以正确的顺序启用了所有可用(基础)验证图层(您的订单可能不是这种情况),因此不必在之后逐个添加它们。

答案 1 :(得分:-1)

另一个类似错误的可能原因是未调用:

vkDeviceWaitIdle ( Device );
在渲染/并条机调用之间

。所有提交的命令缓冲区都添加到仅从以下位置清除的列表中:

vkQueueWaitIdle, vkDeviceWaitIdle and vkWaitForFences 

通话。如果您在程序中调用其中之一,统一缓冲区代码将通过copyBuffer调用在每个帧中调用vkDeviceWaitIdle,并且不会再从vkQueueSubmit()中泄漏信息。