Introduce basic support for Vector API (#2890)

* Introduce basic support for Vector API

* add modules to javadoc too

* add assumption comments
This commit is contained in:
Hannes Greule 2024-09-15 17:00:56 +02:00 committed by GitHub
parent 49b063a187
commit ea5589b1f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 341 additions and 17 deletions

View File

@ -91,7 +91,7 @@ tasks {
minecraftVersion(it) minecraftVersion(it)
pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile } pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
.toTypedArray()) .toTypedArray())
jvmArgs("-DPaper.IgnoreJavaVersion=true", "-Dcom.mojang.eula.agree=true") jvmArgs("-DPaper.IgnoreJavaVersion=true", "-Dcom.mojang.eula.agree=true", "--add-modules=jdk.incubator.vector")
group = "run paper" group = "run paper"
runDirectory.set(file("run-$it")) runDirectory.set(file("run-$it"))
} }

View File

@ -28,6 +28,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
options.isDeprecation = true options.isDeprecation = true
options.encoding = "UTF-8" options.encoding = "UTF-8"
options.compilerArgs.add("-parameters") options.compilerArgs.add("-parameters")
options.compilerArgs.add("--add-modules=jdk.incubator.vector")
} }
configurations.all { configurations.all {
@ -51,12 +52,14 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
tasks.withType<Javadoc>().configureEach { tasks.withType<Javadoc>().configureEach {
(options as StandardJavadocDocletOptions).apply { (options as StandardJavadocDocletOptions).apply {
addStringOption("Xdoclint:none", "-quiet") addStringOption("Xdoclint:none", "-quiet")
addStringOption("-add-modules", "jdk.incubator.vector")
tags( tags(
"apiNote:a:API Note:", "apiNote:a:API Note:",
"implSpec:a:Implementation Requirements:", "implSpec:a:Implementation Requirements:",
"implNote:a:Implementation Note:" "implNote:a:Implementation Note:"
) )
options.encoding = "UTF-8" options.encoding = "UTF-8"
links( links(
"https://jd.advntr.dev/api/latest/", "https://jd.advntr.dev/api/latest/",
"https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/",

View File

@ -675,6 +675,11 @@ public class Settings extends Config {
}) })
public boolean ALLOW_TICK_FLUIDS = false; public boolean ALLOW_TICK_FLUIDS = false;
@Comment({
"Whether FAWE should use the incubator Vector API to accelerate some operations"
})
public boolean USE_VECTOR_API = false;
} }
@Comment({"Web/HTTP connection related settings"}) @Comment({"Web/HTTP connection related settings"})

View File

@ -1,8 +1,10 @@
package com.fastasyncworldedit.core.extent.filter; package com.fastasyncworldedit.core.extent.filter;
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import jdk.incubator.vector.ShortVector;
public class CountFilter extends ForkedFilter<CountFilter> { public class CountFilter extends ForkedFilter<CountFilter> implements VectorizedFilter {
private int total; private int total;
@ -33,4 +35,10 @@ public class CountFilter extends ForkedFilter<CountFilter> {
return total; return total;
} }
@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set) {
total += set.length();
return set;
}
} }

View File

@ -2,7 +2,9 @@ package com.fastasyncworldedit.core.extent.filter;
import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter; import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter;
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.Filter;
import jdk.incubator.vector.ShortVector;
/** /**
* Filter which links two Filters together for single-filter-input operations. * Filter which links two Filters together for single-filter-input operations.
@ -10,10 +12,18 @@ import com.fastasyncworldedit.core.queue.Filter;
* @param <T> Parent which extends Filter * @param <T> Parent which extends Filter
* @param <S> Child which extends Filter * @param <S> Child which extends Filter
*/ */
public final class LinkedFilter<T extends Filter, S extends Filter> extends DelegateFilter<T> { public sealed class LinkedFilter<T extends Filter, S extends Filter> extends DelegateFilter<T> {
private final S child; private final S child;
@SuppressWarnings({"unchecked", "rawtypes"}) // we defeated the type system
public static <T extends Filter, S extends Filter> LinkedFilter<? extends T, ? extends S> of(T parent, S child) {
if (parent instanceof VectorizedFilter p && child instanceof VectorizedFilter c) {
return new VectorizedLinkedFilter(p, c);
}
return new LinkedFilter<>(parent, child);
}
public LinkedFilter(T parent, S child) { public LinkedFilter(T parent, S child) {
super(parent); super(parent);
this.child = child; this.child = child;
@ -30,8 +40,30 @@ public final class LinkedFilter<T extends Filter, S extends Filter> extends Dele
} }
@Override @Override
public LinkedFilter<LinkedFilter<T, S>, Filter> newInstance(Filter other) { public LinkedFilter<? extends LinkedFilter<T, S>, ? extends Filter> newInstance(Filter other) {
return new LinkedFilter<>(this, other); return new LinkedFilter<>(this, other);
} }
private final static class VectorizedLinkedFilter<T extends VectorizedFilter, S extends VectorizedFilter>
extends LinkedFilter<T, S> implements VectorizedFilter {
public VectorizedLinkedFilter(final T parent, final S child) {
super(parent, child);
}
@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set) {
ShortVector res = getParent().applyVector(get, set);
return getChild().applyVector(get, res);
}
@Override
public LinkedFilter<? extends LinkedFilter<T, S>, Filter> newInstance(Filter other) {
if (other instanceof VectorizedFilter o) {
return new VectorizedLinkedFilter(this, o);
}
return new LinkedFilter<>(this, other);
}
}
} }

