/* 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; } })();