From 3c65f1494b542636425122301f57e6b602884a18 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 15 Jun 2023 15:17:39 +0900 Subject: [PATCH] [vulkan] Get some subsystems passing validation This is with the new render job scheme. I very much doubt it actually works (can't start testing until everything passes, and it's disabled for the moment (define in vid_render_vulkan.c)), but it's helping iron out what more is needed in the render system. --- include/QF/Vulkan/render.h | 5 +- libs/video/renderer/vid_render_vulkan.c | 13 ++- libs/video/renderer/vulkan/render.c | 28 +++-- libs/video/renderer/vulkan/rp_main_def.plist | 11 ++ libs/video/renderer/vulkan/vulkan_output.c | 19 ++++ libs/video/renderer/vulkan/vulkan_particles.c | 107 +++++++++++++++++- .../renderer/vulkan/vulkan_translucent.c | 51 +++++++++ 7 files changed, 221 insertions(+), 13 deletions(-) diff --git a/include/QF/Vulkan/render.h b/include/QF/Vulkan/render.h index e9a0044b7..8c0469dfe 100644 --- a/include/QF/Vulkan/render.h +++ b/include/QF/Vulkan/render.h @@ -263,7 +263,7 @@ typedef struct qfv_bar_s { typedef struct qfv_pipeline_s { qfv_label_t label; VkPipelineBindPoint bindPoint; - uint32_t dispatch[3]; + vec4u_t dispatch; VkPipeline pipeline; VkPipelineLayout layout; @@ -360,6 +360,9 @@ typedef struct qfv_taskctx_s { qfv_pipeline_t *pipeline; } qfv_taskctx_t; +VkCommandBuffer QFV_GetCmdBufffer (struct vulkan_ctx_s *ctx, bool secondary); +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); diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index ae6db3ebf..a5b110146 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -308,7 +308,8 @@ vulkan_Draw_Glyph (int x, int y, int fontid, int glyphid, int c) { Vulkan_Draw_Glyph (x, y, fontid, glyphid, c, vulkan_ctx); } - +//#define TEST_RENDER +#ifndef TEST_RENDER static void vulkan_begin_frame (void) { @@ -479,10 +480,17 @@ vulkan_end_frame (void) vulkan_ctx->curFrame++; vulkan_ctx->curFrame %= vulkan_ctx->frames.size; } - +#endif static void vulkan_UpdateScreen (transform_t camera, double realtime, SCR_Func *scr_funcs) { +#ifdef TEST_RENDER + while (*scr_funcs) { + (*scr_funcs) (); + scr_funcs++; + } + QFV_RunRenderJob (vulkan_ctx); +#else EntQueue_Clear (r_ent_queue); vulkan_begin_frame (); vulkan_set_2d (1); @@ -492,6 +500,7 @@ vulkan_UpdateScreen (transform_t camera, double realtime, SCR_Func *scr_funcs) } vulkan_render_view (); vulkan_end_frame (); +#endif } static void diff --git a/libs/video/renderer/vulkan/render.c b/libs/video/renderer/vulkan/render.c index 5bca53e84..21a71334f 100644 --- a/libs/video/renderer/vulkan/render.c +++ b/libs/video/renderer/vulkan/render.c @@ -51,8 +51,8 @@ #include "vkparse.h" -static VkCommandBuffer -get_cmd_buffer (vulkan_ctx_t *ctx, int secondary) +VkCommandBuffer +QFV_GetCmdBufffer (vulkan_ctx_t *ctx, bool secondary) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; @@ -71,11 +71,19 @@ get_cmd_buffer (vulkan_ctx_t *ctx, int secondary) return cmd; } +void +QFV_AppendCmdBuffer (vulkan_ctx_t *ctx, VkCommandBuffer cmd) +{ + __auto_type rctx = ctx->render_context; + __auto_type job = rctx->job; + DARRAY_APPEND (&job->commands, cmd); +} + static void -run_tasks (uint32_t task_count, qfv_taskinfo_t *tasks, void *ctx) +run_tasks (uint32_t task_count, qfv_taskinfo_t *tasks, qfv_taskctx_t *ctx) { for (uint32_t i = 0; i < task_count; i++) { - tasks[i].func->func (tasks[i].params, 0, ctx); + tasks[i].func->func (tasks[i].params, 0, (exprctx_t *) ctx); } } @@ -136,19 +144,20 @@ run_renderpass (qfv_renderpass_t *rp, vulkan_ctx_t *ctx) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + __auto_type rctx = ctx->render_context; + __auto_type job = rctx->job; - VkCommandBuffer cmd = get_cmd_buffer (ctx, 1); + VkCommandBuffer cmd = QFV_GetCmdBufffer (ctx, false); VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; - dfunc->vkResetCommandBuffer (cmd, 0); dfunc->vkBeginCommandBuffer (cmd, &beginInfo); QFV_duCmdBeginLabel (device, cmd, rp->label.name, {VEC4_EXP (rp->label.color)}); dfunc->vkCmdBeginRenderPass (cmd, &rp->beginInfo, rp->subpassContents); for (uint32_t i = 0; i < rp->subpass_count; i++) { __auto_type sp = &rp->subpasses[i]; - VkCommandBuffer subcmd = get_cmd_buffer (ctx, 1); + VkCommandBuffer subcmd = QFV_GetCmdBufffer (ctx, true); run_subpass (sp, subcmd, ctx); dfunc->vkCmdExecuteCommands (cmd, 1, &subcmd); //FIXME comment is a bit off as exactly one buffer is always submitted @@ -162,6 +171,7 @@ run_renderpass (qfv_renderpass_t *rp, vulkan_ctx_t *ctx) } } QFV_CmdEndLabel (device, cmd); + DARRAY_APPEND (&job->commands, cmd); } static void @@ -193,7 +203,7 @@ run_compute_pipeline (qfv_pipeline_t *pipeline, VkCommandBuffer cmd, pipeline->num_push_constants, pipeline->push_constants); } - uint32_t *d = pipeline->dispatch; + vec4u_t d = pipeline->dispatch; dfunc->vkCmdDispatch (cmd, d[0], d[1], d[2]); } @@ -205,7 +215,7 @@ run_compute (qfv_compute_t *comp, vulkan_ctx_t *ctx) __auto_type rctx = ctx->render_context; __auto_type job = rctx->job; - VkCommandBuffer cmd = get_cmd_buffer (ctx, 0); + VkCommandBuffer cmd = QFV_GetCmdBufffer (ctx, false); VkCommandBufferBeginInfo beginInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, diff --git a/libs/video/renderer/vulkan/rp_main_def.plist b/libs/video/renderer/vulkan/rp_main_def.plist index 5f9ece858..8fedad9d2 100644 --- a/libs/video/renderer/vulkan/rp_main_def.plist +++ b/libs/video/renderer/vulkan/rp_main_def.plist @@ -1310,7 +1310,15 @@ renderpasses = { }; }; steps = { + wait_on_fence = { + process = { + tasks = ( + { func = "wait_on_fence"; }, + ); + }; + }; particles = { + dependencies = (wait_on_fence); compute = { pipelines = { part:update = { @@ -1339,9 +1347,11 @@ steps = { }; }; shadow = { + dependencies = (wait_on_fence); //currently empty }; translucent = { + dependencies = (wait_on_fence); process = { tasks = ( { func = "clear_translucent"; }, @@ -1358,6 +1368,7 @@ steps = { }; }; preoutput = { + dependencies = (wait_on_fence); process = { tasks = ( { func = "acquire_output"; }, diff --git a/libs/video/renderer/vulkan/vulkan_output.c b/libs/video/renderer/vulkan/vulkan_output.c index 58b0b79cf..5c4d93f40 100644 --- a/libs/video/renderer/vulkan/vulkan_output.c +++ b/libs/video/renderer/vulkan/vulkan_output.c @@ -259,6 +259,20 @@ _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 }, {} @@ -271,10 +285,15 @@ 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 }, {} }; diff --git a/libs/video/renderer/vulkan/vulkan_particles.c b/libs/video/renderer/vulkan/vulkan_particles.c index 526eeb2e4..31a0305c6 100644 --- a/libs/video/renderer/vulkan/vulkan_particles.c +++ b/libs/video/renderer/vulkan/vulkan_particles.c @@ -276,16 +276,121 @@ 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 -update_particles (const exprval_t **params, exprval_t *result, exprctx_t *ectx) +update_particles (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; + + particlectx_t *pctx = ctx->particle_context; + __auto_type pframe = &pctx->frames.a[ctx->curFrame]; + + qfv_packet_t *packet = QFV_PacketAcquire (pctx->stage); + + __auto_type limits = &device->physDev->properties->limits; + VkMemoryRequirements req = { + .alignment = limits->minStorageBufferOffsetAlignment + }; + uint32_t numParticles = min (MaxParticles, pctx->psystem->numparticles); + size_t syssize = sizeof (qfv_particle_system_t); + size_t partoffs = QFV_NextOffset (syssize, &req); + size_t partsize = sizeof (qfv_particle_t) * numParticles; + size_t paramoffs = QFV_NextOffset (partoffs + partsize, &req); + size_t paramsize = sizeof (qfv_parameters_t) * numParticles; + size_t size = paramoffs + paramsize; + + qfv_particle_system_t *system = QFV_PacketExtend (packet, size); + *system = (qfv_particle_system_t) { + .vertexCount = 1, + .particleCount = numParticles, + }; + __auto_type particles = (qfv_particle_t *) ((byte *)system + partoffs); + memcpy (particles, pctx->psystem->particles, partsize); + qfv_parameters_t *params = (qfv_parameters_t *)((byte *)system + paramoffs); + memcpy (params, pctx->psystem->partparams, paramsize); + + if (!numParticles) { + // if there are no particles, then no space for the particle states or + // parameters has been allocated in the staging buffer, so map the + // two buffers over the system buffer. This avoids either buffer being + // just past the end of the staging buffer (which the validation layers + // (correctly) do not like). + // This is fine because the two buffers are only read by the compute + // shader. + partsize = paramsize = syssize; + partoffs = paramoffs = 0; + } + + size_t sysoffs = packet->offset; + VkDescriptorBufferInfo bufferInfo[] = { + { packet->stage->buffer, sysoffs + partoffs, partsize}, + { packet->stage->buffer, sysoffs + paramoffs, paramsize}, + { packet->stage->buffer, sysoffs, syssize }, + }; + VkWriteDescriptorSet write[] = { + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, + pframe->newDescriptors, 0, 0, 3, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .pBufferInfo = bufferInfo + }, + }; + dfunc->vkUpdateDescriptorSets (device->dev, 1, write, 0, 0); + + __auto_type pipeline = taskctx->pipeline; + pipeline->dispatch = (vec4u_t) {1, 1, 1}; + pipeline->num_descriptorsets = 3; + pipeline->descriptorsets[0] = pframe->curDescriptors; + pipeline->descriptorsets[1] = pframe->inDescriptors; + pipeline->descriptorsets[2] = pframe->newDescriptors; + + QFV_PacketSubmit (packet); + + pctx->psystem->numparticles = 0; } static void particle_physics (const exprval_t **params, exprval_t *result, exprctx_t *ectx) { + __auto_type taskctx = (qfv_taskctx_t *) ectx; + vulkan_ctx_t *ctx = taskctx->ctx; + + particlectx_t *pctx = ctx->particle_context; + __auto_type pframe = &pctx->frames.a[ctx->curFrame]; + + __auto_type pipeline = taskctx->pipeline; + pipeline->dispatch = (vec4u_t) {MaxParticles, 1, 1}; + pipeline->num_descriptorsets = 1; + pipeline->descriptorsets[0] = pframe->curDescriptors; + + struct { + qfv_push_constants_t push_constants[2]; + particle_push_constants_t constants; + } push = { + .push_constants = { + { VK_SHADER_STAGE_COMPUTE_BIT, + field_offset (particle_push_constants_t, gravity), + sizeof (vec4f_t), &push.constants.gravity }, + { VK_SHADER_STAGE_COMPUTE_BIT, + field_offset (particle_push_constants_t, dT), + sizeof (float), &push.constants.dT }, + }, + .constants = { + .gravity = pctx->psystem->gravity, + .dT = vr_data.frametime, + }, + }; + if (!pipeline->push_constants) { + //FIXME figure out something better for managing push constants + pipeline->push_constants = malloc (sizeof (push)); + } + memcpy (pipeline->push_constants, &push, sizeof (push)); + pipeline->num_push_constants = 2; } static exprfunc_t particles_draw_func[] = { diff --git a/libs/video/renderer/vulkan/vulkan_translucent.c b/libs/video/renderer/vulkan/vulkan_translucent.c index 2cac52ee6..f79bfccc6 100644 --- a/libs/video/renderer/vulkan/vulkan_translucent.c +++ b/libs/video/renderer/vulkan/vulkan_translucent.c @@ -67,6 +67,57 @@ static const char * __attribute__((used)) translucent_pass_names[] = { static void clear_translucent (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; + translucentctx_t *tctx = ctx->translucent_context; + __auto_type tframe = &tctx->frames.a[ctx->curFrame]; + + VkCommandBuffer cmd = QFV_GetCmdBufffer (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, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + qfv_imagebarrier_t ib = imageBarriers[qfv_LT_Undefined_to_TransferDst]; + ib.barrier.image = tframe->heads; + ib.barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (cmd, ib.srcStages, ib.dstStages, + 0, 0, 0, 0, 0, + 1, &ib.barrier); + VkClearColorValue clear_color[] = { + { .int32 = {-1, -1, -1, -1} }, + }; + VkImageSubresourceRange ranges[] = { + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, VK_REMAINING_ARRAY_LAYERS }, + }; + dfunc->vkCmdClearColorImage (cmd, tframe->heads, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + clear_color, 1, ranges); + ib = imageBarriers[qfv_LT_TransferDst_to_General]; + ib.barrier.image = tframe->heads; + ib.barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (cmd, ib.srcStages, ib.dstStages, + 0, 0, 0, 0, 0, + 1, &ib.barrier); + + dfunc->vkEndCommandBuffer (cmd); + QFV_AppendCmdBuffer (ctx, cmd); + + qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); + qfv_transtate_t *state = QFV_PacketExtend (packet, 2 * sizeof (*state)); + *state = (qfv_transtate_t) { 0, tctx->maxFragments }; + __auto_type bb = &bufferBarriers[qfv_BB_TransferWrite_to_ShaderRW]; + QFV_PacketCopyBuffer (packet, tframe->state, 0, bb); + QFV_PacketSubmit (packet); } static exprfunc_t clear_translucent_func[] = {