google / vector_math.dart

A vector math package for 2D and 3D applications
https://pub.dev/packages/vector_math
Other
314 stars 78 forks source link

32 and 64 bit type casting and performance implications #210

Open aab29 opened 5 years ago

aab29 commented 5 years ago

First of all, thank you to everyone who has contributed to this excellent library! 🙌 My brother @ikebart and I created the bezier.dart package, based on Pomax's Bezier.js. You can see our example page here; perhaps you'll spot some similarities. 😅 Anyway, bezier.dart relies heavily on vector_math, and we're big fans of its design. So... thanks for the cool code! 🥂

For the past few... years, my brother and I have been working on our own game engine, running primarily in the Dart VM but bound to C++ for the low-level stuff like rendering. 👾 For the most part this architecture has worked great, but we've hit a fair number of bottlenecks associated with vectors, and I'm wondering if anyone out there has suggestions or strategies for dealing with them. 🚫 🐢

Since we're using vector_math (not vector_math_64), My guess is that these slowdowns stem from casting back and forth between Dart's 64-bit double type and the 32-bit typed data lists that vector_math uses. I'd imagine that each time you perform any operation on a component of a vector, the VM has to cast that component to 64-bit to do the operation... and that any double that gets assigned to a component of a vector must be cast back to 32-bit. 🎣 If that's true, even trivial operations could get pretty expensive. 💸

The obvious solution would seem to be "just switch to vector_math_64," right? Well... I'd like to, but as far as I can tell the graphics/shader libraries (and hardware) we're interfacing with only accept 32-bit floating point numbers. 😕

So far we've been dealing with it by porting any heavy vector calculations into C++, and I suppose we can continue to do that. But I figured I should check to see if anyone has encountered similar issues. Surely this kind of bottleneck also pops up when dealing with stuff like WebGL? Or maybe in Flutter? 🦋 Is my understanding of the underlying problem correct? Are there any techniques to mitigate it I might not have considered? A huge thanks to anyone who takes the time to read this or share their experience. ⏳ 🙇

johnmccutchan commented 1 year ago

I believe that the Dart VM can avoid unnecessary double-to-float conversions. Maybe @mraleph can confirm?

mraleph commented 1 year ago

We don't have such an optimisation, though we did consider adding it long ago (but never go to it). It is relatively straightforward to add though (Flutter does not use 32-bit backed vector math, but maybe they should be?).

The only problem here is that this optimisation applies only to the pattern f64->f32(op.f64(f32->f64(a), f32->f64(a))) which can be converted to op.f32(a, b) - i.e. you need to covert to 32-bit after each binary operation. And that means some operations in vector_math_32 need to be rewritten to match this style - otherwise they will not benefit from the optimization. To make things worse Dart does not actually have an explicit f64->f32 operation exposes on double, the best you could do is to store into a Float32List and load back.