From cc609bbb079b1f2d153356b735354830a92c0719 Mon Sep 17 00:00:00 2001 From: mcrcortex <18544518+MCRcortex@users.noreply.github.com> Date: Wed, 20 Aug 2025 13:44:31 +1000 Subject: [PATCH] Image and ssbo bindings --- .../client/core/IrisVoxyRenderPipeline.java | 53 ++++++++----- .../voxy/client/iris/IrisShaderPatch.java | 3 +- .../iris/IrisVoxyRenderPipelineData.java | 79 +++++++++++++++++-- 3 files changed, 107 insertions(+), 28 deletions(-) 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 cf252e67..36557db0 100644 --- a/src/main/java/me/cortex/voxy/client/core/IrisVoxyRenderPipeline.java +++ b/src/main/java/me/cortex/voxy/client/core/IrisVoxyRenderPipeline.java @@ -137,20 +137,28 @@ public class IrisVoxyRenderPipeline extends AbstractRenderPipeline { glColorMask(true, true, true, true); } - @Override - public void setupAndBindOpaque(Viewport viewport) { - this.fb.bind(); + + private void doBindings() { if (this.shaderUniforms != null) { GL30.glBindBufferBase(GL_UNIFORM_BUFFER, 5, this.shaderUniforms.id);// todo: dont randomly select this to 5 } + if (this.data.getSsboSet() != null) { + this.data.getSsboSet().bindingFunction().accept(10); + } + if (this.data.getImageSet() != null) { + this.data.getImageSet().bindingFunction().accept(6); + } + } + @Override + public void setupAndBindOpaque(Viewport viewport) { + this.fb.bind(); + this.doBindings(); } @Override public void setupAndBindTranslucent(Viewport viewport) { this.fbTranslucent.bind(); - if (this.shaderUniforms != null) { - GL30.glBindBufferBase(GL_UNIFORM_BUFFER, 5, this.shaderUniforms.id);// todo: dont randomly select this to 5 - } + this.doBindings(); if (this.data.getBlender() != null) { this.data.getBlender().run(); } @@ -162,17 +170,33 @@ public class IrisVoxyRenderPipeline extends AbstractRenderPipeline { super.addDebug(debug); } - @Override - public String patchOpaqueShader(AbstractSectionRenderer renderer, String input) { + private StringBuilder buildGenericShaderHeader(AbstractSectionRenderer renderer, String input) { StringBuilder builder = new StringBuilder(input).append("\n\n\n"); if (this.data.getUniforms() != null) { //TODO make ths binding point... not randomly 5 builder.append("layout(binding = 5, std140) uniform ShaderUniformBindings ") .append(this.data.getUniforms().layout()) - .append(";\n\n\n"); + .append(";\n\n"); } + if (this.data.getSsboSet() != null) { + builder.append("#define BUFFER_BINDING_INDEX_BASE 10\n");//TODO: DONT RANDOMLY MAKE THIS 10 + builder.append(this.data.getSsboSet().layout()).append("\n\n"); + } + + if (this.data.getImageSet() != null) { + builder.append("#define BASE_SAMPLER_BINDING_INDEX 6\n");//TODO: DONT RANDOMLY MAKE THIS 6 + builder.append(this.data.getImageSet().layout()).append("\n\n"); + } + + return builder.append("\n\n"); + } + + @Override + public String patchOpaqueShader(AbstractSectionRenderer renderer, String input) { + var builder = this.buildGenericShaderHeader(renderer, input); + builder.append(this.data.opaqueFragPatch()); return builder.toString(); @@ -182,17 +206,8 @@ public class IrisVoxyRenderPipeline extends AbstractRenderPipeline { public String patchTranslucentShader(AbstractSectionRenderer renderer, String input) { if (this.data.translucentFragPatch() == null) return null; - StringBuilder builder = new StringBuilder(input).append("\n\n\n"); - - if (this.data.getUniforms() != null) { - //TODO make ths binding point... not randomly 5 - builder.append("layout(binding = 5, std140) uniform ShaderUniformBindings ") - .append(this.data.getUniforms().layout()) - .append(";\n\n\n"); - } - + var builder = this.buildGenericShaderHeader(renderer, input); builder.append(this.data.translucentFragPatch()); - return builder.toString(); } } diff --git a/src/main/java/me/cortex/voxy/client/iris/IrisShaderPatch.java b/src/main/java/me/cortex/voxy/client/iris/IrisShaderPatch.java index 5c89e165..58354eb9 100644 --- a/src/main/java/me/cortex/voxy/client/iris/IrisShaderPatch.java +++ b/src/main/java/me/cortex/voxy/client/iris/IrisShaderPatch.java @@ -2,6 +2,7 @@ package me.cortex.voxy.client.iris; import com.google.gson.*; import com.google.gson.annotations.JsonAdapter; +import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import me.cortex.voxy.common.Logger; @@ -137,7 +138,7 @@ public class IrisShaderPatch { } public Int2ObjectMap getSSBOs() { - return this.ssbos; + return new Int2ObjectLinkedOpenHashMap<>(this.ssbos); } public String getPatchOpaqueSource() { return String.join("\n", this.patchData.opaquePatchData); 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 60bae3c4..d4993c15 100644 --- a/src/main/java/me/cortex/voxy/client/iris/IrisVoxyRenderPipelineData.java +++ b/src/main/java/me/cortex/voxy/client/iris/IrisVoxyRenderPipelineData.java @@ -26,10 +26,16 @@ import org.joml.*; import org.lwjgl.system.MemoryUtil; import java.util.*; +import java.util.function.IntConsumer; import java.util.function.IntSupplier; import java.util.function.LongConsumer; import java.util.stream.Collectors; +import static org.lwjgl.opengl.ARBDirectStateAccess.glBindTextureUnit; +import static org.lwjgl.opengl.ARBUniformBufferObject.glBindBufferBase; +import static org.lwjgl.opengl.GL33C.glBindSampler; +import static org.lwjgl.opengl.GL43C.GL_SHADER_STORAGE_BUFFER; + public class IrisVoxyRenderPipelineData { public IrisVoxyRenderPipeline thePipeline; public final int[] opaqueDrawTargets; @@ -38,13 +44,25 @@ public class IrisVoxyRenderPipelineData { private final String translucentPatch; private final StructLayout uniforms; private final Runnable blendingSetup; - private IrisVoxyRenderPipelineData(IrisShaderPatch patch, int[] opaqueDrawTargets, int[] translucentDrawTargets, StructLayout uniformSet, Runnable blendingSetup) { + private final ImageSet imageSet; + private final SSBOSet ssboSet; + private IrisVoxyRenderPipelineData(IrisShaderPatch patch, int[] opaqueDrawTargets, int[] translucentDrawTargets, StructLayout uniformSet, Runnable blendingSetup, ImageSet imageSet, SSBOSet ssboSet) { this.opaqueDrawTargets = opaqueDrawTargets; this.translucentDrawTargets = translucentDrawTargets; this.opaquePatch = patch.getPatchOpaqueSource(); this.translucentPatch = patch.getPatchTranslucentSource(); this.uniforms = uniformSet; this.blendingSetup = blendingSetup; + this.imageSet = imageSet; + this.ssboSet = ssboSet; + } + + public SSBOSet getSsboSet() { + return this.ssboSet; + } + + public ImageSet getImageSet() { + return this.imageSet; } public StructLayout getUniforms() { @@ -60,12 +78,13 @@ public class IrisVoxyRenderPipelineData { return this.translucentPatch; } + public static IrisVoxyRenderPipelineData buildPipeline(IrisRenderingPipeline ipipe, IrisShaderPatch patch, CustomUniforms cu, ShaderStorageBufferHolder ssboHolder) { var uniforms = createUniformLayoutStructAndUpdater(createUniformSet(cu, patch)); - createImageSet(ipipe, patch); + var imageSet = createImageSet(ipipe, patch); - createSSBOLayouts(patch.getSSBOs(), ssboHolder); + var ssboSet = createSSBOLayouts(patch.getSSBOs(), ssboHolder); var opaqueDrawTargets = getDrawBuffers(patch.getOpqaueTargets(), ipipe.getFlippedAfterPrepare(), ((IrisRenderingPipelineAccessor)ipipe).getRenderTargets()); var translucentDrawTargets = getDrawBuffers(patch.getTranslucentTargets(), ipipe.getFlippedAfterPrepare(), ((IrisRenderingPipelineAccessor)ipipe).getRenderTargets()); @@ -73,7 +92,7 @@ public class IrisVoxyRenderPipelineData { //TODO: need to transform the string patch with the uniform decleration aswell as sampler declerations - return new IrisVoxyRenderPipelineData(patch, opaqueDrawTargets, translucentDrawTargets, uniforms, patch.createBlendSetup()); + return new IrisVoxyRenderPipelineData(patch, opaqueDrawTargets, translucentDrawTargets, uniforms, patch.createBlendSetup(), imageSet, ssboSet); } private static int[] getDrawBuffers(int[] targets, ImmutableSet stageWritesToAlt, RenderTargets rt) { @@ -277,11 +296,13 @@ public class IrisVoxyRenderPipelineData { return uniforms; } - private record TextureWSampler(String name, IntSupplier texture, int sampler) { + private record TextureWSampler(String name, IntSupplier texture, int sampler) { } + public record ImageSet(String layout, IntConsumer bindingFunction) { } - private static void createImageSet(IrisRenderingPipeline ipipe, IrisShaderPatch patch) { + private static ImageSet createImageSet(IrisRenderingPipeline ipipe, IrisShaderPatch patch) { Set samplerNameSet = new LinkedHashSet<>(List.of(patch.getSamplerList())); + if (samplerNameSet.isEmpty()) return null; Set samplerSet = new LinkedHashSet<>(); SamplerHolder samplerBuilder = new SamplerHolder() { @Override @@ -350,10 +371,52 @@ public class IrisVoxyRenderPipelineData { //TODO: generate a layout (defines) for all the samplers with the correct types + StringBuilder builder = new StringBuilder(); + TextureWSampler[] samplers = new TextureWSampler[samplerSet.size()]; + int i = 0; + for (var entry : samplerSet) { + samplers[i]=entry; + builder.append("layout(binding=(BASE_SAMPLER_BINDING_INDEX+").append(i).append(")) uniform sampler2D ").append(entry.name).append(";\n"); + i++; + } + + + IntConsumer bindingFunction = base->{ + for (int j = 0; j < samplers.length; j++) { + int unit = j+base; + var ts = samplers[j]; + glBindTextureUnit(unit, ts.texture.getAsInt()); + if (ts.sampler != -1) { + glBindSampler(unit, ts.sampler); + }//TODO: might need to bind sampler 0 + } + }; + return new ImageSet(builder.toString(), bindingFunction); } - - private static void createSSBOLayouts(Int2ObjectMap ssbos, ShaderStorageBufferHolder ssboStore) { + public record SSBOSet(String layout, IntConsumer bindingFunction){} + private record SSBOBinding(int irisIndex, int bindingOffset) {} + private static SSBOSet createSSBOLayouts(Int2ObjectMap ssbos, ShaderStorageBufferHolder ssboStore) { + if (ssbos.isEmpty()) return null; + String header = ""; + if (ssbos.containsKey(-1)) header = ssbos.remove(-1); + StringBuilder builder = new StringBuilder(header); + builder.append("\n"); + SSBOBinding[] bindings = new SSBOBinding[ssbos.size()]; + int i = 0; + for (var entry : ssbos.int2ObjectEntrySet()) { + var val = entry.getValue(); + bindings[i] = new SSBOBinding(entry.getIntKey(), i); + builder.append("layout(binding = (BUFFER_BINDING_INDEX_BASE+").append(i).append(")) restrict buffer IrisBufferBinding").append(i); + builder.append(" ").append(val).append(";\n"); + i++; + } //ssboStore.getBufferIndex() + IntConsumer bindingFunction = base->{ + for (var binding : bindings) { + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, base+binding.bindingOffset, ssboStore.getBufferIndex(binding.irisIndex)); + } + }; + return new SSBOSet(builder.toString(), bindingFunction); } }