2020-05-21 00:11:25 +02:00
|
|
|
/* globals testAPI */
|
2017-08-13 23:44:31 +02:00
|
|
|
(function(){
|
2017-10-03 15:35:31 +02:00
|
|
|
"use strict";
|
|
|
|
|
2019-11-28 01:26:35 +01:00
|
|
|
function getParameters(context){
|
|
|
|
const parameters = [];
|
2019-12-16 19:27:28 +01:00
|
|
|
for (let name in context){
|
2019-11-28 01:26:35 +01:00
|
|
|
if (name.toUpperCase() === name){
|
2019-12-16 19:27:28 +01:00
|
|
|
const value = context.getParameter(context[name]);
|
2019-11-28 01:26:35 +01:00
|
|
|
if (value !== null){
|
|
|
|
parameters.push({name: name, value: value});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const debugExtension = context.getExtension("WEBGL_debug_renderer_info");
|
|
|
|
|
2019-12-16 19:27:28 +01:00
|
|
|
for (let name in debugExtension){
|
2019-11-28 01:26:35 +01:00
|
|
|
if (name.toUpperCase() === name){
|
2019-12-16 19:27:28 +01:00
|
|
|
const value = context.getParameter(debugExtension[name]);
|
2019-11-28 01:26:35 +01:00
|
|
|
if (value !== null){
|
|
|
|
parameters.push({name: name, value: value});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-16 19:27:28 +01:00
|
|
|
const frontParameters = ["VENDOR", "RENDERER", "UNMASKED_VENDOR_WEBGL", "UNMASKED_RENDERER_WEBGL"];
|
2019-11-28 01:26:35 +01:00
|
|
|
parameters.sort(function(a, b){
|
2019-12-16 19:27:28 +01:00
|
|
|
const frontA = frontParameters.indexOf(a.name);
|
|
|
|
const frontB = frontParameters.indexOf(b.name);
|
2019-11-28 01:26:35 +01:00
|
|
|
if (frontA !== -1){
|
|
|
|
if (frontB !== -1){
|
|
|
|
return frontA - frontB;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (frontB !== -1){
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return a.name < b.name? -1: 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return parameters;
|
|
|
|
}
|
|
|
|
|
2020-05-21 00:11:25 +02:00
|
|
|
function createHashRow(hashTable, rowName){
|
|
|
|
const row = document.createElement("tr");
|
|
|
|
hashTable.appendChild(row);
|
|
|
|
|
|
|
|
const nameCell = document.createElement("th");
|
|
|
|
nameCell.textContent = rowName;
|
|
|
|
row.appendChild(nameCell);
|
|
|
|
|
|
|
|
const valueCell = document.createElement("td");
|
|
|
|
valueCell.innerHTML = "<i>computing</i>";
|
|
|
|
row.appendChild(valueCell);
|
|
|
|
|
|
|
|
return valueCell;
|
|
|
|
}
|
|
|
|
|
|
|
|
function fillWebGlContext(context){
|
|
|
|
// taken from https://github.com/Valve/fingerprintjs2/blob/master/fingerprint2.js
|
|
|
|
const vertexShaderTemplate = "attribute vec2 attrVertex;varying vec2 varyingTexCoordinate;" +
|
|
|
|
"uniform vec2 uniformOffset;void main(){varyingTexCoordinate=attrVertex+uniformOffset;" +
|
|
|
|
"gl_Position=vec4(attrVertex,0,1);}";
|
|
|
|
const fragmentShaderTemplate = "precision mediump float;varying vec2 varyingTexCoordinate;" +
|
|
|
|
"void main() {gl_FragColor=vec4(varyingTexCoordinate,0,1);}";
|
|
|
|
const vertexPosBuffer = context.createBuffer();
|
|
|
|
context.bindBuffer(context.ARRAY_BUFFER, vertexPosBuffer);
|
|
|
|
const vertices = new Float32Array([-0.2, -0.9, 0, 0.4, -0.26, 0, 0, 0.732134444, 0]);
|
|
|
|
context.bufferData(context.ARRAY_BUFFER, vertices, context.STATIC_DRAW);
|
|
|
|
vertexPosBuffer.itemSize = 3;
|
|
|
|
vertexPosBuffer.numItems = 3;
|
|
|
|
const program = context.createProgram();
|
|
|
|
const vertexShader = context.createShader(context.VERTEX_SHADER);
|
|
|
|
context.shaderSource(vertexShader, vertexShaderTemplate);
|
|
|
|
context.compileShader(vertexShader);
|
|
|
|
const fragmentShader = context.createShader(context.FRAGMENT_SHADER);
|
|
|
|
context.shaderSource(fragmentShader, fragmentShaderTemplate);
|
|
|
|
context.compileShader(fragmentShader);
|
|
|
|
context.attachShader(program, vertexShader);
|
|
|
|
context.attachShader(program, fragmentShader);
|
|
|
|
context.linkProgram(program);
|
|
|
|
context.useProgram(program);
|
|
|
|
program.vertexPosAttrib = context.getAttribLocation(program, "attrVertex");
|
|
|
|
program.offsetUniform = context.getUniformLocation(program, "uniformOffset");
|
|
|
|
context.enableVertexAttribArray(program.vertexPosArray);
|
|
|
|
context.vertexAttribPointer(program.vertexPosAttrib, vertexPosBuffer.itemSize, context.FLOAT, !1, 0, 0);
|
|
|
|
context.uniform2f(program.offsetUniform, 1, 1);
|
|
|
|
context.drawArrays(context.TRIANGLE_STRIP, 0, vertexPosBuffer.numItems);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function testSupport(context, index){
|
|
|
|
const canvas = document.createElement("canvas");
|
|
|
|
canvas.width = 11;
|
|
|
|
canvas.height = 13;
|
|
|
|
|
2019-12-16 19:27:28 +01:00
|
|
|
const output = document.createElement("div");
|
2017-10-10 20:13:40 +02:00
|
|
|
document.getElementById("output").appendChild(output);
|
|
|
|
try {
|
2019-12-16 19:27:28 +01:00
|
|
|
const gl = canvas.getContext(context) || canvas.getContext("experimental-" + context);
|
2017-10-10 20:13:40 +02:00
|
|
|
|
|
|
|
// paint it completely black
|
|
|
|
gl.clearColor(index * 0.25, index * 0.25, index * 0.25, 1);
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
|
|
|
2019-12-16 19:27:28 +01:00
|
|
|
const pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);
|
2017-10-10 20:13:40 +02:00
|
|
|
gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
2019-12-16 19:27:28 +01:00
|
|
|
const values = {};
|
|
|
|
let max = 0;
|
|
|
|
for (let i = 0; i < pixels.length; i += 1){
|
2017-10-10 20:13:40 +02:00
|
|
|
values[pixels[i]] = (values[pixels[i]] || 0) + 1;
|
|
|
|
max = Math.max(max, values[pixels[i]]);
|
|
|
|
}
|
2019-09-19 00:41:20 +02:00
|
|
|
|
2020-05-21 00:11:25 +02:00
|
|
|
output.textContent = context + ": " +
|
|
|
|
(max !== 3 * values[255]? "": "not ") + "supported ";
|
|
|
|
output.title = JSON.stringify(values);
|
|
|
|
}
|
|
|
|
catch (error){
|
|
|
|
output.textContent = context + ": ERROR";
|
|
|
|
output.title = error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function testParameters(context, hashTable){
|
|
|
|
const canvas = document.createElement("canvas");
|
|
|
|
canvas.width = 11;
|
|
|
|
canvas.height = 13;
|
|
|
|
|
|
|
|
const hashCell = createHashRow(hashTable, "parameter");
|
|
|
|
|
|
|
|
try {
|
|
|
|
const gl = canvas.getContext(context) || canvas.getContext("experimental-" + context);
|
|
|
|
|
2019-11-28 01:26:35 +01:00
|
|
|
const parameters = getParameters(gl);
|
2019-09-19 00:41:20 +02:00
|
|
|
if (context === "webgl2"){
|
2019-12-16 19:27:28 +01:00
|
|
|
const parameterOutput = document.createElement("table");
|
2019-09-19 00:41:20 +02:00
|
|
|
document.getElementById("parameters").appendChild(parameterOutput);
|
|
|
|
parameters.forEach(function(parameter){
|
2019-12-16 19:27:28 +01:00
|
|
|
const parameterRow = document.createElement("tr");
|
2019-09-19 00:41:20 +02:00
|
|
|
parameterRow.innerHTML = "<td>" + parameter.name + "</td><td>" + parameter.value + "</td>";
|
|
|
|
parameterOutput.appendChild(parameterRow);
|
|
|
|
});
|
|
|
|
}
|
2019-12-16 19:27:28 +01:00
|
|
|
|
2020-05-21 00:11:25 +02:00
|
|
|
hashCell.textContent = await testAPI.hash(parameters.map(function(parameter){
|
|
|
|
return parameter.name + ": " + parameter.value;
|
|
|
|
}).join(","));
|
2017-10-10 20:13:40 +02:00
|
|
|
}
|
2019-11-28 01:26:35 +01:00
|
|
|
catch (error){
|
2020-05-21 00:11:25 +02:00
|
|
|
hashCell.textContent = "ERROR";
|
|
|
|
hashCell.title = error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-01 13:53:05 +02:00
|
|
|
const drawImage = location.search !== "?noDraw";
|
|
|
|
|
2020-05-21 00:11:25 +02:00
|
|
|
async function createImageHash(context, hashTable){
|
|
|
|
return Promise.all([function(){
|
|
|
|
const canvas = document.createElement("canvas");
|
|
|
|
canvas.width = 300;
|
|
|
|
canvas.height = 150;
|
|
|
|
return canvas;
|
|
|
|
}, function(){
|
|
|
|
if (window.OffscreenCanvas){
|
|
|
|
return new OffscreenCanvas(300, 150);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}].map(async function(getter){
|
|
|
|
const canvas = getter();
|
|
|
|
if (canvas){
|
|
|
|
const hashCell = createHashRow(hashTable, "image" + (canvas.toDataURL? "": " (offscreen)"));
|
|
|
|
try {
|
2020-06-01 13:53:05 +02:00
|
|
|
if (drawImage){
|
|
|
|
const gl = canvas.getContext(context) || canvas.getContext("experimental-" + context);
|
|
|
|
fillWebGlContext(gl);
|
|
|
|
}
|
2020-05-21 00:11:25 +02:00
|
|
|
if (canvas.convertToBlob || canvas.toBlob){
|
2020-06-01 13:53:05 +02:00
|
|
|
const blob = await (canvas.convertToBlob? canvas.convertToBlob(): (canvas.toBlob.length?
|
2020-05-21 00:11:25 +02:00
|
|
|
new Promise(function(resolve){canvas.toBlob(resolve);}):
|
|
|
|
canvas.toBlob()
|
|
|
|
));
|
|
|
|
hashCell.textContent = await testAPI.hash(await testAPI.readBlob(blob));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (error){
|
|
|
|
console.log(error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
async function createWorkerImageHash(context, hashTable){
|
|
|
|
if (window.Worker && window.OffscreenCanvas){
|
|
|
|
const hashCell = createHashRow(hashTable, "image (offscreen worker)");
|
|
|
|
const url = new URL("./testAPI.js", location);
|
2020-06-01 13:53:05 +02:00
|
|
|
hashCell.textContent = await testAPI.runInWorker(async function getHash(contextType, drawImage){
|
2020-05-21 00:11:25 +02:00
|
|
|
const canvas = new OffscreenCanvas(300, 150);
|
2020-06-01 13:53:05 +02:00
|
|
|
if (drawImage){
|
|
|
|
const context = canvas.getContext(contextType);
|
|
|
|
fillWebGlContext(context);
|
|
|
|
}
|
2020-05-21 00:11:25 +02:00
|
|
|
return await testAPI.hash(
|
|
|
|
await testAPI.readBlob(
|
|
|
|
canvas.convertToBlob?
|
|
|
|
await canvas.convertToBlob():
|
|
|
|
await canvas.toBlob()
|
|
|
|
)
|
|
|
|
);
|
2020-06-01 13:53:05 +02:00
|
|
|
}, [context, drawImage], [url, fillWebGlContext]);
|
2017-10-10 20:13:40 +02:00
|
|
|
}
|
2020-05-21 00:11:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
["webgl", "webgl2"].forEach(async function(context, index){
|
|
|
|
testSupport(context, index);
|
|
|
|
|
|
|
|
const hashOutput = document.createElement("div");
|
|
|
|
document.getElementById("hashes").appendChild(hashOutput);
|
|
|
|
|
|
|
|
hashOutput.textContent = context + ": ";
|
|
|
|
const table = document.createElement("table");
|
|
|
|
hashOutput.appendChild(table);
|
|
|
|
|
|
|
|
testParameters(context, table);
|
|
|
|
createImageHash(context, table);
|
|
|
|
createWorkerImageHash(context, table);
|
2017-10-10 20:13:40 +02:00
|
|
|
});
|
2017-08-13 23:44:31 +02:00
|
|
|
}());
|