[vulkan] Get brush models rendering again

The new system seems to work quite nicely with brush models, which was
the intent, but it's nice to see. Hopefully, it works well when it comes
to shadows. There's still water warp and screen shots to fix, and
fisheye to get working, as well.
This commit is contained in:
Bill Currie 2023-06-25 00:22:03 +09:00
parent 65a63e7423
commit eb176c37e2
3 changed files with 160 additions and 323 deletions

View file

@ -316,13 +316,13 @@ typedef struct bsp_pass_s {
/// \ingroup vulkan_bsp
///@{
typedef enum {
QFV_bspDepth,
QFV_bspGBuffer,
QFV_bspSolid,
QFV_bspSky,
QFV_bspTurb,
QFV_bspTrans, // texture translucency
QFV_bspTurb, // also translucent via r_wateralpha
QFV_bspNumPasses
} QFV_BspSubpass;
} QFV_BspQueue;
typedef struct bspframe_s {
uint32_t *index_data; // pointer into mega-buffer for this frame (c)
@ -380,7 +380,6 @@ typedef struct bspctx_s {
} bspctx_t;
struct vulkan_ctx_s;
void Vulkan_Bsp_Flush (struct vulkan_ctx_s *ctx);
void Vulkan_LoadSkys (const char *sky, struct vulkan_ctx_s *ctx);
void Vulkan_RegisterTextures (model_t **models, int num_models,
struct vulkan_ctx_s *ctx);

View file

@ -1449,6 +1449,15 @@ steps = {
dependencies = (wait_on_fence);
//currently empty
};
world = {
dependencies = (wait_on_fence);
process = {
tasks = (
{ func = bsp_visit_world;
params = (main); },
);
};
};
translucent = {
dependencies = (wait_on_fence);
process = {
@ -1468,7 +1477,7 @@ steps = {
};
};
main = {
dependencies = (setup_main, particles, shadow, translucent);
dependencies = (setup_main, particles, shadow, world, translucent);
render = {
renderpasses = {
deferred = $renderpasses.deferred;

View file

@ -33,12 +33,7 @@
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <string.h>
#include <stdlib.h>
#include "qfalloca.h"
@ -578,7 +573,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx)
}
}
#if 0
static int
R_DrawBrushModel (entity_t ent, bsp_pass_t *pass, vulkan_ctx_t *ctx)
{
@ -607,7 +602,7 @@ R_DrawBrushModel (entity_t ent, bsp_pass_t *pass, vulkan_ctx_t *ctx)
renderer->render_id);
return 1;
}
#endif
static inline void
visit_leaf (mleaf_t *leaf)
{
@ -729,7 +724,7 @@ R_VisitWorldNodes (bsp_pass_t *pass, vulkan_ctx_t *ctx)
break;
}
}
#if 0
static void
bind_texture (vulktex_t *tex, uint32_t setnum, VkPipelineLayout layout,
qfv_devfuncs_t *dfunc, VkCommandBuffer cmd)
@ -763,152 +758,6 @@ push_fragconst (bsp_push_constants_t *constants, VkPipelineLayout layout,
QFV_PushConstants (device, cmd, layout, 4, push_constants);
}
static void
bsp_begin_subpass (QFV_BspSubpass subpass, VkPipeline pipeline,
VkPipelineLayout layout, qfv_orenderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
VkCommandBuffer cmd = bframe->cmdSet.a[subpass];
dfunc->vkResetCommandBuffer (cmd, 0);
VkCommandBufferInheritanceInfo inherit = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0,
rFrame->renderpass->renderpass, subpass_map[subpass],
rFrame->framebuffer,
0, 0, 0,
};
VkCommandBufferBeginInfo beginInfo = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0,
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
| VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit,
};
dfunc->vkBeginCommandBuffer (cmd, &beginInfo);
QFV_duCmdBeginLabel (device, cmd, va (ctx->va_ctx, "bsp:%s",
bsp_pass_names[subpass]),
{0, 0.5, 0.6, 1});
dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline);
dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport);
dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor);
VkBuffer buffers[] = { bctx->vertex_buffer, bctx->entid_buffer };
VkDeviceSize offsets[] = { 0, bframe->entid_offset };
dfunc->vkCmdBindVertexBuffers (cmd, 0, 2, buffers, offsets);
dfunc->vkCmdBindIndexBuffer (cmd, bctx->index_buffer, bframe->index_offset,
VK_INDEX_TYPE_UINT32);
VkDescriptorSet sets[] = {
Vulkan_Matrix_Descriptors (ctx, ctx->curFrame),
Vulkan_Scene_Descriptors (ctx),
Vulkan_Translucent_Descriptors (ctx, ctx->curFrame),
};
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
layout, 0, 3, sets, 0, 0);
//XXX glsl_Fog_GetColor (fog);
//XXX fog[3] = glsl_Fog_GetDensity () / 64.0;
}
static void
bsp_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
QFV_duCmdEndLabel (device, cmd);
dfunc->vkEndCommandBuffer (cmd);
}
static void
bsp_begin (qfv_orenderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
bspctx_t *bctx = ctx->bsp_context;
//XXX quat_t fog;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passDepth],
bframe->cmdSet.a[QFV_bspDepth]);
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passGBuffer],
bframe->cmdSet.a[QFV_bspGBuffer]);
qfvPushDebug (ctx, "bsp_begin_subpass");
bsp_begin_subpass (QFV_bspDepth, bctx->depth, bctx->layout, rFrame);
bsp_begin_subpass (QFV_bspGBuffer, bctx->gbuf, bctx->layout, rFrame);
qfvPopDebug (ctx);
}
static void
bsp_end (vulkan_ctx_t *ctx)
{
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
bsp_end_subpass (bframe->cmdSet.a[QFV_bspDepth], ctx);
bsp_end_subpass (bframe->cmdSet.a[QFV_bspGBuffer], ctx);
}
static void
turb_begin (qfv_orenderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucentFrag],
bframe->cmdSet.a[QFV_bspTurb]);
qfvPushDebug (ctx, "bsp_begin_subpass");
bsp_begin_subpass (QFV_bspTurb, bctx->turb, bctx->layout, rFrame);
qfvPopDebug (ctx);
}
static void
turb_end (vulkan_ctx_t *ctx)
{
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
bsp_end_subpass (bframe->cmdSet.a[QFV_bspTurb], ctx);
}
static void
sky_begin (qfv_orenderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucentFrag],
bframe->cmdSet.a[QFV_bspSky]);
qfvPushDebug (ctx, "bsp_begin_subpass");
if (bctx->skybox_tex) {
bsp_begin_subpass (QFV_bspSky, bctx->skybox, bctx->layout, rFrame);
} else {
bsp_begin_subpass (QFV_bspSky, bctx->skysheet, bctx->layout, rFrame);
}
qfvPopDebug (ctx);
}
static void
sky_end (vulkan_ctx_t *ctx)
{
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
bsp_end_subpass (bframe->cmdSet.a[QFV_bspSky], ctx);
}
#endif
static void
clear_queues (bspctx_t *bctx, bsp_pass_t *pass)
{
@ -924,19 +773,19 @@ clear_queues (bspctx_t *bctx, bsp_pass_t *pass)
}
pass->index_count = 0;
}
#if 0
static void
queue_faces (bsp_pass_t *pass, const bspctx_t *bctx, bspframe_t *bframe)
{
pass->indices = bframe->index_data + bframe->index_count;
for (size_t i = 0; i < bctx->registered_textures.size; i++) {
__auto_type queue = &pass->face_queue[i];
auto queue = &pass->face_queue[i];
if (!queue->size) {
continue;
}
for (size_t j = 0; j < queue->size; j++) {
__auto_type is = queue->a[j];
__auto_type f = bctx->faces[is.face];
auto is = queue->a[j];
auto f = bctx->faces[is.face];
f.flags |= ((is.inst_id & INST_ALPHA)
>> (BITOP_LOG2(INST_ALPHA)
@ -990,13 +839,13 @@ queue_faces (bsp_pass_t *pass, const bspctx_t *bctx, bspframe_t *bframe)
}
static void
draw_queue (bsp_pass_t *pass, int queue, VkPipelineLayout layout,
draw_queue (bsp_pass_t *pass, QFV_BspQueue queue, VkPipelineLayout layout,
qfv_device_t *device, VkCommandBuffer cmd)
{
qfv_devfuncs_t *dfunc = device->funcs;
for (size_t i = 0; i < pass->draw_queues[queue].size; i++) {
__auto_type d = pass->draw_queues[queue].a[i];
auto d = pass->draw_queues[queue].a[i];
if (pass->textures) {
vulktex_t *tex = pass->textures->a[d.tex_id];
bind_texture (tex, TEX_SET, layout, dfunc, cmd);
@ -1016,77 +865,8 @@ ent_model_cmp (const void *_a, const void *_b)
return ra->model->render_id - rb->model->render_id;
}
void
Vulkan_DrawWorld (qfv_orenderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device;
//qfv_devfuncs_t *dfunc = device->funcs;
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
bctx->main_pass.bsp_context = bctx;
bctx->main_pass.position = r_refdef.frame.position;
bctx->main_pass.vis_frame = r_visframecount;
bctx->main_pass.face_frames = r_face_visframes;
bctx->main_pass.leaf_frames = r_leaf_visframes;
bctx->main_pass.node_frames = r_node_visframes;
bctx->main_pass.entid_data = bframe->entid_data;
bctx->main_pass.entid_count = 0;
bctx->anim_index = r_data->realtime * 5;
clear_queues (bctx, &bctx->main_pass); // do this first for water and skys
bframe->index_count = 0;
entity_t worldent = nullentity;
int world_id = Vulkan_Scene_AddEntity (ctx, worldent);
bctx->main_pass.ent_frame = 0; // world is always frame 0
bctx->main_pass.inst_id = world_id;
bctx->main_pass.brush = &r_refdef.worldmodel->brush;
if (bctx->main_pass.instances) {
DARRAY_APPEND (&bctx->main_pass.instances[world_id].entities, world_id);
}
R_VisitWorldNodes (&bctx->main_pass, ctx);
if (!bctx->vertex_buffer) {
return;
}
if (r_drawentities) {
heapsort (r_ent_queue->ent_queues[mod_brush].a,
r_ent_queue->ent_queues[mod_brush].size,
sizeof (entity_t), ent_model_cmp);
for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) {
entity_t ent = r_ent_queue->ent_queues[mod_brush].a[i];
if (!R_DrawBrushModel (ent, &bctx->main_pass, ctx)) {
Sys_Printf ("Too many entities!\n");
break;
}
}
}
bframe->entid_count = bctx->main_pass.entid_count;
queue_faces (&bctx->main_pass, bctx, bframe);
bsp_begin (rFrame);
bsp_push_constants_t frag_constants = { .time = vr_data.realtime };
push_fragconst (&frag_constants, bctx->layout, device,
bframe->cmdSet.a[QFV_bspGBuffer]);
VkPipelineLayout layout = bctx->layout;
__auto_type pass = &bctx->main_pass;
pass->textures = 0;
draw_queue (pass, 0, layout, device, bframe->cmdSet.a[QFV_bspDepth]);
draw_queue (pass, 1, layout, device, bframe->cmdSet.a[QFV_bspDepth]);
pass->textures = &bctx->registered_textures;
draw_queue (pass, 0, layout, device, bframe->cmdSet.a[QFV_bspGBuffer]);
bsp_end (ctx);
}
#endif
void
Vulkan_Bsp_Flush (vulkan_ctx_t *ctx)
static void
bsp_flush (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
@ -1117,71 +897,7 @@ Vulkan_Bsp_Flush (vulkan_ctx_t *ctx)
};
dfunc->vkFlushMappedMemoryRanges (device->dev, 2, ranges);
}
#if 0
void
Vulkan_DrawWaterSurfaces (qfv_orenderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device;
//qfv_devfuncs_t *dfunc = device->funcs;
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
if (!bctx->main_pass.draw_queues[3].size)
return;
turb_begin (rFrame);
VkPipelineLayout layout = bctx->layout;
bsp_push_constants_t frag_constants = {
.time = vr_data.realtime,
.alpha = 1,
.turb_scale = 0,
};
push_fragconst (&frag_constants, layout, device,
bframe->cmdSet.a[QFV_bspTurb]);
__auto_type pass = &bctx->main_pass;
pass->textures = &bctx->registered_textures;
draw_queue (pass, 2, layout, device, bframe->cmdSet.a[QFV_bspTurb]);
frag_constants.alpha = r_wateralpha;
frag_constants.turb_scale = 1;
push_fragconst (&frag_constants, bctx->layout, device,
bframe->cmdSet.a[QFV_bspTurb]);
draw_queue (pass, 3, layout, device, bframe->cmdSet.a[QFV_bspTurb]);
turb_end (ctx);
}
void
Vulkan_DrawSky (qfv_orenderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
if (!bctx->main_pass.draw_queues[1].size)
return;
sky_begin (rFrame);
vulktex_t skybox = { .descriptor = bctx->skybox_descriptor };
bind_texture (&skybox, SKYBOX_SET, bctx->layout, dfunc,
bframe->cmdSet.a[QFV_bspSky]);
bsp_push_constants_t frag_constants = { .time = vr_data.realtime };
push_fragconst (&frag_constants, bctx->layout, device,
bframe->cmdSet.a[QFV_bspSky]);
VkPipelineLayout layout = bctx->layout;
__auto_type pass = &bctx->main_pass;
pass->textures = &bctx->registered_textures;
draw_queue (pass, 1, layout, device, bframe->cmdSet.a[QFV_bspSky]);
sky_end (ctx);
}
#endif
static void
create_default_skys (vulkan_ctx_t *ctx)
{
@ -1359,27 +1075,126 @@ bsp_draw_queue (const exprval_t **params, exprval_t *result, exprctx_t *ectx)
{
auto taskctx = (qfv_taskctx_t *) ectx;
auto ctx = taskctx->ctx;
auto device = ctx->device;
auto dfunc = device->funcs;
auto bctx = ctx->bsp_context;
int pass = *(int *) params[2]->value;
if (!pass && r_refdef.worldmodel) {
bctx->main_pass.bsp_context = bctx;
bctx->main_pass.position = r_refdef.frame.position;
bctx->main_pass.vis_frame = r_visframecount;
bctx->main_pass.face_frames = r_face_visframes;
bctx->main_pass.leaf_frames = r_leaf_visframes;
bctx->main_pass.node_frames = r_node_visframes;
//bctx->main_pass.entid_data = bframe->entid_data;
//bctx->main_pass.entid_count = 0;
auto layout = taskctx->pipeline->layout;
auto cmd = taskctx->cmd;
EntQueue_Clear (r_ent_queue);
clear_queues (bctx, &bctx->main_pass); // do this first for water and skys
entity_t worldent = nullentity;
int world_id = Vulkan_Scene_AddEntity (ctx, worldent);
bctx->main_pass.ent_frame = 0; // world is always frame 0
bctx->main_pass.inst_id = world_id;
bctx->main_pass.brush = &r_refdef.worldmodel->brush;
R_VisitWorldNodes (&bctx->main_pass, ctx);
if (!bctx->vertex_buffer) {
return;
}
// params are in reverse order
auto stage = *(int *) params[2]->value;
auto queue = *(QFV_BspQueue *) params[1]->value;
auto pass = *(int *) params[0]->value;
if (stage) {
Sys_Error ("bps stages not implemented");
}
auto mpass = &bctx->main_pass;
if (!mpass->draw_queues[queue].size) {
return;
}
auto bframe = &bctx->frames.a[ctx->curFrame];
VkBuffer buffers[] = { bctx->vertex_buffer, bctx->entid_buffer };
VkDeviceSize offsets[] = { 0, bframe->entid_offset };
dfunc->vkCmdBindVertexBuffers (cmd, 0, 2, buffers, offsets);
dfunc->vkCmdBindIndexBuffer (cmd, bctx->index_buffer, bframe->index_offset,
VK_INDEX_TYPE_UINT32);
VkDescriptorSet sets[] = {
Vulkan_Matrix_Descriptors (ctx, ctx->curFrame),
Vulkan_Scene_Descriptors (ctx),
Vulkan_Translucent_Descriptors (ctx, ctx->curFrame),
};
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
layout, 0, 3, sets, 0, 0);
//XXX glsl_Fog_GetColor (fog);
//XXX fog[3] = glsl_Fog_GetDensity () / 64.0;
bsp_push_constants_t frag_constants = {
.time = vr_data.realtime,
.alpha = queue == QFV_bspTurb ? r_wateralpha : 1,
.turb_scale = queue == QFV_bspTurb ? 1 : 0,
};
push_fragconst (&frag_constants, layout, device, cmd);
if (queue == QFV_bspSky) {
vulktex_t skybox = { .descriptor = bctx->skybox_descriptor };
bind_texture (&skybox, SKYBOX_SET, layout, dfunc, cmd);
}
mpass->textures = pass ? &bctx->registered_textures : 0;
draw_queue (mpass, queue, layout, device, cmd);
}
static void
bsp_visit_world (const exprval_t **params, exprval_t *result, exprctx_t *ectx)
{
auto taskctx = (qfv_taskctx_t *) ectx;
auto ctx = taskctx->ctx;
auto stage = *(int *) params[0]->value;
if (stage) {
Sys_Error ("bps stages not implemented");
}
EntQueue_Clear (r_ent_queue);
Vulkan_Scene_Flush (ctx);
auto bctx = ctx->bsp_context;
clear_queues (bctx, &bctx->main_pass); // do this first for water and skys
if (!r_refdef.worldmodel) {
return;
}
auto bframe = &bctx->frames.a[ctx->curFrame];
bctx->main_pass.bsp_context = bctx;
bctx->main_pass.position = r_refdef.frame.position;
bctx->main_pass.vis_frame = r_visframecount;
bctx->main_pass.face_frames = r_face_visframes;
bctx->main_pass.leaf_frames = r_leaf_visframes;
bctx->main_pass.node_frames = r_node_visframes;
bctx->main_pass.entid_data = bframe->entid_data;
bctx->main_pass.entid_count = 0;
bctx->anim_index = r_data->realtime * 5;
bframe->index_count = 0;
entity_t worldent = nullentity;
int world_id = Vulkan_Scene_AddEntity (ctx, worldent);
bctx->main_pass.ent_frame = 0; // world is always frame 0
bctx->main_pass.inst_id = world_id;
bctx->main_pass.brush = &r_refdef.worldmodel->brush;
if (bctx->main_pass.instances) {
DARRAY_APPEND (&bctx->main_pass.instances[world_id].entities, world_id);
}
R_VisitWorldNodes (&bctx->main_pass, ctx);
if (r_drawentities) {
heapsort (r_ent_queue->ent_queues[mod_brush].a,
r_ent_queue->ent_queues[mod_brush].size,
sizeof (entity_t), ent_model_cmp);
for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) {
entity_t ent = r_ent_queue->ent_queues[mod_brush].a[i];
if (!R_DrawBrushModel (ent, &bctx->main_pass, ctx)) {
Sys_Printf ("Too many entities!\n");
break;
}
}
}
bframe->entid_count = bctx->main_pass.entid_count;
queue_faces (&bctx->main_pass, bctx, bframe);
bsp_flush (ctx);
}
static exprenum_t bsp_stage_enum;
@ -1407,7 +1222,12 @@ static exprtype_t bsp_queue_type = {
.get_string = cexpr_enum_get_string,
.data = &bsp_queue_enum,
};
static int bsp_queue_values[] = { 0, 1, 2, 3, };
static int bsp_queue_values[] = {
QFV_bspSolid,
QFV_bspSky,
QFV_bspTrans,
QFV_bspTurb,
};
static exprsym_t bsp_queue_symbols[] = {
{"solid", &bsp_queue_type, bsp_queue_values + 0},
{"sky", &bsp_queue_type, bsp_queue_values + 1},
@ -1421,17 +1241,26 @@ static exprenum_t bsp_queue_enum = {
&bsp_queue_symtab,
};
static exprtype_t *bsp_visit_world_params[] = {
&bsp_stage_type,
};
static exprtype_t *bsp_draw_queue_params[] = {
&cexpr_int,
&bsp_queue_type,
&bsp_stage_type,
};
static exprfunc_t bsp_visit_world_func[] = {
{ 0, 1, bsp_visit_world_params, bsp_visit_world },
{}
};
static exprfunc_t bsp_draw_queue_func[] = {
{ 0, 3, bsp_draw_queue_params, bsp_draw_queue },
{}
};
static exprsym_t bsp_task_syms[] = {
{ "bsp_visit_world", &cexpr_function, bsp_visit_world_func },
{ "bsp_draw_queue", &cexpr_function, bsp_draw_queue_func },
{}
};
@ -1505,7 +1334,7 @@ Vulkan_Bsp_Setup (vulkan_ctx_t *ctx)
frames * entid_size, 0, (void **) &entid_data);
for (size_t i = 0; i < frames; i++) {
__auto_type bframe = &bctx->frames.a[i];
auto bframe = &bctx->frames.a[i];
DARRAY_INIT (&bframe->cmdSet, QFV_bspNumPasses);
DARRAY_RESIZE (&bframe->cmdSet, QFV_bspNumPasses);
@ -1543,7 +1372,7 @@ Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx)
bspctx_t *bctx = ctx->bsp_context;
for (size_t i = 0; i < bctx->frames.size; i++) {
__auto_type bframe = &bctx->frames.a[i];
auto bframe = &bctx->frames.a[i];
free (bframe->cmdSet.a);
}