Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-12-25 02:20:07 +01:00
Allow lazy-loading chunk section data when using Vector API
Dieser Commit ist enthalten in:
Ursprung
74bb6e30d2
Commit
678a8ea4a7
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -11,35 +11,41 @@ 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 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,7 +53,8 @@ public interface VectorizedMask {
|
||||
*
|
||||
* @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);
|
||||
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren