Reduce buffer streaming VRAM usage

This commit is contained in:
lax1dude 2024-12-13 00:20:32 -08:00
parent eb6131cacf
commit a6958812bb
3 changed files with 89 additions and 25 deletions

View File

@ -1190,8 +1190,8 @@ public class EaglerAdapterGL30 extends EaglerAdapterImpl2 {
bindTheShader(); bindTheShader();
StreamBufferInstance sb = shader.streamBuffer.getBuffer(bl); StreamBufferInstance sb = shader.streamBuffer.getBuffer(bl);
_wglBindVertexArray0(sb.vertexArray); _wglBindVertexArray0(sb.getVertexArray());
_wglBindBuffer(_wGL_ARRAY_BUFFER, sb.vertexBuffer); _wglBindBuffer(_wGL_ARRAY_BUFFER, sb.getVertexBuffer());
if (!shader.bufferIsInitialized) { if (!shader.bufferIsInitialized) {
shader.bufferIsInitialized = true; shader.bufferIsInitialized = true;
_wglBufferData(_wGL_ARRAY_BUFFER, blankUploadArray, _wGL_DYNAMIC_DRAW); _wglBufferData(_wGL_ARRAY_BUFFER, blankUploadArray, _wGL_DYNAMIC_DRAW);
@ -1625,15 +1625,17 @@ public class EaglerAdapterGL30 extends EaglerAdapterImpl2 {
long millis = steadyTimeMillis(); long millis = steadyTimeMillis();
long remaining = timerPtr[0] - millis; long remaining = timerPtr[0] - millis;
if(remaining > 0) { if(remaining > 0) {
if(isWebGL) { if(isWebGL && immediateContinueSupported()) {
immediateContinue(); // cannot stack setTimeouts, or it will throttle immediateContinue(); // cannot stack setTimeouts, or it will throttle
millis = steadyTimeMillis(); millis = steadyTimeMillis();
remaining = timerPtr[0] - millis; remaining = timerPtr[0] - millis;
if(remaining > 0) { if(remaining > 0) {
sleep((int)remaining); sleep((int)remaining);
millis = steadyTimeMillis();
} }
}else { }else {
sleep((int)remaining); sleep((int)remaining);
millis = steadyTimeMillis();
} }
blocked = true; blocked = true;
} }

View File

@ -4,10 +4,48 @@ import static net.lax1dude.eaglercraft.EaglerAdapter.*;
public class StreamBuffer { public class StreamBuffer {
public static final int poolSize = 16;
public final int initialSize; public final int initialSize;
public final int initialCount; public final int initialCount;
public final int maxCount; 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 StreamBufferInstance[] buffers;
protected int currentBufferId = 0; protected int currentBufferId = 0;
@ -17,9 +55,8 @@ public class StreamBuffer {
public static class StreamBufferInstance { public static class StreamBufferInstance {
protected PoolInstance poolInstance = null;
protected BufferArrayGL vertexArray = null; protected BufferArrayGL vertexArray = null;
protected BufferGL vertexBuffer = null;
protected int vertexBufferSize = 0;
public boolean bindQuad16 = false; public boolean bindQuad16 = false;
public boolean bindQuad32 = false; public boolean bindQuad32 = false;
@ -29,7 +66,7 @@ public class StreamBuffer {
} }
public BufferGL getVertexBuffer() { 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) { public StreamBuffer(int initialSize, int initialCount, int maxCount, IStreamBufferInitializer initializer) {
if(maxCount > poolSize) {
maxCount = poolSize;
}
this.buffers = new StreamBufferInstance[initialCount]; this.buffers = new StreamBufferInstance[initialCount];
for(int i = 0; i < this.buffers.length; ++i) { 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.initialSize = initialSize;
this.initialCount = initialCount; this.initialCount = initialCount;
@ -51,18 +93,10 @@ public class StreamBuffer {
public StreamBufferInstance getBuffer(int requiredMemory) { public StreamBufferInstance getBuffer(int requiredMemory) {
StreamBufferInstance next = buffers[(currentBufferId++) % buffers.length]; StreamBufferInstance next = buffers[(currentBufferId++) % buffers.length];
if(next.vertexBuffer == null) { resizeInstance(next.poolInstance, requiredMemory);
next.vertexBuffer = _wglCreateBuffer();
}
if(next.vertexArray == null) { if(next.vertexArray == null) {
next.vertexArray = _wglCreateVertexArray(); next.vertexArray = _wglCreateVertexArray();
initializer.initialize(next.vertexArray, next.vertexBuffer); initializer.initialize(next.vertexArray, next.poolInstance.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;
} }
return next; return next;
} }
@ -83,12 +117,10 @@ public class StreamBuffer {
if(buffers[i].vertexArray != null) { if(buffers[i].vertexArray != null) {
_wglDeleteVertexArray(buffers[i].vertexArray); _wglDeleteVertexArray(buffers[i].vertexArray);
} }
if(buffers[i].vertexBuffer != null) {
_wglDeleteBuffer(buffers[i].vertexBuffer);
}
} }
} }
buffers = newArray; buffers = newArray;
refill();
} }
overflowCounter = 0; overflowCounter = 0;
}else if(overflowCounter > 15) { }else if(overflowCounter > 15) {
@ -106,25 +138,52 @@ public class StreamBuffer {
} }
} }
buffers = newArray; buffers = newArray;
refill();
} }
overflowCounter = 0; overflowCounter = 0;
} }
currentBufferId = 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() { public void destroy() {
for(int i = 0; i < buffers.length; ++i) { for(int i = 0; i < buffers.length; ++i) {
StreamBufferInstance next = buffers[i]; StreamBufferInstance next = buffers[i];
if(next.vertexArray != null) { if(next.vertexArray != null) {
_wglDeleteVertexArray(next.vertexArray); _wglDeleteVertexArray(next.vertexArray);
} }
if(next.vertexBuffer != null) {
_wglDeleteBuffer(next.vertexBuffer);
}
} }
buffers = new StreamBufferInstance[initialCount]; buffers = new StreamBufferInstance[initialCount];
for(int i = 0; i < buffers.length; ++i) { for(int i = 0; i < initialCount; ++i) {
buffers[i] = new StreamBufferInstance(); 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;
}
}
}
} }

View File

@ -1774,6 +1774,9 @@ public class EaglerAdapterImpl2 {
sleep(0); sleep(0);
} }
} }
public static final boolean immediateContinueSupported() {
return immediateContinueChannel != null;
}
private static final JSString emptyJSString = JSString.valueOf(""); private static final JSString emptyJSString = JSString.valueOf("");
@Async @Async
private static native void immediateContinueTeaVM0(); private static native void immediateContinueTeaVM0();