[vulkan] Add a step and task to create a framebuffer

I don't like the current name (update_framebuffer), but if the
referenced render pass doesn't have a framebuffer, one is created. The
renderpass is referenced via the active renderpass of the named render
step. Unfortunately, this has uncovered a bug in the setup of renderpass
objects: main.deferred has output's renderpass, and main.deferred_cube
and output have bogus renderpass objects.
This commit is contained in:
Bill Currie 2023-06-18 18:42:07 +09:00
parent 8e25fb13d1
commit 2cadf040d3
6 changed files with 123 additions and 75 deletions

View file

@ -313,10 +313,7 @@ typedef struct qfv_renderpass_s {
VkRenderPassBeginInfo beginInfo;
VkSubpassContents subpassContents;
//struct qfv_imageset_s *attachment_images;
//struct qfv_imageviewset_s *attachment_views;
//VkDeviceMemory attachmentMemory;
//size_t attachmentMemory_size;
qfv_framebufferinfo_t *framebufferinfo;
//qfv_output_t output;
uint32_t subpass_count;
@ -386,8 +383,6 @@ void QFV_AppendCmdBuffer (struct vulkan_ctx_s *ctx, VkCommandBuffer cmd);
void QFV_RunRenderJob (struct vulkan_ctx_s *ctx);
void QFV_LoadRenderInfo (struct vulkan_ctx_s *ctx);
void QFV_BuildRender (struct vulkan_ctx_s *ctx);
void QFV_CreateFramebuffer (struct vulkan_ctx_s *ctx);
void QFV_DestroyFramebuffer (struct vulkan_ctx_s *ctx);
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);

View file

@ -118,7 +118,6 @@ vulkan_R_Init (void)
QFV_LoadRenderInfo (vulkan_ctx);
QFV_BuildRender (vulkan_ctx);
QFV_CreateFramebuffer (vulkan_ctx);
Skin_Init ();

View file

