[vulkan] Get particles mostly working in the new system

The particles die instantly due to curFrame not updating (next commit),
but otherwise work nicely, especially sync is better (many thanks to
Darian for his help with understanding sync scope).
This commit is contained in:
Bill Currie 2023-06-24 03:26:22 +09:00
parent 87356a5211
commit 41d69586d2
5 changed files with 174 additions and 305 deletions

View file

@ -79,7 +79,6 @@ struct qfv_orenderframe_s;
struct psystem_s *Vulkan_ParticleSystem (struct vulkan_ctx_s *ctx);
void Vulkan_Particles_Init (struct vulkan_ctx_s *ctx);
void Vulkan_Particles_Shutdown (struct vulkan_ctx_s *ctx);
void Vulkan_DrawParticles (struct qfv_orenderframe_s *rFrame);
void Vulkan_Particles_CreateRenderPasses (struct vulkan_ctx_s *ctx);
#endif//__QF_Vulkan_qf_particles_h

View file

@ -127,6 +127,8 @@ run_renderpass (qfv_renderpass_t *rp, vulkan_ctx_t *ctx)
__auto_type job = rctx->job;
VkCommandBuffer cmd = QFV_GetCmdBuffer (ctx, false);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, cmd,
va (ctx->va_ctx, "cmd:render:%s", rp->label.name));
VkCommandBufferBeginInfo beginInfo = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
};
@ -188,11 +190,13 @@ run_compute_pipeline (qfv_pipeline_t *pipeline, VkCommandBuffer cmd,
0, 0);
}
vec4u_t d = pipeline->dispatch;
dfunc->vkCmdDispatch (cmd, d[0], d[1], d[2]);
if (d[0] && d[1] && d[2]) {
dfunc->vkCmdDispatch (cmd, d[0], d[1], d[2]);
}
}
static void
run_compute (qfv_compute_t *comp, vulkan_ctx_t *ctx)
run_compute (qfv_compute_t *comp, vulkan_ctx_t *ctx, qfv_step_t *step)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
@ -200,6 +204,10 @@ run_compute (qfv_compute_t *comp, vulkan_ctx_t *ctx)
__auto_type job = rctx->job;
VkCommandBuffer cmd = QFV_GetCmdBuffer (ctx, false);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, cmd,
va (ctx->va_ctx, "cmd:compute:%s", step->label.name));
QFV_duCmdBeginLabel (device, cmd, step->label.name,
{VEC4_EXP (step->label.color)});
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
@ -210,6 +218,7 @@ run_compute (qfv_compute_t *comp, vulkan_ctx_t *ctx)
__auto_type pipeline = &comp->pipelines[i];
run_compute_pipeline (pipeline, cmd, ctx);
}
QFV_duCmdEndLabel (device, cmd);
dfunc->vkEndCommandBuffer (cmd);
DARRAY_APPEND (&job->commands, cmd);
}
@ -236,7 +245,7 @@ QFV_RunRenderJob (vulkan_ctx_t *ctx)
run_renderpass (step->render->active, ctx);
}
if (step->compute) {
run_compute (step->compute, ctx);
run_compute (step->compute, ctx, step);
}
if (step->process) {
run_process (step->process, ctx);

View file

@ -1457,6 +1457,7 @@ steps = {
tasks = (
{ func = update_framebuffer;
params = ("\"main\""); },
{ func = particle_wait_physics; },
);
};
};

View file

@ -100,7 +100,6 @@ Vulkan_RenderView (qfv_orenderframe_t *rFrame)
Vulkan_DrawViewModel (ctx);
}
Vulkan_DrawWaterSurfaces (rFrame);
Vulkan_DrawParticles (rFrame);
Vulkan_Bsp_Flush (ctx);
Vulkan_Scene_Flush (ctx);
}

View file

