-
Bug
-
Resolution: Fixed
-
Minecraft 1.10.2
-
None
-
NVIDIA + Linux
-
Unconfirmed
There is an OpenGL leak in the View Frustum and subsequently all individual Chunk Renderers + Vertex Buffers.
Without digging too deeply I believe this leak is either 1) a regression or 2) only now obvious due to the use of VBOs by default, which (on NVIDIA + Linux at least) have an allocation time that grows exponentially as more and more buffers are already allocated.
To attempt to reproduce this issue, first enable VBOs. Then join a world and fly around causing lots of chunks to be loaded. Disconnect from the world and repeat this process. After perhaps half a dozen repetitions, the world load time will be very slow (up to 2000ms above normal time has been observed). Note that at this point disabling use of VBOs will restore normal world load time (and toggling them back on will make the issue apparent once more).
The cause of this is that when resetting the Global Renderer on world join, the View Frustum is nulled out before the cleanup method (guarded by a null check) can be run. To fix this leak the cleanup method must be called the line before the View Frustum is nulled out.
Once this additional cleanup is called world load time remains constant even with the use of VBOs.
I have based my terminology on the MCP namings, A patch with hopefully sufficient context is below:
--- a/src/minecraft/net/minecraft/client/renderer/RenderGlobal.java +++ b/src/minecraft/net/minecraft/client/renderer/RenderGlobal.java @@ -456,61 +456,66 @@ public class RenderGlobal implements IWorldEventListener, IResourceManagerReload } /** * set null to clear */ public void setWorldAndLoadRenderers(@Nullable WorldClient worldClientIn) { if (this.theWorld != null) { this.theWorld.removeEventListener(this); } this.frustumUpdatePosX = Double.MIN_VALUE; this.frustumUpdatePosY = Double.MIN_VALUE; this.frustumUpdatePosZ = Double.MIN_VALUE; this.frustumUpdatePosChunkX = Integer.MIN_VALUE; this.frustumUpdatePosChunkY = Integer.MIN_VALUE; this.frustumUpdatePosChunkZ = Integer.MIN_VALUE; this.renderManager.set(worldClientIn); this.theWorld = worldClientIn; if (worldClientIn != null) { worldClientIn.addEventListener(this); this.loadRenderers(); } else { this.chunksToUpdate.clear(); this.renderInfos.clear(); - this.viewFrustum = null; + + if (this.viewFrustum != null) + { + this.viewFrustum.deleteGlResources(); + this.viewFrustum = null; + } if (this.renderDispatcher != null) { this.renderDispatcher.stopWorkerThreads(); } this.renderDispatcher = null; } } /** * Loads all the renderers and sets up the basic settings usage */ public void loadRenderers() { if (this.theWorld != null) { if (this.renderDispatcher == null) { this.renderDispatcher = new ChunkRenderDispatcher(); } this.displayListEntitiesDirty = true; Blocks.LEAVES.setGraphicsLevel(this.mc.gameSettings.fancyGraphics); Blocks.LEAVES2.setGraphicsLevel(this.mc.gameSettings.fancyGraphics); this.renderDistanceChunks = this.mc.gameSettings.renderDistanceChunks; boolean flag = this.vboEnabled; this.vboEnabled = OpenGlHelper.useVbo(); if (flag && !this.vboEnabled)