diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h index 7424dca2d..29bf1f9a6 100644 --- a/include/QF/Vulkan/qf_lighting.h +++ b/include/QF/Vulkan/qf_lighting.h @@ -49,11 +49,6 @@ typedef struct qfv_lightmatset_s DARRAY_TYPE (mat4f_t) qfv_lightmatset_t; #define ST_CASCADE 2 // cascaded shadow maps #define ST_CUBE 3 // cubemap (omni, large spotlight) -typedef struct qfv_lightid_buffer_s { - uint32_t lightCount; - uint32_t lightIds[MaxLights]; -} qfv_lightid_buffer_t; - typedef struct qfv_light_render_s { // mat_id (13) map_id (5) layer (11) type (2) uint32_t id_data; @@ -69,6 +64,11 @@ typedef struct qfv_light_render_s { typedef struct qfv_framebufferset_s DARRAY_TYPE (VkFramebuffer) qfv_framebufferset_t; +typedef struct light_queue_s { + uint16_t start; + uint16_t count; +} light_queue_t; + typedef struct lightingframe_s { VkDescriptorSet shadowmat_set; VkDescriptorSet lights_set; @@ -79,6 +79,7 @@ typedef struct lightingframe_s { VkBuffer render_buffer; VkBuffer style_buffer; VkBuffer id_buffer; + light_queue_t light_queue[4]; uint32_t ico_count; uint32_t cone_count; uint32_t flat_count; @@ -113,15 +114,21 @@ typedef struct lightingctx_s { struct qfv_resource_s *light_resources; qfv_lightmatset_t light_mats; - qfv_imageset_t light_images; - qfv_imageviewset_t light_views; + VkImage *map_images; + VkImageView *map_views; + bool *map_cube; + int num_maps; + VkImage default_map; + VkImageView default_view_cube; + VkImageView default_view_2d; light_control_set_t light_control; qfv_attachmentinfo_t shadow_info; VkSampler shadow_sampler; - VkDescriptorSet shadow_set; + VkDescriptorSet shadow_cube_set; + VkDescriptorSet shadow_2d_set; VkBuffer splat_verts; VkBuffer splat_inds; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index d5883a28b..7545ebc90 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -330,6 +330,7 @@ bsp_turbf_src = $(vkshaderpath)/bsp_turb.frag bsp_turbf_c = $(vkshaderpath)/bsp_turb.frag.spvc debug_src = $(vkshaderpath)/debug.frag debug_c = $(vkshaderpath)/debug.frag.spvc +light_attach_h = $(vkshaderpath)/light_attach.h light_flat_src = $(vkshaderpath)/light_flat.vert light_flat_c = $(vkshaderpath)/light_flat.vert.spvc light_splatv_src = $(vkshaderpath)/light_splat.vert @@ -338,8 +339,15 @@ light_splatf_src = $(vkshaderpath)/light_splat.frag light_splatf_c = $(vkshaderpath)/light_splat.frag.spvc light_debug_src = $(vkshaderpath)/light_debug.frag light_debug_c = $(vkshaderpath)/light_debug.frag.spvc -lightingf_src = $(vkshaderpath)/lighting.frag -lightingf_c = $(vkshaderpath)/lighting.frag.spvc +lighting_cascadef_src = $(vkshaderpath)/lighting_cascade.frag +lighting_cascadef_c = $(vkshaderpath)/lighting_cascade.frag.spvc +lighting_cubef_src = $(vkshaderpath)/lighting_cube.frag +lighting_cubef_c = $(vkshaderpath)/lighting_cube.frag.spvc +lighting_main = $(vkshaderpath)/lighting_main.finc +lighting_nonef_src = $(vkshaderpath)/lighting_none.frag +lighting_nonef_c = $(vkshaderpath)/lighting_none.frag.spvc +lighting_planef_src = $(vkshaderpath)/lighting_plane.frag +lighting_planef_c = $(vkshaderpath)/lighting_plane.frag.spvc lighting_h = $(vkshaderpath)/lighting.h composef_src = $(vkshaderpath)/compose.frag composef_c = $(vkshaderpath)/compose.frag.spvc @@ -437,7 +445,13 @@ $(light_splatf_c): $(light_splatf_src) $(lighting_h) $(light_debug_c): $(light_debug_src) $(lighting_h) -$(lightingf_c): $(lightingf_src) $(lighting_h) +$(lighting_nonef_c): $(lighting_nonef_src) $(lighting_h) $(light_attach_h) $(lighting_main) + +$(lighting_cascadef_c): $(lighting_cascadef_src) $(lighting_h) $(light_attach_h) $(lighting_main) + +$(lighting_cubef_c): $(lighting_cubef_src) $(lighting_h) $(light_attach_h) $(lighting_main) + +$(lighting_planef_c): $(lighting_planef_src) $(lighting_h) $(light_attach_h) $(lighting_main) $(composef_c): $(composef_src) $(oit_blend) $(oit_h) @@ -504,7 +518,10 @@ vkshader_c = \ $(light_splatv_c) \ $(light_splatf_c) \ $(light_debug_c) \ - $(lightingf_c) \ + $(lighting_cascadef_c) \ + $(lighting_cubef_c) \ + $(lighting_nonef_c) \ + $(lighting_planef_c) \ $(composef_c) \ $(aliasv_c) \ $(alias_depth_c) \ @@ -591,11 +608,15 @@ EXTRA_DIST += \ $(bsp_skyf_src) \ $(bsp_turbf_src) \ $(debug_src) \ + $(light_attach_h) \ $(light_flat_src) \ $(light_splatv_src) \ $(light_splatf_src) \ $(light_debug_src) \ - $(lightingf_src) \ + $(lighting_cascadef_src) \ + $(lighting_cubef_src) \ + $(lighting_nonef_src) \ + $(lighting_planef_src) \ $(lighting_h) \ $(composef_src) \ $(aliasv_src) \ diff --git a/libs/video/renderer/vulkan/rp_main_def.plist b/libs/video/renderer/vulkan/rp_main_def.plist index 79327af0f..17ba2f3a8 100644 --- a/libs/video/renderer/vulkan/rp_main_def.plist +++ b/libs/video/renderer/vulkan/rp_main_def.plist @@ -618,51 +618,25 @@ properties = { name = main; module = $builtin/light_splat.frag; }; - shadow_specialization = { - mapEntries = ( - // ShadowType - { size = 4; offset = 0; constantID = 0; }, - ); - }; fragment_none = { stage = fragment; name = main; - module = $builtin/lighting.frag; - specializationInfo = { - @inherit = $lighting.shader.shadow_specialization; - // ShadowType - data = "array(0)"; - }; + module = $builtin/lighting_none.frag; }; fragment_plane = { stage = fragment; name = main; - module = $builtin/lighting.frag; - specializationInfo = { - @inherit = $lighting.shader.shadow_specialization; - // ShadowType - data = "array(1)"; - }; + module = $builtin/lighting_plane.frag; }; fragment_cascade = { stage = fragment; name = main; - module = $builtin/lighting.frag; - specializationInfo = { - @inherit = $lighting.shader.shadow_specialization; - // ShadowType - data = "array(2)"; - }; + module = $builtin/lighting_cascade.frag; }; fragment_cube = { stage = fragment; name = main; - module = $builtin/lighting.frag; - specializationInfo = { - @inherit = $lighting.shader.shadow_specialization; - // ShadowType - data = "array(3)"; - }; + module = $builtin/lighting_cube.frag; }; debug_fragment = { stage = fragment; @@ -698,6 +672,11 @@ properties = { layout = { descriptorSets = (shadowmat_set, lighting_lights, lighting_attach, lighting_shadow); + pushConstants = { + fragment = { + queue = uint; + }; + }; }; }; compose = { diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index d03ddd5e2..5b372ba5a 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -99,7 +99,13 @@ static static #include "libs/video/renderer/vulkan/shader/light_debug.frag.spvc" static -#include "libs/video/renderer/vulkan/shader/lighting.frag.spvc" +#include "libs/video/renderer/vulkan/shader/lighting_cascade.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/lighting_cube.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/lighting_none.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/lighting_plane.frag.spvc" static #include "libs/video/renderer/vulkan/shader/compose.frag.spvc" static @@ -172,7 +178,12 @@ static shaderdata_t builtin_shaders[] = { { "light_splat.vert", light_splat_vert, sizeof (light_splat_vert) }, { "light_splat.frag", light_splat_frag, sizeof (light_splat_frag) }, { "light_debug.frag", light_debug_frag, sizeof (light_debug_frag) }, - { "lighting.frag", lighting_frag, sizeof (lighting_frag) }, + { "lighting_cascade.frag", lighting_cascade_frag, + sizeof (lighting_cascade_frag) }, + { "lighting_cube.frag", lighting_cube_frag, sizeof (lighting_cube_frag) }, + { "lighting_none.frag", lighting_none_frag, sizeof (lighting_none_frag) }, + { "lighting_plane.frag", lighting_plane_frag, + sizeof (lighting_plane_frag) }, { "compose.frag", compose_frag, sizeof (compose_frag) }, { "alias.vert", alias_vert, sizeof (alias_vert) }, { "alias_depth.vert", alias_depth_vert, sizeof (alias_depth_vert) }, diff --git a/libs/video/renderer/vulkan/shader/light_attach.h b/libs/video/renderer/vulkan/shader/light_attach.h new file mode 100644 index 000000000..2876d4858 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/light_attach.h @@ -0,0 +1,4 @@ +layout (input_attachment_index = 0, set = 2, binding = 0) uniform subpassInput color; +layout (input_attachment_index = 1, set = 2, binding = 1) uniform subpassInput emission; +layout (input_attachment_index = 2, set = 2, binding = 2) uniform subpassInput normal; +layout (input_attachment_index = 3, set = 2, binding = 3) uniform subpassInput position; diff --git a/libs/video/renderer/vulkan/shader/lighting.h b/libs/video/renderer/vulkan/shader/lighting.h index 48a31dbae..77a0c5c91 100644 --- a/libs/video/renderer/vulkan/shader/lighting.h +++ b/libs/video/renderer/vulkan/shader/lighting.h @@ -16,7 +16,6 @@ struct LightRender { }; layout (set = 1, binding = 0) buffer LightIds { - uint lightCount; uint lightIds[]; }; layout (set = 1, binding = 1) buffer Lights { diff --git a/libs/video/renderer/vulkan/shader/lighting_cascade.frag b/libs/video/renderer/vulkan/shader/lighting_cascade.frag new file mode 100644 index 000000000..7f453a0ed --- /dev/null +++ b/libs/video/renderer/vulkan/shader/lighting_cascade.frag @@ -0,0 +1,12 @@ +#version 450 +#extension GL_GOOGLE_include_directive : enable + +layout (set = 3, binding = 0) uniform sampler2DArrayShadow shadow_map[32]; + +float +shadow (uint map_id, uint layer, uint mat_id, vec3 pos) +{ + return 1; +} + +#include "lighting_main.finc" diff --git a/libs/video/renderer/vulkan/shader/lighting_cube.frag b/libs/video/renderer/vulkan/shader/lighting_cube.frag new file mode 100644 index 000000000..05fab8045 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/lighting_cube.frag @@ -0,0 +1,17 @@ +#version 450 +#extension GL_GOOGLE_include_directive : enable + +layout (set = 0, binding = 0) buffer ShadowMatrices { + mat4 shadow_mats[]; +}; +layout (set = 3, binding = 0) uniform samplerCubeArrayShadow shadow_map[32]; + +float +shadow (uint map_id, uint layer, uint mat_id, vec3 pos) +{ + vec4 p = shadow_mats[mat_id] * vec4 (pos, 1); + float depth = (p / p.w).z; + return texture (shadow_map[map_id], vec4 (p.xyz, layer), depth); +} + +#include "lighting_main.finc" diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting_main.finc similarity index 53% rename from libs/video/renderer/vulkan/shader/lighting.frag rename to libs/video/renderer/vulkan/shader/lighting_main.finc index eb7c08eed..ceb5bd151 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting_main.finc @@ -1,20 +1,11 @@ -#version 450 -#extension GL_GOOGLE_include_directive : enable - #include "lighting.h" - -layout (input_attachment_index = 0, set = 2, binding = 0) uniform subpassInput color; -layout (input_attachment_index = 1, set = 2, binding = 1) uniform subpassInput emission; -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 (set = 3, binding = 0) uniform sampler2DArrayShadow shadowCascade[32]; -layout (set = 3, binding = 0) uniform sampler2DArrayShadow shadowPlane[32]; -layout (set = 3, binding = 0) uniform samplerCubeArrayShadow shadowCube[32]; +#include "light_attach.h" layout (location = 0) out vec4 frag_color; -layout (constant_id = 0) const int ShadowType = ST_NONE; +layout (push_constant) uniform PushConstants { + uint queue; +}; float spot_cone (LightData light, vec3 incoming) @@ -32,24 +23,6 @@ diffuse (vec3 incoming, vec3 normal) return clamp (lightdot, 0, 1); } -float -shadow_cascade (sampler2DArrayShadow map, uint layer, uint mat_id, vec3 pos) -{ - return 1; -} - -float -shadow_plane (sampler2DArrayShadow map, uint layer, uint mat_id, vec3 pos) -{ - return 1; -} - -float -shadow_cube (samplerCubeArrayShadow map, uint layer, uint mat_id, vec3 pos) -{ - return 1; -} - void main (void) { @@ -59,8 +32,10 @@ main (void) vec3 p = subpassLoad (position).rgb; vec3 light = vec3 (0); - //vec3 minLight = vec3 (0); - for (int i = 0; i < lightCount; i++) { + uint start = bitfieldExtract (queue, 0, 16); + uint count = bitfieldExtract (queue, 16, 16); + + for (uint i = start; i < count; i++) { uint id = lightIds[i]; LightData l = lights[id]; vec3 dir = l.position.xyz - l.position.w * p; @@ -78,13 +53,8 @@ main (void) uint mat_id = bitfieldExtract (id_data, 0, 13); uint map_id = bitfieldExtract (id_data, 13, 5); uint layer = bitfieldExtract (id_data, 18, 11); - if (ShadowType == ST_CASCADE) { - I *= shadow_cascade (shadowCascade[map_id], layer, mat_id, p); - } 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); - } + + I *= shadow (map_id, layer, mat_id, p); float namb = dot(l.direction.xyz, l.direction.xyz); I *= spot_cone (l, incoming) * diffuse (incoming, n); diff --git a/libs/video/renderer/vulkan/shader/lighting_none.frag b/libs/video/renderer/vulkan/shader/lighting_none.frag new file mode 100644 index 000000000..12f908d7e --- /dev/null +++ b/libs/video/renderer/vulkan/shader/lighting_none.frag @@ -0,0 +1,10 @@ +#version 450 +#extension GL_GOOGLE_include_directive : enable + +float +shadow (uint mapid, uint layer, uint mat_id, vec3 pos) +{ + return 1; +} + +#include "lighting_main.finc" diff --git a/libs/video/renderer/vulkan/shader/lighting_plane.frag b/libs/video/renderer/vulkan/shader/lighting_plane.frag new file mode 100644 index 000000000..7f453a0ed --- /dev/null +++ b/libs/video/renderer/vulkan/shader/lighting_plane.frag @@ -0,0 +1,12 @@ +#version 450 +#extension GL_GOOGLE_include_directive : enable + +layout (set = 3, binding = 0) uniform sampler2DArrayShadow shadow_map[32]; + +float +shadow (uint map_id, uint layer, uint mat_id, vec3 pos) +{ + return 1; +} + +#include "lighting_main.finc" diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index b578798c2..62fd1f324 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -94,13 +94,13 @@ static int cone_inds[] = { 1, 6, 5, 4, 3, 2, }; #define num_cone_inds (sizeof (cone_inds) / sizeof (cone_inds[0])) - +#if 0 static const light_t * get_light (entity_t ent) { return Ent_GetComponent (ent.id, scene_light, ent.reg); } - +#endif static uint32_t get_lightstyle (entity_t ent) { @@ -188,7 +188,7 @@ create_view (vulkan_ctx_t *ctx, light_control_t *renderer) VkImageViewCreateInfo cInfo = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = lctx->light_images.a[renderer->map_index], + .image = lctx->map_images[renderer->map_index], .viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY, .format = VK_FORMAT_X8_D24_UNORM_PACK32, .subresourceRange = { @@ -252,7 +252,7 @@ lighting_draw_shadow_maps (const exprval_t **params, exprval_t *result, auto render = shadow->render; auto lframe = &lctx->frames.a[ctx->curFrame]; - if (!lctx->ldata) { + if (!lctx->num_maps) { return; } //auto pass = Vulkan_Bsp_GetAuxPass (ctx); @@ -293,6 +293,7 @@ lighting_update_lights (const exprval_t **params, exprval_t *result, lframe->ico_count = 0; lframe->cone_count = 0; lframe->flat_count = 0; + memset (lframe->light_queue, 0, sizeof (lframe->light_queue)); if (!lctx->scene || !lctx->scene->lights) { return; } @@ -307,11 +308,10 @@ lighting_update_lights (const exprval_t **params, exprval_t *result, QFV_PacketCopyBuffer (packet, lframe->style_buffer, 0, bb); QFV_PacketSubmit (packet); - uint32_t ico_ids[MaxLights]; - uint32_t cone_ids[MaxLights]; - uint32_t flat_ids[MaxLights]; + uint32_t ids[4][MaxLights]; uint32_t light_count = 0; + auto queue = lframe->light_queue; dlight_t *dynamic_lights[MaxLights]; int maxdlight = MaxLights - lctx->dynamic_base; @@ -322,7 +322,9 @@ lighting_update_lights (const exprval_t **params, exprval_t *result, packet = QFV_PacketAcquire (ctx->staging); light_t *lights = QFV_PacketExtend (packet, sizeof (light_t[ndlight])); for (int i = 0; i < ndlight; i++) { - ico_ids[lframe->ico_count++] = lctx->dynamic_base + light_count++; + uint32_t id = lctx->dynamic_base + light_count++; + //FIXME should be ST_CUBE but need to alloc maps for dlights + ids[ST_NONE][queue[ST_NONE].count++] = id; VectorCopy (dynamic_lights[i]->color, lights[i].color); // dynamic lights seem a tad faint, so 16x map lights @@ -355,10 +357,9 @@ lighting_update_lights (const exprval_t **params, exprval_t *result, QFV_PacketSubmit (packet); } - auto queue = r_ent_queue; //FIXME fetch from scene - for (size_t i = 0; i < queue->ent_queues[mod_light].size; i++) { - entity_t ent = queue->ent_queues[mod_light].a[i]; - auto l = get_light (ent); + auto entqueue = r_ent_queue; //FIXME fetch from scene + for (size_t i = 0; i < entqueue->ent_queues[mod_light].size; i++) { + entity_t ent = entqueue->ent_queues[mod_light].a[i]; auto ls = get_lightstyle (ent); if (!d_lightstylevalue[ls]) { continue; @@ -366,16 +367,8 @@ lighting_update_lights (const exprval_t **params, exprval_t *result, light_count++; uint32_t id = lctx->light_control.a[get_lightid (ent)].light_id; - if (l->position[3] && !VectorIsZero (l->direction) - && l->attenuation[3]) { - if (l->direction[3] < 0) { - cone_ids[lframe->cone_count++] = id; - } else { - ico_ids[lframe->ico_count++] = id; - } - } else { - flat_ids[lframe->flat_count++] = id; - } + int mode = lctx->light_control.a[get_lightid (ent)].mode; + ids[mode][queue[mode].count++] = id; } if (developer & SYS_lighting) { Vulkan_Draw_String (vid.width - 32, 8, @@ -383,21 +376,17 @@ lighting_update_lights (const exprval_t **params, exprval_t *result, ctx); } - uint32_t id_count = lframe->ico_count + lframe->cone_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 (light_count) { + for (int i = 1; i < 4; i++) { + queue[i].start = queue[i - 1].start + queue[i - 1].count; + } packet = QFV_PacketAcquire (ctx->staging); - 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)); - 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)); + uint32_t *lids = QFV_PacketExtend (packet, + sizeof (uint32_t[light_count])); + for (int i = 0; i < 4; i++) { + memcpy (lids + queue[i].start, ids[i], + sizeof (uint32_t[queue[i].count])); + } QFV_PacketCopyBuffer (packet, lframe->id_buffer, 0, &bufferBarriers[qfv_BB_TransferWrite_to_IndexRead]); QFV_PacketSubmit (packet); @@ -470,17 +459,25 @@ lighting_bind_descriptors (const exprval_t **params, exprval_t *result, auto device = ctx->device; auto dfunc = device->funcs; auto lctx = ctx->lighting_context; + if (!lctx->num_maps) { + return; + } auto cmd = taskctx->cmd; auto layout = taskctx->pipeline->layout; auto lframe = &lctx->frames.a[ctx->curFrame]; + auto shadow_type = *(int *) params[0]->value; VkDescriptorSet sets[] = { - //Vulkan_Matrix_Descriptors (ctx, ctx->curFrame), lframe->shadowmat_set, lframe->lights_set, lframe->attach_set, - lctx->shadow_set, + (VkDescriptorSet[]) { + lctx->shadow_2d_set, + lctx->shadow_2d_set, + lctx->shadow_2d_set, + lctx->shadow_cube_set + }[shadow_type], }; dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 4, sets, 0, 0); @@ -546,13 +543,22 @@ lighting_draw_lights (const exprval_t **params, exprval_t *result, auto device = ctx->device; auto dfunc = device->funcs; auto lctx = ctx->lighting_context; + auto layout = taskctx->pipeline->layout; auto cmd = taskctx->cmd; auto lframe = &lctx->frames.a[ctx->curFrame]; - if (!(lframe->ico_count + lframe->cone_count + lframe->flat_count)) { + auto shadow_type = *(int *) params[0]->value; + auto queue = lframe->light_queue[shadow_type]; + + if (!queue.count) { return; } + qfv_push_constants_t push_constants[] = { + { VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof (queue), &queue }, + }; + QFV_PushConstants (device, cmd, layout, 1, push_constants); + dfunc->vkCmdDraw (cmd, 3, 1, 0, 0); } @@ -661,6 +667,54 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx) QFV_Render_AddAttachments (ctx, 1, attachments); } +static void +make_default_map (int size, VkImage default_map, vulkan_ctx_t *ctx) +{ + auto device = ctx->device; + auto dfunc = device->funcs; + + auto packet = QFV_PacketAcquire (ctx->staging); + size_t imgsize = size * size * sizeof (uint32_t); + uint32_t *img = QFV_PacketExtend (packet, imgsize); + for (int i = 0; i < 64; i++) { + for (int j = 0; j < 64; j++) { + img[i * 64 + j] = ((j ^ i) & 1) ? 0x00ffffff : 0; + } + } + + auto ib = imageBarriers[qfv_LT_Undefined_to_TransferDst]; + ib.barrier.image = default_map; + ib.barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + ib.barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + ib.barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, ib.srcStages, ib.dstStages, + 0, 0, 0, 0, 0, 1, &ib.barrier); + + VkBufferImageCopy copy_region[6]; + for (int i = 0; i < 6; i++) { + copy_region[i] = (VkBufferImageCopy) { + .bufferOffset = packet->offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, i, 1}, + {0, 0, 0}, {size, size, 1}, + }; + } + dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer, + default_map, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 6, copy_region); + + ib = imageBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + ib.barrier.image = default_map; + ib.barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + ib.barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + ib.barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, ib.srcStages, ib.dstStages, + 0, 0, 0, 0, 0, 1, &ib.barrier); + QFV_PacketSubmit (packet); +} + static void make_ico (qfv_packet_t *packet) { @@ -732,8 +786,6 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx) #endif DARRAY_INIT (&lctx->light_mats, 16); - DARRAY_INIT (&lctx->light_images, 16); - DARRAY_INIT (&lctx->light_views, 16); DARRAY_INIT (&lctx->light_control, 16); auto rctx = ctx->render_context; @@ -747,6 +799,8 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx) + sizeof (qfv_resobj_t) // splat indices + sizeof (qfv_resobj_t) + // default shadow map and views + + 3 * sizeof (qfv_resobj_t) // light ids + sizeof (qfv_resobj_t[frames]) // light data @@ -757,20 +811,23 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx) + sizeof (qfv_resobj_t[frames]) // light matrices + sizeof (qfv_resobj_t[frames])); - auto splat_verts = (qfv_resobj_t *) &lctx->light_resources[1]; - auto splat_inds = &splat_verts[1]; - auto light_ids = &splat_inds[1]; - auto light_data = &light_ids[frames]; - auto light_render = &light_data[frames]; - auto light_styles = &light_render[frames]; - auto light_mats = &light_styles[frames]; lctx->light_resources[0] = (qfv_resource_t) { .name = "lights", .va_ctx = ctx->va_ctx, .memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - .num_objects = 2 + 5 * frames, - .objects = splat_verts, + .num_objects = 2 + 3 + 5 * frames, + .objects = (qfv_resobj_t *) &lctx->light_resources[1], }; + auto splat_verts = lctx->light_resources->objects; + auto splat_inds = &splat_verts[1]; + auto default_map = &splat_inds[1]; + auto default_view_cube = &default_map[1]; + auto default_view_2d = &default_view_cube[1]; + auto light_ids = &default_view_2d[1]; + auto light_data = &light_ids[frames]; + auto light_render = &light_data[frames]; + auto light_styles = &light_render[frames]; + auto light_mats = &light_styles[frames]; splat_verts[0] = (qfv_resobj_t) { .name = "splat:vertices", .type = qfv_res_buffer, @@ -789,6 +846,49 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx) | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, }, }; + default_map[0] = (qfv_resobj_t) { + .name = "default_map", + .type = qfv_res_image, + .image = { + .flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, + .type = VK_IMAGE_TYPE_2D, + .format = VK_FORMAT_X8_D24_UNORM_PACK32, + .extent = { 64, 64, 1 }, + .num_mipmaps = 1, + .num_layers = 6, + .samples = VK_SAMPLE_COUNT_1_BIT, + .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT, + }, + }; + default_view_cube[0] = (qfv_resobj_t) { + .name = "default_map:view_cube", + .type = qfv_res_image_view, + .image_view = { + .image = default_map - lctx->light_resources->objects, + .type = VK_IMAGE_VIEW_TYPE_CUBE_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, + }, + }, + }; + default_view_2d[0] = (qfv_resobj_t) { + .name = "default_map:view_2d", + .type = qfv_res_image_view, + .image_view = { + .image = default_map - lctx->light_resources->objects, + .type = 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, + }, + }, + }; for (size_t i = 0; i < frames; i++) { light_ids[i] = (qfv_resobj_t) { .name = "ids", @@ -843,11 +943,17 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx) lctx->splat_verts = splat_verts[0].buffer.buffer; lctx->splat_inds = splat_inds[0].buffer.buffer; + lctx->default_map = default_map[0].image.image; + lctx->default_view_cube = default_view_cube[0].image_view.view; + lctx->default_view_2d = default_view_2d[0].image_view.view; auto shadow_mgr = QFV_Render_DSManager (ctx, "lighting_shadow"); - lctx->shadow_set = QFV_DSManager_AllocSet (shadow_mgr); + lctx->shadow_cube_set = QFV_DSManager_AllocSet (shadow_mgr); + lctx->shadow_2d_set = QFV_DSManager_AllocSet (shadow_mgr); QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET, - lctx->shadow_set, "lighting:shadow_set"); + lctx->shadow_cube_set, "lighting:shadow_cube_set"); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET, + lctx->shadow_2d_set, "lighting:shadow_2d_set"); lctx->shadow_sampler = QFV_Render_Sampler (ctx, "shadow_sampler"); auto attach_mgr = QFV_Render_DSManager (ctx, "lighting_attach"); @@ -927,6 +1033,8 @@ Vulkan_Lighting_Setup (vulkan_ctx_t *ctx) dfunc->vkUpdateDescriptorSets (device->dev, 5, bufferWrite, 0, 0); } + make_default_map (64, lctx->default_map, ctx); + auto packet = QFV_PacketAcquire (ctx->staging); make_ico (packet); make_cone (packet); @@ -953,8 +1061,13 @@ clear_shadows (vulkan_ctx_t *ctx) free (lctx->shadow_resources); lctx->shadow_resources = 0; } - lctx->light_images.size = 0; - lctx->light_views.size = 0; + free (lctx->map_images); + free (lctx->map_views); + free (lctx->map_cube); + lctx->map_images = 0; + lctx->map_views = 0; + lctx->map_cube = 0; + lctx->num_maps = 0; lctx->light_control.size = 0; } @@ -977,9 +1090,10 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx) } DARRAY_CLEAR (&lctx->light_mats); - DARRAY_CLEAR (&lctx->light_images); - DARRAY_CLEAR (&lctx->light_views); DARRAY_CLEAR (&lctx->light_control); + free (lctx->map_images); + free (lctx->map_views); + free (lctx->map_cube); free (lctx->frames.a); free (lctx); } @@ -1129,6 +1243,23 @@ upload_light_data (lightingctx_t *lctx, vulkan_ctx_t *ctx) lctx->dynamic_count = 0; } +static int +light_shadow_type (const light_t *light) +{ + if (!light->position[3]) { + if (!VectorIsZero (light->direction)) { + return ST_CASCADE; + } + } else { + if (light->direction[3] > -0.5) { + return ST_CUBE; + } else { + return ST_PLANE; + } + } + return ST_NONE; +} + static int light_compare (const void *_li2, const void *_li1, void *_lights) { @@ -1149,14 +1280,91 @@ light_compare (const void *_li2, const void *_li1, void *_lights) return s1 - s2; } +typedef struct { + int size; + int layers; + int cube; +} mapdesc_t; + +typedef struct { + mapdesc_t *maps; + int numMaps; + int numLights; + const light_t *lights; + int *imageMap; + const int *lightMap; + light_control_t *control; + int maxLayers; +} mapctx_t; + +static int +allocate_map (mapctx_t *mctx, int type, int (*getsize) (const light_t *light)) +{ + int size = -1; + int numLayers = 0; + int totalLayers = 0; + int layers = ((int[4]) { 0, 1, 4, 6 })[type]; + int cube = type == ST_CUBE; + + for (int i = 0; i < mctx->numLights; i++) { + auto li = mctx->lightMap[i]; + auto lr = &mctx->control[li]; + + if (lr->mode != type) { + continue; + } + int light_size = getsize (&mctx->lights[li]); + if (size != light_size || numLayers + layers > mctx->maxLayers) { + if (numLayers) { + mctx->maps[mctx->numMaps++] = (mapdesc_t) { + .size = size, + .layers = numLayers, + .cube = cube, + }; + numLayers = 0; + } + size = light_size; + } + mctx->imageMap[li] = mctx->numMaps; + lr->size = size; + lr->layer = numLayers; + lr->numLayers = layers; + numLayers += layers; + totalLayers += layers; + } + if (numLayers) { + mctx->maps[mctx->numMaps++] = (mapdesc_t) { + .size = size, + .layers = numLayers, + .cube = cube, + }; + } + return totalLayers; +} + +static int +get_point_size (const light_t *light) +{ + return abs ((int) light->color[3]); +} + +static int +get_spot_size (const light_t *light) +{ + float c = light->direction[3]; + float s = sqrt (1 - c * c); + return abs ((int) (s * light->color[3])); +} + +static int +get_direct_size (const light_t *light) +{ + return 1024; +} + static void build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) { - typedef struct { - int size; - int layers; - int cube; - } mapdesc_t; qfv_device_t *device = ctx->device; qfv_physdev_t *physDev = device->physDev; @@ -1168,12 +1376,9 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) auto light_pool = ®->comp_pools[scene_light]; auto lights = (light_t *) light_pool->data; int numLights = light_pool->count; - int size = -1; - int numLayers = 0; int totalLayers = 0; int imageMap[numLights]; int lightMap[numLights]; - int numMaps = 0; mapdesc_t maps[numLights]; for (int i = 0; i < numLights; i++) { @@ -1183,108 +1388,51 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) DARRAY_RESIZE (&lctx->light_control, numLights); for (int i = 0; i < numLights; i++) { - int layers = 1; auto li = lightMap[i]; auto lr = &lctx->light_control.a[li]; - *lr = (light_control_t) { .light_id = li, }; + *lr = (light_control_t) { + .mode = light_shadow_type (&lights[li]), + .light_id = li, + }; set_lightid (light_pool->dense[li], reg, li); - - if (!lights[li].position[3]) { - if (!VectorIsZero (lights[li].direction)) { - lr->mode = ST_CASCADE; - } - } else { - if (lights[li].direction[3] > -0.5) { - lr->mode = ST_CUBE; - } else { - lr->mode = ST_PLANE; - } - } - if (lr->mode == ST_CASCADE || lr->mode == ST_NONE) { - // cascade shadows will be handled separately, and "none" has no - // shadow map at all - imageMap[li] = -1; - continue; - } - if (lr->mode == ST_CUBE) { - layers = 6; - } - if (size != abs ((int) lights[li].color[3]) - || numLayers + layers > maxLayers) { - if (numLayers) { - maps[numMaps++] = (mapdesc_t) { - .size = size, - .layers = numLayers, - .cube = 1, - }; - numLayers = 0; - } - size = abs ((int) lights[li].color[3]); - } - imageMap[li] = numMaps; - lr->size = size; - lr->layer = numLayers; - lr->numLayers = layers; - numLayers += layers; - totalLayers += layers; - } - if (numLayers) { - maps[numMaps++] = (mapdesc_t) { - .size = size, - .layers = numLayers, - .cube = 1, - }; + // assume all lights have no shadows + imageMap[li] = -1; } - numLayers = 0; - size = 1024; - for (int i = 0; i < numLights; i++) { - int layers = 4; - auto li = lightMap[i]; - auto lr = &lctx->light_control.a[li]; + mapctx_t mctx = { + .maps = maps, + .numLights = numLights, + .lights = lights, + .imageMap = imageMap, + .lightMap = lightMap, + .control = lctx->light_control.a, + .maxLayers = maxLayers, + }; + totalLayers += allocate_map (&mctx, ST_CUBE, get_point_size); + totalLayers += allocate_map (&mctx, ST_PLANE, get_spot_size); + totalLayers += allocate_map (&mctx, ST_CASCADE, get_direct_size); - if (lr->mode != ST_CASCADE) { - continue; - } - if (numLayers + layers > maxLayers) { - maps[numMaps++] = (mapdesc_t) { - .size = size, - .layers = numLayers, - .cube = 0, - }; - numLayers = 0; - } - imageMap[li] = numMaps; - lr->size = size; - lr->layer = numLayers; - lr->numLayers = layers; - numLayers += layers; - totalLayers += layers; - } - if (numLayers) { - maps[numMaps++] = (mapdesc_t) { - .size = size, - .layers = numLayers, - .cube = 0, - }; - } - - if (numMaps) { + lctx->num_maps = mctx.numMaps; + if (mctx.numMaps) { qfv_resource_t *shad = calloc (1, sizeof (qfv_resource_t) - + sizeof (qfv_resobj_t[numMaps]) - + sizeof (qfv_resobj_t[numMaps])); + + sizeof (qfv_resobj_t[mctx.numMaps]) + + sizeof (qfv_resobj_t[mctx.numMaps])); lctx->shadow_resources = shad; *shad = (qfv_resource_t) { .name = "shadow", .va_ctx = ctx->va_ctx, .memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - .num_objects = 2 * numMaps, + .num_objects = 2 * mctx.numMaps, .objects = (qfv_resobj_t *) &shad[1], }; + lctx->map_images = malloc (sizeof (VkImage[mctx.numMaps])); + lctx->map_views = malloc (sizeof (VkImageView[mctx.numMaps])); + lctx->map_cube = malloc (sizeof (bool[mctx.numMaps])); auto images = shad->objects; - auto views = &images[numMaps]; - for (int i = 0; i < numMaps; i++) { - int cube = maps[i].layers < 6 ? 0 : maps[i].cube; + auto views = &images[mctx.numMaps]; + for (int i = 0; i < mctx.numMaps; i++) { + int cube = maps[i].cube; + lctx->map_cube[i] = cube; images[i] = (qfv_resobj_t) { .name = va (ctx->va_ctx, "map:image:%d:%d", i, maps[i].size), .type = qfv_res_image, @@ -1317,9 +1465,9 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) }; } QFV_CreateResource (device, shad); - for (int i = 0; i < numMaps; i++) { - DARRAY_APPEND (&lctx->light_images, images[i].image.image); - DARRAY_APPEND (&lctx->light_views, views[i].image_view.view); + for (int i = 0; i < mctx.numMaps; i++) { + lctx->map_images[i] = images[i].image.image; + lctx->map_views[i] = views[i].image_view.view; } } @@ -1348,9 +1496,51 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) lr->map_index = imageMap[li]; } Sys_MaskPrintf (SYS_lighting, - "shadow maps: %d layers in %zd images: %"PRId64"\n", - totalLayers, lctx->light_images.size, - lctx->shadow_resources->size); + "shadow maps: %d layers in %d images: %"PRId64"\n", + totalLayers, lctx->num_maps, + lctx->shadow_resources ? lctx->shadow_resources->size + : (VkDeviceSize) 0); +} + +static void +transition_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx) +{ + auto device = ctx->device; + auto dfunc = device->funcs; + + VkCommandBufferAllocateInfo aInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = ctx->cmdpool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + VkCommandBuffer cmd; + dfunc->vkAllocateCommandBuffers (device->dev, &aInfo, &cmd); + VkCommandBufferBeginInfo bInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }; + dfunc->vkBeginCommandBuffer (cmd, &bInfo); + + auto ib = imageBarriers[qfv_LT_Undefined_to_ShaderReadOnly]; + ib.barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + ib.barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + ib.barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + VkImageMemoryBarrier barriers[lctx->num_maps]; + for (int i = 0; i < lctx->num_maps; i++) { + barriers[i] = ib.barrier; + barriers[i].image = lctx->map_images[i]; + } + dfunc->vkCmdPipelineBarrier (cmd, ib.srcStages, ib.dstStages, + 0, 0, 0, 0, 0, lctx->num_maps, barriers); + dfunc->vkEndCommandBuffer (cmd); + + VkSubmitInfo submitInfo = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &cmd, + }; + dfunc->vkQueueSubmit (device->queue.queue, 1, &submitInfo, 0); } static void @@ -1359,28 +1549,48 @@ 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]; + VkDescriptorImageInfo imageInfoCube[32]; + VkDescriptorImageInfo imageInfo2d[32]; + for (int i = 0; i < 32; i++) { + VkImageView viewCube = lctx->default_view_cube; + VkImageView view2d = lctx->default_view_2d; + if (i < lctx->num_maps) { + if (lctx->map_cube[i]) { + viewCube = lctx->map_views[i]; + } else { + view2d = lctx->map_views[i]; + } } - imageInfo[i] = (VkDescriptorImageInfo) { + imageInfoCube[i] = (VkDescriptorImageInfo) { .sampler = lctx->shadow_sampler, - .imageView = view, + .imageView = viewCube, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + imageInfo2d[i] = (VkDescriptorImageInfo) { + .sampler = lctx->shadow_sampler, + .imageView = view2d, .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, + VkWriteDescriptorSet imageWrite[2] = { + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = lctx->shadow_cube_set, + .dstBinding = 0, + .descriptorCount = 32, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = imageInfoCube, + }, + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = lctx->shadow_2d_set, + .dstBinding = 0, + .descriptorCount = 32, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = imageInfo2d, + }, }; - dfunc->vkUpdateDescriptorSets (device->dev, 1, imageWrite, 0, 0); + dfunc->vkUpdateDescriptorSets (device->dev, 2, imageWrite, 0, 0); } void @@ -1398,6 +1608,7 @@ Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx) auto light_pool = ®->comp_pools[scene_light]; if (light_pool->count) { build_shadow_maps (lctx, ctx); + transition_shadow_maps (lctx, ctx); update_shadow_descriptors (lctx, ctx); create_light_matrices (lctx); upload_light_matrices (lctx, ctx);