168 lines
5.0 KiB
HTML
168 lines
5.0 KiB
HTML
<!DOCTYPE html>
|
|
<head>
|
|
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
|
|
<title>WebGL Triangle</title>
|
|
<style>
|
|
canvas {
|
|
width: 2px;
|
|
height: 2px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<script id="vertexShaderSource" type="text/glsl">
|
|
attribute vec4 position;
|
|
void main() {
|
|
gl_Position = position;
|
|
}
|
|
</script>
|
|
<script id="fragmentShaderSource" type="text/glsl">
|
|
#ifdef GL_ES
|
|
precision mediump float;
|
|
#endif
|
|
|
|
void main() {
|
|
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
|
}
|
|
</script>
|
|
<script>
|
|
|
|
if (window.testRunner) {
|
|
window.testRunner.waitUntilDone();
|
|
window.testRunner.dumpAsText();
|
|
}
|
|
|
|
function logResult(message) {
|
|
var output = document.getElementById("results");
|
|
output.innerHTML += message + "<br>";
|
|
}
|
|
|
|
function drawTriangle(canvas) {
|
|
|
|
canvas.width = 2;
|
|
canvas.height = 2;
|
|
|
|
var gl = canvas.getContext("webgl", { antialias: true });
|
|
|
|
if (!gl) {
|
|
logResult("ERROR: Couldn't create WebGL context.");
|
|
return;
|
|
}
|
|
|
|
if (!gl.getContextAttributes().antialias) {
|
|
logResult("ERROR: Antialiasing was not enabled at creation time.");
|
|
return;
|
|
}
|
|
|
|
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
|
|
gl.shaderSource(vertexShader, document.getElementById("vertexShaderSource").textContent);
|
|
|
|
gl.compileShader(vertexShader);
|
|
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
|
|
logResult("ERROR: Vertex Shader failed to compile.");
|
|
logResult(gl.getShaderInfoLog(vertexShader));
|
|
return;
|
|
}
|
|
|
|
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
gl.shaderSource(fragmentShader, document.getElementById("fragmentShaderSource").textContent);
|
|
gl.compileShader(fragmentShader);
|
|
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
|
|
logResult("ERROR: Fragment Shader failed to compile.");
|
|
logResult(gl.getShaderInfoLog(fragmentShader));
|
|
return;
|
|
}
|
|
|
|
var program = gl.createProgram();
|
|
gl.attachShader(program, vertexShader);
|
|
gl.attachShader(program, fragmentShader);
|
|
gl.linkProgram(program);
|
|
|
|
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
logResult("ERROR: Unable to link shaders into program.");
|
|
return;
|
|
}
|
|
|
|
gl.useProgram(program);
|
|
var positionAttribute = gl.getAttribLocation(program, "position");
|
|
gl.enableVertexAttribArray(positionAttribute);
|
|
|
|
var vertices = new Float32Array([
|
|
-1.0, -1.0,
|
|
1.0, -1.0,
|
|
1.0, 1.0
|
|
]);
|
|
var triangleBuffer = gl.createBuffer();
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, triangleBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
|
|
|
gl.clearColor(0, 0, 0, 1);
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, triangleBuffer);
|
|
gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 0, 0);
|
|
|
|
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
}
|
|
|
|
function pixelAt(cssX, cssY, buffer) {
|
|
// Remember that "top" in CSS coordinates is the last row in WebGL. i.e. things are upside down.
|
|
var col = cssX;
|
|
var row = 1 - cssY;
|
|
return {
|
|
r: buffer[(row * 2 + col) * 4 + 0],
|
|
g: buffer[(row * 2 + col) * 4 + 1],
|
|
b: buffer[(row * 2 + col) * 4 + 2],
|
|
a: buffer[(row * 2 + col) * 4 + 3],
|
|
};
|
|
}
|
|
|
|
function pixelToString(pixel) {
|
|
return "{r: " + pixel.r + ", g: " + pixel.g + ", b: " + pixel.b + ", a: " + pixel.a + "}";
|
|
}
|
|
|
|
function testOutput(canvas) {
|
|
|
|
var gl = canvas.getContext("webgl");
|
|
|
|
if (!gl) {
|
|
logResult("FAIL: No WebGL context to examine.");
|
|
return;
|
|
}
|
|
|
|
var imageBuffer = new Uint8Array(canvas.width * canvas.height * 4);
|
|
gl.readPixels(0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, imageBuffer);
|
|
|
|
// Check that the top left pixel is fully black.
|
|
var topLeft = pixelAt(0, 0, imageBuffer);
|
|
if (topLeft.r != 0 || topLeft.g != 0 || topLeft.b != 0 || topLeft.a != 255) {
|
|
logResult("FAIL: top left corner was not fully black. " + pixelToString(topLeft));
|
|
return;
|
|
}
|
|
logResult("PASS: top left corner was fully black.");
|
|
|
|
// Check that the top right pixel isn't fully red. If it is, it implies we didn't multisample.
|
|
var topRight = pixelAt(1, 0, imageBuffer);
|
|
if (topRight.r == 255) {
|
|
logResult("FAIL: top right corner had a solid red channel. " + pixelToString(topRight));
|
|
return;
|
|
}
|
|
logResult("PASS: top right corner did not have a completely solid red channel.");
|
|
}
|
|
|
|
window.addEventListener("load", function () {
|
|
var canvas = document.querySelector("canvas");
|
|
drawTriangle(canvas);
|
|
testOutput(canvas);
|
|
if (window.testRunner)
|
|
window.testRunner.notifyDone();
|
|
}, false);
|
|
</script>
|
|
<body>
|
|
<p>To check anti-aliasing, we draw a triangle over half of a 2x2 quad, then check the pixel colors
|
|
in the corners. Note that if you're looking at the rendering results on a high-dpi display
|
|
you will see some artefacts as the canvas is scaled by the page zoom. Don't mistake that for
|
|
anti-aliasing (the test code doesn't).</p>
|
|
<canvas></canvas>
|
|
<p id="results"></p>
|
|
</body> |