Skip to content

Commit 6a7aa96

Browse files
authored
Allow lazy-loading chunk section data when using Vector API (#3035)
1 parent 84cba16 commit 6a7aa96

File tree

9 files changed

+124
-54
lines changed

9 files changed

+124
-54
lines changed

worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/CountFilter.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.fastasyncworldedit.core.extent.filter;
22

33
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
4+
import com.fastasyncworldedit.core.internal.simd.VectorFacade;
45
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
5-
import jdk.incubator.vector.ShortVector;
66
import jdk.incubator.vector.VectorMask;
77

88
public class CountFilter extends ForkedFilter<CountFilter> implements VectorizedFilter {
@@ -37,9 +37,8 @@ public int getTotal() {
3737
}
3838

3939
@Override
40-
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
40+
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
4141
total += mask.trueCount();
42-
return set;
4342
}
4443

4544
}

worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.fastasyncworldedit.core.extent.filter;
22

33
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
4+
import com.fastasyncworldedit.core.internal.simd.VectorFacade;
45
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
56
import com.fastasyncworldedit.core.queue.Filter;
67
import com.fastasyncworldedit.core.queue.IChunk;
78
import com.sk89q.worldedit.regions.Region;
8-
import jdk.incubator.vector.ShortVector;
99
import jdk.incubator.vector.VectorMask;
1010
import org.jetbrains.annotations.Nullable;
1111

@@ -78,9 +78,9 @@ public VectorizedLinkedFilter(final L left, final R right) {
7878
}
7979

8080
@Override
81-
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
82-
ShortVector res = getLeft().applyVector(get, set, mask);
83-
return getRight().applyVector(get, res, mask);
81+
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
82+
getLeft().applyVector(get, set, mask);
83+
getRight().applyVector(get, set, mask);
8484
}
8585

8686
@Override

worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/MaskFilter.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter;
44
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
5+
import com.fastasyncworldedit.core.internal.simd.VectorFacade;
56
import com.fastasyncworldedit.core.internal.simd.SimdSupport;
67
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
78
import com.fastasyncworldedit.core.internal.simd.VectorizedMask;
@@ -11,6 +12,7 @@
1112
import jdk.incubator.vector.ShortVector;
1213
import jdk.incubator.vector.VectorMask;
1314
import jdk.incubator.vector.VectorOperators;
15+
import jdk.incubator.vector.VectorSpecies;
1416

1517
import java.util.Objects;
1618
import java.util.concurrent.atomic.AtomicInteger;
@@ -82,13 +84,15 @@ public VectorizedMaskFilter(final T other, final Mask root, AtomicInteger change
8284
}
8385

8486
@Override
85-
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
87+
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
8688
final T parent = getParent();
87-
VectorMask<Short> masked = vectorizedMask.compareVector(set, get);
88-
ShortVector res = parent.applyVector(get, set, mask.and(masked));
89-
VectorMask<Short> changed = res.compare(VectorOperators.NE, set);
90-
changes.getAndAdd(changed.trueCount());
91-
return res;
89+
final VectorSpecies<Short> species = mask.vectorSpecies();
90+
VectorMask<Short> masked = this.vectorizedMask.compareVector(set, get, species);
91+
ShortVector before = set.getOrZero(masked.vectorSpecies());
92+
parent.applyVector(get, set, mask.and(masked));
93+
ShortVector after = set.getOrZero(masked.vectorSpecies());
94+
VectorMask<Short> changed = after.compare(VectorOperators.NE, before);
95+
this.changes.getAndAdd(changed.trueCount());
9296
}
9397

9498
@Override

worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/CharFilterBlock.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ public class CharFilterBlock extends ChunkFilterBlock {
3737

3838
private int maxLayer;
3939
private int minLayer;
40-
private CharGetBlocks get;
41-
private IChunkSet set;
40+
protected CharGetBlocks get;
41+
protected IChunkSet set;
4242
protected char[] getArr;
4343
@Nullable
4444
protected char[] setArr;
4545
protected SetDelegate delegate;
4646
// local
47-
private int layer;
47+
protected int layer;
4848
private int index;
4949
private int x;
5050
private int y;

worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/SimdSupport.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,23 +54,23 @@ public static boolean useVectorApi() {
5454
if (base == null) {
5555
yield null;
5656
}
57-
yield (set, get) -> base.compareVector(set, get).not();
57+
yield (set, get, species) -> base.compareVector(set, get, species).not();
5858
}
5959
default -> null;
6060
};
6161
}
6262

