Add a LodRender OpenGL context
This commit is contained in:
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user