rtx: improve surface lights

use bsp/pvs-based visibility data for acceleration:
+ fps 5 -> 60
- correctness: some areas have too many lights, which ends up culling visible ones too

also fix shadow artefacts
This commit is contained in:
Ivan 'provod' Avdeev 2021-04-12 11:07:41 -07:00
parent 0407f12638
commit ad7b210228
11 changed files with 292 additions and 92 deletions

View File

@ -1,7 +1,13 @@
## 2021-04-12
- [x] rtx: fix surface-kusok index mismatch
- [x] rtx: try to use light visibility data
-> too few slots for light sources
-> some areas have too many naively visible lights
- [x] rtx: fix light shadow artefacts
# Next
- [ ] rtx: use light visibility data
- [ ] sometimes we get uninitialized models
- [ ] rtx: "toilet error": attempting to get AS device address crashes the driver
- [ ] rtx: sometimes we get uninitialized models
- [ ] run under asan
- [ ] rtx: fix blas destruction on exit
- [ ] rtx: read rad file data
@ -10,8 +16,14 @@
- [ ] rtx: textures
- [ ] rtx: better random
- [ ] rtx: some studio models have glitchy geometry
- [ ] rtx: simple convolution denoise (bilateral?)
# Planned
- [ ] rtx: denoise
- [ ] non local means ?
- [ ] reprojection
- [ ] SVG+
- [ ] ...
- [ ] rtx: add fps: rasterize into G-buffer, and only then compute lighting with rtx
- [ ] bake light visibility in compute shader
- [ ] rtx: cull light sources (dlights and light textures) using bsp
@ -168,3 +180,6 @@
- [x] rtx: add fps
- [x] rtx: don't group brush draws by texture
- [x] better AS structure (fewer blases, etc)
## 2021-04-11
- [x] vscode build and debug

View File

