[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.
This commit is contained in:
Bill Currie 2023-06-15 15:17:39 +09:00
parent 97f9fd81d6
commit 3c65f1494b
7 changed files with 221 additions and 13 deletions

View file

@ -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);

View file

@ -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

View file

@ -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,

View file

@ -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"; },

View file

@ -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 },
{}
};

View file

@ -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[] = {

View file

@ -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[] = {