add RenderManager: improve CPU control with global render queue and parallel trace pooling

This commit is contained in:
2026-06-21 17:49:57 +02:00
parent 220cda1deb
commit f83ccdc7ff
7 changed files with 312 additions and 62 deletions
@@ -7,6 +7,7 @@ import eu.mhsl.minecraft.pixelpics.assets.ResourcePackLoader;
import eu.mhsl.minecraft.pixelpics.assets.TextureCache;
import eu.mhsl.minecraft.pixelpics.commands.PixelPicsCommand;
import eu.mhsl.minecraft.pixelpics.listeners.OnMapInitialize;
import eu.mhsl.minecraft.pixelpics.render.RenderManager;
import eu.mhsl.minecraft.pixelpics.render.render.DefaultScreenRenderer;
import eu.mhsl.minecraft.pixelpics.render.tint.BiomeTintProvider;
import org.bukkit.Bukkit;
@@ -23,6 +24,7 @@ public final class Main extends JavaPlugin {
private ResourcePack resourcePack;
private DefaultScreenRenderer screenRenderer;
private RenderManager renderManager;
public final NamespacedKey pictureIdFlag = new NamespacedKey(this, "imageid");
@@ -37,6 +39,9 @@ public final class Main extends JavaPlugin {
public void onEnable() {
instance = this;
saveDefaultConfig();
initRenderManager();
Bukkit.getPluginManager().registerEvents(new OnMapInitialize(), this);
Objects.requireNonNull(Bukkit.getPluginCommand("pixelPic")).setExecutor(new PixelPicsCommand());
@@ -48,6 +53,20 @@ public final class Main extends JavaPlugin {
initRenderer();
}
private void initRenderManager() {
int cores = Runtime.getRuntime().availableProcessors();
int threads = getConfig().getInt("render.threads", 0);
if (threads <= 0) threads = Math.max(1, cores - 2);
threads = Math.min(threads, cores);
int maxConcurrent = Math.max(1, getConfig().getInt("render.max-concurrent", 2));
int queueSize = Math.max(0, getConfig().getInt("render.queue-size", 8));
int timeoutSeconds = Math.max(1, getConfig().getInt("render.timeout-seconds", 30));
this.renderManager = new RenderManager(this, threads, maxConcurrent, queueSize, timeoutSeconds);
getLogger().info("Render pool: " + threads + " core(s), max " + maxConcurrent
+ " concurrent, queue " + queueSize + ", timeout " + timeoutSeconds + "s.");
}
private void initRenderer() {
File resourcePackDir = new File(getDataFolder(), "resourcepack");
if (!resourcePackDir.exists() && !resourcePackDir.mkdirs()) {
@@ -85,7 +104,8 @@ public final class Main extends JavaPlugin {
eu.mhsl.minecraft.pixelpics.render.entity.cem.BlockEntityBaker blockEntityBaker =
new eu.mhsl.minecraft.pixelpics.render.entity.cem.BlockEntityBaker(cemLoader, textures, skinCache, font);
this.screenRenderer = new DefaultScreenRenderer(registry, tintProvider, textures, entityBaker, blockEntityBaker, getLogger());
this.screenRenderer = new DefaultScreenRenderer(registry, tintProvider, textures, entityBaker,
blockEntityBaker, getLogger(), renderManager.tracePool());
// Warm the map palette on the main thread so off-thread dithering never triggers its first init.
eu.mhsl.minecraft.pixelpics.utils.MapColorPalette.size();
getLogger().info("PixelPics renderer initialized with resource pack assets.");
@@ -94,6 +114,10 @@ public final class Main extends JavaPlugin {
@Override
public void onDisable() {
eu.mhsl.minecraft.pixelpics.survival.SurvivalRecipes.unregister();
if (renderManager != null) {
renderManager.shutdown();
renderManager = null;
}
if (resourcePack != null) {
resourcePack.close();
resourcePack = null;
@@ -105,6 +129,11 @@ public final class Main extends JavaPlugin {
return this.screenRenderer;
}
/** The render queue/limiter; always available after {@code onEnable}. */
public RenderManager getRenderManager() {
return this.renderManager;
}
public static Main getInstance() {
return instance;
}