203 lines
8.6 KiB
Diff
203 lines
8.6 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: MrHua269 <wangxyper@163.com>
|
|
Date: Sun, 12 Jan 2025 14:00:28 +0800
|
|
Subject: [PATCH] Pufferfish SIMD Utilities
|
|
|
|
|
|
diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..856de1331b15542c00e01990f471fa5152722c11
|
|
--- /dev/null
|
|
+++ b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java
|
|
@@ -0,0 +1,35 @@
|
|
+package gg.pufferfish.pufferfish.simd;
|
|
+
|
|
+import jdk.incubator.vector.FloatVector;
|
|
+import jdk.incubator.vector.IntVector;
|
|
+import jdk.incubator.vector.VectorSpecies;
|
|
+import org.slf4j.Logger;
|
|
+
|
|
+/**
|
|
+ * Basically, java is annoying and we have to push this out to its own class.
|
|
+ */
|
|
+@Deprecated
|
|
+public class SIMDChecker {
|
|
+
|
|
+ @Deprecated
|
|
+ public static boolean canEnable(Logger logger) {
|
|
+ try {
|
|
+ SIMDDetection.testRun = true;
|
|
+
|
|
+ VectorSpecies<Integer> ISPEC = IntVector.SPECIES_PREFERRED;
|
|
+ VectorSpecies<Float> FSPEC = FloatVector.SPECIES_PREFERRED;
|
|
+
|
|
+ logger.info("Max SIMD vector size on this system is {} bits (int)", ISPEC.vectorBitSize());
|
|
+ logger.info("Max SIMD vector size on this system is " + FSPEC.vectorBitSize() + " bits (float)");
|
|
+
|
|
+ if (ISPEC.elementSize() < 2 || FSPEC.elementSize() < 2) {
|
|
+ logger.warn("SIMD is not properly supported on this system!");
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ } catch (NoClassDefFoundError | Exception ignored) {} // Basically, we don't do anything. This lets us detect if it's not functional and disable it.
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..0a64cd0e88083ac4af6674ad0fb07b771109c737
|
|
--- /dev/null
|
|
+++ b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java
|
|
@@ -0,0 +1,34 @@
|
|
+package gg.pufferfish.pufferfish.simd;
|
|
+
|
|
+import org.slf4j.Logger;
|
|
+
|
|
+@Deprecated
|
|
+public class SIMDDetection {
|
|
+
|
|
+ public static boolean isEnabled = false;
|
|
+ public static boolean testRun = false;
|
|
+
|
|
+ @Deprecated
|
|
+ public static boolean canEnable(Logger logger) {
|
|
+ try {
|
|
+ return SIMDChecker.canEnable(logger);
|
|
+ } catch (NoClassDefFoundError | Exception ignored) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Deprecated
|
|
+ public static int getJavaVersion() {
|
|
+ // https://stackoverflow.com/a/2591122
|
|
+ String version = System.getProperty("java.version");
|
|
+ if(version.startsWith("1.")) {
|
|
+ version = version.substring(2, 3);
|
|
+ } else {
|
|
+ int dot = version.indexOf(".");
|
|
+ if(dot != -1) { version = version.substring(0, dot); }
|
|
+ }
|
|
+ version = version.split("-")[0]; // Azul is stupid
|
|
+ return Integer.parseInt(version);
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java b/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..c26dcaaa2e85882730c854099df80d69eec70f33
|
|
--- /dev/null
|
|
+++ b/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java
|
|
@@ -0,0 +1,84 @@
|
|
+package gg.pufferfish.pufferfish.simd;
|
|
+
|
|
+import jdk.incubator.vector.FloatVector;
|
|
+import jdk.incubator.vector.IntVector;
|
|
+import jdk.incubator.vector.VectorMask;
|
|
+import jdk.incubator.vector.VectorSpecies;
|
|
+import org.bukkit.map.MapPalette;
|
|
+
|
|
+import java.awt.*;
|
|
+
|
|
+@Deprecated
|
|
+public class VectorMapPalette {
|
|
+
|
|
+ private static final VectorSpecies<Integer> I_SPEC = IntVector.SPECIES_PREFERRED;
|
|
+ private static final VectorSpecies<Float> F_SPEC = FloatVector.SPECIES_PREFERRED;
|
|
+
|
|
+ @Deprecated
|
|
+ public static void matchColorVectorized(int[] in, byte[] out) {
|
|
+ int speciesLength = I_SPEC.length();
|
|
+ int i;
|
|
+ for (i = 0; i < in.length - speciesLength; i += speciesLength) {
|
|
+ float[] redsArr = new float[speciesLength];
|
|
+ float[] bluesArr = new float[speciesLength];
|
|
+ float[] greensArr = new float[speciesLength];
|
|
+ int[] alphasArr = new int[speciesLength];
|
|
+
|
|
+ for (int j = 0; j < speciesLength; j++) {
|
|
+ alphasArr[j] = (in[i + j] >> 24) & 0xFF;
|
|
+ redsArr[j] = (in[i + j] >> 16) & 0xFF;
|
|
+ greensArr[j] = (in[i + j] >> 8) & 0xFF;
|
|
+ bluesArr[j] = (in[i + j] >> 0) & 0xFF;
|
|
+ }
|
|
+
|
|
+ IntVector alphas = IntVector.fromArray(I_SPEC, alphasArr, 0);
|
|
+ FloatVector reds = FloatVector.fromArray(F_SPEC, redsArr, 0);
|
|
+ FloatVector greens = FloatVector.fromArray(F_SPEC, greensArr, 0);
|
|
+ FloatVector blues = FloatVector.fromArray(F_SPEC, bluesArr, 0);
|
|
+ IntVector resultIndex = IntVector.zero(I_SPEC);
|
|
+ VectorMask<Integer> modificationMask = VectorMask.fromLong(I_SPEC, 0xffffffff);
|
|
+
|
|
+ modificationMask = modificationMask.and(alphas.lt(128).not());
|
|
+ FloatVector bestDistances = FloatVector.broadcast(F_SPEC, Float.MAX_VALUE);
|
|
+
|
|
+ for (int c = 4; c < MapPalette.colors.length; c++) {
|
|
+ // We're using 32-bit floats here because it's 2x faster and nobody will know the difference.
|
|
+ // For correctness, the original algorithm uses 64-bit floats instead. Completely unnecessary.
|
|
+ FloatVector compReds = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getRed());
|
|
+ FloatVector compGreens = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getGreen());
|
|
+ FloatVector compBlues = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getBlue());
|
|
+
|
|
+ FloatVector rMean = reds.add(compReds).div(2.0f);
|
|
+ FloatVector rDiff = reds.sub(compReds);
|
|
+ FloatVector gDiff = greens.sub(compGreens);
|
|
+ FloatVector bDiff = blues.sub(compBlues);
|
|
+
|
|
+ FloatVector weightR = rMean.div(256.0f).add(2);
|
|
+ FloatVector weightG = FloatVector.broadcast(F_SPEC, 4.0f);
|
|
+ FloatVector weightB = FloatVector.broadcast(F_SPEC, 255.0f).sub(rMean).div(256.0f).add(2.0f);
|
|
+
|
|
+ FloatVector distance = weightR.mul(rDiff).mul(rDiff).add(weightG.mul(gDiff).mul(gDiff)).add(weightB.mul(bDiff).mul(bDiff));
|
|
+
|
|
+ // Now we compare to the best distance we've found.
|
|
+ // This mask contains a "1" if better, and a "0" otherwise.
|
|
+ VectorMask<Float> bestDistanceMask = distance.lt(bestDistances);
|
|
+ bestDistances = bestDistances.blend(distance, bestDistanceMask); // Update the best distances
|
|
+
|
|
+ // Update the result array
|
|
+ // We also AND with the modification mask because we don't want to interfere if the alpha value isn't large enough.
|
|
+ resultIndex = resultIndex.blend(c, bestDistanceMask.cast(I_SPEC).and(modificationMask)); // Update the results
|
|
+ }
|
|
+
|
|
+ for (int j = 0; j < speciesLength; j++) {
|
|
+ int index = resultIndex.lane(j);
|
|
+ out[i + j] = (byte) (index < 128 ? index : -129 + (index - 127));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // For the final ones, fall back to the regular method
|
|
+ for (; i < in.length; i++) {
|
|
+ out[i] = MapPalette.matchColor(new Color(in[i], true));
|
|
+ }
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/org/bukkit/map/MapPalette.java b/src/main/java/org/bukkit/map/MapPalette.java
|
|
index 6995f9cc08d162e3adcd3a28f6bfa6d329661999..83ea70a16b4090a8c628784f2807cd16e7065103 100644
|
|
--- a/src/main/java/org/bukkit/map/MapPalette.java
|
|
+++ b/src/main/java/org/bukkit/map/MapPalette.java
|
|
@@ -45,7 +45,7 @@ public final class MapPalette {
|
|
}
|
|
|
|
@NotNull
|
|
- static final Color[] colors = {
|
|
+ public static final Color[] colors = { // Luminol - package-private -> public
|
|
c(0, 0, 0, 0), c(0, 0, 0, 0), c(0, 0, 0, 0), c(0, 0, 0, 0),
|
|
c(89, 125, 39), c(109, 153, 48), c(127, 178, 56), c(67, 94, 29),
|
|
c(174, 164, 115), c(213, 201, 140), c(247, 233, 163), c(130, 123, 86),
|
|
@@ -216,9 +216,11 @@ public final class MapPalette {
|
|
temp.getRGB(0, 0, temp.getWidth(), temp.getHeight(), pixels, 0, temp.getWidth());
|
|
|
|
byte[] result = new byte[temp.getWidth() * temp.getHeight()];
|
|
+ if ((mapColorCache != null && mapColorCache.isCached()) || !gg.pufferfish.pufferfish.simd.SIMDDetection.isEnabled) { // Luminol - Pufferfish - vectorized map color conversion
|
|
for (int i = 0; i < pixels.length; i++) {
|
|
result[i] = matchColor(new Color(pixels[i], true));
|
|
}
|
|
+ } else gg.pufferfish.pufferfish.simd.VectorMapPalette.matchColorVectorized(pixels, result); // Luminol - Pufferfish - vectorized map color conversion
|
|
return result;
|
|
}
|
|
|