[vulkan] Apply the light culling information

The results of the occlusion queries give the lights that don't have a
visible hull, but unfortunately that includes any lights which the
camera is inside, but simple distance checks sort that out (with a
fudge-factor for the icosahedron vertices (1.583 (3(2+p)/(2+3p), p is
golden ratio)).
This commit is contained in:
Bill Currie 2023-12-17 10:45:59 +09:00
parent f08b8dc3c7
commit 187c48bde3
3 changed files with 152 additions and 13 deletions

View file

@ -80,6 +80,11 @@ typedef struct light_queue_s {
uint16_t count;
} light_queue_t;
typedef struct light_idrad_s {
uint32_t id;
float radius;
} light_idrad_t;
typedef struct lightingframe_s {
VkDescriptorSet shadowmat_set;
VkDescriptorSet lights_set;
@ -98,6 +103,9 @@ typedef struct lightingframe_s {
VkBuffer entid_buffer;
light_queue_t light_queue[4];
light_idrad_t *id_radius;
vec4f_t *positions;
light_queue_t stage_queue[LIGHTING_STAGES];
// map_id (0,5) first layer (5,11)
uint16_t *stage_targets;

View file

@ -1366,7 +1366,7 @@ renderpasses = {
base_pipeline = {
@inherit = $pipeline_base;
depthStencil = $depth_test_and_write;
depthStencil = $depth_test_only;
rasterization = $cw_cull_back;
};
pipelines = {
@ -1387,7 +1387,7 @@ renderpasses = {
vertexInput = $lighting.vertexInput_splat;
inputAssembly = $lighting.inputAssembly;
layout = $lighting.splat_layout;
rasterization = $cw_cull_back;
rasterization = $counter_cw_cull_back;
depthStencil = $depth_test_only;
};
};

View file

@ -618,6 +618,7 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
uint32_t light_ids[ST_COUNT][MaxLights];
float light_radii[ST_COUNT][MaxLights];
vec4f_t light_positions[ST_COUNT][MaxLights];
uint32_t entids[ST_COUNT][MaxLights];
uint32_t light_count = 0;
@ -657,10 +658,11 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
int mode = r->mode;
auto light = get_light (ent.id, ent.reg);
light_ids[mode][queue[mode].count] = id;
light_radii[mode][queue[mode].count] = light_radius (light);
entids[mode][queue[mode].count] = ent.id;
queue[mode].count++;
uint32_t ind = queue[mode].count++;
light_ids[mode][ind] = id;
light_radii[mode][ind] = light_radius (light);
light_positions[mode][ind] = light->position;
entids[mode][ind] = ent.id;
}
lframe->stage_queue[0].start = 0;
@ -767,10 +769,11 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
};
uint32_t id = lctx->dynamic_base + i;
set_lightid (dynamic_light_entities[i], lctx->scene->reg, id);
light_ids[ST_CUBE][queue[ST_CUBE].count] = id;
light_radii[ST_CUBE][queue[ST_CUBE].count] = light_radius (&light);
entids[ST_CUBE][queue[ST_CUBE].count] = dynamic_light_entities[i];
queue[ST_CUBE].count++;
uint32_t ind = queue[ST_CUBE].count++;
light_ids[ST_CUBE][ind] = id;
light_radii[ST_CUBE][ind] = light_radius (&light);
light_positions[ST_CUBE][ind] = light.position;
entids[ST_CUBE][ind] = dynamic_light_entities[i];
lights[i] = light;
}
@ -850,6 +853,19 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
auto ir_barrier = &bufferBarriers[qfv_BB_TransferWrite_to_IndexRead];
QFV_PacketScatterBuffer (packet, lframe->entid_buffer, 1, &eid_scatter,
ir_barrier);
for (int i = 0; i < ST_COUNT; i++) {
auto q = queue[i];
auto idr = &lframe->id_radius[q.start];
auto pos = &lframe->positions[q.start];
for (uint32_t j = 0; j < q.count; j++) {
idr[j] = (light_idrad_t) {
.id = light_ids[i][j],
.radius = light_radii[i][j],
};
pos[j] = light_positions[i][j];
}
}
}
auto matrix_ids = (uint32_t *) packet_data;
@ -1020,6 +1036,78 @@ lighting_draw_splats (const exprval_t **params, exprval_t *result,
}
}
static void
lighting_rewrite_ids (lightingframe_t *lframe, vulkan_ctx_t *ctx)
{
uint32_t count = 0;
for (int i = 0; i < ST_COUNT; i++) {
auto q = &lframe->light_queue[i];
count += q->count;
}
uint32_t light_ids[count];
float light_radii[count];
uint32_t light_count = 0;
light_queue_t queue[ST_COUNT] = {};
for (int i = 0; i < ST_COUNT; i++) {
auto q = &lframe->light_queue[i];
for (uint32_t j = 0; j < q[0].count; j++) {
uint32_t id = lframe->id_radius[q[0].start + j].id;
float radius = lframe->id_radius[q[0].start + j].radius;
if (id != ~0u) {
light_ids[queue[i].start + queue[i].count] = id;
light_radii[queue[i].start + queue[i].count] = radius;
queue[i].count++;
}
}
if (i < ST_COUNT - 1) {
queue[i + 1].start = queue[i].start + queue[i].count;
} else {
light_count = queue[i].start + queue[i].count;
}
}
for (int i = 0; i < ST_COUNT; i++) {
lframe->light_queue[i] = queue[i];
}
size_t packet_size = 0;
packet_size += sizeof (uint32_t[light_count]);
packet_size += sizeof (float[light_count]);
auto bb = &bufferBarriers[qfv_BB_TransferWrite_to_UniformRead];
auto packet = QFV_PacketAcquire (ctx->staging);
byte *packet_start = QFV_PacketExtend (packet, packet_size);
byte *packet_data = packet_start;
qfv_scatter_t id_scatter = {
.srcOffset = packet_data - packet_start,
.dstOffset = 0,
.length = sizeof (uint32_t[light_count]),
};
auto id_data = (uint32_t *) packet_data;
packet_data += id_scatter.length;
qfv_scatter_t radius_scatter = {
.srcOffset = packet_data - packet_start,
.dstOffset = 0,
.length = sizeof (uint32_t[light_count]),
};
auto radius_data = (uint32_t *) packet_data;
packet_data += radius_scatter.length;
memcpy (id_data, light_ids, packet_size);
memcpy (radius_data, light_radii, packet_size);
QFV_PacketScatterBuffer (packet, lframe->id_buffer, 1, &id_scatter, bb);
QFV_PacketScatterBuffer (packet, lframe->radius_buffer,
1, &radius_scatter, bb);
QFV_PacketSubmit (packet);
if (developer & SYS_lighting) {
Vulkan_Draw_String (vid.width - 32, 16,
va (ctx->va_ctx, "%3d", light_count),
ctx);
}
}
static void
lighting_cull_lights (const exprval_t **params, exprval_t *result,
exprctx_t *ectx)
@ -1071,10 +1159,47 @@ lighting_cull_lights (const exprval_t **params, exprval_t *result,
size, frag_counts, sizeof (uint32_t),
VK_QUERY_RESULT_WAIT_BIT);
uint32_t c = 0;
for (uint32_t i = 0; i < count; i++) {
c += frag_counts[i] != 0;
uint32_t ci = 0;
vec4f_t cam = r_refdef.camera[3];
uint32_t id = 0;
if (lframe->light_queue[ST_CUBE].count) {
auto q = lframe->light_queue[ST_CUBE];
for (uint32_t i = 0; i < q.count; i++) {
uint32_t fc = frag_counts[id++];
c += fc != 0;
if (!fc) {
uint32_t hull = q.start + i;
vec4f_t dist = cam - lframe->positions[hull];
dist[3] = 0;
float rad = lframe->id_radius[hull].radius;
constexpr float s = 1.5835921350012616f;
bool inside = dotf(dist, dist)[0] < rad * rad * s;
ci += inside;
if (!inside) {
lframe->id_radius[hull].id = ~0u;
}
}
}
}
if (1) printf ("%d/%d visible\n", c, count);
if (lframe->light_queue[ST_PLANE].count) {
auto q = lframe->light_queue[ST_PLANE];
for (uint32_t i = 0; i < q.count; i++) {
uint32_t fc = frag_counts[id++];
c += fc != 0;
if (!fc) {
uint32_t hull = q.start + i;
vec4f_t dist = cam - lframe->positions[hull];
dist[3] = 0;
float rad = lframe->id_radius[hull].radius;
bool inside = dotf(dist, dist)[0] < rad * rad;
ci += inside;
if (!inside) {
lframe->id_radius[hull].id = ~0u;
}
}
}
}
lighting_rewrite_ids (lframe, ctx);
}
static void
@ -1734,10 +1859,16 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
}
size_t target_count = MaxLights * 6;
size_t target_size = frames * sizeof (uint16_t[target_count]);
size_t idr_size = frames * sizeof (light_idrad_t[MaxLights]);
size_t position_size = frames * sizeof (vec4f_t[MaxLights]);
lctx->frames.a[0].stage_targets = malloc (target_size);
lctx->frames.a[0].id_radius = malloc (idr_size);
lctx->frames.a[0].positions = malloc (position_size);
for (size_t i = 1; i < frames; i++) {
auto lframe = &lctx->frames.a[i];
lframe[0].stage_targets = lframe[-1].stage_targets + target_count;
lframe[0].id_radius = lframe[-1].id_radius + MaxLights;
lframe[0].positions = lframe[-1].positions + MaxLights;
}
make_default_map (64, lctx->default_map, ctx);