[vulkan] Upload light matrices for shadow maps

This involved rewriting the descriptor update code too, but that now
feels cleaner.

The matrices are loaded into a storage buffer as it can get quite big at
6 matrices per light (and the current max lights is 768).
This commit is contained in:
Bill Currie 2023-07-30 11:28:42 +09:00
parent aac6fca2c5
commit aed1e7e077
3 changed files with 148 additions and 90 deletions

View File

@ -65,24 +65,17 @@ typedef struct qfv_framebufferset_s
DARRAY_TYPE (VkFramebuffer) qfv_framebufferset_t; DARRAY_TYPE (VkFramebuffer) qfv_framebufferset_t;
typedef struct lightingframe_s { typedef struct lightingframe_s {
VkBuffer data_buffer; VkDescriptorSet shadowmat_set;
VkDescriptorSet lights_set;
VkDescriptorSet attach_set;
VkBuffer shadowmat_buffer;
VkBuffer light_buffer;
VkBuffer id_buffer; VkBuffer id_buffer;
uint32_t ico_count; uint32_t ico_count;
uint32_t cone_count; uint32_t cone_count;
uint32_t flat_count; uint32_t flat_count;
VkDescriptorBufferInfo bufferInfo[LIGHTING_BUFFER_INFOS];
VkDescriptorImageInfo attachInfo[LIGHTING_ATTACH_INFOS];
VkDescriptorImageInfo shadowInfo[LIGHTING_SHADOW_INFOS];
union {
VkWriteDescriptorSet descriptors[LIGHTING_DESCRIPTORS];
struct {
VkWriteDescriptorSet bufferWrite[LIGHTING_BUFFER_INFOS];
VkWriteDescriptorSet attachWrite[LIGHTING_ATTACH_INFOS];
VkWriteDescriptorSet shadowWrite;
};
};
qfv_imageviewset_t views; qfv_imageviewset_t views;
qfv_framebufferset_t framebuffers; qfv_framebufferset_t framebuffers;
} lightingframe_t; } lightingframe_t;

View File

