Skip to content
This repository was archived by the owner on Dec 11, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions baseq2/q2rtx.menu
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ begin video
toggle "AMD FSR 1.0" flt_fsr_enable
range --status "lower is sharper" "AMD FSR 1.0 sharpness" flt_fsr_sharpness 0 2 0.01
pairs "global illumination" pt_num_bounce_rays low 0.5 medium 1 high 2
pairs "direct light sampling" pt_restir "RIS light" 0 "ReSTIR, high quality" 1 "ReSTIR, half" 2 "ReSTIR, quarter" 3
pairs "reflection/refraction depth" pt_reflect_refract off 0 1 1 2 2 4 4 8 8
toggle --status "turn some monitors in the game into security camera views" \
"security cameras" pt_cameras
Expand Down
1 change: 1 addition & 0 deletions cmake/compileShaders.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ set(SHADER_SOURCE_DEPENDENCIES
${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/precomputed_sky.glsl
${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/precomputed_sky_params.h
${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/projection.glsl
${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/restir.h
${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/sky.h
${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/tiny_encryption_algorithm.h
${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/tone_mapping_utils.glsl
Expand Down
7 changes: 7 additions & 0 deletions doc/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,13 @@ Selects the projection to use for rendering. Default value is 0.
#### `pt_reflect_refract`
Number of reflection or refraction bounces to trace. Default value is 2.

#### `pt_restir`
Switch for experimental direct light sampling algorithms. Default value is 1.
- 0 — RIS light sampling.
- 1 — ReSTIR, high quality.
- 2 — ReSTIR El-Cheapo, uses half of the shadow rays.
- 3 — ReSTIR El-Very-Cheapo, uses one quarter of the shadow rays.

#### `pt_roughness_override`
Global override for roughness of all materials. Negative values mean there is no
override. Default value is -1.
Expand Down
1 change: 1 addition & 0 deletions inc/refresh/models.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ typedef struct light_poly_s {
int cluster;
int style;
float emissive_factor;
int type;
} light_poly_t;

typedef struct maliasmesh_s maliasmesh_t;
Expand Down
4 changes: 4 additions & 0 deletions src/refresh/vkpt/bsp_mesh.c
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,7 @@ collect_one_light_poly_entire_texture(bsp_t *bsp, mface_t *surf, mtexinfo_t *tex

light.material = texinfo->material;
light.style = light_style;
light.type = LIGHT_POLYGON;

if(!get_triangle_off_center(light.positions, light.off_center, NULL, 1.f))
continue;
Expand Down Expand Up @@ -1113,6 +1114,7 @@ collect_one_light_poly(bsp_t *bsp, mface_t *surf, mtexinfo_t *texinfo, int model
light_poly_t* light = append_light_poly(num_lights, allocated_lights, lights);
light->material = texinfo->material;
light->style = light_style;
light->type = LIGHT_POLYGON;
light->emissive_factor = emissive_factor;
VectorCopy(instance_positions[0], light->positions + 0);
VectorCopy(instance_positions[i1], light->positions + 3);
Expand Down Expand Up @@ -1328,6 +1330,7 @@ collect_sky_and_lava_light_polys(bsp_mesh_t *wm, bsp_t* bsp)
}

light.style = 0;
light.type = LIGHT_POLYGON;

if (!get_triangle_off_center(light.positions, light.off_center, NULL, 1.f))
continue;
Expand Down Expand Up @@ -1821,6 +1824,7 @@ bsp_mesh_create_custom_sky_prims(uint32_t* prim_ctr, bsp_mesh_t* wm, const bsp_t
light->material = 0;
light->style = 0;
light->cluster = cluster;
light->type = LIGHT_POLYGON;

++*prim_ctr;

Expand Down
10 changes: 10 additions & 0 deletions src/refresh/vkpt/conversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ static inline float halfToFloat(uint16_t value)
return v.f;
}

static inline float uintBitsToFloat(uint32_t ui)
{
union {
float f;
uint32_t ui;
} bits;
bits.ui = ui;
return bits.f;
}

void packHalf4x16(uint32_t* half, float* vec4);

#endif // CONVERSION_H_
135 changes: 93 additions & 42 deletions src/refresh/vkpt/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1666,20 +1666,14 @@ destroy_vulkan(void)
return 0;
}

typedef struct entity_hash_s {
unsigned int mesh : 8;
unsigned int model : 9;
unsigned int entity : 14;
unsigned int bsp : 1;
} entity_hash_t;

static int entity_frame_num = 0;
static uint32_t model_entity_ids[2][MAX_MODEL_INSTANCES];
static int model_entity_id_count[2];
static int light_entity_ids[2][MAX_MODEL_LIGHTS];
static int light_entity_id_count[2];
static int iqm_matrix_count[2];
static ModelInstance model_instances_prev[MAX_MODEL_INSTANCES];

#define MAX_MODEL_LIGHTS 16384
static int num_model_lights = 0;
static light_poly_t model_lights[MAX_MODEL_LIGHTS];

Expand Down Expand Up @@ -1808,47 +1802,70 @@ static void fill_model_instance(ModelInstance* instance, const entity_t* entity,
instance->material |= MATERIAL_FLAG_LIGHT;
}

static void add_dlight_spot(const dlight_t* light, DynLightData* dynlight_data)
static void add_dlight_spot(const dlight_t* dlight, light_poly_t* light)
{
// Copy spot data
VectorCopy(light->spot.direction, dynlight_data->spot_direction);
switch(light->spot.emission_profile)
VectorCopy(dlight->spot.direction, light->positions + 6);
uint spot_type = 0, spot_data = 0;
switch(dlight->spot.emission_profile)
{
case DLIGHT_SPOT_EMISSION_PROFILE_FALLOFF:
dynlight_data->type |= DYNLIGHT_SPOT_EMISSION_PROFILE_FALLOFF << 16;
dynlight_data->spot_data = floatToHalf(light->spot.cos_total_width) | (floatToHalf(light->spot.cos_falloff_start) << 16);
spot_type = DYNLIGHT_SPOT_EMISSION_PROFILE_FALLOFF;
spot_data = floatToHalf(dlight->spot.cos_total_width) | (floatToHalf(dlight->spot.cos_falloff_start) << 16);
break;
case DLIGHT_SPOT_EMISSION_PROFILE_AXIS_ANGLE_TEXTURE:
dynlight_data->type |= DYNLIGHT_SPOT_EMISSION_PROFILE_AXIS_ANGLE_TEXTURE << 16;
dynlight_data->spot_data = floatToHalf(light->spot.total_width) | (light->spot.texture << 16);
spot_type = DYNLIGHT_SPOT_EMISSION_PROFILE_AXIS_ANGLE_TEXTURE;
spot_data = floatToHalf(dlight->spot.total_width) | (dlight->spot.texture << 16);
break;
}
light->positions[4] = uintBitsToFloat(spot_type);
light->positions[5] = uintBitsToFloat(spot_data);
}

static void
add_dlights(const dlight_t* lights, int num_lights, QVKUniformBuffer_t* ubo)
add_dlights(const dlight_t* dlights, int num_dlights, light_poly_t* light_list, int* num_lights, int max_lights, bsp_t *bsp, int* light_entity_ids)
{
ubo->num_dyn_lights = 0;

for (int i = 0; i < num_lights; i++)
for (int i = 0; i < num_dlights; i++)
{
const dlight_t* light = lights + i;

DynLightData* dynlight_data = ubo->dyn_light_data + ubo->num_dyn_lights;
VectorCopy(light->origin, dynlight_data->center);
VectorScale(light->color, light->intensity / 25.f, dynlight_data->color);
dynlight_data->radius = light->radius;
switch(light->light_type) {
case DLIGHT_SPHERE:
dynlight_data->type = DYNLIGHT_SPHERE;
break;
case DLIGHT_SPOT:
dynlight_data->type = DYNLIGHT_SPOT;
add_dlight_spot(light, dynlight_data);
break;
}
if (*num_lights >= max_lights)
return;

const dlight_t* dlight = dlights + i;
light_poly_t* light = light_list + *num_lights;

ubo->num_dyn_lights++;
light->cluster = BSP_PointLeaf(bsp->nodes, dlight->origin)->cluster;

entity_hash_t hash;
hash.entity = i + 1; //entity ID
hash.mesh = 0xAA;

if(light->cluster >= 0)
{
//Super wasteful but we want to have all lights in the same list.

VectorCopy(dlight->origin, light->positions + 0);
VectorScale(dlight->color, dlight->intensity / 25.f, light->color);
light->positions[3] = dlight->radius;
light->material = NULL;
light->style = 0;

switch(dlight->light_type) {
case DLIGHT_SPHERE:
light->type = LIGHT_SPHERE;
hash.model = 0xFE;
break;
case DLIGHT_SPOT:
light->type = LIGHT_SPOT;
// Copy spot data
add_dlight_spot(dlight, light);
hash.model = 0xFD;
break;
}

light_entity_ids[(*num_lights)] = *(uint32_t*)&hash;
(*num_lights)++;

}
}
}

Expand All @@ -1860,7 +1877,7 @@ static inline void transform_point(const float* p, const float* matrix, float* r
VectorCopy(transformed, result); // vec4 -> vec3
}

static void instance_model_lights(int num_light_polys, const light_poly_t* light_polys, const float* transform)
static void instance_model_lights(int num_light_polys, const light_poly_t* light_polys, const float* transform, entity_hash_t hash)
{
for (int nlight = 0; nlight < num_light_polys; nlight++)
{
Expand Down Expand Up @@ -1890,10 +1907,15 @@ static void instance_model_lights(int num_light_polys, const light_poly_t* light
VectorCopy(src_light->color, dst_light->color);
dst_light->material = src_light->material;
dst_light->style = src_light->style;
dst_light->type = LIGHT_POLYGON;

hash.mesh = nlight; //More a light index than a mesh
light_entity_ids[entity_frame_num][num_model_lights] = *(uint32_t*)&hash;

num_model_lights++;
}
}

static const mat4 g_identity_transform = {
{ 1.f, 0.f, 0.f, 0.f },
{ 0.f, 1.f, 0.f, 0.f },
Expand Down Expand Up @@ -1973,7 +1995,7 @@ static void process_bsp_entity(const entity_t* entity, int* instance_count)
mi->render_buffer_idx = VERTEX_BUFFER_WORLD;
mi->render_prim_offset = model->geometry.prim_offsets[0];

instance_model_lights(model->num_light_polys, model->light_polys, transform);
instance_model_lights(model->num_light_polys, model->light_polys, transform, hash);

if (model->geometry.accel)
{
Expand Down Expand Up @@ -2166,7 +2188,13 @@ static void process_regular_entity(
mult_matrix_vector(end, transform, offset2);
VectorSet(color, 0.25f, 0.5f, 0.07f);

vkpt_build_cylinder_light(model_lights, &num_model_lights, MAX_MODEL_LIGHTS, bsp_world_model, begin, end, color, 1.5f);
entity_hash_t hash;
hash.entity = entity->id;
hash.model = entity->model;
hash.mesh = 0;
hash.bsp = 0;

vkpt_build_cylinder_light(model_lights, &num_model_lights, MAX_MODEL_LIGHTS, bsp_world_model, begin, end, color, 1.5f, hash, light_entity_ids[entity_frame_num]);
}

*instance_count = current_instance_index;
Expand Down Expand Up @@ -2241,7 +2269,13 @@ prepare_entities(EntityUploadInfo* upload_info)
else
create_entity_matrix(transform, (entity_t*)entity);

instance_model_lights(model->num_light_polys, model->light_polys, transform);
entity_hash_t hash;
hash.entity = i + 1;
hash.model = ~entity->model;
hash.mesh = 0;
hash.bsp = 0;

instance_model_lights(model->num_light_polys, model->light_polys, transform, hash);
}
}
}
Expand Down Expand Up @@ -2318,6 +2352,7 @@ prepare_entities(EntityUploadInfo* upload_info)

memset(instance_buffer->model_current_to_prev, -1, sizeof(instance_buffer->model_current_to_prev));
memset(instance_buffer->model_prev_to_current, -1, sizeof(instance_buffer->model_prev_to_current));
memset(instance_buffer->mlight_prev_to_current, ~0u, sizeof(instance_buffer->mlight_prev_to_current));

model_entity_id_count[entity_frame_num] = model_instance_idx;
for(int i = 0; i < model_entity_id_count[entity_frame_num]; i++) {
Expand Down Expand Up @@ -2937,8 +2972,6 @@ prepare_ubo(refdef_t *fd, mleaf_t* viewleaf, const reference_mode_t* ref_mode, c
VectorCopy(sky_matrix[0], ubo->environment_rotation_matrix[0]);
VectorCopy(sky_matrix[1], ubo->environment_rotation_matrix[1]);
VectorCopy(sky_matrix[2], ubo->environment_rotation_matrix[2]);

add_dlights(vkpt_refdef.fd->dlights, vkpt_refdef.fd->num_dlights, ubo);

if (wm->num_cameras > 0)
{
Expand All @@ -2955,6 +2988,21 @@ prepare_ubo(refdef_t *fd, mleaf_t* viewleaf, const reference_mode_t* ref_mode, c
ubo->num_cameras = wm->num_cameras;
}

static void
update_mlight_prev_to_current(void)
{
light_entity_id_count[entity_frame_num] = num_model_lights;
for(int i = 0; i < light_entity_id_count[entity_frame_num]; i++) {
entity_hash_t hash = *(entity_hash_t*)&light_entity_ids[entity_frame_num][i];
if(hash.entity == 0u) continue;
for(int j = 0; j < light_entity_id_count[!entity_frame_num]; j++) {
if(light_entity_ids[entity_frame_num][i] == light_entity_ids[!entity_frame_num][j]) {
vkpt_refdef.uniform_instance_buffer.mlight_prev_to_current[j] = i;
break;
}
}
}
}

/* renders the map ingame */
void
Expand Down Expand Up @@ -3043,9 +3091,12 @@ R_RenderFrame_RTX(refdef_t *fd)
vkpt_pt_instance_model_blas(&vkpt_refdef.bsp_mesh_world.geom_sky, g_identity_transform, VERTEX_BUFFER_WORLD, -1, 0);
vkpt_pt_instance_model_blas(&vkpt_refdef.bsp_mesh_world.geom_custom_sky, g_identity_transform, VERTEX_BUFFER_WORLD, -1, 0);

vkpt_build_beam_lights(model_lights, &num_model_lights, MAX_MODEL_LIGHTS, bsp_world_model, fd->entities, fd->num_entities, prev_adapted_luminance);
vkpt_build_beam_lights(model_lights, &num_model_lights, MAX_MODEL_LIGHTS, bsp_world_model, fd->entities, fd->num_entities, prev_adapted_luminance, light_entity_ids[entity_frame_num], &num_model_lights);
add_dlights(vkpt_refdef.fd->dlights, vkpt_refdef.fd->num_dlights, model_lights, &num_model_lights, MAX_MODEL_LIGHTS, bsp_world_model, light_entity_ids[entity_frame_num]);
}

update_mlight_prev_to_current();

vkpt_vertex_buffer_ensure_primbuf_size(upload_info.num_prims);

QVKUniformBuffer_t *ubo = &vkpt_refdef.uniform_buffer;
Expand Down
6 changes: 6 additions & 0 deletions src/refresh/vkpt/path_tracer.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ cvar_t* cvar_pt_enable_sprites = NULL;

extern cvar_t *cvar_pt_caustics;
extern cvar_t *cvar_pt_reflect_refract;
extern cvar_t *cvar_pt_restir;


typedef struct QvkGeometryInstance_s {
Expand Down Expand Up @@ -1139,6 +1140,11 @@ vkpt_pt_trace_lighting(VkCommandBuffer cmd_buf, float num_bounce_rays)
BARRIER_COMPUTE(cmd_buf, qvk.images[VKPT_IMG_PT_COLOR_HF]);
BARRIER_COMPUTE(cmd_buf, qvk.images[VKPT_IMG_PT_COLOR_SPEC]);

if(cvar_pt_restir->value != 0) {
int frame_idx = qvk.frame_counter & 1;
BARRIER_COMPUTE(cmd_buf, qvk.images[VKPT_IMG_PT_RESTIR_A + frame_idx]);
}

BUFFER_BARRIER(cmd_buf,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
Expand Down
8 changes: 5 additions & 3 deletions src/refresh/vkpt/shader/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MAX_TLAS_INSTANCES (MAX_MODEL_INSTANCES + MAX_RESERVED_INSTANCES)
#define MAX_LIGHT_SOURCES 32
#define MAX_LIGHT_STYLES 64
#define MAX_MODEL_LIGHTS 16384

#define TLAS_INDEX_GEOMETRY 0
#define TLAS_INDEX_EFFECTS 1
Expand Down Expand Up @@ -161,9 +162,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define M_PI 3.1415926535897932384626433832795
#endif

// Dynamic light types
#define DYNLIGHT_SPHERE 0
#define DYNLIGHT_SPOT 1
// Light types
#define LIGHT_POLYGON 0
#define LIGHT_SPHERE 1
#define LIGHT_SPOT 2

//
// Spotlight styles (emission profiles)
Expand Down
Loading