-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
139 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
patches/api/0003-Pufferfish-Optimize-map-rendering.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: Kevin Raneri <kevin.raneri@gmail.com> | ||
Date: Tue, 8 Feb 2022 12:53:02 -0500 | ||
Subject: [PATCH] Pufferfish: Optimize map rendering | ||
|
||
Original code by Kevin Raneri <kevin.raneri@gmail.com> | ||
You can find the original code on https://github.com/pufferfish-gg/Pufferfish | ||
|
||
This patch does not add any API that should be used by plugins. Any | ||
classes and methods added by this patch should NOT be used in plugins. | ||
|
||
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..5538d2d18ff03e34c6e39a6cffdd7e6c6a4fc46f | ||
--- /dev/null | ||
+++ b/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java | ||
@@ -0,0 +1,81 @@ | ||
+package gg.pufferfish.pufferfish.simd; | ||
+ | ||
+import java.awt.Color; | ||
+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; | ||
+ | ||
+public class VectorMapPalette { | ||
+ | ||
+ private static final VectorSpecies<Integer> I_SPEC = IntVector.SPECIES_PREFERRED; | ||
+ private static final VectorSpecies<Float> F_SPEC = FloatVector.SPECIES_PREFERRED; | ||
+ | ||
+ 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)); | ||
+ } | ||
+ } | ||
+ | ||
+} | ||
\ No newline at end of file | ||
diff --git a/src/main/java/org/bukkit/map/MapPalette.java b/src/main/java/org/bukkit/map/MapPalette.java | ||
index c80faa079eca1564847070f0338fc98024639829..a16d26304fdbba6b47b1c6e7ca7955356f218550 100644 | ||
--- a/src/main/java/org/bukkit/map/MapPalette.java | ||
+++ b/src/main/java/org/bukkit/map/MapPalette.java | ||
@@ -1,5 +1,6 @@ | ||
package org.bukkit.map; | ||
|
||
+import gg.pufferfish.pufferfish.simd.SIMDDetection; // Pufferfish | ||
import com.google.common.base.Preconditions; | ||
import java.awt.Color; | ||
import java.awt.Graphics2D; | ||
@@ -40,7 +41,7 @@ public final class MapPalette { | ||
} | ||
|
||
@NotNull | ||
- static final Color[] colors = { | ||
+ public static final Color[] colors = { // Pufferfish - public access | ||
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), | ||
@@ -211,9 +212,15 @@ public final class MapPalette { | ||
temp.getRGB(0, 0, temp.getWidth(), temp.getHeight(), pixels, 0, temp.getWidth()); | ||
|
||
byte[] result = new byte[temp.getWidth() * temp.getHeight()]; | ||
+ // Pufferfish start | ||
+ if (!SIMDDetection.isEnabled) { | ||
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); | ||
+ } | ||
+ // Pufferfish end | ||
return result; | ||
} | ||
|