From 146d9da417a3b98b5c127ca4a2f7ae2ef14f842e Mon Sep 17 00:00:00 2001 From: James Seibel Date: Fri, 20 Oct 2023 19:23:07 -0500 Subject: [PATCH] Fix memory leaks when moving between dimensions --- .../core/render/renderer/LodRenderer.java | 102 +++++++++++------- .../renderer/shaders/DhApplyShader.java | 3 + .../core/sql/DatabaseUpdater.java | 51 ++++++--- 3 files changed, 101 insertions(+), 55 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java index a526dfe62..9ca04ae85 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java @@ -140,6 +140,8 @@ public class LodRenderer private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + private final ReentrantLock setupLock = new ReentrantLock(); + public final RenderBufferHandler bufferHandler; // The shader program @@ -148,9 +150,9 @@ public class LodRenderer public boolean isSetupComplete = false; // frameBuffer and texture ID's for this renderer - private int framebufferId; - private int colorTextureId; - private int depthTextureId; + private int framebufferId = -1; + private int colorTextureId = -1; + private int depthTextureId = -1; @@ -497,21 +499,31 @@ public class LodRenderer return; } - EVENT_LOGGER.info("Setting up renderer"); - this.isSetupComplete = true; - this.shaderProgram = new LodRenderProgram(LodFogConfig.generateFogConfig()); // TODO this doesn't actually use the fog config - if (ENABLE_IBO) + try { - this.quadIBO = new QuadElementBuffer(); - this.quadIBO.reserve(AbstractRenderBuffer.MAX_QUADS_PER_BUFFER); + this.setupLock.lock(); + + + EVENT_LOGGER.info("Setting up renderer"); + this.isSetupComplete = true; + this.shaderProgram = new LodRenderProgram(LodFogConfig.generateFogConfig()); // TODO this doesn't actually use the fog config + if (ENABLE_IBO) + { + this.quadIBO = new QuadElementBuffer(); + this.quadIBO.reserve(AbstractRenderBuffer.MAX_QUADS_PER_BUFFER); + } + + // Generate framebuffer, color texture, and depth render buffer + this.framebufferId = GL32.glGenFramebuffers(); + this.colorTextureId = GL32.glGenTextures(); + this.depthTextureId = GL32.glGenTextures(); + + EVENT_LOGGER.info("Renderer setup complete"); + } + finally + { + this.setupLock.unlock(); } - - // Generate framebuffer, color texture, and depth render buffer - this.framebufferId = GL32.glGenFramebuffers(); - this.colorTextureId = GL32.glGenTextures(); - this.depthTextureId = GL32.glGenTextures(); - - EVENT_LOGGER.info("Renderer setup complete"); } private Color getFogColor(float partialTicks) @@ -561,38 +573,48 @@ public class LodRenderer */ private void cleanup() { - if (!this.isSetupComplete) - { - EVENT_LOGGER.warn("Renderer cleanup called but Renderer has not completed setup!"); - return; - } - if (!GLProxy.hasInstance()) + if (GLProxy.getInstance() == null) { + // shouldn't normally happen, but just in case EVENT_LOGGER.warn("Renderer Cleanup called but the GLProxy has never been initalized!"); return; } - this.isSetupComplete = false; - - GLProxy.getInstance().recordOpenGlCall(() -> + try { - EVENT_LOGGER.info("Renderer Cleanup Started"); + this.setupLock.lock(); + this.isSetupComplete = false; - this.shaderProgram.free(); - this.shaderProgram = null; - if (this.quadIBO != null) + GLProxy.getInstance().recordOpenGlCall(() -> { - this.quadIBO.destroy(false); - } - - // Delete framebuffer, color texture, and depth texture - //GL32.glBindRenderbuffer(GL32.GL_RENDERBUFFER, 0); - GL32.glDeleteFramebuffers(this.framebufferId); - GL32.glDeleteTextures(this.colorTextureId); - GL32.glDeleteTextures(this.depthTextureId); - - EVENT_LOGGER.info("Renderer Cleanup Complete"); - }); + EVENT_LOGGER.info("Renderer Cleanup Started"); + + if (this.shaderProgram != null) + { + this.shaderProgram.free(); + this.shaderProgram = null; + } + + if (this.quadIBO != null) + { + this.quadIBO.destroy(false); + } + + // Delete framebuffer, color texture, and depth texture + if (this.framebufferId != -1) + GL32.glDeleteFramebuffers(this.framebufferId); + if (this.colorTextureId != -1) + GL32.glDeleteTextures(this.colorTextureId); + if (this.depthTextureId != -1) + GL32.glDeleteTextures(this.depthTextureId); + + EVENT_LOGGER.info("Renderer Cleanup Complete"); + }); + } + catch (Exception e) + { + this.setupLock.unlock(); + } } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhApplyShader.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhApplyShader.java index 6b8517197..256f6b3fe 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhApplyShader.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/shaders/DhApplyShader.java @@ -46,6 +46,9 @@ public class DhApplyShader extends AbstractShaderRenderer public int tempDepthTextureId; + + private DhApplyShader() { } + @Override public void onInit() { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/sql/DatabaseUpdater.java b/core/src/main/java/com/seibel/distanthorizons/core/sql/DatabaseUpdater.java index 9b6b4f526..131fb92a8 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/sql/DatabaseUpdater.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/sql/DatabaseUpdater.java @@ -22,6 +22,7 @@ package com.seibel.distanthorizons.core.sql; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import org.apache.logging.log4j.Logger; +import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; @@ -55,7 +56,16 @@ public class DatabaseUpdater public static void runAutoUpdateScripts(AbstractDhRepo repo) throws SQLException { // get the resource scripts - ArrayList scriptList = getAutoUpdateScripts(); + ArrayList scriptList; + try + { + scriptList = getAutoUpdateScripts(); + } + catch (IOException e) + { + LOGGER.error("Get auto update SQL scripts failed. Error: " + e.getMessage(), e); + return; + } @@ -155,25 +165,31 @@ public class DatabaseUpdater //===============// /** @throws NullPointerException if any of the script files failed to be read. */ - private static ArrayList getAutoUpdateScripts() throws NullPointerException + private static ArrayList getAutoUpdateScripts() throws NullPointerException, IOException { final ClassLoader loader = Thread.currentThread().getContextClassLoader(); // get the script list - InputStream scriptListInputStream = loader.getResourceAsStream(SQL_SCRIPT_LIST_FILE); - if (scriptListInputStream == null) + String scriptListString; + try (InputStream scriptListInputStream = loader.getResourceAsStream(SQL_SCRIPT_LIST_FILE)) { - throw new NullPointerException("Failed to find the SQL Script list file ["+SQL_SCRIPT_LIST_FILE+"], no auto update scripts can be run."); + if (scriptListInputStream == null) + { + throw new NullPointerException("Failed to find the SQL Script list file [" + SQL_SCRIPT_LIST_FILE + "], no auto update scripts can be run."); + } + + try (Scanner scanner = new Scanner(scriptListInputStream).useDelimiter("\\A")) + { + scriptListString = scanner.hasNext() ? scanner.next() : ""; + } } - Scanner scanner = new Scanner(scriptListInputStream).useDelimiter("\\A"); - String result = scanner.hasNext() ? scanner.next() : ""; // get each script ArrayList scriptList = new ArrayList<>(); - String[] sqlScriptNames = result.split("\n"); + String[] sqlScriptNames = scriptListString.split("\n"); for (String scriptName : sqlScriptNames) { scriptName = scriptName.trim(); @@ -185,15 +201,20 @@ public class DatabaseUpdater scriptName = SQL_SCRIPT_RESOURCE_FOLDER + scriptName.trim(); // get the script's content - InputStream scriptInputStream = loader.getResourceAsStream(scriptName); - if (scriptInputStream == null) + try(InputStream scriptInputStream = loader.getResourceAsStream(scriptName)) { - throw new NullPointerException("Failed to find the SQL Script file ["+scriptName+"], no auto update scripts can be run."); + if (scriptInputStream == null) + { + throw new NullPointerException("Failed to find the SQL Script file [" + scriptName + "], no auto update scripts can be run."); + } + + try (Scanner fileScanner = new Scanner(scriptInputStream).useDelimiter("\\A")) + { + scriptListString = fileScanner.hasNext() ? fileScanner.next() : ""; + } + + scriptList.add(new SqlScript(scriptName, scriptListString)); } - scanner = new Scanner(scriptInputStream).useDelimiter("\\A"); - result = scanner.hasNext() ? scanner.next() : ""; - - scriptList.add(new SqlScript(scriptName, result)); } return scriptList;