6363
private static VectorizedMask vectorizedTargetMaskNonAir() {
6464
// everything > VOID_AIR is not air
65-
return (set, get) -> get.compare(VectorOperators.UNSIGNED_GT, BlockTypesCache.ReservedIDs.VOID_AIR);
65+
return (set, get, species) -> get.get(species).compare(VectorOperators.UNSIGNED_GT, BlockTypesCache.ReservedIDs.VOID_AIR);
6666
}
6767

6868
private static VectorizedMask vectorizedTargetMask(char ordinal) {
69-
return (set, get) -> get.compare(VectorOperators.EQ, (short) ordinal);
69+
return (set, get, species) -> get.get(species).compare(VectorOperators.EQ, (short) ordinal);
7070
}
7171

7272
private static VectorizedMask vectorizedTargetMaskInverse(char ordinal) {
73-
return (set, get) -> get.compare(VectorOperators.NE, (short) ordinal);
73+
return (set, get, species) -> get.get(species).compare(VectorOperators.NE, (short) ordinal);
7474
}
7575

7676
public static @Nullable VectorizedFilter vectorizedPattern(Pattern pattern) {
@@ -102,14 +102,16 @@ public VectorizedPattern(final T parent, char ordinal) {
102102
}
103103

104104
@Override
105-
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
106-
// only change the lanes the mask dictates us to change, keep the rest
107-
return set.blend(ShortVector.broadcast(ShortVector.SPECIES_PREFERRED, ordinal), mask);
105+
public Filter newInstance(final Filter other) {
106+
return new VectorizedPattern<>(other, ordinal);
108107
}
109108

110109
@Override
111-
public Filter newInstance(final Filter other) {
112-
return new VectorizedPattern<>(other, ordinal);
110+
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
111+
ShortVector s = set.getOrZero(mask.vectorSpecies());
112+
// only change the lanes the mask dictates us to change, keep the rest
113+
s = s.blend(ShortVector.broadcast(ShortVector.SPECIES_PREFERRED, ordinal), mask);
114+
set.setOrIgnore(s);
113115
}
114116

115117
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.fastasyncworldedit.core.internal.simd;
2+
3+
import com.fastasyncworldedit.core.queue.IBlocks;
4+
import com.sk89q.worldedit.world.block.BlockTypesCache;
5+
import jdk.incubator.vector.ShortVector;
6+
import jdk.incubator.vector.VectorSpecies;
7+
import org.jetbrains.annotations.ApiStatus;
8+
9+
@ApiStatus.Internal
10+
public class VectorFacade {
11+
private final IBlocks blocks;
12+
private int layer;
13+
private int index;
14+
private char[] data;
15+
16+
VectorFacade(final IBlocks blocks) {
17+
this.blocks = blocks;
18+
}
19+
20+
public ShortVector get(VectorSpecies<Short> species) {
21+
if (this.data == null) {
22+
load();
23+
}
24+
return ShortVector.fromCharArray(species, this.data, this.index);
25+
}
26+
27+
public ShortVector getOrZero(VectorSpecies<Short> species) {
28+
if (this.data == null) {
29+
return species.zero().reinterpretAsShorts();
30+
}
31+
return ShortVector.fromCharArray(species, this.data, this.index);
32+
}
33+
34+
public void setOrIgnore(ShortVector vector) {
35+
if (this.data == null) {
36+
if (vector.eq((short) BlockTypesCache.ReservedIDs.__RESERVED__).allTrue()) {
37+
return;
38+
}
39+
load();
40+
}
41+
vector.intoCharArray(this.data, this.index);
42+
}
43+
44+
private void load() {
45+
this.data = this.blocks.load(this.layer);
46+
}
47+
48+
public void setLayer(int layer) {
49+
this.layer = layer;
50+
this.data = null;
51+
}
52+
53+
public void setIndex(int index) {
54+
this.index = index;
55+
}
56+
57+
public void setData(char[] data) {
58+
this.data = data;
59+
}
60+
61+
}

worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedCharFilterBlock.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,17 @@ public synchronized void filter(final Filter filter) {
1919
throw new IllegalStateException("Unexpected VectorizedCharFilterBlock " + filter);
2020
}
2121
final VectorSpecies<Short> species = ShortVector.SPECIES_PREFERRED;
22-
// TODO can we avoid eager initSet?
23-
initSet(); // set array is null before
24-
char[] setArr = this.setArr;
25-
assert setArr != null;
26-
char[] getArr = this.getArr;
22+
VectorFacade setFassade = new VectorFacade(this.set);
23+
setFassade.setLayer(this.layer);
24+
VectorFacade getFassade = new VectorFacade(this.get);
25+
getFassade.setLayer(this.layer);
26+
getFassade.setData(this.getArr);
2727
// assume setArr.length == getArr.length == 4096
2828
VectorMask<Short> affectAll = species.maskAll(true);
2929
for (int i = 0; i < 4096; i += species.length()) {
30-
ShortVector set = ShortVector.fromCharArray(species, setArr, i);
31-
ShortVector get = ShortVector.fromCharArray(species, getArr, i);
32-
ShortVector res = vecFilter.applyVector(get, set, affectAll);
33-
res.intoCharArray(setArr, i);
30+
setFassade.setIndex(i);
31+
getFassade.setIndex(i);
32+
vecFilter.applyVector(getFassade, setFassade, affectAll);
3433
}
3534
}
3635
}
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.fastasyncworldedit.core.internal.simd;
22

