Skip to content

Commit 0ed63c8

Browse files
authored
Vectorized map palette conversion
Vectorized map palette conversion
2 parents 9ca4d55 + 33d37a8 commit 0ed63c8

File tree

6 files changed

+242
-22
lines changed

6 files changed

+242
-22
lines changed

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ def jvm_arguments = [
8080

8181
def compiler_jvm_arguments = [
8282
'--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED',
83-
'--add-exports=java.base/jdk.internal.reflect=ALL-UNNAMED'
83+
'--add-exports=java.base/jdk.internal.reflect=ALL-UNNAMED',
84+
'--add-modules=jdk.incubator.vector' // CatRoom - SIMD support
8485
]
8586
// Projects
8687

patches/minecraft/net/minecraft/server/dedicated/DedicatedServer.java.patch

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,19 @@
147147
this.field_154332_n = new ServerEula(new File("eula.txt"));
148148

149149
if (!this.field_154332_n.func_154346_a())
150-
@@ -163,17 +202,17 @@
150+
@@ -152,6 +191,11 @@
151+
this.func_71189_e(this.field_71340_o.func_73671_a("server-ip", ""));
152+
}
153+
154+
+ // CatRoom start - SIMD support
155+
+ try {
156+
+ gg.pufferfish.pufferfish.simd.SIMDDetection.initialize();
157+
+ } catch (Throwable ignored) {}
158+
+ // CatRoom end - SIMD support
159+
this.func_71251_e(this.field_71340_o.func_73670_a("spawn-animals", true));
160+
this.func_71257_f(this.field_71340_o.func_73670_a("spawn-npcs", true));
161+
this.func_71188_g(this.field_71340_o.func_73670_a("pvp", true));
162+
@@ -163,17 +207,17 @@
151163

152164
if (this.field_71340_o.func_73669_a("difficulty", 1) < 0)
153165
{
@@ -168,7 +180,7 @@
168180
InetAddress inetaddress = null;
169181

170182
if (!this.func_71211_k().isEmpty())
171-
@@ -186,29 +225,42 @@
183+
@@ -186,29 +230,42 @@
172184
this.func_71208_b(this.field_71340_o.func_73669_a("server-port", 25565));
173185
}
174186

@@ -227,7 +239,7 @@
227239
field_155771_h.warn("To change this, set \"online-mode\" to \"true\" in the server.properties file.");
228240
}
229241

230-
@@ -223,7 +275,9 @@
242+
@@ -223,7 +280,9 @@
231243
}
232244
else
233245
{
@@ -238,7 +250,7 @@
238250
long j = System.nanoTime();
239251

240252
if (this.func_71270_I() == null)
241-
@@ -234,7 +288,7 @@
253+
@@ -234,7 +293,7 @@
242254
String s = this.field_71340_o.func_73671_a("level-seed", "");
243255
String s1 = this.field_71340_o.func_73671_a("level-type", "DEFAULT");
244256
String s2 = this.field_71340_o.func_73671_a("generator-settings", "");
@@ -247,7 +259,7 @@
247259

248260
if (!s.isEmpty())
249261
{
250-
@@ -247,7 +301,7 @@
262+
@@ -247,7 +306,7 @@
251263
k = l;
252264
}
253265
}
@@ -256,7 +268,7 @@
256268
{
257269
k = (long)s.hashCode();
258270
}
259-
@@ -267,21 +321,21 @@
271+
@@ -267,21 +326,21 @@
260272
this.func_71191_d(this.field_71340_o.func_73669_a("max-build-height", 256));
261273
this.func_71191_d((this.func_71207_Z() + 8) / 16 * 16);
262274
this.func_71191_d(MathHelper.func_76125_a(this.func_71207_Z(), 64, 256));
@@ -285,7 +297,7 @@
285297
this.field_71340_o.func_187238_b("announce-player-achievements");
286298
this.field_71340_o.func_73668_b();
287299
}
288-
@@ -293,14 +347,33 @@
300+
@@ -293,14 +352,33 @@
289301
this.field_71342_m.func_72602_a();
290302
}
291303

@@ -324,7 +336,7 @@
324336
{
325337
Thread thread1 = new Thread(new ServerHangWatchdog(this));
326338
thread1.setName("Server Watchdog");
327-
@@ -309,7 +382,8 @@
339+
@@ -309,7 +387,8 @@
328340
}
329341

330342
Items.field_190931_a.func_150895_a(CreativeTabs.field_78027_g, NonNullList.func_191196_a());
@@ -334,7 +346,7 @@
334346
}
335347
}
336348
}
337-
@@ -339,46 +413,38 @@
349+
@@ -339,46 +418,38 @@
338350

339351
if (!this.field_71340_o.func_73671_a("resource-pack", "").isEmpty() && s.isEmpty())
340352
{
@@ -382,7 +394,7 @@
382394
public CrashReport func_71230_b(CrashReport p_71230_1_)
383395
{
384396
p_71230_1_ = super.func_71230_b(p_71230_1_);
385-
@@ -400,40 +466,34 @@
397+
@@ -400,40 +471,34 @@
386398
return p_71230_1_;
387399
}
388400

@@ -425,7 +437,7 @@
425437
public boolean func_70002_Q()
426438
{
427439
return this.field_71340_o.func_73670_a("snooper-enabled", true);
428-
@@ -446,20 +506,39 @@
440+
@@ -446,20 +511,39 @@
429441

430442
public void func_71333_ah()
431443
{
@@ -469,7 +481,7 @@
469481
public boolean func_181035_ah()
470482
{
471483
return this.field_71340_o.func_73670_a("use-native-transport", true);
472-
@@ -470,13 +549,11 @@
484+
@@ -470,13 +554,11 @@
473485
return (DedicatedPlayerList)super.func_184103_al();
474486
}
475487

@@ -483,7 +495,7 @@
483495
public String func_71330_a(String p_71330_1_, String p_71330_2_)
484496
{
485497
return this.field_71340_o.func_73671_a(p_71330_1_, p_71330_2_);
486-
@@ -487,38 +564,32 @@
498+
@@ -487,38 +569,32 @@
487499
return this.field_71340_o.func_73670_a(p_71332_1_, p_71332_2_);
488500
}
489501

@@ -522,7 +534,7 @@
522534
public String func_71274_v()
523535
{
524536
return this.func_71273_Y();
525-
@@ -530,34 +601,29 @@
537+
@@ -530,34 +606,29 @@
526538
this.field_71335_s = true;
527539
}
528540

@@ -558,7 +570,7 @@
558570
{
559571
return false;
560572
}
561-
@@ -583,33 +649,28 @@
573+
@@ -583,33 +654,28 @@
562574
}
563575
}
564576

@@ -593,7 +605,7 @@
593605
public int func_175580_aG()
594606
{
595607
int i = this.field_71340_o.func_73669_a("max-world-size", super.func_175580_aG());
596-
@@ -626,12 +687,14 @@
608+
@@ -626,12 +692,14 @@
597609
return i;
598610
}
599611

@@ -609,7 +621,7 @@
609621
protected boolean func_152368_aE() throws IOException
610622
{
611623
boolean flag = false;
612-
@@ -708,8 +771,9 @@
624+
@@ -708,8 +776,9 @@
613625
{
614626
Thread.sleep(5000L);
615627
}
@@ -620,7 +632,7 @@
620632
}
621633
}
622634

