Vulkan: Что сделал vkQueuePresentKHR? - PullRequest
0 голосов
/ 30 октября 2019
void drawFrame() {

    vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits<uint64_t>::max());

    ...

    VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
    submitInfo.signalSemaphoreCount = 1;
    submitInfo.pSignalSemaphores = signalSemaphores;

    vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame])

    ...

    VkSwapchainKHR swapChains[] = {swapChain};

    VkPresentInfoKHR presentInfo = {};
    presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
    presentInfo.waitSemaphoreCount = 1;
    presentInfo.pWaitSemaphores = signalSemaphores;
    presentInfo.swapchainCount = 1;
    presentInfo.pSwapchains = swapChains;
    presentInfo.pImageIndices = &imageIndex;

    vkQueuePresentKHR(presentQueue, &presentInfo); // <- vkQueuePresentKHR
    ...

    currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
}

VkQueuePresentKHR вызывается для presont после отправки первого кадра vkQueueSubmit. Во втором кадре вызовите vkWaitForFences, чтобы дождаться окончания vkQueueSubmit предыдущего кадра, а затем снова вызовите vkQueueSubmit для фиксации, но на этом этапеПервый кадр vkQueuePresentKHR может быть в рендеринге, он занимает кадровый буфер первого кадра. Так будет ли vkQueueSubmit второго кадра конфликтовать с vkQueuePresentKHR первого кадра?

Я думаю, что может быть две ситуации:

1 : Первый кадр ивторой кадр не занимает один и тот же кадровый буфер , Когда первый кадр vkQueueSubmit заканчивается, данные были скопированы в новую память. vkQueuePresentKHR представляет данные в новой памяти, поэтому рендеринг второго кадра в буфер кадров не влияет на содержимое первого кадра.

2: первый кадр и второй кадр занимают один и тот же кадровый буфер , Когда vkQueuePresentKHRпервого кадра и vkQueueSubmit второго кадра одновременно используют Framebuffer, происходит разрыв изображения (я думаю).

Я думаю, что вторая возможность будет выше.

Я хочу отобразить результат в моей собственной памяти, а не предварительно отобразить его на экране. Я хочу выяснить, что делает vkQueuePresentKHR.

Вот пример рендеринга в вашу собственную память: https://github.com/SaschaWillems/Vulkan/blob/master/examples/renderheadless/renderheadless.cpp

В этом примере визуализированные данные Framebuffer переносятся в новую память.

В разработанной мною программе есть дополнительный поток, отвечающий за ожидание завершения Fence. Эта память используется после завершения передачи. Аналогично приведенному ниже примеру:

Основной поток:

void drawFrame() {

    vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits<uint64_t>::max());

    ...

    VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
    submitInfo.signalSemaphoreCount = 1;
    submitInfo.pSignalSemaphores = signalSemaphores;

    // VkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) cannot be executed before the execution of 
    // vkQueueSubmit(graphicsQueue, 1, &transferSubmitInfo, transferCompleteFences[currentFrame]) in the previous frame. Otherwise,
    // they will occupy the same FrameBuffer. I think it is not possible.
    transferCompleteMutexs[currentFrame].lock();                                                // <- lock transferCompleteMutexs

    vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame])

    ...

    VkSubmitInfo transferSubmitInfo = {};
    transferSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    transferSubmitInfo.commandBufferCount = 1;
    transferSubmitInfo.pCommandBuffers = &commandBuffer;
    transferSubmitInfo.waitSemaphoreCount = 1;
    transferSubmitInfo.pWaitSemaphores = signalSemaphores;
    vkQueueSubmit(graphicsQueue, 1, &transferSubmitInfo, transferCompleteFences[currentFrame]) // Signal <- transferCompleteFences
    ...
}

Вторичный поток:

while(true) {
    // Waiting for transfer to complete
    vkWaitForFences(logicalDevice_->vkLogicalDevice(),
                    1,
                    &transferCompleteFences[currentFrame],                         // Wait <- transferCompleteFences
                    VK_TRUE,
                    std::numeric_limits<uint64_t>::max());

    // using transfer completed data 
    ...

    // Secondary thread knows that the current frame is transmitted. The next Primary thread can be submitted.
    transferCompleteMutexs[currentFrame].unlock();                                // <- unlock transferCompleteMutexs
}

В приведенном выше коде используется TransferCompleteMutexs для защиты FrameBufferЯ думаю, что это необходимо. Но очевидно, что vkQueuePresentKHR этого не делает. У меня есть лучший способ эмулировать vkQueuePresentKHR для отображения данных в моей собственной памяти, или это правильно, что я делаю сейчас?

1 Ответ

0 голосов
/ 31 октября 2019

vkQueueSubmit второго кадра не может "конфликтовать" с vkQueuePresent первого кадра.

Во втором кадре вы также должны сделать vkAcquireNextImage, который дает семафор. При условии, что семафор сигнализирован, изображение больше не используется механизмом презентаций (независимо от того, является ли оно тем же изображением, что и в предыдущем кадре, или нет).

С чем может конфликтовать vkQueueSubmit, несмотря на то, что оно является предыдущимvkQueueSubmit и различные ресурсы, которые используют.

Что vkQueuePresent делает, это передает ваш семафор в ожидании выполнения в очереди, прежде чем он вернется. Он не получит доступ к изображению, пока семафор не получит сигнал. Он представит изображение на изображении снаружи \ асинхронно из очереди Vulkan. Все остальное не указано. Изображение может быть скопировано, скопировано точно в срок или использовано напрямую, или что-либо еще, что соответствует вышеуказанному контракту API.

...