---
url: /examples/gpgpu/maths.md
---

::: example-editor

```ts #active
import { glContext, transformFeedback, createFloatDataTexture } from "@radiancejs/gl";

export function square(flatMatrix: number[], matrixSize: number) {
  const indicesN: number[] = [];
  const indicesP: number[] = [];

  for (let p = 0; p < matrixSize; p++) {
    for (let n = 0; n < matrixSize; n++) {
      indicesN.push(n);
      indicesP.push(p);
    }
  }

  const { gl } = glContext({ canvas: "#glCanvas" });

  const tf = transformFeedback({
    gl,
    vertex: /* glsl */ `
    in float n;
    in float p;
    uniform sampler2D matrixContent;
    out float product;

    void main() {
      product = 0.0;
      int matrixSize = textureSize(matrixContent, 0).x;

      for (int i = 0; i < matrixSize; i++) {
        float a = texelFetch(matrixContent, ivec2(int(n), i), 0).x;
        float b = texelFetch(matrixContent, ivec2(i, int(p)), 0).x;
        product += a * b;
      }
    }
    `,
    uniforms: {
      matrixContent: createFloatDataTexture(flatMatrix.flatMap((v) => [v, 0, 0, 0])), // RGBA texture
    },
    attributes: {
      n: { size: 1, data: indicesN },
      p: { size: 1, data: indicesP },
    },
    outputs: {
      product: { size: 1 },
    },
  });

  tf.render();

  return tf.getOutputData("product");
}

```

```ts
export function square(flatMatrix: number[], matrixSize: number) {
  const result = new Array(matrixSize * matrixSize).fill(0);

  for (let i = 0; i < matrixSize; i++) {
    for (let j = 0; j < matrixSize; j++) {
      for (let k = 0; k < matrixSize; k++) {
        result[i * matrixSize + j] +=
          flatMatrix[i * matrixSize + k] * flatMatrix[k * matrixSize + j];
      }
    }
  }

  return result;
}

```

```ts
import { square as gpuSquare } from "./gpu";
import { square as cpuSquare } from "./cpu";
import { print, benchmark, checkResults } from "./utils";
import "./styles.css";

const matrixSize = 500;
const matrixData = Array.from({ length: matrixSize * matrixSize }, () =>
  Math.floor(Math.random() * 10),
);

print("#size", `${matrixSize}`);

setTimeout(() => {
  const gpuResult = benchmark(() => gpuSquare(matrixData, matrixSize));
  print("#gpu", `${gpuResult.duration}ms`);

  // Let the UI update before running the (slow) CPU benchmark.
  setTimeout(() => {
    const cpuResult = benchmark(() => cpuSquare(matrixData, matrixSize));

    print(
      "#cpu",
      `${cpuResult.duration}ms (x${(cpuResult.duration / gpuResult.duration).toFixed(1)})`,
    );

    // commented out because too many iterations for Codesandbox
    // checkResults(gpuResult.result, cpuResult.result);
  }, 10);
}, 0);

```

```ts
export function benchmark<T>(fn: () => T) {
  performance.mark("start");
  const result = fn();
  performance.mark("end");
  const duration = Math.floor(performance.measure("duration", "start", "end").duration);

  return { result, duration };
}

export function checkResults(gpuResult: Float32Array, cpuResult: number[]) {
  for (let i = 0; i < gpuResult.length; i++) {
    if (gpuResult[i] !== cpuResult[i]) {
      console.error("CPU and GPU results do not match");
      return;
    }
  }
  console.log("CPU and GPU results match");
}

export function print(selector: string, content: string) {
  document.querySelector(selector)!.textContent = content;
}

```

```css
body {
  margin: 0;
  width: 100svw;
  height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: black;
  color: white;
  font-family: sans-serif;
}

canvas {
  display: none;
}

table {
  font-size: 2rem;
  border-spacing: 1em 0.5em;
}

#gpu,
#cpu {
  width: 12ch;
}

```

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>RadianceJS Example</title>
  </head>
  <body>
    <canvas id="glCanvas"></canvas>
    <div>
      <p>Computing the square of a matrix of size <span id="size"></span></p>
      <table>
        <tr>
          <th>GPU</th>
          <td id="gpu">computing...</td>
        </tr>
        <tr>
          <th>CPU</th>
          <td id="cpu">computing...</td>
        </tr>
      </table>
    </div>
    <script src="/index.ts"></script>
  </body>
</html>

```

:::
