Add a LodRender OpenGL context

This commit is contained in:
James Seibel
2021-10-31 15:52:18 -05:00
parent 3e3e1a7cf2
commit b29dac3753
4 changed files with 124 additions and 87 deletions
@@ -20,10 +20,10 @@
package com.seibel.lod.enums;
/**
* Minecraft, Lod_Builder, None
* Minecraft, Lod_Builder, Lod_Render, None
*
* @author James Seibel
* @version 10-1-2021
* @version 10-31-2021
*/
public enum GlProxyContext
{
@@ -33,6 +33,9 @@ public enum GlProxyContext
/** The context we send buffers to the GPU on */
LOD_BUILDER,
/** The context we draw LODs on */
LOD_RENDER,
/** used to un-bind threads */
NONE,
}
@@ -31,6 +31,7 @@ import com.seibel.lod.builders.worldGeneration.LodGenWorker;
import com.seibel.lod.builders.worldGeneration.LodWorldGenerator;
import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.GlProxyContext;
import com.seibel.lod.objects.LodDimension;
import com.seibel.lod.objects.LodWorld;
import com.seibel.lod.objects.RegionPos;
@@ -55,18 +56,12 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
* This handles all events sent to the client,
* and is the starting point for most of the mod.
* @author James_Seibel
* @version 10-23-2021
* @version 10-31-2021
*/
public class ClientProxy
{
public static final Logger LOGGER = LogManager.getLogger("LOD");
/**
* there is some setup that should only happen once,
* once this is true that setup has completed
*/
private boolean firstTimeSetupComplete = false;
private static final LodWorld lodWorld = new LodWorld();
private static final LodBuilder lodBuilder = new LodBuilder();
private static final LodBufferBuilder lodBufferBuilder = new LodBufferBuilder();
@@ -108,13 +103,11 @@ public class ClientProxy
// clear any out of date objects
mc.clearFrameObjectCache();
// make sure the GlProxy is created before the LodBufferBuilder needs it
GlProxy glProxy = GlProxy.getInstance();
try
{
// only run the first time setup once
if (!firstTimeSetupComplete)
firstFrameSetup();
if (mc == null || mc.getPlayer() == null || lodWorld.getIsWorldNotLoaded())
return;
@@ -138,6 +131,7 @@ public class ClientProxy
profiler.pop(); // get out of "terrain"
profiler.push("LOD");
glProxy.setGlContext(GlProxyContext.LOD_RENDER);
renderer.drawLODs(lodDim, mcModelViewMatrix, partialTicks, mc.getProfiler());
profiler.pop(); // end LOD
@@ -154,6 +148,10 @@ public class ClientProxy
LOGGER.error("client proxy: " + e.getMessage());
e.printStackTrace();
}
finally
{
glProxy.setGlContext(GlProxyContext.MINECRAFT);
}
}
/** used in a development environment to change settings on the fly */
@@ -357,16 +355,6 @@ 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 needs it
GlProxy.getInstance();
firstTimeSetupComplete = true;
}
/** this method reset some static data every time we change world */
private void resetMod()
{
+76 -43
View File
@@ -21,6 +21,7 @@ package com.seibel.lod.proxy;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GLCapabilities;
import com.mojang.blaze3d.systems.RenderSystem;
@@ -40,7 +41,7 @@ import com.seibel.lod.wrappers.MinecraftWrapper;
* https://gamedev.stackexchange.com/questions/91995/edit-vbo-data-or-create-a-new-one <br><br>
*
* @author James Seibel
* @version 10-23-2021
* @version 10-31-2021
*/
public class GlProxy
{
@@ -50,14 +51,19 @@ public class GlProxy
/** Minecraft's GLFW window */
public final long minecraftGlContext;
/** Minecraft's GL context */
/** Minecraft's GL capabilities */
public final GLCapabilities minecraftGlCapabilities;
/** the LodBuilder's GLFW window */
public final long lodBuilderGlContext;
/** the LodBuilder's GL context */
/** the LodBuilder's GL capabilities */
public final GLCapabilities lodBuilderGlCapabilities;
/** the LodRender's GLFW window */
public final long lodRenderGlContext;
/** the LodRender's GL capabilities */
public final GLCapabilities lodRenderGlCapabilities;
/**
* This is just used for debugging, hopefully it can be removed once
* the context switching is more stable.
@@ -93,44 +99,27 @@ public class GlProxy
minecraftGlContext = GLFW.glfwGetCurrentContext();
minecraftGlCapabilities = GL.getCapabilities();
// create the LodBuilder's context
// Hopefully this shouldn't cause any issues with other mods that need custom contexts
// (although the number that do should be relatively few)
// context creation setup
GLFW.glfwDefaultWindowHints();
// make the context window invisible
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
// by default the context should get the highest available OpenGL version
// but this can be explicitly set for testing
// GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4);
// GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 5);
// create an invisible window to hold the context
lodBuilderGlCapabilities = GL.createCapabilities();
lodBuilderGlContext = GLFW.glfwCreateWindow(640, 480, "LOD window", 0L, minecraftGlContext);
// create the LodRender context
lodRenderGlContext = GLFW.glfwCreateWindow(64, 48, "LOD Render Window", 0L, 0L); // create a window to hold the context
GLFW.glfwMakeContextCurrent(lodRenderGlContext);
lodRenderGlCapabilities = GL.createCapabilities();
// create the LodBuilder context
lodBuilderGlContext = GLFW.glfwCreateWindow(64, 48, "LOD Builder Window", 0L, lodRenderGlContext);
GLFW.glfwMakeContextCurrent(lodBuilderGlContext);
lodBuilderGlCapabilities = GL.createCapabilities();
// Since this is called on the render thread, make sure the Minecraft context is used in the end
GLFW.glfwMakeContextCurrent(minecraftGlContext);
GL.setCapabilities(minecraftGlCapabilities);
//==============================//
// determine the OpenGL version //
//==============================//
bufferStorageSupported = minecraftGlCapabilities.glBufferStorage != 0;
mapBufferRangeSupported = minecraftGlCapabilities.glMapBufferRange != 0;
if (!minecraftGlCapabilities.OpenGL15)
{
String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GlProxy.class.getSimpleName() + " and discoverd this GPU doesn't support OpenGL 1.5 or greater.";
mc.crashMinecraft(errorMessage + " Sorry I couldn't tell you sooner :(", new UnsupportedOperationException("This GPU doesn't support OpenGL 1.5 or greater."));
}
if (!bufferStorageSupported)
{
String fallBackVersion = mapBufferRangeSupported ? "3.0" : "1.5";
ClientProxy.LOGGER.error("This GPU doesn't support Buffer Storage (OpenGL 4.5), falling back to OpenGL " + fallBackVersion + ". This may cause stuttering and reduced performance.");
}
@@ -139,8 +128,31 @@ public class GlProxy
// get any GPU related capabilities //
//==================================//
// see if this GPU can run fancy fog
fancyFogAvailable = GL.getCapabilities().GL_NV_fog_distance;
ClientProxy.LOGGER.info("Lod Render OpenGL version [" + GL11.glGetString(GL11.GL_VERSION) + "].");
// crash the game if the GPU doesn't support OpenGL 1.5
if (!minecraftGlCapabilities.OpenGL15)
{
// Note: as of MC 1.17 this shouldn't happen since MC
// requires OpenGL 3.3, but just in case.
String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GlProxy.class.getSimpleName() + " and discoverd this GPU doesn't support OpenGL 1.5 or greater.";
mc.crashMinecraft(errorMessage + " Sorry I couldn't tell you sooner :(", new UnsupportedOperationException("This GPU doesn't support OpenGL 1.5 or greater."));
}
// get specific capabilities
bufferStorageSupported = lodBuilderGlCapabilities.glBufferStorage != 0;
mapBufferRangeSupported = lodBuilderGlCapabilities.glMapBufferRange != 0;
fancyFogAvailable = minecraftGlCapabilities.GL_NV_fog_distance;
// display the capabilities
if (!bufferStorageSupported)
{
String fallBackVersion = mapBufferRangeSupported ? "3.0" : "1.5";
ClientProxy.LOGGER.error("This GPU doesn't support Buffer Storage (OpenGL 4.5), falling back to OpenGL " + fallBackVersion + ". This may cause stuttering and reduced performance.");
}
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.");
@@ -148,6 +160,16 @@ public class GlProxy
//==========//
// clean up //
//==========//
// Since this is created on the render thread, make sure the Minecraft context is used in the end
GLFW.glfwMakeContextCurrent(minecraftGlContext);
GL.setCapabilities(minecraftGlCapabilities);
// GlProxy creation success
ClientProxy.LOGGER.error(GlProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day.");
}
@@ -163,12 +185,12 @@ public class GlProxy
{
GlProxyContext currentContext = getGlContext();
// we don't have to change the context, we're already there.
// we don't have to change the context, we are already there.
if (currentContext == newContext)
return;
long contextPointer = 0L;
long contextPointer;
GLCapabilities newGlCapabilities = null;
// get the pointer(s) for this context
@@ -178,6 +200,11 @@ public class GlProxy
contextPointer = lodBuilderGlContext;
newGlCapabilities = lodBuilderGlCapabilities;
break;
case LOD_RENDER:
contextPointer = lodRenderGlContext;
newGlCapabilities = lodRenderGlCapabilities;
break;
case MINECRAFT:
contextPointer = minecraftGlContext;
@@ -187,6 +214,7 @@ public class GlProxy
default: // default should never happen, it is just here to make the compiler happy
case NONE:
// 0L is equivalent to null
contextPointer = 0L;
break;
}
@@ -215,14 +243,19 @@ public class GlProxy
if (currentContext == lodBuilderGlContext)
return GlProxyContext.LOD_BUILDER;
else if (currentContext == lodRenderGlContext)
return GlProxyContext.LOD_RENDER;
else if (currentContext == minecraftGlContext)
return GlProxyContext.MINECRAFT;
else if (currentContext == 0L)
return GlProxyContext.NONE;
else
// hopefully this shouldn't happen, but
// at least now we will be notified if it does happen
throw new IllegalStateException(Thread.currentThread().getName() + " has a unknown OpenGl context: [" + currentContext + "]. Minecraft context [" + minecraftGlContext + "], LodBuilder context [" + lodBuilderGlContext + "], no context [0].");
// hopefully this shouldn't happen
throw new IllegalStateException(Thread.currentThread().getName() +
" has a unknown OpenGl context: [" + currentContext + "]. "
+ "Minecraft context [" + minecraftGlContext + "], "
+ "LodBuilder context [" + lodBuilderGlContext + "], "
+ "LodRender context [" + lodRenderGlContext + "], no context [0].");
}
@@ -63,7 +63,7 @@ import net.minecraft.world.phys.Vec3;
* This is where LODs are draw to the world.
*
* @author James Seibel
* @version 10-25-2021
* @version 10-31-2021
*/
public class LodRenderer
{
@@ -180,14 +180,6 @@ public class LodRenderer
//===============//
// initial setup //
//===============//
profiler = newProfiler;
profiler.push("LOD setup");
// TODO move the buffer regeneration logic into its own class (probably called in the client proxy instead)
// starting here...
determineIfLodsShouldRegenerate(lodDim, partialTicks);
@@ -222,9 +214,18 @@ public class LodRenderer
}
//===========================//
// GL settings for rendering //
//===========================//
//===============//
// initial setup //
//===============//
profiler = newProfiler;
profiler.push("LOD setup");
GlProxy glProxy = GlProxy.getInstance();
// set the required open GL settings
@@ -246,6 +247,7 @@ public class LodRenderer
GL15.glDisable(GL15.GL_LIGHT0);
GL15.glDisable(GL15.GL_LIGHT1);
// get the default projection matrix, so we can
// reset it after drawing the LODs
float[] mcProjMatrixRaw = new float[16];
@@ -255,6 +257,7 @@ public class LodRenderer
// (or maybe vice versa I have no idea :P)
mcProjectionMatrix.transpose();
Matrix4f modelViewMatrix = offsetTheModelViewMatrix(mcModelViewMatrix, partialTicks);
vanillaBlockRenderedDistance = mc.getRenderDistance() * LodUtil.CHUNK_WIDTH;
// required for setupFog and setupProjectionMatrix
@@ -263,19 +266,26 @@ public class LodRenderer
else
farPlaneBlockDistance = LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH;
setupProjectionMatrix(mcProjectionMatrix, vanillaBlockRenderedDistance, partialTicks);
// commented out until we can add shaders to handle lighting
//setupLighting(lodDim, partialTicks);
NearFarFogSettings fogSettings = determineFogSettings();
// determine the current fog settings, so they can be
// reset after drawing the LODs
float defaultFogStartDist = GL15.glGetFloat(GL15.GL_FOG_START);
float defaultFogEndDist = GL15.glGetFloat(GL15.GL_FOG_END);
int defaultFogMode = GL15.glGetInteger(GL15.GL_FOG_MODE);
int defaultFogDistance = GlProxy.getInstance().fancyFogAvailable ? GL15.glGetInteger(NVFogDistance.GL_FOG_DISTANCE_MODE_NV) : -1;
int defaultFogDistance = glProxy.fancyFogAvailable ? GL15.glGetInteger(NVFogDistance.GL_FOG_DISTANCE_MODE_NV) : -1;
NearFarFogSettings fogSettings = determineFogSettings();
//===========//
// rendering //
@@ -289,7 +299,7 @@ public class LodRenderer
Vector3f cameraDir = camera.getLookVector();
boolean cullingDisabled = LodConfig.CLIENT.graphics.advancedGraphicsOption.disableDirectionalCulling.get();
boolean renderBufferStorage = LodConfig.CLIENT.graphics.advancedGraphicsOption.gpuUploadMethod.get() == GpuUploadMethod.BUFFER_STORAGE && GlProxy.getInstance().bufferStorageSupported;
boolean renderBufferStorage = LodConfig.CLIENT.graphics.advancedGraphicsOption.gpuUploadMethod.get() == GpuUploadMethod.BUFFER_STORAGE && glProxy.bufferStorageSupported;
// used to determine what type of fog to render
int halfWidth = vbos.length / 2;
@@ -328,6 +338,9 @@ public class LodRenderer
}
//=========//
// cleanup //
//=========//
@@ -371,17 +384,17 @@ public class LodRenderer
LodUtil.LOD_VERTEX_FORMAT.setupBufferState();
// set up the model view matrix
GL15.glPushMatrix();
GL15.glLoadIdentity();
// GL15.glPushMatrix(); // matrix code is only available in OpenGL 3.2 and lower
// GL15.glLoadIdentity();
FloatBuffer matrixBuffer = FloatBuffer.allocate(16);
modelViewMatrix.store(matrixBuffer);
GL15.glMultMatrixf(matrixBuffer);
// GL15.glMultMatrixf(matrixBuffer);
GL15.glDrawArrays(GL15.GL_QUADS, 0, vertexCount);
// post draw cleanup
GL15.glPopMatrix();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
// GL15.glPopMatrix();
// GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
LodUtil.LOD_VERTEX_FORMAT.clearBufferState();
}