From cec90d7f48783e25a2e2d5306697834554facb54 Mon Sep 17 00:00:00 2001 From: cpw Date: Mon, 6 Mar 2017 17:31:26 -0500 Subject: [PATCH] Add in a check to the splash screen. If the Display.update call takes too long on average (over first 200 frames) we'll use a sleep based timer to allow mods doing splash screen work some time on the LWJGL global lock. (cherry picked from commit 03d7eaa) --- .../fml/client/FMLClientHandler.java | 6 ++++ .../fml/client/SplashProgress.java | 36 +++++++++++++++++-- .../fml/common/FMLCommonHandler.java | 2 ++ .../fml/common/IFMLSidedHandler.java | 2 ++ .../fml/common/ProgressManager.java | 5 +-- .../fml/server/FMLServerHandler.java | 6 ++++ 6 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java b/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java index 53611c68b..006c48334 100644 --- a/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java +++ b/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java @@ -1098,4 +1098,10 @@ public class FMLClientHandler implements IFMLSidedHandler { return (CompoundDataFixer)this.client.getDataFixer(); } + + @Override + public boolean isDisplayVSyncForced() + { + return SplashProgress.isDisplayVSyncForced; + } } diff --git a/src/main/java/net/minecraftforge/fml/client/SplashProgress.java b/src/main/java/net/minecraftforge/fml/client/SplashProgress.java index df02ff5a7..8ddda26bb 100644 --- a/src/main/java/net/minecraftforge/fml/client/SplashProgress.java +++ b/src/main/java/net/minecraftforge/fml/client/SplashProgress.java @@ -115,6 +115,10 @@ public class SplashProgress private static int memoryLowColor; private static float memoryColorPercent; private static long memoryColorChangeTime; + static boolean isDisplayVSyncForced = false; + private static final int TIMING_FRAME_COUNT = 200; + private static final int TIMING_FRAME_THRESHOLD = TIMING_FRAME_COUNT * 5 * 1000000; // 5 ms per frame, scaled to nanos + static final Semaphore mutex = new Semaphore(1); private static String getString(String name, String def) @@ -254,7 +258,8 @@ public class SplashProgress private final int barHeight = 20; private final int textHeight2 = 20; private final int barOffset = 55; - + private long updateTiming; + private long framecount; public void run() { setGL(); @@ -266,6 +271,7 @@ public class SplashProgress glDisable(GL_TEXTURE_2D); while(!done) { + framecount++; ProgressBar first = null, penult = null, last = null; Iterator i = ProgressManager.barIterator(); while(i.hasNext()) @@ -371,16 +377,40 @@ public class SplashProgress // is trying to impose a framerate or other thing is occurring. Without the mutex, the main // thread would delay waiting for the same global display lock mutex.acquireUninterruptibly(); + long updateStart = System.nanoTime(); Display.update(); // As soon as we're done, we release the mutex. The other thread can now ping the processmessages // call as often as it wants until we get get back here again + long dur = System.nanoTime() - updateStart; + if (framecount < TIMING_FRAME_COUNT) { + updateTiming += dur; + } mutex.release(); if(pause) { clearGL(); setGL(); } - Display.sync(100); + // Such a hack - if the time taken is greater than 10 milliseconds, we're gonna guess that we're on a + // system where vsync is forced through the swapBuffers call - so we have to force a sleep and let the + // loading thread have a turn - some badly designed mods access Keyboard and therefore GlobalLock.lock + // during splash screen, and mutex against the above Display.update call as a result. + // 4 milliseconds is a guess - but it should be enough to trigger in most circumstances. (Maybe if + // 240FPS is possible, this won't fire?) + if (framecount >= TIMING_FRAME_COUNT && updateTiming > TIMING_FRAME_THRESHOLD) { + if (!isDisplayVSyncForced) + { + isDisplayVSyncForced = true; + FMLLog.log(Level.INFO, "Using alternative sync timing : %d frames of Display.update took %d nanos", TIMING_FRAME_COUNT, updateTiming); + } + try { Thread.sleep(16); } catch (InterruptedException ie) {} + } else + { + if (framecount ==TIMING_FRAME_COUNT) { + FMLLog.log(Level.INFO, "Using sync timing. %d frames of Display.update took %d nanos", TIMING_FRAME_COUNT, updateTiming); + } + Display.sync(100); + } } clearGL(); } @@ -464,7 +494,7 @@ public class SplashProgress memoryColorChangeTime = time; memoryColorPercent = usedMemoryPercent; } - + int memoryBarColor; if (memoryColorPercent < 0.75f) { diff --git a/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java b/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java index 92f85a0a3..968b6de9d 100644 --- a/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java +++ b/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java @@ -757,4 +757,6 @@ public class FMLCommonHandler { return (CompoundDataFixer)sidedDelegate.getDataFixer(); } + + public boolean isDisplayVSyncForced() { return sidedDelegate.isDisplayVSyncForced(); } } diff --git a/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java b/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java index 4cff0649b..e28ea0fd1 100644 --- a/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java +++ b/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java @@ -80,4 +80,6 @@ public interface IFMLSidedHandler void fireSidedRegistryEvents(); CompoundDataFixer getDataFixer(); + + boolean isDisplayVSyncForced(); } diff --git a/src/main/java/net/minecraftforge/fml/common/ProgressManager.java b/src/main/java/net/minecraftforge/fml/common/ProgressManager.java index e2003c1d6..fe2f99500 100644 --- a/src/main/java/net/minecraftforge/fml/common/ProgressManager.java +++ b/src/main/java/net/minecraftforge/fml/common/ProgressManager.java @@ -32,7 +32,6 @@ import com.google.common.base.Joiner; public class ProgressManager { private static final List bars = new CopyOnWriteArrayList(); - /** * Not a fully fleshed out API, may change in future MC versions. * However feel free to use and suggest additions. @@ -57,7 +56,9 @@ public class ProgressManager return bar; } - + public static boolean isDisplayVSyncForced() { + return FMLCommonHandler.instance().isDisplayVSyncForced(); + } /** * Not a fully fleshed out API, may change in future MC versions. * However feel free to use and suggest additions. diff --git a/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java b/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java index 32a83db5b..64a175dd4 100644 --- a/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java +++ b/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java @@ -349,4 +349,10 @@ public class FMLServerHandler implements IFMLSidedHandler { return (CompoundDataFixer)this.server.getDataFixer(); } + + @Override + public boolean isDisplayVSyncForced() + { + return false; + } }