@ -759,6 +759,16 @@ descriptorSetLayouts = {
}, },
); );
}; };
shadowmat_set = {
bindings = (
{
binding = 0;
descriptorType = storage_buffer;
descriptorCount = 1;
stageFlags = vertex|fragment;
},
);
};
quad_data_set = { quad_data_set = {
bindings = ( bindings = (
{ {

View File

@ -361,7 +361,7 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
ctx); ctx);
} }
QFV_PacketCopyBuffer (packet, lframe->data_buffer, 0, QFV_PacketCopyBuffer (packet, lframe->light_buffer, 0,
&bufferBarriers[qfv_BB_TransferWrite_to_UniformRead]); &bufferBarriers[qfv_BB_TransferWrite_to_UniformRead]);
QFV_PacketSubmit (packet); QFV_PacketSubmit (packet);
uint32_t id_count = lframe->ico_count + lframe->cone_count uint32_t id_count = lframe->ico_count + lframe->cone_count
@ -380,31 +380,6 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
} }
} }
static VkDescriptorBufferInfo base_buffer_info = {
0, 0, VK_WHOLE_SIZE
};
static VkDescriptorImageInfo base_image_info = {
0, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
};
static VkWriteDescriptorSet base_buffer_write = {
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0,
0, 0, 1,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0, 0, 0
};
static VkWriteDescriptorSet base_attachment_write = {
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0,
0, 0, 1,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
0, 0, 0
};
static VkWriteDescriptorSet base_image_write = {
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0,
0, 0, 1,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
0, 0, 0
};
static void static void
lighting_update_descriptors (const exprval_t **params, exprval_t *result, lighting_update_descriptors (const exprval_t **params, exprval_t *result,
exprctx_t *ectx) exprctx_t *ectx)
@ -418,15 +393,54 @@ lighting_update_descriptors (const exprval_t **params, exprval_t *result,
auto lframe = &lctx->frames.a[ctx->curFrame]; auto lframe = &lctx->frames.a[ctx->curFrame];
auto fb = &taskctx->renderpass->framebuffer; auto fb = &taskctx->renderpass->framebuffer;
lframe->bufferInfo[0].buffer = lframe->data_buffer; VkDescriptorImageInfo attachInfo[] = {
lframe->attachInfo[0].imageView = fb->views[QFV_attachDepth]; { .imageView = fb->views[QFV_attachDepth],
lframe->attachInfo[1].imageView = fb->views[QFV_attachColor]; .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
lframe->attachInfo[2].imageView = fb->views[QFV_attachEmission]; { .imageView = fb->views[QFV_attachColor],
lframe->attachInfo[3].imageView = fb->views[QFV_attachNormal]; .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
lframe->attachInfo[4].imageView = fb->views[QFV_attachPosition]; { .imageView = fb->views[QFV_attachEmission],
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
{ .imageView = fb->views[QFV_attachNormal],
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
{ .imageView = fb->views[QFV_attachPosition],
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
};
VkWriteDescriptorSet attachWrite[] = {
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->attach_set,
.dstBinding = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
.pImageInfo = &attachInfo[0], },
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->attach_set,
.dstBinding = 1,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
.pImageInfo = &attachInfo[1], },
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->attach_set,
.dstBinding = 2,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
.pImageInfo = &attachInfo[2], },
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->attach_set,
.dstBinding = 3,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
.pImageInfo = &attachInfo[3], },
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->attach_set,
.dstBinding = 4,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
.pImageInfo = &attachInfo[4], },
};
//lframe->bufferInfo[0].buffer = lframe->light_buffer;
dfunc->vkUpdateDescriptorSets (device->dev, dfunc->vkUpdateDescriptorSets (device->dev,
LIGHTING_DESCRIPTORS, LIGHTING_ATTACH_INFOS, attachWrite,
lframe->descriptors, 0, 0); 0, 0);
} }
static void static void
@ -445,9 +459,8 @@ lighting_bind_descriptors (const exprval_t **params, exprval_t *result,
VkDescriptorSet sets[] = { VkDescriptorSet sets[] = {
Vulkan_Matrix_Descriptors (ctx, ctx->curFrame), Vulkan_Matrix_Descriptors (ctx, ctx->curFrame),
lframe->bufferWrite[0].dstSet, lframe->lights_set,
lframe->attachWrite[0].dstSet, lframe->attach_set,
lframe->shadowWrite.dstSet,
}; };
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
layout, 0, 3, sets, 0, 0); layout, 0, 3, sets, 0, 0);
@ -653,6 +666,7 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
qfvPushDebug (ctx, "lighting init"); qfvPushDebug (ctx, "lighting init");
auto device = ctx->device; auto device = ctx->device;
auto dfunc = device->funcs;
auto lctx = ctx->lighting_context; auto lctx = ctx->lighting_context;
lctx->sampler = QFV_Render_Sampler (ctx, "shadow_sampler"); lctx->sampler = QFV_Render_Sampler (ctx, "shadow_sampler");
@ -684,19 +698,25 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
+ sizeof (qfv_resobj_t) + sizeof (qfv_resobj_t)
// splat indices // splat indices
+ sizeof (qfv_resobj_t) + sizeof (qfv_resobj_t)
// light ids
+ sizeof (qfv_resobj_t[frames])
// light data // light data
+ sizeof (qfv_resobj_t[frames]) + sizeof (qfv_resobj_t[frames])
// light indices // light matrix ids
+ sizeof (qfv_resobj_t[frames])
// light matrices
+ sizeof (qfv_resobj_t[frames])); + sizeof (qfv_resobj_t[frames]));
auto splat_verts = (qfv_resobj_t *) &lctx->light_resources[1]; auto splat_verts = (qfv_resobj_t *) &lctx->light_resources[1];
auto splat_inds = &splat_verts[1]; auto splat_inds = &splat_verts[1];
auto light_data = &splat_inds[1]; auto light_ids = &splat_inds[1];
auto light_ids = &light_data[frames]; auto light_data = &light_ids[frames];
auto light_matids = &light_data[frames];
auto light_mats = &light_matids[frames];
lctx->light_resources[0] = (qfv_resource_t) { lctx->light_resources[0] = (qfv_resource_t) {
.name = "lights", .name = "lights",
.va_ctx = ctx->va_ctx, .va_ctx = ctx->va_ctx,
.memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, .memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
.num_objects = 2 + 2 * frames, .num_objects = 2 + 4 * frames,
.objects = splat_verts, .objects = splat_verts,
}; };
splat_verts[0] = (qfv_resobj_t) { splat_verts[0] = (qfv_resobj_t) {
@ -719,7 +739,7 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
}; };
for (size_t i = 0; i < frames; i++) { for (size_t i = 0; i < frames; i++) {
light_data[i] = (qfv_resobj_t) { light_data[i] = (qfv_resobj_t) {
.name = "data", .name = "lights",
.type = qfv_res_buffer, .type = qfv_res_buffer,
.buffer = { .buffer = {
.size = sizeof (qfv_light_buffer_t), .size = sizeof (qfv_light_buffer_t),
@ -727,6 +747,25 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
| VK_BUFFER_USAGE_TRANSFER_DST_BIT, | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
}, },
}; };
light_matids[i] = (qfv_resobj_t) {
.name = "matrixids",
.type = qfv_res_buffer,
.buffer = {
.size = sizeof (uint32_t[MaxLights]),
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
},
};
light_mats[i] = (qfv_resobj_t) {
.name = "matrices",
.type = qfv_res_buffer,
.buffer = {
// never need more than 6 matrices per light
.size = sizeof (mat4f_t[MaxLights * 6]),
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
},
};
light_ids[i] = (qfv_resobj_t) { light_ids[i] = (qfv_resobj_t) {
.name = "ids", .name = "ids",
.type = qfv_res_buffer, .type = qfv_res_buffer,
@ -745,52 +784,52 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
auto attach_mgr = QFV_Render_DSManager (ctx, "lighting_attach"); auto attach_mgr = QFV_Render_DSManager (ctx, "lighting_attach");
auto lights_mgr = QFV_Render_DSManager (ctx, "lighting_lights"); auto lights_mgr = QFV_Render_DSManager (ctx, "lighting_lights");
auto shadow_mgr = QFV_Render_DSManager (ctx, "lighting_shadow"); auto shadowmat_mgr = QFV_Render_DSManager (ctx, "shadowmat_set");
for (size_t i = 0; i < frames; i++) { for (size_t i = 0; i < frames; i++) {
auto lframe = &lctx->frames.a[i]; auto lframe = &lctx->frames.a[i];
*lframe = (lightingframe_t) { *lframe = (lightingframe_t) {
.data_buffer = light_data[i].buffer.buffer, .shadowmat_set = QFV_DSManager_AllocSet (shadowmat_mgr),
.lights_set = QFV_DSManager_AllocSet (lights_mgr),
.attach_set = QFV_DSManager_AllocSet (attach_mgr),
.shadowmat_buffer = light_mats[i].buffer.buffer,
.light_buffer = light_data[i].buffer.buffer,
.id_buffer = light_ids[i].buffer.buffer, .id_buffer = light_ids[i].buffer.buffer,
}; };
auto attach = QFV_DSManager_AllocSet (attach_mgr); QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET,
auto lights = QFV_DSManager_AllocSet (lights_mgr); lframe->attach_set,
auto shadow = QFV_DSManager_AllocSet (shadow_mgr);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET, attach,
va (ctx->va_ctx, "lighting:attach_set:%zd", i)); va (ctx->va_ctx, "lighting:attach_set:%zd", i));
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET, lights, QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET,
lframe->lights_set,
va (ctx->va_ctx, "lighting:lights_set:%zd", i)); va (ctx->va_ctx, "lighting:lights_set:%zd", i));
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET, shadow, QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET,
va (ctx->va_ctx, "lighting:shadow_set:%zd", i)); lframe->shadowmat_set,
va (ctx->va_ctx, "lighting:shadowmat_set:%zd", i));
for (int j = 0; j < LIGHTING_BUFFER_INFOS; j++) {
lframe->bufferInfo[j] = base_buffer_info;
lframe->bufferWrite[j] = base_buffer_write;
lframe->bufferWrite[j].dstSet = lights;
lframe->bufferWrite[j].dstBinding = j;
lframe->bufferWrite[j].pBufferInfo = &lframe->bufferInfo[j];
}
for (int j = 0; j < LIGHTING_ATTACH_INFOS; j++) {
lframe->attachInfo[j] = base_image_info;
lframe->attachInfo[j].sampler = 0;
lframe->attachWrite[j] = base_attachment_write;
lframe->attachWrite[j].dstSet = attach;
lframe->attachWrite[j].dstBinding = j;
lframe->attachWrite[j].pImageInfo = &lframe->attachInfo[j];
}
for (int j = 0; j < LIGHTING_SHADOW_INFOS; j++) {
lframe->shadowInfo[j] = base_image_info;
lframe->shadowInfo[j].sampler = lctx->sampler;
lframe->shadowInfo[j].imageView = ctx->default_black->view;
}
lframe->shadowWrite = base_image_write;
lframe->shadowWrite.dstSet = shadow;
lframe->shadowWrite.dstBinding = 0;
lframe->shadowWrite.descriptorCount = LIGHTING_SHADOW_INFOS;
lframe->shadowWrite.pImageInfo = lframe->shadowInfo;
lframe->views = (qfv_imageviewset_t) DARRAY_STATIC_INIT (16); lframe->views = (qfv_imageviewset_t) DARRAY_STATIC_INIT (16);
lframe->framebuffers = (qfv_framebufferset_t) DARRAY_STATIC_INIT (16); lframe->framebuffers = (qfv_framebufferset_t) DARRAY_STATIC_INIT (16);
VkDescriptorBufferInfo bufferInfo[] = {
{ .buffer = lframe->light_buffer,
.offset = 0, .range = VK_WHOLE_SIZE, },
{ .buffer = lframe->shadowmat_buffer,
.offset = 0, .range = VK_WHOLE_SIZE, },
};
VkWriteDescriptorSet bufferWrite[] = {
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->lights_set,
.dstBinding = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.pBufferInfo = &bufferInfo[0], },
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->shadowmat_set,
.dstBinding = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &bufferInfo[1], },
};
dfunc->vkUpdateDescriptorSets (device->dev, 2, bufferWrite, 0, 0);
} }
auto packet = QFV_PacketAcquire (ctx->staging); auto packet = QFV_PacketAcquire (ctx->staging);
@ -911,6 +950,21 @@ create_light_matrices (lightingctx_t *lctx)
} }
} }
static void
upload_light_matrices (lightingctx_t *lctx, vulkan_ctx_t *ctx)
{
auto packet = QFV_PacketAcquire (ctx->staging);
size_t mat_size = sizeof (mat4f_t[lctx->light_mats.size]);
void *mat_data = QFV_PacketExtend (packet, mat_size);
memcpy (mat_data, lctx->light_mats.a, mat_size);
auto bb = &bufferBarriers[qfv_BB_TransferWrite_to_UniformRead];
for (size_t i = 0; i < lctx->frames.size; i++) {
auto lframe = &lctx->frames.a[i];
QFV_PacketCopyBuffer (packet, lframe->shadowmat_buffer, 0, bb);
}
QFV_PacketSubmit (packet);
}
static int static int
light_compare (const void *_li2, const void *_li1, void *_lights) light_compare (const void *_li2, const void *_li1, void *_lights)
{ {
@ -1129,6 +1183,7 @@ Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx)
if (light_pool->count) { if (light_pool->count) {
build_shadow_maps (lctx, ctx); build_shadow_maps (lctx, ctx);
create_light_matrices (lctx); create_light_matrices (lctx);
upload_light_matrices (lctx, ctx);
} }
lctx->ldata = scene->lights; lctx->ldata = scene->lights;
} }