mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-17 01:11:45 +00:00
[vulkan] Implement deferred lighting for dlights
Static lights are yet to come (so the screen is black most of the time), but dynamic lights work very nicely (and look very good) despite the falloff being incorrect.
This commit is contained in:
parent
918c3af095
commit
33575f93d5
4 changed files with 152 additions and 13 deletions
|
@ -36,11 +36,29 @@
|
|||
#include "QF/Vulkan/qf_vid.h"
|
||||
#include "QF/Vulkan/command.h"
|
||||
|
||||
typedef struct qfv_light_s {
|
||||
vec3_t color;
|
||||
float intensity;
|
||||
vec3_t position;
|
||||
int radius;
|
||||
vec3_t direction;
|
||||
float cone;
|
||||
} qfv_light_t;
|
||||
|
||||
#define NUM_LIGHTS 128
|
||||
|
||||
typedef struct qfv_light_buffer_s {
|
||||
int lightCount;
|
||||
qfv_light_t lights[NUM_LIGHTS] __attribute__((aligned(16)));
|
||||
} qfv_light_buffer_t;
|
||||
|
||||
|
||||
#define LIGHTING_BUFFER_INFOS 1
|
||||
#define LIGHTING_IMAGE_INFOS 4
|
||||
|
||||
typedef struct lightingframe_s {
|
||||
VkCommandBuffer cmd;
|
||||
VkBuffer light_buffer;
|
||||
VkDescriptorBufferInfo bufferInfo[LIGHTING_BUFFER_INFOS];
|
||||
VkDescriptorImageInfo imageInfo[LIGHTING_IMAGE_INFOS];
|
||||
VkWriteDescriptorSet descriptors[LIGHTING_BUFFER_INFOS
|
||||
|
@ -54,6 +72,7 @@ typedef struct lightingctx_s {
|
|||
lightingframeset_t frames;
|
||||
VkPipeline pipeline;
|
||||
VkPipelineLayout layout;
|
||||
VkDeviceMemory light_memory;
|
||||
} lightingctx_t;
|
||||
|
||||
struct vulkan_ctx_s;
|
||||
|
|
|
@ -575,6 +575,15 @@
|
|||
stage = fragment;
|
||||
name = main;
|
||||
module = $builtin/bsp_gbuf.frag;
|
||||
specializationInfo = {
|
||||
mapEntries = (
|
||||
{ size = 4; offset = 0; constantID = 0; },
|
||||
{ size = 4; offset = 0; constantID = 1; },
|
||||
{ size = 4; offset = 0; constantID = 2; },
|
||||
{ size = 4; offset = 4; constantID = 1; },
|
||||
);
|
||||
data = <00000000ffffffff>;
|
||||
};
|
||||
},
|
||||
);
|
||||
vertexInput = {
|
||||
|
|
|
@ -7,31 +7,49 @@ layout (input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput p
|
|||
|
||||
struct LightData {
|
||||
vec3 color;
|
||||
float dist;
|
||||
float intensity;
|
||||
vec3 position;
|
||||
int type;
|
||||
int radius;
|
||||
vec3 direction;
|
||||
float cone;
|
||||
};
|
||||
|
||||
layout (constant_id = 0) const int MaxLights = 8;
|
||||
/*layout (set = 1, binding = 0) uniform Lights {
|
||||
layout (constant_id = 0) const int MaxLights = 128;
|
||||
layout (set = 1, binding = 0) uniform Lights {
|
||||
int lightCount;
|
||||
LightData lights[MaxLights];
|
||||
};*/
|
||||
};
|
||||
|
||||
layout (location = 0) out vec4 frag_color;
|
||||
|
||||
vec3
|
||||
calc_light (LightData light, vec3 position, vec3 normal)
|
||||
{
|
||||
vec3 dist = light.position - position;
|
||||
vec3 incoming = normalize (dist);
|
||||
float spotdot = -dot (incoming, light.direction);
|
||||
float lightdot = dot (incoming, normal);
|
||||
float d = dot (dist, dist);
|
||||
float r = light.radius;
|
||||
|
||||
float intensity = light.intensity * step (d, r * r);
|
||||
intensity *= step (spotdot, light.cone) * clamp (lightdot, 0, 1);
|
||||
return light.color * intensity;
|
||||
}
|
||||
|
||||
void
|
||||
main (void)
|
||||
{
|
||||
float d = subpassLoad (depth).r;
|
||||
//float d = subpassLoad (depth).r;
|
||||
vec3 c = subpassLoad (color).rgb;
|
||||
vec3 n = subpassLoad (normal).rgb;
|
||||
vec3 p = subpassLoad (position).rgb;
|
||||
vec3 light = vec3 (0);
|
||||
|
||||
c = vec3 (d, d, d);
|
||||
c = (n + 1)/2;
|
||||
c = (p / 1024 + 1) / 2;
|
||||
frag_color = vec4 (c, 1);
|
||||
if (MaxLights > 0) {
|
||||
for (int i = 0; i < lightCount; i++) {
|
||||
light += calc_light (lights[i], p, n);
|
||||
}
|
||||
}
|
||||
frag_color = vec4 (c * light, 1);
|
||||
}
|
||||
|
|
|
@ -42,22 +42,85 @@
|
|||
#include "qfalloca.h"
|
||||
|
||||
#include "QF/sys.h"
|
||||
#include "QF/va.h"
|
||||
|
||||
#include "QF/Vulkan/qf_lighting.h"
|
||||
#include "QF/Vulkan/buffer.h"
|
||||
#include "QF/Vulkan/debug.h"
|
||||
#include "QF/Vulkan/descriptor.h"
|
||||
#include "QF/Vulkan/device.h"
|
||||
#include "QF/Vulkan/image.h"
|
||||
#include "QF/Vulkan/staging.h"
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include "r_internal.h"
|
||||
#include "vid_vulkan.h"
|
||||
|
||||
static void
|
||||
update_lights (vulkan_ctx_t *ctx)
|
||||
{
|
||||
qfv_device_t *device = ctx->device;
|
||||
qfv_devfuncs_t *dfunc = device->funcs;
|
||||
lightingctx_t *lctx = ctx->lighting_context;
|
||||
lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame];
|
||||
|
||||
dlight_t *lights[NUM_LIGHTS];
|
||||
qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging);
|
||||
qfv_light_buffer_t *light_data = QFV_PacketExtend (packet,
|
||||
sizeof (*light_data));
|
||||
|
||||
light_data->lightCount = 0;
|
||||
R_FindNearLights (r_origin, NUM_LIGHTS - 1, lights);
|
||||
for (int i = 0; i < NUM_LIGHTS - 1; i++) {
|
||||
if (!lights[i]) {
|
||||
break;
|
||||
}
|
||||
light_data->lightCount++;
|
||||
VectorCopy (lights[i]->color, light_data->lights[i].color);
|
||||
VectorCopy (lights[i]->origin, light_data->lights[i].position);
|
||||
light_data->lights[i].radius = lights[i]->radius;
|
||||
light_data->lights[i].intensity = 1;
|
||||
VectorZero (light_data->lights[i].direction);
|
||||
light_data->lights[i].cone = 1;
|
||||
}
|
||||
|
||||
VkBufferMemoryBarrier wr_barriers[] = {
|
||||
{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
|
||||
0, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
lframe->light_buffer, 0, sizeof (qfv_light_buffer_t) },
|
||||
};
|
||||
dfunc->vkCmdPipelineBarrier (packet->cmd,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, 0, 0, 1, wr_barriers, 0, 0);
|
||||
VkBufferCopy copy_region[] = {
|
||||
{ packet->offset, 0, sizeof (qfv_light_buffer_t) },
|
||||
};
|
||||
dfunc->vkCmdCopyBuffer (packet->cmd, ctx->staging->buffer,
|
||||
lframe->light_buffer, 1, ©_region[0]);
|
||||
VkBufferMemoryBarrier rd_barriers[] = {
|
||||
{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
lframe->light_buffer, 0, sizeof (qfv_light_buffer_t) },
|
||||
};
|
||||
dfunc->vkCmdPipelineBarrier (packet->cmd,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
||||
0, 0, 0, 1, rd_barriers, 0, 0);
|
||||
QFV_PacketSubmit (packet);
|
||||
}
|
||||
|
||||
void
|
||||
Vulkan_Lighting_Draw (vulkan_ctx_t *ctx)
|
||||
{
|
||||
qfv_device_t *device = ctx->device;
|
||||
qfv_devfuncs_t *dfunc = device->funcs;
|
||||
|
||||
update_lights (ctx);
|
||||
|
||||
lightingctx_t *lctx = ctx->lighting_context;
|
||||
__auto_type cframe = &ctx->frames.a[ctx->curFrame];
|
||||
lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame];
|
||||
|
@ -82,15 +145,16 @@ Vulkan_Lighting_Draw (vulkan_ctx_t *ctx)
|
|||
dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
lctx->pipeline);
|
||||
|
||||
lframe->bufferInfo[0].buffer = lframe->light_buffer;
|
||||
lframe->imageInfo[0].imageView = ctx->attachment_views->a[QFV_attachDepth];
|
||||
lframe->imageInfo[1].imageView = ctx->attachment_views->a[QFV_attachColor];
|
||||
lframe->imageInfo[2].imageView
|
||||
= ctx->attachment_views->a[QFV_attachNormal];
|
||||
lframe->imageInfo[3].imageView
|
||||
= ctx->attachment_views->a[QFV_attachPosition];
|
||||
dfunc->vkUpdateDescriptorSets (device->dev, LIGHTING_IMAGE_INFOS,
|
||||
lframe->descriptors + LIGHTING_BUFFER_INFOS,
|
||||
0, 0);
|
||||
dfunc->vkUpdateDescriptorSets (device->dev,
|
||||
LIGHTING_BUFFER_INFOS + LIGHTING_IMAGE_INFOS,
|
||||
lframe->descriptors, 0, 0);
|
||||
|
||||
VkDescriptorSet sets[] = {
|
||||
lframe->descriptors[1].dstSet,
|
||||
|
@ -134,6 +198,7 @@ void
|
|||
Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
|
||||
{
|
||||
qfv_device_t *device = ctx->device;
|
||||
qfv_devfuncs_t *dfunc = device->funcs;
|
||||
|
||||
lightingctx_t *lctx = calloc (1, sizeof (lightingctx_t));
|
||||
ctx->lighting_context = lctx;
|
||||
|
@ -146,6 +211,25 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
|
|||
lctx->pipeline = Vulkan_CreatePipeline (ctx, "lighting");
|
||||
lctx->layout = Vulkan_CreatePipelineLayout (ctx, "lighting_layout");
|
||||
|
||||
__auto_type lbuffers = QFV_AllocBufferSet (frames, alloca);
|
||||
for (size_t i = 0; i < frames; i++) {
|
||||
lbuffers->a[i] = QFV_CreateBuffer (device, sizeof (qfv_light_buffer_t),
|
||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
|
||||
| VK_BUFFER_USAGE_TRANSFER_DST_BIT);
|
||||
QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER,
|
||||
lbuffers->a[i],
|
||||
va (ctx->va_ctx, "buffer:lighting:%zd", i));
|
||||
}
|
||||
VkMemoryRequirements requirements;
|
||||
dfunc->vkGetBufferMemoryRequirements (device->dev, lbuffers->a[0],
|
||||
&requirements);
|
||||
lctx->light_memory = QFV_AllocBufferMemory (device, lbuffers->a[0],
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
frames * requirements.size, 0);
|
||||
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY,
|
||||
lctx->light_memory, "memory:lighting");
|
||||
|
||||
|
||||
__auto_type cmdSet = QFV_AllocCommandBufferSet (1, alloca);
|
||||
|
||||
__auto_type attach = QFV_AllocDescriptorSetLayoutSet (frames, alloca);
|
||||
|
@ -171,6 +255,10 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
|
|||
QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet);
|
||||
lframe->cmd = cmdSet->a[0];
|
||||
|
||||
lframe->light_buffer = lbuffers->a[i];
|
||||
QFV_BindBufferMemory (device, lbuffers->a[i], lctx->light_memory,
|
||||
i * requirements.size);
|
||||
|
||||
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER,
|
||||
lframe->cmd, "cmd:lighting");
|
||||
for (int j = 0; j < LIGHTING_BUFFER_INFOS; j++) {
|
||||
|
@ -201,6 +289,11 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx)
|
|||
qfv_devfuncs_t *dfunc = device->funcs;
|
||||
lightingctx_t *lctx = ctx->lighting_context;
|
||||
|
||||
for (size_t i = 0; i < lctx->frames.size; i++) {
|
||||
lightingframe_t *lframe = &lctx->frames.a[i];
|
||||
dfunc->vkDestroyBuffer (device->dev, lframe->light_buffer, 0);
|
||||
}
|
||||
dfunc->vkFreeMemory (device->dev, lctx->light_memory, 0);
|
||||
dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0);
|
||||
free (lctx->frames.a);
|
||||
free (lctx);
|
||||
|
|
Loading…
Reference in a new issue