Backed out changeset 7272b7396c78 (bug 1932758) for causing fenix debug failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / performance / parallel_shader_compile / index.html
blob1a2a9000d44a6521cfbb8db8c0275851aa9b6eaf
1 <!--
2 Copyright (c) 2019 The Khronos Group Inc.
3 Use of this source code is governed by an MIT-style license that can be
4 found in the LICENSE.txt file.
5 -->
7 <!doctype html>
8 <html lang="en">
9 <head>
10 <meta charset="utf-8">
11 <title>Parallel Shader Compile test</title>
13 <style>
14 body {
15 margin: 0;
17 #log {
18 margin: 16px;
20 @keyframes move {
21 0% { left: 0%; }
22 50% { left: calc(100% - 64px); }
23 100% { left: 0%; }
25 #block {
26 position: relative;
27 bottom: 0%;
28 left: 0%;
29 width: 32px;
30 height: 32px;
31 background-color: #07f;
33 animation-name: move;
34 animation-duration: 2000ms;
35 animation-iteration-count: infinite;
37 .container {
38 display: flex;
39 flex-wrap: wrap;
41 .button {
42 width: 260px
44 </style>
45 </head>
46 <body>
47 <pre id='log'></pre>
49 <!-- The smoothness of the block's moving indicates whether the main thread is too busy. -->
50 <div id='block'></div>
52 <script>
53 var testGroup;
55 window.addEventListener('error', function (err) {
56 var logElement = document.getElementById('log');
57 logElement.textContent += ' \n';
58 logElement.textContent += err.error.stack.replace(
59 new RegExp(window.location.href, 'g'), '/') + '\n';
60 });
62 function setupGLContextSerial(testRun) {
63 var infoElement = testRun.logElement;
65 testRun.gl = document.createElement('canvas').getContext('webgl2');
66 if (testRun.gl) {
67 infoElement.textContent += 'webgl2 context created.' + '\n\n';
68 return true;
69 } else {
70 infoElement.textContent += 'webgl2 context is not supported.' + '\n\n';
71 return false;
75 function setupGLContextParallel(testRun) {
76 var infoElement = testRun.logElement;
77 if (setupGLContextSerial(testRun)) {
78 // Enable KHR_parallel_shader_compile extension
79 testRun.ext = testRun.gl.getExtension('KHR_parallel_shader_compile');
80 if (testRun.ext) {
81 return true;
82 } else {
83 infoElement.textContent += 'KHR_parallel_shader_compile is unavailable, you' +
84 ' may need to turn on the webgl draft extensions for your browser.'
87 return false;
90 function releasePrograms(testRun) {
91 var gl = testRun.gl;
93 var programs = testRun.programs;
94 for (var i = 0; i < programs.length; i++) {
95 var program = programs[i];
96 if (program.vShader) {
97 gl.deleteShader(program.vShader);
98 program.vShader = null;
100 if (program.fShader) {
101 gl.deleteShader(program.fShader);
102 program.fShader = null;
104 if (program.program) {
105 gl.deleteProgram(program.program);
106 program.program = null;
111 function showStatistics(testRun) {
112 var infoElement = testRun.logElement;
113 infoElement.textContent += ' ' + '\n';
114 infoElement.textContent += (Math.round(testRun.elapsedTotal * 100) / 100) +
115 'ms - ' + 'all shaders compiled, and linked.\n';
116 infoElement.textContent += ' ' + '\n';
117 infoElement.textContent += 'done.' + '\n';
119 releasePrograms(testRun);
122 function checkShader(gl, shader, infoElement) {
123 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
124 var info = gl.getShaderInfoLog(shader);
125 infoElement.textContent += 'couldn\'t compile shader:\n';
126 infoElement.textContent += info.toString() + '\n';
127 return false;
129 return true;
132 function checkProgram(gl, program, infoElement) {
133 if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
134 var info = gl.getProgramInfoLog(program);
135 infoElement.textContent += ' ' + '\n';
136 infoElement.textContent += 'couldn\'t link program:\n';
137 infoElement.textContent += info.toString() + '\n';
138 return false;
140 return true;
143 function makeAllProgramsSerial(testRun) {
144 var gl = testRun.gl;
145 var infoElement = testRun.logElement;
147 var programs = testRun.programs;
148 for (var i = 0; i < programs.length; i++) {
149 var program = programs[i];
150 // vertex shader compilation
151 var vShader = gl.createShader(gl.VERTEX_SHADER);
152 gl.shaderSource(vShader, program.vSource);
153 gl.compileShader(vShader);
154 checkShader(gl, vShader, infoElement);
156 // fragment shader compilation
157 var fShader = gl.createShader(gl.FRAGMENT_SHADER);
158 gl.shaderSource(fShader, program.fSource);
159 gl.compileShader(fShader);
160 checkShader(gl, fShader, infoElement);
162 // program
163 var programHandle = gl.createProgram();
164 gl.attachShader(programHandle, vShader);
165 gl.attachShader(programHandle, fShader);
166 gl.linkProgram(programHandle);
167 checkProgram(gl, programHandle, infoElement);
169 testRun.elapsedTotal = performance.now() - testRun.start;
170 showStatistics(testRun);
173 function makeAllProgramsParallel(testRun) {
174 var gl = testRun.gl;
175 var infoElement = testRun.logElement;
177 var programs = testRun.programs;
178 for (var i = 0; i < programs.length; i++) {
179 var program = programs[i];
180 var vShader = gl.createShader(gl.VERTEX_SHADER);
181 gl.shaderSource(vShader, program.vSource);
182 gl.compileShader(vShader);
184 var fShader = gl.createShader(gl.FRAGMENT_SHADER);
185 gl.shaderSource(fShader, program.fSource);
186 gl.compileShader(fShader);
188 programHandle = gl.createProgram();
189 gl.attachShader(programHandle, vShader);
190 gl.attachShader(programHandle, fShader);
192 program.vShader = vShader;
193 program.fShader = fShader;
194 program.program = programHandle;
195 program.status = "Compiling";
198 function checkCompletion() {
199 var ext = testRun.ext;
201 var allProgramsLinked = true;
203 for (var i = 0; i < programs.length; i++) {
204 var program = programs[i];
205 switch (program.status) {
206 case "Compiling":
207 if (gl.getShaderParameter(program.vShader, ext.COMPLETION_STATUS_KHR) &&
208 gl.getShaderParameter(program.fShader, ext.COMPLETION_STATUS_KHR))
210 checkShader(gl, program.vShader, infoElement);
211 checkShader(gl, program.fShader, infoElement);
212 gl.linkProgram(program.program);
213 program.status = "Linking";
215 allProgramsLinked = false;
216 break;
218 case "Linking":
219 if (gl.getProgramParameter(program.program, ext.COMPLETION_STATUS_KHR))
221 checkProgram(gl, program.program, infoElement);
222 program.status = "Done";
224 else {
225 allProgramsLinked = false;
227 break;
229 case "Done":
230 break;
234 if (allProgramsLinked) {
235 testRun.elapsedTotal = performance.now() - testRun.start;
236 showStatistics(testRun);
238 else {
239 requestAnimationFrame(checkCompletion);
242 requestAnimationFrame(checkCompletion);
245 function parsePrograms(testRun) {
246 var gl = testRun.gl;
247 var infoElement = testRun.logElement;
249 // Parse programs from the cached text, formatted as:
250 // __BEGINPROGRAM__
251 // __VERTEXSHADER__
252 // shader source line
253 // ...
254 // __FRAGMENTSHADER__
255 // shader source line
256 // ...
257 // __ENDPROGRAM__
259 // __BEGINPROGRAM__
260 // ...
261 var arrayOfLines = testRun.test.shaderCache.match(/[^\r\n]+/g);
262 var programs = [];
263 var currentProgram = {};
264 var currentShader;
265 var shaderSourceLine = false;
266 for (var ii = 0; ii < arrayOfLines.length; ii++) {
267 var cur = arrayOfLines[ii];
268 // Use random numbers to fool the program cache mechanism.
269 if (cur.indexOf('PROGRAM_CACHE_BREAKER_RANDOM') != -1) {
270 cur = cur.replace('PROGRAM_CACHE_BREAKER_RANDOM', Math.random())
273 if (cur == '__VERTEXSHADER__') {
274 currentShader = [];
275 shaderSourceLine = true;
276 } else if (cur == '__FRAGMENTSHADER__') {
277 currentProgram.vSource = currentShader.join('\n');
279 currentShader = [];
280 shaderSourceLine = true;
281 } else if (cur == '__ENDPROGRAM__') {
282 currentProgram.fSource = currentShader.join('\n');
283 programs.push(currentProgram);
285 currentProgram = {};
286 currentShader = [];
287 shaderSourceLine = false;
288 } else if (shaderSourceLine) {
289 currentShader.push(cur);
293 infoElement.textContent += programs.length + ' programs found.' + '\n';
294 infoElement.textContent += 'starting compilations ...' + '\n';
296 testRun.start = performance.now();
298 testRun.programs = programs;
300 testRun.makeAllPrograms(testRun);
304 function runTest(index, isParallel) {
305 var testRun = {};
306 var test = testGroup[index];
307 testRun.test = test;
308 testRun.name = test.name + (isParallel ? "_parallel" : "_serial");
309 testRun.logElement = document.getElementById(testRun.name);
310 testRun.logElement.textContent = '';
312 testRun.setupGLContext =
313 (isParallel ? setupGLContextParallel : setupGLContextSerial);
315 testRun.makeAllPrograms =
316 (isParallel ? makeAllProgramsParallel : makeAllProgramsSerial);
318 if (!testRun.setupGLContext(testRun)) {
319 return;
322 if (test.shaderCache === undefined) {
323 // load shader cache
324 var xhr = new XMLHttpRequest();
325 xhr.addEventListener('load', function() {
326 test.shaderCache = xhr.responseText;
328 requestAnimationFrame(function() {
329 parsePrograms(testRun);
332 xhr.open('GET', test.location);
333 xhr.send();
334 } else {
335 parsePrograms(testRun);
339 function createElement(element, attribute, inner) {
340 if (element === undefined) {
341 return false;
343 if (inner === undefined) {
344 inner = [];
346 var el = document.createElement(element);
347 if (typeof(attribute) === 'object') {
348 for (var key in attribute) {
349 el.setAttribute(key, attribute[key]);
352 if (!Array.isArray(inner)) {
353 inner = [inner];
355 for (var k = 0; k < inner.length; k++) {
356 if (inner[k].tagName) {
357 el.appendChild(inner[k]);
358 } else {
359 el.appendChild(document.createTextNode(inner[k]));
362 return el;
365 var container = createElement("div", {"class": "container"});
366 document.body.appendChild(container);
368 testGroup = [{
369 'location': './shaders/aquarium/shader-cache.txt',
370 'name': 'aquarium'
374 testGroup.forEach((test, index) => {
376 function createTestView(test, index, isParallel) {
378 testName = test.name + (isParallel ? "_parallel" : "_serial");
380 var tButton = createElement(
381 'button',
382 {'class': 'button', 'onclick': 'runTest(' + index + ', ' + isParallel + ')'},
383 testName
386 var tPrex = createElement("pre");
387 var tPre = createElement("textarea", { "id": testName, "rows": 10, "cols": 30});
388 var tDivContainer = createElement(
389 "div",
390 {"id": " " + testName + "_container"},
391 [tButton, tPrex, tPre]
393 container.appendChild(tDivContainer);
396 createTestView(test, index, false);
397 createTestView(test, index, true);
400 </script>
401 </body>