stage VBO/IBO upload and allow global IBO

This commit is contained in:
James Seibel
2026-03-21 16:03:18 -05:00
parent d85589c41a
commit 668ba491e8
7 changed files with 171 additions and 174 deletions
@@ -28,12 +28,9 @@ import com.seibel.distanthorizons.common.render.blaze.wrappers.buffer.BlazeVerte
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GlQuadIndexBuffer;
import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
@@ -45,8 +42,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTe
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import net.minecraft.resources.Identifier;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -316,7 +311,7 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
profiler.popPush("rendering");
// render each buffer
IVertexBufferWrapper[] bufferWrapperList = opaquePass ? bufferContainer.vbos : bufferContainer.vbosTransparent;
IVertexBufferWrapper[] bufferWrapperList = opaquePass ? bufferContainer.vboOpaqueWrappers : bufferContainer.vboTransparentWrappers;
for (int i = 0; i < bufferWrapperList.length; i++)
{
BlazeVertexBufferWrapper bufferWrapper = (BlazeVertexBufferWrapper) bufferWrapperList[i];
@@ -336,10 +331,10 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, new DhApiBeforeBufferRenderEvent.EventParam(renderEventParam, modelPos));
}
renderPass.setIndexBuffer(bufferWrapper.indexBuffer, VertexFormat.IndexType.INT);
renderPass.setVertexBuffer(0, bufferWrapper.vboGpuBuffer); // vertex buffer can only be "0" lol
renderPass.setIndexBuffer(bufferWrapper.getIndexGpuBuffer(), VertexFormat.IndexType.INT);
renderPass.setVertexBuffer(0, bufferWrapper.vertexGpuBuffer); // vertex buffer can only be "0" lol
if (!bufferWrapper.vboGpuBuffer.isClosed())
if (!bufferWrapper.vertexGpuBuffer.isClosed())
{
renderPass.drawIndexed(
/*indexStart*/ 0,
@@ -10,18 +10,19 @@ import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.CommandEncoder;
import com.mojang.blaze3d.systems.GpuDevice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GlQuadIndexBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
{
private static final AbstractDhRenderApiDefinition RENDER_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
@@ -29,20 +30,56 @@ public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
public final String name;
public String getName() { return this.name; }
public GpuBuffer vboGpuBuffer = null;
public GpuBuffer indexBuffer = null;
public GpuBuffer vertexGpuBuffer = null;
public int vertexCount = -1;
public int indexCount = -1;
public boolean uploaded = false;
private GpuBuffer indexGpuBuffer = null;
private static GpuBuffer GLOBAL_INDEX_GPU_BUFFER = null;
public GpuBuffer getIndexGpuBuffer()
{
if (RENDER_DEF.useSingleIbo())
{
return GLOBAL_INDEX_GPU_BUFFER;
}
else
{
return this.indexGpuBuffer;
}
}
//=============//
// constructor //
//=============//
//region
static
{
if (RENDER_DEF.useSingleIbo())
{
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Global IBO Creation", () ->
{
int maxSize = LodQuadBuilder.getMaxBufferByteSize();
int maxVertexCount = maxSize / LodQuadBuilder.BYTES_PER_VERTEX;
int maxQuadCount = (maxVertexCount / 4);
ByteBuffer indexBuffer = IndexBufferBuilder.createBuffer(maxQuadCount);
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_INDEX;
GLOBAL_INDEX_GPU_BUFFER = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity());
GpuBufferSlice bufferSlice = new GpuBufferSlice(GLOBAL_INDEX_GPU_BUFFER, /*offset*/ 0, indexBuffer.capacity());
COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer);
});
}
}
public BlazeVertexBufferWrapper(String name) { this.name = name; }
//endregion
@@ -55,7 +92,7 @@ public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
//region
@Override
public void upload(ByteBuffer vertexBuffer, int vertexCount)
public void uploadVertexBuffer(ByteBuffer vertexBuffer, int vertexCount)
{
int oldVertexCount = this.vertexCount;
@@ -65,50 +102,63 @@ public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
this.uploaded = true;
if (this.vboGpuBuffer == null
if (this.vertexGpuBuffer == null
// recreating if the size changes is always necessary (even if we only need a smaller amount)
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|| oldVertexCount != vertexCount)
{
if (this.vboGpuBuffer != null)
if (this.vertexGpuBuffer != null)
{
this.vboGpuBuffer.close();
this.vertexGpuBuffer.close();
}
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_VERTEX;
int byteSize = (vertexBuffer.limit() - vertexBuffer.position());
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getName, usage, byteSize);
this.vertexGpuBuffer = GPU_DEVICE.createBuffer(this::getName, usage, byteSize);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, /*offset*/0, byteSize);
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertexGpuBuffer, /*offset*/0, byteSize);
COMMAND_ENCODER.writeToBuffer(bufferSlice, vertexBuffer);
}
}
@Override
public void uploadIndexBuffer(ByteBuffer buffer, int vertexCount)
{
int oldIndexCount = this.indexCount;
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
this.indexCount = (int)(vertexCount * 1.5);
if (RENDER_DEF.useSingleIbo())
{
// ignore index uploading when running a single IBO
return;
}
if (this.indexBuffer == null
// recreating if the size changes is always necessary (even if we only need a smaller amount)
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|| oldVertexCount != vertexCount)
// recreating if the size changes is always necessary (even if we only need a smaller amount)
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
if (this.indexGpuBuffer == null
|| oldIndexCount != this.indexCount)
{
if (this.indexBuffer != null)
if (this.indexGpuBuffer != null)
{
this.indexBuffer.close();
this.indexGpuBuffer.close();
}
int quadCount = (this.vertexCount / 4);
ByteBuffer indexBuffer = MemoryUtil.memAlloc(quadCount * 6 * GLEnums.getTypeSize(GL32.GL_UNSIGNED_INT));
indexBuffer.order(ByteOrder.nativeOrder());
GlQuadIndexBuffer.buildBuffer(quadCount, indexBuffer, GL32.GL_UNSIGNED_INT);
ByteBuffer indexBuffer = IndexBufferBuilder.createBuffer(this.vertexCount);
int usage = GpuBuffer.USAGE_COPY_DST
| GpuBuffer.USAGE_INDEX;
this.indexBuffer = GPU_DEVICE.createBuffer(this::getIndexBufferName, usage, indexBuffer.capacity());
this.indexGpuBuffer = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity());
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexBuffer, /*offset*/ 0, indexBuffer.capacity());
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, /*offset*/ 0, indexBuffer.capacity());
COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer);
}
}
private String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
private static String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
//endregion
@@ -122,9 +172,14 @@ public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
@Override
public void close()
{
if (this.vboGpuBuffer != null)
if (this.vertexGpuBuffer != null)
{
this.vboGpuBuffer.close();
this.vertexGpuBuffer.close();
}
if (this.indexGpuBuffer != null)
{
this.indexGpuBuffer.close();
}
}
@@ -34,9 +34,8 @@ public class GLIndexBuffer extends GLBuffer
* bigger than the upload payload
*/
protected int indicesCount = 0;
public int getIndicesCount() { return this.indicesCount; }
protected int type = GL32.GL_UNSIGNED_INT;
public int getType() { return type; }
protected int glType = GL32.GL_UNSIGNED_INT;
public int getGlType() { return this.glType; }
public GLIndexBuffer(boolean isBufferStorage)
{
@@ -23,6 +23,10 @@ import java.nio.ByteBuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
import org.lwjgl.opengl.GL32;
@@ -37,6 +41,8 @@ import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
*/
public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
{
private static final AbstractDhRenderApiDefinition RENDER_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
/**
* When uploading to a buffer that is too small, recreate it this many times
* bigger than the upload payload
@@ -44,7 +50,20 @@ public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
protected int vertexCount = 0;
public int getVertexCount() { return this.vertexCount; }
public GlQuadIndexBuffer quadIBO = null;
private GlQuadIndexBuffer quadIBO = null;
private static GlQuadIndexBuffer GLOBAL_QUAD_IBO = null;
public GlQuadIndexBuffer getQuadIBO()
{
if (RENDER_DEF.useSingleIbo())
{
return GLOBAL_QUAD_IBO;
}
else
{
return this.quadIBO;
}
}
@@ -53,6 +72,22 @@ public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
//=============//
//region
static
{
if (RENDER_DEF.useSingleIbo())
{
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Global IBO Creation", () ->
{
GLOBAL_QUAD_IBO = new GlQuadIndexBuffer();
int maxSize = LodQuadBuilder.getMaxBufferByteSize();
int maxVertexCount = maxSize / LodQuadBuilder.BYTES_PER_VERTEX;
int maxQuadCount = (maxVertexCount / 4);
GLOBAL_QUAD_IBO.upload(maxQuadCount);
});
}
}
public GLVertexBuffer() { this(GLProxy.getInstance().getGpuUploadMethod() == EDhApiGpuUploadMethod.BUFFER_STORAGE); }
public GLVertexBuffer(boolean isBufferStorage) { super(isBufferStorage); }
@@ -69,7 +104,7 @@ public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
public int getBufferBindingTarget() { return GL32.GL_ARRAY_BUFFER; }
@Override
public void upload(ByteBuffer buffer, int vertexCount)
public void uploadVertexBuffer(ByteBuffer buffer, int vertexCount)
{
EDhApiGpuUploadMethod uploadMethod = GLProxy.getInstance().getGpuUploadMethod();
int maxBufferSize = LodQuadBuilder.getMaxBufferByteSize();
@@ -91,28 +126,41 @@ public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
// If size is zero, just ignore it.
if (byteBuffer.limit() - byteBuffer.position() != 0)
{
// vertex data
{
super.uploadBuffer(byteBuffer, uploadMethod, maxExpansionSize, uploadMethod.useBufferStorage ? 0 : GL32.GL_STATIC_DRAW);
}
// index data
{
if (this.quadIBO != null)
{
this.quadIBO.close();
}
int quadCount = (vertexCount / 4);
this.quadIBO = new GlQuadIndexBuffer();
this.quadIBO.reserve(quadCount);
}
super.uploadBuffer(byteBuffer, uploadMethod, maxExpansionSize, uploadMethod.useBufferStorage ? 0 : GL32.GL_STATIC_DRAW);
}
this.vertexCount = vertexCount;
}
@Override
public void uploadIndexBuffer(ByteBuffer buffer, int vertexCount)
{
if (RENDER_DEF.useSingleIbo())
{
// ignore index uploading when running a single IBO
return;
}
// If size is zero, just ignore it.
if (vertexCount == 0)
{
return;
}
if (this.quadIBO != null)
{
this.quadIBO.close();
}
this.quadIBO = new GlQuadIndexBuffer();
int quadCount = (vertexCount / 4);
this.quadIBO.upload(quadCount);
}
//endregion
@@ -128,7 +176,10 @@ public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
public void destroyAsync()
{
super.destroyAsync();
this.quadIBO.destroyAsync();
if (this.quadIBO != null)
{
this.quadIBO.destroyAsync();
}
this.vertexCount = 0;
}
@@ -21,6 +21,7 @@ package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import org.lwjgl.opengl.GL32;
@@ -42,7 +43,7 @@ public class GlQuadIndexBuffer extends GLIndexBuffer
public GlQuadIndexBuffer() { super(false); }
public void reserve(int quadCount)
public void upload(int quadCount)
{
if (quadCount < 0)
{
@@ -60,28 +61,12 @@ public class GlQuadIndexBuffer extends GLIndexBuffer
{
return;
}
int vertexCount = quadCount * 4; // 4 vertices per quad
if (vertexCount < 255)
{
// Reserve 1 for the reset index
this.type = GL32.GL_UNSIGNED_BYTE;
}
else if (vertexCount < 65535)
{
// Reserve 1 for the reset index
this.type = GL32.GL_UNSIGNED_SHORT;
}
else
{
this.type = GL32.GL_UNSIGNED_INT;
}
ByteBuffer buffer = MemoryUtil.memAlloc(this.indicesCount * GLEnums.getTypeSize(this.type));
buildBuffer(quadCount, buffer, this.type);
this.glType = GL32.GL_UNSIGNED_INT;
ByteBuffer buffer = IndexBufferBuilder.createBuffer(quadCount);
this.bind();
super.uploadBuffer(buffer, EDhApiGpuUploadMethod.DATA,
this.indicesCount * GLEnums.getTypeSize(this.type), GL32.GL_STATIC_DRAW);
this.indicesCount * GLEnums.getTypeSize(this.glType), GL32.GL_STATIC_DRAW);
MemoryUtil.memFree(buffer);
}
@@ -95,95 +80,7 @@ public class GlQuadIndexBuffer extends GLIndexBuffer
//=========//
//region
public int getCapacity() { return super.getSize() / GLEnums.getTypeSize(this.getType()); }
//endregion
//==========//
// building //
//==========//
//region
public static void buildBuffer(int quadCount, ByteBuffer buffer, int type)
{
switch (type)
{
case GL32.GL_UNSIGNED_BYTE:
buildBufferByte(quadCount, buffer);
break;
case GL32.GL_UNSIGNED_SHORT:
buildBufferShort(quadCount, buffer);
break;
case GL32.GL_UNSIGNED_INT:
buildBufferInt(quadCount, buffer);
break;
default:
throw new IllegalStateException("Unknown buffer type: [" + type + "].");
}
}
private static void buildBufferByte(int quadCount, ByteBuffer buffer)
{
for (int i = 0; i < quadCount; i++)
{
int vIndex = i * 4;
// First triangle
buffer.put((byte) (vIndex));
buffer.put((byte) (vIndex + 1));
buffer.put((byte) (vIndex + 2));
// Second triangle
buffer.put((byte) (vIndex + 2));
buffer.put((byte) (vIndex + 3));
buffer.put((byte) (vIndex));
}
if (buffer.hasRemaining())
{
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
}
buffer.rewind();
}
private static void buildBufferShort(int quadCount, ByteBuffer buffer)
{
for (int i = 0; i < quadCount; i++)
{
int vIndex = i * 4;
// First triangle
buffer.putShort((short) (vIndex));
buffer.putShort((short) (vIndex + 1));
buffer.putShort((short) (vIndex + 2));
// Second triangle
buffer.putShort((short) (vIndex + 2));
buffer.putShort((short) (vIndex + 3));
buffer.putShort((short) (vIndex));
}
if (buffer.hasRemaining())
{
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
}
buffer.rewind();
}
private static void buildBufferInt(int quadCount, ByteBuffer buffer)
{
for (int i = 0; i < quadCount; i++)
{
int vIndex = i * 4;
// First triangle
buffer.putInt(vIndex);
buffer.putInt(vIndex + 1);
buffer.putInt(vIndex + 2);
// Second triangle
buffer.putInt(vIndex + 2);
buffer.putInt(vIndex + 3);
buffer.putInt(vIndex);
}
if (buffer.hasRemaining())
{
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
}
buffer.rewind();
}
public int getCapacity() { return super.getSize() / GLEnums.getTypeSize(this.getGlType()); }
//endregion
@@ -328,7 +328,7 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, new DhApiBeforeBufferRenderEvent.EventParam(renderEventParam, modelPos));
}
IVertexBufferWrapper[] vertexBuffers = (opaquePass ? bufferContainer.vbos : bufferContainer.vbosTransparent);
IVertexBufferWrapper[] vertexBuffers = (opaquePass ? bufferContainer.vboOpaqueWrappers : bufferContainer.vboTransparentWrappers);
for (int vboIndex = 0; vboIndex < vertexBuffers.length; vboIndex++)
{
GLVertexBuffer vbo = (GLVertexBuffer) vertexBuffers[vboIndex];
@@ -346,16 +346,16 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS
int indexCount = (int)(vbo.getVertexCount() * 1.5);
vbo.bind();
vbo.quadIBO.bind();
vbo.getQuadIBO().bind();
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bindVertexBuffer(vbo.getId());
GL32.glDrawElements(
GL32.GL_TRIANGLES,
indexCount,
vbo.quadIBO.getType(), 0);
vbo.getQuadIBO().getGlType(), 0);
vbo.unbind();
vbo.quadIBO.unbind();
vbo.getQuadIBO().unbind();
}
}
}