Skip to content

Commit

Permalink
Version of UVec4::sSort4True that is faster (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrouwe committed Feb 5, 2022
1 parent 44ea7aa commit 0e3f28e
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 146 deletions.
7 changes: 4 additions & 3 deletions Jolt/Math/UVec4.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,10 @@ class [[nodiscard]] UVec4
/// Logical not (component wise)
static JPH_INLINE UVec4 sNot(UVec4Arg inV1);

/// Sorts 4 elements so that the True values go first (highest bit set), sorts ioIndex at the same time.
/// Based on a sorting network: http://en.wikipedia.org/wiki/Sorting_network
static JPH_INLINE void sSort4True(UVec4 &ioValue, UVec4 &ioIndex);
/// Sorts the elements in inIndex so that the values that correspond to trues in inValue are the first elements.
/// The remaining elements will be set to inValue.w.
/// I.e. if inValue = (true, false, true, false) and inIndex = (1, 2, 3, 4) the function returns (1, 3, 4, 4).
static JPH_INLINE UVec4 sSort4True(UVec4Arg inValue, UVec4Arg inIndex);

/// Get individual components
#if defined(JPH_USE_SSE)
Expand Down
37 changes: 8 additions & 29 deletions Jolt/Math/UVec4.inl
Original file line number Diff line number Diff line change
Expand Up @@ -192,39 +192,18 @@ UVec4 UVec4::sNot(UVec4Arg inV1)
#endif
}

void UVec4::sSort4True(UVec4 &ioValue, UVec4 &ioIndex)
UVec4 UVec4::sSort4True(UVec4Arg inValue, UVec4Arg inIndex)
{
// We didn't expose the less operator on UVec4 since X64 doesn't offer an unsigned one, we're comparing true and false here so we know that we only have 2 values
#if defined(JPH_USE_SSE)
#define S4T_COMPARE _mm_cmplt_epi32
#elif defined(JPH_USE_NEON)
#define S4T_COMPARE vcltq_s32
#else
#error Unsupported CPU architecture
#endif

// Pass 1, test 1st vs 3rd, 2nd vs 4th
UVec4 v1 = ioValue.Swizzle<SWIZZLE_Z, SWIZZLE_W, SWIZZLE_X, SWIZZLE_Y>();
UVec4 i1 = ioIndex.Swizzle<SWIZZLE_Z, SWIZZLE_W, SWIZZLE_X, SWIZZLE_Y>();
UVec4 c1 = UVec4(S4T_COMPARE(ioValue.mValue, v1.mValue)).Swizzle<SWIZZLE_Z, SWIZZLE_W, SWIZZLE_Z, SWIZZLE_W>();
ioValue = sSelect(ioValue, v1, c1);
ioIndex = sSelect(ioIndex, i1, c1);
// If inValue.z is false then shift W to Z
UVec4 v = UVec4::sSelect(inIndex.Swizzle<SWIZZLE_X, SWIZZLE_Y, SWIZZLE_W, SWIZZLE_W>(), inIndex, inValue.SplatZ());

// Pass 2, test 1st vs 2nd, 3rd vs 4th
UVec4 v2 = ioValue.Swizzle<SWIZZLE_Y, SWIZZLE_X, SWIZZLE_W, SWIZZLE_Z>();
UVec4 i2 = ioIndex.Swizzle<SWIZZLE_Y, SWIZZLE_X, SWIZZLE_W, SWIZZLE_Z>();
UVec4 c2 = UVec4(S4T_COMPARE(ioValue.mValue, v2.mValue)).Swizzle<SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_W, SWIZZLE_W>();
ioValue = sSelect(ioValue, v2, c2);
ioIndex = sSelect(ioIndex, i2, c2);
// If inValue.y is false then shift Z and further to Y and further
v = UVec4::sSelect(v.Swizzle<SWIZZLE_X, SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W>(), v, inValue.SplatY());

// Pass 3, test 2nd vs 3rd component
UVec4 v3 = ioValue.Swizzle<SWIZZLE_X, SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_W>();
UVec4 i3 = ioIndex.Swizzle<SWIZZLE_X, SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_W>();
UVec4 c3 = UVec4(S4T_COMPARE(ioValue.mValue, v3.mValue)).Swizzle<SWIZZLE_X, SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_W>();
ioValue = sSelect(ioValue, v3, c3);
ioIndex = sSelect(ioIndex, i3, c3);
// If inValue.x is false then shift X and furhter to Y and furhter
v = UVec4::sSelect(v.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W>(), v, inValue.SplatX());

#undef S4T_COMPARE
return v;
}

