Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-16 16:10:07 +01:00
Introduce basic support for Vector API (#2890)
* Introduce basic support for Vector API * add modules to javadoc too * add assumption comments
Dieser Commit ist enthalten in:
Ursprung
49b063a187
Commit
ea5589b1f0
@ -91,7 +91,7 @@ tasks {
|
||||
minecraftVersion(it)
|
||||
pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
|
||||
.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"
|
||||
runDirectory.set(file("run-$it"))
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
|
||||
options.isDeprecation = true
|
||||
options.encoding = "UTF-8"
|
||||
options.compilerArgs.add("-parameters")
|
||||
options.compilerArgs.add("--add-modules=jdk.incubator.vector")
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
@ -51,12 +52,14 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
|
||||
tasks.withType<Javadoc>().configureEach {
|
||||
(options as StandardJavadocDocletOptions).apply {
|
||||
addStringOption("Xdoclint:none", "-quiet")
|
||||
addStringOption("-add-modules", "jdk.incubator.vector")
|
||||
tags(
|
||||
"apiNote:a:API Note:",
|
||||
"implSpec:a:Implementation Requirements:",
|
||||
"implNote:a:Implementation Note:"
|
||||
)
|
||||
options.encoding = "UTF-8"
|
||||
|
||||
links(
|
||||
"https://jd.advntr.dev/api/latest/",
|
||||
"https://logging.apache.org/log4j/2.x/javadoc/log4j-api/",
|
||||
|
@ -675,6 +675,11 @@ public class Settings extends Config {
|
||||
})
|
||||
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"})
|
||||
|
@ -1,8 +1,10 @@
|
||||
package com.fastasyncworldedit.core.extent.filter;
|
||||
|
||||
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;
|
||||
|
||||
@ -33,4 +35,10 @@ public class CountFilter extends ForkedFilter<CountFilter> {
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortVector applyVector(final ShortVector get, final ShortVector set) {
|
||||
total += set.length();
|
||||
return set;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.FilterBlock;
|
||||
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
|
||||
import com.fastasyncworldedit.core.queue.Filter;
|
||||
import jdk.incubator.vector.ShortVector;
|
||||
|
||||
/**
|
||||
* 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 <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;
|
||||
|
||||
@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) {
|
||||
super(parent);
|
||||
this.child = child;
|
||||
@ -30,8 +40,30 @@ public final class LinkedFilter<T extends Filter, S extends Filter> extends Dele
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.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.sk89q.worldedit.function.mask.AbstractExtentMask;
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -15,8 +22,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
*/
|
||||
public class MaskFilter<T extends Filter> extends DelegateFilter<T> {
|
||||
|
||||
private final Mask mask;
|
||||
private final AtomicInteger changes;
|
||||
final Mask mask;
|
||||
final AtomicInteger changes;
|
||||
|
||||
public MaskFilter(T other, Mask root) {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,12 +23,14 @@ import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.sk89q.worldedit.world.block.BlockTypesCache.states;
|
||||
|
||||
@ApiStatus.NonExtendable
|
||||
public class CharFilterBlock extends ChunkFilterBlock {
|
||||
|
||||
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 CharGetBlocks get;
|
||||
private IChunkSet set;
|
||||
private char[] getArr;
|
||||
protected char[] getArr;
|
||||
@Nullable
|
||||
private char[] setArr;
|
||||
private SetDelegate delegate;
|
||||
protected char[] setArr;
|
||||
protected SetDelegate delegate;
|
||||
// local
|
||||
private int layer;
|
||||
private int index;
|
||||
@ -172,7 +174,7 @@ public class CharFilterBlock extends ChunkFilterBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized final void filter(Filter filter) {
|
||||
public synchronized void filter(Filter filter) {
|
||||
for (y = 0, index = 0; y < 16; y++) {
|
||||
for (z = 0; z < 16; z++) {
|
||||
for (x = 0; x < 16; x++, index++) {
|
||||
@ -395,7 +397,7 @@ public class CharFilterBlock extends ChunkFilterBlock {
|
||||
}
|
||||
|
||||
//Set delegate
|
||||
private SetDelegate initSet() {
|
||||
protected final SetDelegate initSet() {
|
||||
setArr = set.load(layer);
|
||||
return delegate = FULL;
|
||||
}
|
||||
@ -427,7 +429,8 @@ public class CharFilterBlock extends ChunkFilterBlock {
|
||||
return getExtent().setBiome(x, y, z, biome);
|
||||
}
|
||||
|
||||
private interface SetDelegate {
|
||||
@ApiStatus.Internal
|
||||
protected interface SetDelegate {
|
||||
|
||||
void set(@Nonnull CharFilterBlock block, char value);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -2,6 +2,9 @@ package com.fastasyncworldedit.core.queue;
|
||||
|
||||
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
|
||||
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.function.operation.Operation;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
@ -146,8 +149,12 @@ public interface IQueueExtent<T extends IChunk> extends Flushable, Trimable, ICh
|
||||
if (newChunk != null) {
|
||||
chunk = newChunk;
|
||||
if (block == null) {
|
||||
if (SimdSupport.useVectorApi() && filter instanceof VectorizedFilter) {
|
||||
block = new VectorizedCharFilterBlock(this);
|
||||
} else {
|
||||
block = this.createFilterBlock();
|
||||
}
|
||||
}
|
||||
block.initChunk(chunkX, chunkZ);
|
||||
chunk.filterBlocks(filter, block, region, full);
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ import com.fastasyncworldedit.core.extent.processor.BatchProcessorHolder;
|
||||
import com.fastasyncworldedit.core.extent.processor.MultiBatchProcessor;
|
||||
import com.fastasyncworldedit.core.function.mask.BlockMaskBuilder;
|
||||
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.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
@ -223,7 +225,9 @@ public class ParallelQueueExtent extends PassthroughExtent {
|
||||
|
||||
@Override
|
||||
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
|
||||
|
@ -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.FilterBlock;
|
||||
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.IBatchProcessor;
|
||||
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.block.BlockStateHolder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.LongFunction;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -47,6 +50,7 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
|
||||
//FAWE start
|
||||
private final LongFunction<ChunkFilterBlock> getOrCreateFilterBlock;
|
||||
private Mask mask;
|
||||
private @Nullable VectorizedMask vectorizedMask;
|
||||
//FAWE end
|
||||
|
||||
/**
|
||||
@ -59,16 +63,23 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
|
||||
super(extent);
|
||||
checkNotNull(mask);
|
||||
this.mask = mask;
|
||||
this.vectorizedMask = SimdSupport.vectorizedTargetMask(mask);
|
||||
//FAWE start
|
||||
this.getOrCreateFilterBlock = FaweCache.INSTANCE.createMainThreadSafeCache(() -> new CharFilterBlock(getExtent()));
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
//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);
|
||||
checkNotNull(mask);
|
||||
this.mask = mask;
|
||||
this.vectorizedMask = vectorizedMask;
|
||||
this.getOrCreateFilterBlock = getOrCreateFilterBlock;
|
||||
}
|
||||
//FAWE end
|
||||
@ -90,6 +101,7 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
|
||||
public void setMask(Mask mask) {
|
||||
checkNotNull(mask);
|
||||
this.mask = mask;
|
||||
this.vectorizedMask = SimdSupport.vectorizedTargetMask(mask);
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
@ -105,6 +117,10 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
|
||||
|
||||
@Override
|
||||
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());
|
||||
filter.initChunk(chunk.getX(), chunk.getZ());
|
||||
return filter.filter(chunk, get, set, this);
|
||||
@ -122,12 +138,12 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
|
||||
if (child == getExtent()) {
|
||||
return this;
|
||||
}
|
||||
return new MaskingExtent(child, this.mask.copy(), this.getOrCreateFilterBlock);
|
||||
return new MaskingExtent(child, this.mask.copy(), this.getOrCreateFilterBlock, this.vectorizedMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter fork() {
|
||||
return new MaskingExtent(getExtent(), this.mask.copy(), this.getOrCreateFilterBlock);
|
||||
return new MaskingExtent(getExtent(), this.mask.copy(), this.getOrCreateFilterBlock, this.vectorizedMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,7 +22,11 @@ package com.sk89q.worldedit.function.mask;
|
||||
import com.fastasyncworldedit.core.extent.filter.MaskFilter;
|
||||
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
|
||||
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.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -64,7 +68,21 @@ public interface Mask {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
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);
|
||||
}
|
||||
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren