3
0
Mirror von https://github.com/IntellectualSites/FastAsyncWorldEdit.git synchronisiert 2024-12-24 18:10:08 +01:00

Allow lazy-loading chunk section data when using Vector API

Dieser Commit ist enthalten in:
SirYwell 2024-12-20 10:00:39 +01:00
Ursprung 74bb6e30d2
Commit 678a8ea4a7
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
9 geänderte Dateien mit 124 neuen und 54 gelöschten Zeilen

Datei anzeigen

@ -1,8 +1,8 @@
package com.fastasyncworldedit.core.extent.filter;
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.internal.simd.VectorFacade;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorMask;
public class CountFilter extends ForkedFilter<CountFilter> implements VectorizedFilter {
@ -37,9 +37,8 @@ public class CountFilter extends ForkedFilter<CountFilter> implements Vectorized
}
@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
total += mask.trueCount();
return set;
}
}

Datei anzeigen

@ -1,11 +1,11 @@
package com.fastasyncworldedit.core.extent.filter;
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.internal.simd.VectorFacade;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IChunk;
import com.sk89q.worldedit.regions.Region;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorMask;
import org.jetbrains.annotations.Nullable;
@ -78,9 +78,9 @@ public sealed class LinkedFilter<L extends Filter, R extends Filter> implements
}
@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
ShortVector res = getLeft().applyVector(get, set, mask);
return getRight().applyVector(get, res, mask);
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
getLeft().applyVector(get, set, mask);
getRight().applyVector(get, set, mask);
}
@Override

Datei anzeigen

@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.extent.filter;
import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter;
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.internal.simd.VectorFacade;
import com.fastasyncworldedit.core.internal.simd.SimdSupport;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import com.fastasyncworldedit.core.internal.simd.VectorizedMask;
@ -11,6 +12,7 @@ import com.sk89q.worldedit.function.mask.Mask;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorMask;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
@ -82,13 +84,15 @@ public class MaskFilter<T extends Filter> extends DelegateFilter<T> {
}
@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
final T parent = getParent();
VectorMask<Short> masked = vectorizedMask.compareVector(set, get);
ShortVector res = parent.applyVector(get, set, mask.and(masked));
VectorMask<Short> changed = res.compare(VectorOperators.NE, set);
changes.getAndAdd(changed.trueCount());
return res;
final VectorSpecies<Short> species = mask.vectorSpecies();
VectorMask<Short> masked = this.vectorizedMask.compareVector(set, get, species);
ShortVector before = set.getOrZero(masked.vectorSpecies());
parent.applyVector(get, set, mask.and(masked));
ShortVector after = set.getOrZero(masked.vectorSpecies());
VectorMask<Short> changed = after.compare(VectorOperators.NE, before);
this.changes.getAndAdd(changed.trueCount());
}
@Override

Datei anzeigen

@ -37,14 +37,14 @@ public class CharFilterBlock extends ChunkFilterBlock {
private int maxLayer;
private int minLayer;
private CharGetBlocks get;
private IChunkSet set;
protected CharGetBlocks get;
protected IChunkSet set;
protected char[] getArr;
@Nullable
protected char[] setArr;
protected SetDelegate delegate;
// local
private int layer;
protected int layer;
private int index;
private int x;
private int y;

Datei anzeigen

@ -54,7 +54,7 @@ public class SimdSupport {
if (base == null) {
yield null;
}
yield (set, get) -> base.compareVector(set, get).not();
yield (set, get, species) -> base.compareVector(set, get, species).not();
}
default -> null;
};
@ -62,15 +62,15 @@ public class SimdSupport {
private static VectorizedMask vectorizedTargetMaskNonAir() {
// everything > VOID_AIR is not air
return (set, get) -> get.compare(VectorOperators.UNSIGNED_GT, BlockTypesCache.ReservedIDs.VOID_AIR);
return (set, get, species) -> get.get(species).compare(VectorOperators.UNSIGNED_GT, BlockTypesCache.ReservedIDs.VOID_AIR);
}
private static VectorizedMask vectorizedTargetMask(char ordinal) {
return (set, get) -> get.compare(VectorOperators.EQ, (short) ordinal);
return (set, get, species) -> get.get(species).compare(VectorOperators.EQ, (short) ordinal);
}
private static VectorizedMask vectorizedTargetMaskInverse(char ordinal) {
return (set, get) -> get.compare(VectorOperators.NE, (short) ordinal);
return (set, get, species) -> get.get(species).compare(VectorOperators.NE, (short) ordinal);
}
public static @Nullable VectorizedFilter vectorizedPattern(Pattern pattern) {
@ -102,14 +102,16 @@ public class SimdSupport {
}
@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
// only change the lanes the mask dictates us to change, keep the rest
return set.blend(ShortVector.broadcast(ShortVector.SPECIES_PREFERRED, ordinal), mask);
public Filter newInstance(final Filter other) {
return new VectorizedPattern<>(other, ordinal);
}
@Override
public Filter newInstance(final Filter other) {
return new VectorizedPattern<>(other, ordinal);
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
ShortVector s = set.getOrZero(mask.vectorSpecies());
// only change the lanes the mask dictates us to change, keep the rest
s = s.blend(ShortVector.broadcast(ShortVector.SPECIES_PREFERRED, ordinal), mask);
set.setOrIgnore(s);
}
}

Datei anzeigen

@ -0,0 +1,61 @@
package com.fastasyncworldedit.core.internal.simd;
import com.fastasyncworldedit.core.queue.IBlocks;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorSpecies;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public class VectorFacade {
private final IBlocks blocks;
private int layer;
private int index;
private char[] data;
VectorFacade(final IBlocks blocks) {
this.blocks = blocks;
}
public ShortVector get(VectorSpecies<Short> species) {
if (this.data == null) {
load();
}
return ShortVector.fromCharArray(species, this.data, this.index);
}
public ShortVector getOrZero(VectorSpecies<Short> species) {
if (this.data == null) {
return species.zero().reinterpretAsShorts();
}
return ShortVector.fromCharArray(species, this.data, this.index);
}
public void setOrIgnore(ShortVector vector) {
if (this.data == null) {
if (vector.eq((short) BlockTypesCache.ReservedIDs.__RESERVED__).allTrue()) {
return;
}
load();
}
vector.intoCharArray(this.data, this.index);
}
private void load() {
this.data = this.blocks.load(this.layer);
}
public void setLayer(int layer) {
this.layer = layer;
this.data = null;
}
public void setIndex(int index) {
this.index = index;
}
public void setData(char[] data) {
this.data = data;
}
}

Datei anzeigen

@ -19,18 +19,17 @@ public class VectorizedCharFilterBlock extends CharFilterBlock {
throw new IllegalStateException("Unexpected VectorizedCharFilterBlock " + filter);
}
final VectorSpecies<Short> species = ShortVector.SPECIES_PREFERRED;
// TODO can we avoid eager initSet?
initSet(); // set array is null before
char[] setArr = this.setArr;
assert setArr != null;
char[] getArr = this.getArr;
VectorFacade setFassade = new VectorFacade(this.set);
setFassade.setLayer(this.layer);
VectorFacade getFassade = new VectorFacade(this.get);
getFassade.setLayer(this.layer);
getFassade.setData(this.getArr);
// assume setArr.length == getArr.length == 4096
VectorMask<Short> affectAll = species.maskAll(true);
for (int i = 0; i < 4096; i += species.length()) {
ShortVector set = ShortVector.fromCharArray(species, setArr, i);
ShortVector get = ShortVector.fromCharArray(species, getArr, i);
ShortVector res = vecFilter.applyVector(get, set, affectAll);
res.intoCharArray(setArr, i);
setFassade.setIndex(i);
getFassade.setIndex(i);
vecFilter.applyVector(getFassade, setFassade, affectAll);
}
}
}

