mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-20 18:52:28 +00:00
[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:
parent
97f9fd81d6
commit
3c65f1494b
7 changed files with 221 additions and 13 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"; },
|
||||
|
|
|
@ -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 },
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
Loading…
Reference in a new issue