Add buffer.readvector2/3/4 and buffer.writevector2/3/4 methods#198
Add buffer.readvector2/3/4 and buffer.writevector2/3/4 methods#198rbxphogen wants to merge 4 commits into
buffer.readvector2/3/4 and buffer.writevector2/3/4 methods#198Conversation
|
Would it be problematic for the proposed alternatives of As you mentioned, the alternative would help reduce API surface area and consume less fastcall slots (assuming these would be fastcalls, which they should be) in exchange for some performance (but certainly not so much that the feature becomes useless). This change in particular -- to take in a |
@ishtar112 the only reason I hesitate to do that is That said, I'm not strongly opposed, since it could make even-wider-vector-types easier to implement in the future. |
|
I feel like if this is going to be an RFC, it might as well be widened to include a method for reading/writing booleans to buffers using a u8. As that's in the same vein as this, although there's no major simd improvements to be made there. |
I think that makes more sense as a separate RFC – since 7 of the 8 bits would be unused when writing a boolean as a u8, packing might become a point of discussion. This proposal uses all available bits and provides additional simd opportunities; in my opinion, that warrants discussing its merits individually |
|
It would be nice if a number writing buffer library method like |
If your color values range local packed = vec.x + bit32.lshift(vec.y, 8) + bit32.lshift(vec.z, 16) + bit32.lshift(vec.w, 24)
buffer.writeu32(buf, 0, packed)Adding a If the maintainers agree to adding |
U32 is generally the better fit since bit32 operates on 32-bit integer ranges directly. local packed = bit32.bor(0b01,0b10) -- 0b11and then: buffer.writeu32(buff, offset, packed)So boolean packing already composes cleanly with existing primitives using:
Although I do think adding U24 could make sense for cases like RGB colors since it maps exactly to 3 bytes. |
I believe this can be done via buffer.writebits(buf, offset * 8, 24, packed) |
| - If `LUA_VECTOR_SIZE` is 4, the `w` component of the resulting vector is also zero. | ||
| - equivalent to `vector.create(buffer.readf32(buf, offset), buffer.readf32(buf, offset + 4), buffer.readf32(buf, offset + 8))` | ||
|
|
||
| When `LUA_VECTOR_SIZE` is defined to be `4`, two additional methods are defined: |
There was a problem hiding this comment.
I think it's best not to have an API that changes that drastically based on VM build options. Maybe the vector4 methods could be replaced with "native" width methods, as in readvector and writevector that deal in vectors of "native" width by reading or writing however many values that requires, i.e. 3 or 4.
This way, if the width is 4, you still have the option to access 3 or 2 values, and similarly, if the width is 3, you have the option to access just 2 values. Otherwise, if you don't care, you can just access the amount required to fill the vector, making all functions available regardless of configuration.
The only issue I foresee with this approach is that the Luau vector library doesn't expose a way to get the environment's vector width. This is an issue for cursors, which won't know how far to advance if you just write a native width vector.
There was a problem hiding this comment.
As a comparison point, the vector.create method only exposes a 4-argument version if 4-element vectors are enabled – so the proposed text is consistent with that precedent.
I considered a pared-down readvector/writevector method set, but what ultimately convinced me against it was portability & predictability:
buffer.writevector3(buf, 0, vec) -- always writes 12 bytes
-- buffer.writevector4(buf, 0, vec) -- if your VM doesn't support 4-element vectors, this is an errorvs.
buffer.writevector(buf, 0, vec) -- writes either 12 or 16 bytesYou pointed out
the Luau vector library doesn't expose a way to get the environment's vector width. This is an issue for cursors, which won't know how far to advance if you just write a native width vector.
But if vectors are serialized and reloaded across environments, the predictability problem becomes even stickier – i.e. it wouldn't be enough to query the vector-size of the recipient-VM, you'd need to query the vector-size of the sender-VM.
There was a problem hiding this comment.
I understand the vector.create precedent but the thing is that it is not an error to call a function with more arguments than its arity, while it is an error to call nil (in normal configurations).
It's pretty "dirty" in my opinion to use the presence of the readvector4 and writevector4 functions as a test to determine environment vector width, and I think it is in the scope of this RFC to add a vector.width value or function to query the environment, returning the information as a width number or even as a boolean isvector4 or such. This should also solve any serdes problems you foresee.
There was a problem hiding this comment.
I'm not opposed to adding a vector.width, I can include it in this proposal – I am not a fan of making readvector/writevector behave differently depending on that value, though, because it's a hidden decision point.
Querying vector.width helps you if the same environment is writing/reading to/from buffers, but if the writing environment differs from the reading environment, writers would need to additionally write the vector-width in order for readers to know whether they can use readvector as-is or handle it as a special case
There was a problem hiding this comment.
I don't see it as a hidden decision point, as the entire vector library already behaves in that way. I think forcing branches in all reader and writer code for something known at VM compile time and making the API less streamlined and consistent is a net negative. The ability to read and write without meta checks is pretty important, as this is a throughput-oriented API.
For readers with untrusted data, branching is unavoidable because you need to know what you're looking at and what tool you have, but I think if we can make it simpler and faster to read and write in the general case where you're dealing with trusted data it would be a lot better.
|
I like the suggestion provided by @ishtar112 of providing a
This allows the handling of unknown vector sizes from external sources, while providing a suitable default when working within the same VM. |
vegorov-rbx
left a comment
There was a problem hiding this comment.
We will not be accepting a proposal exposing vector.width from the define configuration variable.
It exposes an implementation detail that is made for some embedders, but should not be a part of the library API.
What about it leaking in other ways, such as via the presence of a function or by a catchable error from a function with a width argument? |
|
The whole mistake of introducing LUA_VECTOR_SIZE will have bad consequences for years into the future, so we can only minimize the effects (in some way, we are years in the future from that mistake and now dealing with it here). Users are free to find roundabout ways of detecting it (you can check a read of |
I guess that settles it then, I think an API that doesn't accommodate a vector width of 4 is fine. |
@vegorov-rbx if I remove |
This reverts commit aa1fa7d.
Rendered.