Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-17 00:20:09 +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)
|
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"))
|
||||||
}
|
}
|
||||||
|
@ -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/",
|
||||||
|
@ -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"})
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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.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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren