blob: 11076e822598cbfdf00aa18ba03e07a55f362cc1 (
plain)
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
|
using System;
using Silk.NET.OpenGL;
namespace Godosa.Desktop;
/// <summary>GPU time per frame from GL_TIME_ELAPSED queries (game-loop spec §6). A small
/// ring so reading a result never stalls on the frame still in flight; disables itself
/// when the context has no timer queries (e.g. GLES without the extension).</summary>
public sealed class GpuTimer
{
private const int Ring = 4;
private readonly uint[] _queries = new uint[Ring];
private readonly bool[] _pending = new bool[Ring];
private int _current;
private bool _open;
public bool Supported { get; private set; }
public void Init(GL gl)
{
try
{
string version = gl.GetStringS(StringName.Version) ?? "";
if (version.Contains("OpenGL ES", StringComparison.Ordinal)) return;
for (int i = 0; i < Ring; i++) _queries[i] = gl.GenQuery();
Supported = gl.GetError() == GLEnum.NoError;
}
catch (Exception)
{
Supported = false;
}
}
public void Begin(GL gl)
{
if (!Supported || _pending[_current]) return; // slot still in flight: skip this frame
gl.BeginQuery(QueryTarget.TimeElapsed, _queries[_current]);
_open = true;
}
public void End(GL gl)
{
if (!_open) return;
gl.EndQuery(QueryTarget.TimeElapsed);
_pending[_current] = true;
_open = false;
_current = (_current + 1) % Ring;
}
/// <summary>Seconds for each finished query since the last call.</summary>
public void Collect(GL gl, Action<double> onResult)
{
if (!Supported) return;
for (int i = 0; i < Ring; i++)
{
if (!_pending[i]) continue;
gl.GetQueryObject(_queries[i], QueryObjectParameterName.ResultAvailable, out int available);
if (available == 0) continue;
gl.GetQueryObject(_queries[i], QueryObjectParameterName.Result, out ulong nanoseconds);
_pending[i] = false;
onResult(nanoseconds / 1e9);
}
}
public void Delete(GL gl)
{
if (!Supported) return;
for (int i = 0; i < Ring; i++) gl.DeleteQuery(_queries[i]);
Supported = false;
}
}
|