Skip to content

Commit

Permalink
Make a config to manage the max rendering threads for the schematic w…
Browse files Browse the repository at this point in the history
…orld
  • Loading branch information
sakura-ryoko committed Jun 21, 2024
1 parent 09cf584 commit 051c66a
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 36 deletions.
2 changes: 2 additions & 0 deletions src/main/java/fi/dy/masa/litematica/config/Configs.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ public static class Visuals
public static final ConfigBoolean ENABLE_SCHEMATIC_BLOCKS = new ConfigBoolean("enableSchematicBlocksRendering", true, "Enables schematic block rendering.\nDisabling this allows you to only see the color overlay", "Schematic Blocks Rendering");
public static final ConfigBoolean ENABLE_SCHEMATIC_OVERLAY = new ConfigBoolean("enableSchematicOverlay", true, "The main toggle option for the schematic\nblock overlay rendering", "Schematic Overlay Rendering");
public static final ConfigBoolean ENABLE_SCHEMATIC_RENDERING = new ConfigBoolean("enableSchematicRendering", true, "Enable rendering the schematic and overlay", "Schematic Rendering");
public static final ConfigInteger RENDER_SCHEMATIC_MAX_THREADS = new ConfigInteger("renderSchematicMaxThreads", 4, 1, 16, "Maximum Schematic World Rendering Thread Size\nThis will directly effect overall multi-threaded performance\n\n§6USE WITH CAUTION!! This will only take effect\n§6after you leave the game, and rejoin.");
public static final ConfigDouble GHOST_BLOCK_ALPHA = new ConfigDouble( "ghostBlockAlpha", 0.5, 0, 1, "The alpha value of the ghost blocks,\nwhen rendering them as translucent.\n§6Note: §7You also need to enable the translucent rendering separately,\nusing the 'renderBlocksAsTranslucent' option!");
public static final ConfigBoolean IGNORE_EXISTING_FLUIDS = new ConfigBoolean("ignoreExistingFluids", false, "If enabled, then any fluid blocks are ignored as \"extra blocks\"\nand as \"wrong blocks\", ie. where the schematic has air or other blocks.\nBasically this makes building stuff under water a whole lot less annoying.\nNote: You will most likely also want to enable the 'renderCollidingSchematicBlocks'\noption at the same time, to allow the blocks to get rendered inside fluids.");
public static final ConfigBoolean OVERLAY_REDUCED_INNER_SIDES = new ConfigBoolean("overlayReducedInnerSides", false, "If enabled, then the adjacent/touching inner sides\nfor the block overlays are removed/not rendered");
Expand Down Expand Up @@ -189,6 +190,7 @@ public static class Visuals
public static final ImmutableList<IConfigBase> OPTIONS = ImmutableList.of(
ENABLE_RENDERING,
ENABLE_SCHEMATIC_RENDERING,
RENDER_SCHEMATIC_MAX_THREADS,

ENABLE_AREA_SELECTION_RENDERING,
ENABLE_PLACEMENT_BOXES_RENDERING,
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/fi/dy/masa/litematica/render/LitematicaRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ public WorldRendererSchematic getWorldRenderer()
return this.worldRenderer;
}

public WorldRendererSchematic resetWorldRenderer()
{
if (this.worldRenderer != null)
{
this.worldRenderer.setWorldAndLoadRenderers(null);
this.worldRenderer = null;
}

return this.getWorldRenderer();
}

