forked from playcanvas/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgpu-timer.js
More file actions
120 lines (98 loc) · 3.54 KB
/
gpu-timer.js
File metadata and controls
120 lines (98 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
function GpuTimer(app) {
this._gl = app.graphicsDevice.gl;
this._ext = app.graphicsDevice.extDisjointTimerQuery;
this._freeQueries = []; // pool of free queries
this._frameQueries = []; // current frame's queries
this._frames = []; // list of previous frame queries
this._timings = [];
this._prevTimings = [];
this.enabled = true;
app.on('frameupdate', this.begin.bind(this, 'update'));
app.on('framerender', this.mark.bind(this, 'render'));
app.on('frameend', this.end.bind(this));
}
Object.assign(GpuTimer.prototype, {
// mark the beginning of the frame
begin: function (name) {
if (!this.enabled) {
return;
}
// store previous frame's queries
if (this._frameQueries.length > 0) {
this.end();
}
// check if all in-flight queries have been invalidated
this._checkDisjoint();
// resolve previous frame timings
if (this._frames.length > 0) {
if (this._resolveFrameTimings(this._frames[0], this._prevTimings)) {
// swap
var tmp = this._prevTimings;
this._prevTimings = this._timings;
this._timings = tmp;
// free
this._freeQueries = this._freeQueries.concat(this._frames.splice(0, 1)[0]);
}
}
this.mark(name);
},
// mark
mark: function (name) {
if (!this.enabled) {
return;
}
// end previous query
if (this._frameQueries.length > 0) {
this._gl.endQuery(this._ext.TIME_ELAPSED_EXT);
}
// allocate new query and begin
var query = this._allocateQuery();
query[0] = name;
this._gl.beginQuery(this._ext.TIME_ELAPSED_EXT, query[1]);
this._frameQueries.push(query);
},
// end of frame
end: function () {
if (!this.enabled) {
return;
}
this._gl.endQuery(this._ext.TIME_ELAPSED_EXT);
this._frames.push(this._frameQueries);
this._frameQueries = [];
},
// check if the gpu has been interrupted thereby invalidating all
// in-flight queries
_checkDisjoint: function () {
var disjoint = this._gl.getParameter(this._ext.GPU_DISJOINT_EXT);
if (disjoint) {
// return all queries to the free list
this._freeQueries = [this._frames, [this._frameQueries], [this._freeQueries]].flat(2);
this._frameQueries = [];
this._frames = [];
}
},
// either returns a previously free'd query or if there aren't any allocates a new one
_allocateQuery: function () {
return (this._freeQueries.length > 0) ?
this._freeQueries.splice(-1, 1)[0] : ["", this._gl.createQuery()];
},
// attempt to resolve one frame's worth of timings
_resolveFrameTimings: function (frame, timings) {
// wait for the last query in the frame to be available
if (!this._gl.getQueryParameter(frame[frame.length - 1][1], this._gl.QUERY_RESULT_AVAILABLE)) {
return false;
}
for (var i = 0; i < frame.length; ++i) {
timings[i] = [frame[i][0], this._gl.getQueryParameter(frame[i][1], this._gl.QUERY_RESULT) * 0.000001];
}
return true;
}
});
Object.defineProperty(GpuTimer.prototype, 'timings', {
get: function () {
return this._timings.map(function (v) {
return v[1];
});
}
});
export { GpuTimer };