tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

glsl-conformance-test.js (12929B)


      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 */
      6 GLSLConformanceTester = (function(){
      7 
      8 var wtu = WebGLTestUtils;
      9 var defaultVertexShader = [
     10  "attribute vec4 vPosition;",
     11  "void main()",
     12  "{",
     13  "    gl_Position = vPosition;",
     14  "}"
     15 ].join('\n');
     16 
     17 var defaultFragmentShader = [
     18  "precision mediump float;",
     19  "void main()",
     20  "{",
     21  "    gl_FragColor = vec4(1.0,0.0,0.0,1.0);",
     22  "}"
     23 ].join('\n');
     24 
     25 var defaultESSL3VertexShader = [
     26  "#version 300 es",
     27  "in vec4 vPosition;",
     28  "void main()",
     29  "{",
     30  "    gl_Position = vPosition;",
     31  "}"
     32 ].join('\n');
     33 
     34 var defaultESSL3FragmentShader = [
     35  "#version 300 es",
     36  "precision mediump float;",
     37  "out vec4 my_FragColor;",
     38  "void main()",
     39  "{",
     40  "    my_FragColor = vec4(1.0,0.0,0.0,1.0);",
     41  "}"
     42 ].join('\n');
     43 
     44 function log(msg) {
     45  bufferedLogToConsole(msg);
     46 }
     47 
     48 var vShaderDB = {};
     49 var fShaderDB = {};
     50 
     51 /**
     52 * The info parameter should contain the following keys. Note that you may leave
     53 * the parameters for one shader out, in which case the default shader will be
     54 * used.
     55 * vShaderSource: the source code for vertex shader
     56 * vShaderId: id of an element containing vertex shader source code. Used if
     57 *   vShaderSource is not specified.
     58 * vShaderSuccess: true if vertex shader compilation should
     59 *   succeed.
     60 * fShaderSource: the source code for fragment shader
     61 * fShaderId: id of an element containing fragment shader source code. Used if
     62 *   fShaderSource is not specified.
     63 * fShaderSuccess: true if fragment shader compilation should
     64 *   succeed.
     65 * linkSuccess: true if link should succeed
     66 * passMsg: msg to describe success condition.
     67 * render: if true render to unit quad. Green = success
     68 * uniforms: an array of objects specifying uniforms to set prior to rendering.
     69 *   Each object should have the following keys:
     70 *     name: uniform variable name in the shader source. Uniform location will
     71 *       be queried based on its name.
     72 *     functionName: name of the function used to set the uniform. For example:
     73 *       'uniform1i'
     74 *     value: value of the uniform to set.
     75 */
     76 function runOneTest(gl, info) {
     77  var passMsg = info.passMsg
     78  debug("");
     79  debug("test: " + passMsg);
     80 
     81  var consoleDiv = document.getElementById("console");
     82 
     83  var vIsDefault = false;
     84  var fIsDefault = false;
     85 
     86  if (info.vShaderSource === undefined) {
     87    if (info.vShaderId) {
     88      info.vShaderSource = document.getElementById(info.vShaderId).text;
     89    } else {
     90      vIsDefault = true;
     91    }
     92  }
     93  if (info.fShaderSource === undefined) {
     94    if (info.fShaderId) {
     95      info.fShaderSource = document.getElementById(info.fShaderId).text;
     96    } else {
     97      fIsDefault = true;
     98    }
     99  }
    100 
    101  var vLabel = (vIsDefault ? "default" : "test") + " vertex shader";
    102  var fLabel = (fIsDefault ? "default" : "test") + " fragment shader";
    103  if (vIsDefault) {
    104    info.vShaderSource = defaultVertexShader;
    105    info.vShaderSuccess = true;
    106  }
    107  if (fIsDefault) {
    108    info.fShaderSource = defaultFragmentShader;
    109    info.fShaderSuccess = true;
    110  }
    111 
    112  if (vIsDefault != fIsDefault) {
    113    // The language version of the default shader is chosen
    114    // according to the language version of the other shader.
    115    // We rely on "#version 300 es" being in this usual format.
    116    // It must be on the first line of the shader according to the spec.
    117    if (fIsDefault) {
    118      // If we're using the default fragment shader, we need to make sure that
    119      // it's language version matches with the vertex shader.
    120      if (info.vShaderSource.split('\n')[0] == '#version 300 es') {
    121        info.fShaderSource = defaultESSL3FragmentShader;
    122      }
    123    } else {
    124      // If we're using the default vertex shader, we need to make sure that
    125      // it's language version matches with the fragment shader.
    126      if (info.fShaderSource.split('\n')[0] == '#version 300 es') {
    127        info.vShaderSource = defaultESSL3VertexShader;
    128      }
    129    }
    130  }
    131 
    132  var vSource = info.vShaderPrep ? info.vShaderPrep(info.vShaderSource) :
    133    info.vShaderSource;
    134 
    135  if (!quietMode()) {
    136    wtu.addShaderSource(consoleDiv, vLabel, vSource);
    137  }
    138 
    139  // Reuse identical shaders so we test shared shader.
    140  var vShader = vShaderDB[vSource];
    141  if (!vShader) {
    142    // loadShader, with opt_skipCompileStatus: true.
    143    vShader = wtu.loadShader(gl, vSource, gl.VERTEX_SHADER, null, null, null, null, true);
    144    let compiledVShader = vShader;
    145    if (vShader && !gl.getShaderParameter(vShader, gl.COMPILE_STATUS)) {
    146      compiledVShader = null;
    147    }
    148    if (info.vShaderTest) {
    149      if (!info.vShaderTest(compiledVShader)) {
    150        testFailed("[vertex shader test] " + passMsg);
    151        return;
    152      }
    153    }
    154    // As per GLSL 1.0.17 10.27 we can only check for success on
    155    // compileShader, not failure.
    156    if (!info.ignoreResults && info.vShaderSuccess && !compiledVShader) {
    157      testFailed("[unexpected vertex shader compile status] (expected: " +
    158                 info.vShaderSuccess + ") " + passMsg);
    159      if (!quietMode() && vShader) {
    160        const info = gl.getShaderInfoLog(vShader);
    161        wtu.addShaderSource(consoleDiv, vLabel + " info log", info);
    162      }
    163    }
    164    // Save the shaders so we test shared shader.
    165    if (compiledVShader) {
    166      vShaderDB[vSource] = compiledVShader;
    167    } else {
    168      vShader = null;
    169    }
    170  }
    171 
    172  var debugShaders = gl.getExtension('WEBGL_debug_shaders');
    173  if (debugShaders && vShader && !quietMode()) {
    174    wtu.addShaderSource(consoleDiv, vLabel + " translated for driver",
    175                        debugShaders.getTranslatedShaderSource(vShader));
    176  }
    177 
    178  var fSource = info.fShaderPrep ? info.fShaderPrep(info.fShaderSource) :
    179    info.fShaderSource;
    180 
    181  if (!quietMode()) {
    182    wtu.addShaderSource(consoleDiv, fLabel, fSource);
    183  }
    184 
    185  // Reuse identical shaders so we test shared shader.
    186  var fShader = fShaderDB[fSource];
    187  if (!fShader) {
    188    // loadShader, with opt_skipCompileStatus: true.
    189    fShader = wtu.loadShader(gl, fSource, gl.FRAGMENT_SHADER, null, null, null, null, true);
    190    let compiledFShader = fShader;
    191    if (fShader && !gl.getShaderParameter(fShader, gl.COMPILE_STATUS)) {
    192      compiledFShader = null;
    193    }
    194    if (info.fShaderTest) {
    195      if (!info.fShaderTest(compiledFShader)) {
    196        testFailed("[fragment shader test] " + passMsg);
    197        return;
    198      }
    199    }
    200    //debug(fShader == null ? "fail" : "succeed");
    201    // As per GLSL 1.0.17 10.27 we can only check for success on
    202    // compileShader, not failure.
    203    if (!info.ignoreResults && info.fShaderSuccess && !compiledFShader) {
    204      testFailed("[unexpected fragment shader compile status] (expected: " +
    205                info.fShaderSuccess + ") " + passMsg);
    206      if (!quietMode() && fShader) {
    207        const info = gl.getShaderInfoLog(fShader);
    208        wtu.addShaderSource(consoleDiv, fLabel + " info log", info);
    209      }
    210      return;
    211    }
    212 
    213    // Safe the shaders so we test shared shader.
    214    if (compiledFShader) {
    215      fShaderDB[fSource] = compiledFShader;
    216    } else {
    217      fShader = null;
    218    }
    219  }
    220 
    221  if (debugShaders && fShader && !quietMode()) {
    222    wtu.addShaderSource(consoleDiv, fLabel + " translated for driver",
    223                        debugShaders.getTranslatedShaderSource(fShader));
    224  }
    225 
    226  if (vShader && fShader) {
    227    var program = gl.createProgram();
    228    gl.attachShader(program, vShader);
    229    gl.attachShader(program, fShader);
    230 
    231    if (vSource.indexOf("vPosition") >= 0) {
    232      gl.bindAttribLocation(program, 0, "vPosition");
    233    }
    234    if (vSource.indexOf("texCoord0") >= 0) {
    235      gl.bindAttribLocation(program, 1, "texCoord0");
    236    }
    237    gl.linkProgram(program);
    238    var linked = (gl.getProgramParameter(program, gl.LINK_STATUS) != 0);
    239    if (!linked) {
    240      var error = gl.getProgramInfoLog(program);
    241      log("*** Error linking program '"+program+"':"+error);
    242    }
    243    if (!info.ignoreResults && linked != info.linkSuccess) {
    244      testFailed("[unexpected link status] (expected: " +
    245                info.linkSuccess + ") " + passMsg);
    246      return;
    247    }
    248  } else {
    249    if (!info.ignoreResults && info.linkSuccess) {
    250      testFailed("[link failed] " + passMsg);
    251      return;
    252    }
    253  }
    254 
    255  if (parseInt(wtu.getUrlOptions().dumpShaders)) {
    256    var vInfo = {
    257      shader: vShader,
    258      shaderSuccess: info.vShaderSuccess,
    259      label: vLabel,
    260      source: vSource
    261    };
    262    var fInfo = {
    263      shader: fShader,
    264      shaderSuccess: info.fShaderSuccess,
    265      label: fLabel,
    266      source: fSource
    267    };
    268    wtu.dumpShadersInfo(gl, window.location.pathname, passMsg, vInfo, fInfo);
    269  }
    270 
    271  if (!info.render) {
    272    testPassed(passMsg);
    273    return;
    274  }
    275 
    276  gl.useProgram(program);
    277 
    278  if (info.uniforms !== undefined) {
    279    for (var i = 0; i < info.uniforms.length; ++i) {
    280      var uniform = info.uniforms[i];
    281      var uniformLocation = gl.getUniformLocation(program, uniform.name);
    282      if (uniformLocation !== null) {
    283        if (uniform.functionName.includes("Matrix")) {
    284          gl[uniform.functionName](uniformLocation, false, uniform.value);
    285        } else {
    286          gl[uniform.functionName](uniformLocation, uniform.value);
    287        }
    288        debug(uniform.name + ' set to ' + uniform.value);
    289      } else {
    290        debug('uniform ' + uniform.name + ' had null location and was not set');
    291      }
    292    }
    293  }
    294 
    295  if (info.uniformBlocks !== undefined) {
    296    for (var i = 0; i < info.uniformBlocks.length; ++i) {
    297      var uniformBlockIndex = gl.getUniformBlockIndex(program, info.uniformBlocks[i].name);
    298      if (uniformBlockIndex !== null) {
    299        gl.uniformBlockBinding(program, uniformBlockIndex, i);
    300        debug(info.uniformBlocks[i].name + ' (index ' + uniformBlockIndex + ') bound to slot ' + i);
    301 
    302        var uboValueBuffer = gl.createBuffer();
    303        gl.bindBufferBase(gl.UNIFORM_BUFFER, i, uboValueBuffer);
    304        gl.bufferData(gl.UNIFORM_BUFFER, info.uniformBlocks[i].value, info.uniformBlocks[i].usage || gl.STATIC_DRAW);
    305      } else {
    306        debug('uniform block' + info.uniformBlocks[i].name + ' had null block index and was not set');
    307      }
    308    }
    309  }
    310 
    311  wtu.setupUnitQuad(gl);
    312  wtu.clearAndDrawUnitQuad(gl);
    313 
    314  var div = document.createElement("div");
    315  div.className = "testimages";
    316  wtu.insertImage(div, "result", wtu.makeImageFromCanvas(gl.canvas));
    317  div.appendChild(document.createElement('br'));
    318  consoleDiv.appendChild(div);
    319 
    320  var tolerance = 0;
    321  if (info.renderTolerance !== undefined) {
    322    tolerance = info.renderTolerance;
    323  }
    324  if (info.renderColor !== undefined) {
    325    wtu.checkCanvas(gl, info.renderColor, "should be expected color " + info.renderColor, tolerance);
    326  } else {
    327    wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green", tolerance);
    328  }
    329 }
    330 
    331 function runTests(shaderInfos, opt_contextVersion) {
    332  var wtu = WebGLTestUtils;
    333  var canvas = document.createElement('canvas');
    334  canvas.width = 32;
    335  canvas.height = 32;
    336  var gl = wtu.create3DContext(canvas, undefined, opt_contextVersion);
    337  if (!gl) {
    338    testFailed("context does not exist");
    339    finishTest();
    340    return;
    341  }
    342 
    343  for (var i = 0; i < shaderInfos.length; i++) {
    344    runOneTest(gl, shaderInfos[i]);
    345  }
    346 
    347  finishTest();
    348 };
    349 
    350 function getSource(elem) {
    351  var str = elem.text;
    352  return str.replace(/^\s*/, '').replace(/\s*$/, '');
    353 }
    354 
    355 function getPassMessage(source) {
    356  var lines = source.split('\n');
    357  return lines[0].substring(3);
    358 }
    359 
    360 function getSuccess(msg) {
    361  if (msg.indexOf("fail") >= 0) {
    362    return false;
    363  }
    364  if (msg.indexOf("succeed") >= 0) {
    365    return true;
    366  }
    367  testFailed("bad test description. Must have 'fail' or 'succeed'");
    368 }
    369 
    370 function setupTest() {
    371  var info = {};
    372 
    373  var vShaderElem = document.getElementById('vertexShader');
    374  if (vShaderElem) {
    375    info.vShaderSource = getSource(vShaderElem);
    376    info.passMsg = getPassMessage(info.vShaderSource);
    377    info.vShaderSuccess = getSuccess(info.passMsg);
    378  }
    379 
    380  var fShaderElem = document.getElementById('fragmentShader');
    381  if (fShaderElem) {
    382    info.fShaderSource = getSource(fShaderElem);
    383    info.passMsg = getPassMessage(info.fShaderSource);
    384    info.fShaderSuccess = getSuccess(info.passMsg);
    385  }
    386 
    387  // linkSuccess should be true if shader success value is undefined or true for both shaders.
    388  info.linkSuccess = info.vShaderSuccess !== false && info.fShaderSuccess !== false;
    389 
    390  if (info.passMsg === undefined) {
    391    testFailed("no test shader found.");
    392    finishTest();
    393    return;
    394  }
    395 
    396  return info;
    397 }
    398 
    399 function runTest() {
    400  var info = setupTest();
    401  description(info.passMsg);
    402  runTests([info]);
    403 }
    404 
    405 function runRenderTests(tests, opt_contextVersion) {
    406  for (var ii = 0; ii < tests.length; ++ii) {
    407    tests[ii].render = true
    408  }
    409  runTests(tests, opt_contextVersion);
    410 }
    411 
    412 function runRenderTest() {
    413  var info = setupTest();
    414  description(info.passMsg);
    415  runRenderTests([info]);
    416 }
    417 
    418 return {
    419  runTest: runTest,
    420  runTests: runTests,
    421  runRenderTest: runRenderTest,
    422  runRenderTests: runRenderTests
    423 };
    424 }());