The basic idea is that a pointer is returned and then an image will be displayed using the pointer after creating a Vec
at each video frame:
JavaScript:
var ptr = exports.alloc(size);
let bytes = new Uint8ClampedArray(exports.memory.buffer, ptr, size);
let image = new ImageData(bytes, 320, 240);
function tick() {
requestAnimationFrame(tick);
ctx.drawImage(video, 0, 0, width, height);
let imageData = ctx.getImageData(0, 0, width, height).data;
bytes.set(imageData);
exports.create_vector();
ctx.putImageData(img, 0, 0);
}
Rust:
#[no_mangle]
pub extern "C" fn alloc(capacity: usize) -> *mut c_void {
let mut buf = Vec::with_capacity(capacity);
let ptr = buf.as_mut_ptr();
mem::forget(buf);
return ptr as *mut c_void;
}
#[no_mangle]
pub extern "C" fn create_vector() {
let _: Vec<u8> = Vec::with_capacity(320 * 240);
}
Here are the error messages:
Chrome:
Uncaught TypeError: Cannot perform %TypedArray%.prototype.set on a detached ArrayBuffer
at Uint8ClampedArray.set (<anonymous>)
at tick
Safari:
This webpage was reloaded because a problem occurred
Mozilla:
DOMException: "An attempt was made to use an object that is not, or is no longer, usable"
TypeError: Underlying ArrayBuffer has been detached from the view
The main culprits seem to be:
let bytes = new Uint8ClampedArray(exports.memory.buffer, ptr, size);
// ...
exports.create_vector();
// ...
i.e., the browser crashes when I try to use ptr
again after calling exports.create_vector
.
What is going wrong here? Is there a solution?
When you allocate a new buffer and there is not enough memory allocated by the WASM "process" for it, the browser will allocate a new, larger buffer and will copy all data into it from the old location. It's quite transparent inside the WASM interpreter, but all pointers passed to JavaScript (with which you construct Uint8ClampedArray
) get invalidated. There are two solutions to my knowledge: