[vulkan] Hook up all the shadow resources

This gets everything but the actual shadow map bindings working: the
validation layers don't like my type punning (which may well be the
right thing) and specialization constants don't help (yet, anyway) but I
want to get things into git.
This commit is contained in:
Bill Currie 2023-08-01 23:34:08 +09:00
parent 7487a00b36
commit 00040c8900
9 changed files with 511 additions and 160 deletions

View file

@ -49,10 +49,17 @@ typedef struct qfv_lightmatset_s DARRAY_TYPE (mat4f_t) qfv_lightmatset_t;
#define ST_CASCADE 2 // cascaded shadow maps #define ST_CASCADE 2 // cascaded shadow maps
#define ST_CUBE 3 // cubemap (omni, large spotlight) #define ST_CUBE 3 // cubemap (omni, large spotlight)
typedef struct qfv_light_buffer_s { typedef struct qfv_lightid_buffer_s {
light_t lights[MaxLights] __attribute__((aligned(16))); uint32_t lightCount;
int lightCount; uint32_t lightIds[MaxLights];
} qfv_light_buffer_t; } qfv_lightid_buffer_t;
typedef struct qfv_light_render_s {
// mat_id (13) map_id (5) layer (11) type (2)
uint32_t id_data;
// light style (6)
uint32_t style;
} qfv_light_render_t;
#define LIGHTING_BUFFER_INFOS 1 #define LIGHTING_BUFFER_INFOS 1
#define LIGHTING_ATTACH_INFOS 4 #define LIGHTING_ATTACH_INFOS 4
@ -69,6 +76,8 @@ typedef struct lightingframe_s {
VkBuffer shadowmat_buffer; VkBuffer shadowmat_buffer;
VkBuffer light_buffer; VkBuffer light_buffer;
VkBuffer render_buffer;
VkBuffer style_buffer;
VkBuffer id_buffer; VkBuffer id_buffer;
uint32_t ico_count; uint32_t ico_count;
uint32_t cone_count; uint32_t cone_count;
@ -81,18 +90,20 @@ typedef struct lightingframe_s {
typedef struct lightingframeset_s typedef struct lightingframeset_s
DARRAY_TYPE (lightingframe_t) lightingframeset_t; DARRAY_TYPE (lightingframe_t) lightingframeset_t;
typedef struct light_renderer_s { typedef struct light_control_s {
uint8_t renderpass_index; uint8_t renderpass_index;
uint8_t image_index; uint8_t map_index;
uint16_t size; uint16_t size;
uint16_t layer; uint16_t layer;
uint8_t numLayers; uint8_t numLayers;
uint8_t mode; uint8_t mode;
uint16_t matrix_base; uint16_t light_id;
} light_renderer_t; uint16_t matrix_base;// for rendering maps
uint16_t matrix_id; // for rendering shadows
} light_control_t;
typedef struct light_renderer_set_s typedef struct light_control_set_s
DARRAY_TYPE (light_renderer_t) light_renderer_set_t; DARRAY_TYPE (light_control_t) light_control_set_t;
typedef struct lightingctx_s { typedef struct lightingctx_s {
@ -103,14 +114,21 @@ typedef struct lightingctx_s {
qfv_lightmatset_t light_mats; qfv_lightmatset_t light_mats;
qfv_imageset_t light_images; qfv_imageset_t light_images;
qfv_imageviewset_t light_views;
light_renderer_set_t light_renderers; light_control_set_t light_control;
qfv_attachmentinfo_t shadow_info; qfv_attachmentinfo_t shadow_info;
VkSampler shadow_sampler;
VkDescriptorSet shadow_set;
VkBuffer splat_verts; VkBuffer splat_verts;
VkBuffer splat_inds; VkBuffer splat_inds;
uint32_t dynamic_base;
uint32_t dynamic_matrix_base;
uint32_t dynamic_count;
struct lightingdata_s *ldata; struct lightingdata_s *ldata;
struct scene_s *scene; struct scene_s *scene;
} lightingctx_t; } lightingctx_t;

View file

@ -155,6 +155,7 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions)
.multiviewGeometryShader = 1, .multiviewGeometryShader = 1,
}; };
VkPhysicalDeviceFeatures features = { VkPhysicalDeviceFeatures features = {
.imageCubeArray = 1,
.independentBlend = 1, .independentBlend = 1,
.geometryShader = 1, .geometryShader = 1,
.multiViewport = 1, .multiViewport = 1,

View file

@ -618,10 +618,51 @@ properties = {
name = main; name = main;
module = $builtin/light_splat.frag; module = $builtin/light_splat.frag;
}; };
fragment = { shadow_specialization = {
mapEntries = (
// ShadowType
{ size = 4; offset = 0; constantID = 0; },
);
};
fragment_none = {
stage = fragment; stage = fragment;
name = main; name = main;
module = $builtin/lighting.frag; module = $builtin/lighting.frag;
specializationInfo = {
@inherit = $lighting.shader.shadow_specialization;
// ShadowType
data = "array(0)";
};
};
fragment_plane = {
stage = fragment;
name = main;
module = $builtin/lighting.frag;
specializationInfo = {
@inherit = $lighting.shader.shadow_specialization;
// ShadowType
data = "array(1)";
};
};
fragment_cascade = {
stage = fragment;
name = main;
module = $builtin/lighting.frag;
specializationInfo = {
@inherit = $lighting.shader.shadow_specialization;
// ShadowType
data = "array(2)";
};
};
fragment_cube = {
stage = fragment;
name = main;
module = $builtin/lighting.frag;
specializationInfo = {
@inherit = $lighting.shader.shadow_specialization;
// ShadowType
data = "array(3)";
};
}; };
debug_fragment = { debug_fragment = {
stage = fragment; stage = fragment;
@ -651,8 +692,11 @@ properties = {
topology = triangle_fan; topology = triangle_fan;
primitiveRestartEnable = true; primitiveRestartEnable = true;
}; };
splat_layout = {
descriptorSets = (matrix_set, lighting_lights);
};
layout = { layout = {
descriptorSets = (matrix_set, lighting_lights, descriptorSets = (shadowmat_set, lighting_lights,
lighting_attach, lighting_shadow); lighting_attach, lighting_shadow);
}; };
}; };
@ -929,10 +973,28 @@ descriptorSetLayouts = {
bindings = ( bindings = (
{ {
binding = 0; binding = 0;
descriptorType = uniform_buffer; descriptorType = storage_buffer;
descriptorCount = 1; descriptorCount = 1;
stageFlags = vertex|fragment; stageFlags = vertex|fragment;
}, },
{
binding = 1;
descriptorType = storage_buffer;
descriptorCount = 1;
stageFlags = vertex|fragment;
},
{
binding = 2;
descriptorType = storage_buffer;
descriptorCount = 1;
stageFlags = fragment;
},
{
binding = 3;
descriptorType = storage_buffer;
descriptorCount = 1;
stageFlags = fragment;
},
); );
}; };
lighting_shadow = { lighting_shadow = {
@ -1520,19 +1582,71 @@ renderpasses = {
preserve = (depth, output); preserve = (depth, output);
}; };
pipelines = { pipelines = {
lights = { lights_none = {
@inherit = $compose_base; @inherit = $compose_base;
color = $color.lights; color = $color.lights;
tasks = ( tasks = (
{ func = lighting_update_descriptors; }, { func = lighting_bind_descriptors;
{ func = lighting_bind_descriptors; }, params = (none); },
{ func = lighting_draw_lights; }, { func = lighting_draw_lights;
params = (none); },
); );
stages = ( stages = (
$fstriangle.shader.vertex, $fstriangle.shader.vertex,
$lighting.shader.fragment, $lighting.shader.fragment_none,
);
layout = $lighting.layout;
};
lights_plane = {
@inherit = $compose_base;
color = $color.lights;
tasks = (
{ func = lighting_bind_descriptors;
params = (plane); },
{ func = lighting_draw_lights;
params = (plane); },
);
stages = (
$fstriangle.shader.vertex,
$lighting.shader.fragment_plane,
);
layout = $lighting.layout;
};
lights_cascade = {
@inherit = $compose_base;
color = $color.lights;
tasks = (
{ func = lighting_bind_descriptors;
params = (cascade); },
{ func = lighting_draw_lights;
params = (cascade); },
);
stages = (
$fstriangle.shader.vertex,
$lighting.shader.fragment_cascade,
);
layout = $lighting.layout;
};
lights_cube = {
@inherit = $compose_base;
color = $color.lights;
tasks = (
{ func = lighting_bind_descriptors;
params = (cube); },
{ func = lighting_draw_lights;
params = (cube); },
);
stages = (
$fstriangle.shader.vertex,
$lighting.shader.fragment_cube,
); );
layout = $lighting.layout; layout = $lighting.layout;
}; };
@ -1623,7 +1737,7 @@ renderpasses = {
); );
vertexInput = $lighting.vertexInput_splat; vertexInput = $lighting.vertexInput_splat;
inputAssembly = $lighting.inputAssembly; inputAssembly = $lighting.inputAssembly;
layout = $lighting.layout; layout = $lighting.splat_layout;
rasterization = $debug_poly_lines; rasterization = $debug_poly_lines;
depthStencil = $depth_disable; depthStencil = $depth_disable;
}; };
@ -1993,6 +2107,8 @@ steps = {
{ func = clear_translucent; { func = clear_translucent;
params = ("\"main\""); }, params = ("\"main\""); },
{ func = particle_wait_physics; }, { func = particle_wait_physics; },
{ func = lighting_update_descriptors;
params = ("\"main\""); },
); );
}; };
}; };

