From 48d032e65479cda341ba3c2b24017e1a2ebb71eb Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Mon, 26 Jan 2026 21:08:09 -0800 Subject: [PATCH] Tweaks (#1329) --- dependencies.gradle | 2 +- .../gtnewhorizons/angelica/glsm/GLDebug.java | 100 +++++++----------- src/main/java/net/coderbot/iris/Iris.java | 3 + .../net/coderbot/iris/gl/shader/GlShader.java | 2 +- .../coderbot/iris/gl/texture/PixelType.java | 2 +- .../DeferredWorldRenderingPipeline.java | 9 ++ .../pipeline/transform/ShaderTransformer.java | 75 ++++++++++++- .../coderbot/iris/shaderpack/ShaderPack.java | 2 +- 8 files changed, 126 insertions(+), 69 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 82f4abb85..4952acc6c 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -71,7 +71,7 @@ dependencies { // Iris Shaders compileOnly('org.jetbrains:annotations:26.0.2') - api("com.github.GTNewHorizons:GTNHLib:0.9.0:dev") + api("com.github.GTNewHorizons:GTNHLib:0.9.6:dev") shadowImplementation("org.anarres:jcpp:1.4.14") // Apache 2.0 shadowImplementation("org.taumc:glsl-transformation-lib:0.2.0-25.g3a943bb") { exclude module: "antlr4" // we only want to shadow the runtime module diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/GLDebug.java b/src/main/java/com/gtnewhorizons/angelica/glsm/GLDebug.java index f7be55eb2..18589093a 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/GLDebug.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/GLDebug.java @@ -19,9 +19,6 @@ import org.lwjgl.opengl.GL43; import org.lwjgl.opengl.KHRDebug; import org.lwjgl.opengl.KHRDebugCallback; -import java.io.PrintStream; -import java.util.function.Consumer; - import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER; import static org.lwjgl.opengl.ARBDebugOutput.glDebugMessageCallbackARB; @@ -35,20 +32,9 @@ public final class GLDebug { LOGGER.warn("setupDebugMessageCallback called from non-main thread!"); return 0; } - return setupDebugMessageCallback(System.err); + return setupDebugMessageCallbackImpl(); } - private static void trace(Consumer output) { - /* - * We can not just use a fixed stacktrace element offset, because some methods - * are intercepted and some are not. So, check the package name. - */ - StackTraceElement[] elems = filterStackTrace(new Throwable(), 4).getStackTrace(); - for (StackTraceElement ste : elems) { - output.accept(ste.toString()); - } - } - public static Throwable filterStackTrace(Throwable throwable, int offset) { StackTraceElement[] elems = throwable.getStackTrace(); StackTraceElement[] filtered = new StackTraceElement[elems.length]; @@ -66,36 +52,48 @@ public final class GLDebug { return throwable; } - public static void printTrace(PrintStream stream) { - trace(new Consumer() { - boolean first = true; + private static String buildStackTrace() { + StackTraceElement[] elems = filterStackTrace(new Throwable(), 4).getStackTrace(); + StringBuilder sb = new StringBuilder(); + for (StackTraceElement elem : elems) { + sb.append("\n\t").append(elem.toString()); + } + return sb.toString(); + } - public void accept(String str) { - if (first) { - printDetail(stream, "Stacktrace", str); - first = false; - } else { - printDetailLine(stream, "Stacktrace", str); - } - } - }); + private static void logDebugMessage(int id, String source, String type, String severity, String message) { + String fullMessage = String.format("[GL] %s %s (0x%X) from %s: %s%s", severity, type, id, source, message, buildStackTrace()); + + if ("HIGH".equals(severity)) { + LOGGER.error(fullMessage); + } else if ("MEDIUM".equals(severity)) { + LOGGER.warn(fullMessage); + } else { + LOGGER.info(fullMessage); + } + } + + private static void logDebugMessageAMD(int id, String category, String severity, String message) { + String fullMessage = String.format("[GL] %s %s (0x%X): %s%s", severity, category, id, message, buildStackTrace()); + + if ("HIGH".equals(severity)) { + LOGGER.error(fullMessage); + } else if ("MEDIUM".equals(severity)) { + LOGGER.warn(fullMessage); + } else { + LOGGER.info(fullMessage); + } } /** * Sets up debug callbacks * @return 0 for failure, 1 for success, 2 for restart required. */ - public static int setupDebugMessageCallback(PrintStream stream) { + private static int setupDebugMessageCallbackImpl() { if (GLStateManager.capabilities.OpenGL43 || GLStateManager.capabilities.GL_KHR_debug) { LOGGER.info("[GL] Using OpenGL 4.3 for error logging."); - KHRDebugCallback proc = new KHRDebugCallback((source, type, id, severity, message) -> { - stream.println("[LWJGL] OpenGL debug message"); - printDetail(stream, "ID", String.format("0x%X", id)); - printDetail(stream, "Source", getDebugSource(source)); - printDetail(stream, "Type", getDebugType(type)); - printDetail(stream, "Severity", getDebugSeverity(severity)); - printDetail(stream, "Message", message); - printTrace(stream); + final KHRDebugCallback proc = new KHRDebugCallback((source, type, id, severity, message) -> { + logDebugMessage(id, getDebugSource(source), getDebugType(type), getDebugSeverity(severity), message); }); GL43.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); GL43.glDebugMessageControl(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); @@ -114,14 +112,8 @@ public final class GLDebug { return 1; } else if (GLStateManager.capabilities.GL_ARB_debug_output) { LOGGER.info("[GL] Using ARB_debug_output for error logging."); - ARBDebugOutputCallback proc = new ARBDebugOutputCallback((source, type, id, severity, message) -> { - stream.println("[LWJGL] ARB_debug_output message"); - printDetail(stream, "ID", String.format("0x%X", id)); - printDetail(stream, "Source", getSourceARB(source)); - printDetail(stream, "Type", getTypeARB(type)); - printDetail(stream, "Severity", getSeverityARB(severity)); - printDetail(stream, "Message", message); - printTrace(stream); + final ARBDebugOutputCallback proc = new ARBDebugOutputCallback((source, type, id, severity, message) -> { + logDebugMessage(id, getSourceARB(source), getTypeARB(type), getSeverityARB(severity), message); }); ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); ARBDebugOutput.glDebugMessageControlARB(GL11.GL_DONT_CARE, GL11.GL_DONT_CARE, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); @@ -134,13 +126,8 @@ public final class GLDebug { return 1; } else if (GLStateManager.capabilities.GL_AMD_debug_output) { LOGGER.info("[GL] Using AMD_debug_output for error logging."); - AMDDebugOutputCallback proc = new AMDDebugOutputCallback((id, category, severity, message) -> { - stream.println("[LWJGL] AMD_debug_output message"); - printDetail(stream, "ID", String.format("0x%X", id)); - printDetail(stream, "Category", getCategoryAMD(category)); - printDetail(stream, "Severity", getSeverityAMD(severity)); - printDetail(stream, "Message", message); - printTrace(stream); + final AMDDebugOutputCallback proc = new AMDDebugOutputCallback((id, category, severity, message) -> { + logDebugMessageAMD(id, getCategoryAMD(category), getSeverityAMD(severity), message); }); AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_HIGH, null, true); AMDDebugOutput.glDebugMessageEnableAMD(0, GL43.GL_DEBUG_SEVERITY_MEDIUM, null, false); @@ -176,17 +163,6 @@ public final class GLDebug { } } - private static void printDetail(PrintStream stream, String type, String message) { - stream.printf("\t%s: %s\n", type, message); - } - - private static void printDetailLine(PrintStream stream, String type, String message) { - stream.append(" "); - for (int i = 0; i < type.length(); i++) { - stream.append(" "); - } - stream.append(message).append("\n"); - } private static String getDebugSource(int source) { return switch (source) { diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index fcb5600d3..2131738c5 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -390,6 +390,9 @@ public class Iris { // Warm up the threadpool so shader transformations are faster when we need them ShaderTransformExecutor.warmup(); + // Initialize version hoisting pattern based on GL capabilities + ShaderTransformer.init(); + PBRTextureManager.INSTANCE.init(); // Only load the shader pack when we can access OpenGL diff --git a/src/main/java/net/coderbot/iris/gl/shader/GlShader.java b/src/main/java/net/coderbot/iris/gl/shader/GlShader.java index 52f914dc1..1cde5ccc9 100644 --- a/src/main/java/net/coderbot/iris/gl/shader/GlShader.java +++ b/src/main/java/net/coderbot/iris/gl/shader/GlShader.java @@ -17,7 +17,7 @@ import java.util.Locale; * A compiled OpenGL shader object. */ public class GlShader extends GlResource { - private static final Logger LOGGER = LogManager.getLogger(GlShader.class); + private static final Logger LOGGER = LogManager.getLogger("GlShader"); private final String name; diff --git a/src/main/java/net/coderbot/iris/gl/texture/PixelType.java b/src/main/java/net/coderbot/iris/gl/texture/PixelType.java index 7457b2faf..fb65c89e6 100644 --- a/src/main/java/net/coderbot/iris/gl/texture/PixelType.java +++ b/src/main/java/net/coderbot/iris/gl/texture/PixelType.java @@ -23,7 +23,7 @@ public enum PixelType { UNSIGNED_SHORT_4_4_4_4_REV(GL12.GL_UNSIGNED_SHORT_4_4_4_4_REV, GlVersion.GL_12), UNSIGNED_SHORT_5_5_5_1(GL12.GL_UNSIGNED_SHORT_5_5_5_1, GlVersion.GL_12), UNSIGNED_SHORT_1_5_5_5_REV(GL12.GL_UNSIGNED_SHORT_1_5_5_5_REV, GlVersion.GL_12), - UNSIGNED_INT(GL11.GL_UNSIGNED_BYTE, GlVersion.GL_11), + UNSIGNED_INT(GL11.GL_UNSIGNED_INT, GlVersion.GL_11), UNSIGNED_INT_8_8_8_8(GL12.GL_UNSIGNED_INT_8_8_8_8, GlVersion.GL_12), UNSIGNED_INT_8_8_8_8_REV(GL12.GL_UNSIGNED_INT_8_8_8_8_REV, GlVersion.GL_12), UNSIGNED_INT_10_10_10_2(GL12.GL_UNSIGNED_INT_10_10_10_2, GlVersion.GL_12), diff --git a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java index 5bda9be12..ec9f96004 100644 --- a/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java +++ b/src/main/java/net/coderbot/iris/pipeline/DeferredWorldRenderingPipeline.java @@ -754,6 +754,10 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture()); + IrisSamplers.addCustomImages(customTextureSamplerInterceptor, customImages); + IrisSamplers.addCustomTextures(customTextureSamplerInterceptor, customTextureManager.getIrisCustomTextures()); + IrisImages.addCustomImages(builder, customImages); + if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { if (!shadow) { shadowTargetsSupplier.get(); @@ -1130,6 +1134,9 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture()); + IrisSamplers.addCustomImages(customTextureSamplerInterceptor, customImages); + IrisSamplers.addCustomTextures(customTextureSamplerInterceptor, customTextureManager.getIrisCustomTextures()); + if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) { if (shadowRenderTargets != null) { IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowRenderTargets, null, true); @@ -1137,6 +1144,8 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R } } + IrisImages.addCustomImages(builder, customImages); + programs[i] = builder.buildCompute(); this.customUniforms.mapholderToPass(builder, programs[i]); diff --git a/src/main/java/net/coderbot/iris/pipeline/transform/ShaderTransformer.java b/src/main/java/net/coderbot/iris/pipeline/transform/ShaderTransformer.java index 2e3dd8de1..cd76d57dc 100644 --- a/src/main/java/net/coderbot/iris/pipeline/transform/ShaderTransformer.java +++ b/src/main/java/net/coderbot/iris/pipeline/transform/ShaderTransformer.java @@ -2,6 +2,8 @@ package net.coderbot.iris.pipeline.transform; import com.google.common.base.Stopwatch; import com.gtnewhorizons.angelica.rendering.celeritas.iris.IrisExtendedChunkVertexType; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import net.coderbot.iris.Iris; import net.coderbot.iris.gl.shader.ShaderType; @@ -15,13 +17,15 @@ import org.taumc.glsl.ShaderParser; import org.taumc.glsl.Transformer; import org.taumc.glsl.grammar.GLSLLexer; +import com.gtnewhorizons.angelica.glsm.RenderSystem; + import java.util.ArrayList; -import java.util.Arrays; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.BooleanSupplier; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -58,7 +62,63 @@ public class ShaderTransformer { fullReservedWords.add("texture"); // sample was added as a keyword in GLSL 400, many shaders use it - versionedReservedWords.put(400, Arrays.asList("sample")); + versionedReservedWords.put(400, List.of("sample")); + } + + private record VersionRequirement(String keyword, int minVersion, BooleanSupplier supported) {} + + // Sorted descending by minVersion for early exit in getRequiredVersion + private static final VersionRequirement[] VERSION_REQUIREMENTS = { + new VersionRequirement("std430", 430, RenderSystem::supportsSSBO), + new VersionRequirement("iimage", 420, RenderSystem::supportsImageLoadStore), + new VersionRequirement("uimage", 420, RenderSystem::supportsImageLoadStore), + new VersionRequirement("imageLoad", 420, RenderSystem::supportsImageLoadStore), + new VersionRequirement("imageStore", 420, RenderSystem::supportsImageLoadStore) + }; + + private static Pattern hoistPattern; + private static Object2IntMap keywordToVersion; + private static int maxSupportedHoistVersion; + + public static void init() { + final StringBuilder patternBuilder = new StringBuilder(); + final Object2IntOpenHashMap versionMap = new Object2IntOpenHashMap<>(); + int maxVersion = 0; + + for (VersionRequirement req : VERSION_REQUIREMENTS) { + if (req.supported.getAsBoolean()) { + if (!patternBuilder.isEmpty()) patternBuilder.append('|'); + + patternBuilder.append(Pattern.quote(req.keyword)); + versionMap.put(req.keyword, req.minVersion); + maxVersion = Math.max(maxVersion, req.minVersion); + } + } + + if (!patternBuilder.isEmpty()) { + hoistPattern = Pattern.compile(patternBuilder.toString()); + keywordToVersion = versionMap; + } + maxSupportedHoistVersion = maxVersion; + + Iris.logger.info("Shader version hoisting: {} feature(s) GLSL {}", versionMap.size(), maxVersion > 0 ? maxVersion : "N/A"); + } + + private static int getRequiredVersion(String shaderSource, int declaredVersion) { + if (hoistPattern == null || declaredVersion >= maxSupportedHoistVersion) { + return declaredVersion; + } + + final Matcher m = hoistPattern.matcher(shaderSource); + int required = declaredVersion; + while (m.find()) { + final int ver = keywordToVersion.getInt(m.group()); + if (ver > required) { + required = ver; + if (required >= maxSupportedHoistVersion) break; + } + } + return required; } private static final class TransformKey

{ @@ -164,10 +224,19 @@ public class ShaderTransformer { String profile = ""; int versionInt = Integer.parseInt(versionString); + + // Check if shader uses features requiring a higher GLSL version + int requiredVersion = getRequiredVersion(input, versionInt); + if (requiredVersion > versionInt) { + Iris.logger.debug("Shader requires GLSL {} for detected features, hoisting from {}", requiredVersion, versionInt); + versionInt = requiredVersion; + versionString = String.valueOf(versionInt); + } + if (versionInt >= 150) { profile = matcher.group(2); if (profile == null) { - profile = "core"; + profile = "compatibility"; } } diff --git a/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java b/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java index 5456c2c18..5a337b38f 100644 --- a/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java +++ b/src/main/java/net/coderbot/iris/shaderpack/ShaderPack.java @@ -265,7 +265,7 @@ public class ShaderPack { IncludeProcessor includeProcessor = new IncludeProcessor(graph); // Set up our source provider for creating ProgramSets - Iterable finalEnvironmentDefines1 = environmentDefines; + Iterable finalEnvironmentDefines1 = finalEnvironmentDefines; this.sourceProvider = (path) -> { String pathString = path.getPathString(); // Removes the first "/" in the path if present, and the file