Source code

Revision control

Copy as Markdown

Other Tools

<!--
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">
<title>WebGL Big FBO Test</title>
<link rel="stylesheet" href="../resources/js-test-style.css"/>
<script src="../../devtools/src/debug/webgl-debug.js"></script>
<script src="../js/js-test-pre.js"></script>
<script src="../js/webgl-test-utils.js"></script>
</head>
<body>
<canvas id="canvas" width="256" height="256"> </canvas>
<div id="description"></div>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec2 texCoord0;
varying vec2 texCoord;
void main()
{
gl_Position = vec4(vPosition.xyz, 1.0);
texCoord = texCoord0;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D tex;
varying vec2 texCoord;
void main()
{
gl_FragColor = texture2D(tex, texCoord);
}
</script>
<script>
"use strict";
window.onload = init;
var g_textures = [];
debug("Tests the performance of using lots of large FBOs");
function init() {
if (confirm(
"After clicking OK your machine may become unresponsive or crash.")) {
main();
} else {
debug("cancelled");
}
}
function checkFBOStatus(gl) {
var err = gl.getError();
if (err != gl.NO_ERROR) {
if (err != gl.OUT_OF_MEMORY)
testFailed("gl.getError returned " + err);
else
testPassed("OUT-OF-MEMORY");
return false;
}
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (status != gl.FRAMEBUFFER_COMPLETE) {
testFailed("gl.checkFramebufferStatus() returned " + WebGLTestUtils.glEnumToString(gl, status));
return false;
}
return true;
}
function setupFBO(gl, size) {
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
var fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
gl.texImage2D(gl.TEXTURE_2D,
0, // level
gl.RGBA, // internalFormat
size, // width
size, // height
0, // border
gl.RGBA, // format
gl.UNSIGNED_BYTE, // type
null); // data
if (!checkFBOStatus(gl))
return null;
return { fb: fb, tex: tex };
}
function checkPixels(gl) {
var width = 256;
var height = 256;
var thresh = 3;
var buf = new Uint8Array(width * height * 4);
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
for (var yy = 0; yy < height; ++yy) {
for (var xx = 0; xx < width; ++xx) {
var offset = (yy * width + xx) * 4;
if (Math.abs(buf[offset] - 255) > thresh ||
Math.abs(buf[offset + 1] - 0) > thresh ||
Math.abs(buf[offset + 2] - 0) > thresh) {
testFailed("drawing results incorrect");
return false;
}
}
}
return true;
}
function handleContextLost() {
debug("context lost");
}
function main() {
debug("");
debug("Checking for out of memory handling.");
var canvas = document.getElementById("canvas");
canvas.addEventListener('webglcontextlost', handleContextLost);
var wtu = WebGLTestUtils;
var gl = wtu.create3DContext("canvas");
var prog = wtu.setupProgram(gl, ["vshader", "fshader"], ["vPosition", "texCoord0"]);
WebGLDebugUtils.init(gl);
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.BLEND);
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-1,1,0, 1,1,0, -1,-1,0,
-1,-1,0, 1,1,0, 1,-1,0
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0, 1,0, 0,1,
0,1, 1,0, 1,1
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(1);
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
var texLoc = gl.getUniformLocation(prog, "tex");
gl.uniform1i(texLoc, 0);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setup should succeed");
var size = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
debug("max render buffer size: " + size +
", size used: " + (size / 2));
size /= 2;
var maxFBOs = 200;
var numFBOs = 0;
allocateNextFBO();
function allocateNextFBO() {
if (numFBOs >= maxFBOs) {
phase2();
return;
}
if (!allocateFBO()) {
phase2();
return;
}
++numFBOs;
setTimeout(allocateNextFBO, 100);
}
function allocateFBO() {
debug("");
debug("trying to create fbo #" + (numFBOs + 1));
var t = setupFBO(gl, 2);
if (!t) {
return false;
}
var tex = t.tex;
var fb = t.fb;
debug("allocating fbo color buffer of size " + size + " x " + size);
gl.texImage2D(gl.TEXTURE_2D,
0, // level
gl.RGBA, // internalFormat
size, // width
size, // height
0, // border
gl.RGBA, // format
gl.UNSIGNED_BYTE, // type
null); // data
if (!checkFBOStatus(gl)) {
return false;
}
g_textures.push(tex);
debug("succeeded in creating fbo");
debug("clearing the fbo with red color");
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.clearColor(1, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
debug("deleting fbo, but the now red texture should be untouched");
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.deleteFramebuffer(fb);
debug("drawing to the canvas using the red texture");
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
if (!checkPixels(gl)) {
return false;
}
debug("succeeded in drawing");
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "each run with no error");
return true;
}
function phase2() {
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
debug("");
debug("fbos allocated:" + numFBOs);
if (!checkPixels(gl)) {
testFailed("final check of canvas drawing buffer pixels failed");
}
debug("");
finishTest();
}
}
var successfullyParsed = true;
</script>
</body>
</html>