Toggle navigation
MeasureThat.net
Create a benchmark
Tools
Feedback
FAQ
Register
Log In
webg vs canvas
(version: 0)
Comparing performance of:
webgl vs canvas
Created:
5 years ago
by:
Guest
Jump to the latest result
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)
Rendered benchmark preparation results:
Suite status:
<idle, ready to run>
Run tests (2)
Previous results
Fork
Test case name
Result
webgl
canvas
Fastest:
N/A
Slowest:
N/A
Latest run results:
Run details:
(Test run date:
7 months ago
)
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/OS:
Chrome 141 on Windows
View result in a separate tab
Embed
Embed Benchmark Result
Test name
Executions per second
webgl
110.1 Ops/sec
canvas
76.5 Ops/sec
Autogenerated LLM Summary
(model
llama3.2:3b
, generated one year ago):
Let's dive into the benchmark results! We have two tests: `canvas` and `webgl`. The benchmark is likely measuring the performance of rendering graphics using these two technologies. The results show: 1. **Canvas**: 4.496908187866211 executions per second * This suggests that the canvas implementation is relatively fast, but not as efficient as other options. 2. **WebGL**: 4.472271919250488 executions per second * Similar to the canvas result, WebGL is also relatively fast, but there's a small margin of improvement over Canvas. In terms of performance, WebGL appears to be slightly faster than Canvas on this particular benchmark. However, it's essential to note that these results are specific to this test and may not reflect real-world scenarios. When considering which technology to use, the choice between Canvas and WebGL depends on several factors: * **Performance**: If raw speed is crucial, WebGL might be a better option due to its optimized architecture. * **Compatibility**: WebGL requires a powerful GPU to function effectively, while Canvas can run on a wide range of devices. * **Development complexity**: WebGL has more complex setup and usage requirements compared to Canvas. Ultimately, the decision depends on your project's specific needs, performance requirements, and target audience.
Related benchmarks:
Canvas gradient perf
Canvas gradient perf
Canvas Pixel vs Fill rect 1px
Setting Canvas Pixel (w/string interpolation)
Comments
Confirm delete:
Do you really want to delete benchmark?