Handle MC running at 0 FPS
This commit is contained in:
@@ -437,10 +437,10 @@ public class ClientApi
|
||||
try
|
||||
{
|
||||
// make sure the GLProxy is created for future use
|
||||
GLProxy.getInstance();
|
||||
GLProxy glProxy = GLProxy.getInstance();
|
||||
|
||||
// these tasks always need to be called, regardless of whether the renderer is enabled or not to prevent memory leaks
|
||||
GLProxy.runRenderThreadTasks();
|
||||
glProxy.runRenderThreadTasks();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -26,8 +26,10 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.jar.EPlatform;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.opengl.GL;
|
||||
@@ -38,6 +40,7 @@ import org.lwjgl.opengl.GLUtil;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
@@ -48,6 +51,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
public class GLProxy
|
||||
{
|
||||
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
|
||||
@@ -58,6 +62,10 @@ public class GLProxy
|
||||
|
||||
private static final ConcurrentLinkedQueue<Runnable> RENDER_THREAD_RUNNABLE_QUEUE = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private static final Timer TIMER = TimerUtil.CreateTimer("Cleanup timer");
|
||||
private static final long MS_BETWEEN_CLEANUP_TICKS = 1_000L;
|
||||
private static final long MS_BEFORE_RUN_CLEANUP_TIMER = 1_000L;
|
||||
|
||||
|
||||
|
||||
private static GLProxy instance = null;
|
||||
@@ -98,6 +106,8 @@ public class GLProxy
|
||||
null
|
||||
);
|
||||
|
||||
private long msSinceGlTasksRun = System.currentTimeMillis();
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
@@ -194,6 +204,8 @@ public class GLProxy
|
||||
LOGGER.info("GPU Vendor [" + vendor + "] with OS [" + EPlatform.get().getName() + "], Preferred upload method is [" + this.preferredUploadMethod + "].");
|
||||
|
||||
|
||||
TIMER.scheduleAtFixedRate(TimerUtil.createTimerTask(this::manualGlCleanupTick), MS_BETWEEN_CLEANUP_TICKS, MS_BETWEEN_CLEANUP_TICKS);
|
||||
|
||||
|
||||
//==========//
|
||||
// clean up //
|
||||
@@ -273,9 +285,22 @@ public class GLProxy
|
||||
* Doesn't do any thread/GL Context validation.
|
||||
* Running this outside of the render thread may cause crashes or other issues.
|
||||
*/
|
||||
public static void runRenderThreadTasks()
|
||||
public void runRenderThreadTasks()
|
||||
{
|
||||
long startTime = System.nanoTime();
|
||||
int frameLimit = MC_RENDER.getFrameLimit();
|
||||
if (frameLimit <= 1)
|
||||
{
|
||||
frameLimit = 4; // 240 FPS
|
||||
}
|
||||
|
||||
// https://fpstoms.com/
|
||||
int msPerFrame = 1000 / frameLimit;
|
||||
this.runRenderThreadTasks(msPerFrame);
|
||||
}
|
||||
private void runRenderThreadTasks(long msMaxRunTime)
|
||||
{
|
||||
long startTimeMs = System.currentTimeMillis();
|
||||
this.msSinceGlTasksRun = startTimeMs;
|
||||
|
||||
Runnable runnable = RENDER_THREAD_RUNNABLE_QUEUE.poll();
|
||||
while(runnable != null)
|
||||
@@ -283,9 +308,9 @@ public class GLProxy
|
||||
runnable.run();
|
||||
|
||||
// only try running for 4ms (240 FPS) at a time to prevent random lag spikes
|
||||
long currentTime = System.nanoTime();
|
||||
long runDuration = currentTime - startTime;
|
||||
if (runDuration > 4_000_000)
|
||||
long currentTimeMs = System.currentTimeMillis();
|
||||
long runDuration = currentTimeMs - startTimeMs;
|
||||
if (runDuration > msMaxRunTime)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -294,6 +319,26 @@ public class GLProxy
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should only be called if our render code isn't being hit for some reason.
|
||||
* Normally this only happens if there's a mod that limits MC's framerate to 0.
|
||||
*/
|
||||
private void manualGlCleanupTick()
|
||||
{
|
||||
long nowMs = System.currentTimeMillis();
|
||||
long msSinceLast = nowMs - this.msSinceGlTasksRun;
|
||||
if (msSinceLast > MS_BEFORE_RUN_CLEANUP_TIMER)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// We haven't gotten a frame for a while,
|
||||
// this means we could have GL jobs building up.
|
||||
// Run the queued tasks on MC's executor (hopefully this should always run,
|
||||
// even if DH's render code isn't being hit).
|
||||
MC.executeOnRenderThread(() -> this.runRenderThreadTasks(1_000));
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
+12
@@ -120,6 +120,18 @@ public interface IMinecraftClientWrapper extends IBindable
|
||||
*/
|
||||
void crashMinecraft(String errorMessage, Throwable exception);
|
||||
|
||||
/**
|
||||
* This is only designed to be used internally by {@link GLProxy}
|
||||
* since it handles task frame limiting (reducing/preventing stuttering)
|
||||
* whereas this method causes the task to be run whenever MC decides to
|
||||
* (likely all at once the next frame). <br><br>
|
||||
*
|
||||
* Any tasks submitted here will be run on the render thread.
|
||||
*
|
||||
* @see GLProxy#queueRunningOnRenderThread(Runnable)
|
||||
*/
|
||||
void executeOnRenderThread(Runnable runnable);
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
|
||||
+2
@@ -57,6 +57,8 @@ public interface IMinecraftRenderWrapper extends IBindable
|
||||
/** Measured in chunks */
|
||||
int getRenderDistance();
|
||||
|
||||
int getFrameLimit();
|
||||
|
||||
boolean mcRendersToFrameBuffer();
|
||||
boolean runningLegacyOpenGL();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user