From 1196568a7c854c31f0ed53fadcee20eba12b43d3 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 26 Apr 2022 18:25:49 +0100 Subject: [PATCH] =?UTF-8?q?Use=20U=CC=B6=CC=8B=CC=9A=CC=B9n=CC=B5=CC=82?= =?UTF-8?q?=CC=81=CC=A6s=CC=B7=CD=90=CC=AD=CC=B2a=CC=B6=CC=94=CC=9E=CD=94f?= =?UTF-8?q?=CC=B8=CD=81=CC=80=CC=A0e=CC=B5=CC=8B=CC=80=CD=94=20to=20upload?= =?UTF-8?q?=20the=20monitor's=20contents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VBO renderer needs to generate a buffer with two quads for each cell, and then transfer it to the GPU. For large monitors, generating this buffer can get quite slow. Most of the issues come from IVertexBuilder (VertexConsumer under MojMap) having a lot of overhead. By emitting a ByteBuffer directly (and doing so with Unsafe to avoid bounds checks), we can improve performance 10 fold, going from 3fps/300ms for 120 monitors to 111fps/9ms. See 41fa95bce4408239bc59e032bfa9fdc7418bcb19 and #1065 for some more context and other exploratory work. The key thing to note is we _need_ a separate version of FWFR for emitting to a ByteBuffer, as introducing polymorphism to it comes with a significant performance hit. --- .../render/TileEntityMonitorRenderer.java | 65 ++--- .../text/DirectFixedWidthFontRenderer.java | 231 ++++++++++++++++++ .../render/text/FixedWidthFontRenderer.java | 12 +- .../client/util/DirectBuffers.java | 83 +++++++ .../client/util/DirectVertexBuffer.java | 79 ++++++ .../peripheral/monitor/ClientMonitor.java | 7 +- 6 files changed, 441 insertions(+), 36 deletions(-) create mode 100644 src/main/java/dan200/computercraft/client/render/text/DirectFixedWidthFontRenderer.java create mode 100644 src/main/java/dan200/computercraft/client/util/DirectBuffers.java create mode 100644 src/main/java/dan200/computercraft/client/util/DirectVertexBuffer.java diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 2dbf002d5..c2306bc68 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -9,7 +9,10 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.client.FrameInfo; +import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer; import dan200.computercraft.client.render.text.FixedWidthFontRenderer; +import dan200.computercraft.client.util.DirectBuffers; +import dan200.computercraft.client.util.DirectVertexBuffer; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; @@ -17,15 +20,16 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.DirectionUtil; -import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.client.renderer.vertex.VertexBuffer; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Matrix4f; -import net.minecraft.util.math.vector.TransformationMatrix; import net.minecraft.util.math.vector.Vector3f; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; @@ -44,9 +48,7 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer * the monitor frame and contents. */ private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1); - private static ByteBuffer tboContents; - - private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix(); + private static ByteBuffer backingBuffer; public TileEntityMonitorRenderer( TileEntityRendererDispatcher rendererDispatcher ) { @@ -170,14 +172,7 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer if( redraw ) { - int size = width * height * 3; - if( tboContents == null || tboContents.capacity() < size ) - { - tboContents = GLAllocation.createByteBuffer( size ); - } - - ByteBuffer monitorBuffer = tboContents; - monitorBuffer.clear(); + ByteBuffer monitorBuffer = getBuffer( width * height * 3 ); for( int y = 0; y < height; y++ ) { TextBuffer text = terminal.getLine( y ), textColour = terminal.getTextColourLine( y ), background = terminal.getBackgroundColourLine( y ); @@ -217,28 +212,42 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer case VBO: { - VertexBuffer vbo = monitor.buffer; + DirectVertexBuffer vbo = monitor.buffer; if( redraw ) { - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder builder = tessellator.getBuilder(); - builder.begin( RenderTypes.TERMINAL_WITHOUT_DEPTH.mode(), RenderTypes.TERMINAL_WITHOUT_DEPTH.format() ); - FixedWidthFontRenderer.drawTerminalWithoutCursor( - IDENTITY, builder, 0, 0, - terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin - ); + int vertexSize = RenderTypes.TERMINAL_WITHOUT_DEPTH.format().getVertexSize(); + ByteBuffer buffer = getBuffer( DirectFixedWidthFontRenderer.getVertexCount( terminal ) * vertexSize ); - builder.end(); - vbo.upload( builder ); + // Draw the main terminal and store how many vertices it has. + DirectFixedWidthFontRenderer.drawTerminalWithoutCursor( + buffer, 0, 0, terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin + ); + int termIndexes = buffer.position() / vertexSize; + + buffer.flip(); + + vbo.upload( termIndexes, RenderTypes.TERMINAL_WITHOUT_DEPTH.format(), buffer ); } - vbo.bind(); - RenderTypes.TERMINAL_WITHOUT_DEPTH.format().setupBufferState( 0L ); - vbo.draw( matrix, RenderTypes.TERMINAL_WITHOUT_DEPTH.mode() ); - VertexBuffer.unbind(); + vbo.draw( matrix, vbo.getIndexCount() ); + RenderTypes.TERMINAL_WITHOUT_DEPTH.format().clearBufferState(); break; } } } + + @Nonnull + private static ByteBuffer getBuffer( int capacity ) + { + + ByteBuffer buffer = backingBuffer; + if( buffer == null || buffer.capacity() < capacity ) + { + buffer = backingBuffer = buffer == null ? DirectBuffers.createByteBuffer( capacity ) : DirectBuffers.resizeByteBuffer( buffer, capacity ); + } + + buffer.clear(); + return buffer; + } } diff --git a/src/main/java/dan200/computercraft/client/render/text/DirectFixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/render/text/DirectFixedWidthFontRenderer.java new file mode 100644 index 000000000..c528cc951 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render/text/DirectFixedWidthFontRenderer.java @@ -0,0 +1,231 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.render.text; + +import com.mojang.blaze3d.vertex.IVertexBuilder; +import dan200.computercraft.client.util.DirectBuffers; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.shared.util.Colour; +import dan200.computercraft.shared.util.Palette; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import org.lwjgl.system.MemoryUtil; + +import javax.annotation.Nonnull; +import java.nio.ByteBuffer; + +import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.*; +import static org.lwjgl.system.MemoryUtil.memPutByte; +import static org.lwjgl.system.MemoryUtil.memPutFloat; + +/** + * An optimised copy of {@link FixedWidthFontRenderer} emitter emits directly to a {@link ByteBuffer} rather than + * emitting to {@link IVertexBuilder}. This allows us to emit vertices very quickly, when using the VBO renderer. + * + * There are some limitations here: + *
    + *
  • No transformation matrix (not needed for VBOs).
  • + *
  • Only works with {@link DefaultVertexFormats#POSITION_COLOR_TEX}.
  • + *
  • The buffer MUST be allocated with {@link DirectBuffers}, and not through any other means.
  • + *
+ * + * Note this is almost an exact copy of {@link FixedWidthFontRenderer}. While the code duplication is unfortunate, + * it is measurably faster than introducing polymorphism into {@link FixedWidthFontRenderer}. + * + * IMPORTANT: When making changes to this class, please check if you need to make the same changes to + * {@link FixedWidthFontRenderer}. + */ +public final class DirectFixedWidthFontRenderer +{ + private DirectFixedWidthFontRenderer() + { + } + + private static void drawChar( ByteBuffer buffer, float x, float y, int index, byte[] colour ) + { + // Short circuit to avoid the common case - the texture should be blank here after all. + if( index == '\0' || index == ' ' ) return; + + int column = index % 16; + int row = index / 16; + + int xStart = 1 + column * (FONT_WIDTH + 2); + int yStart = 1 + row * (FONT_HEIGHT + 2); + + quad( + buffer, x, y, x + FONT_WIDTH, y + FONT_HEIGHT, colour, + xStart / WIDTH, yStart / WIDTH, (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH + ); + } + + private static void drawQuad( ByteBuffer emitter, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex ) + { + byte[] colour = palette.getByteColour( getColour( colourIndex, Colour.BLACK ), greyscale ); + quad( emitter, x, y, x + width, y + height, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END ); + } + + private static void drawBackground( + @Nonnull ByteBuffer buffer, float x, float y, @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, + float leftMarginSize, float rightMarginSize, float height + ) + { + if( leftMarginSize > 0 ) + { + drawQuad( buffer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) ); + } + + if( rightMarginSize > 0 ) + { + drawQuad( buffer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ) ); + } + + // Batch together runs of identical background cells. + int blockStart = 0; + char blockColour = '\0'; + for( int i = 0; i < backgroundColour.length(); i++ ) + { + char colourIndex = backgroundColour.charAt( i ); + if( colourIndex == blockColour ) continue; + + if( blockColour != '\0' ) + { + drawQuad( buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour ); + } + + blockColour = colourIndex; + blockStart = i; + } + + if( blockColour != '\0' ) + { + drawQuad( buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour ); + } + } + + private static void drawString( @Nonnull ByteBuffer buffer, float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nonnull Palette palette, boolean greyscale ) + { + for( int i = 0; i < text.length(); i++ ) + { + byte[] colour = palette.getByteColour( getColour( textColour.charAt( i ), Colour.BLACK ), greyscale ); + + int index = text.charAt( i ); + if( index > 255 ) index = '?'; + drawChar( buffer, x + i * FONT_WIDTH, y, index, colour ); + } + } + + public static void drawTerminalWithoutCursor( + @Nonnull ByteBuffer buffer, float x, float y, @Nonnull Terminal terminal, boolean greyscale, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) + { + Palette palette = terminal.getPalette(); + int height = terminal.getHeight(); + + // Top and bottom margins + drawBackground( + buffer, x, y - topMarginSize, terminal.getBackgroundColourLine( 0 ), palette, greyscale, + leftMarginSize, rightMarginSize, topMarginSize + ); + + drawBackground( + buffer, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine( height - 1 ), palette, greyscale, + leftMarginSize, rightMarginSize, bottomMarginSize + ); + + // The main text + for( int i = 0; i < height; i++ ) + { + float rowY = y + FONT_HEIGHT * i; + drawBackground( + buffer, x, rowY, terminal.getBackgroundColourLine( i ), palette, greyscale, + leftMarginSize, rightMarginSize, FONT_HEIGHT + ); + drawString( + buffer, x, rowY, terminal.getLine( i ), terminal.getTextColourLine( i ), + palette, greyscale + ); + } + } + + public static void drawCursor( @Nonnull ByteBuffer buffer, float x, float y, @Nonnull Terminal terminal, boolean greyscale ) + { + if( isCursorVisible( terminal ) ) + { + byte[] colour = terminal.getPalette().getByteColour( 15 - terminal.getTextColour(), greyscale ); + drawChar( buffer, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour ); + } + } + + public static int getVertexCount( Terminal terminal ) + { + return (1 + (terminal.getHeight() + 2) * terminal.getWidth() * 2) * 4; + } + + private static void quad( ByteBuffer buffer, float x1, float y1, float x2, float y2, byte[] rgba, float u1, float v1, float u2, float v2 ) + { + // Emit a single quad to our buffer. This uses Unsafe (well, LWJGL's MemoryUtil) to directly blit bytes to the + // underlying buffer. This allows us to have a single bounds check up-front, rather than one for every write. + // This provides significant performance gains, at the cost of well, using Unsafe. + // Each vertex is 24 bytes, giving 96 bytes in total. Vertices are of the form (xyz:FFF)(rgba:BBBB)(uv:FF), + // which matches the POSITION_COLOR_TEX vertex format. + + int position = buffer.position(); + long addr = MemoryUtil.memAddress( buffer ); + + // We're doing terrible unsafe hacks below, so let's be really sure that what we're doing is reasonable. + if( position < 0 || 96 > buffer.limit() - position ) throw new IndexOutOfBoundsException(); + // Require the pointer to be aligned to a 32-bit boundary. + if( (addr & 3) != 0 ) throw new IllegalStateException( "Memory is not aligned" ); + // Also assert the length of the array. This appears to help elide bounds checks on the array in some circumstances. + if( rgba.length != 4 ) throw new IllegalStateException(); + + memPutFloat( addr + 0, x1 ); + memPutFloat( addr + 4, y1 ); + memPutFloat( addr + 8, 0 ); + memPutByte( addr + 12, rgba[0] ); + memPutByte( addr + 13, rgba[1] ); + memPutByte( addr + 14, rgba[2] ); + memPutByte( addr + 15, (byte) 255 ); + memPutFloat( addr + 16, u1 ); + memPutFloat( addr + 20, v1 ); + + memPutFloat( addr + 24, x1 ); + memPutFloat( addr + 28, y2 ); + memPutFloat( addr + 32, 0 ); + memPutByte( addr + 36, rgba[0] ); + memPutByte( addr + 37, rgba[1] ); + memPutByte( addr + 38, rgba[2] ); + memPutByte( addr + 39, (byte) 255 ); + memPutFloat( addr + 40, u1 ); + memPutFloat( addr + 44, v2 ); + + memPutFloat( addr + 48, x2 ); + memPutFloat( addr + 52, y2 ); + memPutFloat( addr + 56, 0 ); + memPutByte( addr + 60, rgba[0] ); + memPutByte( addr + 61, rgba[1] ); + memPutByte( addr + 62, rgba[2] ); + memPutByte( addr + 63, (byte) 255 ); + memPutFloat( addr + 64, u2 ); + memPutFloat( addr + 68, v2 ); + + memPutFloat( addr + 72, x2 ); + memPutFloat( addr + 76, y1 ); + memPutFloat( addr + 80, 0 ); + memPutByte( addr + 84, rgba[0] ); + memPutByte( addr + 85, rgba[1] ); + memPutByte( addr + 86, rgba[2] ); + memPutByte( addr + 87, (byte) 255 ); + memPutFloat( addr + 88, u2 ); + memPutFloat( addr + 92, v1 ); + + // Finally increment the position. + buffer.position( position + 96 ); + + // Well done for getting to the end of this method. I recommend you take a break and go look at cute puppies. + } +} diff --git a/src/main/java/dan200/computercraft/client/render/text/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/render/text/FixedWidthFontRenderer.java index 08137cd73..ba978369d 100644 --- a/src/main/java/dan200/computercraft/client/render/text/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/text/FixedWidthFontRenderer.java @@ -7,6 +7,7 @@ package dan200.computercraft.client.render.text; import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.client.FrameInfo; +import dan200.computercraft.client.render.RenderTypes; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Colour; @@ -30,9 +31,12 @@ import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMA * *
  • {@link #drawTerminal}: Draw a terminal with a cursor. This is used by the various computer GUIs to render the * whole term.
  • - *
  • {@link #drawBlocker}: When rendering a terminal using {@link dan200.computercraft.client.render.RenderTypes#TERMINAL_WITHOUT_DEPTH} you need to + *
  • {@link #drawBlocker}: When rendering a terminal using {@link RenderTypes#TERMINAL_WITHOUT_DEPTH} you need to * render an additional "depth blocker" on top of the monitor.
  • * + * + * IMPORTANT: When making changes to this class, please check if you need to make the same changes to + * {@link DirectFixedWidthFontRenderer}. */ public final class FixedWidthFontRenderer { @@ -40,10 +44,10 @@ public final class FixedWidthFontRenderer public static final int FONT_HEIGHT = 9; public static final int FONT_WIDTH = 6; - public static final float WIDTH = 256.0f; + static final float WIDTH = 256.0f; - private static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH; - private static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; + static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH; + static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; private static final byte[] BLACK = new byte[] { byteColour( Colour.BLACK.getR() ), byteColour( Colour.BLACK.getR() ), byteColour( Colour.BLACK.getR() ), (byte) 255 }; diff --git a/src/main/java/dan200/computercraft/client/util/DirectBuffers.java b/src/main/java/dan200/computercraft/client/util/DirectBuffers.java new file mode 100644 index 000000000..fcddf00aa --- /dev/null +++ b/src/main/java/dan200/computercraft/client/util/DirectBuffers.java @@ -0,0 +1,83 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.util; + +import com.mojang.blaze3d.platform.GlStateManager; +import org.lwjgl.opengl.GL; +import org.lwjgl.opengl.GL15C; +import org.lwjgl.opengl.GL45C; +import org.lwjgl.opengl.GLCapabilities; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; + +/** + * Provides utilities to interact with OpenGL's buffer objects, either using direct state access or binding/unbinding + * it. + */ +public class DirectBuffers +{ + public static final boolean HAS_DSA; + + static + { + GLCapabilities capabilities = GL.getCapabilities(); + HAS_DSA = capabilities.OpenGL45 || capabilities.GL_ARB_direct_state_access; + } + + public static int createBuffer() + { + return HAS_DSA ? GL45C.glCreateBuffers() : GL15C.glGenBuffers(); + } + + public static void setBufferData( int type, int id, ByteBuffer buffer, int flags ) + { + if( HAS_DSA ) + { + GL45C.glNamedBufferData( id, buffer, flags ); + } + else + { + GlStateManager._glBindBuffer( type, id ); + GlStateManager._glBufferData( type, buffer, GL15C.GL_STATIC_DRAW ); + GlStateManager._glBindBuffer( type, 0 ); + } + } + + public static void setEmptyBufferData( int type, int id, int flags ) + { + if( HAS_DSA ) + { + GL45C.glNamedBufferData( id, 0, flags ); + } + else + { + GlStateManager._glBindBuffer( type, id ); + GL45C.glBufferData( type, 0, GL15C.GL_STATIC_DRAW ); + GlStateManager._glBindBuffer( type, 0 ); + } + } + + private static final MemoryUtil.MemoryAllocator ALLOCATOR = MemoryUtil.getAllocator( false ); + + public static ByteBuffer createByteBuffer( int size ) + { + long i = ALLOCATOR.malloc( size ); + if( i == 0L ) throw new OutOfMemoryError( "Failed to allocate " + size + " bytes" ); + return MemoryUtil.memByteBuffer( i, size ); + } + + public static ByteBuffer resizeByteBuffer( ByteBuffer buffer, int size ) + { + long i = ALLOCATOR.realloc( MemoryUtil.memAddress0( buffer ), size ); + if( i == 0L ) + { + throw new OutOfMemoryError( "Failed to resize buffer from " + buffer.capacity() + " bytes to " + size + " bytes" ); + } + + return MemoryUtil.memByteBuffer( i, size ); + } +} diff --git a/src/main/java/dan200/computercraft/client/util/DirectVertexBuffer.java b/src/main/java/dan200/computercraft/client/util/DirectVertexBuffer.java new file mode 100644 index 000000000..4b2dc9569 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/util/DirectVertexBuffer.java @@ -0,0 +1,79 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.util; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.renderer.vertex.VertexBuffer; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.math.vector.Matrix4f; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL15; + +import java.nio.ByteBuffer; + +/** + * A version of {@link VertexBuffer} which allows uploading {@link ByteBuffer}s directly. + */ +public class DirectVertexBuffer implements AutoCloseable +{ + private int vertextBufferId; + private int indexCount; + private VertexFormat format; + + public DirectVertexBuffer() + { + vertextBufferId = DirectBuffers.createBuffer(); + } + + public void upload( int vertexCount, VertexFormat format, ByteBuffer buffer ) + { + RenderSystem.assertThread( RenderSystem::isOnGameThread ); + + DirectBuffers.setBufferData( GL15.GL_ARRAY_BUFFER, vertextBufferId, buffer, GL15.GL_STATIC_DRAW ); + + this.format = format; + indexCount = vertexCount; + } + + public void draw( Matrix4f matrix, int indexCount ) + { + bind(); + format.setupBufferState( 0 ); + + RenderSystem.pushMatrix(); + RenderSystem.loadIdentity(); + RenderSystem.multMatrix( matrix ); + RenderSystem.drawArrays( GL11.GL_QUADS, 0, indexCount ); + RenderSystem.popMatrix(); + + unbind(); + } + + public int getIndexCount() + { + return indexCount; + } + + @Override + public void close() + { + if( vertextBufferId >= 0 ) + { + RenderSystem.glDeleteBuffers( vertextBufferId ); + vertextBufferId = -1; + } + } + + private void bind() + { + RenderSystem.glBindBuffer( GL15.GL_ARRAY_BUFFER, () -> vertextBufferId ); + } + + private static void unbind() + { + RenderSystem.glBindBuffer( GL15.GL_ARRAY_BUFFER, () -> 0 ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java index 7d126cded..0c383b502 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -7,9 +7,8 @@ package dan200.computercraft.shared.peripheral.monitor; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; -import dan200.computercraft.client.render.RenderTypes; +import dan200.computercraft.client.util.DirectVertexBuffer; import dan200.computercraft.shared.common.ClientTerminal; -import net.minecraft.client.renderer.vertex.VertexBuffer; import net.minecraft.util.math.BlockPos; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -33,7 +32,7 @@ public final class ClientMonitor extends ClientTerminal public int tboBuffer; public int tboTexture; - public VertexBuffer buffer; + public DirectVertexBuffer buffer; public ClientMonitor( boolean colour, TileMonitor origin ) { @@ -82,7 +81,7 @@ public final class ClientMonitor extends ClientTerminal if( buffer != null ) return false; deleteBuffers(); - buffer = new VertexBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH.format() ); + buffer = new DirectVertexBuffer(); addMonitor(); return true;