Toggle navigation
MeasureThat.net
Create a benchmark
Tools
Feedback
FAQ
Register
Log In
Run results for:
webg vs canvas
Go to the benchmark
Embed
Embed Benchmark Result
Run details:
User agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0
Browser:
Chrome 141
Operating system:
Windows
Device Platform:
Desktop
Date tested:
7 months ago
Test name
Executions per second
webgl
110.1 Ops/sec
canvas
76.5 Ops/sec
HTML Preparation code:
<canvas id="canvas"></canvas> <div id="test"> </div> <!-- vertex shader --> <script id="vertex-shader-2d" type="x-shader/x-vertex"> attribute vec2 a_position; attribute vec2 a_texCoord; uniform vec2 u_resolution; varying vec2 v_texCoord; void main() { // convert the rectangle from pixels to 0.0 to 1.0 vec2 zeroToOne = a_position / u_resolution; // convert from 0->1 to 0->2 vec2 zeroToTwo = zeroToOne * 2.0; // convert from 0->2 to -1->+1 (clipspace) vec2 clipSpace = zeroToTwo - 1.0; gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); // pass the texCoord to the fragment shader // The GPU will interpolate this value between points. v_texCoord = a_texCoord; } </script> <!-- fragment shader --> <script id="fragment-shader-2d" type="x-shader/x-fragment"> precision mediump float; // our texture uniform sampler2D u_image; // the texCoords passed in from the vertex shader. varying vec2 v_texCoord; void main() { gl_FragColor = texture2D(u_image, v_texCoord); } </script><!-- for most samples webgl-utils only provides shader compiling/linking and canvas resizing because why clutter the examples with code that's the same in every sample. See https://webglfundamentals.org/webgl/lessons/webgl-boilerplate.html and https://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html for webgl-utils, m3, m4, and webgl-lessons-ui. --> <script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script> <style> body { margin: 0; } canvas { width: 900px; height: 600px; display: block; } div { width: 900px; height: 600px; display: block; } </style>
Tests:
webgl
// WebGL - 2D Image // from https://webglfundamentals.org/webgl/webgl-2d-image.html "use strict"; function main() { render() } function render() { // Get A WebGL context /** @type {HTMLCanvasElement} */ var canvas = document.querySelector("#canvas"); var gl = canvas.getContext("webgl"); if (!gl) { return; } // setup GLSL program var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-2d", "fragment-shader-2d"]); // look up where the vertex data needs to go. var positionLocation = gl.getAttribLocation(program, "a_position"); var texcoordLocation = gl.getAttribLocation(program, "a_texCoord"); // Create a buffer to put three 2d clip space points in var positionBuffer = gl.createBuffer(); // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer) gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // Set a rectangle the same size as the image. setRectangle(gl, 0, 0, 900, 600); // provide texture coordinates for the rectangle. var texcoordBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, ]), gl.STATIC_DRAW); // Create a texture. var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); // Set the parameters so we can render any size image. 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); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); // Upload the image into the texture. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 900, 600, 0, gl.RGBA, gl.UNSIGNED_BYTE, createCushion(0, 900, 0, 600, 0, 0.005, -0.001, 0.001, 0, 150, 0)); // lookup uniforms var resolutionLocation = gl.getUniformLocation(program, "u_resolution"); webglUtils.resizeCanvasToDisplaySize(gl.canvas); // Tell WebGL how to convert from clip space to pixels gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); // Clear the canvas gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); // Tell it to use our program (pair of shaders) gl.useProgram(program); // Turn on the position attribute gl.enableVertexAttribArray(positionLocation); // Bind the position buffer. gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER) var size = 2; // 2 components per iteration var type = gl.FLOAT; // the data is 32bit floats var normalize = false; // don't normalize the data var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position var offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( positionLocation, size, type, normalize, stride, offset); // Turn on the texcoord attribute gl.enableVertexAttribArray(texcoordLocation); // bind the texcoord buffer. gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer); // Tell the texcoord attribute how to get data out of texcoordBuffer (ARRAY_BUFFER) var size = 2; // 2 components per iteration var type = gl.FLOAT; // the data is 32bit floats var normalize = false; // don't normalize the data var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position var offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( texcoordLocation, size, type, normalize, stride, offset); // set the resolution gl.uniform2f(resolutionLocation, gl.canvas.width, gl.canvas.height); // Draw the rectangle. var primitiveType = gl.TRIANGLES; var offset = 0; var count = 6; gl.drawArrays(primitiveType, offset, count); } function setRectangle(gl, x, y, width, height) { var x1 = x; var x2 = x + width; var y1 = y; var y2 = y + height; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2, ]), gl.STATIC_DRAW); } function createCushion (minX, maxX, minY, maxY, coef0, coef1, coef2, coef3, base_red, base_green, base_blue) { const img = new Uint8Array(Math.floor(maxX-minX) * Math.floor(maxY-minY) * 4); const lx = 0.21; // 5 const ly = 0.14; // 3 const lz = 0.65; // 15 const width = Math.floor((maxX - minX) * 4) for (var x = 0; x < maxX - minX; ++x) { { for (var y = 0; y < maxY - minY; ++y) { { const nx = -(2 * coef1 * (x + minX) + coef0); const ny = -(2 * coef3 * (y + minY) + coef2); const norm = Math.sqrt(nx * nx + ny * ny + 1); const cosa = (nx * lx + ny * ly + lz) / norm; const luminance = 2 * (0.3 + 0.8 * Math.max(0, cosa)); const red = base_red * luminance; const green = base_green * luminance; const blue = base_blue * luminance; img[((y * width) + (x * 4)) + 0] = Math.min(red, 255); img[((y * width) + (x * 4)) + 1] = Math.min(green, 255); img[((y * width) + (x * 4)) + 2] = Math.min(blue, 255); img[((y * width) + (x * 4)) + 3] = 255; } } } } return img } main();
canvas
function addCushion (id, minX, maxX, minY, maxY, coef0, coef1, coef2, coef3, base_red, base_green, base_blue) { const canvas = document.createElement("canvas"); canvas.width = maxX - minX canvas.height = maxY - minY const ctx = canvas.getContext("2d") const img = ctx.createImageData(maxX - minX, maxY - minY); const lx = 0.21; // 5 const ly = 0.14; // 3 const lz = 0.65; // 15 const width = Math.floor((maxX - minX) * 4) for (var x = 0; x < maxX - minX; ++x) { { for (var y = 0; y < maxY - minY; ++y) { { const nx = -(2 * coef1 * (x + minX) + coef0); const ny = -(2 * coef3 * (y + minY) + coef2); const norm = Math.sqrt(nx * nx + ny * ny + 1); const cosa = (nx * lx + ny * ly + lz) / norm; const luminance = 2 * (0.3 + 0.8 * Math.max(0, cosa)); const red = base_red * luminance; const green = base_green * luminance; const blue = base_blue * luminance; img.data[((y * width) + (x * 4)) + 0] = Math.min(red, 255); img.data[((y * width) + (x * 4)) + 1] = Math.min(green, 255); img.data[((y * width) + (x * 4)) + 2] = Math.min(blue, 255); img.data[((y * width) + (x * 4)) + 3] = 255; } } } } ctx.putImageData(img, 0, 0) console.log(canvas.width) console.log(canvas.height) document.getElementById(id).style.background = 'url(' + canvas.toDataURL() + ')' } addCushion("test", 0, 900, 0, 600, 0, 0.005, -0.001, 0.001, 0, 150, 0)