Created
May 14, 2023 05:45
-
-
Save mrdaybird/7c0978f8752db96d7d659090bd50a9b9 to your computer and use it in GitHub Desktop.
Matrix Multiplication using WebGL2 and Javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
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