mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-12-13 19:50:31 +00:00
Don't render cursors separately
- For TBOs, we now pass cursor position, colour and blink state as variables to the shader, and use them to overlay the cursor texture in the right place. As we no longer need to render the cursor, we can skip the depth buffer, meaning we have to do one fewer upload+draw cycle. - For VBOs, we bake the cursor into the main VBO, and switch between rendering n and n+1 quads. We still need the depth blocker, but can save one upload+draw cycle when the cursor is visible. This saves significant time on the TBO renderer - somewhere between 4 and 7ms/frame, which bumps us up from 35 to 47fps on my test world (480 full-sized monitors, changing every tick). [Taken on 1.18, but should be similar on 1.16]
This commit is contained in:
parent
77a00b14ae
commit
22e8b9b587
@ -9,6 +9,7 @@ import com.google.common.base.Strings;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.client.FrameInfo;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
@ -29,7 +30,7 @@ import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.get
|
||||
|
||||
class MonitorTextureBufferShader
|
||||
{
|
||||
public static final int UNIFORM_SIZE = 4 * 4 * 16 + 4 + 4;
|
||||
public static final int UNIFORM_SIZE = 4 * 4 * 16 + 4 + 4 + 2 * 4 + 4;
|
||||
|
||||
static final int TEXTURE_INDEX = GL13.GL_TEXTURE3;
|
||||
|
||||
@ -40,6 +41,7 @@ class MonitorTextureBufferShader
|
||||
private static int uniformFont;
|
||||
private static int uniformTbo;
|
||||
private static int uniformMonitor;
|
||||
private static int uniformCursorBlink;
|
||||
|
||||
private static boolean initialised;
|
||||
private static boolean ok;
|
||||
@ -53,6 +55,9 @@ class MonitorTextureBufferShader
|
||||
RenderSystem.glUniformMatrix4( uniformMv, false, MATRIX_BUFFER );
|
||||
|
||||
GL31.glBindBufferBase( GL31.GL_UNIFORM_BUFFER, uniformMonitor, tboUniform );
|
||||
|
||||
int cursorAlpha = FrameInfo.getGlobalCursorBlink() ? 1 : 0;
|
||||
RenderSystem.glUniform1i( uniformCursorBlink, cursorAlpha );
|
||||
}
|
||||
|
||||
static boolean use()
|
||||
@ -107,6 +112,7 @@ class MonitorTextureBufferShader
|
||||
uniformTbo = getUniformLocation( program, "u_tbo" );
|
||||
uniformMonitor = GL31.glGetUniformBlockIndex( program, "u_monitor" );
|
||||
if( uniformMonitor == -1 ) throw new IllegalStateException( "Could not find uniformMonitor uniform." );
|
||||
uniformCursorBlink = getUniformLocation( program, "u_cursorBlink" );
|
||||
|
||||
ComputerCraft.log.info( "Loaded monitor shader." );
|
||||
return true;
|
||||
@ -187,8 +193,12 @@ class MonitorTextureBufferShader
|
||||
pos += 4 * 4; // std140 requires these are 4-wide
|
||||
}
|
||||
|
||||
int width = terminal.getWidth(), height = terminal.getHeight();
|
||||
buffer.putInt( pos, width ).putInt( pos + 4, height );
|
||||
boolean showCursor = FixedWidthFontRenderer.isCursorVisible( terminal );
|
||||
buffer
|
||||
.putInt( pos, terminal.getWidth() ).putInt( pos + 4, terminal.getHeight() )
|
||||
.putInt( pos + 8, showCursor ? terminal.getCursorX() : -2 )
|
||||
.putInt( pos + 12, showCursor ? terminal.getCursorY() : -2 )
|
||||
.putInt( pos + 16, 15 - terminal.getTextColour() );
|
||||
|
||||
buffer.limit( UNIFORM_SIZE );
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ package dan200.computercraft.client.render;
|
||||
|
||||
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;
|
||||
@ -115,18 +114,11 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
|
||||
transform.scale( (float) xScale, (float) -yScale, 1.0f );
|
||||
|
||||
Matrix4f matrix = transform.last().pose();
|
||||
renderTerminal( renderer, matrix, originTerminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale) );
|
||||
|
||||
// Sneaky hack here: we get a buffer now in order to flush existing ones and set up the appropriate
|
||||
// render state. I've no clue how well this'll work in future versions of Minecraft, but it does the trick
|
||||
// for now.
|
||||
IVertexBuilder buffer = renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
|
||||
RenderTypes.TERMINAL_WITHOUT_DEPTH.setupRenderState();
|
||||
|
||||
renderTerminal( matrix, originTerminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale) );
|
||||
|
||||
// We don't draw the cursor with the VBO, as it's dynamic and so we'll end up refreshing far more than is
|
||||
// reasonable.
|
||||
FixedWidthFontRenderer.drawCursor( matrix, buffer, 0, 0, terminal, !originTerminal.isColour() );
|
||||
// Force a flush of the buffer. WorldRenderer.updateCameraAndRender will "finish" all the built-in buffers
|
||||
// before calling renderer.finish, which means the blocker isn't actually rendered at that point!
|
||||
renderer.getBuffer( RenderType.solid() );
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
@ -139,22 +131,14 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
|
||||
);
|
||||
}
|
||||
|
||||
FixedWidthFontRenderer.drawBlocker(
|
||||
transform.last().pose(), renderer.getBuffer( RenderTypes.TERMINAL_BLOCKER ),
|
||||
-MARGIN, MARGIN,
|
||||
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
|
||||
);
|
||||
|
||||
// Force a flush of the blocker. WorldRenderer.updateCameraAndRender will "finish" all the built-in
|
||||
// buffers before calling renderer.finish, which means the blocker isn't actually rendered at that point!
|
||||
renderer.getBuffer( RenderType.solid() );
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
|
||||
private static void renderTerminal( Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin )
|
||||
private static void renderTerminal( IRenderTypeBuffer bufferSource, Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin )
|
||||
{
|
||||
Terminal terminal = monitor.getTerminal();
|
||||
int width = terminal.getWidth(), height = terminal.getHeight();
|
||||
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
|
||||
|
||||
MonitorRenderer renderType = MonitorRenderer.current();
|
||||
boolean redraw = monitor.pollTerminalChanged();
|
||||
@ -166,9 +150,6 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
|
||||
{
|
||||
if( !MonitorTextureBufferShader.use() ) return;
|
||||
|
||||
int width = terminal.getWidth(), height = terminal.getHeight();
|
||||
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
|
||||
|
||||
if( redraw )
|
||||
{
|
||||
ByteBuffer terminalBuffer = getBuffer( width * height * 3 );
|
||||
@ -180,6 +161,12 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
|
||||
DirectBuffers.setBufferData( GL31.GL_UNIFORM_BUFFER, monitor.tboUniform, uniformBuffer, GL20.GL_STATIC_DRAW );
|
||||
}
|
||||
|
||||
// Sneaky hack here: we get a buffer now in order to flush existing ones and set up the appropriate
|
||||
// render state. I've no clue how well this'll work in future versions of Minecraft, but it does the trick
|
||||
// for now.
|
||||
bufferSource.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH );
|
||||
RenderTypes.TERMINAL_WITH_DEPTH.setupRenderState();
|
||||
|
||||
// Nobody knows what they're doing!
|
||||
GlStateManager._activeTexture( MonitorTextureBufferShader.TEXTURE_INDEX );
|
||||
GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, monitor.tboTexture );
|
||||
@ -214,14 +201,31 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
|
||||
);
|
||||
int termIndexes = buffer.position() / vertexSize;
|
||||
|
||||
// If the cursor is visible, we append it to the end of our buffer. When rendering, we can either
|
||||
// render n or n+1 quads and so toggle the cursor on and off.
|
||||
DirectFixedWidthFontRenderer.drawCursor( buffer, 0, 0, terminal, !monitor.isColour() );
|
||||
|
||||
buffer.flip();
|
||||
|
||||
vbo.upload( termIndexes, RenderTypes.TERMINAL_WITHOUT_DEPTH.format(), buffer );
|
||||
}
|
||||
|
||||
vbo.draw( matrix, vbo.getIndexCount() );
|
||||
// As with the TBO backend we use getBuffer to flush existing buffers. This time we use TERMINAL_WITHOUT_DEPTH
|
||||
// instead and render a separate depth blocker.
|
||||
bufferSource.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
|
||||
RenderTypes.TERMINAL_WITHOUT_DEPTH.setupRenderState();
|
||||
|
||||
RenderTypes.TERMINAL_WITHOUT_DEPTH.format().clearBufferState();
|
||||
vbo.draw(
|
||||
matrix,
|
||||
// As mentioned in the uploading block, render the extra cursor quad if it is visible this frame.
|
||||
// Each quad has an index count of 6.
|
||||
FixedWidthFontRenderer.isCursorVisible( terminal ) && FrameInfo.getGlobalCursorBlink() ? vbo.getIndexCount() + 6 : vbo.getIndexCount()
|
||||
);
|
||||
|
||||
FixedWidthFontRenderer.drawBlocker(
|
||||
matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_BLOCKER ),
|
||||
-xMargin, -yMargin, pixelWidth + xMargin, pixelHeight + yMargin
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,10 @@ layout(std140) uniform u_monitor {
|
||||
vec3 u_palette[16];
|
||||
int u_width;
|
||||
int u_height;
|
||||
ivec2 u_cursorPos;
|
||||
int u_cursorColour;
|
||||
};
|
||||
uniform int u_cursorBlink;
|
||||
|
||||
in vec2 f_pos;
|
||||
|
||||
@ -22,6 +25,10 @@ vec2 texture_corner(int index) {
|
||||
return vec2(x, y);
|
||||
}
|
||||
|
||||
vec4 recolour(vec4 texture, int colour) {
|
||||
return vec4(texture.rgb * u_palette[colour], texture.rgba);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 term_pos = vec2(f_pos.x / FONT_WIDTH, f_pos.y / FONT_HEIGHT);
|
||||
vec2 corner = floor(term_pos);
|
||||
@ -38,6 +45,12 @@ void main() {
|
||||
int bg = int(texelFetch(u_tbo, index + 2).r);
|
||||
|
||||
vec2 pos = (term_pos - corner) * vec2(FONT_WIDTH, FONT_HEIGHT);
|
||||
vec4 img = texture(u_font, (texture_corner(character) + pos) / 256.0);
|
||||
colour = vec4(mix(u_palette[bg], img.rgb * u_palette[fg], img.a * mult), 1.0);
|
||||
vec4 charTex = recolour(texture(u_font, (texture_corner(character) + pos) / 256.0), fg);
|
||||
|
||||
// Applies the cursor on top of the current character if we're blinking and in the current cursor's cell. We do it
|
||||
// this funky way to avoid branches.
|
||||
vec4 cursorTex = recolour(texture(u_font, (texture_corner(95) + pos) / 256.0), u_cursorColour); // 95 = '_'
|
||||
vec4 img = mix(charTex, cursorTex, cursorTex.a * float(u_cursorBlink) * (u_cursorPos == cell ? 1.0 : 0.0));
|
||||
|
||||
colour = vec4(mix(u_palette[bg], img.rgb, img.a * mult), 1.0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user