diff --git a/ref_vk/TODO.md b/ref_vk/TODO.md index 51ae01af..5633ea72 100644 --- a/ref_vk/TODO.md +++ b/ref_vk/TODO.md @@ -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 diff --git a/ref_vk/shaders/rtx.comp b/ref_vk/shaders/rtx.comp index 4eebf15e..9b7fc671 100644 --- a/ref_vk/shaders/rtx.comp +++ b/ref_vk/shaders/rtx.comp @@ -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.)); } diff --git a/ref_vk/vk_brush.c b/ref_vk/vk_brush.c index 22f19a65..4719da74 100644 --- a/ref_vk/vk_brush.c +++ b/ref_vk/vk_brush.c @@ -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 ); diff --git a/ref_vk/vk_core.c b/ref_vk/vk_core.c index c6aa38a6..dc34a7c9 100644 --- a/ref_vk/vk_core.c +++ b/ref_vk/vk_core.c @@ -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, diff --git a/ref_vk/vk_cvar.c b/ref_vk/vk_cvar.c index b45b4dad..418df447 100644 --- a/ref_vk/vk_cvar.c +++ b/ref_vk/vk_cvar.c @@ -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"); } diff --git a/ref_vk/vk_cvar.h b/ref_vk/vk_cvar.h index 98e4515d..c7ca6e18 100644 --- a/ref_vk/vk_cvar.h +++ b/ref_vk/vk_cvar.h @@ -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) diff --git a/ref_vk/vk_light.c b/ref_vk/vk_light.c index 172c1a3f..a4b613af 100644 --- a/ref_vk/vk_light.c +++ b/ref_vk/vk_light.c @@ -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(); } diff --git a/ref_vk/vk_light.h b/ref_vk/vk_light.h index 0891730f..1bc18b9c 100644 --- a/ref_vk/vk_light.h +++ b/ref_vk/vk_light.h @@ -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 ); diff --git a/ref_vk/vk_render.h b/ref_vk/vk_render.h index 2e7979f5..3c1dace0 100644 --- a/ref_vk/vk_render.h +++ b/ref_vk/vk_render.h @@ -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; diff --git a/ref_vk/vk_rtx.c b/ref_vk/vk_rtx.c index 68635937..3364a07d 100644 --- a/ref_vk/vk_rtx.c +++ b/ref_vk/vk_rtx.c @@ -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; + } + } + } } { diff --git a/ref_vk/vk_scene.c b/ref_vk/vk_scene.c index 089ee034..306160f1 100644 --- a/ref_vk/vk_scene.c +++ b/ref_vk/vk_scene.c @@ -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 );