Fix #4 (Prevent excessive render distances from causing out of memory errors)

This commit is contained in:
James Seibel
2021-06-17 20:27:42 -05:00
parent e380c7c069
commit 799b0e2481
7 changed files with 106 additions and 25 deletions
@@ -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);
@@ -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;
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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. <br><br>
*
* I know there are commands to change that amount
* (specifically "-XX:MaxDirectMemorySize"), but
* I have no idea how to access that amount. <br>
* So I guess this will be the hard limit for now. <br><br>
*
* 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);
}
@@ -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();
}