4 cvar_t r_speeds_graph = {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph", "0", "display a graph of renderer statistics "};
5 cvar_t r_speeds_graph_filter[8] =
7 {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_filter_r", "timedelta", "Red - display the specified renderer statistic"},
8 {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_filter_g", "batch_batches", "Green - display the specified renderer statistic"},
9 {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_filter_b", "batch_triangles", "Blue - display the specified renderer statistic"},
10 {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_filter_y", "fast_triangles", "Yellow - display the specified renderer statistic"},
11 {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_filter_c", "copytriangles_triangles", "Cyan - display the specified renderer statistic"},
12 {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_filter_m", "dynamic_triangles", "Magenta - display the specified renderer statistic"},
13 {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_filter_w", "animcache_shade_vertices", "White - display the specified renderer statistic"},
14 {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_filter_o", "animcache_shape_vertices", "Orange - display the specified renderer statistic"},
16 cvar_t r_speeds_graph_length = {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_length", "1024", "number of frames in statistics graph, can be from 4 to 8192"};
17 cvar_t r_speeds_graph_seconds = {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_seconds", "2", "number of seconds in graph, can be from 0.1 to 120"};
18 cvar_t r_speeds_graph_x = {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_x", "0", "position of graph"};
19 cvar_t r_speeds_graph_y = {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_y", "0", "position of graph"};
20 cvar_t r_speeds_graph_width = {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_width", "256", "size of graph"};
21 cvar_t r_speeds_graph_height = {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_height", "128", "size of graph"};
22 cvar_t r_speeds_graph_maxtimedelta = {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_maxtimedelta", "16667", "maximum timedelta to display in the graph (this value will be the top line)"};
23 cvar_t r_speeds_graph_maxdefault = {CF_CLIENT | CF_ARCHIVE, "r_speeds_graph_maxdefault", "100", "if the minimum and maximum observed values are closer than this, use this value as the graph range (keeps small numbers from being big graphs)"};
26 const char *r_stat_name[r_stat_count] =
39 "lightmapupdatepixels",
49 "lights_lighttriangles",
50 "lights_shadowtriangles",
51 "lights_dynamicshadowtriangles",
53 "bouncegrid_particles",
58 "photoncache_animated",
65 "rendertargets_pixels",
66 "indexbufferuploadcount",
67 "indexbufferuploadsize",
68 "vertexbufferuploadcount",
69 "vertexbufferuploadsize",
72 "bufferdatacurrent_vertex", // R_BUFFERDATA_ types are added to this index
73 "bufferdatacurrent_index16",
74 "bufferdatacurrent_index32",
75 "bufferdatacurrent_uniform",
76 "bufferdatasize_vertex", // R_BUFFERDATA_ types are added to this index
77 "bufferdatasize_index16",
78 "bufferdatasize_index32",
79 "bufferdatasize_uniform",
80 "animcache_skeletal_count",
81 "animcache_skeletal_bones",
82 "animcache_skeletal_maxbones",
83 "animcache_shade_count",
84 "animcache_shade_vertices",
85 "animcache_shade_maxvertices",
86 "animcache_shape_count",
87 "animcache_shape_vertices",
88 "animcache_shape_maxvertices",
98 "copytriangles_batches",
99 "copytriangles_surfaces",
100 "copytriangles_vertices",
101 "copytriangles_triangles",
106 "dynamicskeletal_batches",
107 "dynamicskeletal_surfaces",
108 "dynamicskeletal_vertices",
109 "dynamicskeletal_triangles",
110 "dynamic_batches_because_cvar",
111 "dynamic_surfaces_because_cvar",
112 "dynamic_vertices_because_cvar",
113 "dynamic_triangles_because_cvar",
114 "dynamic_batches_because_lightmapvertex",
115 "dynamic_surfaces_because_lightmapvertex",
116 "dynamic_vertices_because_lightmapvertex",
117 "dynamic_triangles_because_lightmapvertex",
118 "dynamic_batches_because_deformvertexes_autosprite",
119 "dynamic_surfaces_because_deformvertexes_autosprite",
120 "dynamic_vertices_because_deformvertexes_autosprite",
121 "dynamic_triangles_because_deformvertexes_autosprite",
122 "dynamic_batches_because_deformvertexes_autosprite2",
123 "dynamic_surfaces_because_deformvertexes_autosprite2",
124 "dynamic_vertices_because_deformvertexes_autosprite2",
125 "dynamic_triangles_because_deformvertexes_autosprite2",
126 "dynamic_batches_because_deformvertexes_normal",
127 "dynamic_surfaces_because_deformvertexes_normal",
128 "dynamic_vertices_because_deformvertexes_normal",
129 "dynamic_triangles_because_deformvertexes_normal",
130 "dynamic_batches_because_deformvertexes_wave",
131 "dynamic_surfaces_because_deformvertexes_wave",
132 "dynamic_vertices_because_deformvertexes_wave",
133 "dynamic_triangles_because_deformvertexes_wave",
134 "dynamic_batches_because_deformvertexes_bulge",
135 "dynamic_surfaces_because_deformvertexes_bulge",
136 "dynamic_vertices_because_deformvertexes_bulge",
137 "dynamic_triangles_because_deformvertexes_bulge",
138 "dynamic_batches_because_deformvertexes_move",
139 "dynamic_surfaces_because_deformvertexes_move",
140 "dynamic_vertices_because_deformvertexes_move",
141 "dynamic_triangles_because_deformvertexes_move",
142 "dynamic_batches_because_tcgen_lightmap",
143 "dynamic_surfaces_because_tcgen_lightmap",
144 "dynamic_vertices_because_tcgen_lightmap",
145 "dynamic_triangles_because_tcgen_lightmap",
146 "dynamic_batches_because_tcgen_vector",
147 "dynamic_surfaces_because_tcgen_vector",
148 "dynamic_vertices_because_tcgen_vector",
149 "dynamic_triangles_because_tcgen_vector",
150 "dynamic_batches_because_tcgen_environment",
151 "dynamic_surfaces_because_tcgen_environment",
152 "dynamic_vertices_because_tcgen_environment",
153 "dynamic_triangles_because_tcgen_environment",
154 "dynamic_batches_because_tcmod_turbulent",
155 "dynamic_surfaces_because_tcmod_turbulent",
156 "dynamic_vertices_because_tcmod_turbulent",
157 "dynamic_triangles_because_tcmod_turbulent",
158 "dynamic_batches_because_nogaps",
159 "dynamic_surfaces_because_nogaps",
160 "dynamic_vertices_because_nogaps",
161 "dynamic_triangles_because_nogaps",
162 "dynamic_batches_because_derived",
163 "dynamic_surfaces_because_derived",
164 "dynamic_vertices_because_derived",
165 "dynamic_triangles_because_derived",
167 "entitycache_surfaces",
168 "entitycache_vertices",
169 "entitycache_triangles",
170 "entityanimate_count",
171 "entityanimate_surfaces",
172 "entityanimate_vertices",
173 "entityanimate_triangles",
174 "entityskeletal_count",
175 "entityskeletal_surfaces",
176 "entityskeletal_vertices",
177 "entityskeletal_triangles",
178 "entitystatic_count",
179 "entitystatic_surfaces",
180 "entitystatic_vertices",
181 "entitystatic_triangles",
182 "entitycustom_count",
183 "entitycustom_surfaces",
184 "entitycustom_vertices",
185 "entitycustom_triangles",
188 char r_speeds_timestring[4096];
189 int speedstringcount, r_timereport_active;
190 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
191 int r_speeds_longestitem = 0;
193 void R_TimeReport(const char *desc)
199 if (r_speeds.integer < 2 || !r_timereport_active)
203 if (r_speeds.integer == 2)
206 r_timereport_temp = r_timereport_current;
207 r_timereport_current = Sys_DirtyTime();
208 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0 + 0.5);
210 length = dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %s", t, desc);
212 length = (int)sizeof(tempbuf) - 1;
213 if (r_speeds_longestitem < length)
214 r_speeds_longestitem = length;
215 for (;length < r_speeds_longestitem;length++)
216 tempbuf[length] = ' ';
219 if (speedstringcount + length > (vid_conwidth.integer / 8))
221 strlcat(r_speeds_timestring, "\n", sizeof(r_speeds_timestring));
222 speedstringcount = 0;
224 strlcat(r_speeds_timestring, tempbuf, sizeof(r_speeds_timestring));
225 speedstringcount += length;
228 void R_TimeReport_BeginFrame(void)
230 speedstringcount = 0;
231 r_speeds_timestring[0] = 0;
232 r_timereport_active = false;
233 memset(&r_refdef.stats, 0, sizeof(r_refdef.stats));
235 if (r_speeds.integer >= 2)
237 r_timereport_active = true;
238 r_timereport_start = r_timereport_current = Sys_DirtyTime();
242 static int R_CountLeafTriangles(const model_t *model, const mleaf_t *leaf)
244 int i, triangles = 0;
245 for (i = 0;i < leaf->numleafsurfaces;i++)
246 triangles += model->data_surfaces[leaf->firstleafsurface[i]].num_triangles;
250 #define R_SPEEDS_GRAPH_COLORS 8
251 #define R_SPEEDS_GRAPH_TEXTLENGTH 64
252 static float r_speeds_graph_colors[R_SPEEDS_GRAPH_COLORS][4] = {{1, 0, 0, 1}, {0, 1, 0, 1}, {0, 0, 1, 1}, {1, 1, 0, 1}, {0, 1, 1, 1}, {1, 0, 1, 1}, {1, 1, 1, 1}, {1, 0.5f, 0, 1}};
254 extern float viewscalefpsadjusted;
255 void R_TimeReport_EndFrame(void)
259 char string[1024+4096];
261 static double oldtime = 0;
263 r_refdef.stats[r_stat_timedelta] = (int)((host.realtime - oldtime) * 1000000.0);
264 oldtime = host.realtime;
265 r_refdef.stats[r_stat_quality] = (int)(100 * r_refdef.view.quality);
268 if (r_speeds.integer)
270 // put the location name in the r_speeds display as it greatly helps
271 // when creating loc files
272 loc = CL_Locs_FindNearest(cl.movement_origin);
273 viewleaf = (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.PointInLeaf) ? r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, r_refdef.view.origin) : NULL;
274 dpsnprintf(string, sizeof(string),
275 "%6ius time delta %s%s %.3f cl.time%2.4f brightness\n"
276 "%3i renders org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n"
277 "%5i viewleaf%5i cluster%3i area%4i brushes%4i surfaces(%7i triangles)\n"
278 "%7i surfaces%7i triangles %5i entities (%7i surfaces%7i triangles)\n"
279 "%5i leafs%5i portals%6i/%6i particles%6i/%6i decals %3i%% quality\n"
280 "%7i lightmap updates (%7i pixels)%8i/%8i framedata\n"
281 "%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n"
282 "bouncegrid:%4i lights%6i particles%6i traces%6i hits%6i splats%6i bounces\n"
283 "photon cache efficiency:%6i cached%6i traced%6ianimated\n"
284 "%6i draws%8i vertices%8i triangles bloompixels%8i copied%8i drawn\n"
285 "%3i rendertargets%8i pixels\n"
286 "updated%5i indexbuffers%8i bytes%5i vertexbuffers%8i bytes\n"
287 "animcache%5ib gpuskeletal%7i vertices (%7i with normals)\n"
288 "fastbatch%5i count%5i surfaces%7i vertices %7i triangles\n"
289 "copytris%5i count%5i surfaces%7i vertices %7i triangles\n"
290 "dynamic%5i count%5i surfaces%7i vertices%7i triangles\n"
292 , r_refdef.stats[r_stat_timedelta], loc ? "Location: " : "", loc ? loc->name : "", cl.time, r_refdef.view.colorscale
293 , r_refdef.stats[r_stat_renders], r_refdef.view.origin[0], r_refdef.view.origin[1], r_refdef.view.origin[2], r_refdef.view.forward[0], r_refdef.view.forward[1], r_refdef.view.forward[2]
294 , viewleaf ? (int)(viewleaf - r_refdef.scene.worldmodel->brush.data_leafs) : -1, viewleaf ? viewleaf->clusterindex : -1, viewleaf ? viewleaf->areaindex : -1, viewleaf ? viewleaf->numleafbrushes : 0, viewleaf ? viewleaf->numleafsurfaces : 0, viewleaf ? R_CountLeafTriangles(r_refdef.scene.worldmodel, viewleaf) : 0
295 , r_refdef.stats[r_stat_world_surfaces], r_refdef.stats[r_stat_world_triangles], r_refdef.stats[r_stat_entities], r_refdef.stats[r_stat_entities_surfaces], r_refdef.stats[r_stat_entities_triangles]
296 , r_refdef.stats[r_stat_world_leafs], r_refdef.stats[r_stat_world_portals], r_refdef.stats[r_stat_particles], cl.num_particles, r_refdef.stats[r_stat_drawndecals], r_refdef.stats[r_stat_totaldecals], r_refdef.stats[r_stat_quality]
297 , r_refdef.stats[r_stat_lightmapupdates], r_refdef.stats[r_stat_lightmapupdatepixels], r_refdef.stats[r_stat_framedatacurrent], r_refdef.stats[r_stat_framedatasize]
298 , r_refdef.stats[r_stat_lights], r_refdef.stats[r_stat_lights_clears], r_refdef.stats[r_stat_lights_scissored], r_refdef.stats[r_stat_lights_lighttriangles], r_refdef.stats[r_stat_lights_shadowtriangles], r_refdef.stats[r_stat_lights_dynamicshadowtriangles]
299 , r_refdef.stats[r_stat_bouncegrid_lights], r_refdef.stats[r_stat_bouncegrid_particles], r_refdef.stats[r_stat_bouncegrid_traces], r_refdef.stats[r_stat_bouncegrid_hits], r_refdef.stats[r_stat_bouncegrid_splats], r_refdef.stats[r_stat_bouncegrid_bounces]
300 , r_refdef.stats[r_stat_photoncache_cached], r_refdef.stats[r_stat_photoncache_traced], r_refdef.stats[r_stat_photoncache_animated]
301 , r_refdef.stats[r_stat_draws], r_refdef.stats[r_stat_draws_vertices], r_refdef.stats[r_stat_draws_elements] / 3, r_refdef.stats[r_stat_bloom_copypixels], r_refdef.stats[r_stat_bloom_drawpixels]
302 , r_refdef.stats[r_stat_rendertargets_used], r_refdef.stats[r_stat_rendertargets_pixels]
303 , r_refdef.stats[r_stat_indexbufferuploadcount], r_refdef.stats[r_stat_indexbufferuploadsize], r_refdef.stats[r_stat_vertexbufferuploadcount], r_refdef.stats[r_stat_vertexbufferuploadsize]
304 , r_refdef.stats[r_stat_animcache_skeletal_bones], r_refdef.stats[r_stat_animcache_shape_vertices], r_refdef.stats[r_stat_animcache_shade_vertices]
305 , r_refdef.stats[r_stat_batch_fast_batches], r_refdef.stats[r_stat_batch_fast_surfaces], r_refdef.stats[r_stat_batch_fast_vertices], r_refdef.stats[r_stat_batch_fast_triangles]
306 , r_refdef.stats[r_stat_batch_copytriangles_batches], r_refdef.stats[r_stat_batch_copytriangles_surfaces], r_refdef.stats[r_stat_batch_copytriangles_vertices], r_refdef.stats[r_stat_batch_copytriangles_triangles]
307 , r_refdef.stats[r_stat_batch_dynamic_batches], r_refdef.stats[r_stat_batch_dynamic_surfaces], r_refdef.stats[r_stat_batch_dynamic_vertices], r_refdef.stats[r_stat_batch_dynamic_triangles]
308 , r_speeds_timestring);
311 speedstringcount = 0;
312 r_speeds_timestring[0] = 0;
313 r_timereport_active = false;
315 if (r_speeds.integer >= 2)
317 r_timereport_active = true;
318 r_timereport_start = r_timereport_current = Sys_DirtyTime();
324 if (string[strlen(string)-1] == '\n')
325 string[strlen(string)-1] = 0;
327 for (i = 0;string[i];i++)
328 if (string[i] == '\n')
330 y = vid_conheight.integer - sb_lines - lines * 8;
332 r_draw2d_force = true;
333 DrawQ_Fill(0, y, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
337 while (string[i] && string[i] != '\n')
340 DrawQ_String(0, y, string + j, i - j, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);
341 if (string[i] == '\n')
345 r_draw2d_force = false;
348 if (r_speeds_graph_length.integer != bound(4, r_speeds_graph_length.integer, 8192))
349 Cvar_SetValueQuick(&r_speeds_graph_length, bound(4, r_speeds_graph_length.integer, 8192));
350 if (fabs(r_speeds_graph_seconds.value - bound(0.1f, r_speeds_graph_seconds.value, 120.0f)) > 0.01f)
351 Cvar_SetValueQuick(&r_speeds_graph_seconds, bound(0.1f, r_speeds_graph_seconds.value, 120.0f));
352 if (r_speeds_graph.integer)
354 // if we currently have no graph data, reset the graph data entirely
356 if (!cls.r_speeds_graph_data)
357 for (i = 0;i < r_stat_count;i++)
358 cls.r_speeds_graph_datamin[i] = cls.r_speeds_graph_datamax[i] = 0;
359 if (cls.r_speeds_graph_length != r_speeds_graph_length.integer)
361 int stat, index, d, graph_length, *graph_data;
362 cls.r_speeds_graph_length = r_speeds_graph_length.integer;
363 cls.r_speeds_graph_current = 0;
364 if (cls.r_speeds_graph_data)
365 Mem_Free(cls.r_speeds_graph_data);
366 cls.r_speeds_graph_data = (int *)Mem_Alloc(cls.permanentmempool, cls.r_speeds_graph_length * sizeof(r_refdef.stats));
367 // initialize the graph to have the current values throughout history
368 graph_data = cls.r_speeds_graph_data;
369 graph_length = cls.r_speeds_graph_length;
371 for (stat = 0;stat < r_stat_count;stat++)
373 d = r_refdef.stats[stat];
374 if (stat == r_stat_timedelta)
376 for (i = 0;i < graph_length;i++)
377 graph_data[index++] = d;
383 if (cls.r_speeds_graph_length)
385 cls.r_speeds_graph_length = 0;
386 Mem_Free(cls.r_speeds_graph_data);
387 cls.r_speeds_graph_data = NULL;
388 cls.r_speeds_graph_current = 0;
392 if (cls.r_speeds_graph_length)
397 float x, y, width, height, scalex, scaley;
398 int range_default = max(r_speeds_graph_maxdefault.integer, 1);
399 int color, stat, stats, index, range_min, range_max;
400 int graph_current, graph_length, *graph_data;
401 int statindex[R_SPEEDS_GRAPH_COLORS];
404 // add current stats to the graph_data
405 cls.r_speeds_graph_current++;
406 if (cls.r_speeds_graph_current >= cls.r_speeds_graph_length)
407 cls.r_speeds_graph_current = 0;
408 // poke each new stat into the current offset of its graph
409 graph_data = cls.r_speeds_graph_data;
410 graph_current = cls.r_speeds_graph_current;
411 graph_length = cls.r_speeds_graph_length;
412 for (stat = 0;stat < r_stat_count;stat++)
413 graph_data[stat * graph_length + graph_current] = r_refdef.stats[stat];
415 // update the graph ranges
416 for (stat = 0;stat < r_stat_count;stat++)
418 if (cls.r_speeds_graph_datamin[stat] > r_refdef.stats[stat])
419 cls.r_speeds_graph_datamin[stat] = r_refdef.stats[stat];
420 if (cls.r_speeds_graph_datamax[stat] < r_refdef.stats[stat])
421 cls.r_speeds_graph_datamax[stat] = r_refdef.stats[stat];
424 // force 2D drawing to occur even if r_render is 0
425 r_draw2d_force = true;
427 // position the graph
428 width = r_speeds_graph_width.value;
429 height = r_speeds_graph_height.value;
430 x = bound(0, r_speeds_graph_x.value, vid_conwidth.value - width);
431 y = bound(0, r_speeds_graph_y.value, vid_conheight.value - height);
433 // fill background with a pattern of gray and black at one second intervals
434 scalex = (float)width / (float)r_speeds_graph_seconds.value;
435 for (i = 0;i < r_speeds_graph_seconds.integer + 1;i++)
437 float x1 = x + width - (i + 1) * scalex;
438 float x2 = x + width - i * scalex;
442 DrawQ_Fill(x1, y, x2 - x1, height, 0.0f, 0.0f, 0.0f, 0.5f, 0);
444 DrawQ_Fill(x1, y, x2 - x1, height, 0.2f, 0.2f, 0.2f, 0.5f, 0);
447 // count how many stats match our pattern
450 for (color = 0;color < R_SPEEDS_GRAPH_COLORS;color++)
452 // look at all stat names and find ones matching the filter
453 statindex[color] = -1;
454 if (!r_speeds_graph_filter[color].string)
456 for (stat = 0;stat < r_stat_count;stat++)
457 if (!strcmp(r_stat_name[stat], r_speeds_graph_filter[color].string))
459 if (stat >= r_stat_count)
461 // record that this color is this stat for the line drawing loop
462 statindex[color] = stat;
463 // draw the legend text in the background of the graph
464 dpsnprintf(legend, sizeof(legend), "%10i :%s", graph_data[stat * graph_length + graph_current], r_stat_name[stat]);
465 DrawQ_String(x, y + stats * 8, legend, 0, 8, 8, r_speeds_graph_colors[color][0], r_speeds_graph_colors[color][1], r_speeds_graph_colors[color][2], r_speeds_graph_colors[color][3] * 1.00f, 0, NULL, true, FONT_DEFAULT);
466 // count how many stats we need to graph in vertex buffer
472 // legend text is drawn after the graphs
473 // render the graph lines, we'll go back and render the legend text later
474 scalex = (float)width / (1000000.0 * r_speeds_graph_seconds.value);
476 for (color = 0;color < R_SPEEDS_GRAPH_COLORS;color++)
478 // look at all stat names and find ones matching the filter
479 stat = statindex[color];
482 // prefer to graph stats with 0 base, but if they are
483 // negative we have no choice
484 range_min = cls.r_speeds_graph_datamin[stat];
485 range_max = max(cls.r_speeds_graph_datamax[stat], range_min + range_default);
486 // some stats we specifically override the graph scale on
487 if (stat == r_stat_timedelta)
488 range_max = r_speeds_graph_maxtimedelta.integer;
489 scaley = height / (range_max - range_min);
490 // generate lines (2 vertices each)
491 // to deal with incomplete data we walk right to left
492 data = graph_data + stat * graph_length;
493 index = graph_current;
495 for (i = 0;i < graph_length - 1;)
497 float x1, y1, x2, y2;
498 x1 = max(x, x + width - sum * scalex);
499 y1 = y + height - (data[index] - range_min) * scaley;
500 sum += graph_data[r_stat_timedelta * graph_length + index];
503 index = graph_length - 1;
505 x2 = max(x, x + width - sum * scalex);
506 y2 = y + height - (data[index] - range_min) * scaley;
507 DrawQ_Line(1, x1, y1, x2, y2, r_speeds_graph_colors[color][0], r_speeds_graph_colors[color][1], r_speeds_graph_colors[color][2], r_speeds_graph_colors[color][3], 0, true);
512 // return to not drawing anything if r_render is 0
513 r_draw2d_force = false;
516 memset(&r_refdef.stats, 0, sizeof(r_refdef.stats));