CC-Tweaked/projects/common/src/client/java/dan200/computercraft/client/render/monitor/MonitorBlockEntityRenderer....

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

295 lines
14 KiB
Java
Raw Normal View History

// Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
//
// SPDX-License-Identifier: LicenseRef-CCPL
package dan200.computercraft.client.render.monitor;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.platform.MemoryTracker;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Axis;
2024-01-31 20:55:14 +00:00
import dan200.computercraft.annotations.ForgeOverride;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.integration.ShaderMod;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.client.render.vbo.DirectBuffers;
import dan200.computercraft.client.render.vbo.DirectVertexBuffer;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.config.Config;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
Backport 1.15's terminal rendering code (#412) This is a backport of 1.15's terminal rendering code with some further improvements. This duplicates a fair bit of code, and is much more efficient. I expect the work done in #409 will supersede this, but that's unlikely to make its way into the next release so it's worth getting this in for now. - Refactor a lot of common terminal code into `FixedWithFontRenderer`. This shouldn't change any behaviour, but makes a lot of our terminal renderers (printed pages, terminals, monitors) a lot cleaner. - Terminal rendering is done using a single mode/vertex format. Rather than drawing an untextured quad for the background colours, we use an entirely white piece of the terminal font. This allows us to batch draws together more elegantly. - Some minor optimisations: - Skip rendering `"\0"` and `" "` characters. These characters occur pretty often, especially on blank monitors and, as the font is empty here, it is safe to skip them. - Batch together adjacent background cells of the same colour. Again, most terminals will have large runs of the same colour, so this is a worthwhile optimisation. These optimisations do mean that terminal performance is no longer consistent as "noisy" terminals will have worse performance. This is annoying, but still worthwhile. - Switch monitor rendering over to use VBOs. We also add a config option to switch between rendering backends. By default we'll choose the best one compatible with your GPU, but there is a config option to switch between VBOS (reasonable performance) and display lists (bad). When benchmarking 30 full-sized monitors rendering a static image, this improves my FPS[^1] from 7 to 95. This is obviously an extreme case - monitor updates are still slow, and so more frequently updating screens will still be less than stellar. [^1]: My graphics card is an Intel HD Graphics 520. Obviously numbers will vary.
2020-04-21 09:43:26 +00:00
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
2024-01-31 20:55:14 +00:00
import net.minecraft.world.phys.AABB;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL31;
import javax.annotation.Nullable;
import java.nio.ByteBuffer;
import java.util.function.Consumer;
Backport 1.15's terminal rendering code (#412) This is a backport of 1.15's terminal rendering code with some further improvements. This duplicates a fair bit of code, and is much more efficient. I expect the work done in #409 will supersede this, but that's unlikely to make its way into the next release so it's worth getting this in for now. - Refactor a lot of common terminal code into `FixedWithFontRenderer`. This shouldn't change any behaviour, but makes a lot of our terminal renderers (printed pages, terminals, monitors) a lot cleaner. - Terminal rendering is done using a single mode/vertex format. Rather than drawing an untextured quad for the background colours, we use an entirely white piece of the terminal font. This allows us to batch draws together more elegantly. - Some minor optimisations: - Skip rendering `"\0"` and `" "` characters. These characters occur pretty often, especially on blank monitors and, as the font is empty here, it is safe to skip them. - Batch together adjacent background cells of the same colour. Again, most terminals will have large runs of the same colour, so this is a worthwhile optimisation. These optimisations do mean that terminal performance is no longer consistent as "noisy" terminals will have worse performance. This is annoying, but still worthwhile. - Switch monitor rendering over to use VBOs. We also add a config option to switch between rendering backends. By default we'll choose the best one compatible with your GPU, but there is a config option to switch between VBOS (reasonable performance) and display lists (bad). When benchmarking 30 full-sized monitors rendering a static image, this improves my FPS[^1] from 7 to 95. This is obviously an extreme case - monitor updates are still slow, and so more frequently updating screens will still be less than stellar. [^1]: My graphics card is an Intel HD Graphics 520. Obviously numbers will vary.
2020-04-21 09:43:26 +00:00
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
import static dan200.computercraft.core.util.Nullability.assertNonNull;
public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBlockEntity> {
/**
* {@link MonitorBlockEntity#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between
* the monitor frame and contents.
*/
private static final float MARGIN = (float) (MonitorBlockEntity.RENDER_MARGIN * 1.1);
private static final Matrix3f IDENTITY_NORMAL = new Matrix3f().identity();
private static @Nullable ByteBuffer backingBuffer;
private static long lastFrame = -1;
public MonitorBlockEntityRenderer(BlockEntityRendererProvider.Context context) {
}
@Override
public void render(MonitorBlockEntity monitor, float partialTicks, PoseStack transform, MultiBufferSource bufferSource, int lightmapCoord, int overlayLight) {
// Render from the origin monitor
var originTerminal = monitor.getOriginClientMonitor();
if (originTerminal == null) return;
var origin = originTerminal.getOrigin();
var renderState = originTerminal.getRenderState(MonitorRenderState::new);
var monitorPos = monitor.getBlockPos();
// Ensure each monitor terminal is rendered only once. We allow rendering a specific tile
// multiple times in a single frame to ensure compatibility with shaders which may run a
// pass multiple times.
var renderFrame = FrameInfo.getRenderFrame();
if (renderState.lastRenderFrame == renderFrame && !monitorPos.equals(renderState.lastRenderPos)) {
return;
}
lastFrame = renderFrame;
renderState.lastRenderFrame = renderFrame;
renderState.lastRenderPos = monitorPos;
var originPos = origin.getBlockPos();
// Determine orientation
var dir = origin.getDirection();
var front = origin.getFront();
var yaw = dir.toYRot();
var pitch = DirectionUtil.toPitchAngle(front);
// Setup initial transform
transform.pushPose();
transform.translate(
originPos.getX() - monitorPos.getX() + 0.5,
originPos.getY() - monitorPos.getY() + 0.5,
originPos.getZ() - monitorPos.getZ() + 0.5
);
transform.mulPose(Axis.YN.rotationDegrees(yaw));
transform.mulPose(Axis.XP.rotationDegrees(pitch));
transform.translate(
-0.5 + MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN,
origin.getHeight() - 0.5 - (MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN) + 0,
0.5
);
var xSize = origin.getWidth() - 2.0 * (MonitorBlockEntity.RENDER_MARGIN + MonitorBlockEntity.RENDER_BORDER);
var ySize = origin.getHeight() - 2.0 * (MonitorBlockEntity.RENDER_MARGIN + MonitorBlockEntity.RENDER_BORDER);
// Draw the contents
var terminal = originTerminal.getTerminal();
if (terminal != null && !ShaderMod.get().isRenderingShadowPass()) {
// Draw a terminal
int width = terminal.getWidth(), height = terminal.getHeight();
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
var xScale = xSize / pixelWidth;
var yScale = ySize / pixelHeight;
transform.pushPose();
transform.scale((float) xScale, (float) -yScale, 1.0f);
var matrix = transform.last().pose();
renderTerminal(matrix, originTerminal, renderState, terminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale));
transform.popPose();
} else {
FixedWidthFontRenderer.drawEmptyTerminal(
FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(RenderTypes.TERMINAL)),
-MARGIN, MARGIN,
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
);
}
transform.popPose();
}
Backport 1.15's terminal rendering code (#412) This is a backport of 1.15's terminal rendering code with some further improvements. This duplicates a fair bit of code, and is much more efficient. I expect the work done in #409 will supersede this, but that's unlikely to make its way into the next release so it's worth getting this in for now. - Refactor a lot of common terminal code into `FixedWithFontRenderer`. This shouldn't change any behaviour, but makes a lot of our terminal renderers (printed pages, terminals, monitors) a lot cleaner. - Terminal rendering is done using a single mode/vertex format. Rather than drawing an untextured quad for the background colours, we use an entirely white piece of the terminal font. This allows us to batch draws together more elegantly. - Some minor optimisations: - Skip rendering `"\0"` and `" "` characters. These characters occur pretty often, especially on blank monitors and, as the font is empty here, it is safe to skip them. - Batch together adjacent background cells of the same colour. Again, most terminals will have large runs of the same colour, so this is a worthwhile optimisation. These optimisations do mean that terminal performance is no longer consistent as "noisy" terminals will have worse performance. This is annoying, but still worthwhile. - Switch monitor rendering over to use VBOs. We also add a config option to switch between rendering backends. By default we'll choose the best one compatible with your GPU, but there is a config option to switch between VBOS (reasonable performance) and display lists (bad). When benchmarking 30 full-sized monitors rendering a static image, this improves my FPS[^1] from 7 to 95. This is obviously an extreme case - monitor updates are still slow, and so more frequently updating screens will still be less than stellar. [^1]: My graphics card is an Intel HD Graphics 520. Obviously numbers will vary.
2020-04-21 09:43:26 +00:00
private static void renderTerminal(
Matrix4f matrix, ClientMonitor monitor, MonitorRenderState renderState, Terminal terminal, float xMargin, float yMargin
) {
int width = terminal.getWidth(), height = terminal.getHeight();
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
Backport 1.15's terminal rendering code (#412) This is a backport of 1.15's terminal rendering code with some further improvements. This duplicates a fair bit of code, and is much more efficient. I expect the work done in #409 will supersede this, but that's unlikely to make its way into the next release so it's worth getting this in for now. - Refactor a lot of common terminal code into `FixedWithFontRenderer`. This shouldn't change any behaviour, but makes a lot of our terminal renderers (printed pages, terminals, monitors) a lot cleaner. - Terminal rendering is done using a single mode/vertex format. Rather than drawing an untextured quad for the background colours, we use an entirely white piece of the terminal font. This allows us to batch draws together more elegantly. - Some minor optimisations: - Skip rendering `"\0"` and `" "` characters. These characters occur pretty often, especially on blank monitors and, as the font is empty here, it is safe to skip them. - Batch together adjacent background cells of the same colour. Again, most terminals will have large runs of the same colour, so this is a worthwhile optimisation. These optimisations do mean that terminal performance is no longer consistent as "noisy" terminals will have worse performance. This is annoying, but still worthwhile. - Switch monitor rendering over to use VBOs. We also add a config option to switch between rendering backends. By default we'll choose the best one compatible with your GPU, but there is a config option to switch between VBOS (reasonable performance) and display lists (bad). When benchmarking 30 full-sized monitors rendering a static image, this improves my FPS[^1] from 7 to 95. This is obviously an extreme case - monitor updates are still slow, and so more frequently updating screens will still be less than stellar. [^1]: My graphics card is an Intel HD Graphics 520. Obviously numbers will vary.
2020-04-21 09:43:26 +00:00
var renderType = currentRenderer();
Backport 1.15's terminal rendering code (#412) This is a backport of 1.15's terminal rendering code with some further improvements. This duplicates a fair bit of code, and is much more efficient. I expect the work done in #409 will supersede this, but that's unlikely to make its way into the next release so it's worth getting this in for now. - Refactor a lot of common terminal code into `FixedWithFontRenderer`. This shouldn't change any behaviour, but makes a lot of our terminal renderers (printed pages, terminals, monitors) a lot cleaner. - Terminal rendering is done using a single mode/vertex format. Rather than drawing an untextured quad for the background colours, we use an entirely white piece of the terminal font. This allows us to batch draws together more elegantly. - Some minor optimisations: - Skip rendering `"\0"` and `" "` characters. These characters occur pretty often, especially on blank monitors and, as the font is empty here, it is safe to skip them. - Batch together adjacent background cells of the same colour. Again, most terminals will have large runs of the same colour, so this is a worthwhile optimisation. These optimisations do mean that terminal performance is no longer consistent as "noisy" terminals will have worse performance. This is annoying, but still worthwhile. - Switch monitor rendering over to use VBOs. We also add a config option to switch between rendering backends. By default we'll choose the best one compatible with your GPU, but there is a config option to switch between VBOS (reasonable performance) and display lists (bad). When benchmarking 30 full-sized monitors rendering a static image, this improves my FPS[^1] from 7 to 95. This is obviously an extreme case - monitor updates are still slow, and so more frequently updating screens will still be less than stellar. [^1]: My graphics card is an Intel HD Graphics 520. Obviously numbers will vary.
2020-04-21 09:43:26 +00:00
var redraw = monitor.pollTerminalChanged();
if (renderState.createBuffer(renderType)) redraw = true;
switch (renderType) {
case TBO -> {
if (redraw) {
var terminalBuffer = getBuffer(width * height * 3);
MonitorTextureBufferShader.setTerminalData(terminalBuffer, terminal);
DirectBuffers.setBufferData(GL31.GL_TEXTURE_BUFFER, renderState.tboBuffer, terminalBuffer, GL20.GL_STATIC_DRAW);
var uniformBuffer = getBuffer(MonitorTextureBufferShader.UNIFORM_SIZE);
MonitorTextureBufferShader.setUniformData(uniformBuffer, terminal);
DirectBuffers.setBufferData(GL31.GL_UNIFORM_BUFFER, renderState.tboUniform, uniformBuffer, GL20.GL_STATIC_DRAW);
}
// Nobody knows what they're doing!
var active = GlStateManager._getActiveTexture();
RenderSystem.activeTexture(MonitorTextureBufferShader.TEXTURE_INDEX);
GL11.glBindTexture(GL31.GL_TEXTURE_BUFFER, renderState.tboTexture);
RenderSystem.activeTexture(active);
var shader = RenderTypes.getMonitorTextureBufferShader();
shader.setupUniform(renderState.tboUniform);
var buffer = Tesselator.getInstance().getBuilder();
buffer.begin(RenderTypes.MONITOR_TBO.mode(), RenderTypes.MONITOR_TBO.format());
tboVertex(buffer, matrix, -xMargin, -yMargin);
tboVertex(buffer, matrix, -xMargin, pixelHeight + yMargin);
tboVertex(buffer, matrix, pixelWidth + xMargin, -yMargin);
tboVertex(buffer, matrix, pixelWidth + xMargin, pixelHeight + yMargin);
RenderTypes.MONITOR_TBO.end(buffer, VertexSorting.DISTANCE_TO_ORIGIN);
}
Backport 1.15's terminal rendering code (#412) This is a backport of 1.15's terminal rendering code with some further improvements. This duplicates a fair bit of code, and is much more efficient. I expect the work done in #409 will supersede this, but that's unlikely to make its way into the next release so it's worth getting this in for now. - Refactor a lot of common terminal code into `FixedWithFontRenderer`. This shouldn't change any behaviour, but makes a lot of our terminal renderers (printed pages, terminals, monitors) a lot cleaner. - Terminal rendering is done using a single mode/vertex format. Rather than drawing an untextured quad for the background colours, we use an entirely white piece of the terminal font. This allows us to batch draws together more elegantly. - Some minor optimisations: - Skip rendering `"\0"` and `" "` characters. These characters occur pretty often, especially on blank monitors and, as the font is empty here, it is safe to skip them. - Batch together adjacent background cells of the same colour. Again, most terminals will have large runs of the same colour, so this is a worthwhile optimisation. These optimisations do mean that terminal performance is no longer consistent as "noisy" terminals will have worse performance. This is annoying, but still worthwhile. - Switch monitor rendering over to use VBOs. We also add a config option to switch between rendering backends. By default we'll choose the best one compatible with your GPU, but there is a config option to switch between VBOS (reasonable performance) and display lists (bad). When benchmarking 30 full-sized monitors rendering a static image, this improves my FPS[^1] from 7 to 95. This is obviously an extreme case - monitor updates are still slow, and so more frequently updating screens will still be less than stellar. [^1]: My graphics card is an Intel HD Graphics 520. Obviously numbers will vary.
2020-04-21 09:43:26 +00:00
case VBO -> {
var backgroundBuffer = assertNonNull(renderState.backgroundBuffer);
var foregroundBuffer = assertNonNull(renderState.foregroundBuffer);
Backport 1.15's terminal rendering code (#412) This is a backport of 1.15's terminal rendering code with some further improvements. This duplicates a fair bit of code, and is much more efficient. I expect the work done in #409 will supersede this, but that's unlikely to make its way into the next release so it's worth getting this in for now. - Refactor a lot of common terminal code into `FixedWithFontRenderer`. This shouldn't change any behaviour, but makes a lot of our terminal renderers (printed pages, terminals, monitors) a lot cleaner. - Terminal rendering is done using a single mode/vertex format. Rather than drawing an untextured quad for the background colours, we use an entirely white piece of the terminal font. This allows us to batch draws together more elegantly. - Some minor optimisations: - Skip rendering `"\0"` and `" "` characters. These characters occur pretty often, especially on blank monitors and, as the font is empty here, it is safe to skip them. - Batch together adjacent background cells of the same colour. Again, most terminals will have large runs of the same colour, so this is a worthwhile optimisation. These optimisations do mean that terminal performance is no longer consistent as "noisy" terminals will have worse performance. This is annoying, but still worthwhile. - Switch monitor rendering over to use VBOs. We also add a config option to switch between rendering backends. By default we'll choose the best one compatible with your GPU, but there is a config option to switch between VBOS (reasonable performance) and display lists (bad). When benchmarking 30 full-sized monitors rendering a static image, this improves my FPS[^1] from 7 to 95. This is obviously an extreme case - monitor updates are still slow, and so more frequently updating screens will still be less than stellar. [^1]: My graphics card is an Intel HD Graphics 520. Obviously numbers will vary.
2020-04-21 09:43:26 +00:00
if (redraw) {
var size = DirectFixedWidthFontRenderer.getVertexCount(terminal);
// In an ideal world we could upload these both into one buffer. However, we can't render VBOs with
// and starting and ending offset, and so need to use two buffers instead.
renderToBuffer(backgroundBuffer, size, sink ->
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin));
renderToBuffer(foregroundBuffer, size, sink -> {
DirectFixedWidthFontRenderer.drawTerminalForeground(sink, 0, 0, terminal);
// 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(sink, 0, 0, terminal);
});
}
// Our VBO renders coordinates in monitor-space rather than world space. A full sized monitor (8x6) will
// use positions from (0, 0) to (164*FONT_WIDTH, 81*FONT_HEIGHT) = (984, 729). This is far outside the
// normal render distance (~200), and the edges of the monitor fade out due to fog.
// There's not really a good way around this, at least without using a custom render type (which the VBO
// renderer is trying to avoid!). Instead, we just disable fog entirely by setting the fog start to an
// absurdly high value.
var oldFogStart = RenderSystem.getShaderFogStart();
RenderSystem.setShaderFogStart(1e4f);
RenderTypes.TERMINAL.setupRenderState();
// Compose the existing model view matrix with our transformation matrix.
var modelView = new Matrix4f(RenderSystem.getModelViewMatrix()).mul(matrix);
// Render background geometry
backgroundBuffer.bind();
backgroundBuffer.drawWithShader(modelView, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader());
// Render foreground geometry with glPolygonOffset enabled.
RenderSystem.polygonOffset(-1.0f, -10.0f);
RenderSystem.enablePolygonOffset();
foregroundBuffer.bind();
foregroundBuffer.drawWithShader(
modelView, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader(),
// As mentioned in the above comment, render the extra cursor quad if it is visible this frame. Each
// // quad has an index count of 6.
FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()
? foregroundBuffer.getIndexCount() + 6 : foregroundBuffer.getIndexCount()
);
// Clear state
RenderSystem.polygonOffset(0.0f, -0.0f);
RenderSystem.disablePolygonOffset();
RenderTypes.TERMINAL.clearRenderState();
VertexBuffer.unbind();
RenderSystem.setShaderFogStart(oldFogStart);
}
case BEST -> throw new IllegalStateException("Impossible: Should never use BEST renderer");
}
}
private static void renderToBuffer(DirectVertexBuffer vbo, int size, Consumer<DirectFixedWidthFontRenderer.QuadEmitter> draw) {
var sink = ShaderMod.get().getQuadEmitter(size, MonitorBlockEntityRenderer::getBuffer);
var buffer = sink.buffer();
draw.accept(sink);
buffer.flip();
vbo.upload(buffer.limit() / sink.format().getVertexSize(), RenderTypes.TERMINAL.mode(), sink.format(), buffer);
}
private static void tboVertex(VertexConsumer builder, Matrix4f matrix, float x, float y) {
// We encode position in the UV, as that's not transformed by the matrix.
builder.vertex(matrix, x, y, 0).uv(x, y).endVertex();
}
Cleanup and optimise terminal rendering (#1057) - Remove the POSITION_COLOR render type. Instead we just render a background terminal quad as the pocket computer light - it's a little (lot?) more cheaty, but saves having to create a render type. - Use the existing position_color_tex shader instead of our copy. I looked at using RenderType.text, but had a bunch of problems with GUI terminals. Its possible we can fix it, but didn't want to spend too much time on it. - Remove some methods from FixedWidthFontRenderer, inlining them into the call site. - Switch back to using GL_QUADS rather than GL_TRIANGLES. I know Lig will shout at me for this, but the rest of MC uses QUADS, so I don't think best practice really matters here. - Fix the TBO backend monitor not rendering monitors with fog. Unfortunately we can't easily do this to the VBO one without writing a custom shader (which defeats the whole point of the VBO backend!), as the distance calculation of most render types expect an already-transformed position (camera-relative I think!) while we pass a world-relative one. - When rendering to a VBO we push vertices to a ByteBuffer directly, rather than going through MC's VertexConsumer system. This removes the overhead which comes with VertexConsumer, significantly improving performance. - Pre-convert palette colours to bytes, storing both the coloured and greyscale versions as a byte array. This allows us to remove the multiple casts and conversions (double -> float -> (greyscale) -> byte), offering noticeable performance improvements (multiple ms per frame). We're using a byte[] here rather than a record of three bytes as notionally it provides better performance when writing to a ByteBuffer directly compared to calling .put() four times. [^1] - Memorize getRenderBoundingBox. This was taking about 5% of the total time on the render thread[^2], so worth doing. I don't actually think the allocation is the heavy thing here - VisualVM says it's toWorldPos being slow. I'm not sure why - possibly just all the block property lookups? [^2] Note that none of these changes improve compatibility with Optifine. Right now there's some serious issues where monitors are writing _over_ blocks in front of them. To fix this, we probably need to remove the depth blocker and just render characters with a z offset. Will do that in a separate commit, as I need to evaluate how well that change will work first. The main advantage of this commit is the improved performance. In my stress test with 120 monitors updating every tick, I'm getting 10-20fps [^3] (still much worse than TBOs, which manages a solid 60-100). In practice, we'll actually be much better than this. Our network bandwidth limits means only 40 change in a single tick - and so FPS is much more reasonable (+60fps). [^1]: In general, put(byte[]) is faster than put(byte) multiple times. Just not clear if this is true when dealing with a small (and loop unrolled) number of bytes. [^2]: To be clear, this is with 120 monitors and no other block entities with custom renderers. so not really representative. [^3]: I wish I could provide a narrower range, but it varies so much between me restarting the game. Makes it impossible to benchmark anything!
2022-04-02 09:54:03 +00:00
private static ByteBuffer getBuffer(int capacity) {
var buffer = backingBuffer;
if (buffer == null || buffer.capacity() < capacity) {
buffer = backingBuffer = buffer == null ? MemoryTracker.create(capacity) : MemoryTracker.resize(buffer, capacity);
Cleanup and optimise terminal rendering (#1057) - Remove the POSITION_COLOR render type. Instead we just render a background terminal quad as the pocket computer light - it's a little (lot?) more cheaty, but saves having to create a render type. - Use the existing position_color_tex shader instead of our copy. I looked at using RenderType.text, but had a bunch of problems with GUI terminals. Its possible we can fix it, but didn't want to spend too much time on it. - Remove some methods from FixedWidthFontRenderer, inlining them into the call site. - Switch back to using GL_QUADS rather than GL_TRIANGLES. I know Lig will shout at me for this, but the rest of MC uses QUADS, so I don't think best practice really matters here. - Fix the TBO backend monitor not rendering monitors with fog. Unfortunately we can't easily do this to the VBO one without writing a custom shader (which defeats the whole point of the VBO backend!), as the distance calculation of most render types expect an already-transformed position (camera-relative I think!) while we pass a world-relative one. - When rendering to a VBO we push vertices to a ByteBuffer directly, rather than going through MC's VertexConsumer system. This removes the overhead which comes with VertexConsumer, significantly improving performance. - Pre-convert palette colours to bytes, storing both the coloured and greyscale versions as a byte array. This allows us to remove the multiple casts and conversions (double -> float -> (greyscale) -> byte), offering noticeable performance improvements (multiple ms per frame). We're using a byte[] here rather than a record of three bytes as notionally it provides better performance when writing to a ByteBuffer directly compared to calling .put() four times. [^1] - Memorize getRenderBoundingBox. This was taking about 5% of the total time on the render thread[^2], so worth doing. I don't actually think the allocation is the heavy thing here - VisualVM says it's toWorldPos being slow. I'm not sure why - possibly just all the block property lookups? [^2] Note that none of these changes improve compatibility with Optifine. Right now there's some serious issues where monitors are writing _over_ blocks in front of them. To fix this, we probably need to remove the depth blocker and just render characters with a z offset. Will do that in a separate commit, as I need to evaluate how well that change will work first. The main advantage of this commit is the improved performance. In my stress test with 120 monitors updating every tick, I'm getting 10-20fps [^3] (still much worse than TBOs, which manages a solid 60-100). In practice, we'll actually be much better than this. Our network bandwidth limits means only 40 change in a single tick - and so FPS is much more reasonable (+60fps). [^1]: In general, put(byte[]) is faster than put(byte) multiple times. Just not clear if this is true when dealing with a small (and loop unrolled) number of bytes. [^2]: To be clear, this is with 120 monitors and no other block entities with custom renderers. so not really representative. [^3]: I wish I could provide a narrower range, but it varies so much between me restarting the game. Makes it impossible to benchmark anything!
2022-04-02 09:54:03 +00:00
}
buffer.clear();
return buffer;
}
@Override
public int getViewDistance() {
return Config.monitorDistance;
}
2024-01-31 20:55:14 +00:00
@ForgeOverride
public AABB getRenderBoundingBox(MonitorBlockEntity monitor) {
return monitor.getRenderBoundingBox();
}
/**
* Determine if any monitors were rendered this frame.
*
* @return Whether any monitors were rendered.
*/
public static boolean hasRenderedThisFrame() {
return FrameInfo.getRenderFrame() == lastFrame;
}
/**
* Get the current renderer to use.
*
* @return The current renderer. Will not return {@link MonitorRenderer#BEST}.
*/
public static MonitorRenderer currentRenderer() {
var current = Config.monitorRenderer;
if (current == MonitorRenderer.BEST) current = Config.monitorRenderer = bestRenderer();
return current;
}
private static MonitorRenderer bestRenderer() {
return MonitorRenderer.VBO;
}
}