Datei anzeigen

@ -1,7 +1,6 @@
package com.fastasyncworldedit.core.internal.simd;
import com.fastasyncworldedit.core.queue.Filter;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorMask;
public interface VectorizedFilter extends Filter {
@ -12,8 +11,7 @@ public interface VectorizedFilter extends Filter {
* @param get the get vector
* @param set the set vector
* @param mask the mask with the lanes set to true which should be affected by the filter
* @return the resulting set vector.
*/
ShortVector applyVector(ShortVector get, ShortVector set, VectorMask<Short> mask);
void applyVector(VectorFacade get, VectorFacade set, VectorMask<Short> mask);
}

Datei anzeigen

@ -11,43 +11,50 @@ import jdk.incubator.vector.VectorSpecies;
public interface VectorizedMask {
default void processChunks(IChunk chunk, IChunkGet get, IChunkSet set) {
VectorFacade setFassade = new VectorFacade(set);
VectorFacade getFassade = new VectorFacade(get);
for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) {
setFassade.setLayer(layer);
getFassade.setLayer(layer);
final char[] sectionSet = set.loadIfPresent(layer);
if (sectionSet == null) {
continue;
}
final char[] sectionGet = get.load(layer);
processSection(layer, sectionSet, sectionGet);
setFassade.setData(sectionSet);
processSection(layer, setFassade, getFassade);
}
}
default void processSection(int layer, char[] set, char[] get) {
default void processSection(int layer, VectorFacade set, VectorFacade get) {
final VectorSpecies<Short> species = ShortVector.SPECIES_PREFERRED;
// assume that set.length % species.elementSize() == 0
for (int i = 0; i < set.length; i += species.length()) {
ShortVector vectorSet = ShortVector.fromCharArray(species, set, i);
ShortVector vectorGet = ShortVector.fromCharArray(species, get, i);
vectorSet = processVector(vectorSet, vectorGet);
vectorSet.intoCharArray(set, i);
// assume that chunk sections have length 16 * 16 * 16 == 4096
for (int i = 0; i < 4096; i += species.length()) {
set.setIndex(i);
get.setIndex(i);
processVector(set, get, species);
}
}
/**
* {@return the set vector with all lanes that do not match this mask set to 0}
* Clears all blocks that aren't covered by the mask.
*
* @param set the set vector
* @param get the get vector
* @param set the set vector
* @param get the get vector
* @param species the species to use
*/
default ShortVector processVector(ShortVector set, ShortVector get) {
return set.blend(BlockTypesCache.ReservedIDs.__RESERVED__, compareVector(set, get).not());
default void processVector(VectorFacade set, VectorFacade get, VectorSpecies<Short> species) {
ShortVector s = set.getOrZero(species);
s = s.blend(BlockTypesCache.ReservedIDs.__RESERVED__, compareVector(set, get, species).not());
set.setOrIgnore(s);
}
/**
* {@return a mask with all lanes set that match this mask}
*
* @param set the set vector
* @param get the get vector
* @param set the set vector
* @param get the get vector
* @param species the species to use
*/
VectorMask<Short> compareVector(ShortVector set, ShortVector get);
VectorMask<Short> compareVector(VectorFacade set, VectorFacade get, VectorSpecies<Short> species);
}