首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Vulkan正确帧同步

Vulkan正确帧同步
EN

Stack Overflow用户
提问于 2021-08-04 18:51:30
回答 1查看 83关注 0票数 0

我是Vulkan API的trying to synchronize frames,但我有一些奇怪的问题。我像这样实现了同步:

代码语言:javascript
复制
void RenderSystem::OnUpdate(const float deltaTime)
{
    uint32_t frameIndex{};

    auto result = SwapChain->AcquireNextImageIndex(PresentationCompleteSemaphore.get(),
                                                   nullptr,
                                                   &frameIndex);

    InFlightFences[frameIndex]->Wait();
    InFlightFences[frameIndex]->Reset();

    if (result == VK_ERROR_OUT_OF_DATE_KHR)
    {
        Recreate();
        return;
    }
    else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
    {
        throw std::runtime_error("Error when acquiring next image...");
    }

    UpdateModelMatrix(deltaTime, frameIndex); // TODO: Remove this! For testing purposes only

    VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
    GraphicsMainQueue.Submit({ TriangleCommandBuffers[frameIndex].get() },
                             { PresentationCompleteSemaphore.get() },
                             { RenderCompleteSemaphore.get() },
                             InFlightFences[frameIndex].get(),
                             waitStages);

    result = PresentationQueue.Present({ RenderCompleteSemaphore.get() },
                                       { SwapChain.get() },
                                       &frameIndex);

    if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || MainWindow->HasBeenResized())
        Recreate();
    else if (result != VK_SUCCESS)
        throw std::runtime_error("Failed to present result!");
}

而且它在Windows10上的表现也非常出色。不幸的是,在Linux Mint上,它在某些情况下不起作用。首先,在Linux上移动窗口非常慢,有时会使整个操作系统冻结一秒钟,但这并不是最大的问题。关闭窗口会调用vkDeviceWaitIdle和...它会冻结应用程序。它永远不会开始响应,因为它将永远等待设备。验证层没有报告我的代码有任何问题。

我通过在函数底部移动栅栏同步部分解决了这个问题,但在我看来,这是一个次优的解决方案,因为我等待帧完成渲染,而不是准备下一帧。

代码语言:javascript
复制
    // ...

    if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || MainWindow->HasBeenResized())
        Recreate();
    else if (result != VK_SUCCESS)
        throw std::runtime_error("Failed to present result!");

    InFlightFences[frameIndex]->Wait();
    InFlightFences[frameIndex]->Reset();
}

如何不仅在Windows上而且在Linux上正确地同步帧?我做错了什么?我遗漏了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-08-05 14:26:22

您只有一组信号量。这意味着对这些信号量的访问可能不同步。

让我们看看没有干扰的代码:

代码语言:javascript
复制
AcquireNextImageIndex( PresentationCompleteSemaphore, frameIndex );
InFlightFences[frameIndex].WaitAndReset();
QSubmit( PresentationCompleteSemaphore, RenderCompleteSemaphore, InFlightFences[frameIndex] );
Present( RenderCompleteSemaphore, frameIndex );

现在,我们如何知道我们可以在Acquire上重用PresentationCompleteSemaphore呢?Submit等待\取消它的信号,并且必须完成。我们可以从栅栏中推断出这一点,但是栅栏等待发生在Acquire之后。因此,在Acquire尝试重用信号量时,信号量可能仍在使用中。这是一个可能的程序流:

代码语言:javascript
复制
AcquireNextImageIndex( PresentationCompleteSemaphore ) -> frameIndex = 0;
QSubmit( PresentationCompleteSemaphore, RenderCompleteSemaphore, InFlightFences[0] );

// hazard; QSubmit still might be waiting on PresentationCompleteSemaphore
AcquireNextImageIndex( PresentationCompleteSemaphore ) -> frameIndex = 1;

我们怎么知道我们可以重用RenderCompleteSemaphore呢?只有当Present已经使用它时,QSubmit才能使用它。目前唯一合理的推断方法是,当Acquire返回相同的交换链图像时。这是一个可能的程序流:

代码语言:javascript
复制
AcquireNextImageIndex( PresentationCompleteSemaphore ) -> frameIndex = 0;
QSubmit( PresentationCompleteSemaphore, RenderCompleteSemaphore, InFlightFences[0] );
Present( RenderCompleteSemaphore, 0 );

AcquireNextImageIndex( PresentationCompleteSemaphore ) -> frameIndex = 1;
// hazard; RenderCompleteSemaphore might still be waited on by Present
// which presented image 0, but we acquired image 1, so it might be async
QSubmit( PresentationCompleteSemaphore, RenderCompleteSemaphore, InFlightFences[1] );
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68656627

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档