summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Halase <jordan@halase.me>2019-11-07 16:07:31 -0600
committerJordan Halase <jordan@halase.me>2019-11-07 16:07:31 -0600
commit92ae03a9c8783bc224e8ffd1bb675d648c33b460 (patch)
tree7bb741c8395018411ff1fbc2dea9846fba4f0644
parentfe054b7b9d000bd8f6c94cd569e1cb1836419e47 (diff)
Begin adding swapchain recreation support
-rwxr-xr-xmain.c109
1 files changed, 69 insertions, 40 deletions
diff --git a/main.c b/main.c
index 2a7f242..e0debb0 100755
--- a/main.c
+++ b/main.c
@@ -60,6 +60,10 @@ PERFORMANCE OF THIS SOFTWARE.
#define APP_THREAD_LOCAL __declspec(thread)
#endif
+#define MIN(a, b) ((a) <= (b) ? (a) : (b))
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+#define CLAMP(x, l, h) ((x) <= (l) ? (l) : (x) >= (h) ? (h) : (x))
+
struct Arguments {
bool validation;
bool verbose;
@@ -190,6 +194,7 @@ struct SwapchainVulkan {
VkImage *images;
VkImageView *imageViews;
VkFence *fences;
+ VkCommandBuffer *commandBuffers;
};
struct SemaphoreVulkan {
@@ -228,7 +233,6 @@ struct RenderVulkan {
VkQueue graphicsQueue;
VkCommandPool commandPool;
struct SwapchainVulkan *swapchain;
- VkCommandBuffer *commandBuffers;
struct SyncVulkan sync;
};
@@ -720,6 +724,7 @@ int rvkCreateSurface(struct RenderVulkan *vk, const PuglRect frame)
puglSetFrame(vk->view, frame);
puglSetHandle(vk->view, vk);
puglSetBackend(vk->view, puglStubBackend());
+ puglSetViewHint(vk->view, PUGL_RESIZABLE, true);
PuglStatus status;
if ((status = puglCreateWindow(vk->view, "Vulkan Application Using Pugl"))) {
@@ -1318,15 +1323,16 @@ int rvkConfigureSurface(struct RenderVulkan *vk)
static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height)
{
- // TODO: Clamp
+ // FIXME: We actually need a new surfaceCapabilities for every new swapchain.
+ //width = CLAMP(width, vk->surfaceCapabilities.minImageExtent.width, vk->surfaceCapabilities.maxImageExtent.width);
+ //height = CLAMP(height, vk->surfaceCapabilities.minImageExtent.height, vk->surfaceCapabilities.maxImageExtent.height);
+
vk->swapchain->extent.width = width;
vk->swapchain->extent.height = height;
vk->swapchain->nImages = vk->surfaceCapabilities.minImageCount;
//vk->swapchain->nImages = vk->surfaceCapabilities.maxImageCount;
- printf("Using %d swapchain images\n", vk->swapchain->nImages);
-
VkSwapchainCreateInfoKHR createInfo = { 0 };
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = vk->surface;
@@ -1340,7 +1346,9 @@ static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height)
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = vk->presentMode;
createInfo.clipped = VK_TRUE;
- createInfo.oldSwapchain = VK_NULL_HANDLE; // TODO
+ if (vk->swapchain->pNext) {
+ createInfo.oldSwapchain = vk->swapchain->pNext->rawSwapchain;
+ }
VkResult result;
if ((result = vk->dev->vkCreateSwapchainKHR(vk->device, &createInfo, ALLOC_VK, &vk->swapchain->rawSwapchain))) {
rvkSetErrMsg(vk, "Could not create swapchain: %d", result);
@@ -1349,11 +1357,10 @@ static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height)
return 0;
}
-static void rvkDestroyRawSwapchain(struct RenderVulkan *vk)
+static void rvkDestroyRawSwapchain(struct RenderVulkan *vk, struct SwapchainVulkan *swapchain)
{
- if (vk->swapchain && vk->swapchain->rawSwapchain) {
- vk->dev->vkDestroySwapchainKHR(vk->device, vk->swapchain->rawSwapchain, ALLOC_VK);
- memset(&vk->swapchain, 0, sizeof(vk->swapchain));
+ if (swapchain && swapchain->rawSwapchain) {
+ vk->dev->vkDestroySwapchainKHR(vk->device, swapchain->rawSwapchain, ALLOC_VK);
}
}
@@ -1425,19 +1432,18 @@ static VkResult allocateCommandBuffers(struct RenderVulkan *vk)
allocInfo.commandPool = vk->commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = vk->swapchain->nImages;
- vk->commandBuffers = malloc(vk->swapchain->nImages * sizeof(vk->commandBuffers));
- return vk->dev->vkAllocateCommandBuffers(vk->device, &allocInfo, vk->commandBuffers);
+ vk->swapchain->commandBuffers = malloc(vk->swapchain->nImages * sizeof(vk->swapchain->commandBuffers));
+ return vk->dev->vkAllocateCommandBuffers(vk->device, &allocInfo, vk->swapchain->commandBuffers);
}
-static void freeCommandBuffers(struct RenderVulkan *vk)
+static void freeCommandBuffers(struct RenderVulkan *vk, struct SwapchainVulkan *swapchain)
{
- if (vk->commandBuffers) {
+ if (swapchain && swapchain->commandBuffers) {
vk->dev->vkFreeCommandBuffers(vk->device,
vk->commandPool,
- vk->swapchain->nImages,
- vk->commandBuffers);
- free(vk->commandBuffers);
- vk->commandBuffers = NULL;
+ swapchain->nImages,
+ swapchain->commandBuffers);
+ free(swapchain->commandBuffers);
}
}
@@ -1483,24 +1489,24 @@ static int recordCommandBuffers(struct RenderVulkan *vk)
toPresentBarrier.image = vk->swapchain->images[i];
toPresentBarrier.subresourceRange = range;
- vk->dev->vkBeginCommandBuffer(vk->commandBuffers[i], &beginInfo);
- vk->dev->vkCmdPipelineBarrier(vk->commandBuffers[i],
+ vk->dev->vkBeginCommandBuffer(vk->swapchain->commandBuffers[i], &beginInfo);
+ vk->dev->vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i],
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, NULL,
0, NULL,
1, &toClearBarrier);
- vk->dev->vkCmdClearColorImage(vk->commandBuffers[i], vk->swapchain->images[i],
+ vk->dev->vkCmdClearColorImage(vk->swapchain->commandBuffers[i], vk->swapchain->images[i],
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue, 1, &range);
- vk->dev->vkCmdPipelineBarrier(vk->commandBuffers[i],
+ vk->dev->vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i],
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0,
0, NULL,
0, NULL,
1, &toPresentBarrier);
- vk->dev->vkEndCommandBuffer(vk->commandBuffers[i]);
+ vk->dev->vkEndCommandBuffer(vk->swapchain->commandBuffers[i]);
}
return 0;
@@ -1508,7 +1514,9 @@ static int recordCommandBuffers(struct RenderVulkan *vk)
int rvkCreateSwapchain(struct RenderVulkan *vk, const int width, const int height)
{
+ struct SwapchainVulkan *oldSwapchain = vk->swapchain;
vk->swapchain = calloc(1, sizeof(*vk->swapchain));
+ vk->swapchain->pNext = oldSwapchain;
if (rvkCreateRawSwapchain(vk, width, height)) {
return -1;
}
@@ -1537,24 +1545,33 @@ int rvkCreateSwapchain(struct RenderVulkan *vk, const int width, const int heigh
return 0;
}
-void rvkDestroySwapchain(struct RenderVulkan *vk)
+// TODO: Move device into RenderDev to limit scope
+void rvkDestroySwapchain(struct RenderVulkan *vk, struct SwapchainVulkan *swapchain)
{
- if (vk->swapchain && vk->swapchain->fences) {
- for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) {
- if (vk->swapchain->fences[i]) {
+ if (swapchain && swapchain->fences) {
+ for (uint32_t i = 0; i < swapchain->nImages; ++i) {
+ if (swapchain->fences[i]) {
vk->dev->vkDestroyFence(vk->device,
- vk->swapchain->fences[i],
+ swapchain->fences[i],
ALLOC_VK);
}
}
- free(vk->swapchain->fences);
- vk->swapchain->fences = NULL;
- }
- freeCommandBuffers(vk);
- destroySwapchainImageViews(vk->device, vk->dev, vk->swapchain);
- rvkDestroyRawSwapchain(vk);
- free(vk->swapchain);
- vk->swapchain = NULL;
+ free(swapchain->fences);
+ }
+ freeCommandBuffers(vk, swapchain);
+ destroySwapchainImageViews(vk->device, vk->dev, swapchain);
+ rvkDestroyRawSwapchain(vk, swapchain);
+ free(swapchain);
+}
+
+// TODO: Destroy retired swapchains during rendering; not just all at once at destroy time.
+void rvkDestroyAllSwapchains(struct RenderVulkan *vk)
+{
+ struct SwapchainVulkan *swapchain, *pNext;
+ for (swapchain = vk->swapchain; swapchain; swapchain = pNext) {
+ pNext = swapchain->pNext;
+ rvkDestroySwapchain(vk, swapchain);
+ }
}
/** Creates any semaphores or fences for this application. */
@@ -1584,7 +1601,8 @@ static void rvkCloseDevice(struct RenderVulkan *vk)
if (vk->device) {
if (vk->dev->vkDeviceWaitIdle) vk->dev->vkDeviceWaitIdle(vk->device);
rvkDestroySyncObjects(vk);
- rvkDestroySwapchain(vk);
+ //rvkDestroySwapchain(vk);
+ rvkDestroyAllSwapchains(vk);
if (vk->commandPool) {
vk->dev->vkDestroyCommandPool(vk->device, vk->commandPool, ALLOC_VK);
vk->commandPool = VK_NULL_HANDLE;
@@ -1682,18 +1700,29 @@ PuglStatus onDisplay(PuglView *view)
{
struct RenderVulkan *vk = puglGetHandle(view);
uint32_t imageIndex;
+ PuglRect frame;
VkResult result;
// TODO: Swapchain recreation when resizing, minimizing, etc.
- if ((result = vk->dev->vkAcquireNextImageKHR(
+ while ((result = vk->dev->vkAcquireNextImageKHR(
vk->device,
vk->swapchain->rawSwapchain,
UINT64_MAX,
vk->sync.semaphore.presentComplete,
VK_NULL_HANDLE,
&imageIndex))) {
- rvkSetErrMsg(vk, "Could not acquire swapchain image: %d", result);
- return PUGL_FAILURE;
+ switch (result) {
+ case VK_SUCCESS:
+ break;
+ case VK_SUBOPTIMAL_KHR:
+ case VK_ERROR_OUT_OF_DATE_KHR:
+ frame = puglGetFrame(vk->view);
+ CHECK_RVK(vk, rvkCreateSwapchain(vk, frame.width, frame.height));
+ continue;
+ default:
+ rvkSetErrMsg(vk, "Could not acquire swapchain image: %d", result);
+ rvkFatal(vk);
+ }
}
/* If running continuously and with an asynchronous presentation engine,
@@ -1716,7 +1745,7 @@ PuglStatus onDisplay(PuglView *view)
submitInfo.pWaitSemaphores = &vk->sync.semaphore.presentComplete;
submitInfo.pWaitDstStageMask = &waitStage;
submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &vk->commandBuffers[imageIndex];
+ submitInfo.pCommandBuffers = &vk->swapchain->commandBuffers[imageIndex];
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &vk->sync.semaphore.renderFinished;