@ -67,119 +67,6 @@ typedef struct {
float dT;
} particle_push_constants_t;
static const char * __attribute__((used)) particle_pass_names[] = {
"draw",
};
static void
particle_begin_subpass (VkPipeline pipeline, qfv_orenderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
particlectx_t *pctx = ctx->particle_context;
uint32_t curFrame = ctx->curFrame;
particleframe_t *pframe = &pctx->frames.a[curFrame];
VkCommandBuffer cmd = pframe->cmdSet.a[0];
dfunc->vkResetCommandBuffer (cmd, 0);
VkCommandBufferInheritanceInfo inherit = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0,
rFrame->renderpass->renderpass, QFV_passTranslucentFrag,
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, "particles:%s", "draw"),
{ 0.6, 0.5, 0, 1});
dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
VkDescriptorSet sets[] = {
Vulkan_Matrix_Descriptors (ctx, ctx->curFrame),
Vulkan_Palette_Descriptor (ctx),
Vulkan_Translucent_Descriptors (ctx, ctx->curFrame),
};
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
pctx->draw_layout, 0, 3, sets, 0, 0);
dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport);
dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor);
}
static void
particle_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_DrawParticles (qfv_orenderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
particlectx_t *pctx = ctx->particle_context;
uint32_t curFrame = ctx->curFrame;
particleframe_t *pframe = &pctx->frames.a[curFrame];
VkCommandBuffer cmd = pframe->cmdSet.a[0];
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucentFrag],
pframe->cmdSet.a[0]);
particle_begin_subpass (pctx->draw, rFrame);
/*
VkBufferMemoryBarrier barrier[] = {
{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
0, 0,
pframe->states, 0, VK_WHOLE_SIZE },
{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
0, 0,
pframe->params, 0, VK_WHOLE_SIZE },
{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
0, 0,
pframe->system, 0, VK_WHOLE_SIZE },
};
dfunc->vkCmdWaitEvents (cmd, 1, &pframe->physicsEvent,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
| VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
0, 0,
3, barrier,
0, 0);
*/
mat4f_t mat;
mat4fidentity (mat);
qfv_push_constants_t push_constants[] = {
{ VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof (mat4f_t), &mat },
};
QFV_PushConstants (device, cmd, pctx->draw_layout, 1, push_constants);
VkDeviceSize offsets[] = { 0 };
VkBuffer buffers[] = {
pframe->states,
};
dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, buffers, offsets);
dfunc->vkCmdDrawIndirect (cmd, pframe->system, 0, 1,
sizeof (qfv_particle_system_t));
particle_end_subpass (cmd, ctx);
}
static void
create_buffers (vulkan_ctx_t *ctx)
{
@ -187,8 +74,7 @@ create_buffers (vulkan_ctx_t *ctx)
qfv_devfuncs_t *dfunc = device->funcs;
particlectx_t *pctx = ctx->particle_context;
size_t mp = MaxParticles;
auto rctx = ctx->render_context;
size_t frames = rctx->frames.size;
size_t frames = pctx->frames.size;
pctx->resources = malloc (sizeof (qfv_resource_t)
// states buffer
@ -209,7 +95,7 @@ create_buffers (vulkan_ctx_t *ctx)
};
for (size_t i = 0; i < frames; i++) {
state_objs[i] = (qfv_resobj_t) {
.name = "states",
.name = va (ctx->va_ctx, "states:%zd", i),
.type = qfv_res_buffer,
.buffer = {
.size = mp * sizeof (qfv_particle_t),
@ -218,7 +104,7 @@ create_buffers (vulkan_ctx_t *ctx)
},
};
param_objs[i] = (qfv_resobj_t) {
.name = "params",
.name = va (ctx->va_ctx, "param:%zd", i),
.type = qfv_res_buffer,
.buffer = {
.size = mp * sizeof (qfv_parameters_t),
@ -226,7 +112,7 @@ create_buffers (vulkan_ctx_t *ctx)
},
};
system_objs[i] = (qfv_resobj_t) {
.name = "system",
.name = va (ctx->va_ctx, "system:%zd", i),
.type = qfv_res_buffer,
.buffer = {
.size = sizeof (qfv_particle_system_t),
@ -277,19 +163,46 @@ create_buffers (vulkan_ctx_t *ctx)
static void
particles_draw (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 pctx = ctx->particle_context;
auto pframe = &pctx->frames.a[ctx->curFrame];
auto cmd = taskctx->cmd;
VkDescriptorSet sets[] = {
Vulkan_Matrix_Descriptors (ctx, ctx->curFrame),
Vulkan_Palette_Descriptor (ctx),
Vulkan_Translucent_Descriptors (ctx, ctx->curFrame),
};
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
pctx->draw_layout, 0, 3, sets, 0, 0);
mat4f_t mat;
mat4fidentity (mat);
qfv_push_constants_t push_constants[] = {
{ VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof (mat4f_t), &mat },
};
QFV_PushConstants (device, cmd, pctx->draw_layout, 1, push_constants);
VkDeviceSize offsets[] = { 0 };
VkBuffer buffers[] = {
pframe->states,
};
dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, buffers, offsets);
dfunc->vkCmdDrawIndirect (cmd, pframe->system, 0, 1,
sizeof (qfv_particle_system_t));
}
static void
update_particles (const exprval_t **_params, exprval_t *result, exprctx_t *ectx)
update_particles (const exprval_t **p, 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];
auto taskctx = (qfv_taskctx_t *) ectx;
auto ctx = taskctx->ctx;
auto device = ctx->device;
auto dfunc = device->funcs;
auto pctx = ctx->particle_context;
auto pframe = &pctx->frames.a[ctx->curFrame];
qfv_packet_t *packet = QFV_PacketAcquire (pctx->stage);
@ -310,9 +223,9 @@ update_particles (const exprval_t **_params, exprval_t *result, exprctx_t *ectx)
.vertexCount = 1,
.particleCount = numParticles,
};
__auto_type particles = (qfv_particle_t *) ((byte *)system + partoffs);
auto particles = (qfv_particle_t *) ((byte *) system + partoffs);
memcpy (particles, pctx->psystem->particles, partsize);
qfv_parameters_t *params = (qfv_parameters_t *)((byte *)system + paramoffs);
auto params = (qfv_parameters_t *) ((byte *) system + paramoffs);
memcpy (params, pctx->psystem->partparams, paramsize);
if (!numParticles) {
@ -342,32 +255,98 @@ update_particles (const exprval_t **_params, exprval_t *result, exprctx_t *ectx)
};
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;
dfunc->vkResetEvent (device->dev, pframe->updateEvent);
VkBufferMemoryBarrier pl_barrier[] = {
{ .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
.buffer = packet->stage->buffer,
.offset = sysoffs,
.size = paramoffs + paramsize,
},
};
dfunc->vkCmdPipelineBarrier (packet->cmd,
VK_PIPELINE_STAGE_HOST_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0,
0, 0,
1, pl_barrier,
0, 0);
dfunc->vkCmdBindPipeline (packet->cmd, VK_PIPELINE_BIND_POINT_COMPUTE,
pctx->update);
VkDescriptorSet set[3] = {
pframe->curDescriptors,
pframe->inDescriptors,
pframe->newDescriptors,
};
dfunc->vkCmdBindDescriptorSets (packet->cmd, VK_PIPELINE_BIND_POINT_COMPUTE,
pctx->update_layout, 0, 3, set, 0, 0);
dfunc->vkCmdDispatch (packet->cmd, 1, 1, 1);
dfunc->vkCmdSetEvent (packet->cmd, pframe->updateEvent,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
QFV_PacketSubmit (packet);
pctx->psystem->numparticles = 0;
}
static void
wait_on_event (VkBuffer states, VkBuffer params, VkBuffer system,
VkEvent event, bool draw, VkCommandBuffer cmd,
qfv_devfuncs_t *dfunc)
{
VkStructureType type = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
VkAccessFlags srcAccess = draw
? VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT
: VK_ACCESS_SHADER_WRITE_BIT;
VkAccessFlags dstAccess = draw
? VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
: VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT;
VkBufferMemoryBarrier barrier[] = {
{ .sType = type,
.srcAccessMask = srcAccess, .dstAccessMask = dstAccess,
.buffer = states, .offset = 0, .size = VK_WHOLE_SIZE },
{ .sType = type,
.srcAccessMask = srcAccess, .dstAccessMask = dstAccess,
.buffer = params, .offset = 0, .size = VK_WHOLE_SIZE },
{ .sType = type,
.srcAccessMask = srcAccess, .dstAccessMask = dstAccess,
.buffer = system, .offset = 0, .size = VK_WHOLE_SIZE },
};
VkAccessFlags srcStage = draw
? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
: VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
VkAccessFlags dstStage = draw
? VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
| VK_PIPELINE_STAGE_VERTEX_INPUT_BIT
: VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
dfunc->vkCmdWaitEvents (cmd, 1, &event, srcStage, dstStage,
0, 0, 3, barrier, 0, 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;
qfv_device_t *device = ctx->device;
auto taskctx = (qfv_taskctx_t *) ectx;
auto ctx = taskctx->ctx;
auto device = ctx->device;
auto dfunc = device->funcs;
auto pctx = ctx->particle_context;
auto pframe = &pctx->frames.a[ctx->curFrame];
auto cmd = taskctx->cmd;
particlectx_t *pctx = ctx->particle_context;
__auto_type pframe = &pctx->frames.a[ctx->curFrame];
dfunc->vkResetEvent (device->dev, pframe->physicsEvent);
wait_on_event (pframe->states, pframe->params, pframe->system,
pframe->updateEvent, false, cmd, dfunc);
__auto_type pipeline = taskctx->pipeline;
pipeline->dispatch = (vec4u_t) {MaxParticles, 1, 1};
pipeline->num_descriptorsets = 1;
pipeline->descriptorsets[0] = pframe->curDescriptors;
VkDescriptorSet set[] = {
pframe->curDescriptors,
};
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_COMPUTE,
pctx->physics_layout, 0, 1, set, 0, 0);
particle_push_constants_t constants = {
.gravity = pctx->psystem->gravity,
@ -381,8 +360,38 @@ particle_physics (const exprval_t **params, exprval_t *result, exprctx_t *ectx)
field_offset (particle_push_constants_t, dT),
sizeof (float), &constants.dT },
};
QFV_PushConstants (device, taskctx->cmd, pipeline->layout,
2, push_constants);
QFV_PushConstants (device, cmd, pctx->physics_layout, 2, push_constants);
dfunc->vkCmdDispatch (cmd, MaxParticles, 1, 1);
dfunc->vkCmdSetEvent (cmd, pframe->physicsEvent,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
}
static void
particle_wait_physics (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 pctx = ctx->particle_context;
auto pframe = &pctx->frames.a[ctx->curFrame];
auto cmd = QFV_GetCmdBuffer (ctx, false);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, cmd,
va (ctx->va_ctx, "cmd:particle_wait_physics:%d",
ctx->curFrame));
QFV_AppendCmdBuffer (ctx, cmd);
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
};
dfunc->vkBeginCommandBuffer (cmd, &beginInfo);
wait_on_event (pframe->states, pframe->params, pframe->system,
pframe->physicsEvent, true, cmd, dfunc);
dfunc->vkEndCommandBuffer (cmd);
}
static exprfunc_t particles_draw_func[] = {
@ -397,10 +406,15 @@ static exprfunc_t particle_physics_func[] = {
{ .func = particle_physics },
{}
};
static exprfunc_t particle_wait_physics_func[] = {
{ .func = particle_wait_physics },
{}
};
static exprsym_t particles_task_syms[] = {
{ "particles_draw", &cexpr_function, particles_draw_func },
{ "update_particles", &cexpr_function, update_particles_func },
{ "particle_physics", &cexpr_function, particle_physics_func },
{ "particle_wait_physics", &cexpr_function, particle_wait_physics_func },
{}
};
@ -417,8 +431,7 @@ Vulkan_Particles_Init (vulkan_ctx_t *ctx)
ctx->particle_context = pctx;
pctx->psystem = &r_psystem;
auto rctx = ctx->render_context;
size_t frames = rctx->frames.size;
size_t frames = ctx->render_context->frames.size;
DARRAY_INIT (&pctx->frames, frames);
DARRAY_RESIZE (&pctx->frames, frames);
pctx->frames.grow = 0;
@ -448,19 +461,6 @@ Vulkan_Particles_Init (vulkan_ctx_t *ctx)
pframe->inDescriptors = sets->a[i * 3 + 1];
pframe->newDescriptors = sets->a[i * 3 + 2];
DARRAY_INIT (&pframe->cmdSet, QFV_particleNumPasses);
DARRAY_RESIZE (&pframe->cmdSet, QFV_particleNumPasses);
pframe->cmdSet.grow = 0;
QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, &pframe->cmdSet);
for (int j = 0; j < QFV_particleNumPasses; j++) {
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER,
pframe->cmdSet.a[j],
va (ctx->va_ctx, "cmd:particle:%zd:%s", i,
particle_pass_names[j]));
}
VkEventCreateInfo event = { VK_STRUCTURE_TYPE_EVENT_CREATE_INFO };
dfunc->vkCreateEvent (device->dev, &event, 0, &pframe->physicsEvent);
dfunc->vkCreateEvent (device->dev, &event, 0, &pframe->updateEvent);
@ -510,145 +510,6 @@ Vulkan_ParticleSystem (vulkan_ctx_t *ctx)
static void
particles_update (qfv_orenderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
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);
dfunc->vkResetEvent (device->dev, pframe->updateEvent);
dfunc->vkResetEvent (device->dev, pframe->physicsEvent);
VkBufferMemoryBarrier pl_barrier[] = {
{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
0,
VK_ACCESS_SHADER_READ_BIT,
0, 0,
packet->stage->buffer, sysoffs, paramoffs + paramsize },
};
dfunc->vkCmdPipelineBarrier (packet->cmd,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0,
0, 0,
1, pl_barrier,
0, 0);
dfunc->vkCmdBindPipeline (packet->cmd, VK_PIPELINE_BIND_POINT_COMPUTE,
pctx->update);
VkDescriptorSet set[3] = {
pframe->curDescriptors,
pframe->inDescriptors,
pframe->newDescriptors,
};
dfunc->vkCmdBindDescriptorSets (packet->cmd, VK_PIPELINE_BIND_POINT_COMPUTE,
pctx->update_layout, 0, 3, set, 0, 0);
dfunc->vkCmdDispatch (packet->cmd, 1, 1, 1);
dfunc->vkCmdSetEvent (packet->cmd, pframe->updateEvent,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
VkBufferMemoryBarrier ev_barrier[] = {
{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT,
0, 0,
pframe->states, 0, VK_WHOLE_SIZE },
{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT,
0, 0,
pframe->params, 0, VK_WHOLE_SIZE },
{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT,
0, 0,
pframe->system, 0, VK_WHOLE_SIZE },
};
dfunc->vkCmdWaitEvents (packet->cmd, 1, &pframe->updateEvent,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
0, 0,
3, ev_barrier,
0, 0);
dfunc->vkCmdBindPipeline (packet->cmd, VK_PIPELINE_BIND_POINT_COMPUTE,
pctx->physics);
dfunc->vkCmdBindDescriptorSets (packet->cmd, VK_PIPELINE_BIND_POINT_COMPUTE,
pctx->physics_layout, 0, 1, set, 0, 0);
particle_push_constants_t constants = {
.gravity = pctx->psystem->gravity,
.dT = vr_data.frametime,
};
qfv_push_constants_t push_constants[] = {
{ VK_SHADER_STAGE_COMPUTE_BIT,
field_offset (particle_push_constants_t, gravity),
sizeof (vec4f_t), &constants.gravity },
{ VK_SHADER_STAGE_COMPUTE_BIT,
field_offset (particle_push_constants_t, dT),
sizeof (float), &constants.dT },
};
QFV_PushConstants (device, packet->cmd, pctx->physics_layout,
2, push_constants);
dfunc->vkCmdDispatch (packet->cmd, MaxParticles, 1, 1);
//dfunc->vkCmdSetEvent (packet->cmd, pframe->physicsEvent,
// VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
QFV_PacketSubmit (packet);
pctx->psystem->numparticles = 0;
}
void