|
@@ -26,10 +26,17 @@ static VkRect2D scissor;
|
|
|
static VkPipeline pipeline;
|
|
|
static VkFramebuffer* framebuffers;
|
|
|
static VkCommandPool commandPool;
|
|
|
-static VkCommandBuffer commandBuffer;
|
|
|
-static VkSemaphore imageAvailableSemaphore;
|
|
|
-static VkSemaphore renderFinishedSemaphore;
|
|
|
-static VkFence inFlightFence;
|
|
|
+static constexpr size_t MAX_FRAMES = 2;
|
|
|
+static size_t currentFrame = 0;
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ VkCommandBuffer commandBuffer;
|
|
|
+ VkSemaphore imageAvailableSemaphore;
|
|
|
+ VkSemaphore renderFinishedSemaphore;
|
|
|
+ VkFence inFlightFence;
|
|
|
+} Frame;
|
|
|
+
|
|
|
+static Frame frames[MAX_FRAMES];
|
|
|
|
|
|
static int getSurfaceFormatPoints(const VkSurfaceFormatKHR* sf) {
|
|
|
if(sf->format == VK_FORMAT_B8G8R8A8_UNORM &&
|
|
@@ -360,7 +367,7 @@ static bool initCommandPool() {
|
|
|
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
|
|
.queueFamilyIndex = graphicsFamily};
|
|
|
VK_ASSERT(vkCreateCommandPool(device, &info, nullptr, &commandPool));
|
|
|
- return initCommandVulkanBuffer(&commandBuffer, device, commandPool);
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
static bool fillCommandBuffer(VkCommandBuffer cb, u32 index) {
|
|
@@ -385,6 +392,19 @@ static bool fillCommandBuffer(VkCommandBuffer cb, u32 index) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+static bool initFrames() {
|
|
|
+ for(size_t i = 0; i < MAX_FRAMES; i++) {
|
|
|
+ if(initCommandVulkanBuffer(
|
|
|
+ &frames[i].commandBuffer, device, commandPool) ||
|
|
|
+ initVulkanSemaphore(&frames[i].imageAvailableSemaphore, device) ||
|
|
|
+ initVulkanSemaphore(&frames[i].renderFinishedSemaphore, device) ||
|
|
|
+ initVulkanFence(&frames[i].inFlightFence, device)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
bool initVulkan() {
|
|
|
return initVulkanInstance() || initVulkanDebugging() ||
|
|
|
initVulkanSurface(&surface, getWindow()) || initPhysicalDevice() ||
|
|
@@ -394,38 +414,36 @@ bool initVulkan() {
|
|
|
initVulkanFramebuffers(
|
|
|
&framebuffers, &images, device, renderPass, swapchainSize.width,
|
|
|
swapchainSize.height) ||
|
|
|
- initCommandPool() ||
|
|
|
- initVulkanSemaphore(&imageAvailableSemaphore, device) ||
|
|
|
- initVulkanSemaphore(&renderFinishedSemaphore, device) ||
|
|
|
- initVulkanFence(&inFlightFence, device);
|
|
|
+ initCommandPool() || initFrames();
|
|
|
}
|
|
|
|
|
|
static bool render() {
|
|
|
- VK_ASSERT(vkWaitForFences(device, 1, &inFlightFence, true, UINT64_MAX));
|
|
|
- VK_ASSERT(vkResetFences(device, 1, &inFlightFence));
|
|
|
+ Frame* f = frames + currentFrame;
|
|
|
+ VK_ASSERT(vkWaitForFences(device, 1, &f->inFlightFence, true, UINT64_MAX));
|
|
|
+ VK_ASSERT(vkResetFences(device, 1, &f->inFlightFence));
|
|
|
|
|
|
uint32_t imageIndex = 0;
|
|
|
VK_ASSERT(vkAcquireNextImageKHR(
|
|
|
- device, swapchain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE,
|
|
|
- &imageIndex));
|
|
|
+ device, swapchain, UINT64_MAX, f->imageAvailableSemaphore,
|
|
|
+ VK_NULL_HANDLE, &imageIndex));
|
|
|
|
|
|
- vkResetCommandBuffer(commandBuffer, 0);
|
|
|
- fillCommandBuffer(commandBuffer, imageIndex);
|
|
|
+ vkResetCommandBuffer(f->commandBuffer, 0);
|
|
|
+ fillCommandBuffer(f->commandBuffer, imageIndex);
|
|
|
|
|
|
- VkSemaphore waitSemaphores[] = {imageAvailableSemaphore};
|
|
|
+ VkSemaphore waitSemaphores[] = {f->imageAvailableSemaphore};
|
|
|
VkPipelineStageFlags waitStages[] = {
|
|
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
|
|
- VkSemaphore signalSemaphores[] = {renderFinishedSemaphore};
|
|
|
+ VkSemaphore signalSemaphores[] = {f->renderFinishedSemaphore};
|
|
|
VkSubmitInfo info = {
|
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
|
.waitSemaphoreCount = 1,
|
|
|
.pWaitSemaphores = waitSemaphores,
|
|
|
.pWaitDstStageMask = waitStages,
|
|
|
.commandBufferCount = 1,
|
|
|
- .pCommandBuffers = &commandBuffer,
|
|
|
+ .pCommandBuffers = &f->commandBuffer,
|
|
|
.signalSemaphoreCount = 1,
|
|
|
.pSignalSemaphores = signalSemaphores};
|
|
|
- VK_ASSERT(vkQueueSubmit(graphicsQueue, 1, &info, inFlightFence));
|
|
|
+ VK_ASSERT(vkQueueSubmit(graphicsQueue, 1, &info, f->inFlightFence));
|
|
|
|
|
|
VkPresentInfoKHR presentInfo = {
|
|
|
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
|
@@ -436,6 +454,7 @@ static bool render() {
|
|
|
.pImageIndices = &imageIndex};
|
|
|
|
|
|
VK_ASSERT(vkQueuePresentKHR(presentQueue, &presentInfo));
|
|
|
+ currentFrame = (currentFrame + 1) % MAX_FRAMES;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -446,9 +465,12 @@ void renderVulkan() {
|
|
|
void destroyVulkan(void) {
|
|
|
if(device != VK_NULL_HANDLE) {
|
|
|
vkDeviceWaitIdle(device);
|
|
|
- destroyVulkanFence(inFlightFence, device);
|
|
|
- destroyVulkanSemaphore(imageAvailableSemaphore, device);
|
|
|
- destroyVulkanSemaphore(renderFinishedSemaphore, device);
|
|
|
+ for(size_t i = 0; i < MAX_FRAMES; i++) {
|
|
|
+ Frame* f = frames + i;
|
|
|
+ destroyVulkanFence(f->inFlightFence, device);
|
|
|
+ destroyVulkanSemaphore(f->imageAvailableSemaphore, device);
|
|
|
+ destroyVulkanSemaphore(f->renderFinishedSemaphore, device);
|
|
|
+ }
|
|
|
vkDestroyCommandPool(device, commandPool, nullptr);
|
|
|
destroyVulkanFramebuffers(&framebuffers, images.amount, device);
|
|
|
vkDestroyPipeline(device, pipeline, nullptr);
|