4 ms·
I'm working on a web app in JS, the sort of thing I think people on here will enjoy and I'll definitely share it when it's presentable. It's all in JS, includin
by ayaros 2y ago
I'm working on a web app in JS, the sort of thing I think people on here will enjoy and I'll definitely share it when it's presentable. It's all in JS, including the graphical aspects of it (I'm drawing to a canvas). For per-pixel rendering I have 4 levels of nested loops. I feel like I've done everything in my power to optimize the process, and it's still not at the ideal speed. Really, it ought to be about 5-10 times faster than it is now.
I've been thinking of getting it into WASM somehow - it's really just one function that needs to be replaced by a WASM module - but one of the things which has given me pause are benchmarks like this, as well as other anecdotes, that demonstrate I'd only get a minor speedup from WASM. I guess part of this is due to modern JS engines being so optimized.
Just about all of the relevant code is adding and subtracting integers, but theres's some Boolean logic. There's also some multiplication in there that I could eliminate if I really had to, although at this point I'm not certain it would make a significant difference. Most of the data that contributes to the value of each pixel is spread across a tree of objects, and there's some polymorphism involved too. The point is it's not like I'm just dealing with a bunch of contiguous data in memory that is easily cached by the CPU, which might speed things up considerably. I guess I'm just venting now, lamenting a nightmare of my own creation...
- catapart 2y agoFor the record - I can't imagine any tangible value in writing a graphics engine (and form library) for an environment that was literally designed as a graphics engine for forms. But, that disclaimer aside, I've considered WASM for graphics for a game engine and I have had some trial success with allocating a shared array buffer, writing to it in WASM and reading from it at a js-friendly rate of 30-60 fps (whatever requestAnimationFrame is serving). The idea being that you treat the shared array buffer as your "screen" and write to it from the WASM as if it were an image buffer, while on the JS side you read it as an image buffer onto the canvas. Gives you a nice, finite, bandwidth and an easy to scale maximum for how much data you can pass through, and neither JS nor WASM ever has to pass any time-critical data. Of course, this setup leaves a very thin JS client - it's essentially just rendering the same image over and over. So if you've already got everything done in JS, it would mean porting all of your functional code over to something that can compile into WASM. Not a huge lift, but not fun either. And then, on the other hand, if it's just rendering you're seeing as a bottleneck, JS works pretty well with webGL and webGPU for simple form rendering. A little loop unrolling might be a lot easier than porting the rest of the app. Anyway, best of luck on it!
- lerp-io 2y agohave you done any benchmarks to compare wasm performance with js? i have been doing some benchmark test cases after a large refactor of my game engine written in typescript that is built entirely on top of shared buffer arrays (using ECS pattern or so it’s called i guess). i’m done benching for a while now and am ok with results but i have also compared my handcrafted quadtree sort/query algorithm with off the shelf rust implementation that matched the test requirements and saw only 30% gain and figured anything lower than that would not be worth the effort assuming rust compiled to wasm is same or slower and never bothered to test compiled wasm because i could not figure out how to share my buffer arrays with the rust code using wasm bindgen fast enough to bother spending more time on more benching lol
- refulgentis 2y agoI had a fun 2 years where I basically had 800 critical lines of math code that had to be on every platform, one version in the native language of the platform, and one version as performance optimal as possible. I was absolutely stunned to find that on web WASM ~= JS which altogether weren't far off from a naive C++ stdlib port. I had to make custom data structures instead of using stdlib ones to really get performance significantly different . IIRC my most optimized C++ converted to WASM was about 70% the speed of JS.
- catapart 2y agoNothing rigorous at all, no. I did do a lot of practical tests, as a way to compare what I had been doing to what was planned to be done, but I've found js is plenty performant for the types of CPU work I needed done, which is the big benefit of WASM. Since I've mostly focused on rendering, there's just not much that really should be done on the CPU side. But I do have plans to extend my renderer to have a CPU pipeline which doesn't rely on WebGPU or WebGL, and I imagine I'll be doing quite a bit of benchmarking there. Forcing the CPU to render is going to make js choke - it's just a matter of how much it takes. I imagine any forward rendering will be fine, but there's no chance it does path tracing worth a damn. So somewhere between "textures" and "realtime global illumination" I expect I might have a lot of data about what WASM can do to help in that arena (if anything; though I am expecting it to help quite a bit, especially with stuff like SIMD). On the other hand, entirely, I have been using the Rapier physics engine since it has a javascript version and as far as I know it heavily utilizes WASM for its physics calculations, so there might be some good benchmarking for WASM benefits surrounding that library.
- com2kid 2y agoDon't write every pixel by hand to the screen. At high resolutions that just won't work. No modern UI does that anymore, they all use acceleration of some type. I ran into this trap when I tried to write a simple canvas game engine. Just caching blobs of things that don't change frame to frame and got me a 5x-8x speedup, even if where I render those things at changes frame to frame.
- ayaros 2y agoTrust me, I learned this pretty quickly. Areas are only queued when the display has to chnage in some way. There's also a bunch of prepratation before drawing a region of the screen; only the objects that appear within the specified bounds are even considered.