View File

@ -2,10 +2,17 @@ package com.fastasyncworldedit.core.extent.filter;
import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter; import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter;
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.internal.simd.SimdSupport;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import com.fastasyncworldedit.core.internal.simd.VectorizedMask;
import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.Filter;
import com.sk89q.worldedit.function.mask.AbstractExtentMask; import com.sk89q.worldedit.function.mask.AbstractExtentMask;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorMask;
import jdk.incubator.vector.VectorOperators;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** /**
@ -15,8 +22,8 @@ import java.util.concurrent.atomic.AtomicInteger;
*/ */
public class MaskFilter<T extends Filter> extends DelegateFilter<T> { public class MaskFilter<T extends Filter> extends DelegateFilter<T> {
private final Mask mask; final Mask mask;
private final AtomicInteger changes; final AtomicInteger changes;
public MaskFilter(T other, Mask root) { public MaskFilter(T other, Mask root) {
this(other, root, new AtomicInteger()); this(other, root, new AtomicInteger());
@ -60,4 +67,45 @@ public class MaskFilter<T extends Filter> extends DelegateFilter<T> {
return new MaskFilter<>(getParent().fork(), mask.copy(), changes); return new MaskFilter<>(getParent().fork(), mask.copy(), changes);
} }
public static class VectorizedMaskFilter<T extends VectorizedFilter> extends MaskFilter<T> implements VectorizedFilter {
private final VectorizedMask vectorizedMask;
public VectorizedMaskFilter(final T other, final Mask root) {
super(other, root);
this.vectorizedMask = Objects.requireNonNull(SimdSupport.vectorizedTargetMask(root), "invalid vectorizable mask");
}
public VectorizedMaskFilter(final T other, final Mask root, AtomicInteger changes) {
super(other, root, changes);
this.vectorizedMask = Objects.requireNonNull(SimdSupport.vectorizedTargetMask(root), "invalid vectorizable mask");
}
@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set) {
final T parent = getParent();
VectorMask<Short> masked = vectorizedMask.compareVector(set, get);
ShortVector res = parent.applyVector(get, set);
res = set.blend(res, masked);
VectorMask<Short> changed = res.compare(VectorOperators.NE, set);
changes.getAndAdd(changed.trueCount());
return res;
}
@Override
public MaskFilter<?> newInstance(final Filter other) {
if (other instanceof VectorizedFilter o) {
return new VectorizedMaskFilter<>(o, mask);
}
return super.newInstance(other);
}
@SuppressWarnings("unchecked")
@Override
public Filter fork() {
return new VectorizedMaskFilter<>((T) getParent().fork(), mask.copy(), changes);
}
}
} }

View File