View file

@ -8,9 +8,9 @@ layout (input_attachment_index = 1, set = 2, binding = 1) uniform subpassInput e
layout (input_attachment_index = 2, set = 2, binding = 2) uniform subpassInput normal; layout (input_attachment_index = 2, set = 2, binding = 2) uniform subpassInput normal;
layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInput position; layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInput position;
layout (set = 3, binding = 0) uniform sampler2DArrayShadow shadowCascade[MaxLights]; layout (set = 3, binding = 0) uniform sampler2DArrayShadow shadowCascade[32];
layout (set = 3, binding = 0) uniform sampler2DShadow shadowPlane[MaxLights]; layout (set = 3, binding = 0) uniform sampler2DShadow shadowPlane[32];
layout (set = 3, binding = 0) uniform samplerCubeShadow shadowCube[MaxLights]; layout (set = 3, binding = 0) uniform samplerCubeShadow shadowCube[32];
layout (location = 0) flat in uint light_index; layout (location = 0) flat in uint light_index;
layout (location = 0) out vec4 frag_color; layout (location = 0) out vec4 frag_color;

View file

@ -8,12 +8,14 @@ layout (input_attachment_index = 1, set = 2, binding = 1) uniform subpassInput e
layout (input_attachment_index = 2, set = 2, binding = 2) uniform subpassInput normal; layout (input_attachment_index = 2, set = 2, binding = 2) uniform subpassInput normal;
layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInput position; layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInput position;
layout (set = 3, binding = 0) uniform sampler2DArrayShadow shadowCascade[MaxLights]; layout (set = 3, binding = 0) uniform sampler2DArrayShadow shadowCascade[32];
layout (set = 3, binding = 0) uniform sampler2DShadow shadowPlane[MaxLights]; layout (set = 3, binding = 0) uniform sampler2DArrayShadow shadowPlane[32];
layout (set = 3, binding = 0) uniform samplerCubeShadow shadowCube[MaxLights]; layout (set = 3, binding = 0) uniform samplerCubeArrayShadow shadowCube[32];
layout (location = 0) out vec4 frag_color; layout (location = 0) out vec4 frag_color;
layout (constant_id = 0) const int ShadowType = ST_NONE;
float float
spot_cone (LightData light, vec3 incoming) spot_cone (LightData light, vec3 incoming)
{ {
@ -31,19 +33,19 @@ diffuse (vec3 incoming, vec3 normal)
} }
float float
shadow_cascade (sampler2DArrayShadow map) shadow_cascade (sampler2DArrayShadow map, uint layer, uint mat_id, vec3 pos)
{ {
return 1; return 1;
} }
float float
shadow_plane (sampler2DShadow map) shadow_plane (sampler2DArrayShadow map, uint layer, uint mat_id, vec3 pos)
{ {
return 1; return 1;
} }
float float
shadow_cube (samplerCubeShadow map) shadow_cube (samplerCubeArrayShadow map, uint layer, uint mat_id, vec3 pos)
{ {
return 1; return 1;
} }
@ -59,7 +61,8 @@ main (void)
//vec3 minLight = vec3 (0); //vec3 minLight = vec3 (0);
for (int i = 0; i < lightCount; i++) { for (int i = 0; i < lightCount; i++) {
LightData l = lights[i]; uint id = lightIds[i];
LightData l = lights[id];
vec3 dir = l.position.xyz - l.position.w * p; vec3 dir = l.position.xyz - l.position.w * p;
float r2 = dot (dir, dir); float r2 = dot (dir, dir);
vec4 a = l.attenuation; vec4 a = l.attenuation;
@ -71,19 +74,26 @@ main (void)
vec3 incoming = dir / r.y; vec3 incoming = dir / r.y;
float I = (1 - a.w * r.y) / dot (a, r); float I = (1 - a.w * r.y) / dot (a, r);
/*int shadow = lights[i].data & ShadowMask; uint id_data = renderer[id].id_data;
if (shadow == ST_CASCADE) { uint mat_id = bitfieldExtract (id_data, 0, 13);
I *= shadow_cascade (shadowCascade[i]); uint map_id = bitfieldExtract (id_data, 13, 5);
} else if (shadow == ST_PLANE) { uint layer = bitfieldExtract (id_data, 18, 11);
I *= shadow_plane (shadowPlane[i]); if (ShadowType == ST_CASCADE) {
} else if (shadow == ST_CUBE) { I *= shadow_cascade (shadowCascade[map_id], layer, mat_id, p);
I *= shadow_cube (shadowCube[i]); } else if (ShadowType == ST_PLANE) {
}*/ I *= shadow_plane (shadowPlane[map_id], layer, mat_id, p);
} else if (ShadowType == ST_CUBE) {
I *= shadow_cube (shadowCube[map_id], layer, mat_id, p);
}
float namb = dot(l.direction.xyz, l.direction.xyz); float namb = dot(l.direction.xyz, l.direction.xyz);
I *= spot_cone (l, incoming) * diffuse (incoming, n); I *= spot_cone (l, incoming) * diffuse (incoming, n);
I = mix (1, I, namb); I = mix (1, I, namb);
light += I * l.color.w * l.color.xyz; vec4 col = l.color;
if (bitfieldExtract(id_data, 31, 1) == 0) {
col *= style[renderer[id].style];
}
light += I * col.w * col.xyz;
} }
//light = max (light, minLight); //light = max (light, minLight);

