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.
