Line data Source code
1 : /* rendertimers.cpp: renderer functionality used for displaying rendering stats
2 : * while the program is running
3 : *
4 : * timers can be created with designated start/stop points in the code; sub-ms
5 : * times needed for accurate diagnosis possible (each frame is ~16.6ms @ 60Hz)
6 : *
7 : * used in rendergl.cpp
8 : */
9 : #include "../libprimis-headers/cube.h"
10 : #include "../../shared/geomexts.h"
11 : #include "../../shared/glexts.h"
12 :
13 : #include "rendergl.h"
14 : #include "rendertext.h"
15 : #include "renderttf.h"
16 : #include "renderva.h"
17 :
18 : #include "interface/control.h"
19 :
20 : void cleanuptimers(); //needed for timer script gvar
21 : VAR(frametimer, 0, 0, 1); //toggles timing how long each frame takes (and rendering it to timer ui)
22 :
23 : struct timer final
24 : {
25 : enum
26 : {
27 : Timer_MaxQuery = 4 //max number of gl queries
28 : };
29 : const char *name; //name the timer reports as
30 : bool gpu; //whether the timer is for gpu time (true) or cpu time
31 : std::array<GLuint, Timer_MaxQuery> query; //gpu query information
32 : int waiting; //internal bitmask for queries
33 : size_t starttime; //time the timer was started (in terms of ms since game started)
34 : float result, //raw value of the timer, -1 if no info available
35 : print; //the time the timer displays: ms per frame for whatever object
36 : };
37 :
38 : //locally relevant functionality
39 : namespace
40 : {
41 : std::vector<timer> timers;
42 : std::vector<size_t> timerorder;
43 : size_t timercycle = 0;
44 :
45 0 : VARFN(timer, usetimers, 0, 0, 1, cleanuptimers()); //toggles logging timer information & rendering it
46 :
47 0 : timer *findtimer(const char *name, bool gpu) //also creates a new timer if none found
48 : {
49 0 : for(size_t i = 0; i < timers.size(); i++)
50 : {
51 0 : if(!std::strcmp(timers[i].name, name) && timers[i].gpu == gpu)
52 : {
53 0 : timerorder.erase(std::find(timerorder.begin(), timerorder.end(), i));
54 0 : timerorder.push_back(i);
55 0 : return &timers[i];
56 : }
57 : }
58 0 : timerorder.push_back(timers.size());
59 0 : timers.emplace_back();
60 0 : timer &t = timers.back();
61 0 : t.name = name;
62 0 : t.gpu = gpu;
63 0 : t.query.fill(0);
64 0 : if(gpu)
65 : {
66 0 : glGenQueries(timer::Timer_MaxQuery, t.query.data());
67 : }
68 0 : t.waiting = 0;
69 0 : t.starttime = 0;
70 0 : t.result = -1;
71 0 : t.print = -1;
72 0 : return &t;
73 : }
74 : }
75 :
76 : //externally relevant functionality
77 :
78 : //used to start a timer in some part of the code, cannot be used outside of rendering part
79 :
80 0 : timer *begintimer(const char *name, bool gpu)
81 : {
82 0 : if(!usetimers || inbetweenframes || (gpu && (!hasTQ || deferquery)))
83 : {
84 0 : return nullptr;
85 : }
86 0 : timer *t = findtimer(name, gpu);
87 0 : if(t->gpu)
88 : {
89 0 : deferquery++;
90 0 : glBeginQuery(GL_TIME_ELAPSED_EXT, t->query[timercycle]);
91 0 : t->waiting |= 1<<timercycle;
92 : }
93 : else
94 : {
95 0 : t->starttime = getclockmillis();
96 : }
97 0 : return t;
98 : }
99 :
100 : //used to end a timer started by begintimer(), needs to be included sometime after begintimer
101 : //the part between begintimer() and endtimer() is what gets timed
102 0 : void endtimer(timer *t)
103 : {
104 0 : if(!t)
105 : {
106 0 : return;
107 : }
108 0 : if(t->gpu)
109 : {
110 0 : glEndQuery(GL_TIME_ELAPSED_EXT);
111 0 : deferquery--;
112 : }
113 : else
114 : {
115 0 : t->result = std::max(static_cast<float>(getclockmillis() - t->starttime), 0.0f);
116 : }
117 : }
118 :
119 : //foreach timer, query what time has passed since last update
120 0 : void synctimers()
121 : {
122 0 : timercycle = (timercycle + 1) % timer::Timer_MaxQuery;
123 :
124 0 : for(timer& t : timers)
125 : {
126 0 : if(t.waiting&(1<<timercycle))
127 : {
128 0 : GLint available = 0;
129 0 : while(!available)
130 : {
131 0 : glGetQueryObjectiv(t.query[timercycle], GL_QUERY_RESULT_AVAILABLE, &available);
132 : }
133 0 : GLuint64EXT result = 0;
134 0 : glGetQueryObjectui64v(t.query[timercycle], GL_QUERY_RESULT, &result);
135 0 : t.result = std::max(static_cast<float>(result) * 1e-6f, 0.0f);
136 0 : t.waiting &= ~(1<<timercycle);
137 : }
138 : else
139 : {
140 0 : t.result = -1;
141 : }
142 : }
143 0 : }
144 :
145 0 : void cleanuptimers()
146 : {
147 0 : for(const timer& t : timers)
148 : {
149 0 : if(t.gpu)
150 : {
151 0 : glDeleteQueries(timer::Timer_MaxQuery, t.query.data());
152 : }
153 : }
154 0 : timers.clear();
155 0 : timerorder.clear();
156 0 : }
157 :
158 0 : void printtimers(int conw, int framemillis)
159 : {
160 0 : if(!frametimer && !usetimers)
161 : {
162 0 : return;
163 : }
164 : static int lastprint = 0;
165 0 : int offset = 0;
166 0 : if(frametimer)
167 : {
168 : static int printmillis = 0;
169 0 : if(totalmillis - lastprint >= 200)
170 : {
171 0 : printmillis = framemillis;
172 : }
173 : std::array<char, 200> framestring;
174 0 : constexpr int size = 42;
175 0 : std::sprintf(framestring.data(), "frame time %i ms", printmillis);
176 0 : ttr.fontsize(size);
177 0 : ttr.renderttf(framestring.data(), {0xFF, 0xFF, 0xFF, 0}, conw-20*size, size*3/2+offset*9*size/8);
178 : //draw_textf("frame time %i ms", conw-20*FONTH, conh-FONTH*3/2-offset*9*FONTH/8, printmillis);
179 0 : offset++;
180 : }
181 0 : if(usetimers)
182 : {
183 0 : for(int i : timerorder)
184 : {
185 0 : timer &t = timers[i];
186 0 : if(t.print < 0 ? t.result >= 0 : totalmillis - lastprint >= 200)
187 : {
188 0 : t.print = t.result;
189 : }
190 0 : if(t.print < 0 || (t.gpu && !(t.waiting&(1<<timercycle))))
191 : {
192 0 : continue;
193 : }
194 : std::array<char, 200> framestring;
195 0 : constexpr int size = 42;
196 0 : std::sprintf(framestring.data(), "%s%s %5.2f ms", t.name, t.gpu ? "" : " (cpu)", t.print);
197 0 : ttr.fontsize(size);
198 0 : ttr.renderttf(framestring.data(), {0xFF, 0xFF, 0xFF, 0}, conw-20*size, size*3/2+offset*9*size/8);
199 :
200 : //draw_textf("%s%s %5.2f ms", conw-20*FONTH, conh-FONTH*3/2-offset*9*FONTH/8, t.name, t.gpu ? "" : " (cpu)", t.print);
201 0 : offset++;
202 : }
203 : }
204 0 : if(totalmillis - lastprint >= 200)
205 : {
206 0 : lastprint = totalmillis;
207 : }
208 : }
|