From 03d7eaae23fa21710cdc6c6fc9d9c98e5fa14755 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. --- .../fml/client/FMLClientHandler.java | 6 ++++ .../fml/client/SplashProgress.java | 34 +++++++++++++++++-- .../fml/common/FMLCommonHandler.java | 2 ++ .../fml/common/IFMLSidedHandler.java | 2 ++ .../fml/common/ProgressManager.java | 5 +-- .../fml/server/FMLServerHandler.java | 6 ++++ 6 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java b/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java index da5c5e5d54..b81187bd6a 100644 --- a/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java +++ b/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java @@ -1056,4 +1056,10 @@ public class FMLClientHandler implements IFMLSidedHandler { MinecraftForge.EVENT_BUS.post(new ModelRegistryEvent()); } + + @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 2a2c8e3e52..590bfbb831 100644 --- a/src/main/java/net/minecraftforge/fml/client/SplashProgress.java +++ b/src/main/java/net/minecraftforge/fml/client/SplashProgress.java @@ -106,6 +106,10 @@ public class SplashProgress private static int barBorderColor; private static int barColor; private static int barBackgroundColor; + 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) @@ -240,7 +244,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(); @@ -252,6 +257,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()) @@ -348,16 +354,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(); } diff --git a/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java b/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java index e16cd3709a..f057772418 100644 --- a/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java +++ b/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java @@ -751,4 +751,6 @@ public class FMLCommonHandler { sidedDelegate.fireSidedRegistryEvents(); } + + 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 aea07ffcda..457fde95ff 100644 --- a/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java +++ b/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java @@ -77,4 +77,6 @@ public interface IFMLSidedHandler void reloadRenderers(); void fireSidedRegistryEvents(); + + 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 e2003c1d62..fe2f99500a 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 8d5d38b6dd..513e1ca2d7 100644 --- a/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java +++ b/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java @@ -332,4 +332,10 @@ public class FMLServerHandler implements IFMLSidedHandler { // NOOP } + + @Override + public boolean isDisplayVSyncForced() + { + return false; + } }