From a6958812bb140b2756f943afc0bb931dc85bd844 Mon Sep 17 00:00:00 2001 From: lax1dude Date: Fri, 13 Dec 2024 00:20:32 -0800 Subject: [PATCH] Reduce buffer streaming VRAM usage --- .../eaglercraft/glemu/EaglerAdapterGL30.java | 8 +- .../eaglercraft/glemu/StreamBuffer.java | 103 ++++++++++++++---- .../adapter/EaglerAdapterImpl2.java | 3 + 3 files changed, 89 insertions(+), 25 deletions(-) diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/EaglerAdapterGL30.java b/src/main/java/net/lax1dude/eaglercraft/glemu/EaglerAdapterGL30.java index f65037d..91ff668 100644 --- a/src/main/java/net/lax1dude/eaglercraft/glemu/EaglerAdapterGL30.java +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/EaglerAdapterGL30.java @@ -1190,8 +1190,8 @@ public class EaglerAdapterGL30 extends EaglerAdapterImpl2 { bindTheShader(); StreamBufferInstance sb = shader.streamBuffer.getBuffer(bl); - _wglBindVertexArray0(sb.vertexArray); - _wglBindBuffer(_wGL_ARRAY_BUFFER, sb.vertexBuffer); + _wglBindVertexArray0(sb.getVertexArray()); + _wglBindBuffer(_wGL_ARRAY_BUFFER, sb.getVertexBuffer()); if (!shader.bufferIsInitialized) { shader.bufferIsInitialized = true; _wglBufferData(_wGL_ARRAY_BUFFER, blankUploadArray, _wGL_DYNAMIC_DRAW); @@ -1625,15 +1625,17 @@ public class EaglerAdapterGL30 extends EaglerAdapterImpl2 { long millis = steadyTimeMillis(); long remaining = timerPtr[0] - millis; if(remaining > 0) { - if(isWebGL) { + if(isWebGL && immediateContinueSupported()) { immediateContinue(); // cannot stack setTimeouts, or it will throttle millis = steadyTimeMillis(); remaining = timerPtr[0] - millis; if(remaining > 0) { sleep((int)remaining); + millis = steadyTimeMillis(); } }else { sleep((int)remaining); + millis = steadyTimeMillis(); } blocked = true; } diff --git a/src/main/java/net/lax1dude/eaglercraft/glemu/StreamBuffer.java b/src/main/java/net/lax1dude/eaglercraft/glemu/StreamBuffer.java index f322d56..2896a9a 100644 --- a/src/main/java/net/lax1dude/eaglercraft/glemu/StreamBuffer.java +++ b/src/main/java/net/lax1dude/eaglercraft/glemu/StreamBuffer.java @@ -4,10 +4,48 @@ import static net.lax1dude.eaglercraft.EaglerAdapter.*; public class StreamBuffer { + public static final int poolSize = 16; + public final int initialSize; public final int initialCount; public final int maxCount; + protected static final PoolInstance[] pool = new PoolInstance[poolSize]; + protected static int poolBufferID = 0; + + static { + for(int i = 0; i < poolSize; ++i) { + pool[i] = new PoolInstance(); + } + } + + protected static class PoolInstance { + + protected BufferGL vertexBuffer = null; + protected int vertexBufferSize = 0; + + } + + private static PoolInstance fillPoolInstance() { + PoolInstance ret = pool[poolBufferID++]; + if(poolBufferID > poolSize - 1) { + poolBufferID = 0; + } + return ret; + } + + private static void resizeInstance(PoolInstance instance, int requiredMemory) { + if(instance.vertexBuffer == null) { + instance.vertexBuffer = _wglCreateBuffer(); + } + if(instance.vertexBufferSize < requiredMemory) { + int newSize = (requiredMemory & 0xFFFFF000) + 0x2000; + _wglBindBuffer(_wGL_ARRAY_BUFFER, instance.vertexBuffer); + _wglBufferData00(_wGL_ARRAY_BUFFER, newSize, _wGL_STREAM_DRAW); + instance.vertexBufferSize = newSize; + } + } + protected StreamBufferInstance[] buffers; protected int currentBufferId = 0; @@ -17,9 +55,8 @@ public class StreamBuffer { public static class StreamBufferInstance { + protected PoolInstance poolInstance = null; protected BufferArrayGL vertexArray = null; - protected BufferGL vertexBuffer = null; - protected int vertexBufferSize = 0; public boolean bindQuad16 = false; public boolean bindQuad32 = false; @@ -29,7 +66,7 @@ public class StreamBuffer { } public BufferGL getVertexBuffer() { - return vertexBuffer; + return poolInstance.vertexBuffer; } } @@ -39,9 +76,14 @@ public class StreamBuffer { } public StreamBuffer(int initialSize, int initialCount, int maxCount, IStreamBufferInitializer initializer) { + if(maxCount > poolSize) { + maxCount = poolSize; + } this.buffers = new StreamBufferInstance[initialCount]; for(int i = 0; i < this.buffers.length; ++i) { - this.buffers[i] = new StreamBufferInstance(); + StreamBufferInstance j = new StreamBufferInstance(); + j.poolInstance = fillPoolInstance(); + this.buffers[i] = j; } this.initialSize = initialSize; this.initialCount = initialCount; @@ -51,18 +93,10 @@ public class StreamBuffer { public StreamBufferInstance getBuffer(int requiredMemory) { StreamBufferInstance next = buffers[(currentBufferId++) % buffers.length]; - if(next.vertexBuffer == null) { - next.vertexBuffer = _wglCreateBuffer(); - } + resizeInstance(next.poolInstance, requiredMemory); if(next.vertexArray == null) { next.vertexArray = _wglCreateVertexArray(); - initializer.initialize(next.vertexArray, next.vertexBuffer); - } - if(next.vertexBufferSize < requiredMemory) { - int newSize = (requiredMemory & 0xFFFFF000) + 0x2000; - _wglBindBuffer(_wGL_ARRAY_BUFFER, next.vertexBuffer); - _wglBufferData00(_wGL_ARRAY_BUFFER, newSize, _wGL_STREAM_DRAW); - next.vertexBufferSize = newSize; + initializer.initialize(next.vertexArray, next.poolInstance.vertexBuffer); } return next; } @@ -83,12 +117,10 @@ public class StreamBuffer { if(buffers[i].vertexArray != null) { _wglDeleteVertexArray(buffers[i].vertexArray); } - if(buffers[i].vertexBuffer != null) { - _wglDeleteBuffer(buffers[i].vertexBuffer); - } } } buffers = newArray; + refill(); } overflowCounter = 0; }else if(overflowCounter > 15) { @@ -106,25 +138,52 @@ public class StreamBuffer { } } buffers = newArray; + refill(); } overflowCounter = 0; } currentBufferId = 0; } + private void refill() { + for(int i = 0; i < buffers.length; ++i) { + PoolInstance j = fillPoolInstance(); + StreamBufferInstance k = buffers[i]; + if(j != k.poolInstance) { + PoolInstance l = k.poolInstance; + k.poolInstance = j; + if(k.vertexArray != null) { + if(j.vertexBuffer == null) { + resizeInstance(j, l.vertexBufferSize); + } + initializer.initialize(k.vertexArray, j.vertexBuffer); + } + } + } + } + public void destroy() { for(int i = 0; i < buffers.length; ++i) { StreamBufferInstance next = buffers[i]; if(next.vertexArray != null) { _wglDeleteVertexArray(next.vertexArray); } - if(next.vertexBuffer != null) { - _wglDeleteBuffer(next.vertexBuffer); - } } buffers = new StreamBufferInstance[initialCount]; - for(int i = 0; i < buffers.length; ++i) { - buffers[i] = new StreamBufferInstance(); + for(int i = 0; i < initialCount; ++i) { + StreamBufferInstance j = new StreamBufferInstance(); + j.poolInstance = fillPoolInstance(); + buffers[i] = j; } } + + public static void destroyPool() { + for(int i = 0; i < pool.length; ++i) { + if(pool[i].vertexBuffer != null) { + _wglDeleteBuffer(pool[i].vertexBuffer); + pool[i].vertexBuffer = null; + } + } + } + } diff --git a/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java b/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java index 39e38c3..9622f64 100644 --- a/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/adapter/EaglerAdapterImpl2.java @@ -1774,6 +1774,9 @@ public class EaglerAdapterImpl2 { sleep(0); } } + public static final boolean immediateContinueSupported() { + return immediateContinueChannel != null; + } private static final JSString emptyJSString = JSString.valueOf(""); @Async private static native void immediateContinueTeaVM0();