33
import com.fastasyncworldedit.core.queue.Filter;
4-
import jdk.incubator.vector.ShortVector;
54
import jdk.incubator.vector.VectorMask;
65

76
public interface VectorizedFilter extends Filter {
@@ -12,8 +11,7 @@ public interface VectorizedFilter extends Filter {
1211
* @param get the get vector
1312
* @param set the set vector
1413
* @param mask the mask with the lanes set to true which should be affected by the filter
15-
* @return the resulting set vector.
1614
*/
17-
ShortVector applyVector(ShortVector get, ShortVector set, VectorMask<Short> mask);
15+
void applyVector(VectorFacade get, VectorFacade set, VectorMask<Short> mask);
1816

1917
}

worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/simd/VectorizedMask.java

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,50 @@
1111
public interface VectorizedMask {
1212

1313
default void processChunks(IChunk chunk, IChunkGet get, IChunkSet set) {
14+
VectorFacade setFassade = new VectorFacade(set);
15+
VectorFacade getFassade = new VectorFacade(get);
1416
for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) {
17+
setFassade.setLayer(layer);
18+
getFassade.setLayer(layer);
1519
final char[] sectionSet = set.loadIfPresent(layer);
1620
if (sectionSet == null) {
1721
continue;
1822
}
19-
final char[] sectionGet = get.load(layer);
20-
processSection(layer, sectionSet, sectionGet);
23+
setFassade.setData(sectionSet);
24+
processSection(layer, setFassade, getFassade);
2125
}
2226
}
2327

24-
default void processSection(int layer, char[] set, char[] get) {
28+
default void processSection(int layer, VectorFacade set, VectorFacade get) {
2529
final VectorSpecies<Short> species = ShortVector.SPECIES_PREFERRED;
26-
// assume that set.length % species.elementSize() == 0
27-
for (int i = 0; i < set.length; i += species.length()) {
28-
ShortVector vectorSet = ShortVector.fromCharArray(species, set, i);
29-
ShortVector vectorGet = ShortVector.fromCharArray(species, get, i);
30-
vectorSet = processVector(vectorSet, vectorGet);
31-
vectorSet.intoCharArray(set, i);
30+
// assume that chunk sections have length 16 * 16 * 16 == 4096
31+
for (int i = 0; i < 4096; i += species.length()) {
32+
set.setIndex(i);
33+
get.setIndex(i);
34+
processVector(set, get, species);
3235
}
3336
}
3437

3538
/**
36-
* {@return the set vector with all lanes that do not match this mask set to 0}
39+
* Clears all blocks that aren't covered by the mask.
3740
*
38-
* @param set the set vector
39-
* @param get the get vector
41+
* @param set the set vector
42+
* @param get the get vector
43+
* @param species the species to use
4044
*/
41-
default ShortVector processVector(ShortVector set, ShortVector get) {
42-
return set.blend(BlockTypesCache.ReservedIDs.__RESERVED__, compareVector(set, get).not());
45+
default void processVector(VectorFacade set, VectorFacade get, VectorSpecies<Short> species) {
46+
ShortVector s = set.getOrZero(species);
47+
s = s.blend(BlockTypesCache.ReservedIDs.__RESERVED__, compareVector(set, get, species).not());
48+
set.setOrIgnore(s);
4349
}
4450

4551
/**
4652
* {@return a mask with all lanes set that match this mask}
4753
*
48-
* @param set the set vector
49-
* @param get the get vector
54+
* @param set the set vector
55+
* @param get the get vector
56+
* @param species the species to use
5057
*/
51-
VectorMask<Short> compareVector(ShortVector set, ShortVector get);
58+
VectorMask<Short> compareVector(VectorFacade set, VectorFacade get, VectorSpecies<Short> species);
5259

5360
}

0 commit comments

Comments
 (0)