From d2e85f775d1c9900c8b3a3ba0223694178586e8a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 22 Jun 2023 20:27:55 +0900 Subject: [PATCH] [vulkan] Get alias model rendering mostly working Mostly because no lighting or compositing to the output buffer is done, but the model is there in renderdoc's image viewer. --- include/QF/Vulkan/qf_alias.h | 6 - libs/video/renderer/vid_render_vulkan.c | 2 + libs/video/renderer/vulkan/rp_main_def.plist | 26 +- libs/video/renderer/vulkan/vulkan_alias.c | 225 +++++------------- libs/video/renderer/vulkan/vulkan_bsp.c | 25 +- libs/video/renderer/vulkan/vulkan_main.c | 12 +- libs/video/renderer/vulkan/vulkan_output.c | 4 +- libs/video/renderer/vulkan/vulkan_particles.c | 1 - .../renderer/vulkan/vulkan_translucent.c | 9 +- 9 files changed, 108 insertions(+), 202 deletions(-) diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index c1326e82a..cdcc52a51 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -106,13 +106,7 @@ void Vulkan_Mod_MakeAliasModelDisplayLists (struct mod_alias_ctx_s *alias_ctx, void Vulkan_AliasAddSkin (struct vulkan_ctx_s *ctx, qfv_alias_skin_t *skin); void Vulkan_AliasRemoveSkin (struct vulkan_ctx_s *ctx, qfv_alias_skin_t *skin); -void Vulkan_AliasBegin (struct qfv_orenderframe_s *rFrame); -void Vulkan_DrawAlias (struct entity_s ent, struct qfv_orenderframe_s *rFrame); -void Vulkan_AliasEnd (struct qfv_orenderframe_s *rFrame); - void Vulkan_Alias_Init (struct vulkan_ctx_s *ctx); void Vulkan_Alias_Shutdown (struct vulkan_ctx_s *ctx); -void Vulkan_AliasDepthRange (struct qfv_orenderframe_s *rFrame, float n, float f); - #endif//__QF_Vulkan_qf_alias_h diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 8e06409ea..cb81f7ddd 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -127,7 +127,9 @@ static void vulkan_R_ClearState (void) { QFV_DeviceWaitIdle (vulkan_ctx->device); + //FIXME clear scene correctly r_refdef.worldmodel = 0; + EntQueue_Clear (r_ent_queue); R_ClearDlights (); R_ClearParticles (); Vulkan_LoadLights (0, vulkan_ctx); diff --git a/libs/video/renderer/vulkan/rp_main_def.plist b/libs/video/renderer/vulkan/rp_main_def.plist index a666ccb45..dcecf51bd 100644 --- a/libs/video/renderer/vulkan/rp_main_def.plist +++ b/libs/video/renderer/vulkan/rp_main_def.plist @@ -280,7 +280,7 @@ properties = { bindings = ( { binding = 0; stride = "2 * 4 * 4"; inputRate = vertex; }, { binding = 1; stride = "2 * 4 * 4"; inputRate = vertex; }, - { binding = 2; stride = "2 * 4"; inputRate = instance; }, + { binding = 2; stride = "2 * 4"; inputRate = vertex; }, ); attributes = ( { location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0; }, @@ -983,9 +983,9 @@ renderpasses = { color = $color.bsp; tasks = ( { func = bsp_draw_queue; - params = (main, solid); }, + params = (main, solid, 0); }, { func = bsp_draw_queue; - params = (main, sky); }, + params = (main, sky, 0); }, ); stages = ( @@ -1007,7 +1007,8 @@ renderpasses = { alias:depth = { color = $color.alias; tasks = ( - { func = alias_draw; }, + { func = alias_draw; + params = (0); }, ); stages = ( @@ -1076,7 +1077,7 @@ renderpasses = { tasks = ( // FIXME sky should not use OIT { func = bsp_draw_queue; - params = (main, sky); }, + params = (main, sky, 1); }, ); stages = ( @@ -1092,7 +1093,7 @@ renderpasses = { tasks = ( // FIXME sky should not use OIT { func = bsp_draw_queue; - params = (main, sky); }, + params = (main, sky, 1); }, ); stages = ( @@ -1107,9 +1108,9 @@ renderpasses = { color = $color.bsp; tasks = ( { func = bsp_draw_queue; - params = (main, translucent); }, + params = (main, translucent, 2); }, { func = bsp_draw_queue; - params = (main, turbulent); }, + params = (main, turbulent, 2); }, ); stages = ( @@ -1172,9 +1173,9 @@ renderpasses = { color = $color.bsp; tasks = ( { func = bsp_draw_queue; - params = (main, solid); }, + params = (main, solid, 1); }, { func = bsp_draw_queue; - params = (main, sky); }, + params = (main, sky, 1); }, ); stages = ( @@ -1189,7 +1190,8 @@ renderpasses = { alias:gbuffer = { color = $color.alias; tasks = ( - { func = alias_draw; }, + { func = alias_draw; + params = (1); }, ); stages = ( @@ -1385,7 +1387,6 @@ steps = { ); }; }; -/* particles = { dependencies = (wait_on_fence); compute = { @@ -1444,7 +1445,6 @@ steps = { }; }; }; -*/ preoutput = { dependencies = (wait_on_fence); process = { diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index c41461775..ec0126624 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -43,7 +43,6 @@ #include "QF/Vulkan/qf_alias.h" #include "QF/Vulkan/qf_matrices.h" #include "QF/Vulkan/qf_palette.h" -#include "QF/Vulkan/qf_renderpass.h" #include "QF/Vulkan/qf_texture.h" #include "QF/Vulkan/debug.h" #include "QF/Vulkan/device.h" @@ -61,25 +60,12 @@ typedef struct { vec4f_t fog; } alias_push_constants_t; -static const char * __attribute__((used)) alias_pass_names[] = { - "depth", - "g-buffer", - "translucent", -}; - -static QFV_Subpass subpass_map[] = { - QFV_passDepth, // QFV_aliasDepth - QFV_passGBuffer, // QFV_aliasGBuffer - QFV_passTranslucentFrag,// QFV_aliasTranslucent -}; - static void emit_commands (VkCommandBuffer cmd, int pose1, int pose2, qfv_alias_skin_t *skin, uint32_t numPC, qfv_push_constants_t *constants, - aliashdr_t *hdr, qfv_orenderframe_t *rFrame, entity_t ent) + aliashdr_t *hdr, vulkan_ctx_t *ctx, entity_t ent) { - vulkan_ctx_t *ctx = rFrame->vulkan_ctx; qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; aliasctx_t *actx = ctx->alias_context; @@ -116,14 +102,41 @@ emit_commands (VkCommandBuffer cmd, int pose1, int pose2, QFV_CmdEndLabel (device, cmd); } -void -Vulkan_DrawAlias (entity_t ent, qfv_orenderframe_t *rFrame) +static void +alias_depth_range (qfv_taskctx_t *taskctx, float minDepth, float maxDepth) +{ + auto ctx = taskctx->ctx; + auto device = ctx->device; + auto dfunc = device->funcs; + + auto viewport = taskctx->pipeline->viewport; + viewport.minDepth = minDepth; + viewport.maxDepth = maxDepth; + + dfunc->vkCmdSetViewport (taskctx->cmd, 0, 1, &viewport); +} + +void +Vulkan_AliasAddSkin (vulkan_ctx_t *ctx, qfv_alias_skin_t *skin) { - vulkan_ctx_t *ctx = rFrame->vulkan_ctx; aliasctx_t *actx = ctx->alias_context; - aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + skin->descriptor = Vulkan_CreateCombinedImageSampler (ctx, skin->view, + actx->sampler); +} + +void +Vulkan_AliasRemoveSkin (vulkan_ctx_t *ctx, qfv_alias_skin_t *skin) +{ + Vulkan_FreeTexture (ctx, skin->descriptor); + skin->descriptor = 0; +} + +static void +alias_draw_ent (qfv_taskctx_t *taskctx, entity_t ent, bool pass) +{ + auto ctx = taskctx->ctx; renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, ent.reg); - model_t *model = renderer->model; + auto model = renderer->model; aliashdr_t *hdr; qfv_alias_skin_t *skin; alias_push_constants_t constants = {}; @@ -171,138 +184,52 @@ Vulkan_DrawAlias (entity_t ent, qfv_orenderframe_t *rFrame) } QuatZero (constants.fog); - emit_commands (aframe->cmdSet.a[QFV_aliasDepth], - animation->pose1, animation->pose2, - 0, 2, push_constants, hdr, rFrame, ent); - emit_commands (aframe->cmdSet.a[QFV_aliasGBuffer], - animation->pose1, animation->pose2, - skin, 5, push_constants, hdr, rFrame, ent); + emit_commands (taskctx->cmd, animation->pose1, animation->pose2, + pass ? skin : 0, + pass ? 5 : 2, push_constants, + hdr, ctx, ent); } static void -alias_begin_subpass (QFV_AliasSubpass subpass, VkPipeline pipeline, - qfv_orenderframe_t *rFrame) +alias_draw (const exprval_t **params, exprval_t *result, exprctx_t *ectx) { - vulkan_ctx_t *ctx = rFrame->vulkan_ctx; - qfv_device_t *device = ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; - aliasctx_t *actx = ctx->alias_context; - uint32_t curFrame = ctx->curFrame; - aliasframe_t *aframe = &actx->frames.a[curFrame]; - VkCommandBuffer cmd = aframe->cmdSet.a[subpass]; + auto taskctx = (qfv_taskctx_t *) ectx; + bool vmod = Entity_Valid (vr_data.view_model); + int pass = *(int *) params[0]->value; - 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, "alias:%s", - alias_pass_names[subpass]), - { 0.6, 0.5, 0, 1}); - - dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + auto ctx = taskctx->ctx; + auto device = ctx->device; + auto dfunc = device->funcs; + auto actx = ctx->alias_context; + auto cmd = taskctx->cmd; VkDescriptorSet sets[] = { Vulkan_Matrix_Descriptors (ctx, ctx->curFrame), Vulkan_Palette_Descriptor (ctx), }; dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, actx->layout, 0, 2, sets, 0, 0); - dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport); - dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor); - //XXX glsl_Fog_GetColor (fog); - //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; -} - -static void -alias_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); -} - -void -Vulkan_AliasBegin (qfv_orenderframe_t *rFrame) -{ - vulkan_ctx_t *ctx = rFrame->vulkan_ctx; - aliasctx_t *actx = ctx->alias_context; - aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; - - //XXX quat_t fog; - DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passDepth], - aframe->cmdSet.a[QFV_aliasDepth]); - DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passGBuffer], - aframe->cmdSet.a[QFV_aliasGBuffer]); - - alias_begin_subpass (QFV_aliasDepth, actx->depth, rFrame); - alias_begin_subpass (QFV_aliasGBuffer, actx->gbuf, rFrame); -} - -void -Vulkan_AliasEnd (qfv_orenderframe_t *rFrame) -{ - vulkan_ctx_t *ctx = rFrame->vulkan_ctx; - aliasctx_t *actx = ctx->alias_context; - aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; - - alias_end_subpass (aframe->cmdSet.a[QFV_aliasDepth], ctx); - alias_end_subpass (aframe->cmdSet.a[QFV_aliasGBuffer], ctx); -} - -void -Vulkan_AliasDepthRange (qfv_orenderframe_t *rFrame, - float minDepth, float maxDepth) -{ - vulkan_ctx_t *ctx = rFrame->vulkan_ctx; - qfv_device_t *device = ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; - aliasctx_t *actx = ctx->alias_context; - aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; - - VkViewport viewport = rFrame->renderpass->viewport; - viewport.minDepth = minDepth; - viewport.maxDepth = maxDepth; - - dfunc->vkCmdSetViewport (aframe->cmdSet.a[QFV_aliasDepth], 0, 1, - &viewport); - dfunc->vkCmdSetViewport (aframe->cmdSet.a[QFV_aliasGBuffer], 0, 1, - &viewport); -} - -void -Vulkan_AliasAddSkin (vulkan_ctx_t *ctx, qfv_alias_skin_t *skin) -{ - aliasctx_t *actx = ctx->alias_context; - skin->descriptor = Vulkan_CreateCombinedImageSampler (ctx, skin->view, - actx->sampler); -} - -void -Vulkan_AliasRemoveSkin (vulkan_ctx_t *ctx, qfv_alias_skin_t *skin) -{ - Vulkan_FreeTexture (ctx, skin->descriptor); - skin->descriptor = 0; -} - -static void -alias_draw (const exprval_t **params, exprval_t *result, exprctx_t *ectx) -{ + auto queue = r_ent_queue; //FIXME fetch from scene + for (size_t i = 0; i < queue->ent_queues[mod_alias].size; i++) { + entity_t ent = queue->ent_queues[mod_alias].a[i]; + // FIXME hack the depth range to prevent view model + // from poking into walls + if (vmod && ent.id == vr_data.view_model.id) { + alias_depth_range (taskctx, 0, 0.3); + } + alias_draw_ent (taskctx, ent, pass); + // unhack in case the view_model is not the last + if (vmod && ent.id == vr_data.view_model.id) { + alias_depth_range (taskctx, 0, 1); + } + } } +static exprtype_t *alias_draw_params[] = { + &cexpr_int, +}; static exprfunc_t alias_draw_func[] = { - { .func = alias_draw }, + { .func = alias_draw, .num_params = 1, .param_types = alias_draw_params }, {} }; static exprsym_t alias_task_syms[] = { @@ -313,8 +240,6 @@ static exprsym_t alias_task_syms[] = { void Vulkan_Alias_Init (vulkan_ctx_t *ctx) { - qfv_device_t *device = ctx->device; - qfvPushDebug (ctx, "alias init"); QFV_Render_AddTasks (ctx, alias_task_syms); @@ -331,23 +256,6 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) actx->gbuf = Vulkan_CreateGraphicsPipeline (ctx, "alias_gbuf"); actx->layout = Vulkan_CreatePipelineLayout (ctx, "alias_layout"); actx->sampler = Vulkan_CreateSampler (ctx, "alias_sampler"); - - for (size_t i = 0; i < frames; i++) { - __auto_type aframe = &actx->frames.a[i]; - - DARRAY_INIT (&aframe->cmdSet, QFV_aliasNumPasses); - DARRAY_RESIZE (&aframe->cmdSet, QFV_aliasNumPasses); - aframe->cmdSet.grow = 0; - - QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, &aframe->cmdSet); - - for (int j = 0; j < QFV_aliasNumPasses; j++) { - QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, - aframe->cmdSet.a[j], - va (ctx->va_ctx, "cmd:alias:%zd:%s", i, - alias_pass_names[j])); - } - } qfvPopDebug (ctx); } @@ -358,11 +266,6 @@ Vulkan_Alias_Shutdown (vulkan_ctx_t *ctx) qfv_devfuncs_t *dfunc = device->funcs; aliasctx_t *actx = ctx->alias_context; - for (size_t i = 0; i < actx->frames.size; i++) { - __auto_type aframe = &actx->frames.a[i]; - free (aframe->cmdSet.a); - } - dfunc->vkDestroyPipeline (device->dev, actx->depth, 0); dfunc->vkDestroyPipeline (device->dev, actx->gbuf, 0); free (actx->frames.a); diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index ce021a5e0..a680b37b0 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -1365,6 +1365,28 @@ create_notexture (vulkan_ctx_t *ctx) static void bsp_draw_queue (const exprval_t **params, exprval_t *result, exprctx_t *ectx) { + auto taskctx = (qfv_taskctx_t *) ectx; + auto ctx = taskctx->ctx; + 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; + + 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); + } } static exprenum_t bsp_stage_enum; @@ -1407,12 +1429,13 @@ static exprenum_t bsp_queue_enum = { }; static exprtype_t *bsp_draw_queue_params[] = { + &cexpr_int, &bsp_queue_type, &bsp_stage_type, }; static exprfunc_t bsp_draw_queue_func[] = { - { 0, 2, bsp_draw_queue_params, bsp_draw_queue }, + { 0, 3, bsp_draw_queue_params, bsp_draw_queue }, {} }; static exprsym_t bsp_task_syms[] = { diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index 6ac19052d..43402179a 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -74,7 +74,6 @@ Vulkan_RenderEntities (entqueue_t *queue, qfv_orenderframe_t *rFrame) if (!r_drawentities) return; //FIXME need a better way (components? but HasComponent isn't free) - int vmod = Entity_Valid (vr_data.view_model); #define RE_LOOP(type_name, Type) \ do { \ int begun = 0; \ @@ -85,22 +84,12 @@ Vulkan_RenderEntities (entqueue_t *queue, qfv_orenderframe_t *rFrame) Vulkan_##Type##Begin (rFrame); \ begun = 1; \ } \ - /* FIXME hack the depth range to prevent view model */\ - /* from poking into walls */\ - if (vmod && ent.id == vr_data.view_model.id) { \ - Vulkan_AliasDepthRange (rFrame, 0, 0.3); \ - } \ Vulkan_Draw##Type (ent, rFrame); \ - /* unhack in case the view_model is not the last */\ - if (vmod && ent.id == vr_data.view_model.id) { \ - Vulkan_AliasDepthRange (rFrame, 0, 1); \ - } \ } \ if (begun) \ Vulkan_##Type##End (rFrame); \ } while (0) - RE_LOOP (alias, Alias); RE_LOOP (iqm, IQM); RE_LOOP (sprite, Sprite); } @@ -153,6 +142,7 @@ Vulkan_NewScene (scene_t *scene, vulkan_ctx_t *ctx) } r_refdef.worldmodel = scene->worldmodel; + EntQueue_Clear (r_ent_queue); // Force a vis update R_MarkLeaves (0, 0, 0, 0); diff --git a/libs/video/renderer/vulkan/vulkan_output.c b/libs/video/renderer/vulkan/vulkan_output.c index 5581f78ec..130441c65 100644 --- a/libs/video/renderer/vulkan/vulkan_output.c +++ b/libs/video/renderer/vulkan/vulkan_output.c @@ -294,11 +294,11 @@ static exprtype_t *stepref_param[] = { &cexpr_string, }; static exprfunc_t acquire_output_func[] = { - { .func = acquire_output, .num_params = 1, stepref_param }, + { .func = acquire_output, .num_params = 1, .param_types = stepref_param }, {} }; static exprfunc_t update_input_func[] = { - { .func = update_input, .num_params = 1, stepref_param }, + { .func = update_input, .num_params = 1, .param_types = stepref_param }, {} }; static exprfunc_t output_draw_func[] = { diff --git a/libs/video/renderer/vulkan/vulkan_particles.c b/libs/video/renderer/vulkan/vulkan_particles.c index 1a9b26cda..6bd22a0c9 100644 --- a/libs/video/renderer/vulkan/vulkan_particles.c +++ b/libs/video/renderer/vulkan/vulkan_particles.c @@ -277,7 +277,6 @@ create_buffers (vulkan_ctx_t *ctx) static void particles_draw (const exprval_t **params, exprval_t *result, exprctx_t *ectx) { - puts ("particles_draw"); } static void diff --git a/libs/video/renderer/vulkan/vulkan_translucent.c b/libs/video/renderer/vulkan/vulkan_translucent.c index e69951df6..c533efe94 100644 --- a/libs/video/renderer/vulkan/vulkan_translucent.c +++ b/libs/video/renderer/vulkan/vulkan_translucent.c @@ -76,14 +76,9 @@ clear_translucent (const exprval_t **params, exprval_t *result, exprctx_t *ectx) VkCommandBuffer cmd = QFV_GetCmdBuffer (ctx, false); - VkCommandBufferInheritanceInfo inherit = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, - 0, 0, 0, - 0, 0, 0, - }; VkCommandBufferBeginInfo beginInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, &inherit, + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, }; dfunc->vkBeginCommandBuffer (cmd, &beginInfo);