View file

@ -5,9 +5,26 @@ struct LightData {
vec4 attenuation; vec4 attenuation;
}; };
layout (constant_id = 0) const int MaxLights = 768; #define ST_NONE 0 // no shadows
#define ST_PLANE 1 // single plane shadow map (small spotlight)
#define ST_CASCADE 2 // cascaded shadow maps
#define ST_CUBE 3 // cubemap (omni, large spotlight)
layout (set = 1, binding = 0) uniform Lights { struct LightRender {
LightData lights[MaxLights]; uint id_data;
int lightCount; uint style;
};
layout (set = 1, binding = 0) buffer LightIds {
uint lightCount;
uint lightIds[];
};
layout (set = 1, binding = 1) buffer Lights {
LightData lights[];
};
layout (set = 1, binding = 2) buffer Renderer {
LightRender renderer[];
};
layout (set = 1, binding = 3) buffer Style {
vec4 style[];
}; };

View file

@ -1,25 +0,0 @@
#version 450
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
layout (constant_id = 0) const int MaxLights = 128;
layout (set = 0, binding = 0) uniform UBO {
mat4 vp[MaxLights];
} ubo;
layout (location = 0) in int InstanceIndex[];
void
main (void)
{
int index = InstanceIndex[0];
for (int i = 0; i < gl_in.length(); i++) {
gl_Layer = index;
gl_Position = ubo.vp[index] * gl_in[i].gl_Position;
EmitVertex();
}
EndPrimitive();
}

View file

