Merge pull request #671 from w23/stream-E338

Things committed during streams E338-E339

- [x] Allow patching rendermode for func_* entities, fixes #663
- [x] Print out screenshot timings
- [x] Unsuccessfully reset denoiser statistics on discontinuities
This commit is contained in:
Ivan Avdeev 2023-11-30 08:09:07 -08:00 committed by GitHub
commit c9b485f8a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 56 additions and 61 deletions

View File

@ -1,3 +1,10 @@
# 2023-11-28 E338
- [x] rendertest
- [x] read imagecompare results
- [x] html report
- [-] rendermode patch
- [ ] track patch by boolean, not another field
# 2023-11-27 E337 # 2023-11-27 E337
- [x] make rendetest.py the central script - [x] make rendetest.py the central script
- [x] parallelize/make gifs - [x] parallelize/make gifs
@ -7,7 +14,6 @@
- [ ] consider passing a special flag for single-sided blended surfaces (i.e. brush surfaces) - [ ] consider passing a special flag for single-sided blended surfaces (i.e. brush surfaces)
- [x] fix per-entity material mapping, #669 - [x] fix per-entity material mapping, #669
- [x] add to rendertest - [x] add to rendertest
- [ ] html report
# 2023-11-24 E336 # 2023-11-24 E336
- reproducible rendering: - reproducible rendering:

View File