public void loadRenderers()
{
this.getWorldRenderer().loadRenderers();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import net.minecraft.client.util.BufferAllocator;
import net.minecraft.util.math.Vec3d;
import fi.dy.masa.litematica.Litematica;
import fi.dy.masa.litematica.config.Configs;
import fi.dy.masa.litematica.render.schematic.ChunkRendererSchematicVbo.OverlayRenderType;

public class ChunkRenderDispatcherLitematica
Expand All @@ -42,19 +43,17 @@ public class ChunkRenderDispatcherLitematica

public ChunkRenderDispatcherLitematica()
{
// TODO/FIXME 1.17
int threadLimitMemory = Math.max(1, (int)((double)Runtime.getRuntime().maxMemory() * 0.3D) / 10485760);
int threadLimitMemory = Math.max(1, (int) ((double) Runtime.getRuntime().maxMemory() * 0.3D) / BufferAllocatorCache.EXPECTED_TOTAL_SIZE);
int threadLimitCPU = Math.max(1, MathHelper.clamp(Runtime.getRuntime().availableProcessors(), 1, threadLimitMemory / 5));

this.countRenderAllocators = 2;
int maxThreads = Math.max(1, Math.min((Configs.Visuals.RENDER_SCHEMATIC_MAX_THREADS.getIntegerValue()), threadLimitCPU));
int maxCache = Math.max(1, Math.min((Configs.Visuals.RENDER_SCHEMATIC_MAX_THREADS.getIntegerValue() - 1), threadLimitMemory));
this.cameraPos = Vec3d.ZERO;


if (threadLimitCPU > 1)
if (maxThreads > 1)
{
LOGGER.info("Creating {} render threads", threadLimitCPU);
LOGGER.info("Creating {} rendering threads", maxThreads);

for (int i = 0; i < threadLimitCPU; ++i)
for (int i = 0; i < maxThreads; ++i)
{
ChunkRenderWorkerLitematica worker = new ChunkRenderWorkerLitematica(this);
Thread thread = THREAD_FACTORY.newThread(worker);
Expand All @@ -64,15 +63,36 @@ public ChunkRenderDispatcherLitematica()
}
}

LOGGER.info("Using {} total BufferAllocator caches", this.countRenderAllocators + 1);
this.queueFreeRenderAllocators = Queues.newArrayBlockingQueue(maxCache);

this.queueFreeRenderAllocators = Queues.newArrayBlockingQueue(this.countRenderAllocators);

for (int i = 0; i < this.countRenderAllocators; ++i)
for (int i = 0; i < maxCache; ++i)
{
this.queueFreeRenderAllocators.add(new BufferAllocatorCache());
try
{
this.queueFreeRenderAllocators.add(new BufferAllocatorCache());
}
catch (OutOfMemoryError e)
{
LOGGER.warn("Only able to allocate {}/{} BufferAllocator caches", this.queueFreeRenderAllocators.size(), i);
int adjusted = Math.min(this.queueFreeRenderAllocators.size() * 2 / 3, this.queueFreeRenderAllocators.size() - 1);

for (int j = 0; j < adjusted; ++j)
{
try
{
BufferAllocatorCache r = this.queueFreeRenderAllocators.take();
r.close();
}
catch (Exception ignored) { }

maxCache = adjusted;
}
}
}

this.countRenderAllocators = maxCache;
LOGGER.info("Using {} max total BufferAllocator caches", this.countRenderAllocators + 1);

this.renderWorker = new ChunkRenderWorkerLitematica(this, new BufferAllocatorCache());
}

Expand All @@ -89,7 +109,7 @@ public Vec3d getCameraPos()
protected String getDebugInfo()
{
//return this.listWorkerThreads.isEmpty() ? String.format("pC: %03d, single-threaded", this.queueChunkUpdates.size()) : String.format("pC: %03d, pU: %1d, aB: %1d", this.queueChunkUpdates.size(), this.queueChunkUploads.size(), this.queueFreeRenderAllocators.size());
return String.format("pC: %03d, pU: %1d, aB: %1d", this.queueChunkUpdates.size(), this.queueChunkUploads.size(), this.queueFreeRenderAllocators.size());
return String.format("pC: %03d, pU: %03d, aB: %02d", this.queueChunkUpdates.size(), this.queueChunkUploads.size(), this.queueFreeRenderAllocators.size());
}

protected boolean runChunkUploads(long finishTimeNano)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ protected ChunkRenderDataSchematic getChunkRenderData()

protected void setChunkRenderData(ChunkRenderDataSchematic chunkRenderData)
{
if (this.chunkRenderData != null)
{
this.chunkRenderData.closeBuiltBufferCache();
}

this.chunkRenderData = chunkRenderData;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ public class ChunkRendererSchematicVbo implements AutoCloseable
protected ChunkCacheSchematic schematicWorldView;
protected ChunkCacheSchematic clientWorldView;

//private final BufferAllocatorCache allocatorCache;
private final BufferBuilderCache builderCache;

protected AtomicReference<ChunkRenderTaskSchematic> compileTask = new AtomicReference<>(null);
Expand All @@ -77,7 +76,6 @@ protected ChunkRendererSchematicVbo(WorldSchematic world, WorldRendererSchematic
this.vertexBufferOverlay = new IdentityHashMap<>();
this.position = new BlockPos.Mutable();
this.chunkRelativePos = new BlockPos.Mutable();
//this.allocatorCache = new BufferAllocatorCache();
this.builderCache = new BufferBuilderCache();
}

Expand Down Expand Up @@ -107,13 +105,6 @@ protected ChunkRenderDataSchematic getChunkRenderData()
return chunkRenderData.get();
}

/*
protected BufferAllocatorCache getAllocatorCache()
{
return this.allocatorCache;
}
*/

protected BufferBuilderCache getBuilderCache()
{
return this.builderCache;
Expand Down Expand Up @@ -144,8 +135,6 @@ public net.minecraft.util.math.Box getBoundingBox()

protected void setPosition(int x, int y, int z)
{
//Litematica.logger.error("setPosition() [VBO] pos [{}] --> [{} {} {}]", this.position.toShortString(), x, y, z);

if (x != this.position.getX() ||
y != this.position.getY() ||
z != this.position.getZ())
Expand All @@ -168,8 +157,6 @@ protected double getDistanceSq()

protected void deleteGlResources()
{
//Litematica.debugLog("deleteGlResources(): [VBO] for origin [{}]", this.position.toShortString());

this.clear();
this.closeAllVertexBuffers();
//this.world = null;
Expand Down Expand Up @@ -242,15 +229,9 @@ protected void rebuildChunk(ChunkRenderTaskSchematic task)
ChunkRenderDataSchematic data = new ChunkRenderDataSchematic();
task.setChunkRenderData(data);

//this.allocatorCache.clearAll();
this.builderCache.clearAll();
//data.closeBuiltBufferCache();

//Litematica.debugLog("rebuildChunk() [VBO]: bootstrap/clearing all render buffers for chunk origin [{}]", this.position.toShortString());

//this.allocatorCache.clearAll();
this.builderCache.clearAll();
//data.closeBuiltBufferCache();

Set<BlockEntity> tileEntities = new HashSet<>();
BlockPos posChunk = this.position;
Expand Down Expand Up @@ -347,7 +328,7 @@ protected void rebuildChunk(ChunkRenderTaskSchematic task)
}
catch (Exception e)
{
Litematica.logger.error("rebuildChunk() [VBO] failed to postRenderBlocks() for overlay type [{}] --> {}", type.getDrawMode().name(), e.toString());
Litematica.logger.error("rebuildChunk() [VBO] failed to postRenderOverlay() for overlay type [{}] --> {}", type.getDrawMode().name(), e.toString());
}
}
}
Expand Down Expand Up @@ -781,7 +762,10 @@ private BufferBuilderPatch preRenderBlocks(RenderLayer layer, @Nonnull BufferAll

private BufferBuilderPatch preRenderOverlay(OverlayRenderType type, @Nonnull BufferAllocatorCache allocators)
{
//Litematica.logger.warn("postRenderBlocks(): [VBO] for layer [{}] - INIT", ChunkRenderLayers.getFriendlyName(layer));
//Litematica.logger.warn("preRenderOverlay(): [VBO] for overlay type [{}] - INIT", type.getDrawMode().name());

this.existingOverlays.add(type);
this.hasOverlay = true;

RenderSystem.setShader(GameRenderer::getPositionColorProgram);
return this.builderCache.getBufferByOverlay(type, allocators);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ public void setWorldAndLoadRenderers(@Nullable WorldSchematic worldSchematic)
}
else
{
this.chunksToUpdate.forEach(ChunkRendererSchematicVbo::deleteGlResources);
this.chunksToUpdate.clear();
this.renderInfos.forEach(ChunkRendererSchematicVbo::deleteGlResources);
this.renderInfos.clear();

if (this.chunkRendererDispatcher != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,12 @@ public void recreateSchematicWorld(boolean remove)
{
Litematica.debugLog("Removing the schematic world...");
this.world = null;
LitematicaRenderer.getInstance().onSchematicWorldChanged(null);
}
else
{
Litematica.debugLog("(Re-)creating the schematic world...");
@Nullable WorldRendererSchematic worldRenderer = this.world != null ? this.world.worldRenderer : LitematicaRenderer.getInstance().getWorldRenderer();
@Nullable WorldRendererSchematic worldRenderer = this.world != null ? this.world.worldRenderer : LitematicaRenderer.getInstance().resetWorldRenderer();
// Note: The dimension used here must have no skylight, because the custom Chunks don't have those arrays
this.world = createSchematicWorld(worldRenderer);
Litematica.debugLog("Schematic world (re-)created: {}", this.world);
Expand Down

0 comments on commit 051c66a

Please sign in to comment.