@ -23,12 +23,14 @@ import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import org.enginehub.linbus.tree.LinCompoundTag; import org.enginehub.linbus.tree.LinCompoundTag;
import org.jetbrains.annotations.ApiStatus;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static com.sk89q.worldedit.world.block.BlockTypesCache.states; import static com.sk89q.worldedit.world.block.BlockTypesCache.states;
@ApiStatus.NonExtendable
public class CharFilterBlock extends ChunkFilterBlock { public class CharFilterBlock extends ChunkFilterBlock {
private static final SetDelegate FULL = (block, value) -> block.setArr[block.index] = value; private static final SetDelegate FULL = (block, value) -> block.setArr[block.index] = value;
@ -38,10 +40,10 @@ public class CharFilterBlock extends ChunkFilterBlock {
private int minLayer; private int minLayer;
private CharGetBlocks get; private CharGetBlocks get;
private IChunkSet set; private IChunkSet set;
private char[] getArr; protected char[] getArr;
@Nullable @Nullable
private char[] setArr; protected char[] setArr;
private SetDelegate delegate; protected SetDelegate delegate;
// local // local
private int layer; private int layer;
private int index; private int index;
@ -172,7 +174,7 @@ public class CharFilterBlock extends ChunkFilterBlock {
} }
@Override @Override
public synchronized final void filter(Filter filter) { public synchronized void filter(Filter filter) {
for (y = 0, index = 0; y < 16; y++) { for (y = 0, index = 0; y < 16; y++) {
for (z = 0; z < 16; z++) { for (z = 0; z < 16; z++) {
for (x = 0; x < 16; x++, index++) { for (x = 0; x < 16; x++, index++) {
@ -395,7 +397,7 @@ public class CharFilterBlock extends ChunkFilterBlock {
} }
//Set delegate //Set delegate
private SetDelegate initSet() { protected final SetDelegate initSet() {
setArr = set.load(layer); setArr = set.load(layer);
return delegate = FULL; return delegate = FULL;
} }
@ -427,7 +429,8 @@ public class CharFilterBlock extends ChunkFilterBlock {
return getExtent().setBiome(x, y, z, biome); return getExtent().setBiome(x, y, z, biome);
} }
private interface SetDelegate { @ApiStatus.Internal
protected interface SetDelegate {
void set(@Nonnull CharFilterBlock block, char value); void set(@Nonnull CharFilterBlock block, char value);

View File

@ -0,0 +1,99 @@
package com.fastasyncworldedit.core.internal.simd;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter;
import com.fastasyncworldedit.core.function.mask.SingleBlockStateMask;
import com.fastasyncworldedit.core.queue.Filter;
import com.sk89q.worldedit.function.mask.InverseSingleBlockStateMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorOperators;
import javax.annotation.Nullable;
public class SimdSupport {
private static final boolean VECTOR_API_PRESENT;
static {
boolean vectorApiPresent = false;
try {
Class.forName("jdk.incubator.vector.Vector");
vectorApiPresent = true;
} catch (ClassNotFoundException ignored) {
}
VECTOR_API_PRESENT = vectorApiPresent;
if (!VECTOR_API_PRESENT && Settings.settings().EXPERIMENTAL.USE_VECTOR_API) {
LogManagerCompat.getLogger()
.warn("FAWE use-vector-api is enabled but --add-modules=jdk.incubator.vector is not set.");
}
}
public static boolean useVectorApi() {
return VECTOR_API_PRESENT && Settings.settings().EXPERIMENTAL.USE_VECTOR_API;
}
public static @Nullable VectorizedMask vectorizedTargetMask(Mask mask) {
if (!useVectorApi()) {
return null;
}
return switch (mask) {
case SingleBlockStateMask single -> vectorizedTargetMask(single.getBlockState().getOrdinalChar());
case InverseSingleBlockStateMask inverse -> vectorizedTargetMaskInverse(inverse.getBlockState().getOrdinalChar());
default -> null;
};
}
private static VectorizedMask vectorizedTargetMask(char ordinal) {
return (set, get) -> get.compare(VectorOperators.EQ, (short) ordinal);
}
private static VectorizedMask vectorizedTargetMaskInverse(char ordinal) {
return (set, get) -> get.compare(VectorOperators.NE, (short) ordinal);
}
public static @Nullable VectorizedFilter vectorizedPattern(Pattern pattern) {
if (!useVectorApi()) {
return null;
}
return switch (pattern) {
case BaseBlock block -> {
if (block.getNbtReference() == null) {
yield new VectorizedPattern<>(block, block.getOrdinalChar());
}
yield null;
}
case BlockStateHolder<?> blockStateHolder -> new VectorizedPattern<>(
blockStateHolder,
blockStateHolder.getOrdinalChar()
);
default -> null;
};
}
private static final class VectorizedPattern<T extends Filter> extends DelegateFilter<T> implements VectorizedFilter {
private final char ordinal;
public VectorizedPattern(final T parent, char ordinal) {
super(parent);
this.ordinal = ordinal;
}
@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set) {
return ShortVector.broadcast(ShortVector.SPECIES_PREFERRED, ordinal);
}
@Override
public Filter newInstance(final Filter other) {
return new VectorizedPattern<>(other, ordinal);
}
}
}

View File

@ -0,0 +1,33 @@
package com.fastasyncworldedit.core.internal.simd;
import com.fastasyncworldedit.core.extent.filter.block.CharFilterBlock;
import com.fastasyncworldedit.core.queue.Filter;
import com.sk89q.worldedit.extent.Extent;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorSpecies;
public class VectorizedCharFilterBlock extends CharFilterBlock {
public VectorizedCharFilterBlock(final Extent extent) {
super(extent);
}
@Override
public synchronized void filter(final Filter filter) {
if (!(filter instanceof VectorizedFilter vecFilter)) {
throw new IllegalStateException("Unexpected VectorizedCharFilterBlock " + filter);
}
final VectorSpecies<Short> species = ShortVector.SPECIES_PREFERRED;
initSet(); // set array is null before
char[] setArr = this.setArr;
assert setArr != null;
char[] getArr = this.getArr;
// assume setArr.length == getArr.length == 4096
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);
res.intoCharArray(setArr, i);
}
}
}

View File

@ -0,0 +1,8 @@
package com.fastasyncworldedit.core.internal.simd;
import com.fastasyncworldedit.core.queue.Filter;
import jdk.incubator.vector.ShortVector;
public interface VectorizedFilter extends Filter {
ShortVector applyVector(ShortVector get, ShortVector set);
}

View File

@ -0,0 +1,40 @@
package com.fastasyncworldedit.core.internal.simd;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorMask;
import jdk.incubator.vector.VectorSpecies;
public interface VectorizedMask {
default void processChunks(IChunk chunk, IChunkGet get, IChunkSet set) {
for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) {
final char[] sectionSet = set.loadIfPresent(layer);
if (sectionSet == null) {
continue;
}
final char[] sectionGet = get.load(layer);
processSection(layer, sectionSet, sectionGet);
}
}
default void processSection(int layer, char[] set, char[] 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);
}
}
default ShortVector processVector(ShortVector set, ShortVector get) {
return set.blend(0, compareVector(set, get).not());
}
VectorMask<Short> compareVector(ShortVector set, ShortVector get);
}

View File

@ -2,6 +2,9 @@ package com.fastasyncworldedit.core.queue;
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
import com.fastasyncworldedit.core.extent.processor.IBatchProcessorHolder; import com.fastasyncworldedit.core.extent.processor.IBatchProcessorHolder;
import com.fastasyncworldedit.core.internal.simd.SimdSupport;
import com.fastasyncworldedit.core.internal.simd.VectorizedCharFilterBlock;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
@ -146,8 +149,12 @@ public interface IQueueExtent<T extends IChunk> extends Flushable, Trimable, ICh
if (newChunk != null) { if (newChunk != null) {
chunk = newChunk; chunk = newChunk;
if (block == null) { if (block == null) {
if (SimdSupport.useVectorApi() && filter instanceof VectorizedFilter) {
block = new VectorizedCharFilterBlock(this);
} else {
block = this.createFilterBlock(); block = this.createFilterBlock();
} }
}
block.initChunk(chunkX, chunkZ); block.initChunk(chunkX, chunkZ);
chunk.filterBlocks(filter, block, region, full); chunk.filterBlocks(filter, block, region, full);
} }

View File

@ -14,6 +14,8 @@ import com.fastasyncworldedit.core.extent.processor.BatchProcessorHolder;
import com.fastasyncworldedit.core.extent.processor.MultiBatchProcessor; import com.fastasyncworldedit.core.extent.processor.MultiBatchProcessor;
import com.fastasyncworldedit.core.function.mask.BlockMaskBuilder; import com.fastasyncworldedit.core.function.mask.BlockMaskBuilder;
import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.internal.exception.FaweException;
import com.fastasyncworldedit.core.internal.simd.SimdSupport;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent; import com.fastasyncworldedit.core.queue.IQueueExtent;
@ -223,7 +225,9 @@ public class ParallelQueueExtent extends PassthroughExtent {
@Override @Override
public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
return this.changes = apply(region, new LinkedFilter<>(pattern, new CountFilter()), true).getChild().getTotal(); VectorizedFilter vectorizedPattern = SimdSupport.vectorizedPattern(pattern);
var filter = LinkedFilter.of(vectorizedPattern == null ? pattern : vectorizedPattern, new CountFilter());
return this.changes = apply(region, filter, true).getChild().getTotal();
} }
@Override @Override

View File

@ -24,6 +24,8 @@ import com.fastasyncworldedit.core.extent.filter.block.CharFilterBlock;
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock; import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.fastasyncworldedit.core.internal.simd.SimdSupport;
import com.fastasyncworldedit.core.internal.simd.VectorizedMask;
import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunk; import com.fastasyncworldedit.core.queue.IChunk;
@ -35,6 +37,7 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nullable;
import java.util.function.LongFunction; import java.util.function.LongFunction;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -47,6 +50,7 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
//FAWE start //FAWE start
private final LongFunction<ChunkFilterBlock> getOrCreateFilterBlock; private final LongFunction<ChunkFilterBlock> getOrCreateFilterBlock;
private Mask mask; private Mask mask;
private @Nullable VectorizedMask vectorizedMask;
//FAWE end //FAWE end
/** /**
@ -59,16 +63,23 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
super(extent); super(extent);
checkNotNull(mask); checkNotNull(mask);
this.mask = mask; this.mask = mask;
this.vectorizedMask = SimdSupport.vectorizedTargetMask(mask);
//FAWE start //FAWE start
this.getOrCreateFilterBlock = FaweCache.INSTANCE.createMainThreadSafeCache(() -> new CharFilterBlock(getExtent())); this.getOrCreateFilterBlock = FaweCache.INSTANCE.createMainThreadSafeCache(() -> new CharFilterBlock(getExtent()));
//FAWE end //FAWE end
} }
//FAWE start //FAWE start
private MaskingExtent(Extent extent, Mask mask, LongFunction<ChunkFilterBlock> getOrCreateFilterBlock) { private MaskingExtent(
Extent extent,
Mask mask,
LongFunction<ChunkFilterBlock> getOrCreateFilterBlock,
@Nullable VectorizedMask vectorizedMask
) {
super(extent); super(extent);
checkNotNull(mask); checkNotNull(mask);
this.mask = mask; this.mask = mask;
this.vectorizedMask = vectorizedMask;
this.getOrCreateFilterBlock = getOrCreateFilterBlock; this.getOrCreateFilterBlock = getOrCreateFilterBlock;
} }
//FAWE end //FAWE end
@ -90,6 +101,7 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
public void setMask(Mask mask) { public void setMask(Mask mask) {
checkNotNull(mask); checkNotNull(mask);
this.mask = mask; this.mask = mask;
this.vectorizedMask = SimdSupport.vectorizedTargetMask(mask);
} }
//FAWE start //FAWE start
@ -105,6 +117,10 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
@Override @Override
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
if (this.vectorizedMask != null) {
this.vectorizedMask.processChunks(chunk, get, set);
return set;
}
final ChunkFilterBlock filter = getOrCreateFilterBlock.apply(Thread.currentThread().getId()); final ChunkFilterBlock filter = getOrCreateFilterBlock.apply(Thread.currentThread().getId());
filter.initChunk(chunk.getX(), chunk.getZ()); filter.initChunk(chunk.getX(), chunk.getZ());
return filter.filter(chunk, get, set, this); return filter.filter(chunk, get, set, this);
@ -122,12 +138,12 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
if (child == getExtent()) { if (child == getExtent()) {
return this; return this;
} }
return new MaskingExtent(child, this.mask.copy(), this.getOrCreateFilterBlock); return new MaskingExtent(child, this.mask.copy(), this.getOrCreateFilterBlock, this.vectorizedMask);
} }
@Override @Override
public Filter fork() { public Filter fork() {
return new MaskingExtent(getExtent(), this.mask.copy(), this.getOrCreateFilterBlock); return new MaskingExtent(getExtent(), this.mask.copy(), this.getOrCreateFilterBlock, this.vectorizedMask);
} }
@Override @Override

View File

@ -22,7 +22,11 @@ package com.sk89q.worldedit.function.mask;
import com.fastasyncworldedit.core.extent.filter.MaskFilter; import com.fastasyncworldedit.core.extent.filter.MaskFilter;
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.function.mask.InverseMask; import com.fastasyncworldedit.core.function.mask.InverseMask;
import com.fastasyncworldedit.core.internal.simd.SimdSupport;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import com.fastasyncworldedit.core.internal.simd.VectorizedMask;
import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.Filter;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -64,7 +68,21 @@ public interface Mask {
return null; return null;
} }
@SuppressWarnings({"unchecked", "rawtypes"})
default <T extends Filter> MaskFilter<T> toFilter(T filter) { default <T extends Filter> MaskFilter<T> toFilter(T filter) {
final VectorizedMask mask = SimdSupport.vectorizedTargetMask(this);
if (mask != null) {
VectorizedFilter vectorizedFilter = null;
if (filter instanceof VectorizedFilter vf) {
vectorizedFilter = vf;
} else if (filter instanceof Pattern p) {
vectorizedFilter = SimdSupport.vectorizedPattern(p);
}
if (vectorizedFilter != null) {
// also pass original?
return new MaskFilter.VectorizedMaskFilter(vectorizedFilter, this);
}
}
return new MaskFilter<>(filter, this); return new MaskFilter<>(filter, this);
} }