Отправка первого кадра не удалась из-за незаписанного командного буфера и несигнализированного семафора в многопоточном C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Отправка первого кадра не удалась из-за незаписанного командного буфера и несигнализированного семафора в многопоточном

Сообщение Anonymous »

Я реализую цикл рендеринга Vulkan с несколькими динамическими кадрами, используя шаблон производитель-потребитель и пул потоков.
Основная логика цикла:
  • Код: Выделить всё

    PreRender
    в основном потоке — ожидание на границах, получение образа цепочки обмена.
  • Отправьте AcademicFrame и RenderFrame в пул потоков.
  • Подождите () для завершения задач пула потоков.
  • Код: Выделить всё

    PostRender
    в основном потоке — представьте изображение.
  • Повторите.
Однако в самом первом кадре проверка Vulkan сообщает об ошибках, что буфер команд не записан, а семафор, используемый для ожидания, не может быть сигнализирован.

❓ С чем я борюсь
На первой итерации:
  • Код: Выделить всё

    PrepareFrame
    записывает команды (проход очистки цвета).
  • Но RenderFrame, который отправляет буфер команд, работает с неправильным индексом кадра, отправляя буфер команд, который никогда не записывался.
  • Уровни проверки сообщают, что семафор ожидания никогда не сигнализировался.
    Вот соответствующая цепочка вызовов:

    Код: Выделить всё

    void View::OnUpdate(double deltaTime)
    {
    if (m_RenderSurface)
    {
    m_RenderSurface->PreRender();
    
    m_ThreadsUpdate.Submit([&]()
    {
    m_RenderQueue->SetDeltaTime(static_cast(deltaTime));
    m_RenderSurface->PrepareFrame(m_RenderQueue);
    });
    
    m_ThreadsUpdate.Submit([&]()
    {
    m_RenderSurface->RenderFrame();
    });
    
    m_ThreadsUpdate.Join();
    
    m_RenderSurface->PostRender();
    }
    }
    
    Фрагменты кода (фреймы/Vulkan)
    Структура данных фрейма:

    Код: Выделить всё

    struct FrameData
    {
    VkFence fence = VK_NULL_HANDLE;
    VkSemaphore acquireSemaphore = VK_NULL_HANDLE;
    VkSemaphore renderSemaphore = VK_NULL_HANDLE;
    VkCommandBuffer cmdBuffer = VK_NULL_HANDLE;
    uint32_t imageIndex = 0;
    bool inFlight = false;
    };
    std::array m_Frames;
    
    Ротация индекса:

    Код: Выделить всё

    void IGAPI::EndRender()
    {
    m_IndexFrameRender = (m_IndexFrameRender + 1) % BACK_BUFFER_COUNT;
    m_IndexFramePrepare = (m_IndexFrameRender + 1) % BACK_BUFFER_COUNT;
    }
    

    Код: Выделить всё

    PreRender()
    получает изображение:
    vr = vkAcquireNextImageKHR(device, m_Swapchain, UINT64_MAX,frame.acquireSemaphore, VK_NULL_HANDLE, &imageIndex);

Код: Выделить всё

PrepareFrame()
сбрасывает и записывает буфер команд.

Код: Выделить всё

RenderFrame()
вызывает:

Код: Выделить всё

vkResetFences(device, 1, &frame.fence);

VkSubmitInfo submitInfo{};
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &frame.acquireSemaphore;
submitInfo.pWaitDstStageMask = &waitStage;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &frame.cmdBuffer;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &frame.renderSemaphore;

vkQueueSubmit(m_VulkanAPI->GetGraphicsQueue(), 1, &submitInfo, frame.fence);
Наконец, PostRender() представляет:

Код: Выделить всё

VkPresentInfoKHR presentInfo{};
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = &frame.renderSemaphore;
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &m_Swapchain;
presentInfo.pImageIndices = &frame.imageIndex;

vkQueuePresentKHR(m_VulkanAPI->GetPresentQueue(), &presentInfo);
Вывод проверки при первой итерации

Код: Выделить всё

>>>>> #0 PreRender(). stepCounter: 1, indexPrepare: 0, imageIndex: 0.
>>>>> PrepareFrame(). stepCounter: 1, indexPrepare: 0, frame.imageIndex: 0.
>>>>> RenderFrame(). stepCounter: 1, indexRender: 1.

Vulkan Validation: ERROR | vkQueueSubmit(): pCommandBuffers[0] is unrecorded and contains no commands.
Vulkan Validation: ERROR | vkQueueSubmit(): pWaitSemaphores[0] has no way to be signaled.

>>>>> PostRender().  stepCounter: 1, indexRender: 1.

Vulkan Validation: ERROR | vkQueuePresentKHR(): pPresentInfo->pImageIndices[0] was acquired with a semaphore that has not since been waited on
Ожидаемое поведение
Я ожидаю, что:
  • Первый кадр записывает команды в AcceptFrame и отправляет их в RenderFrame.
  • Настоящий семафор правильно сигнализируется и ожидает в vkQueuePresentKHR.
Репозиторий кода
Полный код и ветка с этой реализацией Vulkan доступны здесь:
https://github.com/k119-55524/Zzz

Ветвь: origin/clear-VK-api

Вопрос
  • Как правильно записать и отправить первый кадр в этом конвейере Vulkan с кадрами в полете, чтобы избежать ошибок «незаписанного командного буфера» и «несигнализированного семафора»?
  • Есть ли ошибка рекомендуемый шаблон для инициализации и отправки самого первого кадра при использовании нескольких динамических кадров и пула потоков?
  • В качестве альтернативы предоставьте ссылки на учебные пособия или руководства, в которых объясняется, как реализовать правильный конвейер рендеринга производитель-потребитель в Vulkan с несколькими динамическими кадрами и синхронизацией.


Подробнее здесь: https://stackoverflow.com/questions/799 ... aled-semap
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»