From 27de599ac4a6a8a9b0f7f56bc52466f09327b98e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 May 2022 11:15:52 +0900 Subject: [PATCH] [vulkan] Resurrect the shadow map resource creation However, this time it doesn't modify the light array when it sorts the lights by size since the lights are now located before the renderer gets to see them, and having the fix up the light leafs array would be too painful (and probably the completely wrong thing to do anyway: the light array should be treated as constant by the renderer). 1.6GB of memory for gmsp3v2's lights (a little better than marcher: more smaller lights?). For reference: gmsp3v2: shadow maps: 8330 layers in 29 images: 1647706112 marcher: shadow maps: 2440 layers in 11 images: 2358575104 --- .../renderer/vulkan/shader/lighting.frag | 55 ++++++++------- libs/video/renderer/vulkan/vulkan_lighting.c | 67 ++++++++++++------- 2 files changed, 70 insertions(+), 52 deletions(-) diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index 4b8e516cf..3e100a55c 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -88,36 +88,35 @@ main (void) vec3 p = subpassLoad (position).rgb; vec3 light = vec3 (0); - if (MaxLights > 0) { - vec3 minLight = vec3 (0); - for (int i = 0; i < lightCount; i++) { - LightData l = lights[i]; - vec3 dir = l.position.xyz - l.position.w * p; - float r2 = dot (dir, dir); - vec4 a = l.attenuation; + //vec3 minLight = vec3 (0); + for (int i = 0; i < lightCount; i++) { + LightData l = lights[i]; + vec3 dir = l.position.xyz - l.position.w * p; + float r2 = dot (dir, dir); + vec4 a = l.attenuation; - if (l.position.w * a.w * a.w * r2 >= 1) { - continue; - } - vec4 r = vec4 (r2, sqrt(r2), 1, 0); - vec3 incoming = dir / r.y; - float I = (1 - a.w * r.y) / dot (a, r); - - /*int shadow = lights[i].data & ShadowMask; - if (shadow == ST_CASCADE) { - I *= shadow_cascade (shadowCascade[i]); - } else if (shadow == ST_PLANE) { - I *= shadow_plane (shadowPlane[i]); - } else if (shadow == ST_CUBE) { - I *= shadow_cube (shadowCube[i]); - }*/ - - float namb = dot(l.direction.xyz, l.direction.xyz); - I *= spot_cone (l, incoming) * diffuse (incoming, n); - I = mix (1, I, namb); - light += I * l.color.w * l.color.xyz; + if (l.position.w * a.w * a.w * r2 >= 1) { + continue; } - light = max (light, minLight); + vec4 r = vec4 (r2, sqrt(r2), 1, 0); + vec3 incoming = dir / r.y; + float I = (1 - a.w * r.y) / dot (a, r); + + /*int shadow = lights[i].data & ShadowMask; + if (shadow == ST_CASCADE) { + I *= shadow_cascade (shadowCascade[i]); + } else if (shadow == ST_PLANE) { + I *= shadow_plane (shadowPlane[i]); + } else if (shadow == ST_CUBE) { + I *= shadow_cube (shadowCube[i]); + }*/ + + float namb = dot(l.direction.xyz, l.direction.xyz); + I *= spot_cone (l, incoming) * diffuse (incoming, n); + I = mix (1, I, namb); + light += I * l.color.w * l.color.xyz; } + //light = max (light, minLight); + frag_color = vec4 (c * light + e, 1); } diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index e31216d60..89d2b6264 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -43,6 +43,7 @@ #include "QF/cvar.h" #include "QF/dstring.h" +#include "QF/heapsort.h" #include "QF/plist.h" #include "QF/progs.h" #include "QF/script.h" @@ -372,6 +373,7 @@ clear_shadows (vulkan_ctx_t *ctx) if (lctx->shadow_memory) { dfunc->vkFreeMemory (device->dev, lctx->shadow_memory, 0); + lctx->shadow_memory = 0; } for (size_t i = 0; i < lctx->lightviews.size; i++) { dfunc->vkDestroyImageView (device->dev, lctx->lightviews.a[i], 0); @@ -405,7 +407,7 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx) free (lctx->frames.a); free (lctx); } -#if 0 + static vec4f_t ref_direction = { 0, 0, 1, 0 }; static void @@ -464,10 +466,13 @@ create_light_matrices (lightingctx_t *lctx) } static int -light_compare (const void *_l2, const void *_l1) +light_compare (const void *_li2, const void *_li1, void *_ldata) { - const light_t *l1 = _l1; - const light_t *l2 = _l2; + const int *li1 = _li1; + const int *li2 = _li2; + lightingdata_t *ldata = _ldata; + const light_t *l1 = &ldata->lights.a[*li1]; + const light_t *l2 = &ldata->lights.a[*li2]; if (l1->color[3] == l2->color[3]) { return (l1->position[3] == l2->position[3]) @@ -572,17 +577,22 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) int totalLayers = 0; int *imageMap = alloca (numLights * sizeof (int)); size_t memsize = 0; + int *lightMap = alloca (numLights * sizeof (int)); + for (int i = 0; i < numLights; i++) { + lightMap[i] = i; + } DARRAY_RESIZE (&lctx->lightlayers, numLights); - qsort (lights, numLights, sizeof (light_t), light_compare); + heapsort_r (lightMap, numLights, sizeof (int), light_compare, ldata); for (int i = 0; i < numLights; i++) { int layers = 1; int shadow = ST_NONE; + int li = lightMap[i]; - if (!lights[i].position[3]) { + if (!lights[li].position[3]) { shadow = ST_CASCADE; } else { - if (lights[i].direction[3] > -0.5) { + if (lights[li].direction[3] > -0.5) { shadow = ST_CUBE; } else { shadow = ST_PLANE; @@ -591,23 +601,23 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) if (shadow == ST_CASCADE || shadow == ST_NONE) { // cascade shadows will be handled separately, and "none" has no // shadow map at all - imageMap[i] = -1; + imageMap[li] = -1; continue; } if (shadow == ST_CUBE) { layers = 6; } - if (size != (int) lights[i].color[3] + if (size != (int) lights[li].color[3] || numLayers + layers > maxLayers) { if (numLayers) { VkImage shadow_map = create_map (size, numLayers, 1, ctx); DARRAY_APPEND (&lctx->lightimages, shadow_map); numLayers = 0; } - size = lights[i].color[3]; + size = lights[li].color[3]; } - imageMap[i] = lctx->lightimages.size; - lctx->lightlayers.a[i] = numLayers; + imageMap[li] = lctx->lightimages.size; + lctx->lightlayers.a[li] = numLayers; numLayers += layers; totalLayers += layers; } @@ -621,11 +631,12 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) for (int i = 0; i < numLights; i++) { int layers = 4; int shadow = ST_NONE; + int li = lightMap[i]; - if (!lights[i].position[3]) { + if (!lights[li].position[3]) { shadow = ST_CASCADE; } else { - if (lights[i].direction[3] > -0.5) { + if (lights[li].direction[3] > -0.5) { shadow = ST_CUBE; } else { shadow = ST_PLANE; @@ -640,8 +651,8 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) DARRAY_APPEND (&lctx->lightimages, shadow_map); numLayers = 0; } - imageMap[i] = lctx->lightimages.size; - lctx->lightlayers.a[i] = numLayers; + imageMap[li] = lctx->lightimages.size; + lctx->lightlayers.a[li] = numLayers; numLayers += layers; totalLayers += layers; } @@ -668,29 +679,30 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) DARRAY_RESIZE (&lctx->lightviews, numLights); for (int i = 0; i < numLights; i++) { - if (imageMap[i] == -1) { - lctx->lightviews.a[i] = 0; + int li = lightMap[i]; + + if (imageMap[li] == -1) { + lctx->lightviews.a[li] = 0; continue; } int mode = ST_NONE; - if (!ldata->lights.a[i].position[3]) { + if (!ldata->lights.a[li].position[3]) { mode = ST_CASCADE; } else { - if (ldata->lights.a[i].direction[3] > -0.5) { + if (ldata->lights.a[li].direction[3] > -0.5) { mode = ST_CUBE; } else { mode = ST_PLANE; } } - lctx->lightviews.a[i] = create_view (lctx->lightimages.a[imageMap[i]], - lctx->lightlayers.a[i], - mode, i, ctx); + lctx->lightviews.a[li] = create_view (lctx->lightimages.a[imageMap[li]], + lctx->lightlayers.a[li], + mode, li, ctx); } Sys_MaskPrintf (SYS_vulkan, "shadow maps: %d layers in %zd images: %zd\n", totalLayers, lctx->lightimages.size, memsize); } -#endif void Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx) @@ -699,4 +711,11 @@ Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx) lctx->scene = scene; lctx->ldata = scene ? scene->lights : 0; + + clear_shadows (ctx); + + if (lctx->ldata && lctx->ldata->lights.size) { + build_shadow_maps (lctx, ctx); + create_light_matrices (lctx); + } }