GPU: Math: Add floatBitsToOrderedInt and orderedIntBitsToFloat

These allow the usage of `atomicMin` and `atomicMax` function with float
values as there is no overload for these types in GLSL.

This also allows signed 0 preservation.
This commit is contained in:
Clément Foucault 2023-01-16 00:39:47 +01:00
parent 945d108ab8
commit 28db19433e
2 changed files with 34 additions and 0 deletions

View File

@ -93,4 +93,23 @@ uvec4 unpackUvec4x8(uint data)
return (uvec4(data) >> uvec4(0u, 8u, 16u, 24u)) & uvec4(0xFFu);
}
/**
* Convert from float representation to ordered int allowing min/max atomic operation.
* Based on: https://stackoverflow.com/a/31010352
*/
int floatBitsToOrderedInt(float value)
{
/* Floats can be sorted using their bits interpreted as integers for positive values.
* Negative values do not follow int's two's complement ordering which is reversed.
* So we have to XOR all bits except the sign bits in order to reverse the ordering.
* Note that this is highly hardware dependent, but there seems to be no case of GPU where the
* ints ares not two's complement. */
int int_value = floatBitsToInt(value);
return (int_value < 0) ? (int_value ^ 0x7FFFFFFF) : int_value;
}
float orderedIntBitsToFloat(int int_value)
{
return intBitsToFloat((int_value < 0) ? (int_value ^ 0x7FFFFFFF) : int_value);
}
#endif /* GPU_SHADER_UTILDEFINES_GLSL */

View File

@ -287,4 +287,19 @@ void main()
vec4(0.0f, 0.0f, -1.0f, 1.0f)));
EXPECT_NEAR(pers2, expect, 1e-4);
}
TEST(math_matrix, OrderedInt)
{
/* Identity. */
EXPECT_EQ(orderedIntBitsToFloat(floatBitsToOrderedInt(0.5)), 0.5);
EXPECT_EQ(orderedIntBitsToFloat(floatBitsToOrderedInt(-0.5)), -0.5);
EXPECT_EQ(orderedIntBitsToFloat(floatBitsToOrderedInt(0.0)), 0.0);
EXPECT_EQ(orderedIntBitsToFloat(floatBitsToOrderedInt(-0.0)), -0.0);
EXPECT_GE(floatBitsToOrderedInt(-0.5), floatBitsToOrderedInt(-1.0));
EXPECT_LE(floatBitsToOrderedInt(0.5), floatBitsToOrderedInt(1.0));
EXPECT_LE(floatBitsToOrderedInt(-0.5), floatBitsToOrderedInt(1.0));
EXPECT_GE(floatBitsToOrderedInt(0.5), floatBitsToOrderedInt(-1.0));
EXPECT_LE(floatBitsToOrderedInt(-0.0), floatBitsToOrderedInt(0.0));
}
}