[vulkan] Abandon light splats

They were an interesting idea and might be useful in the future, but
they don't work as well as I had hoped for quake's maps due to the
overlapping light volumes causing contention while doing the additive
blends in the frame buffer. The cause was made obvious when testing in
the marcher map: most of its over 400 lights have infinite radius thus
require full screen passes: all those passes fighting for the frame
buffer did very nasty things to performance. However, light splats might be
useful for many small, non-overlapping light volumes, thus the code is
being kept (and I like the cleanups that came with it).
This commit is contained in:
Bill Currie 2023-06-28 13:19:10 +09:00
parent 49dab2af85
commit afa84afc79
3 changed files with 68 additions and 85 deletions

View file

@ -560,6 +560,11 @@ properties = {
name = main;
module = $builtin/light_splat.frag;
};
fragment = {
stage = fragment;
name = main;
module = $builtin/lighting.frag;
};
debug_fragment = {
stage = fragment;
name = main;
@ -1439,45 +1444,26 @@ renderpasses = {
color = {
light = {
layout = color_attachment_optimal;
blend = $additive_blend;
blend = $blend_disable;
};
};
preserve = (output);
};
pipelines = {
light_splats = {
lights = {
@inherit = $compose_base;
color = $color.lights;
tasks = (
{ func = lighting_update_descriptors; },
{ func = lighting_bind_descriptors; },
{ func = lighting_draw_splats; },
{ func = lighting_draw_lights; },
);
stages = (
$lighting.shader.vertex_splat,
$lighting.shader.fragment_splat,
$fstriangle.shader.vertex,
$lighting.shader.fragment,
);
vertexInput = $lighting.vertexInput_splat;
inputAssembly = $lighting.inputAssembly;
layout = $lighting.layout;
rasterization = $cw_cull_back;
//depthStencil = $depth_disable;
};
light_flat = {
@inherit = $compose_base;
color = $color.lights;
tasks = (
{ func = lighting_draw_flats; },
);
stages = (
$lighting.shader.vertex_flat,
$lighting.shader.fragment_splat,
);
vertexInput = $lighting.vertexInput_flat;
layout = $lighting.layout;
};
};

View file

@ -1,46 +1,17 @@
#version 450
#extension GL_GOOGLE_include_directive : enable
layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput depth;
layout (input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput color;
layout (input_attachment_index = 2, set = 0, binding = 2) uniform subpassInput emission;
layout (input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput normal;
layout (input_attachment_index = 4, set = 0, binding = 4) uniform subpassInput position;
#include "lighting.h"
struct LightData {
vec4 color; // .a is intensity
vec4 position; // .w = 0 -> directional, .w = 1 -> point/cone
vec4 direction; // .w = -cos(cone_angle/2) (1 for omni/dir)
vec4 attenuation;
};
layout (input_attachment_index = 0, set = 2, binding = 0) uniform subpassInput depth;
layout (input_attachment_index = 1, set = 2, binding = 1) uniform subpassInput color;
layout (input_attachment_index = 2, set = 2, binding = 2) uniform subpassInput emission;
layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInput normal;
layout (input_attachment_index = 4, set = 2, binding = 4) uniform subpassInput position;
#define StyleMask 0x07f
#define ModelMask 0x380
#define ShadowMask 0xc00
#define LM_LINEAR (0 << 7) // light - dist (or radius + dist if -ve)
#define LM_INVERSE (1 << 7) // distFactor1 * light / dist
#define LM_INVERSE2 (2 << 7) // distFactor2 * light / (dist * dist)
#define LM_INFINITE (3 << 7) // light
#define LM_AMBIENT (4 << 7) // light
#define LM_INVERSE3 (5 << 7) // distFactor2 * light / (dist + distFactor2)**2
#define ST_NONE (0 << 10) // no shadows
#define ST_PLANE (1 << 10) // single plane shadow map (small spotlight)
#define ST_CASCADE (2 << 10) // cascaded shadow maps
#define ST_CUBE (3 << 10) // cubemap (omni, large spotlight)
layout (constant_id = 0) const int MaxLights = 768;
layout (set = 2, binding = 0) uniform sampler2DArrayShadow shadowCascade[MaxLights];
layout (set = 2, binding = 0) uniform sampler2DShadow shadowPlane[MaxLights];
layout (set = 2, binding = 0) uniform samplerCubeShadow shadowCube[MaxLights];
layout (set = 1, binding = 0) uniform Lights {
LightData lights[MaxLights];
int lightCount;
//mat4 shadowMat[MaxLights];
//vec4 shadowCascale[MaxLights];
};
layout (set = 3, binding = 0) uniform sampler2DArrayShadow shadowCascade[MaxLights];
layout (set = 3, binding = 0) uniform sampler2DShadow shadowPlane[MaxLights];
layout (set = 3, binding = 0) uniform samplerCubeShadow shadowCube[MaxLights];
layout (location = 0) out vec4 frag_color;
@ -118,5 +89,5 @@ main (void)
}
//light = max (light, minLight);
frag_color = vec4 (c * light + e, 1);
frag_color = vec4 (light, 1);
}

View file

@ -248,19 +248,20 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
QFV_PacketCopyBuffer (packet, lframe->data_buffer, 0,
&bufferBarriers[qfv_BB_TransferWrite_to_UniformRead]);
QFV_PacketSubmit (packet);
packet = QFV_PacketAcquire (ctx->staging);
uint32_t id_count = lframe->ico_count + lframe->cone_count
+ lframe->flat_count;
uint32_t *ids = QFV_PacketExtend (packet, id_count * sizeof (uint32_t));
memcpy (ids, ico_ids, lframe->ico_count * sizeof (uint32_t));
ids += lframe->ico_count;
memcpy (ids, cone_ids, lframe->cone_count * sizeof (uint32_t));
ids += lframe->cone_count;
memcpy (ids, flat_ids, lframe->flat_count * sizeof (uint32_t));
QFV_PacketCopyBuffer (packet, lframe->id_buffer, 0,
if (0) {
packet = QFV_PacketAcquire (ctx->staging);
uint32_t id_count = lframe->ico_count + lframe->cone_count
+ lframe->flat_count;
uint32_t *ids = QFV_PacketExtend (packet, id_count * sizeof (uint32_t));
memcpy (ids, ico_ids, lframe->ico_count * sizeof (uint32_t));
ids += lframe->ico_count;
memcpy (ids, cone_ids, lframe->cone_count * sizeof (uint32_t));
ids += lframe->cone_count;
memcpy (ids, flat_ids, lframe->flat_count * sizeof (uint32_t));
QFV_PacketCopyBuffer (packet, lframe->id_buffer, 0,
&bufferBarriers[qfv_BB_TransferWrite_to_IndexRead]);
QFV_PacketSubmit (packet);
QFV_PacketSubmit (packet);
}
}
static VkDescriptorBufferInfo base_buffer_info = {
@ -334,15 +335,16 @@ lighting_bind_descriptors (const exprval_t **params, exprval_t *result,
};
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
layout, 0, 3, sets, 0, 0);
VkBuffer buffers[] = {
lframe->id_buffer,
lctx->splat_verts,
};
VkDeviceSize offsets[] = { 0, 0 };
dfunc->vkCmdBindVertexBuffers (cmd, 0, 2, buffers, offsets);
dfunc->vkCmdBindIndexBuffer (cmd, lctx->splat_inds, 0,
VK_INDEX_TYPE_UINT32);
if (0) {
VkBuffer buffers[] = {
lframe->id_buffer,
lctx->splat_verts,
};
VkDeviceSize offsets[] = { 0, 0 };
dfunc->vkCmdBindVertexBuffers (cmd, 0, 2, buffers, offsets);
dfunc->vkCmdBindIndexBuffer (cmd, lctx->splat_inds, 0,
VK_INDEX_TYPE_UINT32);
}
}
static void
@ -386,6 +388,25 @@ lighting_draw_flats (const exprval_t **params, exprval_t *result,
dfunc->vkCmdDraw (cmd, 3, lframe->flat_count, 0, splat_count);
}
static void
lighting_draw_lights (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 lctx = ctx->lighting_context;
auto cmd = taskctx->cmd;
auto lframe = &lctx->frames.a[ctx->curFrame];
if (!(lframe->ico_count + lframe->cone_count + lframe->flat_count)) {
return;
}
dfunc->vkCmdDraw (cmd, 3, 1, 0, 0);
}
static exprfunc_t lighting_update_lights_func[] = {
{ .func = lighting_update_lights },
{}
@ -406,6 +427,10 @@ static exprfunc_t lighting_draw_flats_func[] = {
{ .func = lighting_draw_flats },
{}
};
static exprfunc_t lighting_draw_lights_func[] = {
{ .func = lighting_draw_lights },
{}
};
static exprsym_t lighting_task_syms[] = {
{ "lighting_update_lights", &cexpr_function, lighting_update_lights_func },
{ "lighting_update_descriptors", &cexpr_function,
@ -414,6 +439,7 @@ static exprsym_t lighting_task_syms[] = {
lighting_bind_descriptors_func },
{ "lighting_draw_splats", &cexpr_function, lighting_draw_splats_func },
{ "lighting_draw_flats", &cexpr_function, lighting_draw_flats_func },
{ "lighting_draw_lights", &cexpr_function, lighting_draw_lights_func },
{}
};