mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-12-14 13:10:09 +01:00
vk/speeds: preserve metric names that might not be registered initially
When `r_speeds_graphs` cvar is read for the first time, not all metrics might be registered yet. It leads to some graphs missing. Retry searching for these metrics on further frames, thus preserving the graph list from previous session fully.
This commit is contained in:
parent
c72ff1d0c5
commit
5dda220751
@ -40,10 +40,11 @@ typedef struct {
|
||||
} r_speeds_metric_t;
|
||||
|
||||
typedef struct {
|
||||
char name[64];
|
||||
float *data;
|
||||
int data_count;
|
||||
int data_write;
|
||||
int source_metric;
|
||||
int source_metric; // can be -1 for missing metrics
|
||||
|
||||
int height;
|
||||
int max_value; // Computed automatically every frame
|
||||
@ -95,8 +96,8 @@ static void speedsStrcat( const char *msg ) {
|
||||
|
||||
static void speedsPrintf( const char *msg, ... ) _format(1);
|
||||
static void speedsPrintf( const char *msg, ... ) {
|
||||
va_list argptr;
|
||||
char text[MAX_SPEEDS_MESSAGE];
|
||||
va_list argptr;
|
||||
char text[MAX_SPEEDS_MESSAGE];
|
||||
|
||||
va_start( argptr, msg );
|
||||
Q_vsnprintf( text, sizeof( text ), msg, argptr );
|
||||
@ -280,6 +281,42 @@ static void handlePause( uint32_t prev_frame_index ) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *s;
|
||||
int len;
|
||||
} const_string_view_t;
|
||||
|
||||
static int stringViewCmp(const_string_view_t sv, const char* s) {
|
||||
for (int i = 0; i < sv.len; ++i) {
|
||||
const int d = sv.s[i] - s[i];
|
||||
if (d != 0)
|
||||
return d;
|
||||
if (s[i] == '\0')
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check that both strings end the same
|
||||
return '\0' - s[sv.len];
|
||||
}
|
||||
|
||||
static int findMetricIndexByName( const_string_view_t name) {
|
||||
for (int i = 0; i < g_speeds.metrics_count; ++i) {
|
||||
if (stringViewCmp(name, g_speeds.metrics[i].name) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int findGraphIndexByName( const_string_view_t name) {
|
||||
for (int i = 0; i < g_speeds.graphs_count; ++i) {
|
||||
if (stringViewCmp(name, g_speeds.graphs[i].name) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int drawGraph( r_speeds_graph_t *const graph, int frame_bar_y ) {
|
||||
const int min_width = 100 * g_speeds.font_metrics.scale;
|
||||
const int graph_width = clampi32(
|
||||
@ -289,6 +326,22 @@ static int drawGraph( r_speeds_graph_t *const graph, int frame_bar_y ) {
|
||||
min_width, vk_frame.width); // clamp to min_width..frame_width
|
||||
const int graph_height = graph->height * g_speeds.font_metrics.scale;
|
||||
|
||||
if (graph->source_metric < 0) {
|
||||
// Check whether this metric has been registered
|
||||
const int metric_index = findMetricIndexByName((const_string_view_t){graph->name, Q_strlen(graph->name)});
|
||||
|
||||
if (metric_index >= 0) {
|
||||
graph->source_metric = metric_index;
|
||||
g_speeds.metrics[metric_index].graph_index = graph - g_speeds.graphs;
|
||||
} else {
|
||||
const char *name = graph->name;
|
||||
rgba_t text_color = {0xff, 0x00, 0x00, 0xff};
|
||||
gEngine.Con_DrawString(0, frame_bar_y, name, text_color);
|
||||
frame_bar_y += g_speeds.font_metrics.glyph_height;
|
||||
return frame_bar_y;
|
||||
}
|
||||
}
|
||||
|
||||
const r_speeds_metric_t *const metric = g_speeds.metrics + graph->source_metric;
|
||||
const int graph_max_value = metric->max_value ? Q_max(metric->max_value, graph->max_value) : graph->max_value;
|
||||
|
||||
@ -493,7 +546,10 @@ static void getCurrentFontMetrics(void) {
|
||||
static int drawGraphs( int y ) {
|
||||
for (int i = 0; i < g_speeds.graphs_count; ++i) {
|
||||
r_speeds_graph_t *const graph = g_speeds.graphs + i;
|
||||
graph->data[graph->data_write] = *g_speeds.metrics[graph->source_metric].p_value;
|
||||
|
||||
if (graph->source_metric >= 0)
|
||||
graph->data[graph->data_write] = *g_speeds.metrics[graph->source_metric].p_value;
|
||||
|
||||
graph->data_write = (graph->data_write + 1) % graph->data_count;
|
||||
y = drawGraph(graph, y) + 10;
|
||||
}
|
||||
@ -512,31 +568,36 @@ static void togglePause( void ) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *s;
|
||||
int len;
|
||||
} const_string_view_t;
|
||||
static void speedsGraphAdd(const_string_view_t name, int metric_index) {
|
||||
gEngine.Con_Printf("Adding profiler graph for metric %.*s(%d) at graph index %d\n", name.len, name.s, metric_index, g_speeds.graphs_count);
|
||||
|
||||
static int stringViewCmp(const_string_view_t sv, const char* s) {
|
||||
for (int i = 0; i < sv.len; ++i) {
|
||||
const int d = sv.s[i] - s[i];
|
||||
if (d != 0)
|
||||
return d;
|
||||
if (s[i] == '\0')
|
||||
return 1;
|
||||
if (g_speeds.graphs_count == MAX_GRAPHS) {
|
||||
gEngine.Con_Printf(S_ERROR "Cannot add graph \"%.*s\", no free graphs slots (max=%d)\n", name.len, name.s, MAX_GRAPHS);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that both strings end the same
|
||||
return '\0' - s[sv.len];
|
||||
}
|
||||
|
||||
static int findMetricIndexByName( const_string_view_t name) {
|
||||
for (int i = 0; i < g_speeds.metrics_count; ++i) {
|
||||
if (stringViewCmp(name, g_speeds.metrics[i].name) == 0)
|
||||
return i;
|
||||
if (metric_index >= 0) {
|
||||
r_speeds_metric_t *const metric = g_speeds.metrics + metric_index;
|
||||
metric->graph_index = g_speeds.graphs_count;
|
||||
}
|
||||
|
||||
return -1;
|
||||
r_speeds_graph_t *const graph = g_speeds.graphs + g_speeds.graphs_count++;
|
||||
|
||||
// TODO make these customizable
|
||||
graph->data_count = 256;
|
||||
graph->height = 100;
|
||||
graph->max_value = 1; // Will be computed automatically on first frame
|
||||
graph->color[3] = 255;
|
||||
|
||||
const int len = Q_min(name.len, sizeof(graph->name) - 1);
|
||||
memcpy(graph->name, name.s, len);
|
||||
graph->name[len] = '\0';
|
||||
getColorForString(graph->name, graph->color);
|
||||
|
||||
ASSERT(!graph->data);
|
||||
graph->data = Mem_Calloc(vk_core.pool, graph->data_count * sizeof(float));
|
||||
graph->data_write = 0;
|
||||
graph->source_metric = metric_index;
|
||||
}
|
||||
|
||||
static void speedsGraphAddByMetricName( const_string_view_t name ) {
|
||||
@ -552,63 +613,45 @@ static void speedsGraphAddByMetricName( const_string_view_t name ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_speeds.graphs_count == MAX_GRAPHS) {
|
||||
gEngine.Con_Printf(S_ERROR "Cannot add graph for metric \"%.*s\", no free graphs slots (max=%d)\n", name.len, name.s, MAX_GRAPHS);
|
||||
return;
|
||||
}
|
||||
|
||||
gEngine.Con_Printf("Adding profiler graph for metric %.*s(%d) at graph index %d\n", name.len, name.s, metric_index, g_speeds.graphs_count);
|
||||
|
||||
metric->graph_index = g_speeds.graphs_count++;
|
||||
r_speeds_graph_t *const graph = g_speeds.graphs + metric->graph_index;
|
||||
|
||||
// TODO make these customizable
|
||||
graph->data_count = 256;
|
||||
graph->height = 100;
|
||||
graph->max_value = 1; // Will be computed automatically on first frame
|
||||
graph->color[3] = 255;
|
||||
getColorForString(metric->name, graph->color);
|
||||
|
||||
ASSERT(!graph->data);
|
||||
graph->data = Mem_Calloc(vk_core.pool, graph->data_count * sizeof(float));
|
||||
graph->data_write = 0;
|
||||
graph->source_metric = metric_index;
|
||||
speedsGraphAdd( name, metric_index );
|
||||
}
|
||||
|
||||
static void speedsGraphRemoveByMetricName( const_string_view_t name ) {
|
||||
const int metric_index = findMetricIndexByName(name);
|
||||
if (metric_index < 0) {
|
||||
gEngine.Con_Printf(S_ERROR "Metric \"%.*s\" not found\n", name.len, name.s);
|
||||
return;
|
||||
}
|
||||
static void speedsGraphDelete( r_speeds_graph_t *graph ) {
|
||||
ASSERT(graph->data);
|
||||
Mem_Free(graph->data);
|
||||
graph->data = NULL;
|
||||
graph->name[0] = '\0';
|
||||
|
||||
r_speeds_metric_t *const metric = g_speeds.metrics + metric_index;
|
||||
if (metric->graph_index < 0) {
|
||||
gEngine.Con_Printf(S_WARN "Metric \"%.*s\" doesn't have a graph\n", name.len, name.s);
|
||||
return;
|
||||
}
|
||||
|
||||
gEngine.Con_Printf("Removing profiler graph for metric %.*s(%d) at graph index %d\n", name.len, name.s, metric_index, metric->graph_index);
|
||||
|
||||
// Remove/free the graph itself
|
||||
const int graph_index = metric->graph_index;
|
||||
{
|
||||
r_speeds_graph_t *const graph = g_speeds.graphs + metric->graph_index;
|
||||
ASSERT(graph->data);
|
||||
Mem_Free(graph->data);
|
||||
graph->data = NULL;
|
||||
|
||||
ASSERT(graph->source_metric >= 0);
|
||||
if (graph->source_metric >= 0) {
|
||||
ASSERT(graph->source_metric < g_speeds.metrics_count);
|
||||
r_speeds_metric_t *const metric = g_speeds.metrics + graph->source_metric;
|
||||
metric->graph_index = -1;
|
||||
}
|
||||
|
||||
graph->source_metric = -1;
|
||||
}
|
||||
|
||||
static void speedsGraphRemoveByName( const_string_view_t name ) {
|
||||
const int graph_index = findGraphIndexByName(name);
|
||||
if (graph_index < 0) {
|
||||
gEngine.Con_Printf(S_ERROR "Graph \"%.*s\" not found\n", name.len, name.s);
|
||||
return;
|
||||
}
|
||||
|
||||
r_speeds_graph_t *const graph = g_speeds.graphs + graph_index;
|
||||
speedsGraphDelete( graph );
|
||||
|
||||
gEngine.Con_Printf("Removing profiler graph %.*s(%d) at graph index %d\n", name.len, name.s, graph->source_metric, graph_index);
|
||||
|
||||
// Move all further graphs one slot back, also updating their indices
|
||||
for (int i = graph_index + 1; i < g_speeds.graphs_count; ++i) {
|
||||
r_speeds_graph_t *const dst = g_speeds.graphs + i - 1;
|
||||
const r_speeds_graph_t *const src = g_speeds.graphs + i;
|
||||
|
||||
g_speeds.metrics[src->source_metric].graph_index--;
|
||||
if (src->source_metric >= 0) {
|
||||
ASSERT(src->source_metric < g_speeds.metrics_count);
|
||||
g_speeds.metrics[src->source_metric].graph_index--;
|
||||
}
|
||||
|
||||
memcpy(dst, src, sizeof(r_speeds_graph_t));
|
||||
}
|
||||
@ -620,13 +663,7 @@ static void speedsGraphsRemoveAll( void ) {
|
||||
gEngine.Con_Printf("Removing all %d profiler graphs\n", g_speeds.graphs_count);
|
||||
for (int i = 0; i < g_speeds.graphs_count; ++i) {
|
||||
r_speeds_graph_t *const graph = g_speeds.graphs + i;
|
||||
ASSERT(graph->data);
|
||||
Mem_Free(graph->data);
|
||||
graph->data = NULL;
|
||||
|
||||
ASSERT(graph->source_metric >= 0);
|
||||
ASSERT(graph->source_metric < g_speeds.metrics_count);
|
||||
g_speeds.metrics[graph->source_metric].graph_index = -1;
|
||||
speedsGraphDelete(graph);
|
||||
}
|
||||
|
||||
g_speeds.graphs_count = 0;
|
||||
@ -646,7 +683,13 @@ static void processGraphCvar( void ) {
|
||||
while (*p) {
|
||||
const char *next = Q_strchrnul(p, ',');
|
||||
const const_string_view_t name = {p, next - p};
|
||||
speedsGraphAddByMetricName( name );
|
||||
|
||||
const int metric_index = findMetricIndexByName(name);
|
||||
if (metric_index < 0) {
|
||||
gEngine.Con_Printf(S_WARN "Metric \"%.*s\" not found (yet? can be registered later)\n", name.len, name.s);
|
||||
}
|
||||
|
||||
speedsGraphAdd( name, metric_index );
|
||||
if (!*next)
|
||||
break;
|
||||
p = next + 1;
|
||||
@ -724,7 +767,7 @@ static void graphCmd( void ) {
|
||||
for (int i = 2; i < argc; ++i) {
|
||||
const char *const arg = gEngine.Cmd_Argv(i);
|
||||
const const_string_view_t name = {arg, Q_strlen(arg) };
|
||||
speedsGraphRemoveByMetricName( name );
|
||||
speedsGraphRemoveByName( name );
|
||||
}
|
||||
break;
|
||||
case Clear:
|
||||
@ -739,21 +782,26 @@ static void graphCmd( void ) {
|
||||
|
||||
// update cvar
|
||||
{
|
||||
g_speeds.graphs_list[0] = '\0';
|
||||
|
||||
const int len = sizeof(g_speeds.graphs_list) - 1;
|
||||
char *const buf = g_speeds.graphs_list;
|
||||
|
||||
buf[0] = '\0';
|
||||
int off = 0;
|
||||
for (int i = 0; i < g_speeds.graphs_count; ++i) {
|
||||
const r_speeds_graph_t *const graph = g_speeds.graphs + i;
|
||||
ASSERT(graph->source_metric >= 0);
|
||||
ASSERT(graph->source_metric < g_speeds.metrics_count);
|
||||
const char *const name = g_speeds.metrics[graph->source_metric].name;
|
||||
|
||||
if (off)
|
||||
buf[off++] = ',';
|
||||
|
||||
off += Q_strncat(buf + off, name, sizeof(buf) - off);
|
||||
if (off == sizeof(buf))
|
||||
//gEngine.Con_Reportf("buf='%s' off=%d %s(%d)\n", buf, off, graph->name, (int)Q_strlen(graph->name));
|
||||
|
||||
const char *s = graph->name;
|
||||
while (off < len && *s)
|
||||
buf[off++] = *s++;
|
||||
|
||||
buf[off] = '\0';
|
||||
|
||||
if (off >= len - 1)
|
||||
break;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user