004 Web Assembly Conway game optimization

0 introduction

Video address: https://www.bilibili.com/video/BV1eg411g7c8
Related source code: https://github.com/anonymousGiga/Rust-and-Web-Assembly

1 Description

In the implementation of the previous section, we implemented the padding content in Rust, and then let wasm bindgen convert it into a valid js string, which resulted in unnecessary copies. Because the js code already knows the width and height of the universe, it can directly read the memory of the web assembly that makes up the cell. Also we'll be switching to the Canvas API instead of using unicode text directly.

This section is modified directly on top of the content of the previous section.

2 achieve

The content of the body tag in wasm-game-of-life/www/index.html is modified as follows:

<body>
  <!--canvas标签是表示图像或图表-->
  <canvas id="game-of-life-canvas"></canvas>
  <script src='./bootstrap.js'></script>
</body>

Next, we add the following code in wasm-game-of-life/src/lib.rs:


#![allow(unused_variables)]
fn main() {
/// Public methods, exported to JavaScript.
#[wasm_bindgen]
impl Universe {
    // ...

    pub fn width(&self) -> u32 {
        self.width
    }

    pub fn height(&self) -> u32 {
        self.height
    }

    pub fn cells(&self) -> *const Cell {
        self.cells.as_ptr()
    }
}
}

Modify the code in wasm-game-of-life/www/index.js as follows:

//import { Universe } from "wasm-game-of-life";
import { Universe, Cell } from "wasm-game-of-life";
import { memory } from "wasm-game-of-life/wasm_game_of_life_bg";

const CELL_SIZE = 5; // px
const GRID_COLOR = "#CCCCCC";
const DEAD_COLOR = "#FFFFFF";
const ALIVE_COLOR = "#000000";

const universe = Universe.new();
const width = universe.width();
const height = universe.height();

const canvas = document.getElementById("game-of-life-canvas");
canvas.height = (CELL_SIZE + 1) * height + 1;
canvas.width = (CELL_SIZE + 1) * width + 1;

const ctx = canvas.getContext('2d');

function renderLoop() {
  universe.tick();

  drawGrid();
  drawCells();

  window.requestAnimationFrame(renderLoop);
}

function drawGrid() {
  ctx.beginPath();
  ctx.strokeStyle = GRID_COLOR;

  // Vertical lines.
  for (let i = 0; i <= width; i++) {
    ctx.moveTo(i * (CELL_SIZE + 1) + 1, 0);
    ctx.lineTo(i * (CELL_SIZE + 1) + 1, (CELL_SIZE + 1) * height + 1);
  }

  // Horizontal lines.
  for (let j = 0; j <= height; j++) {
    ctx.moveTo(0,                           j * (CELL_SIZE + 1) + 1);
    ctx.lineTo((CELL_SIZE + 1) * width + 1, j * (CELL_SIZE + 1) + 1);
  }

  ctx.stroke();
}

function getIndex(row, column) {
  return row * width + column;
}

function drawCells() {
  const cellsPtr = universe.cells();
  const cells = new Uint8Array(memory.buffer, cellsPtr, width * height);

  ctx.beginPath();

  for (let row = 0; row < height; row++) {
    for (let col = 0; col < width; col++) {
      const idx = getIndex(row, col);

      ctx.fillStyle = cells[idx] === Cell.Dead
        ? DEAD_COLOR
        : ALIVE_COLOR;

      ctx.fillRect(
        col * (CELL_SIZE + 1) + 1,
        row * (CELL_SIZE + 1) + 1,
        CELL_SIZE,
        CELL_SIZE
      );
    }
  }

  ctx.stroke();
}

window.requestAnimationFrame(renderLoop);

3 compile and run

Execute in the wasm-game-of-life directory:

wasm-pack build

Compile rust code.

Execute in the wasm-game-of-life/www directory:

npm run start

Type in your browser:


127.0.0.1:8080

Guess you like

Origin blog.csdn.net/lcloveyou/article/details/123415974