From 8aeaf404ca85bbbe341ca5c3b5eb47d33086a785 Mon Sep 17 00:00:00 2001 From: LAX1DUDE Date: Sun, 3 Jul 2022 13:49:55 -0700 Subject: [PATCH] Made chunk loading smarter, boosted the FPS a lot --- .../java/net/minecraft/client/Minecraft.java | 6 +- .../java/net/minecraft/src/EnumOptions.java | 2 +- .../net/minecraft/src/EnumOptionsHelper.java | 6 + .../java/net/minecraft/src/GameSettings.java | 10 +- .../net/minecraft/src/GuiVideoSettings.java | 4 +- .../java/net/minecraft/src/RenderGlobal.java | 213 ++++++++---------- .../java/net/minecraft/src/WorldRenderer.java | 12 + 7 files changed, 130 insertions(+), 123 deletions(-) diff --git a/src/main/java/net/minecraft/client/Minecraft.java b/src/main/java/net/minecraft/client/Minecraft.java index efcfe71..0e5a269 100644 --- a/src/main/java/net/minecraft/client/Minecraft.java +++ b/src/main/java/net/minecraft/client/Minecraft.java @@ -137,9 +137,11 @@ public class Minecraft implements Runnable { /** The profiler instance */ public final Profiler mcProfiler = new Profiler(); private long field_83002_am = -1L; - + public int chunkUpdates = 0; + public int chunkGeometryUpdates = 0; public static int debugChunkUpdates = 0; + public static int debugChunkGeometryUpdates = 0; /** * Set to true to keep the game loop running. Set to false by shutdown() to @@ -724,6 +726,8 @@ public class Minecraft implements Runnable { fpsCounter = 0; debugChunkUpdates = chunkUpdates; chunkUpdates = 0; + debugChunkGeometryUpdates = chunkGeometryUpdates; + chunkGeometryUpdates = 0; secondTimer = System.currentTimeMillis(); } this.mcProfiler.startSection("syncDisplay"); diff --git a/src/main/java/net/minecraft/src/EnumOptions.java b/src/main/java/net/minecraft/src/EnumOptions.java index e5704c3..e7ee9e4 100644 --- a/src/main/java/net/minecraft/src/EnumOptions.java +++ b/src/main/java/net/minecraft/src/EnumOptions.java @@ -8,7 +8,7 @@ public enum EnumOptions { CHAT_VISIBILITY("options.chat.visibility", false, false), CHAT_COLOR("options.chat.color", false, true), CHAT_LINKS("options.chat.links", false, true), CHAT_OPACITY("options.chat.opacity", true, false), CHAT_LINKS_PROMPT("options.chat.links.prompt", false, true), USE_SERVER_TEXTURES("options.serverTextures", false, true), SNOOPER_ENABLED("options.snooper", false, true), USE_FULLSCREEN("options.fullscreen", false, true), PATCH_ANGLE("options.patchAnisotropic", false, true), ENABLE_FOG("options.fog", false, true), SHOW_CAPE("options.showCape", false, true), ANTIALIASING("options.framebufferAntialias", false, false), CHAT_SCALE("options.chat.scale", true, false), CHAT_WIDTH("options.chat.width", true, false), - CHAT_HEIGHT_FOCUSED("options.chat.height.focused", true, false), CHAT_HEIGHT_UNFOCUSED("options.chat.height.unfocused", true, false); + CHAT_HEIGHT_FOCUSED("options.chat.height.focused", true, false), CHAT_HEIGHT_UNFOCUSED("options.chat.height.unfocused", true, false), CHUNK_UPDATES("options.chunkUpdates", false, false); private final boolean enumFloat; private final boolean enumBoolean; diff --git a/src/main/java/net/minecraft/src/EnumOptionsHelper.java b/src/main/java/net/minecraft/src/EnumOptionsHelper.java index c07ba94..95f18e0 100644 --- a/src/main/java/net/minecraft/src/EnumOptionsHelper.java +++ b/src/main/java/net/minecraft/src/EnumOptionsHelper.java @@ -87,5 +87,11 @@ class EnumOptionsHelper { } catch (NoSuchFieldError var10) { ; } + + try { + enumOptionsMappingHelperArray[EnumOptions.CHUNK_UPDATES.ordinal()] = 16; + } catch (NoSuchFieldError var10) { + ; + } } } diff --git a/src/main/java/net/minecraft/src/GameSettings.java b/src/main/java/net/minecraft/src/GameSettings.java index eca4faa..f5c4164 100644 --- a/src/main/java/net/minecraft/src/GameSettings.java +++ b/src/main/java/net/minecraft/src/GameSettings.java @@ -135,6 +135,7 @@ public class GameSettings { public boolean allowFNAWSkins = true; public boolean showOtherCapes = true; + public int chunkUpdatePerFrame = 0; public GameSettings(Minecraft par1Minecraft) { this.keyBindings = new KeyBinding[] { this.keyBindAttack, this.keyBindUseItem, this.keyBindForward, this.keyBindLeft, this.keyBindBack, this.keyBindRight, this.keyBindJump, this.keyBindSneak, this.keyBindDrop, this.keyBindInventory, @@ -291,6 +292,10 @@ public class GameSettings { this.limitFramerate = (this.limitFramerate + par2 + 3) % 3; } + if (par1EnumOptions == EnumOptions.CHUNK_UPDATES) { + this.chunkUpdatePerFrame = (this.chunkUpdatePerFrame + par2) % 5; + } + if (par1EnumOptions == EnumOptions.DIFFICULTY) { this.difficulty = this.difficulty + par2 & 3; } @@ -460,8 +465,9 @@ public class GameSettings { : (par1EnumOptions == EnumOptions.FRAMERATE_LIMIT ? var3 + getTranslation(LIMIT_FRAMERATES, this.limitFramerate) : (par1EnumOptions == EnumOptions.AMBIENT_OCCLUSION ? var3 + getTranslation(AMBIENT_OCCLUSIONS, this.ambientOcclusion) : (par1EnumOptions == EnumOptions.ANTIALIASING ? var3 + getTranslation(ANTIALIASING, this.antialiasMode) + : (par1EnumOptions == EnumOptions.CHUNK_UPDATES ? var3 + (chunkUpdatePerFrame + 1) : (par1EnumOptions == EnumOptions.GRAPHICS ? (this.fancyGraphics ? var3 + var2.translateKey("options.graphics.fancy") : var3 + var2.translateKey("options.graphics.fast")) - : var3)))))))); + : var3))))))))); } } @@ -519,6 +525,7 @@ public class GameSettings { if(yee.hasKey("showSkinRightLeg")) showSkinRightLeg = yee.getBoolean("showSkinRightLeg"); if(yee.hasKey("allowFNAWSkins")) allowFNAWSkins = yee.getBoolean("allowFNAWSkins"); if(yee.hasKey("showOtherCapes")) showOtherCapes = yee.getBoolean("showOtherCapes"); + if(yee.hasKey("chunkUpdates")) chunkUpdatePerFrame = yee.getInteger("chunkUpdates"); for (int var4 = 0; var4 < this.keyBindings.length; ++var4) { if(yee.hasKey(keyBindings[var4].keyDescription)) this.keyBindings[var4].keyCode = yee.getInteger(keyBindings[var4].keyDescription); @@ -581,6 +588,7 @@ public class GameSettings { yee.setBoolean("showSkinRightLeg", showSkinRightLeg); yee.setBoolean("allowFNAWSkins", allowFNAWSkins); yee.setBoolean("showOtherCapes", showOtherCapes); + yee.setInteger("chunkUpdates", chunkUpdatePerFrame); for (int var4 = 0; var4 < this.keyBindings.length; ++var4) { yee.setInteger(keyBindings[var4].keyDescription, keyBindings[var4].keyCode); diff --git a/src/main/java/net/minecraft/src/GuiVideoSettings.java b/src/main/java/net/minecraft/src/GuiVideoSettings.java index 6d91621..e2537c8 100644 --- a/src/main/java/net/minecraft/src/GuiVideoSettings.java +++ b/src/main/java/net/minecraft/src/GuiVideoSettings.java @@ -17,7 +17,7 @@ public class GuiVideoSettings extends GuiScreen { /** An array of all of EnumOption's video options. */ private static EnumOptions[] videoOptions = new EnumOptions[] { EnumOptions.GRAPHICS, EnumOptions.RENDER_DISTANCE, EnumOptions.AMBIENT_OCCLUSION, EnumOptions.FRAMERATE_LIMIT, EnumOptions.ANAGLYPH, EnumOptions.VIEW_BOBBING, - EnumOptions.GUI_SCALE, EnumOptions.GAMMA, EnumOptions.RENDER_CLOUDS, EnumOptions.ENABLE_FOG, EnumOptions.PARTICLES, EnumOptions.PATCH_ANGLE }; + EnumOptions.GUI_SCALE, EnumOptions.GAMMA, EnumOptions.RENDER_CLOUDS, EnumOptions.ENABLE_FOG, EnumOptions.PARTICLES, EnumOptions.PATCH_ANGLE, EnumOptions.CHUNK_UPDATES }; public GuiVideoSettings(GuiScreen par1GuiScreen, GameSettings par2GameSettings) { this.parentGuiScreen = par1GuiScreen; @@ -31,7 +31,7 @@ public class GuiVideoSettings extends GuiScreen { StringTranslate var1 = StringTranslate.getInstance(); this.screenTitle = var1.translateKey("options.videoTitle"); this.buttonList.clear(); - this.buttonList.add(new GuiButton(200, this.width / 2 - 100, this.height / 6 + 168, var1.translateKey("gui.done"))); + this.buttonList.add(new GuiButton(200, this.width / 2 - 100, this.height / 6 + 178, var1.translateKey("gui.done"))); this.is64bit = true; /* String[] var2 = new String[] { "sun.arch.data.model", "com.ibm.vm.bitmode", "os.arch" }; diff --git a/src/main/java/net/minecraft/src/RenderGlobal.java b/src/main/java/net/minecraft/src/RenderGlobal.java index 1a1e8cd..c64fc7b 100644 --- a/src/main/java/net/minecraft/src/RenderGlobal.java +++ b/src/main/java/net/minecraft/src/RenderGlobal.java @@ -145,6 +145,8 @@ public class RenderGlobal implements IWorldAccess { */ int frustumCheckOffset = 0; + private int occlusionForcedIndexShift = 0; + public RenderGlobal(Minecraft par1Minecraft, RenderEngine par2RenderEngine) { this.mc = par1Minecraft; this.renderEngine = par2RenderEngine; @@ -415,7 +417,8 @@ public class RenderGlobal implements IWorldAccess { } public String getDebugInfoShort() { - return "" + Minecraft.debugFPS + "fps | C: " + this.renderersBeingRendered + "/" + this.renderersLoaded + ", E: " + this.countEntitiesRendered + "+" + tileEntities.size()+", U: "+Minecraft.debugChunkUpdates; + return "" + Minecraft.debugFPS + "fps | C: " + this.renderersBeingRendered + "/" + this.renderersLoaded + ", E: " + this.countEntitiesRendered + "+" + tileEntities.size() + + ", U: " + Minecraft.debugChunkGeometryUpdates + "/" + Minecraft.debugChunkUpdates; } /** @@ -564,11 +567,11 @@ public class RenderGlobal implements IWorldAccess { RenderHelper.disableStandardItemLighting(); byte var17 = 0; int var34; - + long queryRate = 50l; - long stallRateVisible = 50l; + long stallRateVisible = 60l; long stallRate = 500l; - int cooldownRate = 10; + int cooldownRate = 13; long ct = System.currentTimeMillis(); if(par2 == 0) { @@ -578,26 +581,36 @@ public class RenderGlobal implements IWorldAccess { int ccx = c.chunkX - fx; int ccy = c.chunkY - fy; int ccz = c.chunkZ - fz; - if((ccx < 2 && ccx > -2 && ccy < 2 && ccy > -2 && ccz < 2 && ccz > -2) || glOcclusionQuery[c.chunkIndex] == -1) { + boolean forced = ccx < 2 && ccx > -2 && ccy < 2 && ccy > -2 && ccz < 2 && ccz > -2; + if(forced) { + c.hasOcclusionData = 5; + } + if(forced || glOcclusionQuery[c.chunkIndex] == -1) { c.isNowVisible = true; c.isVisible = cooldownRate; - }else if(!c.skipAllRenderPasses() && c.isInFrustum) { - if(occlusionQueryAvailable[c.chunkIndex]) { - if(EaglerAdapter.glGetQueryResultAvailable(glOcclusionQuery[c.chunkIndex])) { - if(EaglerAdapter.glGetQueryResult(glOcclusionQuery[c.chunkIndex])) { - c.isNowVisible = true; - c.isVisible = cooldownRate; - }else { - if(c.isVisible <= 0) { - c.isNowVisible = false; + }else if(occlusionQueryAvailable[c.chunkIndex]) { + if(EaglerAdapter.glGetQueryResultAvailable(glOcclusionQuery[c.chunkIndex])) { + if(EaglerAdapter.glGetQueryResult(glOcclusionQuery[c.chunkIndex])) { + c.isNowVisible = true; + ++c.hasOcclusionData; + if(c.hasOcclusionData > 5) { + c.hasOcclusionData = 5; + } + c.isVisible = cooldownRate; + }else { + if(c.isVisible <= 0) { + c.isNowVisible = false; + --c.hasOcclusionData; + if(c.hasOcclusionData < 0) { + c.hasOcclusionData = 0; } } - occlusionQueryAvailable[c.chunkIndex] = false; - occlusionQueryStalled[c.chunkIndex] = 0l; - }else if(occlusionQueryStalled[c.chunkIndex] != 0l && ct - occlusionQueryStalled[c.chunkIndex] > stallRateVisible) { - c.isNowVisible = true; - c.isVisible = cooldownRate; } + occlusionQueryAvailable[c.chunkIndex] = false; + occlusionQueryStalled[c.chunkIndex] = 0l; + }else if(occlusionQueryStalled[c.chunkIndex] != 0l && ct - occlusionQueryStalled[c.chunkIndex] > stallRateVisible) { + c.isNowVisible = true; + c.isVisible = cooldownRate; } } } @@ -610,6 +623,27 @@ public class RenderGlobal implements IWorldAccess { ct = System.currentTimeMillis(); if(par2 == 0 && ct - lastOcclusionQuery > queryRate) { + + int totalRenderers = this.sortedWorldRenderers.length; + int inFrustumCount = 0; + for (int i = 0; i < totalRenderers; ++i) { + WorldRenderer c = this.sortedWorldRenderers[i]; + if(c.isInFrustum) { + ++inFrustumCount; + } + } + + int occlusionForceCount = (int)(500l / queryRate); + int occlusionForceStep = MathHelper.floor_float(inFrustumCount / (float)occlusionForceCount) + 1; + int forceStartIndex = occlusionForcedIndexShift * occlusionForceStep; + int forceEndIndex = forceStartIndex + occlusionForceStep; + ++occlusionForcedIndexShift; + if(forceEndIndex + (occlusionForceStep >> 1) > inFrustumCount) { + forceEndIndex = inFrustumCount; + occlusionForcedIndexShift = 0; + } + + inFrustumCount = 0; lastOcclusionQuery = ct; this.theWorld.theProfiler.endStartSection("occl"); EaglerAdapter.glEnable(EaglerAdapter.GL_CULL_FACE); @@ -622,7 +656,14 @@ public class RenderGlobal implements IWorldAccess { int ccx = c.chunkX - fx; int ccy = c.chunkY - fy; int ccz = c.chunkZ - fz; - if(!c.skipAllRenderPasses() && c.isInFrustum && !(ccx < 2 && ccx > -2 && ccy < 2 && ccy > -2 && ccz < 2 && ccz > -2)) { + boolean shouldTry = c.isInFrustum; + if(c.isInFrustum) { + ++inFrustumCount; + if(!shouldTry && inFrustumCount >= forceStartIndex && inFrustumCount < forceEndIndex) { + shouldTry = true; + } + } + if(shouldTry && !(ccx < 2 && ccx > -2 && ccy < 2 && ccy > -2 && ccz < 2 && ccz > -2)) { boolean stalled = false; if(occlusionQueryAvailable[c.chunkIndex]) { if(occlusionQueryStalled[c.chunkIndex] == 0l) { @@ -642,6 +683,11 @@ public class RenderGlobal implements IWorldAccess { EaglerAdapter.glDrawOcclusionBB((float)(c.posX - var33), (float)(c.posY - var7), (float)(c.posZ - var9), 16, 16, 16); EaglerAdapter.glEndQuery(); } + }else { + --c.hasOcclusionData; + if(c.hasOcclusionData < 0) { + c.hasOcclusionData = 0; + } } if(c.isVisible > 0) { --c.isVisible; @@ -1227,54 +1273,31 @@ public class RenderGlobal implements IWorldAccess { WorldRenderer var10; int var11; int var12; - label136: - + List laterUpdateList = new ArrayList(var7); for (var9 = 0; var9 < var7; ++var9) { var10 = (WorldRenderer) this.worldRenderersToUpdate.get(var9); if (var10 != null) { - if (!par2) { - if (var10.distanceToEntitySquared(par1EntityLiving) > 256.0F) { - for (var11 = 0; var11 < var3 && (var5[var11] == null || var4.doCompare(var5[var11], var10) <= 0); ++var11) { - ; - } - - --var11; - - if (var11 > 0) { - var12 = var11; - - while (true) { - --var12; - - if (var12 == 0) { - var5[var11] = var10; - continue label136; - } - - var5[var12 - 1] = var5[var12]; - } - } - - continue; + if (!var10.isInFrustum || !var10.isNowVisible || var10.hasOcclusionData < 3) { // config? + laterUpdateList.add(var10); + }else { + if (var6 == null) { + var6 = new ArrayList(); } - } else if (!var10.isInFrustum) { - continue; + + ++var8; + var6.add(var10); } - - if (var6 == null) { - var6 = new ArrayList(); - } - - ++var8; - var6.add(var10); - this.worldRenderersToUpdate.set(var9, (Object) null); } } + + this.worldRenderersToUpdate = laterUpdateList; this.theWorld.theProfiler.endSection(); - this.theWorld.theProfiler.startSection("sort"); + this.theWorld.theProfiler.startSection("sortAndUpdate"); + int updates = 0; + int dropped = 0; if (var6 != null) { if (var6.size() > 1) { Collections.sort(var6, var4); @@ -1282,71 +1305,24 @@ public class RenderGlobal implements IWorldAccess { for (var9 = var6.size() - 1; var9 >= 0; --var9) { var10 = (WorldRenderer) var6.get(var9); - var10.updateRenderer(); - var10.needsUpdate = false; + if(updates >= mc.gameSettings.chunkUpdatePerFrame + 1) { // make configurable + this.worldRenderersToUpdate.add(var10); + ++dropped; + }else { + ++mc.chunkUpdates; + var10.updateRenderer(); + var10.needsUpdate = false; + if(!var10.skipAllRenderPasses()) { + ++updates; + ++mc.chunkGeometryUpdates; + } + } } } this.theWorld.theProfiler.endSection(); - var9 = 0; - int var16; - - for (var16 = var3 - 1; var16 >= 0; --var16) { - WorldRenderer var17 = var5[var16]; - - if (var17 != null) { - if (!var17.isInFrustum && var16 != var3 - 1) { - var5[var16] = null; - var5[0] = null; - break; - } - - var5[var16].updateRenderer(); - var5[var16].needsUpdate = false; - ++var9; - } - } - this.mc.chunkUpdates += var9; - this.theWorld.theProfiler.startSection("cleanup"); - var16 = 0; - var11 = 0; - - for (var12 = this.worldRenderersToUpdate.size(); var16 != var12; ++var16) { - WorldRenderer var13 = (WorldRenderer) this.worldRenderersToUpdate.get(var16); - - if (var13 != null) { - boolean var14 = false; - - for (int var15 = 0; var15 < var3 && !var14; ++var15) { - if (var13 == var5[var15]) { - var14 = true; - } - } - - if (!var14) { - if (var11 != var16) { - this.worldRenderersToUpdate.set(var11, var13); - } - - ++var11; - } - } - } - - this.theWorld.theProfiler.endSection(); - this.theWorld.theProfiler.startSection("trim"); - - while (true) { - --var16; - - if (var16 < var11) { - this.theWorld.theProfiler.endSection(); - return var7 == var8 + var9; - } - - this.worldRenderersToUpdate.remove(var16); - } + return true; } private static final TextureLocation tex_terrain = new TextureLocation("/terrain.png"); @@ -1561,7 +1537,8 @@ public class RenderGlobal implements IWorldAccess { */ public void clipRenderersByFrustum(ICamera par1ICamera, float par2) { for (int var3 = 0; var3 < this.worldRenderers.length; ++var3) { - if (!this.worldRenderers[var3].skipAllRenderPasses() && (!this.worldRenderers[var3].isInFrustum || (var3 + this.frustumCheckOffset & 15) == 0)) { + WorldRenderer rd = this.worldRenderers[var3]; + if (!rd.isInFrustum || (var3 + this.frustumCheckOffset & 31) == 0) { this.worldRenderers[var3].updateInFrustum(par1ICamera); } } diff --git a/src/main/java/net/minecraft/src/WorldRenderer.java b/src/main/java/net/minecraft/src/WorldRenderer.java index f775040..abbab05 100644 --- a/src/main/java/net/minecraft/src/WorldRenderer.java +++ b/src/main/java/net/minecraft/src/WorldRenderer.java @@ -14,6 +14,7 @@ public class WorldRenderer { private int glRenderList = -1; private static Tessellator tessellator = Tessellator.instance; public static int chunksUpdated = 0; + public static int chunksGeometryUpdated = 0; public int posX; public int posY; public int posZ; @@ -72,6 +73,7 @@ public class WorldRenderer { /** Is the chunk lit */ public boolean isChunkLit; private boolean isInitialized = false; + public int hasOcclusionData = 0; /** All the tile entities that have special rendering code for this chunk */ public List tileEntityRenderers = new ArrayList(); @@ -96,6 +98,7 @@ public class WorldRenderer { public void setPosition(int par1, int par2, int par3) { if (par1 != this.posX || par2 != this.posY || par3 != this.posZ) { this.setDontDraw(); + this.hasOcclusionData = 0; this.posX = par1; this.posY = par2; this.posZ = par3; @@ -224,6 +227,11 @@ public class WorldRenderer { break; } } + + if(!(skipRenderPass[0] && skipRenderPass[1])) { + ++chunksGeometryUpdated; + } + EaglerAdapter.hintAnisotropicFix(false); } @@ -283,6 +291,10 @@ public class WorldRenderer { public void callOcclusionQueryList() { EaglerAdapter.glCallList(this.glRenderList + 2); } + + public boolean shouldTryOcclusionQuery() { + return !this.isInitialized ? true : !this.skipRenderPass[0] || !this.skipRenderPass[1]; + } /** * Checks if all render passes are to be skipped. Returns false if the renderer