Skip to content

Instantly share code, notes, and snippets.

@mrdaybird
Created May 14, 2023 05:45
Show Gist options
  • Save mrdaybird/7c0978f8752db96d7d659090bd50a9b9 to your computer and use it in GitHub Desktop.
Save mrdaybird/7c0978f8752db96d7d659090bd50a9b9 to your computer and use it in GitHub Desktop.
Matrix Multiplication using WebGL2 and Javascript
<!--
Matrix Multiplication using WebGL2.
Written by vaibhav(github: mrdaybird)
-->
<!DOCTYPE html>
<html>
<head>
<title>Matrix multiplication using WebGL2</title>
</head>
<body>
<script type="module">
//Make sure twgl-full.module.js is in the current working directory or
//the library is imported from the correct file destination
//twgl.js link: https://github.com/greggman/twgl.js
import * as twgl from './twgl-full.module.js';
const vs = `
#version 300 es
in vec4 position;
void main(){
gl_Position = position;
}
`;
const fs = `
#version 300 es
precision highp float;
in vec4 position;
uniform sampler2D matA;
uniform sampler2D matB;
out vec4 outColor;
vec4 dotproduct(int rowIdx, int columnIdx, int rowLengthA){
vec4 sum = vec4(0.0);
for(int k = 0; k < rowLengthA; k++){
vec4 elementA = texelFetch(matA, ivec2(k, rowIdx), 0);
vec4 elementB = texelFetch(matB, ivec2(columnIdx, k), 0);
sum += elementA * elementB;
}
return sum;
}
void main(){
ivec2 texelCoord = ivec2(gl_FragCoord.xy);
int rowIdx = texelCoord.y;
int columnIdx = texelCoord.x;
ivec2 dimA = textureSize(matA, 0);
outColor = dotproduct(rowIdx, columnIdx, dimA.x);
}
`;
const canvas = document.createElement("canvas");
const gl = canvas.getContext("webgl2");
const ext = gl.getExtension("EXT_color_buffer_float");
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
if(!ext){
console.error("EXT_color_buffer_float not found. Sorry, the code will not work!");
}
const arrays = {
position : { numComponents : 2, data: [
-1, -1,
1, -1,
-1, 1,
-1, 1,
1, -1,
1, 1]
}};
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const n = 4, m = 3;
function random(N){
const arr = new Float32Array(N);
for(let i = 0; i < N; i++)
arr[i] = Math.random();
return arr;
}
const A = random(n*m);
const B = random(n*m);
const textures = twgl.createTextures(gl, {
matA : {
width : m,
height : n,
src : A,
internalFormat : gl.R32F,
format : gl.RED,
minMag : gl.NEAREST
},
matB : {
width : n,
height : m,
src : B,
internalFormat : gl.R32F,
format : gl.RED,
minMag : gl.NEAREST
}
});
const uniforms = {
matA : textures.matA,
matB : textures.matB
};
const matC = twgl.createTexture(gl, {
width : n,
height : n,
internalFormat : gl.R32F,
format : gl.RED,
type : gl.FLOAT,
minMag : gl.NEAREST
});
const attachments = [
{ format : gl.RED,
attachment : matC,
type : gl.FLOAT,
}
];
const fbi = twgl.createFramebufferInfo(gl, attachments, n, n);
gl.bindFramebuffer(gl.FRAMEBUFFER, fbi.framebuffer);
gl.viewport(0, 0, n, n);
gl.useProgram(programInfo.program);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, bufferInfo);
const pixels = new Float32Array(n*n*4);
gl.readPixels(0, 0, n, n, gl.RGBA, gl.FLOAT, pixels);
const results = new Float32Array(n*n);
for(let i = 0; i < n*n; i++)
results[i] = pixels[i*4];
displayMatrix(A, n, m, "A");
displayMatrix(B, m, n, "B");
displayMatrix(results, n, n, "C")
function displayMatrix(mat, N, M, tag){
log(`${tag}:\n${createMatString(mat, N, M)}`);
}
function createMatString(mat, N, M){
let str = "";
for(let i = 0; i < N; i++){
for(let j = 0; j < M; j++){
str += `${mat[i * M + j].toFixed(5)} `;
}
str += '\n';
}
return str;
}
function log(...args) {
const elem = document.createElement('pre');
elem.textContent = args.join(' ');
document.body.appendChild(elem);
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment