Merge pull request #652 from w23/stream-E331b

Thing done during stream E331

- [x] add `trihash` option to  `rt_debug_display_only` cvar
- [x] fix #465 
  - [x] update UVs
  - [ ] fix validation woes -- cannot reproduce anymore
This commit is contained in:
Ivan Avdeev 2023-11-16 10:10:33 -08:00 committed by GitHub
commit 414c43f7a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 211 additions and 92 deletions

View File

@ -2,7 +2,10 @@
- [x] Emissive waters
- [x] add emissive water surface to polygon lights
- [x] update emissive color for water surfaces
- [ ] dynamic UVs
- [x] trihash option
- [x] dynamic UVs
- [x] update UVs for conveyors
- [ ] pls don't aggravate validation on changelevel -- cannot reproduce
- [ ] discuss integration test strategies
# 2023-11-14 E330

View File

@ -6,44 +6,40 @@
// xxhash (https://github.com/Cyan4973/xxHash)
// From https://www.shadertoy.com/view/Xt3cDn
uint xxhash32(uint p)
{
uint xxhash32(uint p) {
const uint PRIME32_2 = 2246822519U, PRIME32_3 = 3266489917U;
const uint PRIME32_4 = 668265263U, PRIME32_5 = 374761393U;
uint h32 = p + PRIME32_5;
h32 = PRIME32_4*((h32 << 17) | (h32 >> (32 - 17)));
h32 = PRIME32_2*(h32^(h32 >> 15));
h32 = PRIME32_3*(h32^(h32 >> 13));
return h32^(h32 >> 16);
h32 = PRIME32_2*(h32^(h32 >> 15));
h32 = PRIME32_3*(h32^(h32 >> 13));
return h32^(h32 >> 16);
}
uint xxhash32(uvec2 p)
{
const uint PRIME32_2 = 2246822519U, PRIME32_3 = 3266489917U;
uint xxhash32(uvec2 p) {
const uint PRIME32_2 = 2246822519U, PRIME32_3 = 3266489917U;
const uint PRIME32_4 = 668265263U, PRIME32_5 = 374761393U;
uint h32 = p.y + PRIME32_5 + p.x*PRIME32_3;
h32 = PRIME32_4*((h32 << 17) | (h32 >> (32 - 17)));
h32 = PRIME32_2*(h32^(h32 >> 15));
h32 = PRIME32_3*(h32^(h32 >> 13));
return h32^(h32 >> 16);
uint h32 = p.y + PRIME32_5 + p.x*PRIME32_3;
h32 = PRIME32_4*((h32 << 17) | (h32 >> (32 - 17)));
h32 = PRIME32_2*(h32^(h32 >> 15));
h32 = PRIME32_3*(h32^(h32 >> 13));
return h32^(h32 >> 16);
}
uint xxhash32(uvec3 p)
{
const uint PRIME32_2 = 2246822519U, PRIME32_3 = 3266489917U;
uint xxhash32(uvec3 p) {
const uint PRIME32_2 = 2246822519U, PRIME32_3 = 3266489917U;
const uint PRIME32_4 = 668265263U, PRIME32_5 = 374761393U;
uint h32 = p.z + PRIME32_5 + p.x*PRIME32_3;
h32 = PRIME32_4*((h32 << 17) | (h32 >> (32 - 17)));
h32 += p.y * PRIME32_3;
h32 = PRIME32_4*((h32 << 17) | (h32 >> (32 - 17)));
h32 = PRIME32_2*(h32^(h32 >> 15));
h32 = PRIME32_3*(h32^(h32 >> 13));
return h32^(h32 >> 16);
h32 = PRIME32_2*(h32^(h32 >> 15));
h32 = PRIME32_3*(h32^(h32 >> 13));
return h32^(h32 >> 16);
}
uint xxhash32(uvec4 p)
{
const uint PRIME32_2 = 2246822519U, PRIME32_3 = 3266489917U;
uint xxhash32(uvec4 p) {
const uint PRIME32_2 = 2246822519U, PRIME32_3 = 3266489917U;
const uint PRIME32_4 = 668265263U, PRIME32_5 = 374761393U;
uint h32 = p.w + PRIME32_5 + p.x*PRIME32_3;
h32 = PRIME32_4*((h32 << 17) | (h32 >> (32 - 17)));
@ -51,90 +47,85 @@ uint xxhash32(uvec4 p)
h32 = PRIME32_4*((h32 << 17) | (h32 >> (32 - 17)));
h32 += p.z * PRIME32_3;
h32 = PRIME32_4*((h32 << 17) | (h32 >> (32 - 17)));
h32 = PRIME32_2*(h32^(h32 >> 15));
h32 = PRIME32_3*(h32^(h32 >> 13));
return h32^(h32 >> 16);
h32 = PRIME32_2*(h32^(h32 >> 15));
h32 = PRIME32_3*(h32^(h32 >> 13));
return h32^(h32 >> 16);
}
// https://www.pcg-random.org/
uint pcg(uint v)
{
uint pcg(uint v) {
uint state = v * 747796405u + 2891336453u;
uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
return (word >> 22u) ^ word;
}
uvec2 pcg2d(uvec2 v)
{
v = v * 1664525u + 1013904223u;
uvec2 pcg2d(uvec2 v) {
v = v * 1664525u + 1013904223u;
v.x += v.y * 1664525u;
v.y += v.x * 1664525u;
v.x += v.y * 1664525u;
v.y += v.x * 1664525u;
v = v ^ (v>>16u);
v = v ^ (v>>16u);
v.x += v.y * 1664525u;
v.y += v.x * 1664525u;
v.x += v.y * 1664525u;
v.y += v.x * 1664525u;
v = v ^ (v>>16u);
v = v ^ (v>>16u);
return v;
return v;
}
// http://www.jcgt.org/published/0009/03/02/
uvec3 pcg3d(uvec3 v) {
v = v * 1664525u + 1013904223u;
v = v * 1664525u + 1013904223u;
v.x += v.y*v.z;
v.y += v.z*v.x;
v.z += v.x*v.y;
v.x += v.y*v.z;
v.y += v.z*v.x;
v.z += v.x*v.y;
v ^= v >> 16u;
v ^= v >> 16u;
v.x += v.y*v.z;
v.y += v.z*v.x;
v.z += v.x*v.y;
v.x += v.y*v.z;
v.y += v.z*v.x;
v.z += v.x*v.y;
return v;
return v;
}
// http://www.jcgt.org/published/0009/03/02/
uvec3 pcg3d16(uvec3 v)
{
v = v * 12829u + 47989u;
uvec3 pcg3d16(uvec3 v) {
v = v * 12829u + 47989u;
v.x += v.y*v.z;
v.y += v.z*v.x;
v.z += v.x*v.y;
v.x += v.y*v.z;
v.y += v.z*v.x;
v.z += v.x*v.y;
v.x += v.y*v.z;
v.y += v.z*v.x;
v.z += v.x*v.y;
v.x += v.y*v.z;
v.y += v.z*v.x;
v.z += v.x*v.y;
v >>= 16u;
return v;
return v;
}
// http://www.jcgt.org/published/0009/03/02/
uvec4 pcg4d(uvec4 v)
{
v = v * 1664525u + 1013904223u;
uvec4 pcg4d(uvec4 v) {
v = v * 1664525u + 1013904223u;
v.x += v.y*v.w;
v.y += v.z*v.x;
v.z += v.x*v.y;
v.w += v.y*v.z;
v.x += v.y*v.w;
v.y += v.z*v.x;
v.z += v.x*v.y;
v.w += v.y*v.z;
v ^= v >> 16u;
v ^= v >> 16u;
v.x += v.y*v.w;
v.y += v.z*v.x;
v.z += v.x*v.y;
v.w += v.y*v.z;
v.x += v.y*v.w;
v.y += v.z*v.x;
v.z += v.x*v.y;
v.w += v.y*v.z;
return v;
return v;
}
uint rand01_state = 0;
@ -154,7 +145,7 @@ float rand01() {
}
vec3 rand3_f01(uvec3 seed) {
uvec3 v = pcg3d(seed);
return vec3(uintToFloat01(v.x), uintToFloat01(v.y), uintToFloat01(v.z));
uvec3 v = pcg3d(seed);
return vec3(uintToFloat01(v.x), uintToFloat01(v.y), uintToFloat01(v.z));
}
#endif // NOISE_GLSL_INCLUDED

View File

@ -180,6 +180,7 @@ struct PushConstants {
#define DEBUG_DISPLAY_INDIRECT 9
#define DEBUG_DISPLAY_INDIRECT_SPEC 10
#define DEBUG_DISPLAY_INDIRECT_DIFF 11
#define DEBUG_DISPLAY_TRIHASH 12
// add more when needed
struct UniformBuffer {

View File

@ -106,9 +106,16 @@ void primaryRayHit(rayQueryEXT rq, inout RayPayloadPrimary payload) {
payload.base_color_a *= color;
payload.emissive.rgb *= color.rgb;
if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_SURFHASH) {
if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_DISABLED) {
// Nop
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_SURFHASH) {
const uint hash = xxhash32(geom.kusok_index);
payload.emissive.rgb = vec3(0xff & (hash>>16), 0xff & (hash>>8), 0xff & hash) / 255.;
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_TRIHASH) {
const int primitive_index = rayQueryGetIntersectionPrimitiveIndexEXT(rq, true);
const uint hash = xxhash32(geom.kusok_index + primitive_index * 2246822519U);
payload.emissive.rgb = vec3(0xff & (hash>>16), 0xff & (hash>>8), 0xff & hash) / 255.;
}
}

View File

@ -36,6 +36,14 @@ typedef struct {
vk_render_model_t render_model;
} r_brush_water_model_t;
typedef struct {
float texture_width;
int vertices_count;
int vertices_src_offset;
int vertices_dst_offset;
int geometry_index;
} r_conveyor_t;
typedef struct vk_brush_model_s {
model_t *engine_model;
@ -52,6 +60,10 @@ typedef struct vk_brush_model_s {
r_brush_water_model_t water;
r_brush_water_model_t water_sides;
int conveyors_count;
r_conveyor_t *conveyors;
vk_vertex_t *conveyors_vertices;
} vk_brush_model_t;
typedef struct {
@ -64,6 +76,8 @@ typedef struct {
int num_surfaces, num_vertices, num_indices;
int max_texture_id;
int animated_count;
int conveyors_count;
int conveyors_vertices_count;
water_model_sizes_t water, side_water;
} model_sizes_t;
@ -547,6 +561,7 @@ typedef enum {
BrushSurface_Water,
BrushSurface_WaterSide,
BrushSurface_Sky,
BrushSurface_Conveyor,
} brush_surface_type_e;
static brush_surface_type_e getSurfaceType( const msurface_t *surf, int i, qboolean is_worldmodel ) {
@ -595,9 +610,12 @@ static brush_surface_type_e getSurfaceType( const msurface_t *surf, int i, qbool
if( FBitSet( surf->flags, SURF_DRAWSKY ))
return BrushSurface_Sky;
if( surf->flags & SURF_CONVEYOR ) {
return BrushSurface_Conveyor;
}
//if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS ) ) {
if( surf->flags & ( SURF_DRAWTURB | SURF_DRAWTURB_QUADS ) ) {
//if( surf->flags & ( SURF_DRAWSKY | SURF_CONVEYOR ) ) {
// FIXME don't print this on second sort-by-texture pass
//DEBUG("Skipping surface %d because of flags %08x", i, surf->flags);
return BrushSurface_Hidden;
@ -723,16 +741,12 @@ static void brushDrawWater(r_brush_water_model_t *wmodel, const cl_entity_t *ent
APROF_SCOPE_END(brush_draw_water);
}
#if 0
// TODO use this
static void computeConveyorSpeed(const color24 rendercolor, int tex_index, vec2_t speed) {
static void computeConveyorOffset(const color24 rendercolor, float tex_width, float time, vec2_t out_offset) {
float sy, cy;
float flConveyorSpeed = 0.0f;
float flRate, flAngle;
vk_texture_t *texture = R_TextureGetByIndex( tex_index );
//gl_texture_t *texture;
// FIXME
// TODO
/* if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ) && RI.currententity == gEngfuncs.GetEntityByIndex( 0 ) ) */
/* { */
/* // same as doom speed */
@ -743,16 +757,23 @@ static void computeConveyorSpeed(const color24 rendercolor, int tex_index, vec2_
flConveyorSpeed = (rendercolor.g<<8|rendercolor.b) / 16.0f;
if( rendercolor.r ) flConveyorSpeed = -flConveyorSpeed;
}
//texture = R_GetTexture( glState.currentTextures[glState.activeTMU] );
flRate = fabs( flConveyorSpeed ) / (float)texture->width;
flRate = fabs( flConveyorSpeed ) / tex_width;
flAngle = ( flConveyorSpeed >= 0 ) ? 180 : 0;
// TODO no SinCos, no
SinCos( flAngle * ( M_PI_F / 180.0f ), &sy, &cy );
speed[0] = cy * flRate;
speed[1] = sy * flRate;
out_offset[0] = cy * flRate * time;
out_offset[1] = sy * flRate * time;
// make sure that we are positive
if( out_offset[0] < 0.0f ) out_offset[0] += 1.0f + -(int)out_offset[0];
if( out_offset[1] < 0.0f ) out_offset[1] += 1.0f + -(int)out_offset[1];
// make sure that we are in a [0,1] range
out_offset[0] = out_offset[0] - (int)out_offset[0];
out_offset[1] = out_offset[1] - (int)out_offset[1];
}
#endif
/*
===============
@ -873,7 +894,6 @@ void R_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, con
brushDrawWater(&bmodel->water_sides, ent, bmodel->engine_model->surfaces, render_type, color, transform, bmodel->prev_transform, bmodel->prev_time);
}
++g_brush.stat.models_drawn;
if (bmodel->render_model.num_geometries == 0)
@ -919,6 +939,28 @@ void R_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, con
APROF_SCOPE_END(brush_update_textures);
}
// Move conveyors
for (int i = 0; i < bmodel->conveyors_count; ++i) {
const r_conveyor_t *const conv = bmodel->conveyors + i;
vec2_t offset = {0, 0};
computeConveyorOffset(ent->curstate.rendercolor, conv->texture_width, gpGlobals->time, offset);
ASSERT(conv->geometry_index >= 0);
ASSERT(conv->geometry_index < bmodel->render_model.num_geometries);
const vk_render_geometry_t *const geom = bmodel->render_model.geometries + conv->geometry_index;
const r_geometry_range_lock_t lock = R_GeometryRangeLockSubrange(&bmodel->geometry, conv->vertices_dst_offset, conv->vertices_count);
for (int j = 0; j < conv->vertices_count; ++j) {
const vk_vertex_t *const src = bmodel->conveyors_vertices + conv->vertices_src_offset + j;
vk_vertex_t *const dst = lock.vertices + j;
*dst = *src;
dst->gl_tc[0] = src->gl_tc[0] + offset[0];
dst->gl_tc[1] = src->gl_tc[1] + offset[1];
}
R_GeometryRangeUnlock(&lock);
}
const material_mode_e material_mode = brushMaterialModeForRenderType(render_type);
R_RenderModelDraw(&bmodel->render_model, (r_model_draw_t){
.render_type = render_type,
@ -958,6 +1000,11 @@ static model_sizes_t computeSizes( const model_t *mod, qboolean is_worldmodel )
case BrushSurface_Animated:
sizes.animated_count++;
break;
case BrushSurface_Conveyor:
sizes.conveyors_count++;
sizes.conveyors_vertices_count += surf->numedges;
break;
case BrushSurface_Regular:
case BrushSurface_Sky:
break;
@ -971,9 +1018,10 @@ static model_sizes_t computeSizes( const model_t *mod, qboolean is_worldmodel )
DEBUG("Computed sizes for brush model \"%s\":", mod->name);
DEBUG(" num_surfaces=%d animated_count=%d num_vertices=%d num_indices=%d max_texture_id=%d",
sizes.num_surfaces, sizes.animated_count, sizes.num_vertices, sizes.num_indices, sizes.max_texture_id);
DEBUG(" conveyors_count=%d conveyors_vertices_count=%d",
sizes.conveyors_count, sizes.conveyors_vertices_count);
DEBUG(" water_surfaces=%d water_vertices=%d water_indices=%d",
sizes.water.surfaces, sizes.water.vertices, sizes.water.indices);
DEBUG(" side_water_surfaces=%d side_water_vertices=%d side_water_indices=%d",
sizes.side_water.surfaces, sizes.side_water.vertices, sizes.side_water.indices);
@ -1234,6 +1282,8 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
int vertex_offset = 0;
int num_geometries = 0;
int animated_count = 0;
int conveyors_count = 0;
int conveyors_vertices_count = 0;
vk_vertex_t *p_vert = args.out_vertices;
uint16_t *p_ind = args.out_indices;
@ -1270,6 +1320,9 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
continue;
case BrushSurface_Animated:
args.bmodel->animated_indexes[animated_count++] = num_geometries;
break;
case BrushSurface_Conveyor:
break;
case BrushSurface_Regular:
case BrushSurface_Sky:
break;
@ -1277,6 +1330,24 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
args.bmodel->surface_to_geometry_index[i] = num_geometries;
// Fill conveyor data if conveyor
r_conveyor_t *conv = NULL;
if (type == BrushSurface_Conveyor) {
ASSERT(conveyors_count < args.sizes.conveyors_count);
conv = &args.bmodel->conveyors[conveyors_count++];
conv->vertices_count = surf->numedges;
conv->vertices_dst_offset = vertex_offset;
conv->vertices_src_offset = conveyors_vertices_count;
conveyors_vertices_count += conv->vertices_count;
ASSERT(conveyors_vertices_count <= args.sizes.conveyors_vertices_count);
conv->geometry_index = num_geometries;
conv->texture_width = R_TexturesGetParm(PARM_TEX_WIDTH, orig_tex_id);
}
++num_geometries;
//DEBUG( "surface %d: numverts=%d numedges=%d", i, surf->polys ? surf->polys->numverts : -1, surf->numedges );
@ -1337,13 +1408,10 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
VK_CreateSurfaceLightmap( surf, args.mod );
}
if (FBitSet( surf->flags, SURF_CONVEYOR )) {
// FIXME make an explicit list of dynamic-uv geometries
}
vec3_t surf_normal;
getSurfaceNormal(surf, surf_normal);
vk_vertex_t *const pvert_begin = p_vert;
for( int k = 0; k < surf->numedges; k++ )
{
@ -1425,6 +1493,13 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
Vector4Set(vertex.color, 255, 255, 255, 255);
// Store original vertex data for conveyor reasons
if (conv) {
const int vertex_index = conv->vertices_src_offset + k;
ASSERT(vertex_index < args.sizes.conveyors_vertices_count);
args.bmodel->conveyors_vertices[vertex_index] = vertex;
}
*(p_vert++) = vertex;
// Ray tracing apparently expects triangle list only (although spec is not very clear about this kekw)
@ -1444,6 +1519,8 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
ASSERT(args.sizes.num_surfaces == num_geometries);
ASSERT(args.sizes.animated_count == animated_count);
ASSERT(args.sizes.conveyors_count == conveyors_count);
ASSERT(args.sizes.conveyors_vertices_count == conveyors_vertices_count);
return true;
}
@ -1465,6 +1542,13 @@ static qboolean createRenderModel( const model_t *mod, vk_brush_model_t *bmodel,
WARN("Too many animated textures %d for model \"%s\" some surfaces can be static", sizes.animated_count, mod->name);
}
if (sizes.conveyors_count > 0) {
ASSERT(sizes.conveyors_vertices_count > 3);
bmodel->conveyors_count = sizes.conveyors_count;
bmodel->conveyors_vertices = Mem_Malloc(vk_core.pool, sizeof(vk_vertex_t) * sizes.conveyors_vertices_count);
bmodel->conveyors = Mem_Malloc(vk_core.pool, sizeof(r_conveyor_t) * sizes.conveyors_count);
}
const r_geometry_range_lock_t geom_lock = R_GeometryRangeLock(&bmodel->geometry);
const qboolean fill_result = fillBrushSurfaces((fill_geometries_args_t){
@ -1564,6 +1648,12 @@ static void R_BrushModelDestroy( vk_brush_model_t *bmodel ) {
ASSERT(bmodel->engine_model->cache.data == bmodel);
ASSERT(bmodel->engine_model->type == mod_brush);
if (bmodel->conveyors_vertices)
Mem_Free(bmodel->conveyors_vertices);
if (bmodel->conveyors)
Mem_Free(bmodel->conveyors);
if (bmodel->water.surfaces_count) {
R_RenderModelDestroy(&bmodel->water.render_model);
Mem_Free((int*)bmodel->water.surfaces_indices);

View File

@ -83,6 +83,31 @@ r_geometry_range_lock_t R_GeometryRangeLock(const r_geometry_range_t *range) {
};
}
r_geometry_range_lock_t R_GeometryRangeLockSubrange(const r_geometry_range_t *range, int vertices_offset, int vertices_count ) {
const vk_staging_buffer_args_t staging_args = {
.buffer = g_geom.buffer.buffer,
.offset = range->block_handle.offset + sizeof(vk_vertex_t) * vertices_offset,
.size = sizeof(vk_vertex_t) * vertices_count,
.alignment = 4,
};
ASSERT(staging_args.offset >= range->block_handle.offset);
ASSERT(staging_args.offset + staging_args.size <= range->block_handle.offset + range->block_handle.size);
const vk_staging_region_t staging = R_VkStagingLockForBuffer(staging_args);
ASSERT(staging.ptr);
ASSERT( range->block_handle.offset % sizeof(vk_vertex_t) == 0 );
return (r_geometry_range_lock_t){
.vertices = (vk_vertex_t *)staging.ptr,
.indices = NULL,
.impl_ = {
.staging_handle = staging.handle,
},
};
}
void R_GeometryRangeUnlock(const r_geometry_range_lock_t *lock) {
R_VkStagingUnlock(lock->impl_.staging_handle);
}

View File

@ -52,6 +52,7 @@ typedef struct {
// Lock staging memory for uploading
r_geometry_range_lock_t R_GeometryRangeLock(const r_geometry_range_t *range);
r_geometry_range_lock_t R_GeometryRangeLockSubrange(const r_geometry_range_t *range, int vertices_offset, int vertices_count );
void R_GeometryRangeUnlock(const r_geometry_range_lock_t *lock);
typedef struct {

View File

@ -164,6 +164,7 @@ static void parseDebugDisplayValue( void ) {
X(NSHADE) \
X(NGEOM) \
X(SURFHASH) \
X(TRIHASH) \
X(DIRECT) \
X(INDIRECT) \
X(INDIRECT_SPEC) \