From 45aaf9b98108483ceae40311d7540e76d7e36fa7 Mon Sep 17 00:00:00 2001 From: mcrcortex <18544518+MCRcortex@users.noreply.github.com> Date: Tue, 6 May 2025 01:06:37 +1000 Subject: [PATCH] rewrote the render side of texture bakery, is very significantly better --- .../voxy/client/core/gl/GlVertexArray.java | 72 ++++ .../core/model/BakedBlockEntityModel.java | 2 +- .../core/model/BudgetBufferRenderer.java | 121 ++++-- .../core/model/ModelBakerySubsystem.java | 8 + .../voxy/client/core/model/ModelFactory.java | 7 +- .../core/model/bakery/GlViewCapture.java | 7 + .../core/model/bakery/ModelTextureBakery.java | 4 +- .../model/bakery/ModelTextureBakery2.java | 375 ++++++++++++++++++ .../client/core/rendering/RenderService.java | 4 +- .../voxy/common/thread/ServiceThreadPool.java | 2 +- .../common/world/ActiveSectionTracker.java | 31 +- .../voxy/shaders/bakery/position_tex.fsh | 6 +- .../voxy/shaders/bakery/position_tex.vsh | 9 +- 13 files changed, 583 insertions(+), 65 deletions(-) create mode 100644 src/main/java/me/cortex/voxy/client/core/gl/GlVertexArray.java create mode 100644 src/main/java/me/cortex/voxy/client/core/model/bakery/ModelTextureBakery2.java diff --git a/src/main/java/me/cortex/voxy/client/core/gl/GlVertexArray.java b/src/main/java/me/cortex/voxy/client/core/gl/GlVertexArray.java new file mode 100644 index 00000000..c819a164 --- /dev/null +++ b/src/main/java/me/cortex/voxy/client/core/gl/GlVertexArray.java @@ -0,0 +1,72 @@ +package me.cortex.voxy.client.core.gl; + +import me.cortex.voxy.common.util.TrackedObject; + +import java.util.Arrays; + +import static org.lwjgl.opengl.GL45C.*; + +public class GlVertexArray extends TrackedObject { + public final int id; + private int[] indices = new int[0]; + private int stride; + public GlVertexArray() { + this.id = glCreateVertexArrays(); + } + + @Override + public void free() { + this.free0(); + glDeleteVertexArrays(this.id); + } + + public void bind() { + glBindVertexArray(this.id); + } + + public GlVertexArray bindBuffer(int buffer) { + //TODO: optimization, use glVertexArrayVertexBuffers + for (int index : this.indices) { + glVertexArrayVertexBuffer(this.id, index, buffer, 0, this.stride); + } + return this; + } + + public GlVertexArray bindElementBuffer(int buffer) { + glVertexArrayElementBuffer(this.id, buffer); + return this; + } + + public GlVertexArray setStride(int stride) { + this.stride = stride; + return this; + } + + public GlVertexArray setI(int index, int type, int count, int offset) { + this.addIndex(index); + glEnableVertexArrayAttrib(this.id, index); + glVertexArrayAttribIFormat(this.id, index, count, type, offset); + return this; + } + + public GlVertexArray setF(int index, int type, int count, int offset) { + return this.setF(index, type, count, false, offset); + } + + public GlVertexArray setF(int index, int type, int count, boolean normalize, int offset) { + this.addIndex(index); + glEnableVertexArrayAttrib(this.id, index); + glVertexArrayAttribFormat(this.id, index, count, type, normalize, offset); + return this; + } + + private void addIndex(int index) { + for (int i : this.indices) { + if (i == index) { + return; + } + } + this.indices = Arrays.copyOf(this.indices, this.indices.length+1); + this.indices[this.indices.length-1] = index; + } +} diff --git a/src/main/java/me/cortex/voxy/client/core/model/BakedBlockEntityModel.java b/src/main/java/me/cortex/voxy/client/core/model/BakedBlockEntityModel.java index 317e862a..a0b2e96b 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/BakedBlockEntityModel.java +++ b/src/main/java/me/cortex/voxy/client/core/model/BakedBlockEntityModel.java @@ -123,7 +123,7 @@ public class BakedBlockEntityModel { layer.putInto(bb); var mesh = bb.endNullable(); if (mesh!=null) - BudgetBufferRenderer.draw(mesh, texture, matrix); + BudgetBufferRenderer.drawFast(mesh, texture, matrix); } } diff --git a/src/main/java/me/cortex/voxy/client/core/model/BudgetBufferRenderer.java b/src/main/java/me/cortex/voxy/client/core/model/BudgetBufferRenderer.java index 56c90dd7..f627bbd6 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/BudgetBufferRenderer.java +++ b/src/main/java/me/cortex/voxy/client/core/model/BudgetBufferRenderer.java @@ -8,54 +8,103 @@ import com.mojang.blaze3d.systems.RenderPass; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.textures.GpuTexture; import com.mojang.blaze3d.vertex.VertexFormat; +import me.cortex.voxy.client.core.gl.GlBuffer; +import me.cortex.voxy.client.core.gl.GlVertexArray; +import me.cortex.voxy.client.core.gl.shader.Shader; +import me.cortex.voxy.client.core.gl.shader.ShaderType; +import me.cortex.voxy.client.core.rendering.util.SharedIndexBuffer; +import me.cortex.voxy.client.core.rendering.util.UploadStream; +import me.cortex.voxy.common.util.UnsafeUtil; import net.minecraft.client.gl.*; import net.minecraft.client.render.BuiltBuffer; import net.minecraft.client.render.VertexFormats; import net.minecraft.util.Identifier; import org.joml.Matrix4f; +import org.lwjgl.system.MemoryUtil; + +import static org.lwjgl.opengl.ARBVertexArrayObject.glBindVertexArray; +import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER; +import static org.lwjgl.opengl.GL15.glBindBuffer; +import static org.lwjgl.opengl.GL20.glUniformMatrix4fv; +import static org.lwjgl.opengl.GL33.glBindSampler; +import static org.lwjgl.opengl.GL43.glBindVertexBuffer; +import static org.lwjgl.opengl.GL45.*; public class BudgetBufferRenderer { - public static final RenderPipeline RENDERER_THING = RenderPipeline.builder() - .withLocation(Identifier.of("voxy","bakery/position_tex")) - .withVertexShader(Identifier.of("voxy","bakery/position_tex")) - .withFragmentShader(Identifier.of("voxy","bakery/position_tex")) - .withUniform("transform", UniformType.MATRIX4X4) - .withSampler("tex") - .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST) - .withVertexFormat(VertexFormats.POSITION_TEXTURE_COLOR, VertexFormat.DrawMode.QUADS) - .build(); + private static final Shader bakeryShader = Shader.make() + .add(ShaderType.VERTEX, "voxy:bakery/position_tex.vsh") + .add(ShaderType.FRAGMENT, "voxy:bakery/position_tex.fsh") + .compile(); + + + private static final GlBuffer indexBuffer; + static { + var i = RenderSystem.getSequentialBuffer(VertexFormat.DrawMode.QUADS); + int id = ((GlGpuBuffer) i.getIndexBuffer(4096*3*2)).id; + if (i.getIndexType() != VertexFormat.IndexType.SHORT) { + throw new IllegalStateException(); + } + indexBuffer = new GlBuffer(3*2*2*4096); + glCopyNamedBufferSubData(id, indexBuffer.id, 0, 0, 3*2*2*4096); + } + + private static final int STRIDE = 24; + private static final GlVertexArray VA = new GlVertexArray() + .setStride(STRIDE) + .setF(0, GL_FLOAT, 3, 0)//pos + .setI(1, GL_INT, 1, 4 * 3)//metadata + .setF(2, GL_FLOAT, 2, 4 * 4)//UV + .bindElementBuffer(indexBuffer.id); + + private static GlBuffer immediateBuffer; + private static int quadCount; + public static void drawFast(BuiltBuffer buffer, GpuTexture tex, Matrix4f matrix) { + if (buffer.getDrawParameters().mode() != VertexFormat.DrawMode.QUADS) { + throw new IllegalStateException("Fast only supports quads"); + } + + var buff = buffer.getBuffer(); + int size = buff.remaining(); + if (size%STRIDE != 0) throw new IllegalStateException(); + size /= STRIDE; + if (size%4 != 0) throw new IllegalStateException(); + size /= 4; + setup(MemoryUtil.memAddress(buff), size, ((net.minecraft.client.texture.GlTexture)tex).getGlId()); + buffer.close(); + + render(matrix); + } + + public static void setup(long dataPtr, int quads, int texId) { + if (quads == 0) { + throw new IllegalStateException(); + } - public static void draw(BuiltBuffer buffer, GpuTexture tex, Matrix4f matrix) { - //Fuz the gpu sampler state GlStateManager._activeTexture(GlConst.GL_TEXTURE0); GlStateManager._bindTexture(0); - GlStateManager._activeTexture(GlConst.GL_TEXTURE1); - GlStateManager._bindTexture(0); - GlStateManager._activeTexture(GlConst.GL_TEXTURE2); - GlStateManager._bindTexture(0); - GlStateManager._activeTexture(GlConst.GL_TEXTURE2+1); - GlStateManager._bindTexture(0); - RenderSystem.ShapeIndexBuffer shapeIndexBuffer = RenderSystem.getSequentialBuffer(buffer.getDrawParameters().mode()); - GpuBuffer gpuBuffer = buffer.getDrawParameters().format().uploadImmediateVertexBuffer(buffer.getBuffer()); + quadCount = quads; - var res = (GlResourceManager)RenderSystem.getDevice() - .createCommandEncoder(); - res.currentProgram = null; - res.currentPipeline = null; - try (RenderPass renderPass = new RenderPassImpl(res, false)) { - renderPass.setPipeline(RENDERER_THING); - renderPass.setVertexBuffer(0, gpuBuffer); - - renderPass.bindSampler("tex", tex); - renderPass.setUniform("transform", matrix); - - renderPass.setIndexBuffer(shapeIndexBuffer.getIndexBuffer(buffer.getDrawParameters().indexCount()), shapeIndexBuffer.getIndexType()); - renderPass.drawIndexed(0, buffer.getDrawParameters().indexCount()); + long size = quads * 4L * STRIDE; + if (immediateBuffer == null || immediateBuffer.size()processTextureBakeResult(blockId, blockState, textureData)); }); - this.bakery.renderFacesToStream(blockState, 123456, isFluid, this.downstream.getBufferId(), allocation); + this.bakery.renderToStream(blockState, this.downstream.getBufferId(), allocation); return true; } diff --git a/src/main/java/me/cortex/voxy/client/core/model/bakery/GlViewCapture.java b/src/main/java/me/cortex/voxy/client/core/model/bakery/GlViewCapture.java index 84284e70..d9b3b14f 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/bakery/GlViewCapture.java +++ b/src/main/java/me/cortex/voxy/client/core/model/bakery/GlViewCapture.java @@ -6,11 +6,13 @@ import me.cortex.voxy.client.core.gl.GlTexture; import me.cortex.voxy.client.core.gl.shader.Shader; import me.cortex.voxy.client.core.gl.shader.ShaderType; +import static org.lwjgl.opengl.ARBDirectStateAccess.glClearNamedFramebufferfv; import static org.lwjgl.opengl.ARBDirectStateAccess.glTextureParameteri; import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.opengl.GL11.GL_STENCIL_INDEX; import static org.lwjgl.opengl.GL30.*; import static org.lwjgl.opengl.GL43.*; +import static org.lwjgl.opengl.GL45.glClearNamedFramebufferfi; public class GlViewCapture { private final int width; @@ -57,6 +59,11 @@ public class GlViewCapture { glDispatchCompute(3, 2, 1); } + public void clear() { + glClearNamedFramebufferfv(this.framebuffer.id, GL_COLOR, 0, new float[]{0,0,0,0}); + glClearNamedFramebufferfi(this.framebuffer.id, GL_DEPTH_STENCIL, 0, 1.0f, 0); + } + public void free() { this.framebuffer.free(); this.colourTex.free(); diff --git a/src/main/java/me/cortex/voxy/client/core/model/bakery/ModelTextureBakery.java b/src/main/java/me/cortex/voxy/client/core/model/bakery/ModelTextureBakery.java index 6146a7d4..e25144f4 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/bakery/ModelTextureBakery.java +++ b/src/main/java/me/cortex/voxy/client/core/model/bakery/ModelTextureBakery.java @@ -219,6 +219,8 @@ public class ModelTextureBakery { if (!renderFluid) { //TODO: need to do 2 variants for quads, one which have coloured, ones that dont, might be able to pull a spare bit // at the end whether or not a pixel should be mixed with texture + + //TODO: CACHE THE BUILT MODEL AND REUSE AND JUST RENDER FROM DIFFERENT VIEWS renderQuads(bb, model, new MatrixStack(), randomValue); } else { MinecraftClient.getInstance().getBlockRenderManager().renderFluid(BlockPos.ORIGIN, new BlockRenderView() { @@ -291,7 +293,7 @@ public class ModelTextureBakery { var mesh = bb.endNullable(); if (mesh != null) - BudgetBufferRenderer.draw(mesh, texture, transform); + BudgetBufferRenderer.drawFast(mesh, texture, transform); } private static void renderQuads(BufferBuilder builder, BlockStateModel model, MatrixStack stack, long randomValue) { diff --git a/src/main/java/me/cortex/voxy/client/core/model/bakery/ModelTextureBakery2.java b/src/main/java/me/cortex/voxy/client/core/model/bakery/ModelTextureBakery2.java new file mode 100644 index 00000000..28e6677d --- /dev/null +++ b/src/main/java/me/cortex/voxy/client/core/model/bakery/ModelTextureBakery2.java @@ -0,0 +1,375 @@ +package me.cortex.voxy.client.core.model.bakery; + +import me.cortex.voxy.client.core.model.BudgetBufferRenderer; +import me.cortex.voxy.common.util.MemoryBuffer; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.FluidBlock; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.RenderLayers; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.render.model.BlockStateModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.fluid.FluidState; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.RotationAxis; +import net.minecraft.util.math.random.LocalRandom; +import net.minecraft.world.BlockRenderView; +import net.minecraft.world.LightType; +import net.minecraft.world.biome.ColorResolver; +import net.minecraft.world.chunk.light.LightingProvider; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4f; +import org.lwjgl.system.MemoryUtil; + +import static org.lwjgl.opengl.ARBShaderImageLoadStore.GL_FRAMEBUFFER_BARRIER_BIT; +import static org.lwjgl.opengl.ARBShaderImageLoadStore.glMemoryBarrier; +import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.opengl.GL11C.GL_DEPTH; +import static org.lwjgl.opengl.GL14C.glBlendFuncSeparate; +import static org.lwjgl.opengl.GL30.*; +import static org.lwjgl.opengl.GL45.glClearNamedFramebufferfv; + +public class ModelTextureBakery2 { + //Note: the first bit of metadata is if alpha discard is enabled + private static final Matrix4f[] VIEWS = new Matrix4f[6]; + + private final GlViewCapture capture; + private final ReuseVertexConsumer vc = new ReuseVertexConsumer(); + private static final int FORMAT_STRIDE = 24; + private static final class ReuseVertexConsumer implements VertexConsumer { + private MemoryBuffer buffer = new MemoryBuffer(8192); + private long ptr; + private int count; + + public ReuseVertexConsumer() { + this.reset(); + } + + @Override + public ReuseVertexConsumer vertex(float x, float y, float z) { + this.ensureCanPut(); + this.ptr += FORMAT_STRIDE; this.count++; //Goto next vertex + MemoryUtil.memPutFloat(this.ptr, x); + MemoryUtil.memPutFloat(this.ptr + 4, y); + MemoryUtil.memPutFloat(this.ptr + 8, z); + return this; + } + + public ReuseVertexConsumer meta(int metadata) { + MemoryUtil.memPutInt(this.ptr + 12, metadata); + return this; + } + + @Override + public ReuseVertexConsumer color(int red, int green, int blue, int alpha) { + return this; + } + + @Override + public ReuseVertexConsumer texture(float u, float v) { + MemoryUtil.memPutFloat(this.ptr + 16, u); + MemoryUtil.memPutFloat(this.ptr + 20, v); + return this; + } + + @Override + public ReuseVertexConsumer overlay(int u, int v) { + return this; + } + + @Override + public ReuseVertexConsumer light(int u, int v) { + return this; + } + + @Override + public ReuseVertexConsumer normal(float x, float y, float z) { + return this; + } + + public ReuseVertexConsumer quad(BakedQuad quad, int metadata) { + int[] data = quad.vertexData(); + for (int i = 0; i < 4; i++) { + float x = Float.intBitsToFloat(data[i * 8]); + float y = Float.intBitsToFloat(data[i * 8 + 1]); + float z = Float.intBitsToFloat(data[i * 8 + 2]); + this.vertex(x,y,z); + float u = Float.intBitsToFloat(data[i * 8 + 4]); + float v = Float.intBitsToFloat(data[i * 8 + 5]); + this.texture(u,v); + + this.meta(metadata); + } + return this; + } + + private void ensureCanPut() { + if ((long) (this.count + 1) * FORMAT_STRIDE < this.buffer.size) { + return; + } + long offset = this.buffer.address-this.ptr; + //1.5x the size + var newBuffer = new MemoryBuffer((((int)(this.buffer.size*1.5)+FORMAT_STRIDE-1)/FORMAT_STRIDE)*FORMAT_STRIDE); + this.buffer.cpyTo(newBuffer.address); + this.buffer.free(); + this.buffer = newBuffer; + this.ptr = offset + newBuffer.address; + } + + public ReuseVertexConsumer reset() { + this.count = 0; + this.ptr = this.buffer.address - FORMAT_STRIDE;//the thing is first time this gets incremented by FORMAT_STRIDE + return this; + } + + public void free() { + this.buffer.free(); + this.buffer = null; + } + } + + private final int width; + private final int height; + public ModelTextureBakery2(int width, int height) { + this.capture = new GlViewCapture(width, height); + this.width = width; + this.height = height; + } + + private void bakeBlockModel(BlockState state, RenderLayer layer) { + var model = MinecraftClient.getInstance() + .getBakedModelManager() + .getBlockModels() + .getModel(state); + + boolean hasDiscard = layer == RenderLayer.getCutout() || + layer == RenderLayer.getCutoutMipped() || + layer == RenderLayer.getTripwire(); + + for (Direction direction : new Direction[]{Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST, null}) { + for (var part : model.getParts(new LocalRandom(42L))) { + var quads = part.getQuads(direction); + for (var quad : quads) { + //TODO: add meta specifiying quad has a tint + + int meta = hasDiscard?1:0; + this.vc.quad(quad, meta); + } + } + } + } + + + private void bakeFluidState(BlockState state, int face) { + MinecraftClient.getInstance().getBlockRenderManager().renderFluid(BlockPos.ORIGIN, new BlockRenderView() { + @Override + public float getBrightness(Direction direction, boolean shaded) { + return 0; + } + + @Override + public LightingProvider getLightingProvider() { + return null; + } + + @Override + public int getLightLevel(LightType type, BlockPos pos) { + return 0; + } + + @Override + public int getColor(BlockPos pos, ColorResolver colorResolver) { + return 0; + } + + @Nullable + @Override + public BlockEntity getBlockEntity(BlockPos pos) { + return null; + } + + @Override + public BlockState getBlockState(BlockPos pos) { + if (shouldReturnAirForFluid(pos, face)) { + return Blocks.AIR.getDefaultState(); + } + + //Fixme: + // This makes it so that the top face of water is always air, if this is commented out + // the up block will be a liquid state which makes the sides full + // if this is uncommented, that issue is fixed but e.g. stacking water layers ontop of eachother + // doesnt fill the side of the block + + //if (pos.getY() == 1) { + // return Blocks.AIR.getDefaultState(); + //} + return state; + } + + @Override + public FluidState getFluidState(BlockPos pos) { + if (shouldReturnAirForFluid(pos, face)) { + return Blocks.AIR.getDefaultState().getFluidState(); + } + + return state.getFluidState(); + } + + @Override + public int getHeight() { + return 0; + } + + @Override + public int getBottomY() { + return 0; + } + }, this.vc, state, state.getFluidState()); + } + + private static boolean shouldReturnAirForFluid(BlockPos pos, int face) { + var fv = Direction.byIndex(face).getVector(); + int dot = fv.getX()*pos.getX() + fv.getY()*pos.getY() + fv.getZ()*pos.getZ(); + return dot >= 1; + } + + public void free() { + this.capture.free(); + this.vc.free(); + } + + + public void renderToStream(BlockState state, int streamBuffer, int streamOffset) { + this.capture.clear(); + boolean isBlock = true; + RenderLayer layer; + if (state.getBlock() instanceof FluidBlock) { + layer = RenderLayers.getFluidLayer(state.getFluidState()); + isBlock = false; + } else { + layer = RenderLayers.getBlockLayer(state); + } + + //TODO: support block model entities + //state.hasBlockEntity() + + //Setup GL state + int[] viewdat = new int[4]; + int blockTextureId; + + { + glEnable(GL_STENCIL_TEST); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + if (layer == RenderLayer.getTranslucent()) { + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glDisable(GL_BLEND); + } + + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + glStencilFunc(GL_ALWAYS, 1, 0xFF); + glStencilMask(0xFF); + + glGetIntegerv(GL_VIEWPORT, viewdat);//TODO: faster way todo this, or just use main framebuffer resolution + + //Bind the capture framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, this.capture.framebuffer.id); + + var tex = MinecraftClient.getInstance().getTextureManager().getTexture(Identifier.of("minecraft", "textures/atlas/blocks.png")).getGlTexture(); + blockTextureId = ((net.minecraft.client.texture.GlTexture)tex).getGlId(); + } + + //TODO: fastpath for blocks + if (isBlock) { + this.vc.reset(); + this.bakeBlockModel(state, layer); + if (this.vc.count != 0) {//only render if there... is shit to render + if (this.vc.count % 4 != 0) throw new IllegalStateException(); + + //Setup for continual emission + BudgetBufferRenderer.setup(this.vc.buffer.address, this.vc.count / 4, blockTextureId);//note: this.vc.buffer.address NOT this.vc.ptr + + var mat = new Matrix4f(); + for (int i = 0; i < VIEWS.length; i++) { + glViewport((i % 3) * this.width, (i / 3) * this.height, this.width, this.height); + + //The projection matrix + mat.set(2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, -1f, 0, + -1, -1, 0, 1); + + BudgetBufferRenderer.render(mat.mul(VIEWS[i])); + } + } + glBindVertexArray(0); + } else {//Is fluid, slow path :( + if (!(state.getBlock() instanceof FluidBlock)) throw new IllegalStateException(); + + var mat = new Matrix4f(); + for (int i = 0; i < VIEWS.length; i++) { + this.vc.reset(); + this.bakeFluidState(state, i); + if (this.vc.count == 0) continue; + BudgetBufferRenderer.setup(this.vc.buffer.address, this.vc.count / 4, blockTextureId); + + glViewport((i % 3) * this.width, (i / 3) * this.height, this.width, this.height); + + //The projection matrix + mat.set(2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, -1f, 0, + -1, -1, 0, 1); + + BudgetBufferRenderer.render(mat.mul(VIEWS[i])); + } + glBindVertexArray(0); + } + + //"Restore" gl state + glViewport(viewdat[0], viewdat[1], viewdat[2], viewdat[3]); + glDisable(GL_STENCIL_TEST); + glDisable(GL_BLEND); + + //Finish and download + glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); + this.capture.emitToStream(streamBuffer, streamOffset); + + glBindFramebuffer(GL_FRAMEBUFFER, this.capture.framebuffer.id); + glClearDepth(1); + glClear(GL_DEPTH_BUFFER_BIT); + } + + + + + static { + //TODO: FIXME: need to bake in the correct orientation, HOWEVER some orientations require a flipped winding order!!!! + + addView(0, -90,0, 0, false);//Direction.DOWN + addView(1, 90,0, 0, false);//Direction.UP + addView(2, 0,180, 0, true);//Direction.NORTH + addView(3, 0,0, 0, false);//Direction.SOUTH + //TODO: check these arnt the wrong way round + addView(4, 0,90, 270, false);//Direction.EAST + addView(5, 0,270, 270, false);//Direction.WEST + } + + private static void addView(int i, float pitch, float yaw, float rotation, boolean flipX) { + var stack = new MatrixStack(); + stack.translate(0.5f,0.5f,0.5f); + stack.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(rotation)); + stack.multiply(RotationAxis.POSITIVE_X.rotationDegrees(pitch)); + stack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw)); + stack.translate(-0.5f,-0.5f,-0.5f); + VIEWS[i] = new Matrix4f(stack.peek().getPositionMatrix()); + } +} diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/RenderService.java b/src/main/java/me/cortex/voxy/client/core/rendering/RenderService.java index b6269910..1bd98f56 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/RenderService.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/RenderService.java @@ -80,7 +80,7 @@ public class RenderService, J extends Vi this.viewportSelector = new ViewportSelector<>(this.sectionRenderer::createViewport); this.renderGen = new RenderGenerationService(world, this.modelService, serviceThreadPool, this.geometryUpdateQueue::push, this.sectionRenderer.getGeometryManager() instanceof IUsesMeshlets, - ()->this.geometryUpdateQueue.count()<1000); + ()->this.geometryUpdateQueue.count()<7000); router.setCallbacks(this.renderGen::enqueueTask, section -> { section.acquire(); @@ -142,7 +142,7 @@ public class RenderService, J extends Vi //if (this.modelService.getProcessingCount() < 750) {//Very bad hack to try control things - this.geometryUpdateQueue.consumeNano(1_000_000 - (System.nanoTime() - frameStart)); + this.geometryUpdateQueue.consumeNano(1_500_000 - (System.nanoTime() - frameStart)); } this.nodeCleaner.tick(this.traversal.getNodeBuffer());//Probably do this here?? diff --git a/src/main/java/me/cortex/voxy/common/thread/ServiceThreadPool.java b/src/main/java/me/cortex/voxy/common/thread/ServiceThreadPool.java index 03cac039..0fc46069 100644 --- a/src/main/java/me/cortex/voxy/common/thread/ServiceThreadPool.java +++ b/src/main/java/me/cortex/voxy/common/thread/ServiceThreadPool.java @@ -206,7 +206,7 @@ public class ServiceThreadPool { if (service == null) { Logger.warn("No available jobs, sleeping releasing returning"); try { - Thread.sleep(500); + Thread.sleep((long) (200*Math.random()+5)); } catch (InterruptedException e) { throw new RuntimeException(e); } diff --git a/src/main/java/me/cortex/voxy/common/world/ActiveSectionTracker.java b/src/main/java/me/cortex/voxy/common/world/ActiveSectionTracker.java index 5cccbcef..c447c1b3 100644 --- a/src/main/java/me/cortex/voxy/common/world/ActiveSectionTracker.java +++ b/src/main/java/me/cortex/voxy/common/world/ActiveSectionTracker.java @@ -173,21 +173,26 @@ public class ActiveSectionTracker { sec = section; } } + + WorldSection aa = null; + if (sec != null) { + long stamp2 = this.lruLock.writeLock(); + WorldSection a = this.lruSecondaryCache.put(section.key, section); + if (a != null) { + throw new IllegalStateException("duplicate sections in cache is impossible"); + } + //If cache is bigger than its ment to be, remove the least recently used and free it + if (this.lruSize < this.lruSecondaryCache.size()) { + aa = this.lruSecondaryCache.removeFirst(); + } + this.lruLock.unlockWrite(stamp2); + + } + lock.unlockWrite(stamp); - if (sec != null) { - stamp = this.lruLock.writeLock(); - - WorldSection a = this.lruSecondaryCache.put(section.key, section); - //If cache is bigger than its ment to be, remove the least recently used and free it - if (a == null && this.lruSize < this.lruSecondaryCache.size()) { - a = this.lruSecondaryCache.removeFirst(); - } - this.lruLock.unlockWrite(stamp); - - if (a != null) { - a._releaseArray(); - } + if (aa != null) { + aa._releaseArray(); } } diff --git a/src/main/resources/assets/voxy/shaders/bakery/position_tex.fsh b/src/main/resources/assets/voxy/shaders/bakery/position_tex.fsh index e6950991..28c679d4 100644 --- a/src/main/resources/assets/voxy/shaders/bakery/position_tex.fsh +++ b/src/main/resources/assets/voxy/shaders/bakery/position_tex.fsh @@ -1,13 +1,13 @@ #version 430 layout(location=0) uniform sampler2D tex; -in vec2 texCoord; in flat uint metadata; +in vec2 texCoord; out vec4 colour; void main() { - colour = texture(tex, texCoord)*(metadata&1); - if (colour.a <0.0001f) { + colour = texture(tex, texCoord); + if (colour.a < 0.0001f && ((metadata&1u)!=0)) { discard; } } diff --git a/src/main/resources/assets/voxy/shaders/bakery/position_tex.vsh b/src/main/resources/assets/voxy/shaders/bakery/position_tex.vsh index 7831068f..f5b3813a 100644 --- a/src/main/resources/assets/voxy/shaders/bakery/position_tex.vsh +++ b/src/main/resources/assets/voxy/shaders/bakery/position_tex.vsh @@ -1,16 +1,15 @@ #version 430 layout(location=0) in vec3 pos; -layout(location=1) in vec2 uv; -layout(location=2) in vec4 _metadata; +layout(location=1) in uint _metadata; +layout(location=2) in vec2 uv; -uniform mat4 transform; +layout(location=1) uniform mat4 transform; out vec2 texCoord; out flat uint metadata; void main() { - uvec4 meta = uvec4(_metadata*255); - metadata = (meta.r<<16)|(meta.g<<8)|(meta.b); + metadata = _metadata; gl_Position = transform * vec4(pos, 1.0); texCoord = uv;