@ -1,6 +1,10 @@
#version 460
#extension GL_EXT_ray_query : require
#extension GL_EXT_shader_16bit_storage : require
#extension GL_EXT_shader_8bit_storage : require
const float normal_offset_fudge = .01;
const float shadow_offset_fudge = .5;
const float
C_A = 434073., C_B = 497559., C_C = 397590., C_D = 498071.,
@ -65,6 +69,10 @@ struct Kusok {
uint index_offset;
uint vertex_offset;
uint triangles;
uint leaf;
uint num_dlights;
uint num_surface_lights;
uint is_emissive;
//vec4 emissive;
};
@ -93,14 +101,43 @@ layout(set=0,binding=6) uniform UBODLights {
Light lights[max_dlights];
};
layout (constant_id = 2) const uint max_lighttextures = 256;
layout (set=0,binding=7) uniform UBOLightTextures {
uint num_lighttextures;
uint lighttextures[max_lighttextures];
struct EmissiveKusok {
uint kusok_index;
vec3 emissive_color;
};
layout (constant_id = 2) const uint max_lighttextures = 256;
layout (set = 0, binding = 7/*, align=4*/) uniform UBOEmissiveKusochki {
uint num_kusochki;
EmissiveKusok kusochki[256];
} emissive_kusochki;
layout(binding = 8, set = 0, rgba8) uniform readonly image2D previous_frame;
// FIXME shader specialization constants
#define MAX_VISIBLE_DLIGHTS 15
#define MAX_VISIBLE_SURFACE_LIGHTS 15
struct LightLeaf {
uint8_t num_dlights;
uint8_t num_slights;
uint8_t dlights[MAX_VISIBLE_DLIGHTS];
uint8_t slights[MAX_VISIBLE_SURFACE_LIGHTS];
};
// FIMXE specialize
layout (constant_id = 3) const uint max_light_leaves = 8192;
layout (set = 0, binding = 9, align = 1) readonly buffer UBOLightLeaves {
LightLeaf light_leaves[max_light_leaves];
};
layout (push_constant) uniform PC {
float t;
int bounces;
float prev_frame_blend_factor;
} pc;
//uint picked_light = 76;//uint(mod(pc.t * 4., emissive_kusochki.num_kusochki));
float printText(in vec2 p) {
#define PIXSZ 4.
p = floor(p / PIXSZ);
@ -119,8 +156,35 @@ float printText(in vec2 p) {
return 0.;
const int idx = int(pc.y);
const Kusok kusok = kusochki[idx];
PUTN(idx); PUTC(0.); PUTN(kusok.index_offset); PUTC(0.); PUTN(kusok.vertex_offset); PUTC(0.); PUTN(kusok.triangles);
#define _ PUTC(0.);
if (false) {
const Kusok kusok = kusochki[idx];
PUTN(idx); PUTC(0.); PUTN(kusok.leaf); PUTC(0.); PUTN(kusok.num_surface_lights); PUTC(0.);
PUTN(kusok.num_dlights);
//PUTN(kusok.index_offset); PUTC(0.); PUTN(kusok.vertex_offset); PUTC(0.); PUTN(kusok.triangles);
} else if (false) {
PUTN(idx);
_ PUTN(float(int(light_leaves[idx].num_slights)));
_ PUTN(float(int(light_leaves[idx].slights[0])));
_ PUTN(float(int(light_leaves[idx].slights[1])));
_ PUTN(float(int(light_leaves[idx].slights[2])));
_ PUTN(float(int(light_leaves[idx].slights[3])));
} else if (false)
{
PUTN(emissive_kusochki.num_kusochki);
_ PUTN(idx);
_ PUTN(emissive_kusochki.kusochki[idx].kusok_index);
_ PUTN(emissive_kusochki.kusochki[idx].emissive_color.r*255.);
_ PUTN(emissive_kusochki.kusochki[idx].emissive_color.g*255.);
_ PUTN(emissive_kusochki.kusochki[idx].emissive_color.b*255.);
const uint kidx = emissive_kusochki.kusochki[idx].kusok_index;
_ PUTN(kusochki[kidx].leaf);
_ PUTN(kusochki[kidx].triangles);
} else if (true) {
//PUTN(picked_light);
}
#undef _
return col;
}
@ -148,11 +212,6 @@ float rand01() {
float hash(float f) { return fract(sin(f)*53478.4327); }
layout (push_constant) uniform PC {
float t;
int bounces;
} pc;
bool shadowed(vec3 pos, vec3 dir, float dist) {
rayQueryEXT shadowRayQuery;
rayQueryInitializeEXT(shadowRayQuery, tlas,
@ -194,10 +253,18 @@ void main() {
//const int instance_index = rayQueryGetIntersectionInstanceIdEXT(rayQuery, true);
const int geom_index = rayQueryGetIntersectionGeometryIndexEXT(rayQuery, true);
const int kusok_index = instance_kusochki_offset + geom_index;
const Kusok kusok = kusochki[kusok_index];
const uint leaf = kusochki[kusok_index].leaf-1;
//C = fract(pos / 100.);
//C = vec3(hash(float(geom_index)), hash(float(geom_index)+15.43), hash(float(geom_index)+34.));
//C = vec3(hash(float(leaf)), hash(float(leaf)+15.43), hash(float(leaf)+34.));
//C = vec3(hash(float(leaf)), float(kusok.num_surface_lights) / 63., float(kusok.is_emissive));
//break;
// if (kusok.is_emissive != 0) {
// C = vec3(0., 1., 0.);
// break;
//}
const int prim_index = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true);
const mat4x3 transform = rayQueryGetIntersectionObjectToWorldEXT(rayQuery, true);
@ -218,57 +285,76 @@ void main() {
// TODO read from texture
const vec3 baseColor = vec3(1.);
// FIXME upload this data
#if 0
for (uint i = 0; i < num_lighttextures; ++i) {
const uint kusok_index_light = lighttextures[i];
const Kusok kusok = kusochki[kusok_index];
if (kusok_index_light == kusok_index) {
// TODO do we need to do this when we have textures?
C += kc * vec3(hash(float(kusok_index)), hash(float(kusok_index)+15.43), hash(float(kusok_index)+34.));//kusok.emissive.rgb;
continue;
}
#if 1
if (kusok.leaf != 0xffffffff) {
const uint num_emissive_kusochki = uint(light_leaves[kusok.leaf].num_slights);
//const uint num_emissive_kusochki = emissive_kusochki.num_kusochki;
for (uint i = 0; i < num_emissive_kusochki; ++i) {
const uint index_into_emissive_kusochki = uint(light_leaves[kusok.leaf].slights[i]);
//const uint index_into_emissive_kusochki = i;
const uint emissive_kusok_index = emissive_kusochki.kusochki[index_into_emissive_kusochki].kusok_index;
const Kusok ekusok = kusochki[emissive_kusok_index];
const vec3 emissive = emissive_kusochki.kusochki[index_into_emissive_kusochki].emissive_color.rgb;
const uint picked_tri = rand_range(kusok.triangles);
for (uint ti = 0; ti < kusok.triangles; ++ti) {
const uint first_index_offset = kusok.index_offset + ti * 3;
// TODO this is not entirely correct -- need to mix between all normals, or have this normal precomputed
const uint vi1 = uint(indices[first_index_offset+0]) + kusok.vertex_offset;
const vec3 n1 = vertices[vi1].normal;
// if (dot(n1, normal) >= 0. /* TODO epsilon */ )
// if (i != picked_light) {
// continue;
// }
if (picked_tri > ti)
if (emissive_kusok_index == kusok_index) {
// TODO do we need to do this when we have textures?
//C += kc * vec3(hash(float(kusok_index)), hash(float(kusok_index)+15.43), hash(float(kusok_index)+34.));//kusok.emissive.rgb;
//C = vec3(1., 0., 1.);
if (bounce == 0)
C += kc * emissive;
continue;
}
// TODO random sample point on the entire kusok geometry
const uint vi2 = uint(indices[first_index_offset+1]) + kusok.vertex_offset;
const uint vi3 = uint(indices[first_index_offset+2]) + kusok.vertex_offset;
const uint picked_tri = rand_range(ekusok.triangles);
for (uint ti = 0; ti < ekusok.triangles; ++ti) {
const uint first_index_offset = ekusok.index_offset + ti * 3;
const vec3 sample_pos = mix(mix(
vertices[vi1].pos, vertices[vi2].pos, rand01()
), vertices[vi3].pos, rand01());
// TODO this is not entirely correct -- need to mix between all normals, or have this normal precomputed
const uint vi1 = uint(indices[first_index_offset+0]) + ekusok.vertex_offset;
const vec3 n1 = vertices[vi1].normal;
// if (dot(n1, normal) >= 0. /* TODO epsilon */ )
// continue;
// const vec3 n2 = vertices[vi2].normal;
// const vec3 n3 = vertices[vi3].normal;
if (picked_tri > ti)
continue;
vec3 light_dir = sample_pos - pos;
if (dot(light_dir, normal) <= 0.)
continue;
// TODO random sample point on the entire ekusok geometry
const uint vi2 = uint(indices[first_index_offset+1]) + ekusok.vertex_offset;
const uint vi3 = uint(indices[first_index_offset+2]) + ekusok.vertex_offset;
const float light_dist = length(light_dir);
light_dir /= light_dist;
if (shadowed(pos + .01 * normal, light_dir, light_dist))
continue;
const vec3 sample_pos = mix(mix(
vertices[vi1].pos, vertices[vi2].pos, rand01()
), vertices[vi3].pos, rand01());
// TODO
const float brightness_fudge = 1000.;
//const vec3 emissive = kusochki[kusok_index].emissive.rgb;
//C += brightness_fudge * kc * baseColor * emissive * dot(light_dir, normal) / (light_dist * light_dist);
//const vec3 sample_pos = vertices[vi1].pos;
// Sample just one triangle
break;
// const vec3 n2 = vertices[vi2].normal;
// const vec3 n3 = vertices[vi3].normal;
vec3 light_dir = sample_pos - pos;
if (dot(light_dir, normal) <= 0.) {
//C = vec3(1., 0., 1.);
continue;
}
const float light_dist = length(light_dir);
light_dir /= light_dist;
if (shadowed(pos + normal_offset_fudge * normal, light_dir, light_dist - shadow_offset_fudge)) {
//C = vec3(0., 1., 0.);
continue;
}
// TODO
const float brightness_fudge = 100.;
C += brightness_fudge * kc * baseColor * emissive * dot(light_dir, normal) / (light_dist * light_dist);
// Sample just one triangle
break;
}
}
}
#endif
@ -297,7 +383,7 @@ void main() {
const float d2 = dot(light_dir, light_dir);
const float light_dist = sqrt(d2);
if (shadowed(pos + .01 * normal, light_dir_norm, light_dist))
if (shadowed(pos + .01 * normal, light_dir_norm, light_dist + shadow_offset_fudge))
continue;
const float r2 = light_pos_r.w * light_pos_r.w;
@ -323,13 +409,12 @@ void main() {
} // for all bounces
//C = mix(C, vec3(1.), printText(vec2(1.,-1.) * vec2(gl_GlobalInvocationID.xy) + vec2(0., imageSize(image).y)));
//C = mix(C, vec3(1.), printText(vec2(1.,-1.) * vec2(gl_GlobalInvocationID.xy) + vec2(0., imageSize(image).y)));
C = mix(C, vec3(1.), printText(vec2(1.,-1.) * vec2(gl_GlobalInvocationID.xy) + vec2(0., imageSize(image).y)));
//if (gl_GlobalInvocationID.x > imageSize(image).x / 2)
if (false)
if (true)
{
const float wet = .5;
C = mix(C, imageLoad(previous_frame, ivec2(gl_GlobalInvocationID.xy)).rgb, wet);
C = mix(C, imageLoad(previous_frame, ivec2(gl_GlobalInvocationID.xy)).rgb, pc.prev_frame_blend_factor);
}
imageStore(image, ivec2(gl_GlobalInvocationID.xy), vec4(C, 1.));
}

View File

@ -10,6 +10,7 @@
#include "vk_lightmap.h"
#include "vk_scene.h"
#include "vk_render.h"
#include "vk_light.h"
#include "ref_params.h"
#include "eiface.h"
@ -212,7 +213,8 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
{
for( int i = 0; i < mod->nummodelsurfaces; ++i)
{
msurface_t *surf = mod->surfaces + mod->firstmodelsurface + i;
const int surface_index = mod->firstmodelsurface + i;
msurface_t *surf = mod->surfaces + surface_index;
mextrasurf_t *info = surf->info;
vk_render_geometry_t *model_geometry = bmodel->render_model.geometries + num_surfaces;
const float sample_size = gEngine.Mod_SampleSizeForFace( surf );
@ -241,6 +243,8 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
model_geometry->vertex_offset = 0;
model_geometry->texture = t;
model_geometry->vertex_count = surf->numedges;
model_geometry->leaf = surface_index < g_lights.num_surfaces ? g_lights.surfaces[surface_index].leaf : -1;
model_geometry->surface_index = i;
VK_CreateSurfaceLightmap( surf, mod );

View File

@ -380,12 +380,17 @@ static qboolean pickAndCreateDevice( void )
.accelerationStructure = VK_TRUE,
.pNext = &buffer_address_feature,
};
VkPhysicalDevice8BitStorageFeatures eight_bit_feature = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES,
.pNext = &accel_feature,
.storageBuffer8BitAccess = VK_TRUE,
.uniformAndStorageBuffer8BitAccess = VK_TRUE,
};
VkPhysicalDeviceRayQueryFeaturesKHR ray_query_feature = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR,
.rayQuery = VK_TRUE,
.pNext = &accel_feature,
.pNext = &eight_bit_feature,
};
VkDeviceCreateInfo create_info = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = vk_core.rtx ? &ray_query_feature : NULL,

View File

@ -13,4 +13,5 @@ void VK_LoadCvars( void )
cl_lightstyle_lerping = gEngine.pfnGetCvarPointer( "cl_lightstyle_lerping", 0 );
r_drawentities = gEngine.pfnGetCvarPointer( "r_drawentities", 0 );
vk_rtx_bounces = gEngine.Cvar_Get( "vk_rtx_bounces", "2", FCVAR_ARCHIVE, "RTX path tracing ray bounces" );
vk_rtx_prev_frame_blend_factor = gEngine.Cvar_Get("vk_rtx_prev_frame_blend_factor", "0.1", FCVAR_ARCHIVE, "RTX path tracer ghetto temporal denoiser strength");
}

View File

@ -10,6 +10,7 @@ void VK_LoadCvars( void );
X(r_lighting_modulate) \
X(cl_lightstyle_lerping) \
X(vk_rtx_bounces) \
X(vk_rtx_prev_frame_blend_factor) \
#define EXTERN_CVAR(cvar) extern cvar_t *cvar;
DECLARE_CVAR(EXTERN_CVAR)

View File

@ -384,22 +384,20 @@ static void initPVL( void ) {
Mem_Free(g_lights.leaves);
}
if (g_lights.surfaces) {
Mem_Free(g_lights.surfaces);
}
g_lights.num_leaves = map->numleafs;
g_lights.leaves = Mem_Malloc(vk_core.pool, g_lights.num_leaves * sizeof(vk_light_leaf_t));
g_lights.frame_number = -1;
g_lights.num_surfaces = map->nummarksurfaces;
g_lights.surfaces = Mem_Malloc(vk_core.pool, g_lights.num_surfaces * sizeof(*g_lights.surfaces));
g_lights.num_emissive_surfaces = 0;
}
void VK_LightsLoad( void ) {
parseStaticLightEntities();
initPVL();
// FIXME ...
initHackRadTable();
}
void VK_LightsBakePVL( int frame_number ) {
static void bakeLights( void ) {
const model_t *map = gEngine.pfnGetModelByIndex( 1 );
const world_static_t *world = gEngine.GetWorld();
@ -476,6 +474,8 @@ void VK_LightsBakePVL( int frame_number ) {
ASSERT(surface_index >= 0);
ASSERT(surface_index < map->numsurfaces);
g_lights.surfaces[surface_index].leaf = leaf->cluster;
// TODO entity transformation
// TODO ^^^ we need to bake it per-entity probably
@ -574,5 +574,14 @@ void VK_LightsBakePVL( int frame_number ) {
Mem_Free(surface_to_emissive_surface_map);
Mem_Free(eigenlicht);
g_lights.frame_number = frame_number;
}
void VK_LightsLoadMap( void ) {
parseStaticLightEntities();
initPVL();
// FIXME ...
initHackRadTable();
bakeLights();
}

View File

@ -15,7 +15,7 @@ typedef struct {
extern vk_emissive_texture_table_t g_emissive_texture_table[MAX_TEXTURES];
void VK_LightsLoad( void );
void VK_LightsLoadMap( void );
typedef struct {
uint8_t num_dlights;
@ -30,18 +30,19 @@ typedef struct {
} vk_emissive_surface_t;
typedef struct {
int frame_number;
// TODO make this opaque light clusters
int num_leaves; // same as worldmodel->numleaves
vk_light_leaf_t *leaves;
int num_emissive_surfaces;
vk_emissive_surface_t emissive_surfaces[256]; // indexed by uint8_t
int num_surfaces;
struct {
int leaf;
} *surfaces;
} vk_potentially_visible_lights_t;
extern vk_potentially_visible_lights_t g_lights;
void VK_LightsBakePVL( int frame_number );
void VK_LightsShutdown( void );

View File

@ -74,6 +74,7 @@ typedef struct {
uint32_t element_count;
uint32_t index_offset, vertex_offset;
uint32_t vertex_count;
int leaf, surface_index;
// TODO potentially dynamic int light_cluster;
} vk_render_geometry_t;

View File

@ -18,7 +18,8 @@
#define MAX_KUSOCHKI 8192
#define MAX_SCRATCH_BUFFER (16*1024*1024)
#define MAX_ACCELS_BUFFER (64*1024*1024)
#define MAX_LIGHT_TEXTURES 256
#define MAX_EMISSIVE_KUSOCHKI 256
#define MAX_LIGHT_LEAVES 8192
// TODO settings/realtime modifiable/adaptive
#define FRAME_WIDTH 1280
@ -40,20 +41,24 @@ typedef struct {
uint32_t index_offset;
uint32_t vertex_offset;
uint32_t triangles;
//uint32_t leaf;
uint32_t leaf;
uint32_t num_dlights;
uint32_t num_surface_lights;
uint32_t emissive;
//float sad_padding_[1];
//vec4_t emissive;
} vk_kusok_data_t;
typedef struct {
uint32_t num_lighttextures;
uint32_t num_kusochki;
uint32_t padding__[3];
struct {
// TODO should we move emissive here?
uint32_t kusok_index;
uint32_t padding__[3];
} lighttexture[MAX_LIGHT_TEXTURES];
} vk_lighttexture_data_t;
vec3_t emissive_color;
uint32_t padding___;
} kusochki[MAX_EMISSIVE_KUSOCHKI];
} vk_emissive_kusochki_t;
typedef struct {
matrix3x4 transform_row;
@ -64,6 +69,7 @@ typedef struct {
typedef struct {
float t;
int bounces;
float prev_frame_blend_factor;
} vk_rtx_push_constants_t;
static struct {
@ -82,7 +88,8 @@ static struct {
vk_buffer_t kusochki_buffer;
// TODO this should really be a single uniform buffer for matrices and light data
vk_buffer_t lighttextures_buffer;
vk_buffer_t emissive_kusochki_buffer;
vk_buffer_t light_leaves_buffer;
VkAccelerationStructureKHR tlas;
@ -205,6 +212,22 @@ void VK_RayNewMap( void ) {
g_rtx.map.buffer_offset = 0;
g_rtx.map.num_kusochki = 0;
// Upload light leaves
ASSERT(g_lights.num_leaves <= MAX_LIGHT_LEAVES);
memcpy(g_rtx.light_leaves_buffer.mapped, g_lights.leaves, g_lights.num_leaves * sizeof(vk_light_leaf_t));
// Upload emissive kusochki
{
vk_emissive_kusochki_t *ek = g_rtx.emissive_kusochki_buffer.mapped;
ASSERT(g_lights.num_emissive_surfaces <= MAX_EMISSIVE_KUSOCHKI);
memset(ek, 0, sizeof(*ek));
ek->num_kusochki = g_lights.num_emissive_surfaces;
// for (int i = 0; i < g_lights.num_emissive_surfaces; ++i) {
// VectorCopy(g_lights.emissive_surfaces[i].emissive, ek->kusochki[i].emissive_color);
// ek->kusochki[i].kusok_index = g_lights.emissive_surfaces[i].surface_index;
// }
}
}
void VK_RayFrameBegin( void )
@ -447,8 +470,13 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
.offset = args->dlights.offset,
.range = args->dlights.size,
};
const VkDescriptorBufferInfo dbi_lighttextures = {
.buffer = g_rtx.lighttextures_buffer.buffer,
const VkDescriptorBufferInfo dbi_emissive_kusochki = {
.buffer = g_rtx.emissive_kusochki_buffer.buffer,
.offset = 0,
.range = VK_WHOLE_SIZE,
};
const VkDescriptorBufferInfo dbi_light_leaves = {
.buffer = g_rtx.light_leaves_buffer.buffer,
.offset = 0,
.range = VK_WHOLE_SIZE,
};
@ -523,7 +551,7 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
.dstSet = g_rtx.desc_set,
.dstBinding = 7,
.dstArrayElement = 0,
.pBufferInfo = &dbi_lighttextures,
.pBufferInfo = &dbi_emissive_kusochki,
},
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
@ -534,6 +562,15 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
.dstArrayElement = 0,
.pImageInfo = &dii_src,
},
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.dstSet = g_rtx.desc_set,
.dstBinding = 9,
.dstArrayElement = 0,
.pBufferInfo = &dbi_light_leaves,
},
};
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
@ -575,6 +612,7 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
vk_rtx_push_constants_t push_constants = {
.t = gpGlobals->realtime,
.bounces = vk_rtx_bounces->value,
.prev_frame_blend_factor = vk_rtx_prev_frame_blend_factor->value,
};
vkCmdPushConstants(cmdbuf, g_rtx.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(push_constants), &push_constants);
}
@ -685,6 +723,11 @@ static void createLayouts( void ) {
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
}, {
.binding = 9,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
},
};
@ -710,7 +753,7 @@ static void createLayouts( void ) {
{
VkDescriptorPoolSize pools[] = {
{.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .descriptorCount = 2},
{.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 3},
{.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 4},
{.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = 3},
{.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, .descriptorCount = 1},
};
@ -772,14 +815,20 @@ qboolean VK_RayInit( void )
// FIXME complain, handle
return false;
}
if (!createBuffer(&g_rtx.lighttextures_buffer, sizeof(vk_lighttexture_data_t),
if (!createBuffer(&g_rtx.emissive_kusochki_buffer, sizeof(vk_emissive_kusochki_t),
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT /* | VK_BUFFER_USAGE_TRANSFER_DST_BIT */,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
// FIXME complain, handle
return false;
}
if (!createBuffer(&g_rtx.light_leaves_buffer, sizeof(vk_light_leaf_t) * MAX_LIGHT_LEAVES,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT /* | VK_BUFFER_USAGE_TRANSFER_DST_BIT */,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
// FIXME complain, handle
return false;
}
createLayouts();
createPipeline();
@ -855,7 +904,8 @@ void VK_RayShutdown( void )
destroyBuffer(&g_rtx.accels_buffer);
destroyBuffer(&g_rtx.tlas_geom_buffer);
destroyBuffer(&g_rtx.kusochki_buffer);
destroyBuffer(&g_rtx.lighttextures_buffer);
destroyBuffer(&g_rtx.emissive_kusochki_buffer);
destroyBuffer(&g_rtx.light_leaves_buffer);
}
qboolean VK_RayModelInit( vk_ray_model_init_t args ) {
@ -915,6 +965,30 @@ qboolean VK_RayModelInit( vk_ray_model_init_t args ) {
kusochki[i].vertex_offset = vertex_offset;
kusochki[i].index_offset = index_offset;
kusochki[i].triangles = prim_count;
kusochki[i].leaf = mg->leaf;
kusochki[i].emissive = ((mg->texture >= 0 && mg->texture < MAX_TEXTURES)
? g_emissive_texture_table[mg->texture].set
: 0);
if (mg->leaf >= 0 && mg->leaf < g_lights.num_leaves)
{
const vk_light_leaf_t* leaflight = g_lights.leaves + mg->leaf;
kusochki[i].num_dlights = leaflight->num_dlights;
kusochki[i].num_surface_lights = leaflight->num_slights;
} else {
kusochki[i].num_dlights = kusochki[i].num_surface_lights = 0;
}
if (kusochki[i].emissive && mg->surface_index >= 0) {
vk_emissive_kusochki_t *ek = g_rtx.emissive_kusochki_buffer.mapped;
for (int j = 0; j < g_lights.num_emissive_surfaces; ++j) {
if (mg->surface_index == g_lights.emissive_surfaces[j].surface_index) {
VectorCopy(g_lights.emissive_surfaces[j].emissive, ek->kusochki[j].emissive_color);
ek->kusochki[j].kusok_index = i + args.model->rtx.kusochki_offset;
break;
}
}
}
}
{

View File

@ -11,6 +11,7 @@
#include "vk_global.h"
#include "vk_beams.h"
#include "vk_light.h"
#include "vk_rtx.h"
#include "com_strings.h"
#include "ref_params.h"
@ -100,6 +101,8 @@ void R_NewMap( void )
// This is to ensure that we have computed lightstyles properly
VK_RunLightStyles();
VK_LightsLoadMap();
// TODO should we do something like VK_BrushBeginLoad?
VK_BrushStatsClear();
@ -109,7 +112,8 @@ void R_NewMap( void )
// This leads to ASSERTS firing when trying to draw erased buffers.
VK_RenderBufferClearMap();
VK_LightsLoad();
if (vk_core.rtx)
VK_RayNewMap();
// Load all models at once
gEngine.Con_Reportf( "Num models: %d:\n", num_models );