Simplify the multi-context uploading, improve stability, and refactor

This commit is contained in:
James Seibel
2021-09-14 22:49:08 -05:00
parent a945eb4579
commit aebbeb6ade
4 changed files with 84 additions and 92 deletions
@@ -82,9 +82,6 @@ public class LodBufferBuilder
*/
public volatile VertexBuffer[][] drawableVbos;
public GlProxyContext buildingContext = GlProxyContext.ALPHA;
public GlProxyContext renderContext = GlProxyContext.BETA;
/**
* if this is true the LOD buffers are currently being
* regenerated.
@@ -459,8 +456,11 @@ public class LodBufferBuilder
*/
private void uploadBuffers(boolean fullRegen, LodDimension lodDim)
{
GlProxy.getInstance().setGlContext(buildingContext);
// used to prevent debug printing multiple times per upload cycle
GlProxy glProxy = GlProxy.getInstance();
// make sure we are uploading to a different OpenGL context,
// to prevent interference (IE stuttering) with the Minecraft context.
glProxy.setGlContext(GlProxyContext.LOD_BUILDER);
// only print console debugging for vboUpload once per upload cycle
boolean bufferMapFail = false;
@@ -481,7 +481,7 @@ public class LodBufferBuilder
// make sure all the buffers have been uploaded.
// this probably is necessary, but it makes me feel good :)
GL11.glFlush();
GlProxy.getInstance().setGlContext(GlProxyContext.NONE);
glProxy.setGlContext(GlProxyContext.NONE);
}
/**
@@ -520,7 +520,7 @@ public class LodBufferBuilder
// only print to console once per upload cycle
if (!bufferMapFail)
ClientProxy.LOGGER.debug("LOD buffer upload glMapBuffer failed, using slower glBufferData.");
ClientProxy.LOGGER.debug("LOD buffer upload: glMapBuffer failed, used slower glBufferData.");
bufferMapFail = true;
}
@@ -547,10 +547,6 @@ public class LodBufferBuilder
drawableVbos = buildableVbos;
buildableVbos = tmpVbo;
GlProxyContext tmpContext = renderContext;
renderContext = buildingContext;
buildingContext = tmpContext;
drawableCenterChunkPos = buildableCenterChunkPos;
// the vbos have been swapped
@@ -558,7 +554,7 @@ public class LodBufferBuilder
bufferLock.unlock();
}
return new VertexBuffersAndOffset(drawableVbos, drawableCenterChunkPos, renderContext);
return new VertexBuffersAndOffset(drawableVbos, drawableCenterChunkPos);
}
/**
@@ -568,13 +564,11 @@ public class LodBufferBuilder
{
public VertexBuffer[][] vbos;
public ChunkPos drawableCenterChunkPos;
public GlProxyContext drawingContext;
public VertexBuffersAndOffset(VertexBuffer[][] newVbos, ChunkPos newDrawableCenterChunkPos, GlProxyContext newDrawingContext)
public VertexBuffersAndOffset(VertexBuffer[][] newVbos, ChunkPos newDrawableCenterChunkPos)
{
vbos = newVbos;
drawableCenterChunkPos = newDrawableCenterChunkPos;
drawingContext = newDrawingContext;
}
}
@@ -27,7 +27,6 @@ import com.seibel.lod.builders.worldGeneration.LodNodeGenWorker;
import com.seibel.lod.builders.worldGeneration.LodWorldGenerator;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.LodDetail;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.LodWorld;
import com.seibel.lod.objects.RegionPos;
@@ -47,15 +46,17 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
/**
* This handles all events sent to the client,
* and is the starting point for most of this program.
* and is the starting point for most of the mod.
*
* @author James_Seibel
* @version 8-24-2021
* @version 9-14-2021
*/
public class ClientProxy
{
public static final Logger LOGGER = LogManager.getLogger("LOD");
private boolean firstTimeSetupComplete = false;
private static LodWorld lodWorld = new LodWorld();
private static LodBuilder lodBuilder = new LodBuilder();
private static LodBufferBuilder lodBufferBuilder = new LodBufferBuilder();
@@ -64,7 +65,7 @@ public class ClientProxy
private boolean configOverrideReminderPrinted = false;
MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
private MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
/**
@@ -99,7 +100,13 @@ public class ClientProxy
*/
public void renderLods(float partialTicks)
{
GlProxy.getInstance();
// only run the first time setup once
if (firstTimeSetupComplete)
{
firstFrameSetup();
}
DetailDistanceUtil.updateSettings();
if (mc == null || mc.getPlayer() == null || !lodWorld.getIsWorldLoaded())
@@ -113,8 +120,6 @@ public class ClientProxy
playerMoveEvent(lodDim);
//System.out.println("memory needed " + lodDim.getMinMemoryNeeded() + " byte");
//System.out.println(lodDim);
lodDim.treeCutter((int) mc.getPlayer().getX(), (int) mc.getPlayer().getZ());
lodDim.treeGenerator((int) mc.getPlayer().getX(), (int) mc.getPlayer().getZ());
@@ -135,7 +140,7 @@ public class ClientProxy
renderer.drawLODs(lodDim, partialTicks, mc.getProfiler());
profiler.pop(); // end LOD
profiler.push("terrain"); // restart "terrain"
profiler.push("terrain"); // go back into "terrain"
// these can't be set until after the buffers are built (in renderer.drawLODs)
@@ -157,8 +162,8 @@ public class ClientProxy
//LodConfig.CLIENT.drawLODs.set(true);
//LodConfig.CLIENT.debugMode.set(true);
LodConfig.CLIENT.graphics.maxDrawDetail.set(LodDetail.FULL);
LodConfig.CLIENT.worldGenerator.maxGenerationDetail.set(LodDetail.FULL);
// LodConfig.CLIENT.graphics.maxDrawDetail.set(LodDetail.FULL);
// LodConfig.CLIENT.worldGenerator.maxGenerationDetail.set(LodDetail.FULL);
// LodConfig.CLIENT.graphics.fogDistance.set(FogDistance.FAR);
// LodConfig.CLIENT.graphics.fogDrawOverride.set(FogDrawOverride.ALWAYS_DRAW_FOG_FANCY);
@@ -167,14 +172,14 @@ public class ClientProxy
// LodConfig.CLIENT.graphics.saturationMultiplier.set(1.0);
// LodConfig.CLIENT.worldGenerator.distanceGenerationMode.set(DistanceGenerationMode.SURFACE);
LodConfig.CLIENT.graphics.lodChunkRenderDistance.set(256);
// LodConfig.CLIENT.graphics.lodChunkRenderDistance.set(64);
// LodConfig.CLIENT.worldGenerator.lodDistanceCalculatorType.set(DistanceCalculatorType.LINEAR);
LodConfig.CLIENT.graphics.lodQuality.set(3);
// LodConfig.CLIENT.graphics.lodQuality.set(2);
// LodConfig.CLIENT.worldGenerator.allowUnstableFeatureGeneration.set(false);
LodConfig.CLIENT.buffers.bufferRebuildPlayerMoveTimeout.set(2000); // 2000
LodConfig.CLIENT.buffers.bufferRebuildChunkChangeTimeout.set(1000); // 1000
LodConfig.CLIENT.buffers.bufferRebuildLodChangeTimeout.set(5000); // 5000
// LodConfig.CLIENT.buffers.bufferRebuildPlayerMoveTimeout.set(2000); // 2000
// LodConfig.CLIENT.buffers.bufferRebuildChunkChangeTimeout.set(1000); // 1000
// LodConfig.CLIENT.buffers.bufferRebuildLodChangeTimeout.set(5000); // 5000
LodConfig.CLIENT.debugging.enableDebugKeybinding.set(true);
}
@@ -267,10 +272,9 @@ public class ClientProxy
}
//==================//
// frame LOD events //
//==================//
//============//
// LOD events //
//============//
/**
* Re-centers the given LodDimension if it needs to be.
@@ -315,6 +319,20 @@ public class ClientProxy
DetailDistanceUtil.updateSettings();
}
/**
* This event is called once during the first frame Minecraft renders in the world.
*/
public void firstFrameSetup()
{
// make sure the GlProxy is created before the LodBufferBuilder
GlProxy.getInstance();
firstTimeSetupComplete = true;
}
//================//
+34 -25
View File
@@ -7,7 +7,8 @@ import org.lwjgl.opengl.WGL;
import com.mojang.blaze3d.systems.RenderSystem;
/**
* A singleton that holds references to different openGL contexts.
* A singleton that holds references to different openGL contexts
* and GPU capabilities.
*
* <p>
* Helpful OpenGL resources: <br><br>
@@ -31,8 +32,13 @@ public class GlProxy
public long lodBuilderGlContext;
public GLCapabilities lodBuilderGlCapabilities;
public long lodRenderGlContext;
public GLCapabilities lodRenderGlCapabilities;
/**
* Does this computer's GPU support fancy fog?
*/
public final boolean fancyFogAvailable;
private GlProxy()
{
@@ -42,6 +48,12 @@ public class GlProxy
throw new IllegalStateException(GlProxy.class.getSimpleName() + " was created outside the render thread!");
//============================//
// create the builder context //
//============================//
minecraftGlContext = WGL.wglGetCurrentContext();
minecraftGlCapabilities = GL.getCapabilities();
deviceContext = WGL.wglGetCurrentDC();
@@ -50,22 +62,28 @@ public class GlProxy
if (!WGL.wglShareLists(minecraftGlContext, lodBuilderGlContext))
throw new IllegalStateException("Unable to share lists between Minecraft and builder contexts.");
if (!WGL.wglMakeCurrent(deviceContext, lodBuilderGlContext))
throw new IllegalStateException("Unable to change OpenGL contexts! tried to change to [" + GlProxyContext.ALPHA.toString() + "] from [" + GlProxyContext.MINECRAFT.toString() + "]");
throw new IllegalStateException("Unable to change OpenGL contexts! tried to change to [" + GlProxyContext.LOD_BUILDER.toString() + "] from [" + GlProxyContext.MINECRAFT.toString() + "]");
lodBuilderGlCapabilities = GL.createCapabilities();
WGL.wglMakeCurrent(deviceContext, 0L);
lodRenderGlContext = WGL.wglCreateContext(deviceContext);
if (!WGL.wglShareLists(minecraftGlContext, lodRenderGlContext))
throw new IllegalStateException("Unable to share lists between builder and render contexts.");
if (!WGL.wglMakeCurrent(deviceContext, lodRenderGlContext))
throw new IllegalStateException("Unable to change OpenGL contexts! tried to change to [" + GlProxyContext.ALPHA.toString() + "] from [" + GlProxyContext.BETA.toString() + "]");
lodRenderGlCapabilities = GL.createCapabilities();
// Since this is called on the render thread, make sure the Minecraft context is used in the end
WGL.wglMakeCurrent(deviceContext, minecraftGlContext);
//==================================//
// get any GPU related capabilities //
//==================================//
// see if this GPU can run fancy fog
fancyFogAvailable = GL.getCapabilities().GL_NV_fog_distance;
if (!fancyFogAvailable)
{
ClientProxy.LOGGER.info("This GPU does not support GL_NV_fog_distance. This means that the fancy fog option will not be available.");
}
}
@@ -80,14 +98,10 @@ public class GlProxy
GLCapabilities newGlCapabilities = null;
switch(context)
{
case ALPHA:
case LOD_BUILDER:
contextPointer = lodBuilderGlContext;
newGlCapabilities = lodBuilderGlCapabilities;
break;
case BETA:
contextPointer = lodRenderGlContext;
newGlCapabilities = lodRenderGlCapabilities;
break;
case MINECRAFT:
contextPointer = minecraftGlContext;
newGlCapabilities = minecraftGlCapabilities;
@@ -111,11 +125,7 @@ public class GlProxy
long currentContext = WGL.wglGetCurrentContext();
if(currentContext == lodBuilderGlContext)
{
return GlProxyContext.ALPHA;
}
else if(currentContext == lodRenderGlContext)
{
return GlProxyContext.BETA;
return GlProxyContext.LOD_BUILDER;
}
else if(currentContext == minecraftGlContext)
{
@@ -130,8 +140,7 @@ public class GlProxy
public enum GlProxyContext
{
MINECRAFT,
ALPHA,
BETA,
LOD_BUILDER,
/** used to un-bind threads */
NONE,
@@ -23,7 +23,6 @@ import java.nio.FloatBuffer;
import java.util.HashSet;
import java.util.Iterator;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL15C;
@@ -95,13 +94,7 @@ public class LodRenderer
* https://stackoverflow.com/questions/50499238/bytebuffer-allocatedirect-and-xmx
*/
public static final int MAX_ALOCATEABLE_DIRECT_MEMORY = 64 * 1024 * 1024;
/**
* Does this computer's GPU support fancy fog?
*/
private static Boolean fancyFogAvailable = null;
private static GlProxy glProxy;
/**
* If true the LODs colors will be replaced with
* a checkerboard, this can be used for debugging.
@@ -189,25 +182,8 @@ public class LodRenderer
profiler = newProfiler;
profiler.push("LOD setup");
// only check the GPU capability's once
if (fancyFogAvailable == null)
{
//TODO add this to the GlProxy
// see if this GPU can run fancy fog
fancyFogAvailable = GL.getCapabilities().GL_NV_fog_distance;
if (!fancyFogAvailable)
{
ClientProxy.LOGGER.info("This GPU does not support GL_NV_fog_distance. This means that fancy fog options will not be available.");
}
// create the GlProxy TODO this should probably be done somewhere else
glProxy = GlProxy.getInstance();
}
// TODO move the buffer regeneration logic into its own class (probably called in the client proxy instead)
// starting here...
determineIfLodsShouldRegenerate(lodDim);
@@ -243,11 +219,6 @@ public class LodRenderer
swapBuffers();
}
if (renderContext == null)
{
return;
}
//===========================//
@@ -738,7 +709,7 @@ public class LodRenderer
// only use fancy fog if the user's GPU can deliver
if (!fancyFogAvailable && quality == FogQuality.FANCY)
if (!GlProxy.getInstance().fancyFogAvailable && quality == FogQuality.FANCY)
{
quality = FogQuality.FAST;
}