mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[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:
parent
503013dd38
commit
25cfef18d6
6 changed files with 108 additions and 35 deletions
|
@ -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;
|
||||
|
|
|
@ -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__
|
||||
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -1348,8 +1348,6 @@ steps = {
|
|||
tasks = (
|
||||
{ func = acquire_output;
|
||||
params = ("\"output\""); },
|
||||
{ func = update_framebuffer;
|
||||
params = ("\"output\""); },
|
||||
{ func = update_input; },
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue