From 799b0e24812e21d6d7c15cec53721a7305691b45 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Thu, 17 Jun 2021 20:27:42 -0500 Subject: [PATCH] Fix #4 (Prevent excessive render distances from causing out of memory errors) --- .../lodTemplates/AbstractLodTemplate.java | 7 +- .../lodTemplates/CubicLodTemplate.java | 10 ++- .../lodTemplates/DynamicLodTemplate.java | 9 +- .../lodTemplates/TriangularLodTemplate.java | 9 +- .../com/seibel/lod/enums/LodTemplate.java | 8 +- .../java/com/seibel/lod/render/LodRender.java | 82 +++++++++++++++---- .../java/com/seibel/lod/util/LodConfig.java | 6 +- 7 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java index 80f1607aa..a4f7031e2 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java @@ -1,5 +1,6 @@ package com.seibel.lod.builders.lodTemplates; +import com.seibel.lod.enums.LodDetail; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; @@ -10,7 +11,7 @@ import net.minecraft.client.renderer.BufferBuilder; * BufferBuilders. * * @author James Seibel - * @version 06-12-2021 + * @version 06-16-2021 */ public abstract class AbstractLodTemplate { @@ -27,7 +28,9 @@ public abstract class AbstractLodTemplate buffer.pos(x, y, z).color(red, green, blue, alpha).endVertex(); } - + /** Returns in bytes how much buffer memory is required + * for one LOD object */ + public abstract int getBufferMemoryForSingleLod(LodDetail detail); diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java index 832f1ed77..8ac0c8ae4 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java @@ -15,7 +15,7 @@ import net.minecraft.util.math.AxisAlignedBB; * Builds LODs as rectangular prisms. * * @author James Seibel - * @version 06-13-2021 + * @version 06-16-2021 */ public class CubicLodTemplate extends AbstractLodTemplate { @@ -159,6 +159,14 @@ public class CubicLodTemplate extends AbstractLodTemplate addPosAndColor(buffer, bb.maxX, bb.minY, bb.maxZ, c[ColorDirection.EAST.value].getRed(), c[ColorDirection.EAST.value].getGreen(), c[ColorDirection.EAST.value].getBlue(), c[ColorDirection.EAST.value].getAlpha()); addPosAndColor(buffer, bb.maxX, bb.minY, bb.minZ, c[ColorDirection.EAST.value].getRed(), c[ColorDirection.EAST.value].getGreen(), c[ColorDirection.EAST.value].getBlue(), c[ColorDirection.EAST.value].getAlpha()); } + + + @Override + public int getBufferMemoryForSingleLod(LodDetail detail) + { + // (sidesOnACube * pointsInASquare * (positionPoints + colorPoints))) * howManyPointsPerLodChunk + return (6 * 4 * (3 + 4)) * detail.lengthCount * detail.lengthCount; + } diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java index 0a66fdf9b..7203aa273 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java @@ -1,5 +1,6 @@ package com.seibel.lod.builders.lodTemplates; +import com.seibel.lod.enums.LodDetail; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; @@ -12,7 +13,7 @@ import net.minecraft.client.renderer.BufferBuilder; * is at a significantly different height. * * @author James Seibel - * @version 05-07-2021 + * @version 06-16-2021 */ public class DynamicLodTemplate extends AbstractLodTemplate { @@ -24,4 +25,10 @@ public class DynamicLodTemplate extends AbstractLodTemplate { System.err.println("DynamicLodTemplate not implemented!"); } + + @Override + public int getBufferMemoryForSingleLod(LodDetail detail) { + // TODO Auto-generated method stub + return 0; + } } diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java index 66c9e9288..d1188f6ba 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java @@ -1,5 +1,6 @@ package com.seibel.lod.builders.lodTemplates; +import com.seibel.lod.enums.LodDetail; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; @@ -10,7 +11,7 @@ import net.minecraft.client.renderer.BufferBuilder; * Builds each LOD chunk as a singular rectangular prism. * * @author James Seibel - * @version 05-07-2021 + * @version 06-16-2021 */ public class TriangularLodTemplate extends AbstractLodTemplate { @@ -22,4 +23,10 @@ public class TriangularLodTemplate extends AbstractLodTemplate { System.err.println("DynamicLodTemplate not implemented!"); } + + @Override + public int getBufferMemoryForSingleLod(LodDetail detail) { + // TODO Auto-generated method stub + return 0; + } } diff --git a/src/main/java/com/seibel/lod/enums/LodTemplate.java b/src/main/java/com/seibel/lod/enums/LodTemplate.java index 71aaa0fa4..f9dc4e867 100644 --- a/src/main/java/com/seibel/lod/enums/LodTemplate.java +++ b/src/main/java/com/seibel/lod/enums/LodTemplate.java @@ -9,7 +9,7 @@ import com.seibel.lod.builders.lodTemplates.TriangularLodTemplate; * Cubic, Triangular, Dynamic * * @author James Seibel - * @version 05-07-2021 + * @version 06-16-2021 */ public enum LodTemplate { @@ -35,4 +35,10 @@ public enum LodTemplate { template = newTemplate; } + + + public int getBufferMemoryForSingleLod(LodDetail detail) + { + return template.getBufferMemoryForSingleLod(detail); + } } diff --git a/src/main/java/com/seibel/lod/render/LodRender.java b/src/main/java/com/seibel/lod/render/LodRender.java index da6c879c0..96c84d693 100644 --- a/src/main/java/com/seibel/lod/render/LodRender.java +++ b/src/main/java/com/seibel/lod/render/LodRender.java @@ -13,11 +13,14 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.seibel.lod.builders.LodBufferBuilder; import com.seibel.lod.enums.FogDistance; import com.seibel.lod.enums.FogQuality; +import com.seibel.lod.enums.LodDetail; +import com.seibel.lod.enums.LodTemplate; import com.seibel.lod.handlers.ReflectionHandler; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; import com.seibel.lod.objects.NearFarBuffer; import com.seibel.lod.objects.NearFarFogSetting; +import com.seibel.lod.proxy.ClientProxy; import com.seibel.lod.util.LodConfig; import net.minecraft.client.Minecraft; @@ -45,14 +48,28 @@ import net.minecraft.util.math.vector.Vector3f; * This is where LODs are draw to the world. * * @author James Seibel - * @version 05-08-2021 + * @version 06-17-2021 */ public class LodRender { /** this is the light used when rendering the LODs, * it should be something different than what is used by Minecraft */ private static final int LOD_GL_LIGHT_NUMBER = GL11.GL_LIGHT2; - + + /** + * 64 MB by default is the maximum amount of memory that + * can be directly allocated.

+ * + * I know there are commands to change that amount + * (specifically "-XX:MaxDirectMemorySize"), but + * I have no idea how to access that amount.
+ * So I guess this will be the hard limit for now.

+ * + * https://stackoverflow.com/questions/50499238/bytebuffer-allocatedirect-and-xmx + */ + public static final int MAX_ALOCATEABLE_DIRECT_MEMORY = 64 * 1024 * 1024; + + /** If true the LODs colors will be replaced with * a checkerboard, this can be used for debugging. */ public boolean debugging = false; @@ -114,7 +131,6 @@ public class LodRender * @param newDimension The dimension to draw, if null doesn't replace the current dimension. * @param partialTicks how far into the current tick this method was called. */ - @SuppressWarnings("deprecation") public void drawLODs(LodDimension lodDim, float partialTicks, IProfiler newProfiler) { if (lodDim == null) @@ -493,7 +509,6 @@ public class LodRender /** * setup the lighting to be used for the LODs */ - @SuppressWarnings("deprecation") private void setupLighting(LodDimension lodDimension, float partialTicks) { float sunBrightness = lodDimension.dimension.hasSkyLight() ? mc.world.getSunBrightness(partialTicks) : 0.2f; @@ -510,28 +525,63 @@ public class LodRender RenderSystem.enableLighting(); } - /** * Create all buffers that will be used. */ private void setupBuffers(int numbChunksWide) { - // calculate the max amount of storage needed (in bytes) - int bufferMaxCapacity = (numbChunksWide * numbChunksWide * (6 * 4 * (3 + 4))); - // (numbChunksWide * numbChunksWide * - // (sidesOnACube * pointsInASquare * (positionPoints + colorPoints))) + // calculate the max amount of memory needed (in bytes) + int bufferMemory = getBufferMemoryForRadiusMultiplier(LodConfig.CLIENT.lodChunkRadiusMultiplier.get()); - // TODO complain or do something when memory is too low - // currently the VM will just crash and complain there is no more memory - // issue #4 - drawableNearBuffer = new BufferBuilder(bufferMaxCapacity); - drawableFarBuffer = new BufferBuilder(bufferMaxCapacity); + // if the required memory is greater than the + // MAX_ALOCATEABLE_DIRECT_MEMORY lower the lodChunkRadiusMultiplier + // to fit. + if (bufferMemory > MAX_ALOCATEABLE_DIRECT_MEMORY) + { + int maxRadiusMultiplier = getMaxRadiusMultiplierWithAvaliableMemory(LodConfig.CLIENT.lodTemplate.get(), LodConfig.CLIENT.lodDetail.get()); + + ClientProxy.LOGGER.warn("The lodChunkRadiusMultiplier was set too high " + + "and had to be lowered to fit memory constraints " + + "from " + LodConfig.CLIENT.lodChunkRadiusMultiplier.get() + " " + + "to " + maxRadiusMultiplier); + + LodConfig.CLIENT.lodChunkRadiusMultiplier.set( + maxRadiusMultiplier); + + bufferMemory = getBufferMemoryForRadiusMultiplier(maxRadiusMultiplier); + } - lodBufferBuilder.setupBuffers(bufferMaxCapacity); + drawableNearBuffer = new BufferBuilder(bufferMemory); + drawableFarBuffer = new BufferBuilder(bufferMemory); + + lodBufferBuilder.setupBuffers(bufferMemory); } + /** + * Get how much buffer memory would be required for the given radius multiplier + */ + public int getBufferMemoryForRadiusMultiplier(int radiusMultiplier) + { + int numbChunksWide = mc.gameSettings.renderDistanceChunks * + radiusMultiplier * 2; + + // calculate the max amount of buffer memory needed (in bytes) + return numbChunksWide * numbChunksWide * + LodConfig.CLIENT.lodTemplate.get(). + getBufferMemoryForSingleLod(LodConfig.CLIENT.lodDetail.get()); + } - + /** + * Returns the maxViewDistanceMultiplier for the given LodTemplate + * at the given LodDetail level. + */ + public int getMaxRadiusMultiplierWithAvaliableMemory(LodTemplate lodTemplate, LodDetail lodDetail) + { + int maxNumberOfLods = MAX_ALOCATEABLE_DIRECT_MEMORY / lodTemplate.getBufferMemoryForSingleLod(lodDetail); + int numbLodsWide = (int) Math.sqrt(maxNumberOfLods); + + return numbLodsWide / (2 * mc.gameSettings.renderDistanceChunks); + } diff --git a/src/main/java/com/seibel/lod/util/LodConfig.java b/src/main/java/com/seibel/lod/util/LodConfig.java index 6d6bb4d08..c0fb26fac 100644 --- a/src/main/java/com/seibel/lod/util/LodConfig.java +++ b/src/main/java/com/seibel/lod/util/LodConfig.java @@ -21,7 +21,7 @@ import net.minecraftforge.fml.config.ModConfig; /** * * @author James Seibel - * @version 6-13-2021 + * @version 6-17-2021 */ @Mod.EventBusSubscriber public class LodConfig @@ -89,8 +89,8 @@ public class LodConfig + " This is multiplied by the default view distance \n" + " to determine how far out to generate/render LODs. \n" + " A value of 2 means that there is 1 render distance worth \n" - + " of LODs in each cardinal direction.") - .defineInRange("lodChunkRadiusMultiplier", 6, 2, 1023); + + " of LODs in each cardinal direction. ") + .defineInRange("lodChunkRadiusMultiplier", 6, 2, 32); builder.pop(); }