vk: profiler: control profiler with r_speeds command

use bits to enable particular performance data display:
0 -- off
1 -- simple frame time
2 -- more object count and sizes statistics (TODO)
4 -- overall gpu usage (TODO)
8 -- extended intra-frame data, function times graph, etc
This commit is contained in:
Ivan Avdeev 2023-03-20 12:37:48 -07:00 committed by Ivan Avdeev
parent 55af70c422
commit 9d8ec1bc9d
5 changed files with 59 additions and 36 deletions

View File

@ -3,6 +3,7 @@
#include "shaders/ray_interop.h" // stats: struct LightCluster
#include "vk_overlay.h"
#include "vk_framectl.h"
#include "vk_cvar.h"
#include "profiler.h"
@ -12,6 +13,18 @@
#define MAX_FRAMES_HISTORY 256
#define TARGET_FRAME_TIME (1000.f / 60.f)
// Valid bits for `r_speeds` argument:
enum {
SPEEDS_BIT_OFF = 0, // `r_speeds 0` turns off all performance stats display
SPEEDS_BIT_SIMPLE = 1, // `r_speeds 1` displays only basic info about frame time
SPEEDS_BIT_STATS = 2, // `r_speeds 2` displays additional metrics, i.e. lights counts, dynamic geometry upload sizes, etc (TODO)
SPEEDS_BIT_GPU_USAGE = 4, // `r_speeds 4` displays overall GPU usage stats (TODO)
SPEEDS_BIT_FRAME = 8, // `r_speeds 8` diplays details instrumental profiler frame data, e.g. specific functions times graphs, etc
// These bits can be combined, e.g. `r_speeds 9`, 8+1, will display 1: basic timing info and 8: frame graphs
};
static struct {
float frame_times[MAX_FRAMES_HISTORY];
uint32_t frame_num;
@ -182,46 +195,56 @@ static int drawFrames( uint32_t prev_frame_index, int y, const uint64_t gpu_fram
return y;
}
// FIXME move this to r_speeds or something like that
static void getCurrentFontMetrics(void) {
// hidpi scaling
float scale = gEngine.pfnGetCvarFloat("con_fontscale");
if (scale <= 0.f)
scale = 1.f;
// TODO these numbers are mostly fine for the "default" font. Unfortunately
// we don't have any access to real font metrics from here, ref_api_t doesn't give us anything about fonts. ;_;
g_slows.font_metrics.glyph_width = 8 * scale;
g_slows.font_metrics.glyph_height = 20 * scale;
}
void R_ShowExtendedProfilingData(uint32_t prev_frame_index, uint64_t gpu_frame_begin_ns, uint64_t gpu_frame_end_ns) {
APROF_SCOPE_DECLARE_BEGIN(__FUNCTION__, __FUNCTION__);
{
// hidpi scaling
float scale = gEngine.pfnGetCvarFloat("con_fontscale");
if (scale <= 0.f)
scale = 1.f;
// TODO these numbers are mostly fine for the "default" font. Unfortunately
// we don't have any access to real font metrics from here, ref_api_t doesn't give us anything about fonts. ;_;
g_slows.font_metrics.glyph_width = 8 * scale;
g_slows.font_metrics.glyph_height = 20 * scale;
}
const uint32_t speeds_bits = r_speeds->value;
int line = 4;
{
const int dirty = g_lights.stats.dirty_cells;
gEngine.Con_NPrintf(line++, "Dirty light cells: %d, size = %dKiB, ranges = %d\n", dirty, (int)(dirty * sizeof(struct LightCluster) / 1024), g_lights.stats.ranges_uploaded);
}
// TODO collect into a r_speeds_msg string, similar to ref/gl
//R_Speeds_Printf( "Renderer: ^1Engine^7\n\n" );
const uint32_t events = g_aprof.events_last_frame - prev_frame_index;
const uint64_t frame_begin_time = APROF_EVENT_TIMESTAMP(g_aprof.events[prev_frame_index]);
const unsigned long long delta_ns = APROF_EVENT_TIMESTAMP(g_aprof.events[g_aprof.events_last_frame]) - frame_begin_time;
const float frame_time = delta_ns / 1e6;
const uint64_t gpu_time_ns = gpu_frame_end_ns - gpu_frame_begin_ns;
gEngine.Con_NPrintf(line++, "GPU frame time: %.03fms\n", gpu_time_ns * 1e-6);
gEngine.Con_NPrintf(line++, "aprof events this frame: %u, wraps: %d, frame time: %.03fms\n", events, g_aprof.current_frame_wraparounds, frame_time);
if (speeds_bits & SPEEDS_BIT_SIMPLE) {
const uint64_t gpu_time_ns = gpu_frame_end_ns - gpu_frame_begin_ns;
gEngine.Con_NPrintf(line++, "GPU frame time: %.03fms\n", gpu_time_ns * 1e-6);
}
if (speeds_bits & SPEEDS_BIT_STATS) {
const int dirty = g_lights.stats.dirty_cells;
gEngine.Con_NPrintf(line++, "aprof events this frame: %u, wraps: %d, frame time: %.03fms\n", events, g_aprof.current_frame_wraparounds, frame_time);
gEngine.Con_NPrintf(line++, "Dirty light cells: %d, size = %dKiB, ranges = %d\n", dirty, (int)(dirty * sizeof(struct LightCluster) / 1024), g_lights.stats.ranges_uploaded);
}
g_slows.frame_times[g_slows.frame_num] = frame_time;
g_slows.frame_num = (g_slows.frame_num + 1) % MAX_FRAMES_HISTORY;
handlePause( prev_frame_index );
int y = 100;
const float frame_bar_y_scale = 2.f; // ms to pixels (somehow)
y = drawFrameTimeGraph( y, frame_bar_y_scale ) + 20;
y = drawFrames( prev_frame_index, y, gpu_frame_begin_ns, gpu_frame_end_ns );
if (speeds_bits & SPEEDS_BIT_FRAME) {
getCurrentFontMetrics();
int y = 100;
const float frame_bar_y_scale = 2.f; // ms to pixels (somehow)
y = drawFrameTimeGraph( y, frame_bar_y_scale ) + 20;
y = drawFrames( prev_frame_index, y, gpu_frame_begin_ns, gpu_frame_end_ns );
}
APROF_SCOPE_END(__FUNCTION__);
}

View File

@ -1,4 +1,3 @@
//#include "xash3d_types.h"
#include "const.h" // required for ref_api.h
#include "cvardef.h"
#include "com_model.h"

View File

@ -6,13 +6,15 @@
DECLARE_CVAR(NONEXTERN_CVAR)
#undef NONEXTERN_CVAR
static cvar_t *r_drawentities;
DEFINE_ENGINE_SHARED_CVAR_LIST()
void VK_LoadCvars( void )
{
#define gEngfuncs gEngine // ...
RETRIEVE_ENGINE_SHARED_CVAR_LIST()
r_lighting_modulate = gEngine.Cvar_Get( "r_lighting_modulate", "0.6", FCVAR_ARCHIVE, "lightstyles modulate scale" );
cl_lightstyle_lerping = gEngine.pfnGetCvarPointer( "cl_lightstyle_lerping", 0 );
r_drawentities = gEngine.pfnGetCvarPointer( "r_drawentities", 0 );
r_lightmap = gEngine.Cvar_Get( "r_lightmap", "0", FCVAR_CHEAT, "lightmap debugging tool" );
ui_infotool = gEngine.Cvar_Get( "ui_infotool", "0", FCVAR_CHEAT, "DEBUG: print entity info under crosshair" );
vk_only = gEngine.Cvar_Get( "vk_only", "0", FCVAR_GLCONFIG, "Full disable Ray Tracing pipeline" );

View File

@ -2,6 +2,11 @@
#include "cvardef.h"
#include "xash3d_types.h" // required for ref_api.h
#include "const.h" // required for ref_api.h
#include "com_model.h" // required for ref_api.h
#include "ref_api.h"
// from engine/common/cvar.h
#define FCVAR_READ_ONLY (1<<17) // cannot be set by user at all, and can't be requested by CvarGetPointer from game dlls
@ -23,7 +28,8 @@ void VK_LoadCvarsAfterInit( void );
X(vk_only) \
X(vk_device_target_id) \
#define EXTERN_CVAR(cvar) extern cvar_t *cvar;
DECLARE_CVAR(EXTERN_CVAR)
#undef EXTERN_CVAR
DECLARE_ENGINE_SHARED_CVAR_LIST()

View File

@ -6,6 +6,7 @@
#include "vk_previous_frame.h"
#include "vk_renderstate.h"
#include "vk_math.h"
#include "vk_cvar.h"
#include "camera.h"
#include "xash3d_mathlib.h"
@ -39,8 +40,6 @@ typedef struct
model_t *model;
} player_model_t;
cvar_t *r_glowshellfreq;
cvar_t r_shadows = { (char*)"r_shadows", (char*)"0", 0 };
typedef struct sortedmesh_s
@ -116,9 +115,7 @@ typedef struct
} studio_draw_state_t;
// studio-related cvars
static cvar_t *r_drawviewmodel;
cvar_t *cl_righthand = NULL;
static cvar_t *cl_himodels;
static r_studio_interface_t *pStudioDraw;
static studio_draw_state_t g_studio; // global studio state
@ -144,11 +141,7 @@ static struct {
void R_StudioInit( void )
{
cl_himodels = gEngine.pfnGetCvarPointer( "cl_himodels", 0 );
r_drawviewmodel = gEngine.Cvar_Get( "r_drawviewmodel", "1", 0, "draw firstperson weapon model" );
Matrix3x4_LoadIdentity( g_studio.rotationmatrix );
r_glowshellfreq = gEngine.Cvar_Get( "r_glowshellfreq", "2.2", 0, "glowing shell frequency update" );
// g-cont. cvar disabled by Valve
// gEngine.Cvar_RegisterVariable( &r_shadows );