michael@0: GLSLConformanceTester = (function(){ michael@0: michael@0: var wtu = WebGLTestUtils; michael@0: var defaultVertexShader = [ michael@0: "attribute vec4 vPosition;", michael@0: "void main()", michael@0: "{", michael@0: " gl_Position = vPosition;", michael@0: "}" michael@0: ].join('\n'); michael@0: michael@0: var defaultFragmentShader = [ michael@0: "precision mediump float;", michael@0: "void main()", michael@0: "{", michael@0: " gl_FragColor = vec4(1.0,0.0,0.0,1.0);", michael@0: "}" michael@0: ].join('\n'); michael@0: michael@0: function log(msg) { michael@0: if (window.console && window.console.log) { michael@0: window.console.log(msg); michael@0: } michael@0: } michael@0: michael@0: var vShaderDB = {}; michael@0: var fShaderDB = {}; michael@0: michael@0: /** michael@0: * vShaderSource: the source code for vertex shader michael@0: * vShaderSuccess: true if vertex shader compiliation should michael@0: * succeed. michael@0: * fShaderSource: the source code for fragment shader michael@0: * fShaderSuccess: true if fragment shader compiliation should michael@0: * succeed. michael@0: * linkSuccess: true of link should succeed michael@0: * passMsg: msg to describe success condition. michael@0: * render: if true render to unit quad. Green = success michael@0: * michael@0: */ michael@0: function runOneTest(gl, info) { michael@0: var passMsg = info.passMsg michael@0: debug("test: " + passMsg); michael@0: michael@0: var console = document.getElementById("console"); michael@0: michael@0: if (info.vShaderSource === undefined) { michael@0: if (info.vShaderId) { michael@0: info.vShaderSource = document.getElementById(info.vShaderId).text; michael@0: } else { michael@0: info.vShader = 'defaultVertexShader'; michael@0: info.vShaderSource = defaultVertexShader; michael@0: } michael@0: } michael@0: if (info.fShaderSource === undefined) { michael@0: if (info.fShaderId) { michael@0: info.fShaderSource = document.getElementById(info.fShaderId).text; michael@0: } else { michael@0: info.fShader = 'defaultFragmentShader'; michael@0: info.fShaderSource = defaultFragmentShader; michael@0: } michael@0: } michael@0: michael@0: var vLabel = (info.vShaderSource == defaultVertexShader ? "default" : "test") + " vertex shader"; michael@0: var fLabel = (info.fShaderSource == defaultFragmentShader ? "default" : "test") + " fragment shader"; michael@0: michael@0: var vSource = info.vShaderPrep ? info.vShaderPrep(info.vShaderSource) : michael@0: info.vShaderSource; michael@0: michael@0: wtu.addShaderSource(console, vLabel, vSource); michael@0: michael@0: // Reuse identical shaders so we test shared shader. michael@0: var vShader = vShaderDB[vSource]; michael@0: if (!vShader) { michael@0: vShader = wtu.loadShader(gl, vSource, gl.VERTEX_SHADER); michael@0: if (info.vShaderTest) { michael@0: if (!info.vShaderTest(vShader)) { michael@0: testFailed("[vertex shader test] " + passMsg); michael@0: return; michael@0: } michael@0: } michael@0: // As per GLSL 1.0.17 10.27 we can only check for success on michael@0: // compileShader, not failure. michael@0: if (info.vShaderSuccess && !vShader) { michael@0: testFailed("[unexpected vertex shader compile status] (expected: " + michael@0: info.vShaderSuccess + ") " + passMsg); michael@0: } michael@0: // Save the shaders so we test shared shader. michael@0: if (vShader) { michael@0: vShaderDB[vSource] = vShader; michael@0: } michael@0: } michael@0: michael@0: var fSource = info.fShaderPrep ? info.fShaderPrep(info.fShaderSource) : michael@0: info.fShaderSource; michael@0: michael@0: wtu.addShaderSource(console, fLabel, fSource); michael@0: michael@0: // Reuse identical shaders so we test shared shader. michael@0: var fShader = fShaderDB[fSource]; michael@0: if (!fShader) { michael@0: fShader = wtu.loadShader(gl, fSource, gl.FRAGMENT_SHADER); michael@0: if (info.fShaderTest) { michael@0: if (!info.fShaderTest(fShader)) { michael@0: testFailed("[fragment shdaer test] " + passMsg); michael@0: return; michael@0: } michael@0: } michael@0: //debug(fShader == null ? "fail" : "succeed"); michael@0: // As per GLSL 1.0.17 10.27 we can only check for success on michael@0: // compileShader, not failure. michael@0: if (info.fShaderSuccess && !fShader) { michael@0: testFailed("[unexpected fragment shader compile status] (expected: " + michael@0: info.fShaderSuccess + ") " + passMsg); michael@0: return; michael@0: } michael@0: // Safe the shaders so we test shared shader. michael@0: if (fShader) { michael@0: fShaderDB[fSource] = fShader; michael@0: } michael@0: } michael@0: michael@0: if (vShader && fShader) { michael@0: var program = gl.createProgram(); michael@0: gl.attachShader(program, vShader); michael@0: gl.attachShader(program, fShader); michael@0: gl.bindAttribLocation(program, 0, "vPosition"); michael@0: gl.bindAttribLocation(program, 1, "texCoord0"); michael@0: gl.linkProgram(program); michael@0: var linked = (gl.getProgramParameter(program, gl.LINK_STATUS) != 0); michael@0: if (!linked) { michael@0: var error = gl.getProgramInfoLog(program); michael@0: log("*** Error linking program '"+program+"':"+error); michael@0: } michael@0: if (linked != info.linkSuccess) { michael@0: testFailed("[unexpected link status] " + passMsg); michael@0: return; michael@0: } michael@0: } else { michael@0: if (info.linkSuccess) { michael@0: testFailed("[link failed] " + passMsg); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: if (!info.render) { michael@0: testPassed(passMsg); michael@0: return; michael@0: } michael@0: michael@0: gl.useProgram(program); michael@0: wtu.setupUnitQuad(gl); michael@0: wtu.drawQuad(gl); michael@0: michael@0: var div = document.createElement("div"); michael@0: div.className = "testimages"; michael@0: wtu.insertImage(div, "result", wtu.makeImage(gl.canvas)); michael@0: div.appendChild(document.createElement('br')); michael@0: console.appendChild(div); michael@0: wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green", 0); michael@0: } michael@0: michael@0: function runTests(shaderInfos) { michael@0: var wtu = WebGLTestUtils; michael@0: var canvas = document.createElement('canvas'); michael@0: canvas.width = 32; michael@0: canvas.height = 32; michael@0: var gl = wtu.create3DContext(canvas); michael@0: if (!gl) { michael@0: testFailed("context does not exist"); michael@0: finishTest(); michael@0: return; michael@0: } michael@0: michael@0: for (var ii = 0; ii < shaderInfos.length; ++ii) { michael@0: runOneTest(gl, shaderInfos[ii]); michael@0: } michael@0: michael@0: finishTest(); michael@0: }; michael@0: michael@0: function loadExternalShaders(filename, passMsg) { michael@0: var shaderInfos = []; michael@0: var lines = wtu.readFileList(filename); michael@0: for (var ii = 0; ii < lines.length; ++ii) { michael@0: var info = { michael@0: vShaderSource: defaultVertexShader, michael@0: vShaderSuccess: true, michael@0: fShaderSource: defaultFragmentShader, michael@0: fShaderSuccess: true, michael@0: linkSuccess: true, michael@0: }; michael@0: michael@0: var line = lines[ii]; michael@0: var files = line.split(/ +/); michael@0: var passMsg = ""; michael@0: for (var jj = 0; jj < files.length; ++jj) { michael@0: var file = files[jj]; michael@0: var shaderSource = wtu.readFile(file); michael@0: var firstLine = shaderSource.split("\n")[0]; michael@0: var success = undefined; michael@0: if (firstLine.indexOf("fail") >= 0) { michael@0: success = false; michael@0: } else if (firstLine.indexOf("succeed") >= 0) { michael@0: success = true; michael@0: } michael@0: if (success === undefined) { michael@0: testFailed("bad first line in " + file + ":" + firstLine); michael@0: continue; michael@0: } michael@0: if (!wtu.startsWith(firstLine, "// ")) { michael@0: testFailed("bad first line in " + file + ":" + firstLine); michael@0: continue; michael@0: } michael@0: passMsg = passMsg + (passMsg.length ? ", " : "") + firstLine.substr(3); michael@0: if (wtu.endsWith(file, ".vert")) { michael@0: info.vShaderSource = shaderSource; michael@0: info.vShaderSuccess = success; michael@0: } else if (wtu.endsWith(file, ".frag")) { michael@0: info.fShaderSource = shaderSource; michael@0: info.fShaderSuccess = success; michael@0: } michael@0: } michael@0: info.linkSuccess = info.vShaderSuccess && info.fShaderSuccess; michael@0: info.passMsg = passMsg; michael@0: shaderInfos.push(info); michael@0: } michael@0: return shaderInfos; michael@0: } michael@0: michael@0: function getSource(elem) { michael@0: var str = elem.text; michael@0: return str.replace(/^\s*/, '').replace(/\s*$/, ''); michael@0: } michael@0: michael@0: function getPassMessage(source) { michael@0: var lines = source.split('\n'); michael@0: return lines[0].substring(3); michael@0: } michael@0: michael@0: function getSuccess(msg) { michael@0: if (msg.indexOf("fail") >= 0) { michael@0: return false; michael@0: } michael@0: if (msg.indexOf("succeed") >= 0) { michael@0: return true; michael@0: } michael@0: testFailed("bad test description. Must have 'fail' or 'success'"); michael@0: } michael@0: michael@0: function setupTest() { michael@0: var vShaderElem = document.getElementById('vertexShader'); michael@0: var vShaderSource = defaultVertexShader; michael@0: var vShaderSuccess = true; michael@0: michael@0: var fShaderElem = document.getElementById('fragmentShader'); michael@0: var fShaderSource = defaultFragmentShader; michael@0: var fShaderSuccess = true; michael@0: michael@0: var passMsg = undefined; michael@0: michael@0: if (vShaderElem) { michael@0: vShaderSource = getSource(vShaderElem); michael@0: passMsg = getPassMessage(vShaderSource); michael@0: vShaderSuccess = getSuccess(passMsg); michael@0: } michael@0: michael@0: if (fShaderElem) { michael@0: fShaderSource = getSource(fShaderElem); michael@0: passMsg = getPassMessage(fShaderSource); michael@0: fShaderSuccess = getSuccess(passMsg); michael@0: } michael@0: michael@0: var linkSuccess = vShaderSuccess && fShaderSuccess; michael@0: michael@0: if (passMsg === undefined) { michael@0: testFailed("no test shader found."); michael@0: finishTest(); michael@0: return; michael@0: } michael@0: michael@0: var info = { michael@0: vShaderSource: vShaderSource, michael@0: vShaderSuccess: vShaderSuccess, michael@0: fShaderSource: fShaderSource, michael@0: fShaderSuccess: fShaderSuccess, michael@0: linkSuccess: linkSuccess, michael@0: passMsg: passMsg michael@0: }; michael@0: michael@0: return info; michael@0: } michael@0: michael@0: function runTest() { michael@0: var info = setupTest(); michael@0: description(info.passMsg); michael@0: runTests([info]); michael@0: } michael@0: michael@0: function runRenderTests(tests) { michael@0: for (var ii = 0; ii < tests.length; ++ii) { michael@0: tests[ii].render = true michael@0: } michael@0: runTests(tests); michael@0: } michael@0: michael@0: function runRenderTest() { michael@0: var info = setupTest(); michael@0: description(info.passMsg); michael@0: runRenderTests([info]); michael@0: } michael@0: michael@0: return { michael@0: runTest: runTest, michael@0: runTests: runTests, michael@0: runRenderTest: runRenderTest, michael@0: runRenderTests: runRenderTests, michael@0: loadExternalShaders: loadExternalShaders, michael@0: michael@0: none: false, michael@0: }; michael@0: }());