summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/index.html
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/index.html401
1 files changed, 401 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/index.html b/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/index.html
new file mode 100644
index 0000000000..1a2a9000d4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/index.html
@@ -0,0 +1,401 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Parallel Shader Compile test</title>
+
+ <style>
+ body {
+ margin: 0;
+ }
+ #log {
+ margin: 16px;
+ }
+ @keyframes move {
+ 0% { left: 0%; }
+ 50% { left: calc(100% - 64px); }
+ 100% { left: 0%; }
+ }
+ #block {
+ position: relative;
+ bottom: 0%;
+ left: 0%;
+ width: 32px;
+ height: 32px;
+ background-color: #07f;
+
+ animation-name: move;
+ animation-duration: 2000ms;
+ animation-iteration-count: infinite;
+ }
+ .container {
+ display: flex;
+ flex-wrap: wrap;
+ }
+ .button {
+ width: 260px
+ }
+ </style>
+</head>
+<body>
+ <pre id='log'></pre>
+
+ <!-- The smoothness of the block's moving indicates whether the main thread is too busy. -->
+ <div id='block'></div>
+
+ <script>
+ var testGroup;
+
+ window.addEventListener('error', function (err) {
+ var logElement = document.getElementById('log');
+ logElement.textContent += ' \n';
+ logElement.textContent += err.error.stack.replace(
+ new RegExp(window.location.href, 'g'), '/') + '\n';
+ });
+
+ function setupGLContextSerial(testRun) {
+ var infoElement = testRun.logElement;
+
+ testRun.gl = document.createElement('canvas').getContext('webgl2');
+ if (testRun.gl) {
+ infoElement.textContent += 'webgl2 context created.' + '\n\n';
+ return true;
+ } else {
+ infoElement.textContent += 'webgl2 context is not supported.' + '\n\n';
+ return false;
+ }
+ }
+
+ function setupGLContextParallel(testRun) {
+ var infoElement = testRun.logElement;
+ if (setupGLContextSerial(testRun)) {
+ // Enable KHR_parallel_shader_compile extension
+ testRun.ext = testRun.gl.getExtension('KHR_parallel_shader_compile');
+ if (testRun.ext) {
+ return true;
+ } else {
+ infoElement.textContent += 'KHR_parallel_shader_compile is unavailable, you' +
+ ' may need to turn on the webgl draft extensions for your browser.'
+ }
+ }
+ return false;
+ }
+
+ function releasePrograms(testRun) {
+ var gl = testRun.gl;
+
+ var programs = testRun.programs;
+ for (var i = 0; i < programs.length; i++) {
+ var program = programs[i];
+ if (program.vShader) {
+ gl.deleteShader(program.vShader);
+ program.vShader = null;
+ }
+ if (program.fShader) {
+ gl.deleteShader(program.fShader);
+ program.fShader = null;
+ }
+ if (program.program) {
+ gl.deleteProgram(program.program);
+ program.program = null;
+ }
+ }
+ }
+
+ function showStatistics(testRun) {
+ var infoElement = testRun.logElement;
+ infoElement.textContent += ' ' + '\n';
+ infoElement.textContent += (Math.round(testRun.elapsedTotal * 100) / 100) +
+ 'ms - ' + 'all shaders compiled, and linked.\n';
+ infoElement.textContent += ' ' + '\n';
+ infoElement.textContent += 'done.' + '\n';
+
+ releasePrograms(testRun);
+ }
+
+ function checkShader(gl, shader, infoElement) {
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ var info = gl.getShaderInfoLog(shader);
+ infoElement.textContent += 'couldn\'t compile shader:\n';
+ infoElement.textContent += info.toString() + '\n';
+ return false;
+ }
+ return true;
+ }
+
+ function checkProgram(gl, program, infoElement) {
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+ var info = gl.getProgramInfoLog(program);
+ infoElement.textContent += ' ' + '\n';
+ infoElement.textContent += 'couldn\'t link program:\n';
+ infoElement.textContent += info.toString() + '\n';
+ return false;
+ }
+ return true;
+ }
+
+ function makeAllProgramsSerial(testRun) {
+ var gl = testRun.gl;
+ var infoElement = testRun.logElement;
+
+ var programs = testRun.programs;
+ for (var i = 0; i < programs.length; i++) {
+ var program = programs[i];
+ // vertex shader compilation
+ var vShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vShader, program.vSource);
+ gl.compileShader(vShader);
+ checkShader(gl, vShader, infoElement);
+
+ // fragment shader compilation
+ var fShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fShader, program.fSource);
+ gl.compileShader(fShader);
+ checkShader(gl, fShader, infoElement);
+
+ // program
+ var programHandle = gl.createProgram();
+ gl.attachShader(programHandle, vShader);
+ gl.attachShader(programHandle, fShader);
+ gl.linkProgram(programHandle);
+ checkProgram(gl, programHandle, infoElement);
+ }
+ testRun.elapsedTotal = performance.now() - testRun.start;
+ showStatistics(testRun);
+ };
+
+ function makeAllProgramsParallel(testRun) {
+ var gl = testRun.gl;
+ var infoElement = testRun.logElement;
+
+ var programs = testRun.programs;
+ for (var i = 0; i < programs.length; i++) {
+ var program = programs[i];
+ var vShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vShader, program.vSource);
+ gl.compileShader(vShader);
+
+ var fShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fShader, program.fSource);
+ gl.compileShader(fShader);
+
+ programHandle = gl.createProgram();
+ gl.attachShader(programHandle, vShader);
+ gl.attachShader(programHandle, fShader);
+
+ program.vShader = vShader;
+ program.fShader = fShader;
+ program.program = programHandle;
+ program.status = "Compiling";
+ }
+
+ function checkCompletion() {
+ var ext = testRun.ext;
+
+ var allProgramsLinked = true;
+
+ for (var i = 0; i < programs.length; i++) {
+ var program = programs[i];
+ switch (program.status) {
+ case "Compiling":
+ if (gl.getShaderParameter(program.vShader, ext.COMPLETION_STATUS_KHR) &&
+ gl.getShaderParameter(program.fShader, ext.COMPLETION_STATUS_KHR))
+ {
+ checkShader(gl, program.vShader, infoElement);
+ checkShader(gl, program.fShader, infoElement);
+ gl.linkProgram(program.program);
+ program.status = "Linking";
+ }
+ allProgramsLinked = false;
+ break;
+
+ case "Linking":
+ if (gl.getProgramParameter(program.program, ext.COMPLETION_STATUS_KHR))
+ {
+ checkProgram(gl, program.program, infoElement);
+ program.status = "Done";
+ }
+ else {
+ allProgramsLinked = false;
+ }
+ break;
+
+ case "Done":
+ break;
+ }
+ }
+
+ if (allProgramsLinked) {
+ testRun.elapsedTotal = performance.now() - testRun.start;
+ showStatistics(testRun);
+ }
+ else {
+ requestAnimationFrame(checkCompletion);
+ }
+ }
+ requestAnimationFrame(checkCompletion);
+ }
+
+ function parsePrograms(testRun) {
+ var gl = testRun.gl;
+ var infoElement = testRun.logElement;
+
+ // Parse programs from the cached text, formatted as:
+ // __BEGINPROGRAM__
+ // __VERTEXSHADER__
+ // shader source line
+ // ...
+ // __FRAGMENTSHADER__
+ // shader source line
+ // ...
+ // __ENDPROGRAM__
+ //
+ // __BEGINPROGRAM__
+ // ...
+ var arrayOfLines = testRun.test.shaderCache.match(/[^\r\n]+/g);
+ var programs = [];
+ var currentProgram = {};
+ var currentShader;
+ var shaderSourceLine = false;
+ for (var ii = 0; ii < arrayOfLines.length; ii++) {
+ var cur = arrayOfLines[ii];
+ // Use random numbers to fool the program cache mechanism.
+ if (cur.indexOf('PROGRAM_CACHE_BREAKER_RANDOM') != -1) {
+ cur = cur.replace('PROGRAM_CACHE_BREAKER_RANDOM', Math.random())
+ }
+
+ if (cur == '__VERTEXSHADER__') {
+ currentShader = [];
+ shaderSourceLine = true;
+ } else if (cur == '__FRAGMENTSHADER__') {
+ currentProgram.vSource = currentShader.join('\n');
+
+ currentShader = [];
+ shaderSourceLine = true;
+ } else if (cur == '__ENDPROGRAM__') {
+ currentProgram.fSource = currentShader.join('\n');
+ programs.push(currentProgram);
+
+ currentProgram = {};
+ currentShader = [];
+ shaderSourceLine = false;
+ } else if (shaderSourceLine) {
+ currentShader.push(cur);
+ }
+ }
+
+ infoElement.textContent += programs.length + ' programs found.' + '\n';
+ infoElement.textContent += 'starting compilations ...' + '\n';
+
+ testRun.start = performance.now();
+
+ testRun.programs = programs;
+
+ testRun.makeAllPrograms(testRun);
+ };
+
+
+ function runTest(index, isParallel) {
+ var testRun = {};
+ var test = testGroup[index];
+ testRun.test = test;
+ testRun.name = test.name + (isParallel ? "_parallel" : "_serial");
+ testRun.logElement = document.getElementById(testRun.name);
+ testRun.logElement.textContent = '';
+
+ testRun.setupGLContext =
+ (isParallel ? setupGLContextParallel : setupGLContextSerial);
+
+ testRun.makeAllPrograms =
+ (isParallel ? makeAllProgramsParallel : makeAllProgramsSerial);
+
+ if (!testRun.setupGLContext(testRun)) {
+ return;
+ }
+
+ if (test.shaderCache === undefined) {
+ // load shader cache
+ var xhr = new XMLHttpRequest();
+ xhr.addEventListener('load', function() {
+ test.shaderCache = xhr.responseText;
+
+ requestAnimationFrame(function() {
+ parsePrograms(testRun);
+ });
+ });
+ xhr.open('GET', test.location);
+ xhr.send();
+ } else {
+ parsePrograms(testRun);
+ }
+ }
+
+ function createElement(element, attribute, inner) {
+ if (element === undefined) {
+ return false;
+ }
+ if (inner === undefined) {
+ inner = [];
+ }
+ var el = document.createElement(element);
+ if (typeof(attribute) === 'object') {
+ for (var key in attribute) {
+ el.setAttribute(key, attribute[key]);
+ }
+ }
+ if (!Array.isArray(inner)) {
+ inner = [inner];
+ }
+ for (var k = 0; k < inner.length; k++) {
+ if (inner[k].tagName) {
+ el.appendChild(inner[k]);
+ } else {
+ el.appendChild(document.createTextNode(inner[k]));
+ }
+ }
+ return el;
+ }
+
+ var container = createElement("div", {"class": "container"});
+ document.body.appendChild(container);
+
+ testGroup = [{
+ 'location': './shaders/aquarium/shader-cache.txt',
+ 'name': 'aquarium'
+ },
+ ];
+
+ testGroup.forEach((test, index) => {
+
+ function createTestView(test, index, isParallel) {
+
+ testName = test.name + (isParallel ? "_parallel" : "_serial");
+
+ var tButton = createElement(
+ 'button',
+ {'class': 'button', 'onclick': 'runTest(' + index + ', ' + isParallel + ')'},
+ testName
+ );
+
+ var tPrex = createElement("pre");
+ var tPre = createElement("textarea", { "id": testName, "rows": 10, "cols": 30});
+ var tDivContainer = createElement(
+ "div",
+ {"id": " " + testName + "_container"},
+ [tButton, tPrex, tPre]
+ );
+ container.appendChild(tDivContainer);
+ }
+
+ createTestView(test, index, false);
+ createTestView(test, index, true);
+ });
+
+ </script>
+</body>