mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 06:10:56 +00:00
[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:
parent
49dab2af85
commit
afa84afc79
3 changed files with 68 additions and 85 deletions
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 },
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue