| <!-- |
| 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> |
| <head> |
| <meta charset="utf-8"> |
| <link rel="stylesheet" href="../../resources/js-test-style.css"/> |
| <script src="../../js/js-test-pre.js"></script> |
| <script src="../../js/webgl-test-utils.js"></script> |
| <title>WebGL Matrix Attribute Conformance Test</title> |
| </head> |
| <body> |
| <div id="description"></div> |
| <div id="console"></div> |
| <canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas> |
| <script> |
| "use strict"; |
| description("This tests ensures that matrix attribute locations do not clash with other shader attributes."); |
| |
| var wtu = WebGLTestUtils; |
| var canvas = document.getElementById("canvas"); |
| var gl = wtu.create3DContext(canvas, {antialias: false}); |
| |
| // Make sure we have room for at least a mat4. |
| var maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); |
| debug('MAX_VERTEX_ATTRIBUTES is ' + maxAttributes); |
| shouldBeGreaterThanOrEqual('maxAttributes', '4'); |
| |
| var glFragmentShader = wtu.loadShader(gl, wtu.simpleColorFragmentShader, gl.FRAGMENT_SHADER); |
| |
| // prepareMatrixProgram creates a program with glFragmentShader as the fragment shader. |
| // The vertex shader has numVector number of vectors and a matrix with numMatrixDimensions |
| // dimensions at location numMatrixPosition in the list of attributes. |
| // Ensures that every vector and matrix is used by the program. |
| // Returns a valid program on successfull link; null on link failure. |
| function prepareMatrixProgram(numVectors, numMatrixDimensions, numMatrixPosition) { |
| // Add the matrix and vector attribute declarations. Declare the vectors |
| // to have the same number of components as the matrix so we can perform |
| // operations on them when we assign to gl_Position later on. |
| var strVertexShader = ""; |
| for (var ii = 1; ii <= numVectors; ++ii) { |
| if (numMatrixPosition === ii) { |
| strVertexShader += "attribute mat" + numMatrixDimensions + " matrix;\n"; |
| } |
| strVertexShader += "attribute vec" + numMatrixDimensions + " vec_" + ii + ";\n"; |
| } |
| // numMatrixPosition will be one past numVectors if the caller wants it to be |
| // last. Hence, we need this check outside the loop as well as inside. |
| if (numMatrixPosition === ii) { |
| strVertexShader += "attribute mat" + numMatrixDimensions + " matrix;\n"; |
| } |
| // Add the body of the shader. Add up all of the vectors and multiply by the matrix. |
| // The operations we perform do not matter. We just need to ensure that all the vector and |
| // matrix attributes are used. |
| strVertexShader += "void main(void) { \ngl_Position = vec4(("; |
| for (var ii = 1; ii <= numVectors; ++ii) { |
| if (ii > 1) { |
| strVertexShader += "+" |
| } |
| strVertexShader += "vec_" + ii; |
| } |
| strVertexShader += ")*matrix"; |
| // Ensure the vec4 has the correct number of dimensions in order to be assignable |
| // to gl_Position. |
| for (var ii = numMatrixDimensions; ii < 4; ++ii) { |
| strVertexShader += ",0.0"; |
| } |
| strVertexShader += ");}\n"; |
| // Load the shader, attach it to a program, and return the link results |
| var glVertexShader = wtu.loadShader(gl, strVertexShader, gl.VERTEX_SHADER); |
| var strTest = 'Load shader with ' + numVectors + ' vectors and 1 matrix'; |
| if (glVertexShader !== null) { |
| testPassed(strTest); |
| |
| var glProgram = gl.createProgram(); |
| gl.attachShader(glProgram, glVertexShader); |
| gl.attachShader(glProgram, glFragmentShader); |
| gl.linkProgram(glProgram); |
| if (gl.getProgramParameter(glProgram, gl.LINK_STATUS)) { |
| wtu.glErrorShouldBe(gl, gl.NO_ERROR, 'linkProgram'); |
| return glProgram; |
| } |
| } else { |
| testFailed(strTest); |
| } |
| return null; |
| } |
| |
| debug(''); |
| |
| // Test mat2, mat3 and mat4. |
| for (var mm = 2; mm <= 4; ++mm) { |
| // Add maxAttribute number of attributes by saving enough room in the attribute |
| // list for a matrix of mm dimensions. All of the other attribute slots will be |
| // filled with vectors. |
| var numVectors = maxAttributes - mm; |
| for (var pp = 1; pp <= numVectors + 1; ++pp) { |
| debug('Test ' + mm + ' dimensional matrix at position ' + pp); |
| var glProgram = prepareMatrixProgram(numVectors, /*numMatrixDimensions*/mm, /*numMatrixPosition*/pp); |
| shouldBeNonNull('glProgram'); |
| var attribMatrix = gl.getAttribLocation(glProgram, 'matrix'); |
| debug('Matrix is at attribute location ' + attribMatrix); |
| shouldBeTrue('attribMatrix > -1'); |
| // Per the spec, when an attribute is a matrix attribute, getAttribLocation |
| // returns the index of the first component of the matrix. The implementation must |
| // leave sufficient room for all the components. Here we ensure none of the vectors |
| // in the shader are assigned attribute locations that belong to the matrix. |
| for (var vv = 1; vv <= numVectors; ++vv) { |
| var strVector = 'vec_' + vv |
| var attribVector = gl.getAttribLocation(glProgram, strVector); |
| debug(strVector + ' is at attribute location ' + attribVector); |
| // Begin with the first attribute location where the matrix begins and ensure |
| // the vector's attribute location is not assigned to the matrix. Loop until |
| // we've checked all of the attribute locations that belong to the matrix. |
| for (var ii = attribMatrix; ii < attribMatrix + mm; ++ii) { |
| var testStr = strVector + ' attribute location: ' + attribVector + '. Should not be ' + ii; |
| if (attribVector !== ii) { |
| testPassed(testStr); |
| } else { |
| testFailed(testStr); |
| } |
| } |
| } |
| debug(''); |
| } |
| debug(''); |
| } |
| |
| var successfullyParsed = true; |
| </script> |
| <script src="../../js/js-test-post.js"></script> |
| </body> |
| </html> |