diff options
| -rw-r--r-- | main.c | 99 | 
1 files changed, 96 insertions, 3 deletions
| @@ -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); | 
