2021-02-24 10:58:31 +00:00
|
|
|
/*
|
|
|
|
vulkan_lighting.c
|
|
|
|
|
|
|
|
Vulkan lighting pass pipeline
|
|
|
|
|
|
|
|
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
|
|
|
|
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
|
|
Date: 2021/2/23
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "qfalloca.h"
|
|
|
|
|
2021-12-02 13:48:50 +00:00
|
|
|
#include "QF/cvar.h"
|
2021-03-03 09:14:16 +00:00
|
|
|
#include "QF/dstring.h"
|
2022-05-10 02:15:52 +00:00
|
|
|
#include "QF/heapsort.h"
|
2021-03-21 07:13:03 +00:00
|
|
|
#include "QF/plist.h"
|
2021-03-03 09:14:16 +00:00
|
|
|
#include "QF/progs.h"
|
|
|
|
#include "QF/script.h"
|
2021-07-26 02:15:51 +00:00
|
|
|
#include "QF/set.h"
|
2021-02-24 10:58:31 +00:00
|
|
|
#include "QF/sys.h"
|
2021-02-25 06:51:54 +00:00
|
|
|
#include "QF/va.h"
|
2021-02-24 10:58:31 +00:00
|
|
|
|
2022-05-05 05:58:47 +00:00
|
|
|
#include "QF/scene/scene.h"
|
2023-08-08 16:23:13 +00:00
|
|
|
#include "QF/ui/imui.h"
|
|
|
|
#define IMUI_context imui_ctx
|
2022-05-05 05:58:47 +00:00
|
|
|
|
2023-07-27 07:09:33 +00:00
|
|
|
#include "QF/Vulkan/qf_bsp.h"
|
2022-05-27 01:19:15 +00:00
|
|
|
#include "QF/Vulkan/qf_draw.h"
|
2021-02-24 10:58:31 +00:00
|
|
|
#include "QF/Vulkan/qf_lighting.h"
|
2023-06-27 16:01:56 +00:00
|
|
|
#include "QF/Vulkan/qf_matrices.h"
|
2021-04-24 01:40:39 +00:00
|
|
|
#include "QF/Vulkan/qf_texture.h"
|
2023-12-17 01:56:59 +00:00
|
|
|
#include "QF/Vulkan/qf_translucent.h"
|
2021-04-24 06:47:31 +00:00
|
|
|
#include "QF/Vulkan/barrier.h"
|
2021-02-25 06:51:54 +00:00
|
|
|
#include "QF/Vulkan/buffer.h"
|
2021-02-24 10:58:31 +00:00
|
|
|
#include "QF/Vulkan/debug.h"
|
|
|
|
#include "QF/Vulkan/device.h"
|
2023-06-24 12:42:46 +00:00
|
|
|
#include "QF/Vulkan/dsmanager.h"
|
2021-02-24 10:58:31 +00:00
|
|
|
#include "QF/Vulkan/image.h"
|
2021-04-29 11:54:38 +00:00
|
|
|
#include "QF/Vulkan/instance.h"
|
|
|
|
#include "QF/Vulkan/projection.h"
|
2023-02-13 15:55:22 +00:00
|
|
|
#include "QF/Vulkan/render.h"
|
2022-10-27 02:02:45 +00:00
|
|
|
#include "QF/Vulkan/resource.h"
|
2021-02-25 06:51:54 +00:00
|
|
|
#include "QF/Vulkan/staging.h"
|
|
|
|
|
|
|
|
#include "compat.h"
|
2021-02-24 10:58:31 +00:00
|
|
|
|
|
|
|
#include "r_internal.h"
|
|
|
|
#include "vid_vulkan.h"
|
2022-05-31 03:43:04 +00:00
|
|
|
#include "vkparse.h"
|
2021-02-24 10:58:31 +00:00
|
|
|
|
2023-12-14 00:50:49 +00:00
|
|
|
#define shadow_quanta 128
|
2023-08-13 08:25:17 +00:00
|
|
|
#define lnearclip 4
|
2023-08-13 08:36:32 +00:00
|
|
|
#define num_cascade 4
|
2023-12-14 00:56:53 +00:00
|
|
|
#define max_views 29 // FIXME should be 32 (or really, maxMultiviewViewCount,
|
|
|
|
// but there are other problems there), but nvidia's
|
|
|
|
// drivers segfault for > 29
|
2023-08-13 08:36:32 +00:00
|
|
|
|
|
|
|
static vec4f_t ref_direction = { 1, 0, 0, 0 };
|
|
|
|
|
2023-06-27 16:01:56 +00:00
|
|
|
#define ico_verts 12
|
|
|
|
#define cone_verts 7
|
|
|
|
static int ico_inds[] = {
|
|
|
|
0, 4, 6, 9, 2, 8, 4, -1,
|
|
|
|
3, 1, 10, 5, 7, 11, 1, -1,
|
|
|
|
1, 11, 6, 4, 10, -1,
|
|
|
|
9, 6, 11, 7, 2, -1,
|
|
|
|
5, 10, 8, 2, 7, -1,
|
|
|
|
4, 8, 10,
|
|
|
|
};
|
|
|
|
#define num_ico_inds (sizeof (ico_inds) / sizeof (ico_inds[0]))
|
|
|
|
static int cone_inds[] = {
|
|
|
|
0, 1, 2, 3, 4, 5, 6, 1, -1,
|
|
|
|
1, 6, 5, 4, 3, 2,
|
|
|
|
};
|
|
|
|
#define num_cone_inds (sizeof (cone_inds) / sizeof (cone_inds[0]))
|
2023-08-04 06:44:07 +00:00
|
|
|
|
|
|
|
#define dynlight_max 32
|
|
|
|
static int dynlight_size;
|
|
|
|
static cvar_t dynlight_size_cvar = {
|
|
|
|
.name = "dynlight_size",
|
|
|
|
.description =
|
|
|
|
"Effective radius of dynamic light shadow maps. Needs map reload to "
|
|
|
|
"take effect",
|
2023-12-14 00:50:49 +00:00
|
|
|
.default_value = "256",
|
2023-08-04 06:44:07 +00:00
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_int, .value = &dynlight_size },
|
|
|
|
};
|
2023-08-13 08:36:32 +00:00
|
|
|
|
2023-07-24 01:23:05 +00:00
|
|
|
static const light_t *
|
2023-08-13 08:36:32 +00:00
|
|
|
get_light (uint32_t ent, ecs_registry_t *reg)
|
2023-07-24 01:23:05 +00:00
|
|
|
{
|
2023-08-13 08:36:32 +00:00
|
|
|
return Ent_GetComponent (ent, scene_light, reg);
|
2023-07-24 01:23:05 +00:00
|
|
|
}
|
2023-08-13 08:36:32 +00:00
|
|
|
|
2023-08-04 06:44:07 +00:00
|
|
|
static const dlight_t *
|
|
|
|
get_dynlight (entity_t ent)
|
|
|
|
{
|
|
|
|
return Ent_GetComponent (ent.id, scene_dynlight, ent.reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
has_dynlight (entity_t ent)
|
|
|
|
{
|
|
|
|
return Ent_HasComponent (ent.id, scene_dynlight, ent.reg);
|
|
|
|
}
|
|
|
|
|
2023-08-01 14:34:08 +00:00
|
|
|
static uint32_t
|
2023-07-24 01:23:05 +00:00
|
|
|
get_lightstyle (entity_t ent)
|
|
|
|
{
|
2023-08-01 14:34:08 +00:00
|
|
|
return *(uint32_t *) Ent_GetComponent (ent.id, scene_lightstyle, ent.reg);
|
2022-05-31 03:43:04 +00:00
|
|
|
}
|
|
|
|
|
2023-07-27 07:09:33 +00:00
|
|
|
static uint32_t
|
|
|
|
get_lightleaf (entity_t ent)
|
|
|
|
{
|
|
|
|
return *(uint32_t *) Ent_GetComponent (ent.id, scene_lightleaf, ent.reg);
|
|
|
|
}
|
|
|
|
|
2023-07-24 01:23:05 +00:00
|
|
|
static uint32_t
|
|
|
|
get_lightid (entity_t ent)
|
2022-05-31 03:43:04 +00:00
|
|
|
{
|
2023-07-24 01:23:05 +00:00
|
|
|
return *(uint32_t *) Ent_GetComponent (ent.id, scene_lightid, ent.reg);
|
|
|
|
}
|
2022-05-31 03:43:04 +00:00
|
|
|
|
2023-07-24 01:23:05 +00:00
|
|
|
static void
|
|
|
|
set_lightid (uint32_t ent, ecs_registry_t *reg, uint32_t id)
|
|
|
|
{
|
|
|
|
Ent_SetComponent (ent, scene_lightid, reg, &id);
|
|
|
|
}
|
2022-05-31 03:43:04 +00:00
|
|
|
|
2023-07-27 07:09:33 +00:00
|
|
|
static void
|
2023-08-08 09:04:58 +00:00
|
|
|
lighting_setup_shadow (const exprval_t **params, exprval_t *result,
|
|
|
|
exprctx_t *ectx)
|
2023-07-27 07:09:33 +00:00
|
|
|
{
|
2023-11-28 06:54:55 +00:00
|
|
|
qfZoneNamed (zone, true);
|
2023-07-27 07:09:33 +00:00
|
|
|
auto taskctx = (qfv_taskctx_t *) ectx;
|
|
|
|
auto ctx = taskctx->ctx;
|
|
|
|
auto lctx = ctx->lighting_context;
|
|
|
|
|
|
|
|
if (!lctx->ldata) {
|
|
|
|
return;
|
|
|
|
}
|
2023-08-08 16:23:13 +00:00
|
|
|
auto pass = Vulkan_Bsp_GetPass (ctx, QFV_bspShadow);
|
2023-07-27 07:09:33 +00:00
|
|
|
auto brush = pass->brush;
|
2023-08-13 08:36:32 +00:00
|
|
|
|
2023-08-13 17:33:19 +00:00
|
|
|
if (brush->submodels) {
|
|
|
|
lctx->world_mins = loadvec3f (brush->submodels[0].mins);
|
|
|
|
lctx->world_maxs = loadvec3f (brush->submodels[0].maxs);
|
|
|
|
} else {
|
|
|
|
// FIXME better bounds
|
|
|
|
lctx->world_mins = (vec4f_t) { -512, -512, -512, 0 };
|
|
|
|
lctx->world_maxs = (vec4f_t) { 512, 512, 512, 0 };
|
|
|
|
}
|
2023-07-27 07:09:33 +00:00
|
|
|
set_t leafs = SET_STATIC_INIT (brush->modleafs, alloca);
|
|
|
|
set_empty (&leafs);
|
|
|
|
|
2023-08-10 00:38:42 +00:00
|
|
|
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];
|
2023-08-04 06:44:07 +00:00
|
|
|
if (!has_dynlight (ent)) {
|
|
|
|
auto ls = get_lightstyle (ent);
|
|
|
|
if (!d_lightstylevalue[ls]) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-07-27 07:09:33 +00:00
|
|
|
}
|
|
|
|
auto leafnum = get_lightleaf (ent);
|
|
|
|
if (leafnum != ~0u) {
|
|
|
|
set_add (&leafs, leafnum);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set_t pvs = SET_STATIC_INIT (brush->visleafs, alloca);
|
|
|
|
auto iter = set_first (&leafs);
|
|
|
|
if (!iter) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (iter->element == 0) {
|
|
|
|
set_assign (&pvs, lctx->ldata->sun_pvs);
|
|
|
|
} else {
|
|
|
|
Mod_LeafPVS_set (brush->leafs + iter->element, brush, 0, &pvs);
|
|
|
|
}
|
|
|
|
for (iter = set_next (iter); iter; iter = set_next (iter)) {
|
|
|
|
Mod_LeafPVS_mix (brush->leafs + iter->element, brush, 0, &pvs);
|
|
|
|
}
|
|
|
|
|
|
|
|
visstate_t visstate = {
|
|
|
|
.node_visframes = pass->node_frames,
|
|
|
|
.leaf_visframes = pass->leaf_frames,
|
|
|
|
.face_visframes = pass->face_frames,
|
|
|
|
.visframecount = pass->vis_frame,
|
|
|
|
.brush = pass->brush,
|
|
|
|
};
|
|
|
|
R_MarkLeavesPVS (&visstate, &pvs);
|
|
|
|
pass->vis_frame = visstate.visframecount;
|
|
|
|
}
|
|
|
|
|
2023-07-28 16:17:53 +00:00
|
|
|
static VkFramebuffer
|
2023-12-14 12:40:41 +00:00
|
|
|
create_framebuffer (vulkan_ctx_t *ctx, int size,
|
2023-07-28 16:17:53 +00:00
|
|
|
VkImageView view, VkRenderPass renderpass)
|
|
|
|
{
|
|
|
|
auto device = ctx->device;
|
|
|
|
auto dfunc = device->funcs;
|
|
|
|
|
|
|
|
VkFramebuffer framebuffer;
|
|
|
|
dfunc->vkCreateFramebuffer (device->dev,
|
|
|
|
&(VkFramebufferCreateInfo) {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
|
|
.renderPass = renderpass,
|
|
|
|
.attachmentCount = 1,
|
|
|
|
.pAttachments = &view,
|
2023-12-14 12:40:41 +00:00
|
|
|
.width = size,
|
|
|
|
.height = size,
|
2023-07-28 16:17:53 +00:00
|
|
|
.layers = 1,
|
|
|
|
}, 0, &framebuffer);
|
|
|
|
return framebuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-12-14 12:40:41 +00:00
|
|
|
copy_maps (uint32_t start, uint32_t count, int stage_id,
|
|
|
|
lightingframe_t *lframe, lightingctx_t *lctx, vulkan_ctx_t *ctx,
|
|
|
|
qfv_taskctx_t *taskctx)
|
2023-07-28 16:17:53 +00:00
|
|
|
{
|
2023-12-14 12:40:41 +00:00
|
|
|
qfZoneScoped (true);
|
2023-07-28 16:17:53 +00:00
|
|
|
auto device = ctx->device;
|
|
|
|
auto dfunc = device->funcs;
|
2023-12-14 12:40:41 +00:00
|
|
|
|
|
|
|
int num_regions = 0;
|
|
|
|
int num_copies = 0;
|
|
|
|
uint32_t last = ~0u;
|
|
|
|
for (uint32_t j = 0; j < count; j++) {
|
|
|
|
auto tgt = lframe->stage_targets[start + j];
|
|
|
|
// if the map id is different or if the layers aren't sequential
|
|
|
|
if (tgt != last + 0x20) {
|
|
|
|
num_regions++;
|
|
|
|
if ((tgt & 0x1f) != (last & 0x1f)) {
|
|
|
|
num_copies++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
last = tgt;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ib = imageBarriers[qfv_LT_TransferDst_to_ShaderReadOnly];
|
|
|
|
ib.barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
|
|
ib.barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
|
|
|
ib.barrier.subresourceRange.layerCount = 0;
|
|
|
|
|
|
|
|
VkImageMemoryBarrier barriers[num_regions];
|
|
|
|
VkImageCopy2 regions[num_regions];
|
|
|
|
VkCopyImageInfo2 copies[num_copies];
|
|
|
|
num_regions = 0;
|
|
|
|
num_copies = 0;
|
|
|
|
last = ~0u;
|
|
|
|
for (uint32_t j = 0; j < count; j++) {
|
|
|
|
auto tgt = lframe->stage_targets[start + j];
|
|
|
|
int ind = num_regions - 1;
|
|
|
|
// if the map id is different or if the layers aren't sequential
|
|
|
|
if (tgt != last + 0x20) {
|
|
|
|
int cpind = num_copies - 1;
|
|
|
|
if ((tgt & 0x1f) != (last & 0x1f)) {
|
|
|
|
cpind = num_copies++;
|
|
|
|
copies[cpind] = (VkCopyImageInfo2) {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2,
|
|
|
|
.srcImage = lctx->stage_images[stage_id],
|
|
|
|
.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
|
|
.dstImage = lctx->map_images[tgt & 0x1f],
|
|
|
|
.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
.pRegions = ®ions[num_regions],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
copies[cpind].regionCount++;
|
|
|
|
|
|
|
|
ind = num_regions++;
|
|
|
|
|
|
|
|
barriers[ind] = ib.barrier;
|
|
|
|
barriers[ind].subresourceRange.baseArrayLayer = tgt >> 5;
|
|
|
|
barriers[ind].image = lctx->map_images[tgt & 0x1f];
|
|
|
|
|
|
|
|
regions[ind] = (VkImageCopy2) {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_COPY_2,
|
|
|
|
.srcSubresource = {
|
|
|
|
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
|
|
|
|
.baseArrayLayer = j,
|
|
|
|
},
|
|
|
|
.dstSubresource = {
|
|
|
|
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
|
|
|
|
.baseArrayLayer = tgt >> 5,
|
|
|
|
},
|
|
|
|
.extent = {
|
|
|
|
.width = (stage_id + 1) * shadow_quanta,
|
|
|
|
.height = (stage_id + 1) * shadow_quanta,
|
|
|
|
.depth = 1,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
barriers[ind].subresourceRange.layerCount++;
|
|
|
|
regions[ind].srcSubresource.layerCount++;
|
|
|
|
regions[ind].dstSubresource.layerCount++;
|
|
|
|
last = tgt;
|
2023-07-28 16:17:53 +00:00
|
|
|
}
|
2023-12-14 12:40:41 +00:00
|
|
|
|
|
|
|
auto cmd = QFV_GetCmdBuffer (ctx, false);
|
|
|
|
dfunc->vkBeginCommandBuffer (cmd, &(VkCommandBufferBeginInfo) {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
|
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
|
|
|
});
|
|
|
|
{
|
|
|
|
qftVkScopedZoneC (taskctx->frame->qftVkCtx, cmd, "copy stage",
|
|
|
|
0xa0c060);
|
|
|
|
for (int i = 0; i < num_copies; i++) {
|
|
|
|
dfunc->vkCmdCopyImage2 (cmd, &copies[i]);
|
|
|
|
}
|
|
|
|
dfunc->vkCmdPipelineBarrier (cmd, ib.srcStages, ib.dstStages,
|
|
|
|
0, 0, 0, 0, 0, num_regions, barriers);
|
2023-07-28 16:17:53 +00:00
|
|
|
}
|
2023-12-14 12:40:41 +00:00
|
|
|
dfunc->vkEndCommandBuffer (cmd);
|
|
|
|
QFV_AppendCmdBuffer (ctx, cmd);
|
2023-07-28 16:17:53 +00:00
|
|
|
}
|
|
|
|
|
2023-07-24 01:23:05 +00:00
|
|
|
static void
|
|
|
|
lighting_draw_shadow_maps (const exprval_t **params, exprval_t *result,
|
|
|
|
exprctx_t *ectx)
|
|
|
|
{
|
2023-11-28 06:54:55 +00:00
|
|
|
qfZoneNamed (zone, true);
|
2023-07-28 16:17:53 +00:00
|
|
|
auto taskctx = (qfv_taskctx_t *) ectx;
|
|
|
|
auto ctx = taskctx->ctx;
|
|
|
|
auto lctx = ctx->lighting_context;
|
|
|
|
auto shadow = QFV_GetStep (params[0], ctx->render_context->job);
|
|
|
|
auto render = shadow->render;
|
|
|
|
auto lframe = &lctx->frames.a[ctx->curFrame];
|
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
if (!lctx->num_maps) {
|
2023-07-28 16:17:53 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-14 12:40:41 +00:00
|
|
|
uint32_t id_base = 0;
|
|
|
|
for (int i = 0; i < LIGHTING_STAGES; i++) {
|
|
|
|
auto queue = &lframe->stage_queue[i];
|
|
|
|
int count;
|
|
|
|
for (int remaining = queue->count; remaining > 0; remaining -= count) {
|
|
|
|
count = min (remaining, max_views);
|
|
|
|
int rpind = count - 1;
|
|
|
|
auto renderpass = &render->renderpasses[rpind];
|
|
|
|
auto fbuffer = lctx->stage_framebuffers[rpind][i];
|
|
|
|
uint32_t size = (i + 1) * shadow_quanta;
|
|
|
|
auto bi = &renderpass->beginInfo;
|
|
|
|
if (!fbuffer) {
|
|
|
|
auto view = lctx->stage_views[i];
|
|
|
|
fbuffer = create_framebuffer (ctx, size, view, bi->renderPass);
|
|
|
|
lctx->stage_framebuffers[rpind][i] = fbuffer;
|
2023-08-04 06:44:07 +00:00
|
|
|
}
|
2023-12-14 12:40:41 +00:00
|
|
|
bi->framebuffer = fbuffer;
|
|
|
|
QFV_RunRenderPass (ctx, renderpass, size, size, &id_base);
|
|
|
|
bi->framebuffer = 0;
|
|
|
|
|
|
|
|
copy_maps (id_base, count, i, lframe, lctx, ctx, taskctx);
|
|
|
|
id_base += count;
|
2023-08-04 06:44:07 +00:00
|
|
|
}
|
2023-07-28 16:17:53 +00:00
|
|
|
}
|
2022-05-31 03:43:04 +00:00
|
|
|
}
|
2023-07-24 01:23:05 +00:00
|
|
|
|
2023-12-17 04:14:43 +00:00
|
|
|
typedef enum : uint32_t {
|
|
|
|
style_enable,
|
|
|
|
style_disable = 0x80000000,
|
|
|
|
} style_e;
|
|
|
|
|
2023-08-04 06:44:07 +00:00
|
|
|
static uint32_t
|
2023-12-17 04:14:43 +00:00
|
|
|
make_id (const light_control_t *cont, style_e style)
|
2023-08-04 06:44:07 +00:00
|
|
|
{
|
2023-12-17 04:14:43 +00:00
|
|
|
uint32_t matrix_index = cont->matrix_id;
|
|
|
|
uint32_t map_index = cont->map_index;
|
|
|
|
uint32_t layer = cont->layer;
|
|
|
|
uint32_t type = cont->mode;
|
|
|
|
|
2023-08-04 06:44:07 +00:00
|
|
|
if (type == ST_CUBE) {
|
2023-12-13 03:20:10 +00:00
|
|
|
// on the GPU, layer is the cube layer, and one cube layer is 6
|
|
|
|
// flat image layers
|
2023-08-04 06:44:07 +00:00
|
|
|
layer /= 6;
|
|
|
|
}
|
2023-12-13 03:20:10 +00:00
|
|
|
return ((matrix_index & 0x3fff) << 0)
|
|
|
|
| ((map_index & 0x1f) << 14)
|
2023-12-17 04:14:43 +00:00
|
|
|
| ((layer & 0x7ff) << 19)
|
|
|
|
| style;
|
2023-08-04 06:44:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-08-13 08:36:32 +00:00
|
|
|
cube_mats (mat4f_t *mat, vec4f_t position)
|
2023-08-04 06:44:07 +00:00
|
|
|
{
|
|
|
|
mat4f_t view;
|
|
|
|
mat4fidentity (view);
|
|
|
|
view[3] = -position;
|
|
|
|
view[3][3] = 1;
|
|
|
|
|
|
|
|
mat4f_t proj;
|
2023-08-13 08:25:17 +00:00
|
|
|
QFV_PerspectiveTan (proj, 1, 1, lnearclip);
|
2023-08-04 06:44:07 +00:00
|
|
|
for (int j = 0; j < 6; j++) {
|
|
|
|
mat4f_t side_view;
|
|
|
|
mat4f_t rotinv;
|
|
|
|
mat4ftranspose (rotinv, qfv_box_rotations[j]);
|
|
|
|
mmulf (side_view, rotinv, view);
|
|
|
|
mmulf (side_view, qfv_z_up, side_view);
|
|
|
|
mmulf (mat[j], proj, side_view);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-13 08:36:32 +00:00
|
|
|
static void
|
|
|
|
frustum_corners (vec4f_t corners[8], float minz, float maxz,
|
|
|
|
const mat4f_t invproj)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
|
|
vec4f_t p = {
|
|
|
|
(i & 1) ? 1 : -1,
|
|
|
|
(i & 2) ? 1 : -1,
|
|
|
|
(i & 4) ? maxz : minz,
|
|
|
|
1
|
|
|
|
};
|
|
|
|
p = mvmulf (invproj, p);
|
|
|
|
corners[i] = p / p[3];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static vec4f_t
|
|
|
|
vec_select (vec4i_t c, vec4f_t a, vec4f_t b)
|
|
|
|
{
|
|
|
|
return (vec4f_t) ((c & (vec4i_t) a) | (~c & (vec4i_t) b));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
transform_corners (vec4f_t *mins, vec4f_t *maxs, const vec4f_t corners[8],
|
|
|
|
const mat4f_t lightview)
|
|
|
|
{
|
|
|
|
*mins = (vec4f_t) { INFINITY, INFINITY, INFINITY, INFINITY };
|
|
|
|
*maxs = (vec4f_t) { -INFINITY, -INFINITY, -INFINITY, -INFINITY };
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
|
|
vec4f_t p = mvmulf (lightview, corners[i]);
|
|
|
|
vec4i_t tmin = p <= *mins;
|
|
|
|
vec4i_t tmax = p >= *maxs;
|
|
|
|
*mins = vec_select (tmin, p, *mins);
|
|
|
|
*maxs = vec_select (tmax, p, *maxs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cascade_mats (mat4f_t *mat, vec4f_t position, vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
auto mctx = ctx->matrix_context;
|
|
|
|
auto lctx = ctx->lighting_context;
|
|
|
|
mat4f_t invproj;
|
|
|
|
QFV_InversePerspectiveTanFar (invproj, mctx->fov_x, mctx->fov_y,
|
|
|
|
r_nearclip, r_farclip);
|
|
|
|
mat4f_t inv_z_up;
|
|
|
|
mat4ftranspose (inv_z_up, qfv_z_up);
|
|
|
|
mmulf (invproj, inv_z_up, invproj);
|
|
|
|
mmulf (invproj, r_refdef.camera, invproj);
|
|
|
|
|
|
|
|
mat4f_t lightview;
|
|
|
|
// position points towards the light, but the view needs to be from the
|
|
|
|
// light.
|
|
|
|
mat4fquat (lightview, qrotf (-position, ref_direction));
|
|
|
|
|
|
|
|
// Find the world corner closest to the light in order to ensure the
|
|
|
|
// entire world between the focal point and the light is included in the
|
|
|
|
// depth range
|
|
|
|
vec4i_t d = position >= (vec4f_t) {0, 0, 0, 0};
|
|
|
|
vec4f_t lightcorner = vec_select (d, lctx->world_maxs, lctx->world_mins);
|
|
|
|
// assumes position is a unit vector (which it will be for directional
|
|
|
|
// lights loaded from quake maps)
|
|
|
|
float corner_dist = dotf (lightcorner-r_refdef.camera[3], position)[0];
|
|
|
|
|
|
|
|
// Pre-swizzle the light view so it's done only once (and so the
|
|
|
|
// frustum bounds get swizzled correctly for creating the orthographic
|
|
|
|
// projection matrix).
|
|
|
|
// Also, no need (actually, undesirable) to include any translation in
|
|
|
|
// the light view matrix as the orthographic matrix setup includes
|
|
|
|
// translation based on the bounds.
|
|
|
|
mmulf (lightview, qfv_z_up, lightview);
|
|
|
|
|
|
|
|
vec2f_t z_range[] = {
|
|
|
|
{ r_nearclip / 32, 1 },
|
|
|
|
{ r_nearclip / 256, r_nearclip / 32 },
|
|
|
|
{ r_nearclip / 1024, r_nearclip / 256 },
|
|
|
|
{ 0, r_nearclip / 1024 },
|
|
|
|
};
|
|
|
|
for (int i = 0; i < num_cascade; i++) {
|
|
|
|
vec4f_t corners[8];
|
|
|
|
vec4f_t fmin, fmax;
|
|
|
|
frustum_corners (corners, z_range[i][0], z_range[i][1], invproj);
|
|
|
|
transform_corners (&fmin, &fmax, corners, lightview);
|
|
|
|
// ensure evertything between the light and the far frustum corner
|
|
|
|
// is in the depth range
|
|
|
|
fmin[2] = min(fmin[2], -corner_dist);
|
|
|
|
QFV_OrthographicV (mat[i], fmin, fmax);
|
|
|
|
mmulf (mat[i], mat[i], lightview);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-14 12:40:41 +00:00
|
|
|
static uint16_t
|
|
|
|
make_target (uint16_t map_index, uint16_t layer)
|
|
|
|
{
|
|
|
|
return (map_index & 0x1f) | ((layer & 0x7ff) << 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
enqueue_map (uint32_t *ids, lightingframe_t *lframe, light_control_t *r)
|
|
|
|
{
|
|
|
|
auto q = &lframe->stage_queue[r->stage_index];
|
|
|
|
auto tgt = lframe->stage_targets;
|
|
|
|
for (uint32_t i = 0; i < r->numLayers; i++) {
|
|
|
|
ids[q->start + q->count + i] = r->matrix_id + i;
|
|
|
|
tgt[q->start + q->count + i] = make_target (r->map_index, r->layer + i);
|
|
|
|
}
|
|
|
|
q->count += r->numLayers;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
transition_shadow_targets (lightingframe_t *lframe, vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
auto device = ctx->device;
|
|
|
|
auto dfunc = device->funcs;
|
|
|
|
auto lctx = ctx->lighting_context;
|
|
|
|
|
|
|
|
int num_barriers = 0;
|
|
|
|
uint32_t last = ~0u;
|
|
|
|
for (int i = 0; i < LIGHTING_STAGES; i++) {
|
|
|
|
auto q = lframe->stage_queue[i];
|
|
|
|
for (uint32_t j = 0; j < q.count; j++) {
|
|
|
|
auto tgt = lframe->stage_targets[q.start + j];
|
|
|
|
// if the map id is different or if the layers aren't sequential
|
|
|
|
if (tgt != last + 0x20) {
|
|
|
|
num_barriers++;
|
|
|
|
}
|
|
|
|
last = tgt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ib = imageBarriers[qfv_LT_ShaderReadOnly_to_TransferDst];
|
|
|
|
ib.barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
|
|
ib.barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
|
|
|
ib.barrier.subresourceRange.layerCount = 0;
|
|
|
|
|
|
|
|
VkImageMemoryBarrier barriers[num_barriers];
|
|
|
|
num_barriers = 0;
|
|
|
|
last = ~0u;
|
|
|
|
for (int i = 0; i < LIGHTING_STAGES; i++) {
|
|
|
|
auto q = lframe->stage_queue[i];
|
|
|
|
for (uint32_t j = 0; j < q.count; j++) {
|
|
|
|
auto tgt = lframe->stage_targets[q.start + j];
|
|
|
|
int ind = num_barriers - 1;
|
|
|
|
// if the map id is different or if the layers aren't sequential
|
|
|
|
if (tgt != last + 0x20) {
|
|
|
|
barriers[num_barriers++] = ib.barrier;
|
|
|
|
ind = num_barriers - 1;
|
|
|
|
barriers[ind].subresourceRange.baseArrayLayer = tgt >> 5;
|
|
|
|
barriers[ind].image = lctx->map_images[tgt & 0x1f];
|
|
|
|
}
|
|
|
|
barriers[ind].subresourceRange.layerCount++;
|
|
|
|
last = tgt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto cmd = QFV_GetCmdBuffer (ctx, false);
|
|
|
|
dfunc->vkBeginCommandBuffer (cmd, &(VkCommandBufferBeginInfo) {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
|
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
|
|
|
});
|
|
|
|
dfunc->vkCmdPipelineBarrier (cmd, ib.srcStages, ib.dstStages,
|
|
|
|
0, 0, 0, 0, 0, num_barriers, barriers);
|
|
|
|
dfunc->vkEndCommandBuffer (cmd);
|
|
|
|
QFV_AppendCmdBuffer (ctx, cmd);
|
|
|
|
}
|
|
|
|
|
2023-12-16 06:44:44 +00:00
|
|
|
static float
|
|
|
|
light_radius (const light_t *l)
|
|
|
|
{
|
|
|
|
return l->attenuation[3] > 0 ? 1 / l->attenuation[3]
|
|
|
|
: l->attenuation[0] > 0 ? sqrt(abs(l->color[3]/l->attenuation[0]))
|
|
|
|
: l->attenuation[1] > 0 ? abs(l->color[3]/l->attenuation[1])
|
|
|
|
// FIXME ambient lights. not right, but at least it will render
|
|
|
|
: sqrt(abs(l->color[3]));
|
|
|
|
}
|
|
|
|
|
2023-06-27 16:01:56 +00:00
|
|
|
static void
|
|
|
|
lighting_update_lights (const exprval_t **params, exprval_t *result,
|
|
|
|
exprctx_t *ectx)
|
|
|
|
{
|
2023-11-28 06:54:55 +00:00
|
|
|
qfZoneNamed (zone, true);
|
2023-06-27 16:01:56 +00:00
|
|
|
auto taskctx = (qfv_taskctx_t *) ectx;
|
|
|
|
auto ctx = taskctx->ctx;
|
|
|
|
auto lctx = ctx->lighting_context;
|
|
|
|
|
|
|
|
auto lframe = &lctx->frames.a[ctx->curFrame];
|
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
memset (lframe->light_queue, 0, sizeof (lframe->light_queue));
|
2023-06-27 16:01:56 +00:00
|
|
|
if (!lctx->scene || !lctx->scene->lights) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-01 14:34:08 +00:00
|
|
|
auto bb = &bufferBarriers[qfv_BB_TransferWrite_to_UniformRead];
|
2023-06-27 16:01:56 +00:00
|
|
|
|
2023-08-13 08:36:32 +00:00
|
|
|
uint32_t light_ids[ST_COUNT][MaxLights];
|
2023-12-16 06:44:44 +00:00
|
|
|
float light_radii[ST_COUNT][MaxLights];
|
2023-12-17 01:45:59 +00:00
|
|
|
vec4f_t light_positions[ST_COUNT][MaxLights];
|
2023-08-13 08:36:32 +00:00
|
|
|
uint32_t entids[ST_COUNT][MaxLights];
|
2023-06-27 16:01:56 +00:00
|
|
|
|
2023-08-01 14:34:08 +00:00
|
|
|
uint32_t light_count = 0;
|
2023-08-02 08:52:57 +00:00
|
|
|
auto queue = lframe->light_queue;
|
2023-08-01 14:34:08 +00:00
|
|
|
|
2023-08-04 06:44:07 +00:00
|
|
|
uint32_t dynamic_light_entities[MaxLights];
|
|
|
|
const dlight_t *dynamic_lights[MaxLights];
|
|
|
|
int ndlight = 0;
|
|
|
|
|
|
|
|
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];
|
|
|
|
if (has_dynlight (ent)) {
|
|
|
|
dynamic_light_entities[ndlight] = ent.id;
|
|
|
|
dynamic_lights[ndlight] = get_dynlight (ent);
|
|
|
|
ndlight++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto ls = get_lightstyle (ent);
|
|
|
|
if (!d_lightstylevalue[ls]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
light_count++;
|
|
|
|
uint32_t id = lctx->light_control.a[get_lightid (ent)].light_id;
|
2023-12-14 12:40:41 +00:00
|
|
|
auto r = &lctx->light_control.a[id];
|
|
|
|
|
|
|
|
int mode = r->mode;
|
2023-12-16 06:44:44 +00:00
|
|
|
auto light = get_light (ent.id, ent.reg);
|
2023-12-17 01:45:59 +00:00
|
|
|
uint32_t ind = queue[mode].count++;
|
|
|
|
light_ids[mode][ind] = id;
|
|
|
|
light_radii[mode][ind] = light_radius (light);
|
|
|
|
light_positions[mode][ind] = light->position;
|
|
|
|
entids[mode][ind] = ent.id;
|
2023-08-04 06:44:07 +00:00
|
|
|
}
|
2023-08-01 14:34:08 +00:00
|
|
|
|
2023-12-12 12:13:14 +00:00
|
|
|
size_t packet_size = 0;
|
2023-12-05 15:15:42 +00:00
|
|
|
packet_size += sizeof (vec4f_t[NumStyles]);
|
2023-08-13 08:36:32 +00:00
|
|
|
if (queue[ST_CASCADE].count) {
|
|
|
|
uint32_t mat_count = queue[ST_CASCADE].count * num_cascade;
|
2023-12-05 15:15:42 +00:00
|
|
|
packet_size += sizeof (mat4f_t[mat_count]);
|
|
|
|
}
|
|
|
|
if (ndlight) {
|
|
|
|
packet_size += sizeof (mat4f_t[ndlight * 6]);
|
|
|
|
packet_size += sizeof (light_t[ndlight]);
|
|
|
|
packet_size += sizeof (qfv_light_render_t[ndlight]);
|
|
|
|
}
|
|
|
|
if (light_count) {
|
|
|
|
// light ids
|
|
|
|
packet_size += sizeof (uint32_t[light_count]);
|
2023-12-16 06:44:44 +00:00
|
|
|
// light radii
|
|
|
|
packet_size += sizeof (float[light_count]);
|
2023-12-05 15:15:42 +00:00
|
|
|
// ent ids
|
|
|
|
packet_size += sizeof (uint32_t[light_count]);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto packet = QFV_PacketAcquire (ctx->staging);
|
|
|
|
byte *packet_start = QFV_PacketExtend (packet, packet_size);
|
|
|
|
byte *packet_data = packet_start;
|
|
|
|
|
|
|
|
qfv_scatter_t style_scatter = {
|
|
|
|
.srcOffset = 0,
|
|
|
|
.dstOffset = 0,
|
|
|
|
.length = sizeof (vec4f_t[NumStyles]),
|
|
|
|
};
|
|
|
|
auto styles = (vec4f_t *) packet_data;
|
|
|
|
packet_data += style_scatter.length;
|
|
|
|
for (int i = 0; i < NumStyles; i++) {
|
|
|
|
styles[i] = (vec4f_t) { 1, 1, 1, d_lightstylevalue[i] / 65536.0};
|
|
|
|
}
|
|
|
|
QFV_PacketScatterBuffer (packet, lframe->style_buffer,
|
|
|
|
1, &style_scatter, bb);
|
|
|
|
|
|
|
|
if (queue[ST_CASCADE].count) {
|
|
|
|
uint32_t mat_count = queue[ST_CASCADE].count * num_cascade;
|
|
|
|
auto mats = (mat4f_t *) packet_data;
|
|
|
|
auto base = packet_data - packet_start;
|
|
|
|
packet_data += sizeof (mat4f_t[mat_count]);
|
2023-08-13 08:36:32 +00:00
|
|
|
qfv_scatter_t scatter[queue[ST_CASCADE].count];
|
|
|
|
for (uint32_t i = 0; i < queue[ST_CASCADE].count; i++) {
|
|
|
|
auto r = &lctx->light_control.a[light_ids[ST_CASCADE][i]];
|
|
|
|
auto light = get_light (entids[ST_CASCADE][i], lctx->scene->reg);
|
|
|
|
cascade_mats (&mats[i * num_cascade], light->position, ctx);
|
|
|
|
scatter[i] = (qfv_scatter_t) {
|
2023-12-05 15:15:42 +00:00
|
|
|
.srcOffset = base + sizeof (mat4f_t[i * num_cascade]),
|
2023-08-13 08:36:32 +00:00
|
|
|
.dstOffset = sizeof (mat4f_t[r->matrix_id]),
|
|
|
|
.length = sizeof (mat4f_t[num_cascade]),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
QFV_PacketScatterBuffer (packet, lframe->shadowmat_buffer,
|
|
|
|
queue[ST_CASCADE].count, scatter, bb);
|
|
|
|
}
|
|
|
|
|
2023-08-01 14:34:08 +00:00
|
|
|
if (ndlight) {
|
2023-08-04 06:44:07 +00:00
|
|
|
light_count += ndlight;
|
2023-12-05 15:15:42 +00:00
|
|
|
|
|
|
|
auto mats = (mat4f_t *) packet_data;
|
|
|
|
qfv_scatter_t mat_scatter = {
|
|
|
|
.srcOffset = packet_data - packet_start,
|
|
|
|
.dstOffset = sizeof (mat4f_t[lctx->dynamic_matrix_base]),
|
|
|
|
.length = sizeof (mat4f_t[ndlight * 6]),
|
|
|
|
};
|
2023-12-14 14:17:14 +00:00
|
|
|
packet_data += mat_scatter.length;
|
2023-12-05 15:15:42 +00:00
|
|
|
for (int i = 0; i < ndlight; i++) {
|
|
|
|
cube_mats (&mats[i * 6], dynamic_lights[i]->origin);
|
|
|
|
}
|
|
|
|
QFV_PacketScatterBuffer (packet, lframe->shadowmat_buffer,
|
|
|
|
1, &mat_scatter, bb);
|
|
|
|
|
|
|
|
auto lights = (light_t *) packet_data;
|
|
|
|
qfv_scatter_t light_scatter = {
|
|
|
|
.srcOffset = packet_data - packet_start,
|
|
|
|
.dstOffset = sizeof (light_t[lctx->dynamic_base]),
|
|
|
|
.length = sizeof (light_t[ndlight]),
|
|
|
|
};
|
|
|
|
packet_data += light_scatter.length;
|
2023-08-01 14:34:08 +00:00
|
|
|
for (int i = 0; i < ndlight; i++) {
|
2023-12-16 06:44:44 +00:00
|
|
|
light_t light = {
|
|
|
|
.color = {
|
|
|
|
VectorExpand (dynamic_lights[i]->color),
|
|
|
|
// dynamic lights seem a tad faint, so 16x map lights
|
|
|
|
dynamic_lights[i]->radius / 16,
|
|
|
|
},
|
|
|
|
// dlights are local point sources
|
|
|
|
.position = { VectorExpand (dynamic_lights[i]->origin), 1 },
|
|
|
|
// full sphere, normal light (not ambient)
|
|
|
|
.direction = { 0, 0, 1, 1 },
|
|
|
|
.attenuation = { 0, 0, 1, 1/dynamic_lights[i]->radius },
|
|
|
|
};
|
2023-08-04 06:44:07 +00:00
|
|
|
uint32_t id = lctx->dynamic_base + i;
|
|
|
|
set_lightid (dynamic_light_entities[i], lctx->scene->reg, id);
|
2023-12-17 01:45:59 +00:00
|
|
|
uint32_t ind = queue[ST_CUBE].count++;
|
|
|
|
light_ids[ST_CUBE][ind] = id;
|
|
|
|
light_radii[ST_CUBE][ind] = light_radius (&light);
|
|
|
|
light_positions[ST_CUBE][ind] = light.position;
|
|
|
|
entids[ST_CUBE][ind] = dynamic_light_entities[i];
|
2023-08-01 14:34:08 +00:00
|
|
|
|
2023-12-16 06:44:44 +00:00
|
|
|
lights[i] = light;
|
2023-06-27 16:01:56 +00:00
|
|
|
}
|
2023-12-05 15:15:42 +00:00
|
|
|
QFV_PacketScatterBuffer (packet, lframe->light_buffer,
|
|
|
|
1, &light_scatter, bb);
|
|
|
|
|
|
|
|
auto render = (qfv_light_render_t *) packet_data;
|
|
|
|
qfv_scatter_t render_scatter = {
|
|
|
|
.srcOffset = packet_data - packet_start,
|
|
|
|
.dstOffset = sizeof (qfv_light_render_t[lctx->dynamic_base]),
|
|
|
|
.length = sizeof (qfv_light_render_t[ndlight]),
|
|
|
|
};
|
|
|
|
packet_data += render_scatter.length;
|
2023-08-01 14:34:08 +00:00
|
|
|
for (int i = 0; i < ndlight; i++) {
|
2023-08-04 06:44:07 +00:00
|
|
|
auto r = &lctx->light_control.a[lctx->dynamic_base + i];
|
2023-08-01 14:34:08 +00:00
|
|
|
render[i] = (qfv_light_render_t) {
|
2023-12-17 04:14:43 +00:00
|
|
|
.id_data = make_id(r, style_disable),
|
2023-08-01 14:34:08 +00:00
|
|
|
};
|
|
|
|
}
|
2023-12-05 15:15:42 +00:00
|
|
|
QFV_PacketScatterBuffer (packet, lframe->render_buffer,
|
|
|
|
1, &render_scatter, bb);
|
2023-06-27 16:01:56 +00:00
|
|
|
}
|
|
|
|
if (developer & SYS_lighting) {
|
|
|
|
Vulkan_Draw_String (vid.width - 32, 8,
|
2023-08-01 14:34:08 +00:00
|
|
|
va (ctx->va_ctx, "%3d", light_count),
|
2023-06-27 16:01:56 +00:00
|
|
|
ctx);
|
|
|
|
}
|
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
if (light_count) {
|
2023-08-13 08:36:32 +00:00
|
|
|
for (int i = 1; i < ST_COUNT; i++) {
|
2023-08-02 08:52:57 +00:00
|
|
|
queue[i].start = queue[i - 1].start + queue[i - 1].count;
|
|
|
|
}
|
2023-12-16 06:44:44 +00:00
|
|
|
|
2023-12-05 15:15:42 +00:00
|
|
|
auto lids = (uint32_t *) packet_data;
|
|
|
|
qfv_scatter_t lid_scatter = {
|
|
|
|
.srcOffset = packet_data - packet_start,
|
|
|
|
.dstOffset = 0,
|
|
|
|
.length = sizeof (uint32_t[light_count]),
|
|
|
|
};
|
|
|
|
packet_data += lid_scatter.length;
|
2023-08-13 08:36:32 +00:00
|
|
|
for (int i = 0; i < ST_COUNT; i++) {
|
2023-08-07 08:47:49 +00:00
|
|
|
memcpy (lids + queue[i].start, light_ids[i],
|
2023-08-02 08:52:57 +00:00
|
|
|
sizeof (uint32_t[queue[i].count]));
|
|
|
|
}
|
2023-12-05 15:15:42 +00:00
|
|
|
QFV_PacketScatterBuffer (packet, lframe->id_buffer,
|
|
|
|
1, &lid_scatter,
|
2023-06-27 16:01:56 +00:00
|
|
|
&bufferBarriers[qfv_BB_TransferWrite_to_IndexRead]);
|
2023-08-07 08:47:49 +00:00
|
|
|
|
2023-12-16 06:44:44 +00:00
|
|
|
auto lradii = (float *) packet_data;
|
|
|
|
qfv_scatter_t lradius_scatter = {
|
|
|
|
.srcOffset = packet_data - packet_start,
|
|
|
|
.dstOffset = 0,
|
|
|
|
.length = sizeof (float[light_count]),
|
|
|
|
};
|
|
|
|
packet_data += lradius_scatter.length;
|
|
|
|
for (int i = 0; i < ST_COUNT; i++) {
|
|
|
|
memcpy (lradii + queue[i].start, light_radii[i],
|
|
|
|
sizeof (float[queue[i].count]));
|
|
|
|
}
|
|
|
|
QFV_PacketScatterBuffer (packet, lframe->radius_buffer,
|
|
|
|
1, &lradius_scatter,
|
|
|
|
&bufferBarriers[qfv_BB_TransferWrite_to_IndexRead]);
|
|
|
|
|
2023-12-05 15:15:42 +00:00
|
|
|
auto eids = (uint32_t *) packet_data;
|
|
|
|
qfv_scatter_t eid_scatter = {
|
|
|
|
.srcOffset = packet_data - packet_start,
|
|
|
|
.dstOffset = 0,
|
|
|
|
.length = sizeof (uint32_t[light_count]),
|
|
|
|
};
|
|
|
|
packet_data += eid_scatter.length;
|
2023-08-13 08:36:32 +00:00
|
|
|
for (int i = 0; i < ST_COUNT; i++) {
|
2023-08-07 08:47:49 +00:00
|
|
|
memcpy (eids + queue[i].start, entids[i],
|
|
|
|
sizeof (uint32_t[queue[i].count]));
|
|
|
|
}
|
2023-12-14 12:40:41 +00:00
|
|
|
auto ir_barrier = &bufferBarriers[qfv_BB_TransferWrite_to_IndexRead];
|
|
|
|
QFV_PacketScatterBuffer (packet, lframe->entid_buffer, 1, &eid_scatter,
|
|
|
|
ir_barrier);
|
2023-12-17 01:45:59 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < ST_COUNT; i++) {
|
|
|
|
auto q = queue[i];
|
|
|
|
auto idr = &lframe->id_radius[q.start];
|
|
|
|
auto pos = &lframe->positions[q.start];
|
|
|
|
for (uint32_t j = 0; j < q.count; j++) {
|
|
|
|
idr[j] = (light_idrad_t) {
|
|
|
|
.id = light_ids[i][j],
|
|
|
|
.radius = light_radii[i][j],
|
|
|
|
};
|
|
|
|
pos[j] = light_positions[i][j];
|
|
|
|
}
|
|
|
|
}
|
2023-12-14 12:40:41 +00:00
|
|
|
}
|
|
|
|
|
2023-12-05 15:15:42 +00:00
|
|
|
QFV_PacketSubmit (packet);
|
2023-06-27 16:01:56 +00:00
|
|
|
}
|
|
|
|
|
2023-02-13 15:55:22 +00:00
|
|
|
static void
|
2023-06-28 02:47:26 +00:00
|
|
|
lighting_update_descriptors (const exprval_t **params, exprval_t *result,
|
|
|
|
exprctx_t *ectx)
|
2023-02-13 15:55:22 +00:00
|
|
|
{
|
2023-11-28 06:54:55 +00:00
|
|
|
qfZoneNamed (zone, true);
|
2023-06-22 12:36:14 +00:00
|
|
|
auto taskctx = (qfv_taskctx_t *) ectx;
|
|
|
|
auto ctx = taskctx->ctx;
|
|
|
|
auto device = ctx->device;
|
|
|
|
auto dfunc = device->funcs;
|
|
|
|
auto lctx = ctx->lighting_context;
|
|
|
|
|
2023-06-27 16:01:56 +00:00
|
|
|
auto lframe = &lctx->frames.a[ctx->curFrame];
|
2023-06-22 12:36:14 +00:00
|
|
|
|
2023-08-01 14:34:08 +00:00
|
|
|
auto job = ctx->render_context->job;
|
|
|
|
auto step = QFV_GetStep (params[0], job);
|
|
|
|
auto render = step->render;
|
|
|
|
auto fb = &render->active->framebuffer;
|
2023-07-30 02:28:42 +00:00
|
|
|
VkDescriptorImageInfo attachInfo[] = {
|
|
|
|
{ .imageView = fb->views[QFV_attachColor],
|
|
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
|
|
|
{ .imageView = fb->views[QFV_attachEmission],
|
|
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
|
|
|
{ .imageView = fb->views[QFV_attachNormal],
|
|
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
|
|
|
{ .imageView = fb->views[QFV_attachPosition],
|
|
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
|
|
|
|
};
|
|
|
|
VkWriteDescriptorSet attachWrite[] = {
|
|
|
|
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstSet = lframe->attach_set,
|
|
|
|
.dstBinding = 0,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
|
|
|
.pImageInfo = &attachInfo[0], },
|
|
|
|
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstSet = lframe->attach_set,
|
|
|
|
.dstBinding = 1,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
|
|
|
.pImageInfo = &attachInfo[1], },
|
|
|
|
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstSet = lframe->attach_set,
|
|
|
|
.dstBinding = 2,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
|
|
|
.pImageInfo = &attachInfo[2], },
|
|
|
|
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstSet = lframe->attach_set,
|
|
|
|
.dstBinding = 3,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
|
|
|
.pImageInfo = &attachInfo[3], },
|
|
|
|
};
|
2023-06-22 12:36:14 +00:00
|
|
|
dfunc->vkUpdateDescriptorSets (device->dev,
|
2023-07-30 02:28:42 +00:00
|
|
|
LIGHTING_ATTACH_INFOS, attachWrite,
|
|
|
|
0, 0);
|
2023-06-28 02:47:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lighting_bind_descriptors (const exprval_t **params, exprval_t *result,
|
|
|
|
exprctx_t *ectx)
|
|
|
|
{
|
2023-11-28 06:54:55 +00:00
|
|
|
qfZoneNamed (zone, true);
|
2023-06-28 02:47:26 +00:00
|
|
|
auto taskctx = (qfv_taskctx_t *) ectx;
|
|
|
|
auto ctx = taskctx->ctx;
|
|
|
|
auto device = ctx->device;
|
|
|
|
auto dfunc = device->funcs;
|
|
|
|
auto lctx = ctx->lighting_context;
|
2023-08-02 08:52:57 +00:00
|
|
|
if (!lctx->num_maps) {
|
|
|
|
return;
|
|
|
|
}
|
2023-06-28 02:47:26 +00:00
|
|
|
auto cmd = taskctx->cmd;
|
|
|
|
auto layout = taskctx->pipeline->layout;
|
|
|
|
|
|
|
|
auto lframe = &lctx->frames.a[ctx->curFrame];
|
2023-08-02 08:52:57 +00:00
|
|
|
auto shadow_type = *(int *) params[0]->value;
|
2023-08-05 15:20:25 +00:00
|
|
|
auto stage = *(int *) params[1]->value;
|
|
|
|
|
2023-12-16 05:00:01 +00:00
|
|
|
if (stage == lighting_hull) {
|
2023-12-17 01:56:59 +00:00
|
|
|
bool planes = shadow_type == ST_PLANE;
|
2023-08-05 15:20:25 +00:00
|
|
|
VkDescriptorSet sets[] = {
|
|
|
|
Vulkan_Matrix_Descriptors (ctx, ctx->curFrame),
|
|
|
|
lframe->lights_set,
|
2023-12-17 01:56:59 +00:00
|
|
|
planes ? Vulkan_Translucent_Descriptors (ctx, ctx->curFrame) : 0,
|
2023-08-05 15:20:25 +00:00
|
|
|
};
|
|
|
|
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
2023-12-17 01:56:59 +00:00
|
|
|
layout, 0, 2 + planes, sets, 0, 0);
|
2023-06-22 12:36:14 +00:00
|
|
|
|
2023-06-28 04:19:10 +00:00
|
|
|
VkBuffer buffers[] = {
|
|
|
|
lframe->id_buffer,
|
2023-12-16 06:44:44 +00:00
|
|
|
lframe->radius_buffer,
|
2023-06-28 04:19:10 +00:00
|
|
|
lctx->splat_verts,
|
|
|
|
};
|
2023-12-16 06:44:44 +00:00
|
|
|
VkDeviceSize offsets[] = { 0, 0, 0 };
|
|
|
|
dfunc->vkCmdBindVertexBuffers (cmd, 0, 3, buffers, offsets);
|
2023-06-28 04:19:10 +00:00
|
|
|
dfunc->vkCmdBindIndexBuffer (cmd, lctx->splat_inds, 0,
|
|
|
|
VK_INDEX_TYPE_UINT32);
|
2023-08-05 15:20:25 +00:00
|
|
|
} else {
|
|
|
|
VkDescriptorSet sets[] = {
|
|
|
|
lframe->shadowmat_set,
|
|
|
|
lframe->lights_set,
|
|
|
|
lframe->attach_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);
|
2023-06-28 04:19:10 +00:00
|
|
|
}
|
2023-06-27 16:01:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lighting_draw_splats (const exprval_t **params, exprval_t *result,
|
|
|
|
exprctx_t *ectx)
|
|
|
|
{
|
2023-11-28 06:54:55 +00:00
|
|
|
qfZoneNamed (zone, true);
|
2023-06-27 16:01:56 +00:00
|
|
|
auto taskctx = (qfv_taskctx_t *) ectx;
|
|
|
|
auto ctx = taskctx->ctx;
|
|
|
|
auto device = ctx->device;
|
|
|
|
auto dfunc = device->funcs;
|
|
|
|
auto lctx = ctx->lighting_context;
|
|
|
|
auto cmd = taskctx->cmd;
|
|
|
|
|
|
|
|
auto lframe = &lctx->frames.a[ctx->curFrame];
|
2023-08-05 15:20:25 +00:00
|
|
|
if (lframe->light_queue[ST_CUBE].count) {
|
|
|
|
auto q = lframe->light_queue[ST_CUBE];
|
|
|
|
dfunc->vkCmdDrawIndexed (cmd, num_ico_inds, q.count, 0, 0, q.start);
|
2023-06-27 16:01:56 +00:00
|
|
|
}
|
2023-08-05 15:20:25 +00:00
|
|
|
if (lframe->light_queue[ST_PLANE].count) {
|
|
|
|
auto q = lframe->light_queue[ST_PLANE];
|
|
|
|
dfunc->vkCmdDrawIndexed (cmd, num_cone_inds, q.count,
|
|
|
|
num_ico_inds, 12, q.start);
|
2023-06-27 16:01:56 +00:00
|
|
|
}
|
2023-02-13 15:55:22 +00:00
|
|
|
}
|
|
|
|
|
2023-12-17 01:45:59 +00:00
|
|
|
static void
|
|
|
|
lighting_rewrite_ids (lightingframe_t *lframe, vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
uint32_t count = 0;
|
[vulkan] Implement shadow map culling
The rendering of the shadow maps now takes the culling information into
account resulting in a drastic reduction of work. There's still more
work to be done, but demo1 peaks at over 1000fps at 640x480, gmsp3v2 now
gets 14fps (1920x1080) near the front gate (used to be 3, then 6),
ad_tears is up to 3fps, but marcher is still unhappy, but it has
infinite radius lights, so needs more culling work (clipped light
volumes will help, I think). Also, culling lights for which nothing has
moved within their volumes will help somewhat (though not as much for
most id maps, I suspect).
2023-12-17 07:03:41 +00:00
|
|
|
auto lctx = ctx->lighting_context;
|
2023-12-17 01:45:59 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < ST_COUNT; i++) {
|
|
|
|
auto q = &lframe->light_queue[i];
|
|
|
|
count += q->count;
|
|
|
|
}
|
|
|
|
uint32_t light_ids[count];
|
|
|
|
float light_radii[count];
|
|
|
|
uint32_t light_count = 0;
|
|
|
|
light_queue_t queue[ST_COUNT] = {};
|
|
|
|
for (int i = 0; i < ST_COUNT; i++) {
|
|
|
|
auto q = &lframe->light_queue[i];
|
|
|
|
for (uint32_t j = 0; j < q[0].count; j++) {
|
|
|
|
uint32_t id = lframe->id_radius[q[0].start + j].id;
|
|
|
|
float radius = lframe->id_radius[q[0].start + j].radius;
|
|
|
|
if (id != ~0u) {
|
|
|
|
light_ids[queue[i].start + queue[i].count] = id;
|
|
|
|
light_radii[queue[i].start + queue[i].count] = radius;
|
|
|
|
queue[i].count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i < ST_COUNT - 1) {
|
|
|
|
queue[i + 1].start = queue[i].start + queue[i].count;
|
|
|
|
} else {
|
|
|
|
light_count = queue[i].start + queue[i].count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < ST_COUNT; i++) {
|
|
|
|
lframe->light_queue[i] = queue[i];
|
|
|
|
}
|
[vulkan] Implement shadow map culling
The rendering of the shadow maps now takes the culling information into
account resulting in a drastic reduction of work. There's still more
work to be done, but demo1 peaks at over 1000fps at 640x480, gmsp3v2 now
gets 14fps (1920x1080) near the front gate (used to be 3, then 6),
ad_tears is up to 3fps, but marcher is still unhappy, but it has
infinite radius lights, so needs more culling work (clipped light
volumes will help, I think). Also, culling lights for which nothing has
moved within their volumes will help somewhat (though not as much for
most id maps, I suspect).
2023-12-17 07:03:41 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < LIGHTING_STAGES; i++) {
|
|
|
|
lframe->stage_queue[i].count = 0;
|
|
|
|
}
|
|
|
|
int matrix_id_count = 0;
|
|
|
|
for (uint32_t i = 0; i < light_count; i++) {
|
|
|
|
auto r = &lctx->light_control.a[light_ids[i]];
|
|
|
|
if (r->light_id != light_ids[i]) {
|
|
|
|
Sys_Error ("%d != %d", r->light_id, light_ids[i]);
|
|
|
|
}
|
|
|
|
lframe->stage_queue[r->stage_index].count += r->numLayers;
|
|
|
|
matrix_id_count += r->numLayers;
|
|
|
|
}
|
|
|
|
lframe->stage_queue[0].start = 0;
|
|
|
|
for (int i = 1; i < LIGHTING_STAGES; i++) {
|
|
|
|
auto q = &lframe->stage_queue[i];
|
|
|
|
q[0].start = q[-1].start + q[-1].count;
|
|
|
|
q[-1].count = 0;
|
|
|
|
}
|
|
|
|
lframe->stage_queue[LIGHTING_STAGES - 1].count = 0;
|
|
|
|
|
2023-12-17 01:45:59 +00:00
|
|
|
size_t packet_size = 0;
|
|
|
|
packet_size += sizeof (uint32_t[light_count]);
|
|
|
|
packet_size += sizeof (float[light_count]);
|
[vulkan] Implement shadow map culling
The rendering of the shadow maps now takes the culling information into
account resulting in a drastic reduction of work. There's still more
work to be done, but demo1 peaks at over 1000fps at 640x480, gmsp3v2 now
gets 14fps (1920x1080) near the front gate (used to be 3, then 6),
ad_tears is up to 3fps, but marcher is still unhappy, but it has
infinite radius lights, so needs more culling work (clipped light
volumes will help, I think). Also, culling lights for which nothing has
moved within their volumes will help somewhat (though not as much for
most id maps, I suspect).
2023-12-17 07:03:41 +00:00
|
|
|
packet_size += sizeof (uint32_t[matrix_id_count]);
|
2023-12-17 01:45:59 +00:00
|
|
|
|
2023-12-17 11:05:17 +00:00
|
|
|
if (!packet_size) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-17 01:45:59 +00:00
|
|
|
auto bb = &bufferBarriers[qfv_BB_TransferWrite_to_UniformRead];
|
|
|
|
auto packet = QFV_PacketAcquire (ctx->staging);
|
|
|
|
byte *packet_start = QFV_PacketExtend (packet, packet_size);
|
|
|
|
byte *packet_data = packet_start;
|
|
|
|
|
|
|
|
qfv_scatter_t id_scatter = {
|
|
|
|
.srcOffset = packet_data - packet_start,
|
|
|
|
.dstOffset = 0,
|
|
|
|
.length = sizeof (uint32_t[light_count]),
|
|
|
|
};
|
|
|
|
auto id_data = (uint32_t *) packet_data;
|
|
|
|
packet_data += id_scatter.length;
|
|
|
|
|
|
|
|
qfv_scatter_t radius_scatter = {
|
|
|
|
.srcOffset = packet_data - packet_start,
|
|
|
|
.dstOffset = 0,
|
|
|
|
.length = sizeof (uint32_t[light_count]),
|
|
|
|
};
|
|
|
|
auto radius_data = (uint32_t *) packet_data;
|
|
|
|
packet_data += radius_scatter.length;
|
|
|
|
|
[vulkan] Implement shadow map culling
The rendering of the shadow maps now takes the culling information into
account resulting in a drastic reduction of work. There's still more
work to be done, but demo1 peaks at over 1000fps at 640x480, gmsp3v2 now
gets 14fps (1920x1080) near the front gate (used to be 3, then 6),
ad_tears is up to 3fps, but marcher is still unhappy, but it has
infinite radius lights, so needs more culling work (clipped light
volumes will help, I think). Also, culling lights for which nothing has
moved within their volumes will help somewhat (though not as much for
most id maps, I suspect).
2023-12-17 07:03:41 +00:00
|
|
|
qfv_scatter_t matrix_id_scater = {
|
|
|
|
.srcOffset = packet_data - packet_start,
|
|
|
|
.dstOffset = 0,
|
|
|
|
.length = sizeof (uint32_t[matrix_id_count]),
|
|
|
|
};
|
|
|
|
auto matrix_ids = (uint32_t *) packet_data;
|
|
|
|
packet_data += matrix_id_scater.length;
|
|
|
|
|
2023-12-17 01:45:59 +00:00
|
|
|
memcpy (id_data, light_ids, packet_size);
|
|
|
|
memcpy (radius_data, light_radii, packet_size);
|
[vulkan] Implement shadow map culling
The rendering of the shadow maps now takes the culling information into
account resulting in a drastic reduction of work. There's still more
work to be done, but demo1 peaks at over 1000fps at 640x480, gmsp3v2 now
gets 14fps (1920x1080) near the front gate (used to be 3, then 6),
ad_tears is up to 3fps, but marcher is still unhappy, but it has
infinite radius lights, so needs more culling work (clipped light
volumes will help, I think). Also, culling lights for which nothing has
moved within their volumes will help somewhat (though not as much for
most id maps, I suspect).
2023-12-17 07:03:41 +00:00
|
|
|
for (uint32_t i = 0; i < light_count; i++) {
|
|
|
|
auto r = &lctx->light_control.a[light_ids[i]];
|
|
|
|
enqueue_map (matrix_ids, lframe, r);
|
|
|
|
}
|
2023-12-17 01:45:59 +00:00
|
|
|
|
|
|
|
QFV_PacketScatterBuffer (packet, lframe->id_buffer, 1, &id_scatter, bb);
|
|
|
|
QFV_PacketScatterBuffer (packet, lframe->radius_buffer,
|
|
|
|
1, &radius_scatter, bb);
|
[vulkan] Implement shadow map culling
The rendering of the shadow maps now takes the culling information into
account resulting in a drastic reduction of work. There's still more
work to be done, but demo1 peaks at over 1000fps at 640x480, gmsp3v2 now
gets 14fps (1920x1080) near the front gate (used to be 3, then 6),
ad_tears is up to 3fps, but marcher is still unhappy, but it has
infinite radius lights, so needs more culling work (clipped light
volumes will help, I think). Also, culling lights for which nothing has
moved within their volumes will help somewhat (though not as much for
most id maps, I suspect).
2023-12-17 07:03:41 +00:00
|
|
|
QFV_PacketScatterBuffer (packet, lframe->shadowmat_id_buffer,
|
|
|
|
1, &matrix_id_scater, bb);
|
|
|
|
|
2023-12-17 01:45:59 +00:00
|
|
|
QFV_PacketSubmit (packet);
|
[vulkan] Implement shadow map culling
The rendering of the shadow maps now takes the culling information into
account resulting in a drastic reduction of work. There's still more
work to be done, but demo1 peaks at over 1000fps at 640x480, gmsp3v2 now
gets 14fps (1920x1080) near the front gate (used to be 3, then 6),
ad_tears is up to 3fps, but marcher is still unhappy, but it has
infinite radius lights, so needs more culling work (clipped light
volumes will help, I think). Also, culling lights for which nothing has
moved within their volumes will help somewhat (though not as much for
most id maps, I suspect).
2023-12-17 07:03:41 +00:00
|
|
|
transition_shadow_targets (lframe, ctx);
|
|
|
|
|
2023-12-17 01:45:59 +00:00
|
|
|
if (developer & SYS_lighting) {
|
|
|
|
Vulkan_Draw_String (vid.width - 32, 16,
|
|
|
|
va (ctx->va_ctx, "%3d", light_count),
|
|
|
|
ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-15 14:56:41 +00:00
|
|
|
static void
|
|
|
|
lighting_cull_lights (const exprval_t **params, exprval_t *result,
|
|
|
|
exprctx_t *ectx)
|
|
|
|
{
|
|
|
|
auto taskctx = (qfv_taskctx_t *) ectx;
|
|
|
|
auto ctx = taskctx->ctx;
|
|
|
|
auto device = ctx->device;
|
|
|
|
auto dfunc = device->funcs;
|
|
|
|
auto lctx = ctx->lighting_context;
|
|
|
|
|
|
|
|
auto lframe = &lctx->frames.a[ctx->curFrame];
|
|
|
|
auto queue = lframe->light_queue;
|
|
|
|
uint32_t count = queue[ST_CUBE].count + queue[ST_PLANE].count;
|
|
|
|
if (!count) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto light_cull = QFV_GetStep (params[0], ctx->render_context->job);
|
|
|
|
auto render = light_cull->render;
|
|
|
|
|
|
|
|
auto cmd = QFV_GetCmdBuffer (ctx, false);
|
|
|
|
dfunc->vkBeginCommandBuffer (cmd, &(VkCommandBufferBeginInfo) {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
|
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
|
|
|
});
|
2023-12-16 05:00:01 +00:00
|
|
|
qftCVkCollect (lframe->qftVkCtx, cmd);
|
|
|
|
dfunc->vkCmdResetQueryPool (cmd, lframe->query, 0, MaxLights);
|
|
|
|
auto qftVkCtx = taskctx->frame->qftVkCtx;
|
|
|
|
taskctx->frame->qftVkCtx = lframe->qftVkCtx;
|
2023-12-15 14:56:41 +00:00
|
|
|
auto renderpass = &render->renderpasses[0];
|
|
|
|
QFV_RunRenderPassCmd (cmd, ctx, renderpass, 0);
|
2023-12-16 05:00:01 +00:00
|
|
|
taskctx->frame->qftVkCtx = qftVkCtx;
|
2023-12-15 14:56:41 +00:00
|
|
|
dfunc->vkEndCommandBuffer (cmd);
|
|
|
|
|
|
|
|
qfMessageL ("submit");
|
|
|
|
auto dev_queue = &device->queue;
|
|
|
|
VkSubmitInfo submitInfo = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
|
|
.commandBufferCount = 1,
|
|
|
|
.pCommandBuffers = &cmd,
|
|
|
|
};
|
|
|
|
dfunc->vkResetFences (device->dev, 1, &lframe->fence);
|
|
|
|
dfunc->vkQueueSubmit (dev_queue->queue, 1, &submitInfo, lframe->fence);
|
|
|
|
dfunc->vkWaitForFences (device->dev, 1, &lframe->fence, VK_TRUE, 200000000);
|
|
|
|
|
|
|
|
uint32_t frag_counts[count];
|
|
|
|
VkDeviceSize size = sizeof (frag_counts);
|
|
|
|
dfunc->vkGetQueryPoolResults (device->dev, lframe->query, 0, count,
|
|
|
|
size, frag_counts, sizeof (uint32_t),
|
|
|
|
VK_QUERY_RESULT_WAIT_BIT);
|
|
|
|
uint32_t c = 0;
|
2023-12-17 01:45:59 +00:00
|
|
|
uint32_t ci = 0;
|
|
|
|
vec4f_t cam = r_refdef.camera[3];
|
|
|
|
uint32_t id = 0;
|
|
|
|
if (lframe->light_queue[ST_CUBE].count) {
|
|
|
|
auto q = lframe->light_queue[ST_CUBE];
|
|
|
|
for (uint32_t i = 0; i < q.count; i++) {
|
|
|
|
uint32_t fc = frag_counts[id++];
|
|
|
|
c += fc != 0;
|
|
|
|
if (!fc) {
|
|
|
|
uint32_t hull = q.start + i;
|
|
|
|
vec4f_t dist = cam - lframe->positions[hull];
|
|
|
|
dist[3] = 0;
|
|
|
|
float rad = lframe->id_radius[hull].radius;
|
|
|
|
constexpr float s = 1.5835921350012616f;
|
|
|
|
bool inside = dotf(dist, dist)[0] < rad * rad * s;
|
|
|
|
ci += inside;
|
|
|
|
if (!inside) {
|
|
|
|
lframe->id_radius[hull].id = ~0u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lframe->light_queue[ST_PLANE].count) {
|
|
|
|
auto q = lframe->light_queue[ST_PLANE];
|
|
|
|
for (uint32_t i = 0; i < q.count; i++) {
|
|
|
|
uint32_t fc = frag_counts[id++];
|
|
|
|
c += fc != 0;
|
|
|
|
if (!fc) {
|
|
|
|
uint32_t hull = q.start + i;
|
|
|
|
vec4f_t dist = cam - lframe->positions[hull];
|
|
|
|
dist[3] = 0;
|
|
|
|
float rad = lframe->id_radius[hull].radius;
|
|
|
|
bool inside = dotf(dist, dist)[0] < rad * rad;
|
|
|
|
ci += inside;
|
|
|
|
if (!inside) {
|
|
|
|
lframe->id_radius[hull].id = ~0u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-12-15 14:56:41 +00:00
|
|
|
}
|
2023-12-17 01:45:59 +00:00
|
|
|
lighting_rewrite_ids (lframe, ctx);
|
2023-12-15 14:56:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
draw_hull (uint32_t indexCount, uint32_t firstIndex, int32_t vertOffset,
|
|
|
|
uint32_t hull, uint32_t id, VkCommandBuffer cmd, VkQueryPool query,
|
|
|
|
qfv_devfuncs_t *dfunc, qftVkCtx_t *vk)
|
|
|
|
{
|
|
|
|
qfZoneNamed (zone, true);
|
[vulkan] Implement shadow map culling
The rendering of the shadow maps now takes the culling information into
account resulting in a drastic reduction of work. There's still more
work to be done, but demo1 peaks at over 1000fps at 640x480, gmsp3v2 now
gets 14fps (1920x1080) near the front gate (used to be 3, then 6),
ad_tears is up to 3fps, but marcher is still unhappy, but it has
infinite radius lights, so needs more culling work (clipped light
volumes will help, I think). Also, culling lights for which nothing has
moved within their volumes will help somewhat (though not as much for
most id maps, I suspect).
2023-12-17 07:03:41 +00:00
|
|
|
// qftVkScopedZoneC (vk, cmd, "draw_hull", 0xc0a000);
|
2023-12-15 14:56:41 +00:00
|
|
|
dfunc->vkCmdBeginQuery (cmd, query, id, 0);
|
|
|
|
dfunc->vkCmdDrawIndexed (cmd, indexCount, 1, firstIndex, vertOffset, hull);
|
|
|
|
dfunc->vkCmdEndQuery (cmd, query, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lighting_draw_hulls (const exprval_t **params, exprval_t *result,
|
|
|
|
exprctx_t *ectx)
|
|
|
|
{
|
|
|
|
qfZoneNamed (zone, true);
|
|
|
|
auto taskctx = (qfv_taskctx_t *) ectx;
|
|
|
|
auto ctx = taskctx->ctx;
|
|
|
|
auto device = ctx->device;
|
|
|
|
auto dfunc = device->funcs;
|
|
|
|
auto lctx = ctx->lighting_context;
|
|
|
|
auto cmd = taskctx->cmd;
|
|
|
|
|
|
|
|
auto lframe = &lctx->frames.a[ctx->curFrame];
|
|
|
|
uint32_t id = 0;
|
|
|
|
if (lframe->light_queue[ST_CUBE].count) {
|
|
|
|
auto q = lframe->light_queue[ST_CUBE];
|
|
|
|
for (uint32_t i = 0; i < q.count; i++) {
|
|
|
|
uint32_t hull = q.start + i;
|
|
|
|
draw_hull (num_ico_inds, 0, 0, hull, id++,
|
|
|
|
cmd, lframe->query, dfunc, taskctx->frame->qftVkCtx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lframe->light_queue[ST_PLANE].count) {
|
|
|
|
auto q = lframe->light_queue[ST_PLANE];
|
|
|
|
for (uint32_t i = 0; i < q.count; i++) {
|
|
|
|
uint32_t hull = q.start + i;
|
|
|
|
draw_hull (num_cone_inds, num_ico_inds, 12, hull, id++,
|
|
|
|
cmd, lframe->query, dfunc, taskctx->frame->qftVkCtx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-28 04:19:10 +00:00
|
|
|
static void
|
|
|
|
lighting_draw_lights (const exprval_t **params, exprval_t *result,
|
|
|
|
exprctx_t *ectx)
|
|
|
|
{
|
2023-11-28 06:54:55 +00:00
|
|
|
qfZoneNamed (zone, true);
|
2023-06-28 04:19:10 +00:00
|
|
|
auto taskctx = (qfv_taskctx_t *) ectx;
|
|
|
|
auto ctx = taskctx->ctx;
|
|
|
|
auto device = ctx->device;
|
|
|
|
auto dfunc = device->funcs;
|
|
|
|
auto lctx = ctx->lighting_context;
|
2023-08-02 08:52:57 +00:00
|
|
|
auto layout = taskctx->pipeline->layout;
|
2023-06-28 04:19:10 +00:00
|
|
|
auto cmd = taskctx->cmd;
|
|
|
|
|
|
|
|
auto lframe = &lctx->frames.a[ctx->curFrame];
|
2023-08-02 08:52:57 +00:00
|
|
|
auto shadow_type = *(int *) params[0]->value;
|
|
|
|
auto queue = lframe->light_queue[shadow_type];
|
|
|
|
|
|
|
|
if (!queue.count) {
|
2023-06-28 04:19:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-13 17:33:19 +00:00
|
|
|
//FIXME dup of z_range (sort of)
|
|
|
|
vec4f_t depths = {
|
|
|
|
r_nearclip / 32, r_nearclip / 256, r_nearclip / 1024, 0,
|
|
|
|
};
|
2023-08-02 08:52:57 +00:00
|
|
|
qfv_push_constants_t push_constants[] = {
|
2023-08-13 17:33:19 +00:00
|
|
|
{ VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof (depths), &depths },
|
|
|
|
{ VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(depths), sizeof(queue), &queue },
|
2023-08-02 08:52:57 +00:00
|
|
|
};
|
2023-08-13 17:33:19 +00:00
|
|
|
QFV_PushConstants (device, cmd, layout, 2, push_constants);
|
2023-08-02 08:52:57 +00:00
|
|
|
|
2023-06-28 04:19:10 +00:00
|
|
|
dfunc->vkCmdDraw (cmd, 3, 1, 0, 0);
|
|
|
|
}
|
|
|
|
|
2023-08-05 15:20:25 +00:00
|
|
|
static exprenum_t lighting_stage_enum;
|
|
|
|
static exprtype_t lighting_stage_type = {
|
|
|
|
.name = "lighting_stage",
|
|
|
|
.size = sizeof (int),
|
|
|
|
.get_string = cexpr_enum_get_string,
|
|
|
|
.data = &lighting_stage_enum,
|
|
|
|
};
|
|
|
|
static int lighting_stage_values[] = {
|
|
|
|
lighting_main,
|
|
|
|
lighting_shadow,
|
2023-12-16 05:00:01 +00:00
|
|
|
lighting_hull,
|
2023-08-05 15:20:25 +00:00
|
|
|
};
|
|
|
|
static exprsym_t lighting_stage_symbols[] = {
|
|
|
|
{"main", &lighting_stage_type, lighting_stage_values + 0},
|
|
|
|
{"shadow", &lighting_stage_type, lighting_stage_values + 1},
|
2023-12-16 05:00:01 +00:00
|
|
|
{"hull", &lighting_stage_type, lighting_stage_values + 2},
|
2023-08-05 15:20:25 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
static exprtab_t lighting_stage_symtab = { .symbols = lighting_stage_symbols };
|
|
|
|
static exprenum_t lighting_stage_enum = {
|
|
|
|
&lighting_stage_type,
|
|
|
|
&lighting_stage_symtab,
|
|
|
|
};
|
|
|
|
|
2023-08-01 14:34:08 +00:00
|
|
|
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,
|
2023-08-05 15:20:25 +00:00
|
|
|
&lighting_stage_type,
|
2023-08-01 14:34:08 +00:00
|
|
|
};
|
|
|
|
|
2023-07-27 07:09:33 +00:00
|
|
|
static exprtype_t *stepref_param[] = {
|
|
|
|
&cexpr_string,
|
|
|
|
};
|
|
|
|
|
2023-06-27 16:01:56 +00:00
|
|
|
static exprfunc_t lighting_update_lights_func[] = {
|
|
|
|
{ .func = lighting_update_lights },
|
|
|
|
{}
|
|
|
|
};
|
2023-06-28 02:47:26 +00:00
|
|
|
static exprfunc_t lighting_update_descriptors_func[] = {
|
2023-08-01 14:34:08 +00:00
|
|
|
{ .func = lighting_update_descriptors, .num_params = 1,
|
|
|
|
.param_types = stepref_param },
|
2023-06-28 02:47:26 +00:00
|
|
|
{}
|
|
|
|
};
|
2023-06-27 16:01:56 +00:00
|
|
|
static exprfunc_t lighting_bind_descriptors_func[] = {
|
2023-08-05 15:20:25 +00:00
|
|
|
{ .func = lighting_bind_descriptors, .num_params = 2,
|
2023-08-01 14:34:08 +00:00
|
|
|
.param_types = shadow_type_param },
|
2023-06-27 16:01:56 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
static exprfunc_t lighting_draw_splats_func[] = {
|
|
|
|
{ .func = lighting_draw_splats },
|
|
|
|
{}
|
|
|
|
};
|
2023-12-15 14:56:41 +00:00
|
|
|
static exprfunc_t lighting_cull_lights_func[] = {
|
|
|
|
{ .func = lighting_cull_lights, .num_params = 1,
|
|
|
|
.param_types = stepref_param },
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
static exprfunc_t lighting_draw_hulls_func[] = {
|
|
|
|
{ .func = lighting_draw_hulls },
|
|
|
|
{}
|
|
|
|
};
|
2023-06-28 04:19:10 +00:00
|
|
|
static exprfunc_t lighting_draw_lights_func[] = {
|
2023-08-05 15:20:25 +00:00
|
|
|
{ .func = lighting_draw_lights, .num_params = 2,
|
2023-08-01 14:34:08 +00:00
|
|
|
.param_types = shadow_type_param },
|
2023-06-28 04:19:10 +00:00
|
|
|
{}
|
|
|
|
};
|
2023-08-08 09:04:58 +00:00
|
|
|
static exprfunc_t lighting_setup_shadow_func[] = {
|
|
|
|
{ .func = lighting_setup_shadow },
|
2023-07-27 07:09:33 +00:00
|
|
|
{}
|
|
|
|
};
|
2023-07-24 01:23:05 +00:00
|
|
|
static exprfunc_t lighting_draw_shadow_maps_func[] = {
|
2023-07-27 07:09:33 +00:00
|
|
|
{ .func = lighting_draw_shadow_maps, .num_params = 1,
|
|
|
|
.param_types = stepref_param },
|
2023-07-24 01:23:05 +00:00
|
|
|
{}
|
|
|
|
};
|
2023-02-13 15:55:22 +00:00
|
|
|
static exprsym_t lighting_task_syms[] = {
|
2023-06-27 16:01:56 +00:00
|
|
|
{ "lighting_update_lights", &cexpr_function, lighting_update_lights_func },
|
2023-06-28 02:47:26 +00:00
|
|
|
{ "lighting_update_descriptors", &cexpr_function,
|
|
|
|
lighting_update_descriptors_func },
|
2023-06-27 16:01:56 +00:00
|
|
|
{ "lighting_bind_descriptors", &cexpr_function,
|
|
|
|
lighting_bind_descriptors_func },
|
|
|
|
{ "lighting_draw_splats", &cexpr_function, lighting_draw_splats_func },
|
2023-12-15 14:56:41 +00:00
|
|
|
{ "lighting_cull_lights", &cexpr_function, lighting_cull_lights_func },
|
|
|
|
{ "lighting_draw_hulls", &cexpr_function, lighting_draw_hulls_func },
|
2023-06-28 04:19:10 +00:00
|
|
|
{ "lighting_draw_lights", &cexpr_function, lighting_draw_lights_func },
|
2023-08-08 09:04:58 +00:00
|
|
|
{ "lighting_setup_shadow", &cexpr_function, lighting_setup_shadow_func },
|
2023-07-24 01:23:05 +00:00
|
|
|
{ "lighting_draw_shadow_maps", &cexpr_function,
|
|
|
|
lighting_draw_shadow_maps_func },
|
2023-02-13 15:55:22 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2023-12-14 03:43:37 +00:00
|
|
|
static int
|
|
|
|
round_light_size (int size)
|
|
|
|
{
|
|
|
|
size = ((size + shadow_quanta - 1) / shadow_quanta) * shadow_quanta;
|
|
|
|
return min (size, 1024);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dynlight_size_listener (void *data, const cvar_t *cvar)
|
|
|
|
{
|
|
|
|
dynlight_size = round_light_size (dynlight_size);
|
|
|
|
}
|
|
|
|
|
2021-02-24 10:58:31 +00:00
|
|
|
void
|
|
|
|
Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
|
|
|
|
{
|
2023-06-24 01:34:18 +00:00
|
|
|
lightingctx_t *lctx = calloc (1, sizeof (lightingctx_t));
|
|
|
|
ctx->lighting_context = lctx;
|
|
|
|
|
2023-12-14 03:43:37 +00:00
|
|
|
Cvar_Register (&dynlight_size_cvar, dynlight_size_listener, 0);
|
2023-08-04 06:44:07 +00:00
|
|
|
|
2023-02-13 15:55:22 +00:00
|
|
|
QFV_Render_AddTasks (ctx, lighting_task_syms);
|
2023-07-24 01:23:05 +00:00
|
|
|
|
|
|
|
lctx->shadow_info = (qfv_attachmentinfo_t) {
|
|
|
|
.name = "$shadow",
|
|
|
|
.format = VK_FORMAT_X8_D24_UNORM_PACK32,
|
|
|
|
.samples = 1,
|
|
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
|
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
|
|
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
2023-12-14 12:40:41 +00:00
|
|
|
.finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,//FIXME plist
|
2023-07-24 01:23:05 +00:00
|
|
|
};
|
|
|
|
qfv_attachmentinfo_t *attachments[] = {
|
|
|
|
&lctx->shadow_info,
|
|
|
|
};
|
|
|
|
QFV_Render_AddAttachments (ctx, 1, attachments);
|
2023-06-24 12:42:46 +00:00
|
|
|
}
|
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-06-27 16:01:56 +00:00
|
|
|
static void
|
|
|
|
make_ico (qfv_packet_t *packet)
|
|
|
|
{
|
|
|
|
vec3_t *verts = QFV_PacketExtend (packet, sizeof (vec3_t[ico_verts]));
|
|
|
|
float p = (sqrt(5) + 1) / 2;
|
|
|
|
float a = sqrt (3) / p;
|
|
|
|
float b = a / p;
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
for (int j = 0; j < 4; j++) {
|
|
|
|
float my = j & 1 ? a : -a;
|
|
|
|
float mz = j & 2 ? b : -b;
|
|
|
|
int vind = i * 4 + j;
|
|
|
|
int ix = i;
|
|
|
|
int iy = (i + 1) % 3;
|
|
|
|
int iz = (i + 2) % 3;
|
|
|
|
verts[vind][ix] = 0;
|
|
|
|
verts[vind][iy] = my;
|
|
|
|
verts[vind][iz] = mz;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
make_cone (qfv_packet_t *packet)
|
|
|
|
{
|
|
|
|
vec3_t *verts = QFV_PacketExtend (packet, sizeof (vec3_t[cone_verts]));
|
|
|
|
float a = 2 / sqrt (3);
|
|
|
|
float b = 1 / sqrt (3);
|
|
|
|
VectorSet ( 0, 0, 0, verts[0]);
|
|
|
|
VectorSet ( a, 0, -1, verts[1]);
|
|
|
|
VectorSet ( b, 1, -1, verts[2]);
|
|
|
|
VectorSet (-b, 1, -1, verts[3]);
|
|
|
|
VectorSet (-a, 0, -1, verts[4]);
|
|
|
|
VectorSet (-b, -1, -1, verts[5]);
|
|
|
|
VectorSet ( b, -1, -1, verts[6]);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
write_inds (qfv_packet_t *packet)
|
|
|
|
{
|
|
|
|
uint32_t *inds = QFV_PacketExtend (packet, sizeof (ico_inds)
|
|
|
|
+ sizeof (cone_inds));
|
|
|
|
memcpy (inds, ico_inds, sizeof (ico_inds));
|
|
|
|
inds += num_ico_inds;
|
|
|
|
memcpy (inds, cone_inds, sizeof (cone_inds));
|
|
|
|
}
|
|
|
|
|
2023-06-24 12:42:46 +00:00
|
|
|
void
|
|
|
|
Vulkan_Lighting_Setup (vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
qfvPushDebug (ctx, "lighting init");
|
2021-12-02 13:48:50 +00:00
|
|
|
|
2023-06-24 12:42:46 +00:00
|
|
|
auto device = ctx->device;
|
2023-07-30 02:28:42 +00:00
|
|
|
auto dfunc = device->funcs;
|
2023-06-24 12:42:46 +00:00
|
|
|
auto lctx = ctx->lighting_context;
|
2022-05-31 03:43:04 +00:00
|
|
|
|
2023-06-25 14:33:47 +00:00
|
|
|
lctx->sampler = QFV_Render_Sampler (ctx, "shadow_sampler");
|
|
|
|
|
2022-11-24 14:44:07 +00:00
|
|
|
Vulkan_Script_SetOutput (ctx,
|
|
|
|
&(qfv_output_t) { .format = VK_FORMAT_X8_D24_UNORM_PACK32 });
|
2021-02-24 10:58:31 +00:00
|
|
|
|
2022-05-31 03:43:04 +00:00
|
|
|
DARRAY_INIT (&lctx->light_mats, 16);
|
2023-08-01 14:34:08 +00:00
|
|
|
DARRAY_INIT (&lctx->light_control, 16);
|
2021-03-03 09:14:16 +00:00
|
|
|
|
2023-06-22 07:44:05 +00:00
|
|
|
auto rctx = ctx->render_context;
|
|
|
|
size_t frames = rctx->frames.size;
|
2021-02-24 10:58:31 +00:00
|
|
|
DARRAY_INIT (&lctx->frames, frames);
|
|
|
|
DARRAY_RESIZE (&lctx->frames, frames);
|
|
|
|
lctx->frames.grow = 0;
|
|
|
|
|
2023-06-27 16:01:56 +00:00
|
|
|
lctx->light_resources = malloc (sizeof (qfv_resource_t)
|
|
|
|
// splat vertices
|
|
|
|
+ sizeof (qfv_resobj_t)
|
|
|
|
// splat indices
|
|
|
|
+ sizeof (qfv_resobj_t)
|
2023-08-02 08:52:57 +00:00
|
|
|
// default shadow map and views
|
|
|
|
+ 3 * sizeof (qfv_resobj_t)
|
2023-12-05 15:15:42 +00:00
|
|
|
// light matrices
|
2023-08-07 08:47:49 +00:00
|
|
|
+ sizeof (qfv_resobj_t[frames])
|
2023-12-14 01:01:27 +00:00
|
|
|
// light matrix ids
|
|
|
|
+ sizeof (qfv_resobj_t[frames])
|
2023-07-30 02:28:42 +00:00
|
|
|
// light ids
|
|
|
|
+ sizeof (qfv_resobj_t[frames])
|
2023-12-16 06:44:44 +00:00
|
|
|
// light radii
|
|
|
|
+ sizeof (qfv_resobj_t[frames])
|
2023-06-27 16:01:56 +00:00
|
|
|
// light data
|
|
|
|
+ sizeof (qfv_resobj_t[frames])
|
2023-08-01 14:34:08 +00:00
|
|
|
// light render
|
|
|
|
+ sizeof (qfv_resobj_t[frames])
|
|
|
|
// light styles
|
2023-07-30 02:28:42 +00:00
|
|
|
+ sizeof (qfv_resobj_t[frames])
|
2023-12-05 15:15:42 +00:00
|
|
|
// light entids
|
2023-06-27 16:01:56 +00:00
|
|
|
+ sizeof (qfv_resobj_t[frames]));
|
|
|
|
lctx->light_resources[0] = (qfv_resource_t) {
|
|
|
|
.name = "lights",
|
|
|
|
.va_ctx = ctx->va_ctx,
|
|
|
|
.memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
2023-12-16 06:44:44 +00:00
|
|
|
.num_objects = 2 + 3 + 8 * frames,
|
2023-08-02 08:52:57 +00:00
|
|
|
.objects = (qfv_resobj_t *) &lctx->light_resources[1],
|
2023-06-27 16:01:56 +00:00
|
|
|
};
|
2023-08-02 08:52:57 +00:00
|
|
|
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];
|
2023-12-05 15:15:42 +00:00
|
|
|
auto light_mats = &default_view_2d[1];
|
2023-12-14 01:01:27 +00:00
|
|
|
auto light_mat_ids = &light_mats[frames];
|
|
|
|
auto light_ids = &light_mat_ids[frames];
|
2023-12-16 06:44:44 +00:00
|
|
|
auto light_radii = &light_ids[frames];
|
|
|
|
auto light_data = &light_radii[frames];
|
2023-08-02 08:52:57 +00:00
|
|
|
auto light_render = &light_data[frames];
|
|
|
|
auto light_styles = &light_render[frames];
|
2023-12-05 15:15:42 +00:00
|
|
|
auto light_entids = &light_styles[frames];
|
2023-06-27 16:01:56 +00:00
|
|
|
splat_verts[0] = (qfv_resobj_t) {
|
|
|
|
.name = "splat:vertices",
|
|
|
|
.type = qfv_res_buffer,
|
|
|
|
.buffer = {
|
|
|
|
.size = (20 + 7) * sizeof (vec3_t),
|
|
|
|
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
|
|
|
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
splat_inds[0] = (qfv_resobj_t) {
|
|
|
|
.name = "splat:indices",
|
|
|
|
.type = qfv_res_buffer,
|
|
|
|
.buffer = {
|
|
|
|
.size = sizeof (ico_inds) + sizeof (cone_inds),
|
|
|
|
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
|
|
|
| VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
|
|
|
},
|
|
|
|
};
|
2023-08-02 08:52:57 +00:00
|
|
|
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,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
2021-02-25 06:51:54 +00:00
|
|
|
for (size_t i = 0; i < frames; i++) {
|
2023-08-07 08:47:49 +00:00
|
|
|
light_entids[i] = (qfv_resobj_t) {
|
|
|
|
.name = va (ctx->va_ctx, "entids:%zd", i),
|
|
|
|
.type = qfv_res_buffer,
|
|
|
|
.buffer = {
|
|
|
|
.size = MaxLights * sizeof (uint32_t),
|
|
|
|
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
|
|
|
|
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
|
|
|
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
|
|
},
|
|
|
|
};
|
2023-08-01 14:34:08 +00:00
|
|
|
light_ids[i] = (qfv_resobj_t) {
|
2023-08-04 06:44:07 +00:00
|
|
|
.name = va (ctx->va_ctx, "ids:%zd", i),
|
2023-08-01 14:34:08 +00:00
|
|
|
.type = qfv_res_buffer,
|
|
|
|
.buffer = {
|
2023-08-07 08:47:49 +00:00
|
|
|
.size = MaxLights * sizeof (uint32_t),
|
2023-08-01 14:34:08 +00:00
|
|
|
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
|
|
|
|
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
|
|
|
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
|
|
},
|
|
|
|
};
|
2023-12-16 06:44:44 +00:00
|
|
|
light_radii[i] = (qfv_resobj_t) {
|
|
|
|
.name = va (ctx->va_ctx, "radii:%zd", i),
|
|
|
|
.type = qfv_res_buffer,
|
|
|
|
.buffer = {
|
|
|
|
.size = MaxLights * sizeof (float),
|
|
|
|
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
|
|
|
|
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
|
|
},
|
|
|
|
};
|
2023-06-27 16:01:56 +00:00
|
|
|
light_data[i] = (qfv_resobj_t) {
|
2023-08-04 06:44:07 +00:00
|
|
|
.name = va (ctx->va_ctx, "lights:%zd", i),
|
2023-06-27 16:01:56 +00:00
|
|
|
.type = qfv_res_buffer,
|
|
|
|
.buffer = {
|
2023-08-01 14:34:08 +00:00
|
|
|
.size = sizeof (light_t[MaxLights]),
|
|
|
|
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
2023-06-27 16:01:56 +00:00
|
|
|
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
|
|
},
|
|
|
|
};
|
2023-08-01 14:34:08 +00:00
|
|
|
light_render[i] = (qfv_resobj_t) {
|
2023-08-04 06:44:07 +00:00
|
|
|
.name = va (ctx->va_ctx, "render:%zd", i),
|
2023-07-30 02:28:42 +00:00
|
|
|
.type = qfv_res_buffer,
|
|
|
|
.buffer = {
|
2023-08-01 14:34:08 +00:00
|
|
|
.size = sizeof (qfv_light_render_t[MaxLights]),
|
2023-07-30 02:28:42 +00:00
|
|
|
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
|
|
|
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
|
|
},
|
|
|
|
};
|
2023-08-01 14:34:08 +00:00
|
|
|
light_styles[i] = (qfv_resobj_t) {
|
2023-08-04 06:44:07 +00:00
|
|
|
.name = va (ctx->va_ctx, "styles:%zd", i),
|
2023-07-30 02:28:42 +00:00
|
|
|
.type = qfv_res_buffer,
|
|
|
|
.buffer = {
|
2023-08-01 14:34:08 +00:00
|
|
|
.size = sizeof (vec4f_t[NumStyles]),
|
2023-07-30 02:28:42 +00:00
|
|
|
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
|
|
|
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
|
|
},
|
|
|
|
};
|
2023-08-01 14:34:08 +00:00
|
|
|
light_mats[i] = (qfv_resobj_t) {
|
2023-08-04 06:44:07 +00:00
|
|
|
.name = va (ctx->va_ctx, "matrices:%zd", i),
|
2023-06-27 16:01:56 +00:00
|
|
|
.type = qfv_res_buffer,
|
|
|
|
.buffer = {
|
2023-08-01 14:34:08 +00:00
|
|
|
// never need more than 6 matrices per light
|
|
|
|
.size = sizeof (mat4f_t[MaxLights * 6]),
|
|
|
|
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
2023-06-27 16:01:56 +00:00
|
|
|
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
|
|
},
|
|
|
|
};
|
2023-12-14 01:01:27 +00:00
|
|
|
light_mat_ids[i] = (qfv_resobj_t) {
|
|
|
|
.name = va (ctx->va_ctx, "matrix ids:%zd", i),
|
|
|
|
.type = qfv_res_buffer,
|
|
|
|
.buffer = {
|
|
|
|
// never need more than 6 matrices per light
|
|
|
|
.size = sizeof (uint32_t[MaxLights * 6]),
|
|
|
|
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
|
|
|
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
|
|
},
|
|
|
|
};
|
2021-02-25 06:51:54 +00:00
|
|
|
}
|
|
|
|
|
2023-07-05 17:04:47 +00:00
|
|
|
QFV_CreateResource (device, lctx->light_resources);
|
2023-06-27 16:01:56 +00:00
|
|
|
|
|
|
|
lctx->splat_verts = splat_verts[0].buffer.buffer;
|
|
|
|
lctx->splat_inds = splat_inds[0].buffer.buffer;
|
2023-08-02 08:52:57 +00:00
|
|
|
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;
|
2021-02-25 06:51:54 +00:00
|
|
|
|
2023-08-01 14:34:08 +00:00
|
|
|
auto shadow_mgr = QFV_Render_DSManager (ctx, "lighting_shadow");
|
2023-08-02 08:52:57 +00:00
|
|
|
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_cube_set, "lighting:shadow_cube_set");
|
2023-08-01 14:34:08 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET,
|
2023-08-02 08:52:57 +00:00
|
|
|
lctx->shadow_2d_set, "lighting:shadow_2d_set");
|
2023-08-01 14:34:08 +00:00
|
|
|
lctx->shadow_sampler = QFV_Render_Sampler (ctx, "shadow_sampler");
|
|
|
|
|
2023-06-24 12:42:46 +00:00
|
|
|
auto attach_mgr = QFV_Render_DSManager (ctx, "lighting_attach");
|
|
|
|
auto lights_mgr = QFV_Render_DSManager (ctx, "lighting_lights");
|
2023-07-30 02:28:42 +00:00
|
|
|
auto shadowmat_mgr = QFV_Render_DSManager (ctx, "shadowmat_set");
|
2021-02-24 10:58:31 +00:00
|
|
|
for (size_t i = 0; i < frames; i++) {
|
2023-06-27 16:01:56 +00:00
|
|
|
auto lframe = &lctx->frames.a[i];
|
|
|
|
*lframe = (lightingframe_t) {
|
2023-07-30 02:28:42 +00:00
|
|
|
.shadowmat_set = QFV_DSManager_AllocSet (shadowmat_mgr),
|
|
|
|
.lights_set = QFV_DSManager_AllocSet (lights_mgr),
|
|
|
|
.attach_set = QFV_DSManager_AllocSet (attach_mgr),
|
|
|
|
.shadowmat_buffer = light_mats[i].buffer.buffer,
|
2023-12-14 01:01:27 +00:00
|
|
|
.shadowmat_id_buffer = light_mat_ids[i].buffer.buffer,
|
2023-07-30 02:28:42 +00:00
|
|
|
.light_buffer = light_data[i].buffer.buffer,
|
2023-08-01 14:34:08 +00:00
|
|
|
.render_buffer = light_render[i].buffer.buffer,
|
|
|
|
.style_buffer = light_styles[i].buffer.buffer,
|
2023-06-27 16:01:56 +00:00
|
|
|
.id_buffer = light_ids[i].buffer.buffer,
|
2023-12-16 06:44:44 +00:00
|
|
|
.radius_buffer = light_radii[i].buffer.buffer,
|
2023-08-07 08:47:49 +00:00
|
|
|
.entid_buffer = light_entids[i].buffer.buffer,
|
2023-06-27 16:01:56 +00:00
|
|
|
};
|
2021-02-24 10:58:31 +00:00
|
|
|
|
2023-07-30 02:28:42 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET,
|
|
|
|
lframe->attach_set,
|
2021-04-24 01:40:39 +00:00
|
|
|
va (ctx->va_ctx, "lighting:attach_set:%zd", i));
|
2023-07-30 02:28:42 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET,
|
|
|
|
lframe->lights_set,
|
2021-04-24 01:40:39 +00:00
|
|
|
va (ctx->va_ctx, "lighting:lights_set:%zd", i));
|
2023-07-30 02:28:42 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET,
|
|
|
|
lframe->shadowmat_set,
|
|
|
|
va (ctx->va_ctx, "lighting:shadowmat_set:%zd", i));
|
2023-07-28 16:17:53 +00:00
|
|
|
|
2023-07-30 02:28:42 +00:00
|
|
|
VkDescriptorBufferInfo bufferInfo[] = {
|
2023-08-01 14:34:08 +00:00
|
|
|
{ .buffer = lframe->shadowmat_buffer,
|
|
|
|
.offset = 0, .range = VK_WHOLE_SIZE, },
|
2023-12-14 01:01:27 +00:00
|
|
|
{ .buffer = lframe->shadowmat_id_buffer,
|
|
|
|
.offset = 0, .range = VK_WHOLE_SIZE, },
|
2023-08-01 14:34:08 +00:00
|
|
|
{ .buffer = lframe->id_buffer,
|
|
|
|
.offset = 0, .range = VK_WHOLE_SIZE, },
|
2023-07-30 02:28:42 +00:00
|
|
|
{ .buffer = lframe->light_buffer,
|
|
|
|
.offset = 0, .range = VK_WHOLE_SIZE, },
|
2023-08-01 14:34:08 +00:00
|
|
|
{ .buffer = lframe->render_buffer,
|
|
|
|
.offset = 0, .range = VK_WHOLE_SIZE, },
|
|
|
|
{ .buffer = lframe->style_buffer,
|
2023-07-30 02:28:42 +00:00
|
|
|
.offset = 0, .range = VK_WHOLE_SIZE, },
|
2023-08-07 08:47:49 +00:00
|
|
|
{ .buffer = lframe->entid_buffer,
|
|
|
|
.offset = 0, .range = VK_WHOLE_SIZE, },
|
2023-07-30 02:28:42 +00:00
|
|
|
};
|
|
|
|
VkWriteDescriptorSet bufferWrite[] = {
|
|
|
|
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
2023-08-01 14:34:08 +00:00
|
|
|
.dstSet = lframe->shadowmat_set,
|
2023-07-30 02:28:42 +00:00
|
|
|
.dstBinding = 0,
|
|
|
|
.descriptorCount = 1,
|
2023-08-01 14:34:08 +00:00
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
2023-07-30 02:28:42 +00:00
|
|
|
.pBufferInfo = &bufferInfo[0], },
|
2023-12-14 01:01:27 +00:00
|
|
|
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstSet = lframe->shadowmat_set,
|
|
|
|
.dstBinding = 1,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
|
|
.pBufferInfo = &bufferInfo[1], },
|
2023-08-01 14:34:08 +00:00
|
|
|
|
2023-07-30 02:28:42 +00:00
|
|
|
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
2023-08-01 14:34:08 +00:00
|
|
|
.dstSet = lframe->lights_set,
|
2023-07-30 02:28:42 +00:00
|
|
|
.dstBinding = 0,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
2023-12-14 01:01:27 +00:00
|
|
|
.pBufferInfo = &bufferInfo[2], },
|
2023-08-01 14:34:08 +00:00
|
|
|
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstSet = lframe->lights_set,
|
|
|
|
.dstBinding = 1,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
2023-12-14 01:01:27 +00:00
|
|
|
.pBufferInfo = &bufferInfo[3], },
|
2023-08-01 14:34:08 +00:00
|
|
|
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstSet = lframe->lights_set,
|
|
|
|
.dstBinding = 2,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
2023-12-14 01:01:27 +00:00
|
|
|
.pBufferInfo = &bufferInfo[4], },
|
2023-08-01 14:34:08 +00:00
|
|
|
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstSet = lframe->lights_set,
|
|
|
|
.dstBinding = 3,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
2023-12-14 01:01:27 +00:00
|
|
|
.pBufferInfo = &bufferInfo[5], },
|
2023-08-07 08:47:49 +00:00
|
|
|
{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstSet = lframe->lights_set,
|
|
|
|
.dstBinding = 4,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
2023-12-14 01:01:27 +00:00
|
|
|
.pBufferInfo = &bufferInfo[6], },
|
2023-07-30 02:28:42 +00:00
|
|
|
};
|
2023-12-14 01:01:27 +00:00
|
|
|
dfunc->vkUpdateDescriptorSets (device->dev, 7, bufferWrite, 0, 0);
|
2023-12-15 14:56:41 +00:00
|
|
|
|
|
|
|
dfunc->vkCreateQueryPool (device->dev, &(VkQueryPoolCreateInfo) {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
|
|
|
|
.queryType = VK_QUERY_TYPE_OCCLUSION,
|
|
|
|
.queryCount = MaxLights,
|
|
|
|
}, 0, &lframe->query);
|
|
|
|
lframe->fence = QFV_CreateFence (device, 1);
|
2023-12-16 05:00:01 +00:00
|
|
|
#ifdef TRACY_ENABLE
|
|
|
|
auto instance = ctx->instance->instance;
|
|
|
|
auto physdev = ctx->device->physDev->dev;
|
|
|
|
auto gipa = ctx->vkGetInstanceProcAddr;
|
|
|
|
auto gdpa = ctx->instance->funcs->vkGetDeviceProcAddr;
|
|
|
|
lframe->qftVkCtx = qftCVkContextHostCalibrated (instance, physdev,
|
|
|
|
device->dev,
|
|
|
|
gipa, gdpa);
|
|
|
|
#endif
|
2021-02-24 10:58:31 +00:00
|
|
|
}
|
2023-12-14 12:40:41 +00:00
|
|
|
size_t target_count = MaxLights * 6;
|
|
|
|
size_t target_size = frames * sizeof (uint16_t[target_count]);
|
2023-12-17 01:45:59 +00:00
|
|
|
size_t idr_size = frames * sizeof (light_idrad_t[MaxLights]);
|
|
|
|
size_t position_size = frames * sizeof (vec4f_t[MaxLights]);
|
2023-12-14 12:40:41 +00:00
|
|
|
lctx->frames.a[0].stage_targets = malloc (target_size);
|
2023-12-17 01:45:59 +00:00
|
|
|
lctx->frames.a[0].id_radius = malloc (idr_size);
|
|
|
|
lctx->frames.a[0].positions = malloc (position_size);
|
2023-12-14 12:40:41 +00:00
|
|
|
for (size_t i = 1; i < frames; i++) {
|
|
|
|
auto lframe = &lctx->frames.a[i];
|
|
|
|
lframe[0].stage_targets = lframe[-1].stage_targets + target_count;
|
2023-12-17 01:45:59 +00:00
|
|
|
lframe[0].id_radius = lframe[-1].id_radius + MaxLights;
|
|
|
|
lframe[0].positions = lframe[-1].positions + MaxLights;
|
2023-12-14 12:40:41 +00:00
|
|
|
}
|
2023-06-27 16:01:56 +00:00
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
make_default_map (64, lctx->default_map, ctx);
|
|
|
|
|
2023-06-27 16:01:56 +00:00
|
|
|
auto packet = QFV_PacketAcquire (ctx->staging);
|
|
|
|
make_ico (packet);
|
|
|
|
make_cone (packet);
|
|
|
|
QFV_PacketCopyBuffer (packet, splat_verts[0].buffer.buffer, 0,
|
|
|
|
&bufferBarriers[qfv_BB_TransferWrite_to_UniformRead]);
|
|
|
|
QFV_PacketSubmit (packet);
|
|
|
|
packet = QFV_PacketAcquire (ctx->staging);
|
|
|
|
write_inds (packet);
|
|
|
|
QFV_PacketCopyBuffer (packet, splat_inds[0].buffer.buffer, 0,
|
|
|
|
&bufferBarriers[qfv_BB_TransferWrite_to_IndexRead]);
|
|
|
|
QFV_PacketSubmit (packet);
|
|
|
|
|
2021-12-02 13:48:50 +00:00
|
|
|
qfvPopDebug (ctx);
|
2021-02-24 10:58:31 +00:00
|
|
|
}
|
|
|
|
|
2021-04-29 11:54:38 +00:00
|
|
|
static void
|
|
|
|
clear_shadows (vulkan_ctx_t *ctx)
|
|
|
|
{
|
2023-12-04 12:38:43 +00:00
|
|
|
qfZoneScoped (true);
|
2021-04-29 11:54:38 +00:00
|
|
|
qfv_device_t *device = ctx->device;
|
2023-12-14 12:40:41 +00:00
|
|
|
auto dfunc = device->funcs;
|
2021-04-29 11:54:38 +00:00
|
|
|
lightingctx_t *lctx = ctx->lighting_context;
|
|
|
|
|
2022-10-27 02:02:45 +00:00
|
|
|
if (lctx->shadow_resources) {
|
|
|
|
QFV_DestroyResource (device, lctx->shadow_resources);
|
2022-10-27 02:23:49 +00:00
|
|
|
free (lctx->shadow_resources);
|
2022-10-27 02:02:45 +00:00
|
|
|
lctx->shadow_resources = 0;
|
2021-04-29 11:54:38 +00:00
|
|
|
}
|
2023-12-14 12:40:41 +00:00
|
|
|
for (int i = 0; i < LIGHTING_STAGES; i++) {
|
|
|
|
for (int j = 0; j < 32; j++) {
|
|
|
|
auto framebuffer = lctx->stage_framebuffers[j][i];
|
|
|
|
if (framebuffer) {
|
|
|
|
dfunc->vkDestroyFramebuffer (device->dev, framebuffer, 0);
|
|
|
|
}
|
|
|
|
lctx->stage_framebuffers[j][i] = 0;
|
|
|
|
}
|
|
|
|
// images and views freed via shadow_resources
|
|
|
|
lctx->stage_images[i] = 0;
|
|
|
|
lctx->stage_views[i] = 0;
|
|
|
|
}
|
2023-08-02 08:52:57 +00:00
|
|
|
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;
|
2023-08-01 14:34:08 +00:00
|
|
|
lctx->light_control.size = 0;
|
2021-04-29 11:54:38 +00:00
|
|
|
}
|
|
|
|
|
2021-02-24 10:58:31 +00:00
|
|
|
void
|
|
|
|
Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx)
|
|
|
|
{
|
2023-12-15 14:56:41 +00:00
|
|
|
auto device = ctx->device;
|
|
|
|
auto dfunc = device->funcs;
|
|
|
|
auto lctx = ctx->lighting_context;
|
2021-02-24 10:58:31 +00:00
|
|
|
|
2021-04-29 11:54:38 +00:00
|
|
|
clear_shadows (ctx);
|
|
|
|
|
2023-06-27 16:01:56 +00:00
|
|
|
QFV_DestroyResource (device, lctx->light_resources);
|
|
|
|
free (lctx->light_resources);
|
|
|
|
|
2023-12-15 14:56:41 +00:00
|
|
|
for (size_t i = 0; i < lctx->frames.size; i++) {
|
|
|
|
auto lframe = &lctx->frames.a[i];
|
|
|
|
dfunc->vkDestroyQueryPool (device->dev, lframe->query, 0);
|
|
|
|
dfunc->vkDestroyFence (device->dev, lframe->fence, 0);
|
|
|
|
}
|
2023-12-14 12:40:41 +00:00
|
|
|
free (lctx->frames.a[0].stage_targets);
|
2022-05-31 03:43:04 +00:00
|
|
|
DARRAY_CLEAR (&lctx->light_mats);
|
2023-08-01 14:34:08 +00:00
|
|
|
DARRAY_CLEAR (&lctx->light_control);
|
2023-08-02 08:52:57 +00:00
|
|
|
free (lctx->map_images);
|
|
|
|
free (lctx->map_views);
|
|
|
|
free (lctx->map_cube);
|
2021-02-24 10:58:31 +00:00
|
|
|
free (lctx->frames.a);
|
|
|
|
free (lctx);
|
|
|
|
}
|
2023-07-22 13:41:05 +00:00
|
|
|
|
2021-04-29 11:54:38 +00:00
|
|
|
static void
|
|
|
|
create_light_matrices (lightingctx_t *lctx)
|
|
|
|
{
|
2023-07-22 13:41:05 +00:00
|
|
|
auto reg = lctx->scene->reg;
|
|
|
|
auto light_pool = ®->comp_pools[scene_light];
|
|
|
|
auto light_data = (light_t *) light_pool->data;
|
2023-07-30 02:59:47 +00:00
|
|
|
uint16_t mat_count = 0;
|
|
|
|
for (uint32_t i = 0; i < light_pool->count; i++) {
|
|
|
|
entity_t ent = { .reg = reg, .id = light_pool->dense[i] };
|
|
|
|
uint32_t id = get_lightid (ent);
|
2023-08-01 14:34:08 +00:00
|
|
|
auto r = &lctx->light_control.a[id];
|
2023-08-04 06:44:07 +00:00
|
|
|
r->matrix_id = mat_count;
|
2023-07-30 02:59:47 +00:00
|
|
|
mat_count += r->numLayers;
|
|
|
|
}
|
|
|
|
DARRAY_RESIZE (&lctx->light_mats, mat_count);
|
2023-08-01 14:34:08 +00:00
|
|
|
lctx->dynamic_matrix_base = mat_count;
|
2023-08-04 06:44:07 +00:00
|
|
|
for (uint32_t i = 0; i < dynlight_max; i++) {
|
|
|
|
auto r = &lctx->light_control.a[lctx->dynamic_base + i];
|
|
|
|
r->matrix_id = lctx->dynamic_matrix_base + i * 6;
|
|
|
|
}
|
2023-07-30 02:59:47 +00:00
|
|
|
for (uint32_t i = 0; i < light_pool->count; i++) {
|
2023-07-22 13:41:05 +00:00
|
|
|
light_t *light = &light_data[i];
|
2023-07-24 01:23:05 +00:00
|
|
|
entity_t ent = { .reg = reg, .id = light_pool->dense[i] };
|
|
|
|
uint32_t id = get_lightid (ent);
|
2023-08-01 14:34:08 +00:00
|
|
|
auto r = &lctx->light_control.a[id];
|
2023-08-04 06:44:07 +00:00
|
|
|
auto lm = &lctx->light_mats.a[r->matrix_id];
|
2021-04-29 11:54:38 +00:00
|
|
|
mat4f_t view;
|
|
|
|
mat4f_t proj;
|
2023-08-10 22:11:52 +00:00
|
|
|
vec4f_t dir;
|
2021-04-29 11:54:38 +00:00
|
|
|
|
2023-07-30 02:59:47 +00:00
|
|
|
switch (r->mode) {
|
2021-06-01 10:09:03 +00:00
|
|
|
default:
|
2021-04-29 11:54:38 +00:00
|
|
|
case ST_NONE:
|
2023-07-30 02:59:47 +00:00
|
|
|
continue;
|
2021-04-29 11:54:38 +00:00
|
|
|
case ST_CUBE:
|
|
|
|
mat4fidentity (view);
|
|
|
|
break;
|
|
|
|
case ST_CASCADE:
|
|
|
|
case ST_PLANE:
|
|
|
|
//FIXME will fail for -ref_direction
|
2023-08-10 22:11:52 +00:00
|
|
|
dir = light->direction;
|
2022-05-04 23:40:02 +00:00
|
|
|
dir[3] = 0;
|
|
|
|
mat4fquat (view, qrotf (dir, ref_direction));
|
2021-04-29 11:54:38 +00:00
|
|
|
break;
|
|
|
|
}
|
2023-07-30 02:59:47 +00:00
|
|
|
vec4f_t pos = -light->position;
|
|
|
|
pos[3] = 1;
|
|
|
|
view[3] = mvmulf (view, pos);
|
2021-04-29 11:54:38 +00:00
|
|
|
|
2023-07-30 02:59:47 +00:00
|
|
|
switch (r->mode) {
|
2021-04-29 11:54:38 +00:00
|
|
|
case ST_NONE:
|
2023-07-30 02:59:47 +00:00
|
|
|
continue;
|
2021-04-29 11:54:38 +00:00
|
|
|
case ST_CUBE:
|
2023-08-13 08:25:17 +00:00
|
|
|
QFV_PerspectiveTan (proj, 1, 1, lnearclip);
|
2023-07-30 02:59:47 +00:00
|
|
|
for (int j = 0; j < 6; j++) {
|
|
|
|
mat4f_t side_view;
|
|
|
|
mat4f_t rotinv;
|
|
|
|
mat4ftranspose (rotinv, qfv_box_rotations[j]);
|
|
|
|
mmulf (side_view, rotinv, view);
|
|
|
|
mmulf (side_view, qfv_z_up, side_view);
|
|
|
|
mmulf (lm[j], proj, side_view);
|
|
|
|
}
|
2021-04-29 11:54:38 +00:00
|
|
|
break;
|
|
|
|
case ST_CASCADE:
|
|
|
|
// dependent on view fustrum and cascade level
|
|
|
|
mat4fidentity (proj);
|
2023-07-30 02:59:47 +00:00
|
|
|
mmulf (view, qfv_z_up, view);
|
2023-08-13 08:36:32 +00:00
|
|
|
for (int j = 0; j < num_cascade; j++) {
|
2023-07-30 02:59:47 +00:00
|
|
|
mmulf (lm[j], proj, view);
|
|
|
|
}
|
2021-04-29 11:54:38 +00:00
|
|
|
break;
|
|
|
|
case ST_PLANE:
|
2023-08-13 08:25:17 +00:00
|
|
|
QFV_PerspectiveCos (proj, -light->direction[3], lnearclip);
|
2023-07-30 02:59:47 +00:00
|
|
|
mmulf (view, qfv_z_up, view);
|
|
|
|
mmulf (lm[0], proj, view);
|
2021-04-29 11:54:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-30 02:28:42 +00:00
|
|
|
static void
|
|
|
|
upload_light_matrices (lightingctx_t *lctx, vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
auto packet = QFV_PacketAcquire (ctx->staging);
|
|
|
|
size_t mat_size = sizeof (mat4f_t[lctx->light_mats.size]);
|
|
|
|
void *mat_data = QFV_PacketExtend (packet, mat_size);
|
|
|
|
memcpy (mat_data, lctx->light_mats.a, mat_size);
|
|
|
|
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->shadowmat_buffer, 0, bb);
|
|
|
|
}
|
|
|
|
QFV_PacketSubmit (packet);
|
2023-12-14 01:01:27 +00:00
|
|
|
|
|
|
|
// FIXME temporary until batched shadow rendering is implemented
|
|
|
|
packet = QFV_PacketAcquire (ctx->staging);
|
|
|
|
size_t id_size = sizeof (uint32_t[MaxLights * 6]);
|
|
|
|
uint32_t *id_data = QFV_PacketExtend (packet, id_size);
|
|
|
|
for (int i = 0; i < MaxLights * 6; i++) {
|
|
|
|
id_data[i] = i;
|
|
|
|
}
|
|
|
|
for (size_t i = 0; i < lctx->frames.size; i++) {
|
|
|
|
auto lframe = &lctx->frames.a[i];
|
|
|
|
QFV_PacketCopyBuffer (packet, lframe->shadowmat_id_buffer, 0, bb);
|
|
|
|
}
|
|
|
|
QFV_PacketSubmit (packet);
|
2023-07-30 02:28:42 +00:00
|
|
|
}
|
|
|
|
|
2023-08-01 14:34:08 +00:00
|
|
|
static void
|
|
|
|
upload_light_data (lightingctx_t *lctx, vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
auto reg = lctx->scene->reg;
|
|
|
|
auto light_pool = ®->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);
|
2023-08-04 16:25:26 +00:00
|
|
|
if (id >= lctx->light_control.size) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-08-01 14:34:08 +00:00
|
|
|
auto r = &lctx->light_control.a[id];
|
|
|
|
render[i] = (qfv_light_render_t) {
|
2023-12-17 04:14:43 +00:00
|
|
|
.id_data = make_id(r, style_enable),
|
2023-08-01 14:34:08 +00:00
|
|
|
.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);
|
|
|
|
}
|
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-04-29 11:54:38 +00:00
|
|
|
static int
|
2023-07-22 13:41:05 +00:00
|
|
|
light_compare (const void *_li2, const void *_li1, void *_lights)
|
2021-04-29 11:54:38 +00:00
|
|
|
{
|
2022-05-10 02:15:52 +00:00
|
|
|
const int *li1 = _li1;
|
|
|
|
const int *li2 = _li2;
|
2023-07-22 13:41:05 +00:00
|
|
|
const light_t *lights = _lights;
|
|
|
|
const light_t *l1 = &lights[*li1];
|
|
|
|
const light_t *l2 = &lights[*li2];
|
2022-05-11 04:29:17 +00:00
|
|
|
int s1 = abs ((int) l1->color[3]);
|
|
|
|
int s2 = abs ((int) l2->color[3]);
|
2021-04-29 11:54:38 +00:00
|
|
|
|
2022-05-11 04:29:17 +00:00
|
|
|
if (s1 == s2) {
|
2023-12-12 12:13:14 +00:00
|
|
|
// same size
|
2023-07-24 01:23:05 +00:00
|
|
|
if (l1->position[3] == l2->position[3]) {
|
2023-12-12 12:13:14 +00:00
|
|
|
// same "type" (point/spot vs directional)
|
|
|
|
// sort by spot size (1 for point/directional)
|
2023-07-24 01:23:05 +00:00
|
|
|
return (l2->direction[3] > -0.5) - (l1->direction[3] > -0.5);
|
|
|
|
}
|
2023-12-12 12:13:14 +00:00
|
|
|
// sort by "type" (point/spot vs directional)
|
2023-07-24 01:23:05 +00:00
|
|
|
return l2->position[3] - l1->position[3];
|
2021-04-29 11:54:38 +00:00
|
|
|
}
|
2023-12-12 12:13:14 +00:00
|
|
|
// sort by size
|
2022-05-11 04:29:17 +00:00
|
|
|
return s1 - s2;
|
2021-04-29 11:54:38 +00:00
|
|
|
}
|
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
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;
|
2022-10-27 02:02:45 +00:00
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
static int
|
|
|
|
allocate_map (mapctx_t *mctx, int type, int (*getsize) (const light_t *light))
|
|
|
|
{
|
2021-04-29 11:54:38 +00:00
|
|
|
int size = -1;
|
|
|
|
int numLayers = 0;
|
|
|
|
int totalLayers = 0;
|
2023-08-13 08:36:32 +00:00
|
|
|
int layers = ((int[ST_COUNT]) { 0, 1, num_cascade, 6 })[type];
|
2023-08-02 08:52:57 +00:00
|
|
|
int cube = type == ST_CUBE;
|
2022-05-31 03:43:04 +00:00
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
for (int i = 0; i < mctx->numLights; i++) {
|
|
|
|
auto li = mctx->lightMap[i];
|
|
|
|
auto lr = &mctx->control[li];
|
2022-05-04 23:40:02 +00:00
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
if (lr->mode != type) {
|
2021-04-29 11:54:38 +00:00
|
|
|
continue;
|
|
|
|
}
|
2023-12-12 15:03:25 +00:00
|
|
|
int light_size = getsize (&mctx->lights[li]);
|
2023-12-14 03:43:37 +00:00
|
|
|
light_size = round_light_size (light_size);
|
2023-08-02 08:52:57 +00:00
|
|
|
if (size != light_size || numLayers + layers > mctx->maxLayers) {
|
2021-04-29 11:54:38 +00:00
|
|
|
if (numLayers) {
|
2023-08-02 08:52:57 +00:00
|
|
|
mctx->maps[mctx->numMaps++] = (mapdesc_t) {
|
2022-10-27 02:02:45 +00:00
|
|
|
.size = size,
|
|
|
|
.layers = numLayers,
|
2023-08-02 08:52:57 +00:00
|
|
|
.cube = cube,
|
2022-10-27 02:02:45 +00:00
|
|
|
};
|
2021-04-29 11:54:38 +00:00
|
|
|
numLayers = 0;
|
|
|
|
}
|
2023-08-02 08:52:57 +00:00
|
|
|
size = light_size;
|
2021-04-29 11:54:38 +00:00
|
|
|
}
|
2023-08-02 08:52:57 +00:00
|
|
|
mctx->imageMap[li] = mctx->numMaps;
|
2022-05-31 03:43:04 +00:00
|
|
|
lr->size = size;
|
|
|
|
lr->layer = numLayers;
|
|
|
|
lr->numLayers = layers;
|
2021-04-29 11:54:38 +00:00
|
|
|
numLayers += layers;
|
|
|
|
totalLayers += layers;
|
|
|
|
}
|
|
|
|
if (numLayers) {
|
2023-08-02 08:52:57 +00:00
|
|
|
mctx->maps[mctx->numMaps++] = (mapdesc_t) {
|
2022-10-27 02:02:45 +00:00
|
|
|
.size = size,
|
|
|
|
.layers = numLayers,
|
2023-08-02 08:52:57 +00:00
|
|
|
.cube = cube,
|
2022-10-27 02:02:45 +00:00
|
|
|
};
|
2021-04-29 11:54:38 +00:00
|
|
|
}
|
2023-08-02 08:52:57 +00:00
|
|
|
return totalLayers;
|
|
|
|
}
|
|
|
|
|
2023-08-04 06:44:07 +00:00
|
|
|
static int
|
|
|
|
allocate_dynlight_map (mapctx_t *mctx)
|
|
|
|
{
|
|
|
|
int size = -1;
|
|
|
|
int numLayers = 0;
|
|
|
|
int totalLayers = 0;
|
|
|
|
int layers = 6;
|
|
|
|
int cube = 1;
|
|
|
|
|
|
|
|
for (int i = 0; i < dynlight_max; i++) {
|
|
|
|
if (size != dynlight_size || numLayers + layers > mctx->maxLayers) {
|
|
|
|
if (numLayers) {
|
|
|
|
mctx->maps[mctx->numMaps++] = (mapdesc_t) {
|
|
|
|
.size = size,
|
|
|
|
.layers = numLayers,
|
|
|
|
.cube = cube,
|
|
|
|
};
|
|
|
|
numLayers = 0;
|
|
|
|
}
|
|
|
|
size = dynlight_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto li = mctx->numLights + i;
|
|
|
|
auto lr = &mctx->control[li];
|
|
|
|
|
|
|
|
*lr = (light_control_t) {
|
2023-12-14 12:40:41 +00:00
|
|
|
.stage_index = (size / shadow_quanta) - 1,
|
2023-08-04 06:44:07 +00:00
|
|
|
.map_index = mctx->numMaps,
|
|
|
|
.size = size,
|
|
|
|
.layer = numLayers,
|
|
|
|
.numLayers = layers,
|
|
|
|
.mode = ST_CUBE,
|
|
|
|
.light_id = li,
|
|
|
|
};
|
|
|
|
numLayers += layers;
|
|
|
|
totalLayers += layers;
|
|
|
|
}
|
|
|
|
if (numLayers) {
|
|
|
|
mctx->maps[mctx->numMaps++] = (mapdesc_t) {
|
|
|
|
.size = size,
|
|
|
|
.layers = numLayers,
|
|
|
|
.cube = cube,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return totalLayers;
|
|
|
|
}
|
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
|
|
|
|
qfv_device_t *device = ctx->device;
|
|
|
|
qfv_physdev_t *physDev = device->physDev;
|
2023-12-13 11:25:23 +00:00
|
|
|
int maxLayers = physDev->p.properties.limits.maxImageArrayLayers;
|
2023-08-02 08:52:57 +00:00
|
|
|
if (maxLayers > 2048) {
|
|
|
|
maxLayers = 2048;
|
|
|
|
}
|
|
|
|
auto reg = lctx->scene->reg;
|
|
|
|
auto light_pool = ®->comp_pools[scene_light];
|
|
|
|
auto lights = (light_t *) light_pool->data;
|
|
|
|
int numLights = light_pool->count;
|
|
|
|
int totalLayers = 0;
|
|
|
|
int imageMap[numLights];
|
|
|
|
int lightMap[numLights];
|
2023-08-16 01:52:31 +00:00
|
|
|
mapdesc_t maps[numLights + dynlight_max];
|
2023-08-02 08:52:57 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < numLights; i++) {
|
|
|
|
lightMap[i] = i;
|
|
|
|
}
|
2023-12-12 12:13:14 +00:00
|
|
|
// sort lights by size, type, spot-size
|
2023-08-02 08:52:57 +00:00
|
|
|
heapsort_r (lightMap, numLights, sizeof (int), light_compare, lights);
|
2021-04-29 11:54:38 +00:00
|
|
|
|
2023-08-04 06:44:07 +00:00
|
|
|
DARRAY_RESIZE (&lctx->light_control, numLights + dynlight_max);
|
2021-04-29 11:54:38 +00:00
|
|
|
for (int i = 0; i < numLights; i++) {
|
2023-07-24 01:23:05 +00:00
|
|
|
auto li = lightMap[i];
|
2023-08-01 14:34:08 +00:00
|
|
|
auto lr = &lctx->light_control.a[li];
|
2023-08-02 08:52:57 +00:00
|
|
|
*lr = (light_control_t) {
|
|
|
|
.mode = light_shadow_type (&lights[li]),
|
|
|
|
.light_id = li,
|
2022-10-27 02:02:45 +00:00
|
|
|
};
|
2023-08-02 08:52:57 +00:00
|
|
|
set_lightid (light_pool->dense[li], reg, li);
|
|
|
|
// assume all lights have no shadows
|
|
|
|
imageMap[li] = -1;
|
2021-04-29 11:54:38 +00:00
|
|
|
}
|
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
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);
|
|
|
|
|
2023-08-04 06:44:07 +00:00
|
|
|
totalLayers += allocate_dynlight_map (&mctx);
|
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
lctx->num_maps = mctx.numMaps;
|
2023-12-14 12:40:41 +00:00
|
|
|
int stage_layers[LIGHTING_STAGES] = {};
|
2023-08-02 08:52:57 +00:00
|
|
|
if (mctx.numMaps) {
|
2023-12-14 12:40:41 +00:00
|
|
|
for (int i = 0; i < mctx.numMaps; i++) {
|
|
|
|
int ind = (maps[i].size / shadow_quanta) - 1;
|
|
|
|
stage_layers[ind] += maps[i].layers;
|
|
|
|
}
|
|
|
|
int stage_maps = 0;
|
|
|
|
for (int i = 0; i < LIGHTING_STAGES; i++) {
|
|
|
|
stage_layers[i] = min (stage_layers[i], max_views);
|
|
|
|
if (stage_layers[i]) {
|
|
|
|
stage_maps++;
|
|
|
|
}
|
|
|
|
}
|
2022-10-27 02:02:45 +00:00
|
|
|
qfv_resource_t *shad = calloc (1, sizeof (qfv_resource_t)
|
2023-08-02 08:52:57 +00:00
|
|
|
+ sizeof (qfv_resobj_t[mctx.numMaps])
|
2023-12-14 12:40:41 +00:00
|
|
|
+ sizeof (qfv_resobj_t[mctx.numMaps])
|
|
|
|
+ sizeof (qfv_resobj_t[stage_maps])
|
|
|
|
+ sizeof (qfv_resobj_t[stage_maps]));
|
2022-10-27 02:02:45 +00:00
|
|
|
lctx->shadow_resources = shad;
|
|
|
|
*shad = (qfv_resource_t) {
|
|
|
|
.name = "shadow",
|
|
|
|
.va_ctx = ctx->va_ctx,
|
|
|
|
.memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
2023-12-14 12:40:41 +00:00
|
|
|
.num_objects = 2 * (mctx.numMaps + stage_maps),
|
2022-10-27 02:02:45 +00:00
|
|
|
.objects = (qfv_resobj_t *) &shad[1],
|
|
|
|
};
|
2023-08-02 08:52:57 +00:00
|
|
|
lctx->map_images = malloc (sizeof (VkImage[mctx.numMaps]));
|
|
|
|
lctx->map_views = malloc (sizeof (VkImageView[mctx.numMaps]));
|
|
|
|
lctx->map_cube = malloc (sizeof (bool[mctx.numMaps]));
|
2023-08-01 14:34:08 +00:00
|
|
|
auto images = shad->objects;
|
2023-12-14 12:40:41 +00:00
|
|
|
auto stage_images = &images[mctx.numMaps];
|
|
|
|
auto views = &stage_images[stage_maps];
|
|
|
|
auto stage_views = &views[mctx.numMaps];
|
2023-08-02 08:52:57 +00:00
|
|
|
for (int i = 0; i < mctx.numMaps; i++) {
|
|
|
|
int cube = maps[i].cube;
|
|
|
|
lctx->map_cube[i] = cube;
|
2023-08-01 14:34:08 +00:00
|
|
|
images[i] = (qfv_resobj_t) {
|
2023-08-15 05:34:23 +00:00
|
|
|
.name = va (ctx->va_ctx, "map:image:%02d:%d", i, maps[i].size),
|
2022-10-27 02:02:45 +00:00
|
|
|
.type = qfv_res_image,
|
|
|
|
.image = {
|
2023-02-19 03:25:13 +00:00
|
|
|
.flags = cube ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0,
|
2022-10-27 02:02:45 +00:00
|
|
|
.type = VK_IMAGE_TYPE_2D,
|
|
|
|
.format = VK_FORMAT_X8_D24_UNORM_PACK32,
|
|
|
|
.extent = { maps[i].size, maps[i].size, 1 },
|
|
|
|
.num_mipmaps = 1,
|
|
|
|
.num_layers = maps[i].layers,
|
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
|
2023-12-14 12:40:41 +00:00
|
|
|
| VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
2022-10-27 02:02:45 +00:00
|
|
|
| VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
|
|
},
|
|
|
|
};
|
2023-08-01 14:34:08 +00:00
|
|
|
views[i] = (qfv_resobj_t) {
|
2023-08-15 05:34:23 +00:00
|
|
|
.name = va (ctx->va_ctx, "map:view:%02d:%d", i, maps[i].size),
|
2023-08-01 14:34:08 +00:00
|
|
|
.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,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
2022-10-27 02:02:45 +00:00
|
|
|
}
|
2023-12-14 12:40:41 +00:00
|
|
|
for (int i = 0, ind = 0; i < LIGHTING_STAGES; i++) {
|
|
|
|
if (!stage_layers[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int size = (i + 1) * shadow_quanta;
|
|
|
|
stage_images[ind] = (qfv_resobj_t) {
|
|
|
|
.name = va (ctx->va_ctx, "stage_map:image:%02d:%d", ind, size),
|
|
|
|
.type = qfv_res_image,
|
|
|
|
.image = {
|
|
|
|
.type = VK_IMAGE_TYPE_2D,
|
|
|
|
.format = VK_FORMAT_X8_D24_UNORM_PACK32,
|
|
|
|
.extent = { size, size, 1 },
|
|
|
|
.num_mipmaps = 1,
|
|
|
|
.num_layers = stage_layers[i],
|
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
|
|
|
|
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
stage_views[ind] = (qfv_resobj_t) {
|
|
|
|
.name = va (ctx->va_ctx, "stage_map:view:%02d:%d", ind, size),
|
|
|
|
.type = qfv_res_image_view,
|
|
|
|
.image_view = {
|
|
|
|
.image = mctx.numMaps + ind,
|
|
|
|
.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,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
ind++;
|
|
|
|
}
|
2022-10-27 02:02:45 +00:00
|
|
|
QFV_CreateResource (device, shad);
|
2023-08-02 08:52:57 +00:00
|
|
|
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;
|
2022-10-27 02:02:45 +00:00
|
|
|
}
|
2023-12-14 12:40:41 +00:00
|
|
|
for (int i = 0, ind = 0; i < LIGHTING_STAGES; i++) {
|
|
|
|
if (!stage_layers[i]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
lctx->stage_images[i] = stage_images[ind].image.image;
|
|
|
|
lctx->stage_views[i] = stage_views[ind].image_view.view;
|
|
|
|
ind++;
|
|
|
|
}
|
2021-04-29 11:54:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < numLights; i++) {
|
2023-07-24 01:23:05 +00:00
|
|
|
int li = lightMap[i];
|
2023-08-01 14:34:08 +00:00
|
|
|
auto lr = &lctx->light_control.a[li];
|
2022-05-10 02:15:52 +00:00
|
|
|
|
|
|
|
if (imageMap[li] == -1) {
|
2021-04-29 11:54:38 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-05-04 23:40:02 +00:00
|
|
|
|
2023-12-14 12:40:41 +00:00
|
|
|
lr->stage_index = -1;
|
|
|
|
if (lr->numLayers) {
|
|
|
|
lr->stage_index = (lr->size / shadow_quanta) - 1;
|
2022-05-04 23:40:02 +00:00
|
|
|
}
|
2023-08-01 14:34:08 +00:00
|
|
|
lr->map_index = imageMap[li];
|
2021-04-29 11:54:38 +00:00
|
|
|
}
|
2023-07-22 13:41:05 +00:00
|
|
|
Sys_MaskPrintf (SYS_lighting,
|
2023-08-02 08:52:57 +00:00
|
|
|
"shadow maps: %d layers in %d images: %"PRId64"\n",
|
|
|
|
totalLayers, lctx->num_maps,
|
|
|
|
lctx->shadow_resources ? lctx->shadow_resources->size
|
|
|
|
: (VkDeviceSize) 0);
|
2023-12-12 15:03:25 +00:00
|
|
|
if (developer & SYS_lighting) {
|
|
|
|
auto images = lctx->shadow_resources->objects;
|
|
|
|
for (int i = 0; i < lctx->num_maps; i++) {
|
2023-12-14 12:40:41 +00:00
|
|
|
Sys_Printf ("map id:%d width:%d layers:%d\n", i,
|
|
|
|
images[i].image.extent.width,
|
|
|
|
images[i].image.num_layers);
|
|
|
|
}
|
|
|
|
for (int i = 0; i < LIGHTING_STAGES; i++) {
|
|
|
|
Sys_Printf ("stage:%d width:%d layers:%d\n", i,
|
|
|
|
(i + 1) * shadow_quanta, stage_layers[i]);
|
2023-12-12 15:03:25 +00:00
|
|
|
}
|
|
|
|
}
|
2023-08-02 08:52:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2021-04-29 11:54:38 +00:00
|
|
|
}
|
2023-07-22 13:41:05 +00:00
|
|
|
|
2023-08-01 14:34:08 +00:00
|
|
|
static void
|
|
|
|
update_shadow_descriptors (lightingctx_t *lctx, vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
auto device = ctx->device;
|
|
|
|
auto dfunc = device->funcs;
|
|
|
|
|
2023-08-02 08:52:57 +00:00
|
|
|
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];
|
|
|
|
}
|
2023-08-01 14:34:08 +00:00
|
|
|
}
|
2023-08-02 08:52:57 +00:00
|
|
|
imageInfoCube[i] = (VkDescriptorImageInfo) {
|
|
|
|
.sampler = lctx->shadow_sampler,
|
|
|
|
.imageView = viewCube,
|
|
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
|
|
};
|
|
|
|
imageInfo2d[i] = (VkDescriptorImageInfo) {
|
2023-08-01 14:34:08 +00:00
|
|
|
.sampler = lctx->shadow_sampler,
|
2023-08-02 08:52:57 +00:00
|
|
|
.imageView = view2d,
|
2023-08-01 14:34:08 +00:00
|
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
|
|
};
|
|
|
|
}
|
2023-08-02 08:52:57 +00:00
|
|
|
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,
|
|
|
|
},
|
2023-08-01 14:34:08 +00:00
|
|
|
};
|
2023-08-02 08:52:57 +00:00
|
|
|
dfunc->vkUpdateDescriptorSets (device->dev, 2, imageWrite, 0, 0);
|
2023-08-01 14:34:08 +00:00
|
|
|
}
|
|
|
|
|
2023-08-10 00:38:42 +00:00
|
|
|
static void
|
|
|
|
mark_leaves (bsp_pass_t *pass, set_t *pvs)
|
|
|
|
{
|
|
|
|
visstate_t visstate = {
|
|
|
|
.node_visframes = pass->node_frames,
|
|
|
|
.leaf_visframes = pass->leaf_frames,
|
|
|
|
.face_visframes = pass->face_frames,
|
|
|
|
.visframecount = pass->vis_frame,
|
|
|
|
.brush = pass->brush,
|
|
|
|
};
|
|
|
|
R_MarkLeavesPVS (&visstate, pvs);
|
|
|
|
pass->vis_frame = visstate.visframecount;
|
|
|
|
}
|
|
|
|
|
2023-08-08 16:23:13 +00:00
|
|
|
static void
|
|
|
|
show_leaves (vulkan_ctx_t *ctx, uint32_t leafnum, efrag_t *efrags)
|
|
|
|
{
|
|
|
|
auto pass = Vulkan_Bsp_GetPass (ctx, QFV_bspDebug);
|
|
|
|
auto brush = pass->brush;
|
|
|
|
|
|
|
|
set_t pvs = SET_STATIC_INIT (brush->visleafs, alloca);
|
|
|
|
set_empty (&pvs);
|
|
|
|
if (leafnum) {
|
|
|
|
set_add (&pvs, leafnum - 1);
|
2023-08-10 00:38:42 +00:00
|
|
|
} else {
|
|
|
|
for (auto e = efrags; e; e = e->entnext) {
|
|
|
|
set_add (&pvs, e->leaf - brush->leafs - 1);
|
|
|
|
}
|
2023-08-08 16:23:13 +00:00
|
|
|
}
|
2023-08-10 00:38:42 +00:00
|
|
|
mark_leaves (pass, &pvs);
|
2023-08-08 16:23:13 +00:00
|
|
|
}
|
|
|
|
|
2023-08-11 09:05:45 +00:00
|
|
|
static void
|
|
|
|
light_dyn_light_ui (void *comp, imui_ctx_t *imui_ctx,
|
|
|
|
ecs_registry_t *reg, uint32_t ent, void *data)
|
|
|
|
{
|
|
|
|
dlight_t *dlight = comp;
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Labelf ("Origin: ");
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%6.1f %6.1f %6.1f %6g", VEC4_EXP (dlight->origin));
|
|
|
|
}
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Label ("Color: ");
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%5.3f %5.3f %5.3f %5.3f", VEC4_EXP (dlight->color));
|
|
|
|
}
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Labelf ("Radius: ");
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%6g", dlight->radius);
|
|
|
|
}
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Labelf ("Die: ");
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%6.2f", dlight->die);
|
|
|
|
}
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Labelf ("Decay: ");
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%6.2f", dlight->decay);
|
|
|
|
}
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Labelf ("Min Light: ");
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%6g", dlight->minlight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
light_light_ui (void *comp, imui_ctx_t *imui_ctx,
|
|
|
|
ecs_registry_t *reg, uint32_t ent, void *data)
|
|
|
|
{
|
|
|
|
light_t *light = comp;
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Label ("Color: ");
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%5.3f %5.3f %5.3f %3g", VEC4_EXP (light->color));
|
|
|
|
}
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Labelf ("Position: ");
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%6.1f %6.1f %6.1f %6g", VEC4_EXP (light->position));
|
|
|
|
}
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Labelf ("Direction: ");
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%6.3f %6.3f %6.3f %6.3g", VEC4_EXP (light->direction));
|
|
|
|
}
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Labelf ("Attenuation: ");
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%g %g %g %g", VEC4_EXP (light->attenuation));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-08 16:23:13 +00:00
|
|
|
static void
|
|
|
|
scene_efrags_ui (void *comp, imui_ctx_t *imui_ctx,
|
|
|
|
ecs_registry_t *reg, uint32_t ent, void *data)
|
|
|
|
{
|
2023-08-10 00:38:42 +00:00
|
|
|
vulkan_ctx_t *ctx = data;
|
2023-08-08 16:23:13 +00:00
|
|
|
auto efrags = *(efrag_t **) comp;
|
|
|
|
uint32_t len = 0;
|
|
|
|
bool valid = true;
|
|
|
|
for (auto e = efrags; e; e = e->entnext, len++) {
|
|
|
|
valid &= e->entity.id == ent;
|
|
|
|
}
|
|
|
|
UI_Horizontal {
|
2023-08-10 00:38:42 +00:00
|
|
|
if (UI_Button (va (ctx->va_ctx, "Show##lightefrags_ui.%08x", ent))) {
|
|
|
|
show_leaves (ctx, 0, efrags);
|
|
|
|
}
|
2023-08-08 16:23:13 +00:00
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%4s %5u", valid ? "good" : "bad", len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
scene_lightleaf_ui (void *comp, imui_ctx_t *imui_ctx,
|
|
|
|
ecs_registry_t *reg, uint32_t ent, void *data)
|
|
|
|
{
|
|
|
|
vulkan_ctx_t *ctx = data;
|
|
|
|
auto leaf = *(uint32_t *) comp;
|
|
|
|
UI_Horizontal {
|
|
|
|
if (UI_Button (va (ctx->va_ctx, "Show##lightleaf_ui.%08x", ent))) {
|
|
|
|
show_leaves (ctx, leaf, 0);
|
|
|
|
}
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%5u", leaf);
|
2023-08-10 00:38:42 +00:00
|
|
|
|
|
|
|
auto pass = Vulkan_Bsp_GetPass (ctx, QFV_bspDebug);
|
|
|
|
auto brush = pass->brush;
|
|
|
|
set_t pvs = SET_STATIC_INIT (brush->visleafs, alloca);
|
|
|
|
Mod_LeafPVS_set (brush->leafs + leaf, brush, 0, &pvs);
|
|
|
|
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
if (UI_Button (va (ctx->va_ctx, "Vis##lightleaf_ui.%08x", ent))) {
|
|
|
|
mark_leaves (pass, &pvs);
|
|
|
|
}
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
UI_Labelf ("%5u", set_count (&pvs));
|
2023-08-08 16:23:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-17 02:25:25 +00:00
|
|
|
static void
|
|
|
|
scene_lightstyle_ui (void *comp, imui_ctx_t *imui_ctx,
|
|
|
|
ecs_registry_t *reg, uint32_t ent, void *data)
|
|
|
|
{
|
|
|
|
auto style = *(uint32_t *) comp;
|
|
|
|
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Labelf ("%5u", style);
|
|
|
|
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
auto val = d_lightstylevalue[style];
|
|
|
|
UI_Labelf ("%3f", val / 65536.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
scene_lightid_ui (void *comp, imui_ctx_t *imui_ctx,
|
|
|
|
ecs_registry_t *reg, uint32_t ent, void *data)
|
|
|
|
{
|
|
|
|
auto id = *(uint32_t *) comp;
|
|
|
|
|
|
|
|
UI_Horizontal {
|
|
|
|
UI_Labelf ("%5u", id);
|
|
|
|
UI_FlexibleSpace ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-03 09:14:16 +00:00
|
|
|
void
|
2022-05-05 05:58:47 +00:00
|
|
|
Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx)
|
2021-03-03 09:14:16 +00:00
|
|
|
{
|
2023-12-04 12:38:43 +00:00
|
|
|
qfZoneScoped (true);
|
2021-03-03 09:14:16 +00:00
|
|
|
lightingctx_t *lctx = ctx->lighting_context;
|
|
|
|
|
2022-05-05 05:58:47 +00:00
|
|
|
lctx->scene = scene;
|
2023-07-22 13:41:05 +00:00
|
|
|
|
2022-05-10 02:15:52 +00:00
|
|
|
clear_shadows (ctx);
|
|
|
|
|
2023-07-27 07:09:33 +00:00
|
|
|
lctx->ldata = 0;
|
2023-07-22 13:41:05 +00:00
|
|
|
if (lctx->scene) {
|
|
|
|
auto reg = lctx->scene->reg;
|
2023-08-11 09:05:45 +00:00
|
|
|
reg->components.a[scene_dynlight].ui = light_dyn_light_ui;
|
|
|
|
reg->components.a[scene_light].ui = light_light_ui;
|
2023-08-08 16:23:13 +00:00
|
|
|
reg->components.a[scene_efrags].ui = scene_efrags_ui;
|
2023-12-17 02:25:25 +00:00
|
|
|
reg->components.a[scene_lightstyle].ui = scene_lightstyle_ui;
|
2023-08-08 16:23:13 +00:00
|
|
|
reg->components.a[scene_lightleaf].ui = scene_lightleaf_ui;
|
2023-12-17 02:25:25 +00:00
|
|
|
reg->components.a[scene_lightid].ui = scene_lightid_ui;
|
2023-08-08 16:23:13 +00:00
|
|
|
|
2023-07-22 13:41:05 +00:00
|
|
|
auto light_pool = ®->comp_pools[scene_light];
|
|
|
|
if (light_pool->count) {
|
2023-08-04 06:44:07 +00:00
|
|
|
lctx->dynamic_base = light_pool->count;
|
|
|
|
lctx->dynamic_count = 0;
|
2023-07-22 13:41:05 +00:00
|
|
|
build_shadow_maps (lctx, ctx);
|
2023-08-02 08:52:57 +00:00
|
|
|
transition_shadow_maps (lctx, ctx);
|
2023-08-01 14:34:08 +00:00
|
|
|
update_shadow_descriptors (lctx, ctx);
|
2023-07-22 13:41:05 +00:00
|
|
|
create_light_matrices (lctx);
|
2023-07-30 02:28:42 +00:00
|
|
|
upload_light_matrices (lctx, ctx);
|
2023-08-01 14:34:08 +00:00
|
|
|
upload_light_data (lctx, ctx);
|
2023-07-22 13:41:05 +00:00
|
|
|
}
|
2023-07-27 07:09:33 +00:00
|
|
|
lctx->ldata = scene->lights;
|
2022-05-10 02:15:52 +00:00
|
|
|
}
|
2021-03-03 09:14:16 +00:00
|
|
|
}
|
2023-07-30 02:52:13 +00:00
|
|
|
|
|
|
|
VkDescriptorSet
|
|
|
|
Vulkan_Lighting_Descriptors (vulkan_ctx_t *ctx, int frame)
|
|
|
|
{
|
|
|
|
auto lctx = ctx->lighting_context;
|
|
|
|
return lctx->frames.a[frame].shadowmat_set;
|
|
|
|
}
|