diff --git a/src/main/java/me/cortex/voxy/client/core/IrisVoxyRenderPipeline.java b/src/main/java/me/cortex/voxy/client/core/IrisVoxyRenderPipeline.java index 2dbb2a69e..c92d0c02b 100644 --- a/src/main/java/me/cortex/voxy/client/core/IrisVoxyRenderPipeline.java +++ b/src/main/java/me/cortex/voxy/client/core/IrisVoxyRenderPipeline.java @@ -35,10 +35,6 @@ public class IrisVoxyRenderPipeline extends AbstractRenderPipeline { public IrisVoxyRenderPipeline(IrisVoxyRenderPipelineData data, AsyncNodeManager nodeManager, NodeCleaner nodeCleaner, HierarchicalOcclusionTraverser traversal, BooleanSupplier frexSupplier) { super(nodeManager, nodeCleaner, traversal, frexSupplier, data.shouldDeferTranslucency()); this.data = data; - if (this.data.thePipeline != null) { - throw new IllegalStateException("Pipeline data already bound"); - } - this.data.thePipeline = this; //Bind the drawbuffers var oDT = this.data.opaqueDrawTargets; @@ -80,10 +76,6 @@ public void setupExtraModelBakeryData(ModelBakerySubsystem modelService) { @Override public void free() { - if (this.data.thePipeline != this) { - throw new IllegalStateException(); - } - this.data.thePipeline = null; this.depthBlit.delete(); this.fbTranslucent.free(); diff --git a/src/main/java/me/cortex/voxy/client/core/VoxyRenderSystem.java b/src/main/java/me/cortex/voxy/client/core/VoxyRenderSystem.java index 9d552fde8..30abd3bce 100644 --- a/src/main/java/me/cortex/voxy/client/core/VoxyRenderSystem.java +++ b/src/main/java/me/cortex/voxy/client/core/VoxyRenderSystem.java @@ -33,6 +33,8 @@ import me.cortex.voxy.common.world.WorldEngine; import me.cortex.voxy.commonImpl.VoxyCommon; import net.caffeinemc.mods.sodium.client.render.chunk.ChunkRenderMatrices; +import net.irisshaders.iris.Iris; +import net.irisshaders.iris.pipeline.WorldRenderingPipeline; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; import org.joml.Matrix4f; @@ -68,11 +70,20 @@ public class VoxyRenderSystem { private final RenderDistanceTracker renderDistanceTracker; - public final ChunkBoundRenderer chunkBoundRenderer; + public ChunkBoundRenderer chunkBoundRenderer; - private final ViewportSelector viewportSelector; + private ViewportSelector viewportSelector; - private final AbstractRenderPipeline pipeline; + private AbstractRenderPipeline pipeline; + + private WorldRenderingPipeline lastIrisPipeline; + + private final Object pipelineLock = new Object(); + + private boolean pipelineUpdatePending = false; + private ViewportSelector pendingViewportSelector; + private ChunkBoundRenderer pendingChunkBoundRenderer; + private AbstractRenderPipeline oldPipelinePendingFree; // Fog parameters captured before modification by MixinFogRenderer, for Voxy's own fog pass private float capturedFogStart; @@ -236,10 +247,75 @@ public Viewport setupViewport(ChunkRenderMatrices matrices, double cameraX, d return viewport; } + private void setupNewPipeline() { + this.oldPipelinePendingFree = this.pipeline; + + this.pipeline = RenderPipelineFactory.createPipeline(this.nodeManager, this.nodeCleaner, this.traversal, this::frexStillHasWork); + this.pipeline.setupExtraModelBakeryData(this.modelService); + + var backendFactory = getRenderBackendFactory(); + var sectionRenderer = backendFactory.create(this.pipeline, this.modelService.getStore(), this.geometryData); + this.pipeline.setSectionRenderer(sectionRenderer); + + this.pendingViewportSelector = new ViewportSelector<>(sectionRenderer::createViewport); + this.pendingChunkBoundRenderer = new ChunkBoundRenderer(this.pipeline); + this.pipelineUpdatePending = true; + + this.traversal.lateStageCompile(this.pipeline); + } + + private boolean checkAndUpdatePipeline() { + if (!IrisUtil.IRIS_INSTALLED || !IrisUtil.SHADER_SUPPORT) { + return false; + } + + synchronized (pipelineLock) { + WorldRenderingPipeline currentIrisPipeline = Iris.getPipelineManager().getPipelineNullable(); + + if (currentIrisPipeline != lastIrisPipeline) { + Logger.info("Iris pipeline changed, updating Voxy pipeline"); + + try { + setupNewPipeline(); + lastIrisPipeline = currentIrisPipeline; + Logger.info("Voxy pipeline updated successfully (viewport swap deferred)"); + return true; + } catch (Exception e) { + Logger.error("Failed to create new pipeline during update", e); + } + } + } + return false; + } + + private void commitDeferredPipelineUpdate() { + if (!this.pipelineUpdatePending) return; + this.pipelineUpdatePending = false; + + if (this.pendingViewportSelector != null) { + this.viewportSelector.free(); + this.viewportSelector = this.pendingViewportSelector; + this.pendingViewportSelector = null; + } + + if (this.pendingChunkBoundRenderer != null) { + this.chunkBoundRenderer.free(); + this.chunkBoundRenderer = this.pendingChunkBoundRenderer; + this.pendingChunkBoundRenderer = null; + } + + if (this.oldPipelinePendingFree != null) { + this.oldPipelinePendingFree.free(); + this.oldPipelinePendingFree = null; + } + } + public void renderOpaque(Viewport viewport) { if (viewport == null) { return; } + + checkAndUpdatePipeline(); if (viewport.width <= 0 || viewport.height <= 0) { return;//Only render on valid viewport } @@ -461,6 +537,7 @@ public Viewport getViewport() { if (IrisUtil.irisShadowActive()) { return null; } + commitDeferredPipelineUpdate(); return this.viewportSelector.getViewport(); } @@ -499,16 +576,31 @@ public void shutdown() { this.traversal.free(); this.nodeCleaner.free(); this.geometryData.free(); - if (((BasicSectionGeometryData)this.geometryData).isExternalGeometryBuffer) { + if (((BasicSectionGeometryData)this.geometryData).isExternalGeometryBuffer) { RenderResourceReuse.giveBackGeometryBuffer(((BasicSectionGeometryData)this.geometryData).getGeometryBuffer()); } this.chunkBoundRenderer.free(); - this.viewportSelector.free(); + this.viewportSelector.free(); } catch (Exception e) {Logger.error("Error shutting down renderer components", e);} + + if (this.pendingViewportSelector != null) { + this.pendingViewportSelector.free(); + this.pendingViewportSelector = null; + } + if (this.pendingChunkBoundRenderer != null) { + this.pendingChunkBoundRenderer.free(); + this.pendingChunkBoundRenderer = null; + } + + if (this.oldPipelinePendingFree != null) { + this.oldPipelinePendingFree.free(); + this.oldPipelinePendingFree = null; + } + Logger.info("Shutting down render pipeline"); - try {this.pipeline.free();} catch (Exception e){Logger.error("Error releasing render pipeline", e);} + try {if (this.pipeline != null) this.pipeline.free();} catch (Exception e){Logger.error("Error releasing render pipeline", e);} @@ -523,4 +615,8 @@ public void shutdown() { public WorldEngine getEngine() { return this.worldIn; } + + public AbstractRenderPipeline getPipeline() { + return this.pipeline; + } } diff --git a/src/main/java/me/cortex/voxy/client/core/model/MipGen.java b/src/main/java/me/cortex/voxy/client/core/model/MipGen.java index 7ba229afa..66b0735c7 100644 --- a/src/main/java/me/cortex/voxy/client/core/model/MipGen.java +++ b/src/main/java/me/cortex/voxy/client/core/model/MipGen.java @@ -13,9 +13,6 @@ public class MipGen { static { if (MODEL_TEXTURE_SIZE>16) throw new IllegalStateException("TODO: THIS MUST BE UPDATED, IT CURRENTLY ASSUMES 16 OR SMALLER SIZE"); } - private static final short[] SCRATCH = new short[MODEL_TEXTURE_SIZE*MODEL_TEXTURE_SIZE]; - private static final ByteArrayFIFOQueue QUEUE = new ByteArrayFIFOQueue(MODEL_TEXTURE_SIZE*MODEL_TEXTURE_SIZE); - private static long getOffset(int bx, int by, int i) { bx += i&(MODEL_TEXTURE_SIZE-1); by += i/MODEL_TEXTURE_SIZE; @@ -23,6 +20,8 @@ private static long getOffset(int bx, int by, int i) { } private static void solidify(long baseAddr, byte msk) { + short[] SCRATCH = new short[MODEL_TEXTURE_SIZE * MODEL_TEXTURE_SIZE]; + ByteArrayFIFOQueue QUEUE = new ByteArrayFIFOQueue(MODEL_TEXTURE_SIZE * MODEL_TEXTURE_SIZE); for (int idx = 0; idx < 6; idx++) { if (((msk>>idx)&1)==0) continue; int bx = (idx>>1)*MODEL_TEXTURE_SIZE; diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java index 9b46ddac8..5ac07fd72 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/hierachical/HierarchicalOcclusionTraverser.java @@ -97,6 +97,9 @@ public HierarchicalOcclusionTraverser(AsyncNodeManager nodeManager, NodeCleaner } public void lateStageCompile(AbstractRenderPipeline pipeline) { + if (this.traversal != null) { + this.traversal.free(); + } String taa = pipeline.taaFunction("getTAA"); var scr = ShaderLoader.parse("voxy:lod/hierarchical/traversal_dev.comp"); if (taa != null) { diff --git a/src/main/java/me/cortex/voxy/client/iris/IrisVoxyRenderPipelineData.java b/src/main/java/me/cortex/voxy/client/iris/IrisVoxyRenderPipelineData.java index 43e88d1a4..204846120 100644 --- a/src/main/java/me/cortex/voxy/client/iris/IrisVoxyRenderPipelineData.java +++ b/src/main/java/me/cortex/voxy/client/iris/IrisVoxyRenderPipelineData.java @@ -39,7 +39,6 @@ import static org.lwjgl.opengl.GL43C.GL_SHADER_STORAGE_BUFFER; public class IrisVoxyRenderPipelineData { - public IrisVoxyRenderPipeline thePipeline; public final int[] opaqueDrawTargets; public final int[] translucentDrawTargets; private final String opaquePatch; diff --git a/src/main/java/me/cortex/voxy/client/iris/VoxySamplers.java b/src/main/java/me/cortex/voxy/client/iris/VoxySamplers.java index c56732aa1..9e503fb23 100644 --- a/src/main/java/me/cortex/voxy/client/iris/VoxySamplers.java +++ b/src/main/java/me/cortex/voxy/client/iris/VoxySamplers.java @@ -1,9 +1,12 @@ package me.cortex.voxy.client.iris; +import me.cortex.voxy.client.core.IGetVoxyRenderSystem; +import me.cortex.voxy.client.core.IrisVoxyRenderPipeline; import net.irisshaders.iris.gl.sampler.GlSampler; import net.irisshaders.iris.gl.sampler.SamplerHolder; import net.irisshaders.iris.gl.texture.TextureType; import net.irisshaders.iris.pipeline.IrisRenderingPipeline; +import net.minecraft.client.Minecraft; public class VoxySamplers { public static void addSamplers(IrisRenderingPipeline pipeline, SamplerHolder samplers) { @@ -17,18 +20,20 @@ public static void addSamplers(IrisRenderingPipeline pipeline, SamplerHolder sam translucentNames = new String[]{"vxDepthTexTrans", "dhDepthTex", "dhDepthTex0"}; }*/ - //TODO replace ()->0 with the actual depth texture id + //Access the current pipeline through the VoxyRenderSystem samplers.addDynamicSampler(TextureType.TEXTURE_2D, () -> { - var pipeData = ((IGetIrisVoxyPipelineData)pipeline).voxy$getPipelineData(); - if (pipeData == null) { + var voxyRenderSystem = ((IGetVoxyRenderSystem) Minecraft.getInstance().levelRenderer).voxy$getRenderSystem(); + if (voxyRenderSystem == null) { return 0; } - if (pipeData.thePipeline == null) { + + var currentPipeline = voxyRenderSystem.getPipeline(); + if (currentPipeline == null || !(currentPipeline instanceof IrisVoxyRenderPipeline irisPipeline)) { return 0; } - //In theory the first frame could be null - var dt = pipeData.thePipeline.fb.getDepthTex(); + //Get the depth texture from the current pipeline's framebuffer + var dt = irisPipeline.fb.getDepthTex(); if (dt == null) { return 0; } @@ -36,15 +41,18 @@ public static void addSamplers(IrisRenderingPipeline pipeline, SamplerHolder sam }, new GlSampler(false, true, false, false), opaqueNames); samplers.addDynamicSampler(TextureType.TEXTURE_2D, () -> { - var pipeData = ((IGetIrisVoxyPipelineData)pipeline).voxy$getPipelineData(); - if (pipeData == null) { + var voxyRenderSystem = ((IGetVoxyRenderSystem) Minecraft.getInstance().levelRenderer).voxy$getRenderSystem(); + if (voxyRenderSystem == null) { return 0; } - if (pipeData.thePipeline == null) { + + var currentPipeline = voxyRenderSystem.getPipeline(); + if (currentPipeline == null || !(currentPipeline instanceof IrisVoxyRenderPipeline irisPipeline)) { return 0; } - //In theory the first frame could be null - var dt = pipeData.thePipeline.fbTranslucent.getDepthTex(); + + //Get the depth texture from the current pipeline's translucent framebuffer + var dt = irisPipeline.fbTranslucent.getDepthTex(); if (dt == null) { return 0; }