Your numbers do not make sense.

At 300 us a frame, it would be more than 3k frames a second - which would only 
be possible for an extremely tiny area.

You need to include the time to produce the data when considering “render time” 
- otherwise you are talking apples and oranges.

> On Nov 7, 2023, at 9:43 PM, Kai O'Reilly <[email protected]> wrote:
> 
> For future reference for anyone who comes across this thread, you can 
> directly pass RGBA image data to a canvas, which is around 200 times faster 
> than encoding it to a PNG and rendering it to an offscreen image. Also, 
> passing the unsafe pointer to the slice to JavaScript instead of copying the 
> bytes improves performance by another factor of 5. These two changes combined 
> reduced the render time for me from roughly 300 milliseconds to 300 
> microseconds (a 1000x improvement). This performance is enough to run an 
> interactive pure Go GUI through WASM without any noticeable lag, just by 
> writing images to a canvas.
> 
> This is the relevant Go code:
> 
> ```go
>  sz := dw.image.Bounds().Size()
> ptr := uintptr(unsafe.Pointer(&dw.image.Pix[0]))
> js.Global().Call("displayImage", ptr, len(dw.image.Pix), sz.X, sz.Y)
> ```
> 
> And this is the relevant JS code:
> 
> ```js
> const appCanvas = document.getElementById('app');
> const appCanvasCtx = appCanvas.getContext('2d');
> 
> let wasm;
> let memoryBytes;
> 
> // displayImage takes the pointer to the target image in the wasm linear 
> memory
> // and its length. Then, it gets the resulting byte slice and creates an 
> image data
> // with the given width and height.
> function displayImage(pointer, length, w, h) {
>   // if it doesn't exist or is detached, we have to make it
>   if (!memoryBytes || memoryBytes.byteLength === 0) {
>     memoryBytes = new Uint8ClampedArray(wasm.instance.exports.mem.buffer);
>   }
> 
>   // using subarray instead of slice gives a 5x performance improvement due 
> to no copying
>   let bytes = memoryBytes.subarray(pointer, pointer + length);
>   let data = new ImageData(bytes, w, h);
>   appCanvasCtx.putImageData(data, 0, 0);
> }
> ```
> In the JS code, `wasm` is initialized as the result of 
> `WebAssembly.instantiateStreaming`.
> 
> On Friday, July 24, 2020 at 10:53:14 AM UTC-7 Mark Farnan wrote:
> Little old, but this might also help. 
> 
>  A while back I built a helper package to deal with these issues for canvas 
> rendering from Go.  
> 
> https://github.com/markfarnan/go-canvas 
> <https://github.com/markfarnan/go-canvas>  
> 
> I'm currently working on it to add  WebGL support & get it working in TinyGo 
> (some issues still).
> 
> Regards
> 
> Mark.
> 
> 
> 
> On Sunday, 22 March 2020 at 09:08:40 UTC+1 Scott Pakin wrote:
> I figure I ought to follow up with some results.  First, I got the suggested 
> approach of local render + js.CopyBytesToJS 
> <https://golang.org/pkg/syscall/js/#CopyBytesToJS> + update canvas from image 
> to work, so thanks, Agniva and Howard!  Second, for the benefit of future 
> readers of this thread, one thing that wasn't obvious to me is that one needs 
> to render the image data in a browser-recognizable image format—I used PNG 
> <https://en.wikipedia.org/wiki/Portable_Network_Graphics>—not raw {red, 
> green, blue, alpha} bytes as is needed when writing directly to a canvas 
> <https://www.w3schools.com/tags/tag_canvas.asp>'s image data.  Third, I used 
> JavaScript code like the following to update an invisible img 
> <https://www.w3schools.com/tags/tag_img.asp> then copy the image data from 
> there to a visible canvas:
> 
> function copyBytesToCanvas(data) {
>     let blob = new Blob([data], {"type": "image/png"});
>     let img = document.getElementById("myImage");
>     img.onload = function() {
>         let canvas = document.getElementById("myCanvas");
>         let ctx = canvas.getContext("2d");
>         ctx.drawImage(this, 0, 0);
>     };
>     img.src = URL.createObjectURL(blob);
> }
> 
> Fourth, the performance is indeed substantially faster than my previous 
> approach based on using SetIndex 
> <https://golang.org/pkg/syscall/js/#Value.SetIndex> to write directly to the 
> canvas, even though the new approach requires the extra steps of encoding the 
> image in PNG format and copying the image data from an img to a canvas.  The 
> following performance data, measured with Go 1.14 and Chromium 80.0.3987.132 
> on an Ubuntu Linux system, is averaged over 10 runs:
> 
> Old: 686.9 ± 7.6 ms
> New: 290.4 ± 4.1 ms (284.3 ± 4.2 on the WebAssembly side plus 6.0 ± 2.3 on 
> the JavaScript side)
> 
> This is the time to render a simple 800×800 gradient pattern.
> 
> I hope others find this useful.
> 
> — Scott
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected] 
> <mailto:[email protected]>.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/golang-nuts/267bc2d7-1e7a-4704-98cd-3c471fa0d19dn%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/golang-nuts/267bc2d7-1e7a-4704-98cd-3c471fa0d19dn%40googlegroups.com?utm_medium=email&utm_source=footer>.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/16CAE5D4-5F35-46C7-8F51-38FA807097D8%40ix.netcom.com.

Reply via email to