Switching worlds can cause NO LAG! Just remove System.gc() from the code and don't delete all VBOs when changing dimensions. For example, on Hypixel dimension switch is sent 2 times which causes the screen to darken 2 times (especially with render distance 32). This lag can take up to 5 seconds on Windows and 30+ seconds on linux leading to disconnection with the server.
How to reproduce:
Set render distance to 32 and go through the nether portal in singleplayer
or switch subserver in multiplayer.
Solution:
Remove System.gc() Reuse buffers. Sample code below
public class GlBuffer
{
public static GlBuffersStack glBuffers = new GlBuffersStack(1024*64);
private static int glBuffersIndex = 0;
public static int vmem = 0;
private int index;
public static GlBuffer genBuffer(){
GlBuffer result = null;
if(glBuffersIndex < glBuffers.size()){
result = glBuffers.get(glBuffersIndex);
}else{
result = new GlBuffer();
glBuffers.push(result);
}
result.index = glBuffersIndex;
glBuffersIndex++;
return result;
}
public static void trimUnused(){
while(glBuffers.size() > 0){
GlBuffer gb = glBuffers.get(glBuffers.size()-1);
if(gb.released()){
gb.deleteGlBuffers();
glBuffers.popSilently();
}else{
break;
}
}
}
private int glBufferId;
private int size;
private static int globalCount = 0;
public GlBuffer()
{
this.glBufferId = OpenGlHelper.glGenBuffers();
globalCount++;
}
public void bindBuffer()
{
OpenGlHelper.glBindBuffer(OpenGlHelper.GL_ARRAY_BUFFER, this.glBufferId);
}
public void setBufferData(ByteBuffer data)
{
vmem -= this.size;
this.bindBuffer();
OpenGlHelper.glBufferData(OpenGlHelper.GL_ARRAY_BUFFER, data, 35044);
this.unbindBuffer();
this.size = data.limit();
vmem += this.size;
}
public void drawArrays(int mode, int count)
{
GL11.glDrawArrays(mode, 0, count);
}
public void unbindBuffer()
{
OpenGlHelper.glBindBuffer(OpenGlHelper.GL_ARRAY_BUFFER, 0);
}
public void deleteGlBuffers()
{
if (this.glBufferId >= 0)
{
OpenGlHelper.glDeleteBuffers(this.glBufferId);
this.glBufferId = -1;
globalCount--;
}
}
public void releaseGenBuffer(){
if(this.index == -1){
return;
}
GlBuffer self = glBuffers.get(this.index);
if(this != self){
throw new RuntimeException("wrong order in releaseGenBuffer");
}
glBuffersIndex--;
GlBuffer last = glBuffers.get(glBuffersIndex);
glBuffers.set(this.index, last);
glBuffers.set(glBuffersIndex, self);
last.index = this.index;
this.index = -1;
}
public boolean released(){
return this.index == -1;
}
public static int getGlobalCount(){
return globalCount;
}
public int getSize(){
return this.size;
}
}
public final class GlBuffersStack {
public GlBuffer[] stack;
public int size;
public GlBuffersStack(int initialCapacity) {
stack = new GlBuffer[initialCapacity];
}
public GlBuffer push(GlBuffer value) {
if (size + 1 >= stack.length) {
resizeStack(stack.length * 2);
}
stack[size++] = value;
return value;
}
public void popSilently() {
stack[--size] = null;
}
public GlBuffer pop() {
final GlBuffer result = stack[--size];
stack[size] = null;
return result;
}
public GlBuffer peek() {
return size == 0 ? null : stack[size - 1];
}
public int size() {
return size;
}
public boolean hasStuff() {
return size > 0;
}
public GlBuffer get(int i) {
return stack[i];
}
private void resizeStack(int newCapacity) {
GlBuffer[] newStack = new GlBuffer[newCapacity];
System.arraycopy(stack, 0, newStack, 0, Math.min(size, newCapacity));
stack = newStack;
}
public String toString() {
StringBuffer result = new StringBuffer("[");
for (int i = 0; i < size; i++) {
if (i > 0) {
result.append(", ");
}
result.append(stack[i]);
}
result.append(']');
return result.toString();
}
public void set(int i, GlBuffer value) {
stack[i] = value;
}
}
Looks great. I tested and it switches worlds very fast! I think it should be applied to Minecraft.