gridviz
gridviz copied to clipboard
Performance
trafficstars
Opening a separate, broader issue for this as it is not necessarily related to the main thread.
The performance of 2D canvas is quite limited in most situations. Especially on mobile devices (open the lego style demo for example on your mobile and then compare it with the WebGL demo. The difference is huge.)
This got me thinking: would it make sense to port our 2D canvas logic to WebGL?
Here is a mock-up snippet:
class CanvasToWebGL {
constructor(gl) {
this.gl = gl;
this.color = [1.0, 0.0, 0.0, 1.0]; // Default red color
this.initShaders();
}
initShaders() {
const vertexShaderSource = `
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
vec2 zeroToOne = a_position / u_resolution;
vec2 zeroToTwo = zeroToOne * 2.0;
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}`;
const fragmentShaderSource = `
precision mediump float;
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}`;
// Compile shaders and link program
const vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, fragmentShaderSource);
this.program = this.createProgram(vertexShader, fragmentShader);
// Look up attribute/uniform locations
this.positionLocation = this.gl.getAttribLocation(this.program, "a_position");
this.resolutionLocation = this.gl.getUniformLocation(this.program, "u_resolution");
this.colorLocation = this.gl.getUniformLocation(this.program, "u_color");
// Create buffer for rectangle vertices
this.positionBuffer = this.gl.createBuffer();
}
createShader(type, source) {
const shader = this.gl.createShader(type);
this.gl.shaderSource(shader, source);
this.gl.compileShader(shader);
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
console.error(this.gl.getShaderInfoLog(shader));
this.gl.deleteShader(shader);
return null;
}
return shader;
}
createProgram(vertexShader, fragmentShader) {
const program = this.gl.createProgram();
this.gl.attachShader(program, vertexShader);
this.gl.attachShader(program, fragmentShader);
this.gl.linkProgram(program);
if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
console.error(this.gl.getProgramInfoLog(program));
this.gl.deleteProgram(program);
return null;
}
return program;
}
setFillColor(r, g, b, a = 1.0) {
this.color = [r, g, b, a];
}
fillRect(x, y, width, height) {
const gl = this.gl;
// Set up rectangle vertices
const x1 = x, y1 = y;
const x2 = x + width, y2 = y + height;
const vertices = new Float32Array([
x1, y1, x2, y1, x1, y2,
x1, y2, x2, y1, x2, y2,
]);
// Bind buffer and upload data
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// Use program and set uniforms
gl.useProgram(this.program);
gl.uniform2f(this.resolutionLocation, gl.canvas.width, gl.canvas.height);
gl.uniform4fv(this.colorLocation, this.color);
// Enable attribute and set up pointer
gl.enableVertexAttribArray(this.positionLocation);
gl.vertexAttribPointer(this.positionLocation, 2, gl.FLOAT, false, 0, 0);
// Draw rectangle
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
}
// Usage:
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl");
const webGLCanvas = new CanvasToWebGL(gl);
webGLCanvas.setFillColor(1, 0, 0); // Red color
webGLCanvas.fillRect(10, 10, 100, 50);