-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
166 lines (146 loc) · 6.84 KB
/
index.html
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VSync Simulator</title>
<style>
#output {
width: 100%;
height: 400px;
margin: 0 auto;
margin-top: 10px;
border-left: 0px;
border-right: 0px;
padding-left: 0px;
padding-right: 0px;
display: block;
background-color: black;
color: white;
font-family: 'Lucida Console', Monaco, monospace;
outline: none;
}
.column {
float: left;
width: 33.33%;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
</style>
</head>
<body>
<div id="settings"></div>
<textarea id="output" rows="64"></textarea>
<script type='text/javascript'>
g_params = [
// ["vblank_interval", default_val, min, max]
["vblank_interval", 16, 1, 100],
["buffer_count", 2, 1, 3],
["swapchain_count", 2, 1, 4],
["cpu_time", 12, 0, 100],
["cpu_time_variance", 2, 0, 100],
["gpu_time", 14, 0, 100],
["gpu_time_variance", 2, 0, 100],
["num_ticks", 500, 1, 1000],
]
function createAll() {
var settingsDiv = document.getElementById("settings");
for (const param of g_params) {
var rowDiv = document.createElement('div')
rowDiv.setAttribute('class', 'row')
settingsDiv.appendChild(rowDiv)
var descElem = document.createElement('text')
descElem.innerHTML = param[0]
var elem = document.createElement('input')
elem.setAttribute('type', 'range')
elem.setAttribute('title', param[0])
elem.setAttribute('id', param[0])
elem.setAttribute('min', param[2])
elem.setAttribute('max', param[3])
elem.setAttribute('value', param[1])
elem.addEventListener('change', onSliderChanged)
txtElem = document.createElement('text')
txtElem.setAttribute('id', "text_" + param[0])
txtElem.innerHTML = elem.value
var cells = [descElem, elem, txtElem]
for (const cell of cells) {
var colDiv = document.createElement('div')
colDiv.setAttribute('class', 'column')
colDiv.appendChild(cell)
rowDiv.appendChild(colDiv)
}
}
}
function populateParams() {
// Module['arguments'] = [];
args = []
for (const param of g_params) {
const elemSlider = document.getElementById(param[0]);
const txtElem = document.getElementById("text_" + param[0]);
txtElem.innerHTML = elemSlider.value // Update UI
if (param[0] != "num_ticks" && param[0] != "buffer_count" && param[0] != "swapchain_count")
txtElem.innerHTML += "ms"
args.push("--" + param[0]);
args.push(elemSlider.value);
}
Module.callMain(args);
}
function onSliderChanged(event) {
populateParams();
}
var Module = {
// Don't run main() on page load
noInitialRun: true,
preRun: [],
postRun: [],
onRuntimeInitialized: () => {
createAll();
populateParams();
},
print: (function() {
var element = document.getElementById('output');
if (element) element.value = ''; // clear browser cache
return function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&");
//text = text.replace(/</g, "<");
//text = text.replace(/>/g, ">");
//text = text.replace('\n', '<br>', 'g');
console.log(text);
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
};
})()
};
</script>
<p>This simulator simulates worst-case latency when presenting assuming that:</p>
<ul>
<li>The CPU takes cpu_time +/- cpu_time_variance to prepare the commands (randomized)</li>
<li>The GPU takes gpu_time +/- gpu_time_variance to render (randomized)</li>
<li>VSync is Enabled and in FIFO mode</li>
</ul>
<p>Please note vblank_interval is 16ms, not 16.667 which corresponds to a 62.50hz monitor instead of 60hz.</p>
<p>The main purpose of this simulator is to understand the effects of buffer_count & swapchain_count and how they vary on different conditions.</p>
<p>Actual lag can be reduced if the CPU waits to prepare commands instead of starting as soon as possible. For more info see <a href="https://askubuntu.com/a/1420575/274245">my reply on Ask Ubuntu</a> and see
<a href="https://www.gdcvault.com/play/1026327/Controller-to-Display-Latency-in">Controller to Display Latency in Call of Duty</a>.</p>
<p>It is also not meant to be 100% accurate. GPU drivers can use tricks (e.g. often called "Anti Lag" or "Low Latency") to forcefully induce CPU sleeping, or may have implementation quirks that are not considered by the simulator.</p>
<p>Observe that in general:</p>
<ul>
<li>Double Buffer (swapchain_count = 2) reduces latency unless we can't hit VBLANK.</li>
<li>Triple Buffer (swapchain_count = 3) only reduces latency if we frequently miss VBLANK.</li>
<li>Higher buffer_count can increase framerate considerably if gpu_time is much higher than cpu_time, but latency suffers a lot.</li>
<li>Higher buffer_count dampens the stutter mess caused by very large cpu_time_variance and thus miss fewer VBLANKs. This reduces the Lag Std. Deviation.</li>
<li>Higher swapchain_count has the same effect when gpu_time_variance is large and miss fewer VBLANKs.</li>
<li>Don't just observe average framerate & lag. Min 1% and lag variance is very important. Plot it in a graph if you have to.</li>
</ul>
<p>Source Code <a href="https://github.com/darksylinc/vsync_simulator">can be found on Github</a>. You can also find more info there.</p>
<script async type="text/javascript" src="main.js"></script>
</body>
</html>