UVec4 UVec4::operator * (UVec4Arg inV2) const
Expand Down
46 changes: 5 additions & 41 deletions Jolt/Physics/Collision/BroadPhase/QuadTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1123,16 +1123,7 @@ void QuadTree::CollideAABox(const AABox &inBox, CollideShapeBodyCollector &ioCol
{
// Test the box vs 4 boxes
UVec4 hitting = AABox4VsBox(mBox, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);

// Count how many results are hitting
int num_results = hitting.CountTrues();
if (num_results > 0)
{
// Sort trues first
UVec4::sSort4True(hitting, ioChildNodeIDs);
}

return num_results;
return CountAndSortTrues(hitting, ioChildNodeIDs);
}

/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
Expand Down Expand Up @@ -1183,16 +1174,7 @@ void QuadTree::CollideSphere(Vec3Arg inCenter, float inRadius, CollideShapeBodyC
{
// Test 4 boxes vs sphere
UVec4 hitting = AABox4VsSphere(mCenterX, mCenterY, mCenterZ, mRadiusSq, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);

// Count how many results are hitting
int num_results = hitting.CountTrues();
if (num_results > 0)
{
// Sort trues first
UVec4::sSort4True(hitting, ioChildNodeIDs);
}

return num_results;
return CountAndSortTrues(hitting, ioChildNodeIDs);
}

/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
Expand Down Expand Up @@ -1243,16 +1225,7 @@ void QuadTree::CollidePoint(Vec3Arg inPoint, CollideShapeBodyCollector &ioCollec
{
// Test if point overlaps with box
UVec4 hitting = AABox4VsPoint(mPoint, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);

// Count how many results are hitting
int num_results = hitting.CountTrues();
if (num_results > 0)
{
// Sort trues first
UVec4::sSort4True(hitting, ioChildNodeIDs);
}

return num_results;
return CountAndSortTrues(hitting, ioChildNodeIDs);
}

/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
Expand Down Expand Up @@ -1300,16 +1273,7 @@ void QuadTree::CollideOrientedBox(const OrientedBox &inBox, CollideShapeBodyColl
{
// Test if point overlaps with box
UVec4 hitting = AABox4VsBox(mBox, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);

// Count how many results are hitting
int num_results = hitting.CountTrues();
if (num_results > 0)
{
// Sort trues first
UVec4::sSort4True(hitting, ioChildNodeIDs);
}

return num_results;
return CountAndSortTrues(hitting, ioChildNodeIDs);
}

/// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
Expand Down Expand Up @@ -1463,7 +1427,7 @@ void QuadTree::FindCollidingPairs(const BodyVector &inBodies, const BodyID *inAc
UVec4 child_ids = UVec4::sLoadInt4Aligned((const uint32 *)&node.mChildNodeID[0]);

// Sort so that overlaps are first
UVec4::sSort4True(overlap, child_ids);
child_ids = UVec4::sSort4True(overlap, child_ids);

// Push them onto the stack
if (top + 4 < cStackSize)
Expand Down
24 changes: 4 additions & 20 deletions Jolt/Physics/Collision/Shape/HeightFieldShape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -988,8 +988,7 @@ void HeightFieldShape::Draw(DebugRenderer *inRenderer, Mat44Arg inCenterOfMassTr
JPH_INLINE int VisitRangeBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, [[maybe_unused]] int inStackTop) const
{
UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
UVec4::sSort4True(valid, ioProperties);
return valid.CountTrues();
return CountAndSortTrues(valid, ioProperties);
}

JPH_INLINE void VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2) const
Expand Down Expand Up @@ -1665,12 +1664,7 @@ struct HeightFieldShape::HSGetTrianglesContext

// Test which nodes collide
UVec4 collides = AABox4VsBox(mLocalBox, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);

// Sort so the colliding ones go first
UVec4::sSort4True(collides, ioProperties);

// Return number of hits
return collides.CountTrues();
return CountAndSortTrues(collides, ioProperties);
}

void VisitTriangle(uint inX, uint inY, [[maybe_unused]] uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
Expand Down Expand Up @@ -1781,12 +1775,7 @@ void HeightFieldShape::sCollideConvexVsHeightField(const Shape *inShape1, const

// Test which nodes collide
UVec4 collides = AABox4VsBox(mBoundsOf1InSpaceOf2, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);

// Sort so the colliding ones go first
UVec4::sSort4True(collides, ioProperties);

// Return number of hits
return collides.CountTrues();
return CountAndSortTrues(collides, ioProperties);
}

JPH_INLINE void VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
Expand Down Expand Up @@ -1842,12 +1831,7 @@ void HeightFieldShape::sCollideSphereVsHeightField(const Shape *inShape1, const

// Test which nodes collide
UVec4 collides = AABox4VsSphere(mSphereCenterIn2, mRadiusPlusMaxSeparationSq, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);

// Sort so the colliding ones go first
UVec4::sSort4True(collides, ioProperties);

// Return number of hits
return collides.CountTrues();
return CountAndSortTrues(collides, ioProperties);
}

JPH_INLINE void VisitTriangle(uint inX, uint inY, uint inTriangle, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
Expand Down
30 changes: 6 additions & 24 deletions Jolt/Physics/Collision/Shape/MeshShape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,7 @@ void MeshShape::Draw(DebugRenderer *inRenderer, Mat44Arg inCenterOfMassTransform
JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
{
UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
UVec4::sSort4True(valid, ioProperties);
return valid.CountTrues();
return CountAndSortTrues(valid, ioProperties);
}

JPH_INLINE void VisitTriangles(const TriangleCodec::DecodingContext &ioContext, Vec3Arg inRootBoundsMin, Vec3Arg inRootBoundsMax, const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID)
Expand Down Expand Up @@ -549,8 +548,7 @@ void MeshShape::Draw(DebugRenderer *inRenderer, Mat44Arg inCenterOfMassTransform
JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioProperties, int inStackTop)
{
UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
UVec4::sSort4True(valid, ioProperties);
return valid.CountTrues();
return CountAndSortTrues(valid, ioProperties);
}

JPH_INLINE void VisitTriangles(const TriangleCodec::DecodingContext &ioContext, Vec3Arg inRootBoundsMin, Vec3Arg inRootBoundsMax, const void *inTriangles, int inNumTriangles, uint32 inTriangleBlockID)
Expand Down Expand Up @@ -890,12 +888,7 @@ struct MeshShape::MSGetTrianglesContext

// Test which nodes collide
UVec4 collides = AABox4VsBox(mLocalBox, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);

// Sort so the colliding ones go first
UVec4::sSort4True(collides, ioProperties);

// Return number of hits
return collides.CountTrues();
return CountAndSortTrues(collides, ioProperties);
}

JPH_INLINE void VisitTriangles(const TriangleCodec::DecodingContext &ioContext, Vec3Arg inRootBoundsMin, Vec3Arg inRootBoundsMax, const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID)
Expand Down Expand Up @@ -1032,12 +1025,7 @@ void MeshShape::sCollideConvexVsMesh(const Shape *inShape1, const Shape *inShape

// Test which nodes collide
UVec4 collides = AABox4VsBox(mBoundsOf1InSpaceOf2, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);

// Sort so the colliding ones go first
UVec4::sSort4True(collides, ioProperties);

// Return number of hits
return collides.CountTrues();
return CountAndSortTrues(collides, ioProperties);
}

JPH_INLINE void VisitTriangle(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, uint8 inActiveEdges, SubShapeID inSubShapeID2)
Expand Down Expand Up @@ -1082,12 +1070,7 @@ void MeshShape::sCollideSphereVsMesh(const Shape *inShape1, const Shape *inShape

// Test which nodes collide
UVec4 collides = AABox4VsSphere(mSphereCenterIn2, mRadiusPlusMaxSeparationSq, bounds_min_x, bounds_min_y, bounds_min_z, bounds_max_x, bounds_max_y, bounds_max_z);

// Sort so the colliding ones go first
UVec4::sSort4True(collides, ioProperties);

// Return number of hits
return collides.CountTrues();
return CountAndSortTrues(collides, ioProperties);
}

JPH_INLINE void VisitTriangle(Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2, uint8 inActiveEdges, SubShapeID inSubShapeID2)
Expand Down Expand Up @@ -1143,8 +1126,7 @@ Shape::Stats MeshShape::GetStats() const
{
// Visit all valid children
UVec4 valid = UVec4::sOr(UVec4::sOr(Vec4::sLess(inBoundsMinX, inBoundsMaxX), Vec4::sLess(inBoundsMinY, inBoundsMaxY)), Vec4::sLess(inBoundsMinZ, inBoundsMaxZ));
UVec4::sSort4True(valid, ioProperties);
return valid.CountTrues();
return CountAndSortTrues(valid, ioProperties);
}

JPH_INLINE void VisitTriangles([[maybe_unused]] const TriangleCodec::DecodingContext &ioContext, [[maybe_unused]] Vec3Arg inRootBoundsMin, [[maybe_unused]] Vec3Arg inRootBoundsMax, [[maybe_unused]] const void *inTriangles, int inNumTriangles, [[maybe_unused]] uint32 inTriangleBlockID)
Expand Down
28 changes: 4 additions & 24 deletions Jolt/Physics/Collision/Shape/StaticCompoundShape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include <Physics/Collision/Shape/StaticCompoundShape.h>
#include <Physics/Collision/Shape/RotatedTranslatedShape.h>
#include <Physics/Collision/Shape/CompoundShapeVisitors.h>
#include <Physics/Collision/SortReverseAndStore.h>
#include <Core/Profiler.h>
#include <Core/StreamIn.h>
#include <Core/StreamOut.h>
Expand Down Expand Up @@ -482,11 +481,7 @@ void StaticCompoundShape::CollidePoint(Vec3Arg inPoint, const SubShapeIDCreator
{
// Test if point overlaps with box
UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);

// Sort so the colliding ones go first
UVec4::sSort4True(collides, ioProperties);

return collides.CountTrues();
return CountAndSortTrues(collides, ioProperties);
}
};

Expand Down Expand Up @@ -543,12 +538,7 @@ void StaticCompoundShape::CollectTransformedShapes(const AABox &inBox, Vec3Arg i
{
// Test which nodes collide
UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);

// Sort so the colliding ones go first
UVec4::sSort4True(collides, ioProperties);

// Return number of hits
return collides.CountTrues();
return CountAndSortTrues(collides, ioProperties);
}
};

Expand Down Expand Up @@ -594,12 +584,7 @@ void StaticCompoundShape::sCollideCompoundVsShape(const Shape *inShape1, const S
{
// Test which nodes collide
UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);

// Sort so the colliding ones go first
UVec4::sSort4True(collides, ioProperties);

// Return number of hits
return collides.CountTrues();
return CountAndSortTrues(collides, ioProperties);
}
};

Expand All @@ -624,12 +609,7 @@ void StaticCompoundShape::sCollideShapeVsCompound(const Shape *inShape1, const S
{
// Test which nodes collide
UVec4 collides = TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);

// Sort so the colliding ones go first
UVec4::sSort4True(collides, ioProperties);

// Return number of hits
return collides.CountTrues();
return CountAndSortTrues(collides, ioProperties);
}
};

Expand Down
7 changes: 2 additions & 5 deletions Jolt/Physics/Collision/Shape/StaticCompoundShape.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include <Physics/Collision/Shape/CompoundShape.h>
#include <Physics/Collision/SortReverseAndStore.h>
#include <Math/HalfFloat.h>

namespace JPH {
Expand Down Expand Up @@ -79,11 +80,7 @@ class StaticCompoundShape final : public CompoundShape
{
// Test if point overlaps with box
UVec4 collides = GetIntersectingSubShapesVisitor<BoxType>::TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);

// Sort so the colliding ones go first
UVec4::sSort4True(collides, ioProperties);

return collides.CountTrues();
return CountAndSortTrues(collides, ioProperties);
}
};

Expand Down
13 changes: 13 additions & 0 deletions Jolt/Physics/Collision/SortReverseAndStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,17 @@ JPH_INLINE int SortReverseAndStore(Vec4Arg inValues, float inMaxValue, UVec4 &io
return num_results;
}

/// Shift the elements so that the identifiers that correspond with the trues in inValue come first
/// @param inValue Values to test for true or false
/// @param ioIdentifiers the identifiers that are shifted, on return they are shifted
/// @return The number of trues
JPH_INLINE int CountAndSortTrues(UVec4Arg inValue, UVec4 &ioIdentifiers)
{
// Sort the hits
ioIdentifiers = UVec4::sSort4True(inValue, ioIdentifiers);

// Return the amount of hits
return inValue.CountTrues();
}

} // JPH
20 changes: 20 additions & 0 deletions UnitTests/Math/UVec4Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,4 +450,24 @@ TEST_SUITE("UVec4Tests")
CHECK(v.ShiftComponents4Minus(1) == UVec4(4, 0, 0, 0));
CHECK(v.ShiftComponents4Minus(0) == UVec4(0, 0, 0, 0));
}

TEST_CASE("TestUVec4Sort4True")
{
CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(4, 4, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0x00000000U, 0x00000000U, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(1, 4, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0xffffffffU, 0x00000000U, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(2, 4, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0xffffffffU, 0x00000000U, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(1, 2, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0x00000000U, 0xffffffffU, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(3, 4, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0x00000000U, 0xffffffffU, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(1, 3, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0xffffffffU, 0xffffffffU, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(2, 3, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0xffffffffU, 0xffffffffU, 0x00000000U), UVec4(1, 2, 3, 4)) == UVec4(1, 2, 3, 4));
CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0x00000000U, 0x00000000U, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(4, 4, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0x00000000U, 0x00000000U, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(1, 4, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0xffffffffU, 0x00000000U, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(2, 4, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0xffffffffU, 0x00000000U, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(1, 2, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0x00000000U, 0xffffffffU, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(3, 4, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0x00000000U, 0xffffffffU, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(1, 3, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0xffffffffU, 0xffffffffU, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(2, 3, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(1, 2, 3, 4));
}
}

0 comments on commit 0e3f28e

Please sign in to comment.