145 lines
6.4 KiB
Diff
145 lines
6.4 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: "Sofiane H. Djerbi" <46628754+kugge@users.noreply.github.com>
|
|
Date: Fri, 17 Feb 2023 00:34:31 +0200
|
|
Subject: [PATCH] Lithium Math SineLut
|
|
|
|
Author: JellySquid
|
|
Licence: LGPL-3.0
|
|
|
|
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
|
|
index 259f7bdca1b9f59dd148492f8f8fe7dc959e55d9..a4f9f31941ddd119dca74f3e23bf8507ee4b7369 100644
|
|
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
|
|
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
|
|
@@ -200,8 +200,10 @@ public class KaiijuConfig {
|
|
|
|
public static boolean lithiumEnable = true;
|
|
public static boolean lithiumMathFastUtil = true;
|
|
+ public static boolean lithiumMathSineLut = true;
|
|
private static void lithiumSettings() {
|
|
lithiumEnable = getBoolean("lithium.enable", lithiumEnable);
|
|
lithiumMathFastUtil = getBoolean("lithium.math.fast-util", lithiumMathFastUtil) && lithiumEnable;
|
|
+ lithiumMathSineLut = getBoolean("lithium.math.sine-lut", lithiumMathSineLut) && lithiumEnable;
|
|
}
|
|
}
|
|
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/math/CompactSineLUT.java b/src/main/java/me/jellysquid/mods/lithium/common/util/math/CompactSineLUT.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..ccb45e94ea6d1a627df786fb88baec7edd1f2427
|
|
--- /dev/null
|
|
+++ b/src/main/java/me/jellysquid/mods/lithium/common/util/math/CompactSineLUT.java
|
|
@@ -0,0 +1,90 @@
|
|
+package me.jellysquid.mods.lithium.common.util.math;
|
|
+
|
|
+import net.minecraft.util.Mth;
|
|
+
|
|
+/**
|
|
+ * A replacement for the sine angle lookup table used in {@link MathHelper}, both reducing the size of LUT and improving
|
|
+ * the access patterns for common paired sin/cos operations.
|
|
+ *
|
|
+ * sin(-x) = -sin(x)
|
|
+ * ... to eliminate negative angles from the LUT.
|
|
+ *
|
|
+ * sin(x) = sin(pi/2 - x)
|
|
+ * ... to eliminate supplementary angles from the LUT.
|
|
+ *
|
|
+ * Using these identities allows us to reduce the LUT from 64K entries (256 KB) to just 16K entries (64 KB), enabling
|
|
+ * it to better fit into the CPU's caches at the expense of some cycles on the fast path. The implementation has been
|
|
+ * tightly optimized to avoid branching where possible and to use very quick integer operations.
|
|
+ *
|
|
+ * Generally speaking, reducing the size of a lookup table is always a good optimization, but since we need to spend
|
|
+ * extra CPU cycles trying to maintain parity with vanilla, there is the potential risk that this implementation ends
|
|
+ * up being slower than vanilla when the lookup table is able to be kept in cache memory.
|
|
+ *
|
|
+ * Unlike other "fast math" implementations, the values returned by this class are *bit-for-bit identical* with those
|
|
+ * from {@link MathHelper}. Validation is performed during runtime to ensure that the table is correct.
|
|
+ *
|
|
+ * @author coderbot16 Author of the original (and very clever) implementation in Rust:
|
|
+ * https://gitlab.com/coderbot16/i73/-/tree/master/i73-trig/src
|
|
+ * @author jellysquid3 Additional optimizations, port to Java
|
|
+ */
|
|
+public class CompactSineLUT {
|
|
+ private static final int[] SINE_TABLE_INT = new int[16384 + 1];
|
|
+ private static final float SINE_TABLE_MIDPOINT;
|
|
+
|
|
+ static {
|
|
+ final float[] SINE_TABLE = Mth.getSinTable();
|
|
+ // Copy the sine table, covering to raw int bits
|
|
+ for (int i = 0; i < SINE_TABLE_INT.length; i++) {
|
|
+ SINE_TABLE_INT[i] = Float.floatToRawIntBits(SINE_TABLE[i]);
|
|
+ }
|
|
+
|
|
+ SINE_TABLE_MIDPOINT = SINE_TABLE[SINE_TABLE.length / 2];
|
|
+
|
|
+ // Test that the lookup table is correct during runtime
|
|
+ for (int i = 0; i < SINE_TABLE.length; i++) {
|
|
+ float expected = SINE_TABLE[i];
|
|
+ float value = lookup(i);
|
|
+
|
|
+ if (expected != value) {
|
|
+ throw new IllegalArgumentException(String.format("LUT error at index %d (expected: %s, found: %s)", i, expected, value));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // [VanillaCopy] MathHelper#sin(float)
|
|
+ public static float sin(float f) {
|
|
+ return lookup((int) (f * 10430.378f) & 0xFFFF);
|
|
+ }
|
|
+
|
|
+ // [VanillaCopy] MathHelper#cos(float)
|
|
+ public static float cos(float f) {
|
|
+ return lookup((int) (f * 10430.378f + 16384.0f) & 0xFFFF);
|
|
+ }
|
|
+
|
|
+ private static float lookup(int index) {
|
|
+ // A special case... Is there some way to eliminate this?
|
|
+ if (index == 32768) {
|
|
+ return SINE_TABLE_MIDPOINT;
|
|
+ }
|
|
+
|
|
+ // Trigonometric identity: sin(-x) = -sin(x)
|
|
+ // Given a domain of 0 <= x <= 2*pi, just negate the value if x > pi.
|
|
+ // This allows the sin table size to be halved.
|
|
+ int neg = (index & 0x8000) << 16;
|
|
+
|
|
+ // All bits set if (pi/2 <= x), none set otherwise
|
|
+ // Extracts the 15th bit from 'half'
|
|
+ int mask = (index << 17) >> 31;
|
|
+
|
|
+ // Trigonometric identity: sin(x) = sin(pi/2 - x)
|
|
+ int pos = (0x8001 & mask) + (index ^ mask);
|
|
+
|
|
+ // Wrap the position in the table. Moving this down to immediately before the array access
|
|
+ // seems to help the Hotspot compiler optimize the bit math better.
|
|
+ pos &= 0x7fff;
|
|
+
|
|
+ // Fetch the corresponding value from the LUT and invert the sign bit as needed
|
|
+ // This directly manipulate the sign bit on the float bits to simplify logic
|
|
+ return Float.intBitsToFloat(SINE_TABLE_INT[pos] ^ neg);
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/net/minecraft/util/Mth.java b/src/main/java/net/minecraft/util/Mth.java
|
|
index 618f19d70a61062ed5989ec6cf0c036f2e047466..dd320f3a3f2b51a723a2fcc65d477a22c0901455 100644
|
|
--- a/src/main/java/net/minecraft/util/Mth.java
|
|
+++ b/src/main/java/net/minecraft/util/Mth.java
|
|
@@ -45,11 +45,19 @@ public class Mth {
|
|
return (float)((int)(value * f)) / f;
|
|
}
|
|
|
|
+ // Kaiiju start
|
|
+ public static float[] getSinTable() {
|
|
+ return SIN;
|
|
+ }
|
|
+ // Kaiiju end
|
|
+
|
|
public static float sin(float value) {
|
|
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.lithiumMathSineLut) return me.jellysquid.mods.lithium.common.util.math.CompactSineLUT.sin(value); // Kaiiju
|
|
return SIN[(int)(value * 10430.378F) & '\uffff'];
|
|
}
|
|
|
|
public static float cos(float value) {
|
|
+ if (dev.kaiijumc.kaiiju.KaiijuConfig.lithiumMathSineLut) return me.jellysquid.mods.lithium.common.util.math.CompactSineLUT.cos(value); // Kaiiju
|
|
return SIN[(int)(value * 10430.378F + 16384.0F) & '\uffff'];
|
|
}
|
|
|