@ -112,10 +112,10 @@ samplers = {
anisotropyEnable = false; anisotropyEnable = false;
maxAnisotropy = 0; maxAnisotropy = 0;
compareEnable = true; compareEnable = true;
compareOp = greater_or_equal; compareOp = less;
minLod = 0; minLod = 0;
maxLod = 1000; maxLod = 1000;
borderColor = float_transparent_black; borderColor = float_opaque_white;
unnormalizedCoordinates = false; unnormalizedCoordinates = false;
}; };
linear = { linear = {

View file

@ -101,10 +101,10 @@ get_light (entity_t ent)
return Ent_GetComponent (ent.id, scene_light, ent.reg); return Ent_GetComponent (ent.id, scene_light, ent.reg);
} }
static int static uint32_t
get_lightstyle (entity_t ent) get_lightstyle (entity_t ent)
{ {
return *(int *) Ent_GetComponent (ent.id, scene_lightstyle, ent.reg); return *(uint32_t *) Ent_GetComponent (ent.id, scene_lightstyle, ent.reg);
} }
static uint32_t static uint32_t
@ -180,7 +180,7 @@ lighting_setup_aux (const exprval_t **params, exprval_t *result,
} }
static VkImageView static VkImageView
create_view (vulkan_ctx_t *ctx, light_renderer_t *renderer) create_view (vulkan_ctx_t *ctx, light_control_t *renderer)
{ {
auto device = ctx->device; auto device = ctx->device;
auto dfunc = device->funcs; auto dfunc = device->funcs;
@ -188,7 +188,7 @@ create_view (vulkan_ctx_t *ctx, light_renderer_t *renderer)
VkImageViewCreateInfo cInfo = { VkImageViewCreateInfo cInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = lctx->light_images.a[renderer->image_index], .image = lctx->light_images.a[renderer->map_index],
.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY, .viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
.format = VK_FORMAT_X8_D24_UNORM_PACK32, .format = VK_FORMAT_X8_D24_UNORM_PACK32,
.subresourceRange = { .subresourceRange = {
@ -204,7 +204,7 @@ create_view (vulkan_ctx_t *ctx, light_renderer_t *renderer)
} }
static VkFramebuffer static VkFramebuffer
create_framebuffer (vulkan_ctx_t *ctx, light_renderer_t *renderer, create_framebuffer (vulkan_ctx_t *ctx, light_control_t *renderer,
VkImageView view, VkRenderPass renderpass) VkImageView view, VkRenderPass renderpass)
{ {
auto device = ctx->device; auto device = ctx->device;
@ -264,7 +264,7 @@ lighting_draw_shadow_maps (const exprval_t **params, exprval_t *result,
entity_t ent = queue->ent_queues[mod_light].a[i]; entity_t ent = queue->ent_queues[mod_light].a[i];
auto ls = get_lightstyle (ent); auto ls = get_lightstyle (ent);
uint32_t id = get_lightid (ent); uint32_t id = get_lightid (ent);
auto r = &lctx->light_renderers.a[id]; auto r = &lctx->light_control.a[id];
if (!r->numLayers || !d_lightstylevalue[ls]) { if (!r->numLayers || !d_lightstylevalue[ls]) {
continue; continue;
} }
@ -297,39 +297,64 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
return; return;
} }
dlight_t *lights[MaxLights]; auto bb = &bufferBarriers[qfv_BB_TransferWrite_to_UniformRead];
auto packet = QFV_PacketAcquire (ctx->staging);
qfv_light_buffer_t *light_data = QFV_PacketExtend (packet,
sizeof (*light_data));
float style_intensities[NumStyles]; auto packet = QFV_PacketAcquire (ctx->staging);
vec4f_t *styles = QFV_PacketExtend (packet, sizeof (vec4f_t[NumStyles]));
for (int i = 0; i < NumStyles; i++) { for (int i = 0; i < NumStyles; i++) {
style_intensities[i] = d_lightstylevalue[i] / 65536.0; styles[i] = (vec4f_t) { 1, 1, 1, d_lightstylevalue[i] / 65536.0};
} }
QFV_PacketCopyBuffer (packet, lframe->style_buffer, 0, bb);
QFV_PacketSubmit (packet);
uint32_t ico_ids[MaxLights]; uint32_t ico_ids[MaxLights];
uint32_t cone_ids[MaxLights]; uint32_t cone_ids[MaxLights];
uint32_t flat_ids[MaxLights]; uint32_t flat_ids[MaxLights];
light_data->lightCount = 0; uint32_t light_count = 0;
R_FindNearLights (r_refdef.frame.position, MaxLights - 1, lights);
for (int i = 0; i < MaxLights - 1; i++) {
if (!lights[i]) {
break;
}
ico_ids[lframe->ico_count++] = light_data->lightCount++;
VectorCopy (lights[i]->color, light_data->lights[i].color); dlight_t *dynamic_lights[MaxLights];
// dynamic lights seem a tad faint, so 16x map lights int maxdlight = MaxLights - lctx->dynamic_base;
light_data->lights[i].color[3] = lights[i]->radius / 16; int ndlight = R_FindNearLights (r_refdef.frame.position, maxdlight,
VectorCopy (lights[i]->origin, light_data->lights[i].position); dynamic_lights);
// dlights are local point sources
light_data->lights[i].position[3] = 1; if (ndlight) {
light_data->lights[i].attenuation = packet = QFV_PacketAcquire (ctx->staging);
(vec4f_t) { 0, 0, 1, 1/lights[i]->radius }; light_t *lights = QFV_PacketExtend (packet, sizeof (light_t[ndlight]));
// full sphere, normal light (not ambient) for (int i = 0; i < ndlight; i++) {
light_data->lights[i].direction = (vec4f_t) { 0, 0, 1, 1 }; ico_ids[lframe->ico_count++] = lctx->dynamic_base + light_count++;
VectorCopy (dynamic_lights[i]->color, lights[i].color);
// dynamic lights seem a tad faint, so 16x map lights
lights[i].color[3] = dynamic_lights[i]->radius / 16;
VectorCopy (dynamic_lights[i]->origin, lights[i].position);
// dlights are local point sources
lights[i].position[3] = 1;
lights[i].attenuation =
(vec4f_t) { 0, 0, 1, 1/dynamic_lights[i]->radius };
// full sphere, normal light (not ambient)
lights[i].direction = (vec4f_t) { 0, 0, 1, 1 };
}
VkDeviceSize dlight_offset = sizeof (light_t[lctx->dynamic_base]);
QFV_PacketCopyBuffer (packet, lframe->light_buffer, dlight_offset, bb);
QFV_PacketSubmit (packet);
packet = QFV_PacketAcquire (ctx->staging);
uint32_t r_size = sizeof (qfv_light_render_t[ndlight]);
qfv_light_render_t *render = QFV_PacketExtend (packet, r_size);
for (int i = 0; i < ndlight; i++) {
render[i] = (qfv_light_render_t) {
//.id_data = make_id(r->matrix_id, r->map_index, r->layer,
//r->mode),
.id_data = 0x80000000, // no style
.style = 11,
};
}
dlight_offset = sizeof (qfv_light_render_t[lctx->dynamic_base]);
QFV_PacketCopyBuffer (packet, lframe->render_buffer, dlight_offset, bb);
QFV_PacketSubmit (packet);
} }
auto queue = r_ent_queue; //FIXME fetch from scene auto queue = r_ent_queue; //FIXME fetch from scene
for (size_t i = 0; i < queue->ent_queues[mod_light].size; i++) { for (size_t i = 0; i < queue->ent_queues[mod_light].size; i++) {
entity_t ent = queue->ent_queues[mod_light].a[i]; entity_t ent = queue->ent_queues[mod_light].a[i];
@ -339,13 +364,11 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
continue; continue;
} }
uint32_t id = light_data->lightCount++; light_count++;
auto light = &light_data->lights[id]; uint32_t id = lctx->light_control.a[get_lightid (ent)].light_id;
*light = *l; if (l->position[3] && !VectorIsZero (l->direction)
light->color[3] *= style_intensities[ls]; && l->attenuation[3]) {
if (light->position[3] && !VectorIsZero (light->direction) if (l->direction[3] < 0) {
&& light->attenuation[3]) {
if (light->direction[3] < 0) {
cone_ids[lframe->cone_count++] = id; cone_ids[lframe->cone_count++] = id;
} else { } else {
ico_ids[lframe->ico_count++] = id; ico_ids[lframe->ico_count++] = id;
@ -356,18 +379,20 @@ lighting_update_lights (const exprval_t **params, exprval_t *result,
} }
if (developer & SYS_lighting) { if (developer & SYS_lighting) {
Vulkan_Draw_String (vid.width - 32, 8, Vulkan_Draw_String (vid.width - 32, 8,
va (ctx->va_ctx, "%3d", light_data->lightCount), va (ctx->va_ctx, "%3d", light_count),
ctx); ctx);
} }
QFV_PacketCopyBuffer (packet, lframe->light_buffer, 0,
&bufferBarriers[qfv_BB_TransferWrite_to_UniformRead]);
QFV_PacketSubmit (packet);
uint32_t id_count = lframe->ico_count + lframe->cone_count uint32_t id_count = lframe->ico_count + lframe->cone_count
+ lframe->flat_count; + lframe->flat_count;
if (id_count != light_count) {
Sys_Error ("taniwha can't count: %d != %d", id_count, light_count);
}
if (id_count) { if (id_count) {
packet = QFV_PacketAcquire (ctx->staging); packet = QFV_PacketAcquire (ctx->staging);
uint32_t *ids = QFV_PacketExtend (packet, id_count * sizeof (uint32_t)); uint32_t *count = QFV_PacketExtend (packet, sizeof (uint32_t));
*count = id_count;
uint32_t *ids = QFV_PacketExtend (packet, sizeof (uint32_t[id_count]));
memcpy (ids, ico_ids, lframe->ico_count * sizeof (uint32_t)); memcpy (ids, ico_ids, lframe->ico_count * sizeof (uint32_t));
ids += lframe->ico_count; ids += lframe->ico_count;
memcpy (ids, cone_ids, lframe->cone_count * sizeof (uint32_t)); memcpy (ids, cone_ids, lframe->cone_count * sizeof (uint32_t));
@ -391,7 +416,10 @@ 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 job = ctx->render_context->job;
auto step = QFV_GetStep (params[0], job);
auto render = step->render;
auto fb = &render->active->framebuffer;
VkDescriptorImageInfo attachInfo[] = { VkDescriptorImageInfo attachInfo[] = {
{ .imageView = fb->views[QFV_attachColor], { .imageView = fb->views[QFV_attachColor],
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
@ -428,7 +456,6 @@ lighting_update_descriptors (const exprval_t **params, exprval_t *result,
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
.pImageInfo = &attachInfo[3], }, .pImageInfo = &attachInfo[3], },
}; };
//lframe->bufferInfo[0].buffer = lframe->light_buffer;
dfunc->vkUpdateDescriptorSets (device->dev, dfunc->vkUpdateDescriptorSets (device->dev,
LIGHTING_ATTACH_INFOS, attachWrite, LIGHTING_ATTACH_INFOS, attachWrite,
0, 0); 0, 0);
@ -449,18 +476,20 @@ lighting_bind_descriptors (const exprval_t **params, exprval_t *result,
auto lframe = &lctx->frames.a[ctx->curFrame]; auto lframe = &lctx->frames.a[ctx->curFrame];
VkDescriptorSet sets[] = { VkDescriptorSet sets[] = {
Vulkan_Matrix_Descriptors (ctx, ctx->curFrame), //Vulkan_Matrix_Descriptors (ctx, ctx->curFrame),
lframe->shadowmat_set,
lframe->lights_set, lframe->lights_set,
lframe->attach_set, lframe->attach_set,
lctx->shadow_set,
}; };
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
layout, 0, 3, sets, 0, 0); layout, 0, 4, sets, 0, 0);
if (1) { if (1) {
VkBuffer buffers[] = { VkBuffer buffers[] = {
lframe->id_buffer, lframe->id_buffer,
lctx->splat_verts, lctx->splat_verts,
}; };
VkDeviceSize offsets[] = { 0, 0 }; VkDeviceSize offsets[] = { sizeof (uint32_t), 0 };
dfunc->vkCmdBindVertexBuffers (cmd, 0, 2, buffers, offsets); dfunc->vkCmdBindVertexBuffers (cmd, 0, 2, buffers, offsets);
dfunc->vkCmdBindIndexBuffer (cmd, lctx->splat_inds, 0, dfunc->vkCmdBindIndexBuffer (cmd, lctx->splat_inds, 0,
VK_INDEX_TYPE_UINT32); VK_INDEX_TYPE_UINT32);
@ -527,6 +556,31 @@ lighting_draw_lights (const exprval_t **params, exprval_t *result,
dfunc->vkCmdDraw (cmd, 3, 1, 0, 0); dfunc->vkCmdDraw (cmd, 3, 1, 0, 0);
} }
static exprenum_t shadow_type_enum;
static exprtype_t shadow_type_type = {
.name = "shadow_type",
.size = sizeof (int),
.get_string = cexpr_enum_get_string,
.data = &shadow_type_enum,
};
static int shadow_type_values[] = { ST_NONE, ST_PLANE, ST_CASCADE, ST_CUBE };
static exprsym_t shadow_type_symbols[] = {
{"none", &shadow_type_type, shadow_type_values + 0},
{"plane", &shadow_type_type, shadow_type_values + 1},
{"cascade", &shadow_type_type, shadow_type_values + 2},
{"cube", &shadow_type_type, shadow_type_values + 3},
{}
};
static exprtab_t shadow_type_symtab = { .symbols = shadow_type_symbols };
static exprenum_t shadow_type_enum = {
&shadow_type_type,
&shadow_type_symtab,
};
static exprtype_t *shadow_type_param[] = {
&shadow_type_type,
};
static exprtype_t *stepref_param[] = { static exprtype_t *stepref_param[] = {
&cexpr_string, &cexpr_string,
}; };
@ -536,11 +590,13 @@ static exprfunc_t lighting_update_lights_func[] = {
{} {}
}; };
static exprfunc_t lighting_update_descriptors_func[] = { static exprfunc_t lighting_update_descriptors_func[] = {
{ .func = lighting_update_descriptors }, { .func = lighting_update_descriptors, .num_params = 1,
.param_types = stepref_param },
{} {}
}; };
static exprfunc_t lighting_bind_descriptors_func[] = { static exprfunc_t lighting_bind_descriptors_func[] = {
{ .func = lighting_bind_descriptors }, { .func = lighting_bind_descriptors, .num_params = 1,
.param_types = shadow_type_param },
{} {}
}; };
static exprfunc_t lighting_draw_splats_func[] = { static exprfunc_t lighting_draw_splats_func[] = {
@ -552,7 +608,8 @@ static exprfunc_t lighting_draw_flats_func[] = {
{} {}
}; };
static exprfunc_t lighting_draw_lights_func[] = { static exprfunc_t lighting_draw_lights_func[] = {
{ .func = lighting_draw_lights }, { .func = lighting_draw_lights, .num_params = 1,
.param_types = shadow_type_param },
{} {}
}; };
static exprfunc_t lighting_setup_aux_func[] = { static exprfunc_t lighting_setup_aux_func[] = {
@ -676,7 +733,8 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
DARRAY_INIT (&lctx->light_mats, 16); DARRAY_INIT (&lctx->light_mats, 16);
DARRAY_INIT (&lctx->light_images, 16); DARRAY_INIT (&lctx->light_images, 16);
DARRAY_INIT (&lctx->light_renderers, 16); DARRAY_INIT (&lctx->light_views, 16);
DARRAY_INIT (&lctx->light_control, 16);
auto rctx = ctx->render_context; auto rctx = ctx->render_context;
size_t frames = rctx->frames.size; size_t frames = rctx->frames.size;
@ -693,7 +751,9 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
+ sizeof (qfv_resobj_t[frames]) + sizeof (qfv_resobj_t[frames])
// light data // light data
+ sizeof (qfv_resobj_t[frames]) + sizeof (qfv_resobj_t[frames])
// light matrix ids // light render
+ sizeof (qfv_resobj_t[frames])
// light styles
+ sizeof (qfv_resobj_t[frames]) + sizeof (qfv_resobj_t[frames])
// light matrices // light matrices
+ sizeof (qfv_resobj_t[frames])); + sizeof (qfv_resobj_t[frames]));
@ -701,13 +761,14 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
auto splat_inds = &splat_verts[1]; auto splat_inds = &splat_verts[1];
auto light_ids = &splat_inds[1]; auto light_ids = &splat_inds[1];
auto light_data = &light_ids[frames]; auto light_data = &light_ids[frames];
auto light_matids = &light_data[frames]; auto light_render = &light_data[frames];
auto light_mats = &light_matids[frames]; auto light_styles = &light_render[frames];
auto light_mats = &light_styles[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 + 4 * frames, .num_objects = 2 + 5 * frames,
.objects = splat_verts, .objects = splat_verts,
}; };
splat_verts[0] = (qfv_resobj_t) { splat_verts[0] = (qfv_resobj_t) {
@ -729,20 +790,39 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
}, },
}; };
for (size_t i = 0; i < frames; i++) { for (size_t i = 0; i < frames; i++) {
light_ids[i] = (qfv_resobj_t) {
.name = "ids",
.type = qfv_res_buffer,
.buffer = {
.size = 2 * MaxLights * sizeof (uint32_t),
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
},
};
light_data[i] = (qfv_resobj_t) { light_data[i] = (qfv_resobj_t) {
.name = "lights", .name = "lights",
.type = qfv_res_buffer, .type = qfv_res_buffer,
.buffer = { .buffer = {
.size = sizeof (qfv_light_buffer_t), .size = sizeof (light_t[MaxLights]),
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT, | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
}, },
}; };
light_matids[i] = (qfv_resobj_t) { light_render[i] = (qfv_resobj_t) {
.name = "matrixids", .name = "render",
.type = qfv_res_buffer, .type = qfv_res_buffer,
.buffer = { .buffer = {
.size = sizeof (uint32_t[MaxLights]), .size = sizeof (qfv_light_render_t[MaxLights]),
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
},
};
light_styles[i] = (qfv_resobj_t) {
.name = "styles",
.type = qfv_res_buffer,
.buffer = {
.size = sizeof (vec4f_t[NumStyles]),
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT, | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
}, },
@ -757,15 +837,6 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
| VK_BUFFER_USAGE_TRANSFER_DST_BIT, | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
}, },
}; };
light_ids[i] = (qfv_resobj_t) {
.name = "ids",
.type = qfv_res_buffer,
.buffer = {
.size = 2 * MaxLights * sizeof (uint32_t),
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
},
};
} }
QFV_CreateResource (device, lctx->light_resources); QFV_CreateResource (device, lctx->light_resources);
@ -773,6 +844,12 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
lctx->splat_verts = splat_verts[0].buffer.buffer; lctx->splat_verts = splat_verts[0].buffer.buffer;
lctx->splat_inds = splat_inds[0].buffer.buffer; lctx->splat_inds = splat_inds[0].buffer.buffer;
auto shadow_mgr = QFV_Render_DSManager (ctx, "lighting_shadow");
lctx->shadow_set = QFV_DSManager_AllocSet (shadow_mgr);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET,
lctx->shadow_set, "lighting:shadow_set");
lctx->shadow_sampler = QFV_Render_Sampler (ctx, "shadow_sampler");
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 shadowmat_mgr = QFV_Render_DSManager (ctx, "shadowmat_set"); auto shadowmat_mgr = QFV_Render_DSManager (ctx, "shadowmat_set");
@ -784,6 +861,8 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
.attach_set = QFV_DSManager_AllocSet (attach_mgr), .attach_set = QFV_DSManager_AllocSet (attach_mgr),
.shadowmat_buffer = light_mats[i].buffer.buffer, .shadowmat_buffer = light_mats[i].buffer.buffer,
.light_buffer = light_data[i].buffer.buffer, .light_buffer = light_data[i].buffer.buffer,
.render_buffer = light_render[i].buffer.buffer,
.style_buffer = light_styles[i].buffer.buffer,
.id_buffer = light_ids[i].buffer.buffer, .id_buffer = light_ids[i].buffer.buffer,
}; };
@ -801,26 +880,51 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
lframe->framebuffers = (qfv_framebufferset_t) DARRAY_STATIC_INIT (16); lframe->framebuffers = (qfv_framebufferset_t) DARRAY_STATIC_INIT (16);
VkDescriptorBufferInfo bufferInfo[] = { VkDescriptorBufferInfo bufferInfo[] = {
{ .buffer = lframe->shadowmat_buffer,
.offset = 0, .range = VK_WHOLE_SIZE, },
{ .buffer = lframe->id_buffer,
.offset = 0, .range = VK_WHOLE_SIZE, },
{ .buffer = lframe->light_buffer, { .buffer = lframe->light_buffer,
.offset = 0, .range = VK_WHOLE_SIZE, }, .offset = 0, .range = VK_WHOLE_SIZE, },
{ .buffer = lframe->shadowmat_buffer, { .buffer = lframe->render_buffer,
.offset = 0, .range = VK_WHOLE_SIZE, },
{ .buffer = lframe->style_buffer,
.offset = 0, .range = VK_WHOLE_SIZE, }, .offset = 0, .range = VK_WHOLE_SIZE, },
}; };
VkWriteDescriptorSet bufferWrite[] = { 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, { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->shadowmat_set, .dstSet = lframe->shadowmat_set,
.dstBinding = 0, .dstBinding = 0,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &bufferInfo[0], },
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->lights_set,
.dstBinding = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &bufferInfo[1], }, .pBufferInfo = &bufferInfo[1], },
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->lights_set,
.dstBinding = 1,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &bufferInfo[2], },
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->lights_set,
.dstBinding = 2,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &bufferInfo[3], },
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lframe->lights_set,
.dstBinding = 3,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &bufferInfo[4], },
}; };
dfunc->vkUpdateDescriptorSets (device->dev, 2, bufferWrite, 0, 0); dfunc->vkUpdateDescriptorSets (device->dev, 5, bufferWrite, 0, 0);
} }
auto packet = QFV_PacketAcquire (ctx->staging); auto packet = QFV_PacketAcquire (ctx->staging);
@ -850,7 +954,8 @@ clear_shadows (vulkan_ctx_t *ctx)
lctx->shadow_resources = 0; lctx->shadow_resources = 0;
} }
lctx->light_images.size = 0; lctx->light_images.size = 0;
lctx->light_renderers.size = 0; lctx->light_views.size = 0;
lctx->light_control.size = 0;
} }
void void
@ -873,7 +978,8 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx)
DARRAY_CLEAR (&lctx->light_mats); DARRAY_CLEAR (&lctx->light_mats);
DARRAY_CLEAR (&lctx->light_images); DARRAY_CLEAR (&lctx->light_images);
DARRAY_CLEAR (&lctx->light_renderers); DARRAY_CLEAR (&lctx->light_views);
DARRAY_CLEAR (&lctx->light_control);
free (lctx->frames.a); free (lctx->frames.a);
free (lctx); free (lctx);
} }
@ -890,16 +996,17 @@ create_light_matrices (lightingctx_t *lctx)
for (uint32_t i = 0; i < light_pool->count; i++) { for (uint32_t i = 0; i < light_pool->count; i++) {
entity_t ent = { .reg = reg, .id = light_pool->dense[i] }; entity_t ent = { .reg = reg, .id = light_pool->dense[i] };
uint32_t id = get_lightid (ent); uint32_t id = get_lightid (ent);
auto r = &lctx->light_renderers.a[id]; auto r = &lctx->light_control.a[id];
r->matrix_base = mat_count; r->matrix_base = mat_count;
mat_count += r->numLayers; mat_count += r->numLayers;
} }
DARRAY_RESIZE (&lctx->light_mats, mat_count); DARRAY_RESIZE (&lctx->light_mats, mat_count);
lctx->dynamic_matrix_base = mat_count;
for (uint32_t i = 0; i < light_pool->count; i++) { for (uint32_t i = 0; i < light_pool->count; i++) {
light_t *light = &light_data[i]; light_t *light = &light_data[i];
entity_t ent = { .reg = reg, .id = light_pool->dense[i] }; entity_t ent = { .reg = reg, .id = light_pool->dense[i] };
uint32_t id = get_lightid (ent); uint32_t id = get_lightid (ent);
auto r = &lctx->light_renderers.a[id]; auto r = &lctx->light_control.a[id];
auto lm = &lctx->light_mats.a[r->matrix_base]; auto lm = &lctx->light_mats.a[r->matrix_base];
mat4f_t view; mat4f_t view;
mat4f_t proj; mat4f_t proj;
@ -936,6 +1043,7 @@ create_light_matrices (lightingctx_t *lctx)
mmulf (side_view, qfv_z_up, side_view); mmulf (side_view, qfv_z_up, side_view);
mmulf (lm[j], proj, side_view); mmulf (lm[j], proj, side_view);
} }
r->matrix_id = r->matrix_base + BOX_FRONT;
break; break;
case ST_CASCADE: case ST_CASCADE:
// dependent on view fustrum and cascade level // dependent on view fustrum and cascade level
@ -944,11 +1052,13 @@ create_light_matrices (lightingctx_t *lctx)
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
mmulf (lm[j], proj, view); mmulf (lm[j], proj, view);
} }
r->matrix_id = r->matrix_base;
break; break;
case ST_PLANE: case ST_PLANE:
QFV_PerspectiveCos (proj, -light->direction[3]); QFV_PerspectiveCos (proj, -light->direction[3]);
mmulf (view, qfv_z_up, view); mmulf (view, qfv_z_up, view);
mmulf (lm[0], proj, view); mmulf (lm[0], proj, view);
r->matrix_id = r->matrix_base;
break; break;
} }
} }
@ -969,6 +1079,56 @@ upload_light_matrices (lightingctx_t *lctx, vulkan_ctx_t *ctx)
QFV_PacketSubmit (packet); QFV_PacketSubmit (packet);
} }
static uint32_t
make_id (uint32_t matrix_index, uint32_t map_index, uint32_t layer,
uint32_t type)
{
return ((matrix_index & 0x1fff) << 0)
| ((map_index & 0x1f) << 13)
| ((layer & 0x7ff) << 18)
| ((type & 3) << 29);
}
static void
upload_light_data (lightingctx_t *lctx, vulkan_ctx_t *ctx)
{
auto reg = lctx->scene->reg;
auto light_pool = &reg->comp_pools[scene_light];
auto lights = (light_t *) light_pool->data;
uint32_t count = light_pool->count;
auto packet = QFV_PacketAcquire (ctx->staging);
auto light_data = QFV_PacketExtend (packet, sizeof (light_t[count]));
memcpy (light_data, lights, sizeof (light_t[count]));
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->light_buffer, 0, bb);
}
QFV_PacketSubmit (packet);
packet = QFV_PacketAcquire (ctx->staging);
uint32_t r_size = sizeof (qfv_light_render_t[count]);
qfv_light_render_t *render = QFV_PacketExtend (packet, r_size);
for (uint32_t i = 0; i < count; i++) {
entity_t ent = { .reg = reg, .id = light_pool->dense[i] };
uint32_t id = get_lightid (ent);
auto r = &lctx->light_control.a[id];
render[i] = (qfv_light_render_t) {
.id_data = make_id(r->matrix_id, r->map_index, r->layer, r->mode),
.style = get_lightstyle (ent),
};
}
for (size_t i = 0; i < lctx->frames.size; i++) {
auto lframe = &lctx->frames.a[i];
QFV_PacketCopyBuffer (packet, lframe->render_buffer, 0, bb);
}
QFV_PacketSubmit (packet);
lctx->dynamic_base = count;
lctx->dynamic_count = 0;
}
static int static int
light_compare (const void *_li2, const void *_li1, void *_lights) light_compare (const void *_li2, const void *_li1, void *_lights)
{ {
@ -1001,6 +1161,9 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
qfv_device_t *device = ctx->device; qfv_device_t *device = ctx->device;
qfv_physdev_t *physDev = device->physDev; qfv_physdev_t *physDev = device->physDev;
int maxLayers = physDev->properties->limits.maxImageArrayLayers; int maxLayers = physDev->properties->limits.maxImageArrayLayers;
if (maxLayers > 2048) {
maxLayers = 2048;
}
auto reg = lctx->scene->reg; auto reg = lctx->scene->reg;
auto light_pool = &reg->comp_pools[scene_light]; auto light_pool = &reg->comp_pools[scene_light];
auto lights = (light_t *) light_pool->data; auto lights = (light_t *) light_pool->data;
@ -1018,12 +1181,12 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
} }
heapsort_r (lightMap, numLights, sizeof (int), light_compare, lights); heapsort_r (lightMap, numLights, sizeof (int), light_compare, lights);
DARRAY_RESIZE (&lctx->light_renderers, numLights); DARRAY_RESIZE (&lctx->light_control, numLights);
for (int i = 0; i < numLights; i++) { for (int i = 0; i < numLights; i++) {
int layers = 1; int layers = 1;
auto li = lightMap[i]; auto li = lightMap[i];
auto lr = &lctx->light_renderers.a[li]; auto lr = &lctx->light_control.a[li];
*lr = (light_renderer_t) {}; *lr = (light_control_t) { .light_id = li, };
set_lightid (light_pool->dense[li], reg, li); set_lightid (light_pool->dense[li], reg, li);
if (!lights[li].position[3]) { if (!lights[li].position[3]) {
@ -1078,7 +1241,7 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
for (int i = 0; i < numLights; i++) { for (int i = 0; i < numLights; i++) {
int layers = 4; int layers = 4;
auto li = lightMap[i]; auto li = lightMap[i];
auto lr = &lctx->light_renderers.a[li]; auto lr = &lctx->light_control.a[li];
if (lr->mode != ST_CASCADE) { if (lr->mode != ST_CASCADE) {
continue; continue;
@ -1108,19 +1271,22 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
if (numMaps) { if (numMaps) {
qfv_resource_t *shad = calloc (1, sizeof (qfv_resource_t) qfv_resource_t *shad = calloc (1, sizeof (qfv_resource_t)
+ sizeof (qfv_resobj_t[numMaps])
+ sizeof (qfv_resobj_t[numMaps])); + sizeof (qfv_resobj_t[numMaps]));
lctx->shadow_resources = shad; lctx->shadow_resources = shad;
*shad = (qfv_resource_t) { *shad = (qfv_resource_t) {
.name = "shadow", .name = "shadow",
.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 = numMaps, .num_objects = 2 * numMaps,
.objects = (qfv_resobj_t *) &shad[1], .objects = (qfv_resobj_t *) &shad[1],
}; };
auto images = shad->objects;
auto views = &images[numMaps];
for (int i = 0; i < numMaps; i++) { for (int i = 0; i < numMaps; i++) {
int cube = maps[i].layers < 6 ? 0 : maps[i].cube; int cube = maps[i].layers < 6 ? 0 : maps[i].cube;
shad->objects[i] = (qfv_resobj_t) { images[i] = (qfv_resobj_t) {
.name = va (ctx->va_ctx, "map:%d", maps[i].size), .name = va (ctx->va_ctx, "map:image:%d:%d", i, maps[i].size),
.type = qfv_res_image, .type = qfv_res_image,
.image = { .image = {
.flags = cube ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0, .flags = cube ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0,
@ -1134,16 +1300,32 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
| VK_IMAGE_USAGE_SAMPLED_BIT, | VK_IMAGE_USAGE_SAMPLED_BIT,
}, },
}; };
views[i] = (qfv_resobj_t) {
.name = va (ctx->va_ctx, "map:view:%d:%d", i, maps[i].size),
.type = qfv_res_image_view,
.image_view = {
.image = i,
.type = cube ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY
: VK_IMAGE_VIEW_TYPE_2D_ARRAY,
.format = VK_FORMAT_X8_D24_UNORM_PACK32,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
.levelCount = VK_REMAINING_MIP_LEVELS,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
},
};
} }
QFV_CreateResource (device, shad); QFV_CreateResource (device, shad);
for (int i = 0; i < numMaps; i++) { for (int i = 0; i < numMaps; i++) {
DARRAY_APPEND (&lctx->light_images, shad->objects[i].image.image); DARRAY_APPEND (&lctx->light_images, images[i].image.image);
DARRAY_APPEND (&lctx->light_views, views[i].image_view.view);
} }
} }
for (int i = 0; i < numLights; i++) { for (int i = 0; i < numLights; i++) {
int li = lightMap[i]; int li = lightMap[i];
auto lr = &lctx->light_renderers.a[li]; auto lr = &lctx->light_control.a[li];
if (imageMap[li] == -1) { if (imageMap[li] == -1) {
continue; continue;
@ -1163,7 +1345,7 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
Sys_Error ("build_shadow_maps: invalid light layer count: %u", Sys_Error ("build_shadow_maps: invalid light layer count: %u",
lr->numLayers); lr->numLayers);
} }
lr->image_index = imageMap[li]; lr->map_index = imageMap[li];
} }
Sys_MaskPrintf (SYS_lighting, Sys_MaskPrintf (SYS_lighting,
"shadow maps: %d layers in %zd images: %"PRId64"\n", "shadow maps: %d layers in %zd images: %"PRId64"\n",
@ -1171,6 +1353,36 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
lctx->shadow_resources->size); lctx->shadow_resources->size);
} }
static void
update_shadow_descriptors (lightingctx_t *lctx, vulkan_ctx_t *ctx)
{
auto device = ctx->device;
auto dfunc = device->funcs;
VkDescriptorImageInfo imageInfo[32];
VkWriteDescriptorSet imageWrite[1];
for (size_t i = 0; i < 32; i++) {
VkImageView view = ctx->default_black->view;
if (i < lctx->light_views.size) {
view = lctx->light_views.a[i];
}
imageInfo[i] = (VkDescriptorImageInfo) {
.sampler = lctx->shadow_sampler,
.imageView = view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
};
}
imageWrite[0] = (VkWriteDescriptorSet) {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = lctx->shadow_set,
.dstBinding = 0,
.descriptorCount = 32,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = imageInfo,
};
dfunc->vkUpdateDescriptorSets (device->dev, 1, imageWrite, 0, 0);
}
void void
Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx) Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx)
{ {
@ -1186,8 +1398,10 @@ Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx)
auto light_pool = &reg->comp_pools[scene_light]; auto light_pool = &reg->comp_pools[scene_light];
if (light_pool->count) { if (light_pool->count) {
build_shadow_maps (lctx, ctx); build_shadow_maps (lctx, ctx);
update_shadow_descriptors (lctx, ctx);
create_light_matrices (lctx); create_light_matrices (lctx);
upload_light_matrices (lctx, ctx); upload_light_matrices (lctx, ctx);
upload_light_data (lctx, ctx);
} }
lctx->ldata = scene->lights; lctx->ldata = scene->lights;
} }