问题
I'm a total beginner to Rust and WebAssembly. I was trying to find a way to draw on a canvas
element with performance in mind.
To draw on a canvas
using Rust and WebAssembly I usually find examples in which they would use the browser's CanvasRenderingContext2D
interface and draw data on it they will receive from WASM
const canvasContext = canvasElement.getContext("2d");
const canvasImageData = canvasContext.createImageData(width, height);
const imageDataArray = getWasmImageDataArray()
canvasImageData.data.set(imageDataArray);
canvasContext.clearRect(0, 0, width, height);
canvasContext.putImageData(canvasImageData, 0, 0);
Source: https://wasmbyexample.dev/examples/reading-and-writing-graphics/reading-and-writing-graphics.rust.en-us.html
There are variations of this where they would bind the canvas
API to Rust and perform the operations in Rust / WebAssembly, but nonetheless, they would always use the CanvasRenderingContext2D
API to draw on the canvas.
This of course means there is a roundtrip from Rust / WebAssembly over the Browser's canvas
API into the canvas display buffer, which means a drop in performance.
I am wondering if there is another way: Is it possible to bind the buffer for the pixels that the canvas displays directly to Rust and directly manipulate that buffer to change what the canvas shows? Sort of like this (pseudocode)
Rust
Pseudocode:
// Makes whole canvas black
drawOnCanvasDisplayBuffer(displayBuffer) {
for(i = 0; i < displayBuffer.width; i++) {
for(j = 0; j < displayBuffer.height; j++) {
displayBuffer[i][j] = COLOR_BLACK
}
}
}
回答1:
WebAssembly has very limited I/O capabilities. The only way it can interact with its host environment (typically the browser) is directly via imported / exported functions or indirectly by linear memory.
The example you cite has a WebAssembly module where its linear memory is shared with the host allowing it to be read and written to by both the WebAssembly module and the JavaScript host. This is an ideal approach for creating an image buffer for canvas operations.
I am wondering if there is another way: Is it possible to bind the buffer for the pixels that the canvas displays directly to Rust and directly manipulate that buffer to change what the canvas shows?
No, it is not. The shared memory instance must be of type WebAssembly.Memory, it cannot be any arbitrary buffer.
Note, in your example code, the clearRect
operation isn't needed:
canvasContext.clearRect(0, 0, width, height); // ***
canvasContext.putImageData(canvasImageData, 0, 0)
来源:https://stackoverflow.com/questions/60141924/manipulate-canvas-bytes-directly-from-webassembly