[vulkan] Use per-swapchain images for output framebuffers

Imageless framebuffers would probably be easier and cleaner, but this
takes care of the validation error attempting to present the second
frame (because rendering was being done to the first frame's swapchain
image instead of the second frame's).
This commit is contained in:
Bill Currie 2023-06-21 14:47:19 +09:00
parent 503013dd38
commit 25cfef18d6
6 changed files with 108 additions and 35 deletions

View file

@ -53,6 +53,7 @@ typedef struct outputctx_s {
VkPipelineLayout fish_layout;
VkSampler sampler;
VkImageView input;
VkFramebuffer *framebuffers; // one per swapchain image
} outputctx_t;
struct vulkan_ctx_s;

View file

@ -381,6 +381,8 @@ void QFV_Render_Init (struct vulkan_ctx_s *ctx);
void QFV_Render_Shutdown (struct vulkan_ctx_s *ctx);
void QFV_Render_AddTasks (struct vulkan_ctx_s *ctx, exprsym_t *task_sys);
void QFV_CreateFramebuffer (struct vulkan_ctx_s *ctx, qfv_renderpass_t *rp);
qfv_step_t *QFV_GetStep (const exprval_t *param, qfv_job_t *job);
#endif//__QFCC__

View file

@ -137,7 +137,7 @@ run_subpass (qfv_subpass_t *sp, VkCommandBuffer cmd, vulkan_ctx_t *ctx)
static void
run_renderpass (qfv_renderpass_t *rp, vulkan_ctx_t *ctx)
{
printf ("run_renderpass: %s\n", rp->label.name);
printf ("%10.2f run_renderpass: %s\n", Sys_DoubleTime (), rp->label.name);
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
@ -167,7 +167,9 @@ run_renderpass (qfv_renderpass_t *rp, vulkan_ctx_t *ctx)
dfunc->vkCmdNextSubpass (cmd, rp->subpassContents);
}
}
dfunc->vkCmdEndRenderPass (cmd);
QFV_CmdEndLabel (device, cmd);
dfunc->vkEndCommandBuffer (cmd);
DARRAY_APPEND (&job->commands, cmd);
}
@ -235,12 +237,12 @@ run_process (qfv_process_t *proc, vulkan_ctx_t *ctx)
void
QFV_RunRenderJob (vulkan_ctx_t *ctx)
{
__auto_type rctx = ctx->render_context;
__auto_type job = rctx->job;
auto rctx = ctx->render_context;
auto job = rctx->job;
for (uint32_t i = 0; i < job->num_steps; i++) {
__auto_type step = &job->steps[i];
printf ("run_step: %s\n", step->label.name);
printf ("%10.2f run_step: %s\n", Sys_DoubleTime (), step->label.name);
if (step->render) {
run_renderpass (step->render->active, ctx);
}
@ -251,6 +253,31 @@ QFV_RunRenderJob (vulkan_ctx_t *ctx)
run_process (step->process, ctx);
}
}
auto device = ctx->device;
auto dfunc = device->funcs;
auto queue = &device->queue;
auto frame = &ctx->frames.a[ctx->curFrame];
VkPipelineStageFlags waitStage
= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submitInfo = {
VK_STRUCTURE_TYPE_SUBMIT_INFO, 0,
1, &frame->imageAvailableSemaphore, &waitStage,
job->commands.size, job->commands.a,
1, &frame->renderDoneSemaphore,
};
printf ("%10.2f submit for frame %d: %zd %p\n", Sys_DoubleTime (),
ctx->curFrame, job->commands.size, frame->imageAvailableSemaphore);
dfunc->vkResetFences (device->dev, 1, &frame->fence);
dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, frame->fence);
VkPresentInfoKHR presentInfo = {
VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 0,
1, &frame->renderDoneSemaphore,
1, &ctx->swapchain->swapchain, &ctx->swapImageIndex,
0
};
dfunc->vkQueuePresentKHR (queue->queue, &presentInfo);
}
#if 0
@ -292,7 +319,7 @@ find_imageview (qfv_reference_t *ref, qfv_renderctx_t *rctx)
Sys_Error ("%d:invalid imageview: %s", ref->line, ref->name);
}
static void
void
QFV_CreateFramebuffer (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
__auto_type rctx = ctx->render_context;
@ -339,15 +366,20 @@ QFV_CreateFramebuffer (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
static void
wait_on_fence (const exprval_t **params, exprval_t *result, exprctx_t *ectx)
{
__auto_type taskctx = (qfv_taskctx_t *) ectx;
vulkan_ctx_t *ctx = taskctx->ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
VkDevice dev = device->dev;
auto taskctx = (qfv_taskctx_t *) ectx;
auto ctx = taskctx->ctx;
auto device = ctx->device;
auto dfunc = device->funcs;
auto dev = device->dev;
__auto_type frame = &ctx->frames.a[ctx->curFrame];
dfunc->vkWaitForFences (dev, 1, &frame->fence, VK_TRUE, 2000000000);
auto job = ctx->render_context->job;
job->command_pool = frame->command_pool;
dfunc->vkResetCommandPool (device->dev, job->command_pool, 0);
DARRAY_CLEAR (&job->commands);
}
static void
@ -453,12 +485,14 @@ QFV_Render_Shutdown (vulkan_ctx_t *ctx)
QFV_DestroyResource (ctx->device, job->resources);
free (job->resources);
}
if (job->command_pool) {
dfunc->vkDestroyCommandPool (device->dev, job->command_pool, 0);
}
job->command_pool = 0;
DARRAY_CLEAR (&job->commands);
free (rctx->job);
}
for (uint32_t i = 0; i < ctx->frames.size; i++) {
auto frame = &ctx->frames.a[i];
dfunc->vkDestroyCommandPool (device->dev, frame->command_pool, 0);
}
if (rctx->jobinfo) {
__auto_type jinfo = rctx->jobinfo;
for (uint32_t i = 0; i < jinfo->num_descriptorsetlayouts; i++) {

View file

@ -1348,8 +1348,6 @@ steps = {
tasks = (
{ func = acquire_output;
params = ("\"output\""); },
{ func = update_framebuffer;
params = ("\"output\""); },
{ func = update_input; },
);
};

View file

@ -41,6 +41,7 @@
#include "QF/cvar.h"
#include "QF/render.h"
#include "QF/sys.h"
#include "QF/va.h"
#include "QF/Vulkan/qf_draw.h"
#include "QF/Vulkan/qf_matrices.h"
@ -53,6 +54,7 @@
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/image.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/render.h"
#include "QF/Vulkan/swapchain.h"
#include "r_local.h"
@ -63,14 +65,10 @@
static void
acquire_image (qfv_renderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
__auto_type frame = &ctx->frames.a[ctx->curFrame];
//outputctx_t *octx = ctx->output_context;
//uint32_t curFrame = ctx->curFrame;
//outputframe_t *oframe = &octx->frames.a[curFrame];
//qfv_renderpass_t *rp = ctx->output_renderpass;
auto ctx = rFrame->vulkan_ctx;
auto device = ctx->device;
auto dfunc = device->funcs;
auto frame = &ctx->frames.a[ctx->curFrame];
uint32_t imageIndex = 0;
while (!QFV_AcquireNextImage (ctx->swapchain,
@ -98,6 +96,9 @@ acquire_image (qfv_renderframe_t *rFrame)
dfunc->vkDestroySemaphore (device->dev, frame->imageAvailableSemaphore,
0);
frame->imageAvailableSemaphore = QFV_CreateSemaphore (device);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_SEMAPHORE,
frame->imageAvailableSemaphore,
va (ctx->va_ctx, "sc image:%d", ctx->curFrame));
}
ctx->swapImageIndex = imageIndex;
}
@ -252,16 +253,24 @@ acquire_output (const exprval_t **params, exprval_t *result, exprctx_t *ectx)
auto device = ctx->device;
auto dfunc = device->funcs;
auto frame = &ctx->frames.a[ctx->curFrame];
auto octx = ctx->output_context;
auto sc = ctx->swapchain;
printf ("acquire_output: %d\n", ctx->curFrame);
uint32_t imageIndex = 0;
while (!QFV_AcquireNextImage (ctx->swapchain,
frame->imageAvailableSemaphore,
while (!QFV_AcquireNextImage (sc, frame->imageAvailableSemaphore,
0, &imageIndex)) {
QFV_DeviceWaitIdle (device);
if (ctx->capture) {
QFV_DestroyCapture (ctx->capture);
}
for (uint32_t i = 0; i < sc->imageViews->size; i++) {
dfunc->vkDestroyFramebuffer (device->dev,
octx->framebuffers[i], 0);
}
octx->framebuffers = 0;
Vulkan_CreateSwapchain (ctx);
sc = ctx->swapchain;
Vulkan_CreateCapture (ctx);
__auto_type out = ctx->output_renderpass;
@ -274,22 +283,48 @@ acquire_output (const exprval_t **params, exprval_t *result, exprctx_t *ectx)
out->viewport.width = out->output.extent.width;
out->viewport.height = out->output.extent.height;
out->scissor.extent = out->output.extent;
auto step = QFV_GetStep (params[0], ctx->render_context->job);
auto render = step->render;
for (uint32_t i = 0; i < render->num_renderpasses; i++) {
auto rp = &render->renderpasses[i];
if (rp->beginInfo.framebuffer) {
dfunc->vkDestroyFramebuffer (device->dev,
rp->beginInfo.framebuffer, 0);
}
rp->beginInfo.framebuffer = 0; // leave for update_framebuffer
}
dfunc->vkDestroySemaphore (device->dev, frame->imageAvailableSemaphore,
0);
frame->imageAvailableSemaphore = QFV_CreateSemaphore (device);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_SEMAPHORE,
frame->imageAvailableSemaphore,
va (ctx->va_ctx, "sc image:%d", ctx->curFrame));
}
//FIXME clean this up
auto step = QFV_GetStep (params[0], ctx->render_context->job);
auto render = step->render;
auto rp = &render->renderpasses[0];
if (!octx->framebuffers) {
uint32_t count = ctx->swapchain->imageViews->size;
octx->framebuffers = malloc (sizeof (VkFramebuffer [count]));
for (uint32_t i = 0; i < count; i++) {
rp->beginInfo.framebuffer = 0;
//FIXME come up with a better mechanism
ctx->swapImageIndex = i;
QFV_CreateFramebuffer (ctx, rp);
octx->framebuffers[i] = rp->beginInfo.framebuffer;
QFV_duSetObjectName (device, VK_OBJECT_TYPE_FRAMEBUFFER,
octx->framebuffers[i],
va (ctx->va_ctx, "sc fb:%d", i));
}
for (uint32_t i = 0; i < rp->subpass_count; i++) {
auto sp = &rp->subpasses[i];
for (uint32_t j = 0; j < sp->pipeline_count; j++) {
auto pl = &sp->pipelines[j];
pl->viewport.width = sc->extent.width;
pl->viewport.height = sc->extent.height;
pl->scissor.extent = sc->extent;
}
}
}
ctx->swapImageIndex = imageIndex;
rp->beginInfo.framebuffer = octx->framebuffers[imageIndex];
for (uint32_t i = 0; i < rp->subpass_count; i++) {
auto sp = &rp->subpasses[i];
sp->inherit.framebuffer = rp->beginInfo.framebuffer;
}
}
static void

View file

@ -236,6 +236,9 @@ Vulkan_CreateFrames (vulkan_ctx_t *ctx)
__auto_type frame = &ctx->frames.a[i];
frame->fence = QFV_CreateFence (device, 1);
frame->imageAvailableSemaphore = QFV_CreateSemaphore (device);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_SEMAPHORE,
frame->imageAvailableSemaphore,
va (ctx->va_ctx, "sc image:%zd", i));
frame->renderDoneSemaphore = QFV_CreateSemaphore (device);
frame->cmdBuffer = cmdBuffers->a[i];
}