623-
@@ -718,17 +782,68 @@
635+
@@ -718,17 +787,68 @@
624636
return this.field_71340_o.func_179885_a("max-tick-time", TimeUnit.MINUTES.toMillis(1L));
625637
}
626638

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package gg.pufferfish.pufferfish.simd;
2+
3+
import jdk.incubator.vector.FloatVector;
4+
import jdk.incubator.vector.IntVector;
5+
import jdk.incubator.vector.VectorSpecies;
6+
7+
/**
8+
* Basically, java is annoying and we have to push this out to its own class.
9+
*/
10+
public class SIMDChecker {
11+
12+
public static void initialize() {
13+
if (SIMDDetection.isInitialized()) {
14+
return;
15+
}
16+
SIMDDetection.setInitialized();
17+
try {
18+
int javaVersion = SIMDDetection.getJavaVersion();
19+
if (javaVersion < 17) {
20+
return;
21+
}
22+
SIMDDetection.supportingJavaVersion = true;
23+
SIMDDetection.testRunStarted = true;
24+
25+
VectorSpecies<Integer> ISPEC = IntVector.SPECIES_PREFERRED;
26+
VectorSpecies<Float> FSPEC = FloatVector.SPECIES_PREFERRED;
27+
28+
SIMDDetection.intVectorBitSize = ISPEC.vectorBitSize();
29+
SIMDDetection.floatVectorBitSize = FSPEC.vectorBitSize();
30+
31+
SIMDDetection.intElementSize = ISPEC.elementSize();
32+
SIMDDetection.floatElementSize = FSPEC.elementSize();
33+
34+
SIMDDetection.testRunCompleted = true;
35+
36+
if (ISPEC.elementSize() < 2 || FSPEC.elementSize() < 2) {
37+
SIMDDetection.unsupportingLaneSize = true;
38+
return;
39+
}
40+
41+
SIMDDetection.isEnabled = true;
42+
} catch (Throwable ignored) {} // Basically, we don't do anything. This lets us detect if it's not functional and disable it.
43+
}
44+
45+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package gg.pufferfish.pufferfish.simd;
2+
3+
public class SIMDDetection {
4+
5+
private static boolean isInitialized = false;
6+
static int intVectorBitSize;
7+
static int floatVectorBitSize;
8+
static int intElementSize;
9+
static int floatElementSize;
10+
static boolean supportingJavaVersion;
11+
static boolean testRunStarted;
12+
static boolean testRunCompleted;
13+
static boolean unsupportingLaneSize;
14+
static boolean isEnabled;
15+
16+
public static void initialize() {
17+
try {
18+
SIMDChecker.initialize();
19+
} catch (Throwable ignored) {}
20+
}
21+
22+
static void setInitialized() {
23+
isInitialized = true;
24+
}
25+
26+
public static boolean isInitialized() {
27+
return isInitialized;
28+
}
29+
30+
public static int intVectorBitSize() {
31+
return intVectorBitSize;
32+
}
33+
34+
public static int floatVectorBitSize() {
35+
return floatVectorBitSize;
36+
}
37+
38+
public static int intElementSize() {
39+
return intElementSize;
40+
}
41+
42+
public static int floatElementSize() {
43+
return floatElementSize;
44+
}
45+
46+
public static boolean supportingJavaVersion() {
47+
return supportingJavaVersion;
48+
}
49+
50+
public static boolean testRunCompleted() {
51+
return testRunCompleted;
52+
}
53+
54+
public static boolean unsupportingLaneSize() {
55+
return unsupportingLaneSize;
56+
}
57+
58+
public static boolean isEnabled() {
59+
return isEnabled;
60+
}
61+
62+
public static int getJavaVersion() {
63+
// https://stackoverflow.com/a/2591122
64+
String version = System.getProperty("java.version");
65+
if(version.startsWith("1.")) {
66+
version = version.substring(2, 3);
67+
} else {
68+
int dot = version.indexOf(".");
69+
if(dot != -1) { version = version.substring(0, dot); }
70+
}
71+
version = version.split("-")[0]; // Azul is stupid
72+
return Integer.parseInt(version);
73+
}
74+
75+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package gg.pufferfish.pufferfish.simd;
2+
3+
import jdk.incubator.vector.FloatVector;
4+
import jdk.incubator.vector.IntVector;
5+
import jdk.incubator.vector.VectorMask;
6+
import jdk.incubator.vector.VectorSpecies;
7+
import org.bukkit.map.MapPalette;
8+
9+
import java.awt.*;
10+
11+
public class VectorMapPalette {
12+
13+
private static final VectorSpecies<Integer> I_SPEC = IntVector.SPECIES_PREFERRED;
14+
private static final VectorSpecies<Float> F_SPEC = FloatVector.SPECIES_PREFERRED;
15+
16+
public static void matchColorVectorized(int[] in, byte[] out) {
17+
int speciesLength = I_SPEC.length();
18+
int i;
19+
for (i = 0; i < in.length - speciesLength; i += speciesLength) {
20+
float[] redsArr = new float[speciesLength];
21+
float[] bluesArr = new float[speciesLength];
22+
float[] greensArr = new float[speciesLength];
23+
int[] alphasArr = new int[speciesLength];
24+
25+
for (int j = 0; j < speciesLength; j++) {
26+
alphasArr[j] = (in[i + j] >> 24) & 0xFF;
27+
redsArr[j] = (in[i + j] >> 16) & 0xFF;
28+
greensArr[j] = (in[i + j] >> 8) & 0xFF;
29+
bluesArr[j] = (in[i + j] >> 0) & 0xFF;
30+
}
31+
32+
IntVector alphas = IntVector.fromArray(I_SPEC, alphasArr, 0);
33+
FloatVector reds = FloatVector.fromArray(F_SPEC, redsArr, 0);
34+
FloatVector greens = FloatVector.fromArray(F_SPEC, greensArr, 0);
35+
FloatVector blues = FloatVector.fromArray(F_SPEC, bluesArr, 0);
36+
IntVector resultIndex = IntVector.zero(I_SPEC);
37+
VectorMask<Integer> modificationMask = VectorMask.fromLong(I_SPEC, 0xffffffff);
38+
39+
modificationMask = modificationMask.and(alphas.lt(128).not());
40+
FloatVector bestDistances = FloatVector.broadcast(F_SPEC, Float.MAX_VALUE);
41+
42+
for (int c = 4; c < MapPalette.colors.length; c++) {
43+
// We're using 32-bit floats here because it's 2x faster and nobody will know the difference.
44+
// For correctness, the original algorithm uses 64-bit floats instead. Completely unnecessary.
45+
FloatVector compReds = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getRed());
46+
FloatVector compGreens = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getGreen());
47+
FloatVector compBlues = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getBlue());
48+
49+
FloatVector rMean = reds.add(compReds).div(2.0f);
50+
FloatVector rDiff = reds.sub(compReds);
51+
FloatVector gDiff = greens.sub(compGreens);
52+
FloatVector bDiff = blues.sub(compBlues);
53+
54+
FloatVector weightR = rMean.div(256.0f).add(2);
55+
FloatVector weightG = FloatVector.broadcast(F_SPEC, 4.0f);
56+
FloatVector weightB = FloatVector.broadcast(F_SPEC, 255.0f).sub(rMean).div(256.0f).add(2.0f);
57+
58+
FloatVector distance = weightR.mul(rDiff).mul(rDiff).add(weightG.mul(gDiff).mul(gDiff)).add(weightB.mul(bDiff).mul(bDiff));
59+
60+
// Now we compare to the best distance we've found.
61+
// This mask contains a "1" if better, and a "0" otherwise.
62+
VectorMask<Float> bestDistanceMask = distance.lt(bestDistances);
63+
bestDistances = bestDistances.blend(distance, bestDistanceMask); // Update the best distances
64+
65+
// Update the result array
66+
// We also AND with the modification mask because we don't want to interfere if the alpha value isn't large enough.
67+
resultIndex = resultIndex.blend(c, bestDistanceMask.cast(I_SPEC).and(modificationMask)); // Update the results
68+
}
69+
70+
for (int j = 0; j < speciesLength; j++) {
71+
int index = resultIndex.lane(j);
72+
out[i + j] = (byte) (index < 128 ? index : -129 + (index - 127));
73+
}
74+
}
75+
76+
// For the final ones, fall back to the regular method
77+
for (; i < in.length; i++) {
78+
out[i] = MapPalette.matchColor(new Color(in[i], true));
79+
}
80+
}
81+
82+
}

0 commit comments

Comments
 (0)