@ -46,6 +46,7 @@ typedef struct {
typedef struct vk_brush_model_s { typedef struct vk_brush_model_s {
model_t *engine_model; model_t *engine_model;
int patch_rendermode;
r_geometry_range_t geometry; r_geometry_range_t geometry;
@ -428,57 +429,6 @@ static vk_render_type_e brushRenderModeToRenderType( int render_mode ) {
return kVkRenderTypeSolid; return kVkRenderTypeSolid;
} }
#if 0 // TOO OLD
static void brushDrawWaterSurfaces( const cl_entity_t *ent, const vec4_t color, const matrix4x4 transform ) {
const model_t *model = ent->model;
vec3_t mins, maxs;
if( !VectorIsNull( ent->angles ))
{
for( int i = 0; i < 3; i++ )
{
mins[i] = ent->origin[i] - model->radius;
maxs[i] = ent->origin[i] + model->radius;
}
//rotated = true;
}
else
{
VectorAdd( ent->origin, model->mins, mins );
VectorAdd( ent->origin, model->maxs, maxs );
//rotated = false;
}
// if( R_CullBox( mins, maxs ))
// return;
VK_RenderModelDynamicBegin( brushRenderModeToRenderType(ent->curstate.rendermode), color, transform, "%s water", model->name );
// Iterate through all surfaces, find *TURB*
for( int i = 0; i < model->nummodelsurfaces; i++ )
{
const msurface_t *surf = model->surfaces + model->firstmodelsurface + i;
if( !FBitSet( surf->flags, SURF_DRAWTURB ) && !FBitSet( surf->flags, SURF_DRAWTURB_QUADS) )
continue;
if( surf->plane->type != PLANE_Z && !FBitSet( ent->curstate.effects, EF_WATERSIDES ))
continue;
if( mins[2] + 1.0f >= surf->plane->dist )
continue;
EmitWaterPolys( ent, surf, false );
}
// submit as dynamic model
VK_RenderModelDynamicCommit();
// TODO:
// - upload water geometry only once, animate in compute/vertex shader
}
#endif
typedef struct { typedef struct {
const cl_entity_t *ent; const cl_entity_t *ent;
const msurface_t *surfaces; const msurface_t *surfaces;
@ -857,6 +807,9 @@ void R_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, con
else else
Matrix4x4_LoadIdentity(transform); Matrix4x4_LoadIdentity(transform);
if (bmodel->patch_rendermode >= 0)
render_mode = bmodel->patch_rendermode;
vec4_t color = {1, 1, 1, 1}; vec4_t color = {1, 1, 1, 1};
vk_render_type_e render_type = kVkRenderTypeSolid; vk_render_type_e render_type = kVkRenderTypeSolid;
switch (render_mode) { switch (render_mode) {
@ -1042,7 +995,7 @@ static model_sizes_t computeSizes( const model_t *mod, qboolean is_worldmodel )
typedef struct { typedef struct {
const model_t *mod; const model_t *mod;
const vk_brush_model_t *bmodel; vk_brush_model_t *bmodel;
model_sizes_t sizes; model_sizes_t sizes;
uint32_t base_vertex_offset; uint32_t base_vertex_offset;
uint32_t base_index_offset; uint32_t base_index_offset;
@ -1302,8 +1255,14 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
int index_offset = args.base_index_offset; int index_offset = args.base_index_offset;
const xvk_mapent_func_any_t *const entity_patch = getModelFuncAnyPatch(args.mod); const xvk_mapent_func_any_t *const entity_patch = getModelFuncAnyPatch(args.mod);
if (entity_patch) if (entity_patch) {
DEBUG("Found entity_patch(matmap_count=%d) for model \"%s\"", entity_patch->matmap_count, args.mod->name); DEBUG("Found entity_patch(matmap_count=%d, rendermode_patched=%d rendermode=%d) for model \"%s\"",
entity_patch->matmap_count, entity_patch->rendermode_patched, entity_patch->rendermode, args.mod->name);
if (entity_patch->rendermode_patched > 0)
args.bmodel->patch_rendermode = entity_patch->rendermode;
}
connectVertices(args.mod, entity_patch ? entity_patch->smooth_entire_model : false); connectVertices(args.mod, entity_patch ? entity_patch->smooth_entire_model : false);
// Load sorted by gl_texturenum // Load sorted by gl_texturenum
@ -1616,6 +1575,7 @@ qboolean R_BrushModelLoad( model_t *mod, qboolean is_worldmodel ) {
g_brush.models[g_brush.models_count++] = bmodel; g_brush.models[g_brush.models_count++] = bmodel;
bmodel->engine_model = mod; bmodel->engine_model = mod;
bmodel->patch_rendermode = -1;
mod->cache.data = bmodel; mod->cache.data = bmodel;
Matrix4x4_LoadIdentity(bmodel->prev_transform); Matrix4x4_LoadIdentity(bmodel->prev_transform);

View File

@ -642,7 +642,10 @@ static rgbdata_t *R_VkReadPixels( void ) {
0, 0, NULL, 0, NULL, ARRAYSIZE(image_barrier), image_barrier); 0, 0, NULL, 0, NULL, ARRAYSIZE(image_barrier), image_barrier);
} }
submit( combuf, true, draw ); {
const qboolean wait = true;
submit( combuf, wait, draw );
}
// copy bytes to buffer // copy bytes to buffer
{ {
@ -705,6 +708,8 @@ qboolean VID_ScreenShot( const char *filename, int shot_type )
int width = 0, height = 0; int width = 0, height = 0;
qboolean result; qboolean result;
const uint64_t start_ns = aprof_time_now_ns();
// get screen frame // get screen frame
rgbdata_t *r_shot = R_VkReadPixels(); rgbdata_t *r_shot = R_VkReadPixels();
if (!r_shot) if (!r_shot)
@ -745,10 +750,15 @@ qboolean VID_ScreenShot( const char *filename, int shot_type )
gEngine.Image_Process( &r_shot, width, height, flags, 0.0f ); gEngine.Image_Process( &r_shot, width, height, flags, 0.0f );
// write image // write image
const uint64_t save_begin_ns = aprof_time_now_ns();
result = gEngine.FS_SaveImage( filename, r_shot ); result = gEngine.FS_SaveImage( filename, r_shot );
const uint64_t save_end_ns = aprof_time_now_ns();
gEngine.fsapi->AllowDirectPaths( false ); // always reset after store screenshot gEngine.fsapi->AllowDirectPaths( false ); // always reset after store screenshot
gEngine.FS_FreeImage( r_shot ); gEngine.FS_FreeImage( r_shot );
gEngine.Con_Printf("Wrote screenshot %s\n", filename); const uint64_t end_ns = aprof_time_now_ns();
gEngine.Con_Printf("Wrote screenshot %s. Saving file: %.03fms, total: %.03fms\n",
filename, (save_end_ns - save_begin_ns) / 1e6, (end_ns - start_ns) / 1e6);
return result; return result;
} }

View File

@ -523,10 +523,15 @@ static void patchFuncAnyEntity( const entity_props_t *props, uint32_t have_field
if (have_fields & Field_origin) { if (have_fields & Field_origin) {
VectorCopy(props->origin, e->origin); VectorCopy(props->origin, e->origin);
e->origin_patched = true; e->origin_patched = true;
DEBUG("Patching ent=%d func_any=%d %f %f %f", e->entity_index, index, e->origin[0], e->origin[1], e->origin[2]); DEBUG("Patching ent=%d func_any=%d %f %f %f", e->entity_index, index, e->origin[0], e->origin[1], e->origin[2]);
} }
if (have_fields & Field_rendermode) {
e->rendermode = props->rendermode;
e->rendermode_patched = true;
DEBUG("Patching ent=%d func_any=%d rendermode=%d", e->entity_index, index, e->rendermode);
}
if (have_fields & Field__xvk_smooth_entire_model) { if (have_fields & Field__xvk_smooth_entire_model) {
DEBUG("Patching ent=%d func_any=%d smooth_entire_model =%d", e->entity_index, index, props->_xvk_smooth_entire_model); DEBUG("Patching ent=%d func_any=%d smooth_entire_model =%d", e->entity_index, index, props->_xvk_smooth_entire_model);
e->smooth_entire_model = props->_xvk_smooth_entire_model; e->smooth_entire_model = props->_xvk_smooth_entire_model;

View File

@ -106,8 +106,6 @@ typedef struct {
string model; string model;
vec3_t origin; vec3_t origin;
qboolean origin_patched;
#define MAX_MATERIAL_MAPPINGS 8 #define MAX_MATERIAL_MAPPINGS 8
int matmap_count; int matmap_count;
struct { struct {
@ -125,6 +123,10 @@ typedef struct {
struct cl_entity_s *ent; struct cl_entity_s *ent;
*/ */
// TODO flags
qboolean origin_patched;
qboolean rendermode_patched;
} xvk_mapent_func_any_t; } xvk_mapent_func_any_t;
typedef struct { typedef struct {

View File

@ -87,6 +87,7 @@ static struct {
rt_resource_t res[MAX_RESOURCES]; rt_resource_t res[MAX_RESOURCES];
qboolean reload_pipeline; qboolean reload_pipeline;
qboolean discontinuity;
matrix4x4 prev_inv_proj, prev_inv_view; matrix4x4 prev_inv_proj, prev_inv_view;
@ -318,7 +319,7 @@ static void performTracing( vk_combuf_t *combuf, const perform_tracing_args_t* a
src->image = tmp_img; src->image = tmp_img;
// If there was no initial state, prepare it. (this should happen only for the first frame) // If there was no initial state, prepare it. (this should happen only for the first frame)
if (res->resource.write.pipelines == 0) { if (g_rtx.discontinuity || res->resource.write.pipelines == 0) {
// TODO is there a better way? Can image be cleared w/o explicit clear op? // TODO is there a better way? Can image be cleared w/o explicit clear op?
R_VkImageClear( cmdbuf, res->image.image ); R_VkImageClear( cmdbuf, res->image.image );
res->resource.write.pipelines = VK_PIPELINE_STAGE_TRANSFER_BIT; res->resource.write.pipelines = VK_PIPELINE_STAGE_TRANSFER_BIT;
@ -656,6 +657,7 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
tail: tail:
APROF_SCOPE_END(ray_frame_end); APROF_SCOPE_END(ray_frame_end);
g_rtx.discontinuity = false;
} }
static void reloadPipeline( void ) { static void reloadPipeline( void ) {
@ -742,3 +744,7 @@ void VK_RayShutdown( void ) {
RT_VkAccelShutdown(); RT_VkAccelShutdown();
RT_DynamicModelShutdown(); RT_DynamicModelShutdown();
} }
void RT_FrameDiscontinuity( void ) {
g_rtx.discontinuity = true;
}

View File

@ -84,3 +84,7 @@ typedef struct {
} rt_frame_add_once_t; } rt_frame_add_once_t;
void RT_FrameAddOnce( rt_frame_add_once_t args ); void RT_FrameAddOnce( rt_frame_add_once_t args );
// Signal that the next frame is discontinuous, and all accumulated screen-space
// statistics should be reset. Should help with newmap/saveload/teleport denoiser artifacts.
void RT_FrameDiscontinuity( void );

View File

@ -252,6 +252,8 @@ void R_NewMap( void ) {
// Make sure that EntityData doesn't accidentally reference old pointers. // Make sure that EntityData doesn't accidentally reference old pointers.
VK_EntityDataClear(); VK_EntityDataClear();
RT_FrameDiscontinuity();
// Skip clearing already loaded data if the map hasn't changed. // Skip clearing already loaded data if the map hasn't changed.
if (is_save_load) if (is_save_load)
return; return;