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
- [x] make rendetest.py the central script
- [x] parallelize/make gifs
@ -7,7 +14,6 @@
- [ ] consider passing a special flag for single-sided blended surfaces (i.e. brush surfaces)
- [x] fix per-entity material mapping, #669
- [x] add to rendertest
- [ ] html report
# 2023-11-24 E336
- reproducible rendering:

View File

@ -46,6 +46,7 @@ typedef struct {
typedef struct vk_brush_model_s {
model_t *engine_model;
int patch_rendermode;
r_geometry_range_t geometry;
@ -428,57 +429,6 @@ static vk_render_type_e brushRenderModeToRenderType( int render_mode ) {
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 {
const cl_entity_t *ent;
const msurface_t *surfaces;
@ -857,6 +807,9 @@ void R_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, con
else
Matrix4x4_LoadIdentity(transform);
if (bmodel->patch_rendermode >= 0)
render_mode = bmodel->patch_rendermode;
vec4_t color = {1, 1, 1, 1};
vk_render_type_e render_type = kVkRenderTypeSolid;
switch (render_mode) {
@ -1042,7 +995,7 @@ static model_sizes_t computeSizes( const model_t *mod, qboolean is_worldmodel )
typedef struct {
const model_t *mod;
const vk_brush_model_t *bmodel;
vk_brush_model_t *bmodel;
model_sizes_t sizes;
uint32_t base_vertex_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;
const xvk_mapent_func_any_t *const entity_patch = getModelFuncAnyPatch(args.mod);
if (entity_patch)
DEBUG("Found entity_patch(matmap_count=%d) for model \"%s\"", entity_patch->matmap_count, args.mod->name);
if (entity_patch) {
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);
// 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;
bmodel->engine_model = mod;
bmodel->patch_rendermode = -1;
mod->cache.data = bmodel;
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);
}
submit( combuf, true, draw );
{
const qboolean wait = true;
submit( combuf, wait, draw );
}
// copy bytes to buffer
{
@ -705,6 +708,8 @@ qboolean VID_ScreenShot( const char *filename, int shot_type )
int width = 0, height = 0;
qboolean result;
const uint64_t start_ns = aprof_time_now_ns();
// get screen frame
rgbdata_t *r_shot = R_VkReadPixels();
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 );
// write image
const uint64_t save_begin_ns = aprof_time_now_ns();
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.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;
}

View File

@ -523,10 +523,15 @@ static void patchFuncAnyEntity( const entity_props_t *props, uint32_t have_field
if (have_fields & Field_origin) {
VectorCopy(props->origin, e->origin);
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]);
}
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) {
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;

View File

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

View File

@ -87,6 +87,7 @@ static struct {
rt_resource_t res[MAX_RESOURCES];
qboolean reload_pipeline;
qboolean discontinuity;
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;
// 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?
R_VkImageClear( cmdbuf, res->image.image );
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:
APROF_SCOPE_END(ray_frame_end);
g_rtx.discontinuity = false;
}
static void reloadPipeline( void ) {
@ -742,3 +744,7 @@ void VK_RayShutdown( void ) {
RT_VkAccelShutdown();
RT_DynamicModelShutdown();
}
void RT_FrameDiscontinuity( void ) {
g_rtx.discontinuity = true;
}

View File

@ -84,3 +84,7 @@ typedef struct {
} rt_frame_add_once_t;
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.
VK_EntityDataClear();
RT_FrameDiscontinuity();
// Skip clearing already loaded data if the map hasn't changed.
if (is_save_load)
return;