summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c99
1 files changed, 96 insertions, 3 deletions
diff --git a/main.c b/main.c
index 68b43aa..117d665 100644
--- a/main.c
+++ b/main.c
@@ -95,6 +95,7 @@ struct VulkanDev {
PFN_vkDestroyDevice vkDestroyDevice;
PFN_vkDeviceWaitIdle vkDeviceWaitIdle;
PFN_vkGetDeviceQueue vkGetDeviceQueue;
+ PFN_vkQueueWaitIdle vkQueueWaitIdle;
PFN_vkCreateCommandPool vkCreateCommandPool;
PFN_vkDestroyCommandPool vkDestroyCommandPool;
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
@@ -110,7 +111,11 @@ struct VulkanDev {
PFN_vkCmdClearColorImage vkCmdClearColorImage;
PFN_vkCreateSemaphore vkCreateSemaphore;
PFN_vkDestroySemaphore vkDestroySemaphore;
+ PFN_vkCreateFence vkCreateFence;
+ PFN_vkDestroyFence vkDestroyFence;
PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
+ PFN_vkWaitForFences vkWaitForFences;
+ PFN_vkResetFences vkResetFences;
PFN_vkQueueSubmit vkQueueSubmit;
PFN_vkQueuePresentKHR vkQueuePresentKHR;
};
@@ -153,6 +158,9 @@ struct RenderVulkan {
VkSemaphore imageAvailable;
VkSemaphore renderFinished;
} semaphore;
+ struct FenceVulkan {
+ VkFence *swapchain;
+ } fence;
} sync;
};
@@ -847,6 +855,13 @@ static int rvkLoadDeviceFunctions(struct RenderVulkan *vk, VkDevice device)
return -1;
}
+ static const char *const _vkQueueWaitIdle = "vkQueueWaitIdle";
+ vk->dev->vkQueueWaitIdle = (PFN_vkQueueWaitIdle)vk->api->vkGetDeviceProcAddr(device, _vkQueueWaitIdle);
+ if (!vk->dev->vkQueueWaitIdle) {
+ rvkSetErrMsg(vk, strErrLd, _vkQueueWaitIdle);
+ return -1;
+ }
+
static const char *const _vkCreateCommandPool = "vkCreateCommandPool";
vk->dev->vkCreateCommandPool = (PFN_vkCreateCommandPool)vk->api->vkGetDeviceProcAddr(device, _vkCreateCommandPool);
if (!vk->dev->vkCreateCommandPool) {
@@ -945,6 +960,20 @@ static int rvkLoadDeviceFunctions(struct RenderVulkan *vk, VkDevice device)
return -1;
}
+ static const char *const _vkCreateFence = "vkCreateFence";
+ vk->dev->vkCreateFence = (PFN_vkCreateFence)vk->api->vkGetDeviceProcAddr(device, _vkCreateFence);
+ if (!vk->dev->vkCreateFence) {
+ rvkSetErrMsg(vk, strErrLd, _vkCreateFence);
+ return -1;
+ }
+
+ static const char *const _vkDestroyFence = "vkDestroyFence";
+ vk->dev->vkDestroyFence = (PFN_vkDestroyFence)vk->api->vkGetDeviceProcAddr(device, _vkDestroyFence);
+ if (!vk->dev->vkDestroyFence) {
+ rvkSetErrMsg(vk, strErrLd, _vkDestroyFence);
+ return -1;
+ }
+
static const char *const _vkDestroySemaphore = "vkDestroySemaphore";
vk->dev->vkDestroySemaphore = (PFN_vkDestroySemaphore)vk->api->vkGetDeviceProcAddr(device, _vkDestroySemaphore);
if (!vk->dev->vkDestroySemaphore) {
@@ -959,6 +988,20 @@ static int rvkLoadDeviceFunctions(struct RenderVulkan *vk, VkDevice device)
return -1;
}
+ static const char *const _vkWaitForFences = "vkWaitForFences";
+ vk->dev->vkWaitForFences = (PFN_vkWaitForFences)vk->api->vkGetDeviceProcAddr(device, _vkWaitForFences);
+ if (!vk->dev->vkWaitForFences) {
+ rvkSetErrMsg(vk, strErrLd, _vkWaitForFences);
+ return -1;
+ }
+
+ static const char *const _vkResetFences = "vkResetFences";
+ vk->dev->vkResetFences = (PFN_vkResetFences)vk->api->vkGetDeviceProcAddr(device, _vkResetFences);
+ if (!vk->dev->vkResetFences) {
+ rvkSetErrMsg(vk, strErrLd, _vkResetFences);
+ return -1;
+ }
+
static const char *const _vkQueueSubmit = "vkQueueSubmit";
vk->dev->vkQueueSubmit = (PFN_vkQueueSubmit)vk->api->vkGetDeviceProcAddr(device, _vkQueueSubmit);
if (!vk->dev->vkQueueSubmit) {
@@ -1058,6 +1101,12 @@ static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height)
/* UNORM is *NOT* recommended for color blending, but is
* useful for getting simple "HTML" colors to the screen
* without manually converting to a linear color space.
+ *
+ * See:
+ * MinutePhysics (Henry Reich).
+ * "Computer Color Is Broken"
+ * YouTube video, 4:13. March 20, 2015.
+ * https://www.youtube.com/watch?v=LKnqECcg6Gw
*/
VK_FORMAT_B8G8R8A8_UNORM,
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
@@ -1078,13 +1127,16 @@ static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height)
}
// TODO
- VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
+ VkPresentModeKHR presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
// TODO: Clamp
vk->swapchain.extent.width = width;
vk->swapchain.extent.height = height;
vk->swapchain.nImages = surfaceCapabilities.minImageCount;
+ //vk->swapchain.nImages = surfaceCapabilities.maxImageCount;
+
+ printf("Using %d swapchain images\n", vk->swapchain.nImages);
VkSwapchainCreateInfoKHR createInfo = { 0 };
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
@@ -1111,7 +1163,6 @@ static void rvkDestroyRawSwapchain(struct RenderVulkan *vk)
{
if (vk->swapchain.rawSwapchain) {
vk->dev->vkDestroySwapchainKHR(vk->device, vk->swapchain.rawSwapchain, ALLOC_VK);
- memset(&vk->swapchain.surfaceFormat, 0, sizeof(vk->swapchain.surfaceFormat));
memset(&vk->swapchain, 0, sizeof(vk->swapchain));
}
}
@@ -1298,11 +1349,33 @@ int rvkCreateSyncObjects(struct RenderVulkan *vk)
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
vk->dev->vkCreateSemaphore(vk->device, &semaphoreInfo, ALLOC_VK, &vk->sync.semaphore.imageAvailable);
vk->dev->vkCreateSemaphore(vk->device, &semaphoreInfo, ALLOC_VK, &vk->sync.semaphore.renderFinished);
+ VkFenceCreateInfo fenceInfo = { 0 };
+ fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+ vk->sync.fence.swapchain = calloc(vk->swapchain.nImages, sizeof(*vk->sync.fence.swapchain));
+ VkResult result;
+ for (uint32_t i = 0; i < vk->swapchain.nImages; ++i) {
+ if ((result = vk->dev->vkCreateFence(vk->device, &fenceInfo, ALLOC_VK, &vk->sync.fence.swapchain[i]))) {
+ rvkSetErrMsg(vk, "Could not create render finished fence: %d", result);
+ return -1;
+ }
+ }
return 0;
}
void rvkDestroySyncObjects(struct RenderVulkan *vk)
{
+ if (vk->sync.fence.swapchain) {
+ for (uint32_t i = 0; i < vk->swapchain.nImages; ++i) {
+ if (vk->sync.fence.swapchain[i]) {
+ vk->dev->vkDestroyFence(vk->device,
+ vk->sync.fence.swapchain[i],
+ ALLOC_VK);
+ }
+ }
+ free(vk->sync.fence.swapchain);
+ vk->sync.fence.swapchain = NULL;
+ }
if (vk->sync.semaphore.renderFinished) {
vk->dev->vkDestroySemaphore(vk->device, vk->sync.semaphore.renderFinished, ALLOC_VK);
vk->sync.semaphore.renderFinished = VK_NULL_HANDLE;
@@ -1401,6 +1474,8 @@ static void rvkFatal(struct RenderVulkan *vk)
int running = 1;
+uint32_t framesDrawn;
+
PuglStatus onDisplay(PuglView *view)
{
struct RenderVulkan *vk = puglGetHandle(view);
@@ -1418,6 +1493,17 @@ PuglStatus onDisplay(PuglView *view)
return PUGL_FAILURE;
}
+ /* If running continuously, Vulkan can blast the GPU with rendering work
+ * faster than it can get around to presenting it, causing RAM usage to
+ * grow indefinitely. We use fences to limit the number of frames to the
+ * number of swapchain images. This will also be required later when
+ * flushing persistently mapped uniform buffer ranges anyway.
+ */
+ vk->dev->vkWaitForFences(vk->device,
+ 1, &vk->sync.fence.swapchain[imageIndex],
+ VK_TRUE, UINT64_MAX);
+ vk->dev->vkResetFences(vk->device, 1, &vk->sync.fence.swapchain[imageIndex]);
+
VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
VkSubmitInfo submitInfo = { 0 };
@@ -1430,7 +1516,10 @@ PuglStatus onDisplay(PuglView *view)
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &vk->sync.semaphore.renderFinished;
- if ((result = vk->dev->vkQueueSubmit(vk->graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE))) {
+ if ((result = vk->dev->vkQueueSubmit(vk->graphicsQueue,
+ 1, &submitInfo,
+ vk->sync.fence.swapchain[imageIndex]
+ ))) {
rvkSetErrMsg(vk, "Could not submit to queue: %d", result);
return PUGL_FAILURE;
}
@@ -1446,6 +1535,7 @@ PuglStatus onDisplay(PuglView *view)
vk->dev->vkQueuePresentKHR(vk->graphicsQueue, &presentInfo);
+ //++framesDrawn;
return PUGL_SUCCESS;
}
@@ -1500,10 +1590,13 @@ int main()
printf("Opened Vulkan Device Successfully\n");
puglSetEventFunc(view, onEvent);
+ //PuglFpsPrinter fpsPrinter = { puglGetTime(world) };
puglShowWindow(view);
while (running) {
puglPollEvents(world, -1);
+ //puglPostRedisplay(view);
puglDispatchEvents(world);
+ //puglPrintFps(world, &fpsPrinter, &framesDrawn);
}
rvkDestroy(vk);