From 422fad934263cbeed9a46627d2b1902b42ccdb0d Mon Sep 17 00:00:00 2001 From: IMS212 Date: Sun, 15 Sep 2024 14:12:21 -0700 Subject: [PATCH] Add the ability to load file into SSBO --- .../iris/gl/buffer/ShaderStorageBuffer.java | 28 ++++++++++++- .../gl/buffer/ShaderStorageBufferHolder.java | 7 +--- .../iris/gl/buffer/ShaderStorageInfo.java | 2 +- .../iris/pipeline/IrisRenderingPipeline.java | 4 +- .../iris/shaderpack/ShaderPack.java | 39 +++++++++++++++++++ .../shaderpack/properties/PackDirectives.java | 8 ---- .../properties/ShaderProperties.java | 14 +++++-- 7 files changed, 80 insertions(+), 22 deletions(-) diff --git a/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBuffer.java b/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBuffer.java index f4814a5b9f..f3bbd2ccf3 100644 --- a/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBuffer.java +++ b/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBuffer.java @@ -4,15 +4,27 @@ import net.irisshaders.iris.gl.GLDebug; import net.irisshaders.iris.gl.IrisRenderSystem; import org.lwjgl.opengl.GL43C; +import org.lwjgl.opengl.GL46C; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; // Do not extend GlResource, this is immutable. public class ShaderStorageBuffer { protected final int index; - protected final ShaderStorageInfo info; + protected final BuiltShaderStorageInfo info; protected int id; + protected final ByteBuffer content; - public ShaderStorageBuffer(int index, ShaderStorageInfo info) { + public ShaderStorageBuffer(int index, BuiltShaderStorageInfo info) { this.id = IrisRenderSystem.createBuffers(); + if (info.content() != null) { + content = MemoryUtil.memAlloc(info.content().length); + content.put(info.content()); + content.flip(); + } else { + content = null; + } GLDebug.nameObject(GL43C.GL_BUFFER, id, "SSBO " + index); this.index = index; this.info = info; @@ -30,6 +42,7 @@ protected void destroy() { IrisRenderSystem.bindBufferBase(GL43C.GL_SHADER_STORAGE_BUFFER, index, 0); // DO NOT use the GlStateManager version here! On Linux, it will attempt to clear the data using BufferData and cause GL errors. IrisRenderSystem.deleteBuffers(id); + MemoryUtil.memFree(content); } public void bind() { @@ -56,4 +69,15 @@ public void resizeIfRelative(int width, int height) { public int getId() { return id; } + + public void createStatic() { + GlStateManager._glBindBuffer(GL43C.GL_SHADER_STORAGE_BUFFER, getId()); + IrisRenderSystem.bufferStorage(GL43C.GL_SHADER_STORAGE_BUFFER, info.size(), content == null ? 0 : GL46C.GL_DYNAMIC_STORAGE_BIT); + if (content != null) { + GL46C.glBufferSubData(GL43C.GL_SHADER_STORAGE_BUFFER, 0, content); + } else { + IrisRenderSystem.clearBufferSubData(GL43C.GL_SHADER_STORAGE_BUFFER, GL43C.GL_R8, 0, info.size(), GL43C.GL_RED, GL43C.GL_BYTE, new int[]{0}); + } + bind(); + } } diff --git a/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBufferHolder.java b/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBufferHolder.java index 66a284b688..b6b5bcb738 100644 --- a/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBufferHolder.java +++ b/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageBufferHolder.java @@ -19,7 +19,7 @@ public class ShaderStorageBufferHolder { private boolean destroyed; - public ShaderStorageBufferHolder(Int2ObjectArrayMap overrides, int width, int height) { + public ShaderStorageBufferHolder(Int2ObjectArrayMap overrides, int width, int height) { destroyed = false; cachedWidth = width; cachedHeight = height; @@ -40,10 +40,7 @@ public ShaderStorageBufferHolder(Int2ObjectArrayMap overrides if (bufferInfo.relative()) { buffers[index].resizeIfRelative(width, height); } else { - GlStateManager._glBindBuffer(GL43C.GL_SHADER_STORAGE_BUFFER, buffer); - IrisRenderSystem.bufferStorage(GL43C.GL_SHADER_STORAGE_BUFFER, bufferInfo.size(), 0); - IrisRenderSystem.clearBufferSubData(GL43C.GL_SHADER_STORAGE_BUFFER, GL43C.GL_R8, 0, bufferInfo.size(), GL43C.GL_RED, GL43C.GL_BYTE, new int[]{0}); - IrisRenderSystem.bindBufferBase(GL43C.GL_SHADER_STORAGE_BUFFER, index, buffer); + buffers[index].createStatic(); } }); GlStateManager._glBindBuffer(GL43C.GL_SHADER_STORAGE_BUFFER, 0); diff --git a/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageInfo.java b/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageInfo.java index a63ab2e30f..df0c3ad279 100644 --- a/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageInfo.java +++ b/common/src/main/java/net/irisshaders/iris/gl/buffer/ShaderStorageInfo.java @@ -1,4 +1,4 @@ package net.irisshaders.iris.gl.buffer; -public record ShaderStorageInfo(long size, boolean relative, float scaleX, float scaleY) { +public record ShaderStorageInfo(long size, boolean relative, float scaleX, float scaleY, String name) { } diff --git a/common/src/main/java/net/irisshaders/iris/pipeline/IrisRenderingPipeline.java b/common/src/main/java/net/irisshaders/iris/pipeline/IrisRenderingPipeline.java index bab0df177b..245d86a5c0 100644 --- a/common/src/main/java/net/irisshaders/iris/pipeline/IrisRenderingPipeline.java +++ b/common/src/main/java/net/irisshaders/iris/pipeline/IrisRenderingPipeline.java @@ -218,9 +218,9 @@ public IrisRenderingPipeline(ProgramSet programSet) { int internalFormat = TextureInfoCache.INSTANCE.getInfo(depthTextureId).getInternalFormat(); DepthBufferFormat depthBufferFormat = DepthBufferFormat.fromGlEnumOrDefault(internalFormat); - if (!programSet.getPackDirectives().getBufferObjects().isEmpty()) { + if (!pack.getBufferObjects().isEmpty()) { if (IrisRenderSystem.supportsSSBO()) { - this.shaderStorageBufferHolder = new ShaderStorageBufferHolder(programSet.getPackDirectives().getBufferObjects(), main.width, main.height); + this.shaderStorageBufferHolder = new ShaderStorageBufferHolder(pack.getBufferObjects(), main.width, main.height); this.shaderStorageBufferHolder.setupBuffers(); } else { diff --git a/common/src/main/java/net/irisshaders/iris/shaderpack/ShaderPack.java b/common/src/main/java/net/irisshaders/iris/shaderpack/ShaderPack.java index 559ae0e0d4..340d419850 100644 --- a/common/src/main/java/net/irisshaders/iris/shaderpack/ShaderPack.java +++ b/common/src/main/java/net/irisshaders/iris/shaderpack/ShaderPack.java @@ -5,12 +5,16 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.stream.JsonReader; +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.irisshaders.iris.Iris; import net.irisshaders.iris.api.v0.IrisApi; import net.irisshaders.iris.features.FeatureFlags; +import net.irisshaders.iris.gl.buffer.BuiltShaderStorageInfo; +import net.irisshaders.iris.gl.buffer.ShaderStorageInfo; import net.irisshaders.iris.gl.texture.TextureDefinition; import net.irisshaders.iris.gui.FeatureMissingErrorScreen; import net.irisshaders.iris.gui.screen.ShaderPackScreen; @@ -86,6 +90,7 @@ public class ShaderPack { private final ShaderProperties shaderProperties; private final List dimensionIds; private Map dimensionMap; + private Int2ObjectArrayMap bufferObjects; public ShaderPack(Path root, ImmutableList environmentDefines, boolean isZip) throws IOException, IllegalStateException { this(root, Collections.emptyMap(), environmentDefines, isZip); @@ -113,6 +118,7 @@ public ShaderPack(Path root, Map changedConfigs, ImmutableList(); + bufferObjects = new Int2ObjectArrayMap<>(); final boolean[] hasDimensionIds = {false}; // Thanks Java @@ -171,6 +177,35 @@ public ShaderPack(Path root, Map changedConfigs, ImmutableList new ShaderProperties(source, shaderPackOptions, finalEnvironmentDefines)) .orElseGet(ShaderProperties::empty); + for (Int2ObjectMap.Entry shaderStorageInfoEntry : shaderProperties.getBufferObjects().int2ObjectEntrySet()) { + ShaderStorageInfo info = shaderStorageInfoEntry.getValue(); + + if (info.name() == null) { + bufferObjects.put(shaderStorageInfoEntry.getIntKey(), new BuiltShaderStorageInfo(info.size(), info.relative(), info.scaleX(), info.scaleY(), null)); + continue; + } else { + String path = info.name(); + + try { + if (path.startsWith("/")) { + // NB: This does not guarantee the resulting path is in the shaderpack as a double slash could be used, + // this just fixes shaderpacks like Continuum 2.0.4 that use a leading slash in texture paths + path = path.substring(1); + } + + byte[] data = Files.readAllBytes(root.resolve(path)); + + if (data.length > info.size()) { + throw new IllegalStateException("Tried to load a shader storage file with no space in the buffer! Increase the buffer size."); + } + + bufferObjects.put(shaderStorageInfoEntry.getIntKey(), new BuiltShaderStorageInfo(info.size(), info.relative(), info.scaleX(), info.scaleY(), data)); + } catch (IOException e) { + Iris.logger.error("Shader storage buffer with index " + shaderStorageInfoEntry.getIntKey() + " and path " + path + " could not be read.", e); + } + } + } + activeFeatures = new HashSet<>(); for (int i = 0; i < shaderProperties.getRequiredFeatureFlags().size(); i++) { activeFeatures.add(FeatureFlags.getValue(shaderProperties.getRequiredFeatureFlags().get(i))); @@ -587,4 +622,8 @@ public OptionMenuContainer getMenuContainer() { public boolean hasFeature(FeatureFlags feature) { return activeFeatures.contains(feature); } + + public Int2ObjectArrayMap getBufferObjects() { + return bufferObjects; + } } diff --git a/common/src/main/java/net/irisshaders/iris/shaderpack/properties/PackDirectives.java b/common/src/main/java/net/irisshaders/iris/shaderpack/properties/PackDirectives.java index c169efb955..7976d3a5db 100644 --- a/common/src/main/java/net/irisshaders/iris/shaderpack/properties/PackDirectives.java +++ b/common/src/main/java/net/irisshaders/iris/shaderpack/properties/PackDirectives.java @@ -51,7 +51,6 @@ public class PackDirectives { private Object2ObjectMap> explicitFlips = new Object2ObjectOpenHashMap<>(); private Object2ObjectMap scaleOverrides = new Object2ObjectOpenHashMap<>(); private Object2ObjectMap, String> textureMap; - private Int2ObjectArrayMap bufferObjects; private Optional particleRenderingSettings; private PackDirectives(Set supportedRenderTargets, PackShadowDirectives packShadowDirectives) { @@ -63,7 +62,6 @@ private PackDirectives(Set supportedRenderTargets, PackShadowDirectives drynessHalfLife = 200.0f; eyeBrightnessHalfLife = 10.0f; centerDepthHalfLife = 1.0F; - bufferObjects = new Int2ObjectArrayMap<>(); renderTargetDirectives = new PackRenderTargetDirectives(supportedRenderTargets); shadowDirectives = packShadowDirectives; } @@ -94,7 +92,6 @@ public PackDirectives(Set supportedRenderTargets, ShaderProperties prop prepareBeforeShadow = properties.getPrepareBeforeShadow().orElse(false); particleRenderingSettings = properties.getParticleRenderingSettings(); textureMap = properties.getCustomTexturePatching(); - bufferObjects = properties.getBufferObjects(); } PackDirectives(Set supportedRenderTargets, PackDirectives directives) { @@ -112,7 +109,6 @@ public PackDirectives(Set supportedRenderTargets, ShaderProperties prop prepareBeforeShadow = directives.prepareBeforeShadow; particleRenderingSettings = directives.particleRenderingSettings; textureMap = directives.textureMap; - bufferObjects = directives.bufferObjects; } private static float clamp(float val, float lo, float hi) { @@ -239,10 +235,6 @@ public PackShadowDirectives getShadowDirectives() { return shadowDirectives; } - public Int2ObjectArrayMap getBufferObjects() { - return bufferObjects; - } - public boolean supportsColorCorrection() { return supportsColorCorrection; } diff --git a/common/src/main/java/net/irisshaders/iris/shaderpack/properties/ShaderProperties.java b/common/src/main/java/net/irisshaders/iris/shaderpack/properties/ShaderProperties.java index 7990e7477a..e8d0b58a6b 100644 --- a/common/src/main/java/net/irisshaders/iris/shaderpack/properties/ShaderProperties.java +++ b/common/src/main/java/net/irisshaders/iris/shaderpack/properties/ShaderProperties.java @@ -373,15 +373,21 @@ public ShaderProperties(String contents, ShaderPackOptions shaderPackOptions, It boolean isRelative; float scaleX, scaleY; String[] parts = value.split(" "); - if (parts.length == 1) { + if (parts.length <= 2) { try { trueIndex = Integer.parseInt(index); - trueSize = Long.parseLong(value); + trueSize = Long.parseLong(parts[0]); } catch (NumberFormatException e) { Iris.logger.error("Number format exception parsing SSBO index/size!", e); return; } + String name = null; + + if (parts.length > 1) { + name = parts[1]; + } + if (trueIndex > 8) { Iris.logger.fatal("SSBO's cannot use buffer numbers higher than 8, they're reserved!"); return; @@ -392,7 +398,7 @@ public ShaderProperties(String contents, ShaderPackOptions shaderPackOptions, It return; } - bufferObjects.put(trueIndex, new ShaderStorageInfo(trueSize, false, 0, 0)); + bufferObjects.put(trueIndex, new ShaderStorageInfo(trueSize, false, 0, 0, name)); } else { // Assume it's a long one try { @@ -416,7 +422,7 @@ public ShaderProperties(String contents, ShaderPackOptions shaderPackOptions, It return; } - bufferObjects.put(trueIndex, new ShaderStorageInfo(trueSize, isRelative, scaleX, scaleY)); + bufferObjects.put(trueIndex, new ShaderStorageInfo(trueSize, isRelative, scaleX, scaleY, null)); } });