diff --git a/src/main/java/net/minecraftforge/fml/client/SplashProgress.java b/src/main/java/net/minecraftforge/fml/client/SplashProgress.java index cd609923c..dc54bbe4d 100644 --- a/src/main/java/net/minecraftforge/fml/client/SplashProgress.java +++ b/src/main/java/net/minecraftforge/fml/client/SplashProgress.java @@ -23,6 +23,7 @@ import static org.lwjgl.opengl.GL12.*; import java.awt.image.BufferedImage; +import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -35,6 +36,7 @@ import java.lang.Thread.UncaughtExceptionHandler; import java.nio.IntBuffer; import java.nio.charset.StandardCharsets; +import java.util.HashMap; import java.util.Iterator; import java.util.Properties; import java.util.concurrent.Semaphore; @@ -260,149 +262,151 @@ public void run() logoTexture = new Texture(logoLoc, null, false); forgeTexture = new Texture(forgeLoc, forgeFallbackLoc); glEnable(GL_TEXTURE_2D); - fontRenderer = new SplashFontRenderer(); - glDisable(GL_TEXTURE_2D); - while(!done) - { - framecount++; - ProgressBar first = null, penult = null, last = null; - Iterator i = ProgressManager.barIterator(); - while(i.hasNext()) + try (SplashFontRenderer splashFontRenderer = new SplashFontRenderer(false)){ + fontRenderer = splashFontRenderer; + glDisable(GL_TEXTURE_2D); + while(!done) { - if(first == null) first = i.next(); - else + framecount++; + ProgressBar first = null, penult = null, last = null; + Iterator i = ProgressManager.barIterator(); + while(i.hasNext()) { - penult = last; - last = i.next(); + if(first == null) first = i.next(); + else + { + penult = last; + last = i.next(); + } } - } - glClear(GL_COLOR_BUFFER_BIT); - - // matrix setup - int w = Display.getWidth(); - int h = Display.getHeight(); - glViewport(0, 0, w, h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(320 - w/2, 320 + w/2, 240 + h/2, 240 - h/2, -1, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - // mojang logo - setColor(backgroundColor); - glEnable(GL_TEXTURE_2D); - logoTexture.bind(); - glBegin(GL_QUADS); - logoTexture.texCoord(0, 0, 0); - glVertex2f(320 - 256, 240 - 256); - logoTexture.texCoord(0, 0, 1); - glVertex2f(320 - 256, 240 + 256); - logoTexture.texCoord(0, 1, 1); - glVertex2f(320 + 256, 240 + 256); - logoTexture.texCoord(0, 1, 0); - glVertex2f(320 + 256, 240 - 256); - glEnd(); - glDisable(GL_TEXTURE_2D); + glClear(GL_COLOR_BUFFER_BIT); + + // matrix setup + int w = Display.getWidth(); + int h = Display.getHeight(); + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(320 - w/2, 320 + w/2, 240 + h/2, 240 - h/2, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // mojang logo + setColor(backgroundColor); + glEnable(GL_TEXTURE_2D); + logoTexture.bind(); + glBegin(GL_QUADS); + logoTexture.texCoord(0, 0, 0); + glVertex2f(320 - 256, 240 - 256); + logoTexture.texCoord(0, 0, 1); + glVertex2f(320 - 256, 240 + 256); + logoTexture.texCoord(0, 1, 1); + glVertex2f(320 + 256, 240 + 256); + logoTexture.texCoord(0, 1, 0); + glVertex2f(320 + 256, 240 - 256); + glEnd(); + glDisable(GL_TEXTURE_2D); // memory usage - if (showMemory) - { - glPushMatrix(); - glTranslatef(320 - (float) barWidth / 2, 20, 0); - drawMemoryBar(); - glPopMatrix(); - } - - // bars - if(first != null) - { - glPushMatrix(); - glTranslatef(320 - (float)barWidth / 2, 310, 0); - drawBar(first); - if(penult != null) + if (showMemory) { - glTranslatef(0, barOffset, 0); - drawBar(penult); + glPushMatrix(); + glTranslatef(320 - (float) barWidth / 2, 20, 0); + drawMemoryBar(); + glPopMatrix(); } - if(last != null) + + // bars + if(first != null) { - glTranslatef(0, barOffset, 0); - drawBar(last); + glPushMatrix(); + glTranslatef(320 - (float)barWidth / 2, 310, 0); + drawBar(first); + if(penult != null) + { + glTranslatef(0, barOffset, 0); + drawBar(penult); + } + if(last != null) + { + glTranslatef(0, barOffset, 0); + drawBar(last); + } + glPopMatrix(); } - glPopMatrix(); - } - angle += 1; - - // forge logo - glColor4f(1, 1, 1, 1); - float fw = (float)forgeTexture.getWidth() / 2; - float fh = (float)forgeTexture.getHeight() / 2; - if(rotate) - { - float sh = Math.max(fw, fh); - glTranslatef(320 + w/2 - sh - logoOffset, 240 + h/2 - sh - logoOffset, 0); - glRotatef(angle, 0, 0, 1); - } - else - { - glTranslatef(320 + w/2 - fw - logoOffset, 240 + h/2 - fh - logoOffset, 0); - } - int f = (angle / 5) % forgeTexture.getFrames(); - glEnable(GL_TEXTURE_2D); - forgeTexture.bind(); - glBegin(GL_QUADS); - forgeTexture.texCoord(f, 0, 0); - glVertex2f(-fw, -fh); - forgeTexture.texCoord(f, 0, 1); - glVertex2f(-fw, fh); - forgeTexture.texCoord(f, 1, 1); - glVertex2f(fw, fh); - forgeTexture.texCoord(f, 1, 0); - glVertex2f(fw, -fh); - glEnd(); - glDisable(GL_TEXTURE_2D); + angle += 1; - // We use mutex to indicate safely to the main thread that we're taking the display global lock - // So the main thread can skip processing messages while we're updating. - // There are system setups where this call can pause for a while, because the GL implementation - // 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(); - } - // 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) + // forge logo + glColor4f(1, 1, 1, 1); + float fw = (float)forgeTexture.getWidth() / 2; + float fh = (float)forgeTexture.getHeight() / 2; + if(rotate) { - isDisplayVSyncForced = true; - FMLLog.log.info("Using alternative sync timing : {} frames of Display.update took {} nanos", TIMING_FRAME_COUNT, updateTiming); + float sh = Math.max(fw, fh); + glTranslatef(320 + w/2 - sh - logoOffset, 240 + h/2 - sh - logoOffset, 0); + glRotatef(angle, 0, 0, 1); } - try { Thread.sleep(16); } catch (InterruptedException ie) {} - } else - { - if (framecount ==TIMING_FRAME_COUNT) { - FMLLog.log.info("Using sync timing. {} frames of Display.update took {} nanos", TIMING_FRAME_COUNT, updateTiming); + else + { + glTranslatef(320 + w/2 - fw - logoOffset, 240 + h/2 - fh - logoOffset, 0); + } + int f = (angle / 5) % forgeTexture.getFrames(); + glEnable(GL_TEXTURE_2D); + forgeTexture.bind(); + glBegin(GL_QUADS); + forgeTexture.texCoord(f, 0, 0); + glVertex2f(-fw, -fh); + forgeTexture.texCoord(f, 0, 1); + glVertex2f(-fw, fh); + forgeTexture.texCoord(f, 1, 1); + glVertex2f(fw, fh); + forgeTexture.texCoord(f, 1, 0); + glVertex2f(fw, -fh); + glEnd(); + glDisable(GL_TEXTURE_2D); + + // We use mutex to indicate safely to the main thread that we're taking the display global lock + // So the main thread can skip processing messages while we're updating. + // There are system setups where this call can pause for a while, because the GL implementation + // 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(); + } + // 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.info("Using alternative sync timing : {} frames of Display.update took {} nanos", TIMING_FRAME_COUNT, updateTiming); + } + try { Thread.sleep(16); } catch (InterruptedException ie) {} + } else + { + if (framecount ==TIMING_FRAME_COUNT) { + FMLLog.log.info("Using sync timing. {} frames of Display.update took {} nanos", TIMING_FRAME_COUNT, updateTiming); + } + Display.sync(100); } - Display.sync(100); } } clearGL(); @@ -743,7 +747,7 @@ private static IResourcePack createResourcePack(File file) private static final IntBuffer buf = BufferUtils.createIntBuffer(4 * 1024 * 1024); @SuppressWarnings("unused") - private static class Texture + private static class Texture implements Closeable { private final ResourceLocation location; private final int name; @@ -891,21 +895,38 @@ public void texCoord(int frame, float u, float v) { glTexCoord2f(getU(frame, u), getV(frame, v)); } + + @Override + public void close(){ + this.delete(); + } } - private static class SplashFontRenderer extends FontRenderer + public static class SplashFontRenderer extends FontRenderer implements Closeable { - public SplashFontRenderer() + protected HashMap cachedImages; + + public SplashFontRenderer(boolean isForcedUnicode) { - super(Minecraft.getMinecraft().gameSettings, fontTexture.getLocation(), null, false); + super(Minecraft.getMinecraft().gameSettings, fontTexture.getLocation(), null, isForcedUnicode); super.onResourceManagerReload(null); } @Override protected void bindTexture(@Nonnull ResourceLocation location) { - if(location != locationFontTexture) throw new IllegalArgumentException(); - fontTexture.bind(); + if (cachedImages == null) { + cachedImages = new HashMap<>(); + var texture = new Texture(location, null); + cachedImages.put(location, texture = new Texture(location, null)); + texture.bind(); + } else { + var texture = cachedImages.get(location); + if (texture == null) { + cachedImages.put(location, texture = new Texture(location, null)); + } + texture.bind(); + } } @Nonnull @@ -915,6 +936,17 @@ protected IResource getResource(@Nonnull ResourceLocation location) throws IOExc DefaultResourcePack pack = Minecraft.getMinecraft().defaultResourcePack; return new SimpleResource(pack.getPackName(), location, pack.getInputStream(location), null, null); } + + @Override + public void close() { + if(cachedImages != null){ + for(Texture texture : cachedImages.values()) { + texture.delete(); + } + cachedImages.clear(); + cachedImages = null; + } + } } public static void drawVanillaScreen(TextureManager renderEngine) throws LWJGLException @@ -966,4 +998,4 @@ private static int bytesToMb(long bytes) { return (int) (bytes / 1024L / 1024L); } -} \ No newline at end of file +}