Allow parallelisation of masks (#636)

* Allow parallelisation of masks
Increasing performance improvement with increased masking complexity and edit size.

* Address comments
 - Rename Mask#clone to Mask#copy
 - Rename Mask2D#copy to Mask2D#copy2D
 - Correct formatting

* cx -> centerX

* Make various operations relying on a single SingleThreadQueueExtent instance (mainly brushes) thread safe
This commit is contained in:
dordsor21
2020-09-25 15:00:42 +01:00
committed by GitHub
parent 3f1e8fa4d4
commit 855389c785
70 changed files with 893 additions and 266 deletions

View File

@ -44,7 +44,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class MaskingExtent extends AbstractDelegateExtent implements IBatchProcessor, Filter {
private Mask mask;
private LoadingCache<Long, ChunkFilterBlock> threadIdToFilter = FaweCache.IMP.createCache(() -> new CharFilterBlock(getExtent()));
private final LoadingCache<Long, ChunkFilterBlock> threadIdToFilter;
/**
* Create a new instance.
@ -56,6 +56,14 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
super(extent);
checkNotNull(mask);
this.mask = mask;
this.threadIdToFilter = FaweCache.IMP.createCache(() -> new CharFilterBlock(getExtent()));
}
private MaskingExtent(Extent extent, Mask mask, LoadingCache<Long, ChunkFilterBlock> threadIdToFilter) {
super(extent);
checkNotNull(mask);
this.mask = mask;
this.threadIdToFilter = threadIdToFilter;
}
/**
@ -64,7 +72,7 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
* @return the mask
*/
public Mask getMask() {
return mask;
return this.mask;
}
/**
@ -79,38 +87,40 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
return mask.test(location) && super.setBlock(location, block);
return this.mask.test(location) && super.setBlock(location, block);
}
@Override
public boolean setBiome(BlockVector2 position, BiomeType biome) {
return mask.test(position.toBlockVector3()) && super.setBiome(position, biome);
return this.mask.test(position.toBlockVector3()) && super.setBiome(position, biome);
}
@Override
public boolean setBiome(int x, int y, int z, BiomeType biome) {
return mask.test(BlockVector3.at(x, y, z)) && super.setBiome(x, y, z, biome);
return this.mask.test(BlockVector3.at(x, y, z)) && super.setBiome(x, y, z, biome);
}
@Override
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
ChunkFilterBlock filter = threadIdToFilter.getUnchecked(Thread.currentThread().getId());
return filter.filter(chunk, get, set, this);
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
final ChunkFilterBlock filter = threadIdToFilter.getUnchecked(Thread.currentThread().getId());
return filter.filter(chunk, get, set, MaskingExtent.this);
}
@Override
public void applyBlock(FilterBlock block) {
//TODO: Find a way to make masking thread safe without having to synchonise the whole extent
synchronized (this) {
if (!mask.test(block)) {
block.setOrdinal(0);
}
public void applyBlock(final FilterBlock block) {
if (!this.mask.test(block)) {
block.setOrdinal(0);
}
}
@Override
public Extent construct(Extent child) {
if (child == getExtent()) return this;
return new MaskingExtent(child, mask);
return new MaskingExtent(child, this.mask.copy(), this.threadIdToFilter);
}
@Override
public Filter fork() {
return new MaskingExtent(getExtent(), this.mask.copy(), this.threadIdToFilter);
}
}