|
7 | 7 | using System.Runtime.CompilerServices; |
8 | 8 | #if NET7_0_OR_GREATER |
9 | 9 | using System.Runtime.Intrinsics; |
| 10 | +using System.Runtime.Intrinsics.Arm; |
| 11 | +using System.Runtime.Intrinsics.X86; |
10 | 12 | #endif |
11 | 13 | using static Box2D.NET.B2Arrays; |
12 | 14 | using static Box2D.NET.B2Cores; |
@@ -1295,6 +1297,108 @@ static void b2ScatterBodies( b2BodyState* states, int* indices, const b2BodyStat |
1295 | 1297 |
|
1296 | 1298 | #else |
1297 | 1299 |
|
| 1300 | +#if NET7_0_OR_GREATER |
| 1301 | + // b2UnpackLoW: [a0 b0 a1 b1] |
| 1302 | + [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| 1303 | + private static Vector128<float> UnpackLoW(Vector128<float> a, Vector128<float> b) |
| 1304 | + { |
| 1305 | + if (Sse.IsSupported) |
| 1306 | + { |
| 1307 | + return Sse.UnpackLow(a, b); |
| 1308 | + } |
| 1309 | + |
| 1310 | + if (AdvSimd.Arm64.IsSupported) |
| 1311 | + { |
| 1312 | + return AdvSimd.Arm64.ZipLow(a, b); |
| 1313 | + } |
| 1314 | + |
| 1315 | + return Vector128.Create(a.GetElement(0), b.GetElement(0), a.GetElement(1), b.GetElement(1)); |
| 1316 | + } |
| 1317 | + |
| 1318 | + // b2UnpackHiW: [a2 b2 a3 b3] |
| 1319 | + [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| 1320 | + private static Vector128<float> UnpackHiW(Vector128<float> a, Vector128<float> b) |
| 1321 | + { |
| 1322 | + if (Sse.IsSupported) |
| 1323 | + { |
| 1324 | + return Sse.UnpackHigh(a, b); |
| 1325 | + } |
| 1326 | + |
| 1327 | + if (AdvSimd.Arm64.IsSupported) |
| 1328 | + { |
| 1329 | + return AdvSimd.Arm64.ZipHigh(a, b); |
| 1330 | + } |
| 1331 | + |
| 1332 | + return Vector128.Create(a.GetElement(2), b.GetElement(2), a.GetElement(3), b.GetElement(3)); |
| 1333 | + } |
| 1334 | + |
| 1335 | + // Reads the two 16 byte halves of a 32 byte body state. |
| 1336 | + [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| 1337 | + private static Vector128<float> LoadHalf(ref B2BodyState state, int half) |
| 1338 | + { |
| 1339 | + return Unsafe.Add(ref Unsafe.As<B2BodyState, Vector128<float>>(ref state), half); |
| 1340 | + } |
| 1341 | + |
| 1342 | + // This is a load and transpose |
| 1343 | + internal static B2BodyStateW b2GatherBodies(Span<B2BodyState> states, ReadOnlySpan<int> indices) |
| 1344 | + { |
| 1345 | + B2_VALIDATE(indices[0] >= 0 && indices[1] >= 0 && indices[2] >= 0 && indices[3] >= 0); |
| 1346 | + |
| 1347 | + // b2_identityBodyState is exactly [0 0 0 0][0 0 1 0], the identityA/identityB pair |
| 1348 | + // C builds inline, so a null index can bind to it and skip the per-load branch. |
| 1349 | + B2BodyState identity = b2_identityBodyState; |
| 1350 | + |
| 1351 | + // zero means null |
| 1352 | + int i1 = indices[0] - 1; |
| 1353 | + int i2 = indices[1] - 1; |
| 1354 | + int i3 = indices[2] - 1; |
| 1355 | + int i4 = indices[3] - 1; |
| 1356 | + |
| 1357 | + ref B2BodyState s1 = ref (i1 == B2_NULL_INDEX ? ref identity : ref states[i1]); |
| 1358 | + ref B2BodyState s2 = ref (i2 == B2_NULL_INDEX ? ref identity : ref states[i2]); |
| 1359 | + ref B2BodyState s3 = ref (i3 == B2_NULL_INDEX ? ref identity : ref states[i3]); |
| 1360 | + ref B2BodyState s4 = ref (i4 == B2_NULL_INDEX ? ref identity : ref states[i4]); |
| 1361 | + |
| 1362 | + Vector128<float> b1a = LoadHalf(ref s1, 0); |
| 1363 | + Vector128<float> b1b = LoadHalf(ref s1, 1); |
| 1364 | + Vector128<float> b2a = LoadHalf(ref s2, 0); |
| 1365 | + Vector128<float> b2b = LoadHalf(ref s2, 1); |
| 1366 | + Vector128<float> b3a = LoadHalf(ref s3, 0); |
| 1367 | + Vector128<float> b3b = LoadHalf(ref s3, 1); |
| 1368 | + Vector128<float> b4a = LoadHalf(ref s4, 0); |
| 1369 | + Vector128<float> b4b = LoadHalf(ref s4, 1); |
| 1370 | + |
| 1371 | + // [vx1 vx3 vy1 vy3] |
| 1372 | + Vector128<float> t1a = UnpackLoW(b1a, b3a); |
| 1373 | + |
| 1374 | + // [vx2 vx4 vy2 vy4] |
| 1375 | + Vector128<float> t2a = UnpackLoW(b2a, b4a); |
| 1376 | + |
| 1377 | + // [w1 w3 f1 f3] |
| 1378 | + Vector128<float> t3a = UnpackHiW(b1a, b3a); |
| 1379 | + |
| 1380 | + // [w2 w4 f2 f4] |
| 1381 | + Vector128<float> t4a = UnpackHiW(b2a, b4a); |
| 1382 | + |
| 1383 | + B2BodyStateW simdBody = new B2BodyStateW(); |
| 1384 | + simdBody.v.X = StoreW(UnpackLoW(t1a, t2a)); |
| 1385 | + simdBody.v.Y = StoreW(UnpackHiW(t1a, t2a)); |
| 1386 | + simdBody.w = StoreW(UnpackLoW(t3a, t4a)); |
| 1387 | + simdBody.flags = StoreW(UnpackHiW(t3a, t4a)); |
| 1388 | + |
| 1389 | + Vector128<float> t1b = UnpackLoW(b1b, b3b); |
| 1390 | + Vector128<float> t2b = UnpackLoW(b2b, b4b); |
| 1391 | + Vector128<float> t3b = UnpackHiW(b1b, b3b); |
| 1392 | + Vector128<float> t4b = UnpackHiW(b2b, b4b); |
| 1393 | + |
| 1394 | + simdBody.dp.X = StoreW(UnpackLoW(t1b, t2b)); |
| 1395 | + simdBody.dp.Y = StoreW(UnpackHiW(t1b, t2b)); |
| 1396 | + simdBody.dq.C = StoreW(UnpackLoW(t3b, t4b)); |
| 1397 | + simdBody.dq.S = StoreW(UnpackHiW(t3b, t4b)); |
| 1398 | + |
| 1399 | + return simdBody; |
| 1400 | + } |
| 1401 | +#else |
1298 | 1402 | // This is a load and transpose |
1299 | 1403 | internal static B2BodyStateW b2GatherBodies(Span<B2BodyState> states, ReadOnlySpan<int> indices) |
1300 | 1404 | { |
@@ -1326,6 +1430,7 @@ internal static B2BodyStateW b2GatherBodies(Span<B2BodyState> states, ReadOnlySp |
1326 | 1430 |
|
1327 | 1431 | return simdBody; |
1328 | 1432 | } |
| 1433 | +#endif |
1329 | 1434 |
|
1330 | 1435 | // This writes only the velocities back to the solver bodies |
1331 | 1436 | internal static void b2ScatterBodies(Span<B2BodyState> states, ReadOnlySpan<int> indices, ref B2BodyStateW simdBody) |
|
0 commit comments