Source code
Revision control
Copy as Markdown
Other Tools
/* WebWorker for test_offscreencanvas_*.html */
(function () {
var port = null;
function isInWorker() {
try {
return !(self instanceof Window);
} catch (e) {
return true;
}
}
function postMessageGeneral(data) {
if (isInWorker()) {
if (port) {
port.postMessage(data);
} else {
postMessage(data);
}
} else {
postMessage(data, "*");
}
}
function ok(expect, msg) {
postMessageGeneral({ type: "test", result: !!expect, name: msg });
}
function finish() {
postMessageGeneral({ type: "finish" });
}
function drawCount(count) {
postMessageGeneral({ type: "draw", count });
}
function sendBlob(blob) {
postMessageGeneral({ type: "blob", blob });
}
function sendImageBitmap(img) {
if (port) {
port.postMessage({ type: "imagebitmap", bitmap: img });
} else {
postMessage({ type: "imagebitmap", bitmap: img });
}
}
//--------------------------------------------------------------------
// WebGL Drawing Functions
//--------------------------------------------------------------------
function createDrawFunc(canvas) {
var gl;
try {
gl = canvas.getContext("webgl");
} catch (e) {}
if (!gl) {
ok(false, "WebGL is unavailable");
return null;
}
var vertSrc =
"attribute vec2 position; \
void main(void) { \
gl_Position = vec4(position, 0.0, 1.0); \
}";
var fragSrc =
"precision mediump float; \
void main(void) { \
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); \
}";
// Returns a valid shader, or null on errors.
var createShader = function (src, t) {
var shader = gl.createShader(t);
gl.shaderSource(shader, src);
gl.compileShader(shader);
return shader;
};
var createProgram = function (vsSrc, fsSrc) {
var vs = createShader(vsSrc, gl.VERTEX_SHADER);
var fs = createShader(fsSrc, gl.FRAGMENT_SHADER);
var prog = gl.createProgram();
gl.attachShader(prog, vs);
gl.attachShader(prog, fs);
gl.linkProgram(prog);
if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
var str = "Shader program linking failed:";
str += "\nShader program info log:\n" + gl.getProgramInfoLog(prog);
str += "\n\nVert shader log:\n" + gl.getShaderInfoLog(vs);
str += "\n\nFrag shader log:\n" + gl.getShaderInfoLog(fs);
console.log(str);
ok(false, "Shader program linking failed");
return null;
}
return prog;
};
gl.disable(gl.DEPTH_TEST);
var program = createProgram(vertSrc, fragSrc);
ok(program, "Creating shader program");
program.positionAttr = gl.getAttribLocation(program, "position");
ok(program.positionAttr >= 0, "position attribute should be valid");
var vertCoordArr = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
var vertCoordBuff = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertCoordBuff);
gl.bufferData(gl.ARRAY_BUFFER, vertCoordArr, gl.STATIC_DRAW);
var checkGLError = function (prefix, refValue) {
if (!refValue) {
refValue = 0;
}
var error = gl.getError();
ok(
error == refValue,
prefix +
"gl.getError should be 0x" +
refValue.toString(16) +
", was 0x" +
error.toString(16) +
"."
);
};
var testPixel = function (x, y, refData, infoString) {
var pixel = new Uint8Array(4);
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
var pixelMatches =
pixel[0] == refData[0] &&
pixel[1] == refData[1] &&
pixel[2] == refData[2] &&
pixel[3] == refData[3];
ok(pixelMatches, infoString);
};
var preDraw = function (prefix) {
gl.clearColor(1.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
testPixel(
0,
0,
[255, 0, 0, 255],
prefix + "Should be red before drawing."
);
};
var postDraw = function (prefix) {
testPixel(
0,
0,
[0, 255, 0, 255],
prefix + "Should be green after drawing."
);
};
gl.useProgram(program);
gl.enableVertexAttribArray(program.position);
gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0);
// Start drawing
checkGLError("after setup");
return function (prefix, needCommitFrame) {
if (prefix) {
prefix = "[" + prefix + "] ";
} else {
prefix = "";
}
gl.viewport(0, 0, canvas.width, canvas.height);
checkGLError(prefix + "[viewport]");
preDraw(prefix);
checkGLError(prefix + "[predraw]");
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
checkGLError(prefix + "[drawarrays]");
postDraw(prefix);
checkGLError(prefix + "[postdraw]");
if (needCommitFrame) {
gl.commit();
checkGLError(prefix + "[commit]");
}
checkGLError(prefix);
};
}
/* entry point */
function entryFunction(testStr, subtests, offscreenCanvas) {
var test = testStr;
var canvas = offscreenCanvas;
if (test == "webgl_imagebitmap") {
canvas = new OffscreenCanvas(64, 64);
}
if (test != "subworker") {
ok(canvas, "Canvas successfully transfered to worker");
ok(canvas.getContext, "Canvas has getContext");
ok(canvas.width == 64, "OffscreenCanvas width should be 64");
ok(canvas.height == 64, "OffscreenCanvas height should be 64");
}
var draw;
//------------------------------------------------------------------------
// Basic WebGL test
//------------------------------------------------------------------------
if (test == "webgl") {
draw = createDrawFunc(canvas);
if (!draw) {
finish();
return;
}
var count = 0;
var iid = setInterval(function () {
if (count++ > 20) {
clearInterval(iid);
ok(true, "Worker is done");
finish();
return;
}
draw("loop " + count, true);
}, 0);
}
//------------------------------------------------------------------------
// Test dynamic fallback
//------------------------------------------------------------------------
else if (test == "webgl_fallback") {
draw = createDrawFunc(canvas);
if (!draw) {
return;
}
var count = 0;
var iid = setInterval(function () {
++count;
draw("loop " + count, true);
drawCount(count);
}, 0);
}
//------------------------------------------------------------------------
// Test toBlob
//------------------------------------------------------------------------
else if (test == "webgl_toblob") {
draw = createDrawFunc(canvas);
if (!draw) {
return;
}
draw("", false);
canvas.toBlob().then(function (blob) {
sendBlob(blob);
});
}
//------------------------------------------------------------------------
// Test toImageBitmap
//------------------------------------------------------------------------
else if (test == "webgl_imagebitmap") {
draw = createDrawFunc(canvas);
if (!draw) {
return;
}
draw("", false);
var imgBitmap = canvas.transferToImageBitmap();
sendImageBitmap(imgBitmap);
}
//------------------------------------------------------------------------
// Canvas Size Change from Worker
//------------------------------------------------------------------------
else if (test == "webgl_changesize") {
draw = createDrawFunc(canvas);
if (!draw) {
finish();
return;
}
draw("64x64", true);
setTimeout(function () {
canvas.width = 128;
canvas.height = 128;
draw("Increased to 128x128", true);
setTimeout(function () {
canvas.width = 32;
canvas.width = 32;
draw("Decreased to 32x32", true);
setTimeout(function () {
canvas.width = 64;
canvas.height = 64;
draw("Increased to 64x64", true);
ok(true, "Worker is done");
finish();
}, 0);
}, 0);
}, 0);
}
//------------------------------------------------------------------------
// Using OffscreenCanvas from sub workers
//------------------------------------------------------------------------
else if (test == "subworker") {
/* subworker tests take a list of tests to run on children */
var stillRunning = 0;
subtests.forEach(function (subtest) {
++stillRunning;
var subworker = new Worker("offscreencanvas.js");
subworker.onmessage = function (evt) {
/* report finish to parent when all children are finished */
if (evt.data.type == "finish") {
subworker.terminate();
if (--stillRunning == 0) {
ok(true, "Worker is done");
finish();
}
return;
}
/* relay all other messages to parent */
postMessage(evt.data);
};
var findTransferables = function (t) {
if (t.test == "subworker") {
var result = [];
t.subtests.forEach(function (subWorkerTest) {
result = result.concat(findTransferables(subWorkerTest));
});
return result;
} else {
return [t.canvas];
}
};
subworker.postMessage(subtest, findTransferables(subtest));
});
}
}
onmessage = function (evt) {
port = evt.ports[0];
entryFunction(evt.data.test, evt.data.subtests, evt.data.canvas);
};
onconnect = function (evt) {
port = evt.ports[0];
port.addEventListener("message", function (event) {
entryFunction(event.data.test, event.data.subtests, event.data.canvas);
});
port.start();
};
if (!isInWorker()) {
window.entryFunction = entryFunction;
}
})();