This is a question, not an issue
Sorry for asking you here, but I'm trying to understand your code.
function filter(imageData) {
const bufferPointerIn = 1024,
{data, width, height} = imageData,
bufferIn = new Uint8Array(wasmModule.memory.buffer, bufferPointerIn, width * height * 4),
bufferPointerOut = 2048 + width * height * 4,
bufferOut = new Uint8Array(wasmModule.memory.buffer, bufferPointerOut, width * height * 4);
bufferIn.set(data);
wasmModule.outline_c(bufferPointerIn, bufferPointerOut, width, height);
data.set(bufferOut);
return data;
}
I just wonder how bufferPointerIn and bufferPointerOut work? In the C code, they areunsigned char* buffer_in and unsigned char* buffer_out. How can we use two byteOffset as pointers? I am looking forward for you answer. Danke sehr!
I'll try to explain it. Please let me know if anything is still unclear.
There are two ways to pass data from JS to wasm and from wasm to JS:
- via parameters and return values
- by reading and writing the wasm memory buffer.
You can see an example for 1. with the function call of wasmModule.outline_c(). Four parameters are pased in: The two buffer pointers as well as width and height. The problem is, when we're working with the raw wasm API only numbers can be passed in and out directly! Pointers are basically just numbers as well.
So to pass in the image data and get the filtered image back we need to use the second way: By reading and writing the wasm memory buffer directly. To access the wasm memory the WasmModule has a special export called memory, an instance of WebAssembly.Memory. The buffer property is a, well, buffer that can be passed to typed arrays so it can be written and read. The access is similar to a normal JS array via indices. That's exactly what happens in the two lines that define bufferIn and bufferOut - we get byte-wise access to the wasm module's memory.
Before we call outline_c() we copy the source image data to the bufferIn buffer by calling its set method:
bufferIn.set(data);
You may wonder where the 1024 and the 2048 come from. Maybe you noticed the unused buffer variable in line 11 of filter.c? This is just there so the compiler will allocate enough memory for the wasm module for six images (640 and 480 is width resp. height of the image, 4 is the number of bytes for each pixel and 6 is the number of images that would fit in that buffer). The problem is, that I don't know how to dynamically allocate more memory for the wasm module so I used this dirty hack to increase the memory so at least the input and the output buffer can fit in.
The 1024 is just a random number that (hopefully) points somewhere into the memory the buffer variable points to. The 2048 is another one of those random numbers. I add the size of one image on top of that to make sure that the output buffer does not intersect with the input buffer.
Apparently some follow up questions were deleted. In case someone else stumbles onto this issue and has the same questions, I'll paraphrase and try to answer them:
How can I call the
outline_cfunction withcwrap?
This is not an emcc project, this uses the clang compiler directly, without the emcc patches/runtime library, so there is no cwrap available. You can try to compile this code with emcc and possibly succeed (I haven't tested it) but then it should be possible to use cwrap as it is documented in the emcc docs.
It still works fine when I change both pointers to
0.
This should not work without changing the behaviour of the code. The outline_kernel is also a global variable and might be placed in the beginning of the wasm module's memory buffer. By setting the input buffer to 0, this kernel is overwritten and the results should change. If both pointers are set to 0, the output image will overwrite the input image, while it is still used.
The pointers are not really C pointers but indices into the wasm module's memory buffer.
They are both :) C pointers are actually just integer values with some special arithmetic rules. From the C module's perspective, the memory begins with the memory buffer. So the first index is equal to the null pointer. If you wrap the wasm module's memory buffer into a Uint8Array, every index corresponds exactly to a C pointer pointing to the appropriate byte. If you wrap the memory buffer into a Uint16Array, every index into this array can only point to every other byte in the C module's memory.