@ -252,10 +252,10 @@ QFV_RunRenderJob (vulkan_ctx_t *ctx)
}
}
#if 0
void
QFV_DestroyFramebuffer (vulkan_ctx_t *ctx)
{
#if 0
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
__auto_type rctx = ctx->render_context;
@ -267,31 +267,48 @@ QFV_DestroyFramebuffer (vulkan_ctx_t *ctx)
rp->beginInfo.framebuffer = 0;
dfunc->vkDestroyFramebuffer (device->dev, framebuffer, 0);
}
}
#endif
static VkImageView __attribute__((pure))
find_imageview (qfv_reference_t *ref, qfv_renderctx_t *rctx)
{
__auto_type jinfo = rctx->jobinfo;
__auto_type job = rctx->job;
const char *name = ref->name;
if (strncmp (name, "$imageviews.", 7) == 0) {
name += 7;
}
void
QFV_CreateFramebuffer (vulkan_ctx_t *ctx)
{
#if 0
__auto_type rctx = ctx->render_context;
__auto_type rinfo = rctx->renderinfo;
__auto_type job = rctx->job;
__auto_type rpInfo = &rinfo->renderpasses[0];
__auto_type rp = &job->renderpasses[0];
for (uint32_t i = 0; i < jinfo->num_imageviews; i++) {
__auto_type vi = &jinfo->imageviews[i];
__auto_type vo = &job->image_views[i];
if (strcmp (name, vi->name) == 0) {
return vo->image_view.view;
}
}
Sys_Error ("%d:invalid imageview: %s", ref->line, ref->name);
}
VkImageView attachments[rpInfo->num_attachments];
static void
QFV_CreateFramebuffer (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
__auto_type rctx = ctx->render_context;
auto fb = rp->framebufferinfo;
VkImageView attachments[fb->num_attachments];
VkFramebufferCreateInfo cInfo = {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.attachmentCount = rpInfo->num_attachments,
.attachmentCount = fb->num_attachments,
.pAttachments = attachments,
.renderPass = rp->beginInfo.renderPass,
.width = rpInfo->framebuffer.width,
.height = rpInfo->framebuffer.height,
.layers = rpInfo->framebuffer.layers,
.width = fb->width,
.height = fb->height,
.layers = fb->layers,
};
for (uint32_t i = 0; i < rpInfo->num_attachments; i++) {
attachments[i] = find_imageview (&rpInfo->attachments[i].view, rctx);
for (uint32_t i = 0; i < fb->num_attachments; i++) {
attachments[i] = find_imageview (&fb->attachments[i].view, rctx);
}
qfv_device_t *device = ctx->device;
@ -299,16 +316,82 @@ QFV_CreateFramebuffer (vulkan_ctx_t *ctx)
VkFramebuffer framebuffer;
dfunc->vkCreateFramebuffer (device->dev, &cInfo, 0, &framebuffer);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_FRAMEBUFFER, framebuffer,
va (ctx->va_ctx, "framebuffer:%s", rpInfo->name));
va (ctx->va_ctx, "framebuffer:%s", rp->label.name));
rp->beginInfo.framebuffer = framebuffer;
for (uint32_t i = 0; i < rp->subpass_count; i++) {
__auto_type sp = &rp->subpasses[i];
sp->inherit.framebuffer = framebuffer;
}
#endif
}
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_type frame = &ctx->frames.a[ctx->curFrame];
dfunc->vkWaitForFences (dev, 1, &frame->fence, VK_TRUE, 2000000000);
}
static void
update_framebuffer (const exprval_t **params, exprval_t *result,
exprctx_t *ectx)
{
auto taskctx = (qfv_taskctx_t *) ectx;
auto ctx = taskctx->ctx;
auto stepref = params[0];
// cache the render step referenced, using the parameter type as a flag
// for whether the caching has been performed.
if (stepref->type == &cexpr_string) {
if (cexpr_string.size != cexpr_voidptr.size) {
Sys_Error ("string and voidptr incompatible sizes");
}
auto name = *(const char **)stepref->value;
((exprval_t *) stepref)->type = &cexpr_voidptr;
*(void **)stepref->value = 0;
auto job = ctx->render_context->job;
for (uint32_t i = 0; i < job->num_steps; i++) {
auto step = &job->steps[i];
if (!strcmp (step->label.name, name)) {
*(void **)stepref->value = step;
break;
}
}
}
auto step = *(qfv_step_t **)stepref->value;
auto render = step->render;
auto rp = render->active;
if (!rp->beginInfo.framebuffer) {
QFV_CreateFramebuffer (ctx, rp);
}
}
static exprfunc_t wait_on_fence_func[] = {
{ .func = wait_on_fence },
{}
};
static exprtype_t *update_framebuffer_params[] = {
&cexpr_string,
};
static exprfunc_t update_framebuffer_func[] = {
{ .func = update_framebuffer, .num_params = 1, update_framebuffer_params },
{}
};
static exprsym_t render_task_syms[] = {
{ "wait_on_fence", &cexpr_function, wait_on_fence_func },
{ "update_framebuffer", &cexpr_function, update_framebuffer_func },
{}
};
void
QFV_Render_Init (vulkan_ctx_t *ctx)
{
@ -320,6 +403,8 @@ QFV_Render_Init (vulkan_ctx_t *ctx)
rctx->task_functions.symbols = syms;
cexpr_init_symtab (&rctx->task_functions, &ectx);
rctx->task_functions.symbols = 0;
QFV_Render_AddTasks (ctx, render_task_syms);
}
void
@ -330,7 +415,7 @@ QFV_Render_Shutdown (vulkan_ctx_t *ctx)
__auto_type rctx = ctx->render_context;
if (rctx->job) {
__auto_type job = rctx->job;
QFV_DestroyFramebuffer (ctx); //FIXME do properly
//QFV_DestroyFramebuffer (ctx); //FIXME do properly
for (uint32_t i = 0; i < job->num_renderpasses; i++) {
dfunc->vkDestroyRenderPass (device->dev, job->renderpasses[i], 0);
}

View file

@ -772,15 +772,16 @@ init_renderpass (qfv_renderpass_t *rp, qfv_renderpassinfo_t *rpinfo,
.vulkan_ctx = s->ctx,
.label.name = rpinfo->name,
.label.color = rpinfo->color,
.subpass_count = rpinfo->num_subpasses,
.subpasses = &jp->subpasses[s->inds.num_subpasses],
.beginInfo = (VkRenderPassBeginInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = s->ptr.rp[s->inds.num_renderpasses],
.clearValueCount = rpinfo->framebuffer.num_attachments,
.pClearValues = &jp->clearvalues[s->inds.num_attachments],
},
.framebufferinfo = &rpinfo->framebuffer,
.subpassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS,
.subpass_count = rpinfo->num_subpasses,
.subpasses = &jp->subpasses[s->inds.num_subpasses],
};
s->inds.num_attachments += rpinfo->framebuffer.num_attachments;
for (uint32_t i = 0; i < rpinfo->num_subpasses; i++) {
@ -1127,24 +1128,3 @@ QFV_BuildRender (vulkan_ctx_t *ctx)
create_objects (ctx, &counts);
create_resources (ctx, &counts);
}
static VkImageView __attribute__((pure, used))
find_imageview (qfv_reference_t *ref, qfv_renderctx_t *rctx)
{
__auto_type jinfo = rctx->jobinfo;
__auto_type job = rctx->job;
const char *name = ref->name;
if (strncmp (name, "$imageviews.", 7) == 0) {
name += 7;
}
for (uint32_t i = 0; i < jinfo->num_imageviews; i++) {
__auto_type vi = &jinfo->imageviews[i];
__auto_type vo = &job->image_views[i];
if (strcmp (name, vi->name) == 0) {
return vo->image_view.view;
}
}
Sys_Error ("%d:invalid imageview: %s", ref->line, ref->name);
}

View file

@ -857,34 +857,34 @@ renderpasses = {
loadOp = clear;
finalLayout = depth_stencil_attachment_optimal;
clearValue = { depthStencil = { depth = 1; stencil = 0; }; };
view = $imageviews.depth;
view = depth;
};
color = {
@inherit = $attachment_base;
format = $images.color.format;
loadOp = clear;
view = $imageviews.color;
view = color;
};
emission = {
@inherit = $attachment_base;
format = $images.emission.format;
loadOp = clear;
view = $imageviews.emission;
view = emission;
};
normal = {
@inherit = $attachment_base;
format = $images.normal.format;
view = $imageviews.normal;
view = normal;
};
position = {
@inherit = $attachment_base;
format = $images.position.format;
view = $imageviews.position;
view = position;
};
opaque = {
@inherit = $attachment_base;
format = $images.opaque.format;
view = $imageviews.opaque;
view = opaque;
};
output = {
@inherit = $attachment_base;
@ -892,7 +892,7 @@ renderpasses = {
loadOp = clear;
storeOp = store;
finalLayout = $render_output.finalLayout;
view = $imageviews.output;
view = output;
};
};
};
@ -1334,8 +1334,16 @@ steps = {
);
};
};
setup_main = {
process = {
tasks = (
{ func = "update_framebuffer";
params = ("\"main\""); },
);
};
};
main = {
dependencies = (particles, shadow, translucent);
dependencies = (setup_main, particles, shadow, translucent);
render = {
renderpasses = {
deferred = $renderpasses.deferred;

View file

@ -259,20 +259,6 @@ _output_draw (const exprval_t **params, exprval_t *result, exprctx_t *ectx)
{
}
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_type frame = &ctx->frames.a[ctx->curFrame];
dfunc->vkWaitForFences (dev, 1, &frame->fence, VK_TRUE, 2000000000);
}
static exprfunc_t acquire_output_func[] = {
{ .func = acquire_output },
{}
@ -285,15 +271,10 @@ static exprfunc_t output_draw_func[] = {
{ .func = _output_draw },
{}
};
static exprfunc_t wait_on_fence_func[] = {
{ .func = wait_on_fence },
{}
};
static exprsym_t output_task_syms[] = {
{ "acquire_output", &cexpr_function, acquire_output_func },
{ "update_input", &cexpr_function, update_input_func },
{ "output_draw", &cexpr_function, output_draw_func },
{ "wait_on_fence", &cexpr_function, wait_on_fence_func },
{}
};