diff --git a/buildscript/src/main/java/Buildscript.java b/buildscript/src/main/java/Buildscript.java index 3a13588024..48e430b671 100644 --- a/buildscript/src/main/java/Buildscript.java +++ b/buildscript/src/main/java/Buildscript.java @@ -100,6 +100,11 @@ public void getModDependencies(ModDependencyCollector d) { jij(d.addMaven(FabricMaven.URL, new MavenId(FabricMaven.GROUP_ID + ".fabric-api", "fabric-key-binding-api-v1", "1.0.12+54e5b2ec60"), ModDependencyFlag.COMPILE, ModDependencyFlag.RUNTIME)); jij(d.addMaven(Maven.MAVEN_CENTRAL, new MavenId("io.github.douira:glsl-transformer:2.0.0-pre13"), ModDependencyFlag.COMPILE, ModDependencyFlag.RUNTIME)); + jij(d.addMaven(Maven.MAVEN_CENTRAL, new MavenId("org.lwjgl:lwjgl-nuklear:3.3.3"), ModDependencyFlag.COMPILE, ModDependencyFlag.RUNTIME)); + jij(d.addMaven(Maven.MAVEN_CENTRAL, new MavenId("org.lwjgl:lwjgl-nuklear:3.3.3:natives-linux"), ModDependencyFlag.COMPILE, ModDependencyFlag.RUNTIME)); + jij(d.addMaven(Maven.MAVEN_CENTRAL, new MavenId("org.lwjgl:lwjgl-nuklear:3.3.3:natives-windows"), ModDependencyFlag.COMPILE, ModDependencyFlag.RUNTIME)); + jij(d.addMaven(Maven.MAVEN_CENTRAL, new MavenId("org.lwjgl:lwjgl-nuklear:3.3.3:natives-macos"), ModDependencyFlag.COMPILE, ModDependencyFlag.RUNTIME)); + jij(d.addMaven(Maven.MAVEN_CENTRAL, new MavenId("org.lwjgl:lwjgl-nuklear:3.3.3:natives-macos-arm64"), ModDependencyFlag.COMPILE, ModDependencyFlag.RUNTIME)); jij(d.addMaven(Maven.MAVEN_CENTRAL, new MavenId("org.antlr:antlr4-runtime:4.11.1"), ModDependencyFlag.COMPILE, ModDependencyFlag.RUNTIME)); d.addMaven("https://api.modrinth.com/maven", new MavenId("maven.modrinth", "distanthorizons", "2.0.0-a-1.18.2"), ModDependencyFlag.COMPILE); diff --git a/src/main/java/net/coderbot/iris/Iris.java b/src/main/java/net/coderbot/iris/Iris.java index 5ee77b93bc..ae57a98ee6 100644 --- a/src/main/java/net/coderbot/iris/Iris.java +++ b/src/main/java/net/coderbot/iris/Iris.java @@ -6,6 +6,7 @@ import net.coderbot.iris.compat.sodium.SodiumVersionCheck; import net.coderbot.iris.config.IrisConfig; import net.coderbot.iris.gl.GLDebug; +import net.coderbot.iris.gl.debug.TimerQuerier; import net.coderbot.iris.gl.shader.StandardMacros; import net.coderbot.iris.gui.screen.ShaderPackScreen; import net.coderbot.iris.pipeline.FixedFunctionWorldRenderingPipeline; @@ -182,6 +183,7 @@ public static void onRenderSystemInit() { return; } + TimerQuerier.initRenderer(); PBRTextureManager.INSTANCE.init(); // Only load the shader pack when we can access OpenGL diff --git a/src/main/java/net/coderbot/iris/gl/debug/TimerQuerier.java b/src/main/java/net/coderbot/iris/gl/debug/TimerQuerier.java new file mode 100644 index 0000000000..6050489ec8 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/debug/TimerQuerier.java @@ -0,0 +1,66 @@ +package net.coderbot.iris.gl.debug; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArraySet; +import net.coderbot.iris.Iris; +import net.minecraft.client.gui.screens.Screen; +import org.lwjgl.opengl.GL32C; + +import java.util.Set; + +public class TimerQuerier { + private static final Object2ObjectMap[] queries = new Object2ObjectOpenHashMap[5]; + private static int frameId = 0; + + static { + for (int i = 0; i < 5; i++) { + queries[i] = new Object2ObjectOpenHashMap<>(); + } + } + + private static final Set unusedQueries = new ObjectArraySet<>(); + + public static void initRenderer() { + int[] queries = new int[100]; + GL32C.glGenQueries(queries); + for (int i = 0; i < 100; i++) { + unusedQueries.add(new TimerQuery(queries[i])); + } + } + + public static TimerQuery giveQuery() { + if (unusedQueries.isEmpty()) { + Iris.logger.warn("Congrats, you overran the query system. Adding a new query. (If this stops after a bit, it's not an error, you just have a lot going on)"); + unusedQueries.add(new TimerQuery(GL32C.glGenQueries())); + } + TimerQuery query = unusedQueries.iterator().next(); + unusedQueries.remove(query); + return query; + } + + + public static void advanceFrameAndReset() { + // Advance the frame ID + frameId = (frameId + 1) % 5; + + int frameToGet = frameId - 4; + if (frameToGet < 0) frameToGet += 5; + + queries[frameToGet].forEach((name, query) -> { + if (Screen.hasControlDown()) { + Iris.logger.warn("Query result for " + name + " was " + ((float) query.returnResult() / 1000000f) + "ms"); + } + query.stopUsing(); + unusedQueries.add(query); + }); + + queries[frameToGet].clear(); + } + + public static void monitorQuery(String name, TimerQuery query) { + queries[frameId].put(name, query); + } +} diff --git a/src/main/java/net/coderbot/iris/gl/debug/TimerQuery.java b/src/main/java/net/coderbot/iris/gl/debug/TimerQuery.java new file mode 100644 index 0000000000..d7f10b0d06 --- /dev/null +++ b/src/main/java/net/coderbot/iris/gl/debug/TimerQuery.java @@ -0,0 +1,57 @@ +package net.coderbot.iris.gl.debug; + +import net.coderbot.iris.Iris; +import org.jetbrains.annotations.ApiStatus; +import org.lwjgl.opengl.GL42C; + +public class TimerQuery { + private final int query; + private boolean inUse = false; + + private static boolean isInQuery = false; + private static String name; + + public TimerQuery(int query) { + this.query = query; + } + + public boolean isInUse() { + return inUse; + } + + public void startQuery(String name) { + if (inUse || isInQuery) { + throw new IllegalStateException("Query " + name + " already in use"); + } + TimerQuery.name = name; + + inUse = true; + isInQuery = true; + + GL42C.glBeginQuery(GL42C.GL_TIME_ELAPSED, query); + } + + public void startMonitoring() { + if (!inUse) { + throw new IllegalStateException("Not in use, giving up"); + } + + isInQuery = false; + GL42C.glEndQuery(GL42C.GL_TIME_ELAPSED); + + TimerQuerier.monitorQuery(name, this); + } + + @ApiStatus.Internal + public int returnResult() { + return GL42C.glGetQueryObjecti(query, GL42C.GL_QUERY_RESULT); + } + + protected void stopUsing() { + if (!inUse) { + throw new IllegalStateException("Query not in use"); + } + + inUse = false; + } +} diff --git a/src/main/java/net/coderbot/iris/mixin/MixinLevelRenderer.java b/src/main/java/net/coderbot/iris/mixin/MixinLevelRenderer.java index 1b564909ce..4434df7b50 100644 --- a/src/main/java/net/coderbot/iris/mixin/MixinLevelRenderer.java +++ b/src/main/java/net/coderbot/iris/mixin/MixinLevelRenderer.java @@ -7,12 +7,15 @@ import net.coderbot.iris.Iris; import net.coderbot.iris.fantastic.WrappingMultiBufferSource; import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.debug.TimerQuerier; +import net.coderbot.iris.gl.debug.TimerQuery; import net.coderbot.iris.gl.program.Program; import net.coderbot.iris.layer.IsOutlineRenderStateShard; import net.coderbot.iris.layer.OuterWrappedRenderType; import net.coderbot.iris.pipeline.HandRenderer; import net.coderbot.iris.pipeline.WorldRenderingPhase; import net.coderbot.iris.pipeline.WorldRenderingPipeline; +import net.coderbot.iris.shadows.ShadowRenderingState; import net.coderbot.iris.shadows.frustum.fallback.NonCullingFrustum; import net.coderbot.iris.uniforms.CapturedRenderingState; import net.coderbot.iris.uniforms.IrisTimeUniforms; @@ -82,6 +85,7 @@ public class MixinLevelRenderer { CapturedRenderingState.INSTANCE.setTickDelta(tickDelta); SystemTimeUniforms.COUNTER.beginFrame(); SystemTimeUniforms.TIMER.beginFrame(startTime); + TimerQuerier.advanceFrameAndReset(); pipeline = Iris.getPipelineManager().preparePipeline(Iris.getCurrentDimension()); @@ -200,15 +204,25 @@ public class MixinLevelRenderer { pipeline.setPhase(WorldRenderingPhase.NONE); } + @Unique + TimerQuery query; @Inject(method = "renderChunkLayer", at = @At("HEAD")) private void iris$beginTerrainLayer(RenderType renderType, PoseStack poseStack, double d, double e, double f, Matrix4f projectionMatrix, CallbackInfo ci) { pipeline.setPhase(WorldRenderingPhase.fromTerrainRenderType(renderType)); + + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) return; + query = TimerQuerier.giveQuery(); + query.startQuery(WorldRenderingPhase.fromTerrainRenderType(renderType).name()); } @Inject(method = "renderChunkLayer", at = @At("RETURN")) private void iris$endTerrainLayer(RenderType renderType, PoseStack poseStack, double d, double e, double f, Matrix4f projectionMatrix, CallbackInfo ci) { pipeline.setPhase(WorldRenderingPhase.NONE); + if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) return; + + query.startMonitoring(); + query = null; } @Inject(method = "renderLevel", at = @At(value = "INVOKE", target = RENDER_WEATHER)) diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 45da0e6d1a..4c009cf577 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -12,6 +12,8 @@ import net.coderbot.batchedentityrendering.impl.RenderBuffersExt; import net.coderbot.iris.Iris; import net.coderbot.iris.gl.IrisRenderSystem; +import net.coderbot.iris.gl.debug.TimerQuerier; +import net.coderbot.iris.gl.debug.TimerQuery; import net.coderbot.iris.gl.program.ComputeProgram; import net.coderbot.iris.gl.texture.DepthCopyStrategy; import net.coderbot.iris.gui.option.IrisVideoSettings; @@ -360,6 +362,9 @@ public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCame return; } + TimerQuery query = TimerQuerier.giveQuery(); + query.startQuery("shadowPass"); + Minecraft client = Minecraft.getInstance(); levelRenderer.getLevel().getProfiler().popPush("shadows"); @@ -555,6 +560,7 @@ public void renderShadows(LevelRendererAccessor levelRenderer, Camera playerCame if (levelRenderer instanceof CullingDataCache) { ((CullingDataCache) levelRenderer).restoreState(); } + query.startMonitoring(); compositeRenderer.renderAll(); diff --git a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java index 9b3c67b432..ba2cbd0bd3 100644 --- a/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java +++ b/src/main/java/net/coderbot/iris/postprocess/CompositeRenderer.java @@ -17,6 +17,8 @@ import net.coderbot.iris.features.FeatureFlags; import net.coderbot.iris.gl.IrisRenderSystem; import net.coderbot.iris.gl.blending.BlendModeOverride; +import net.coderbot.iris.gl.debug.TimerQuerier; +import net.coderbot.iris.gl.debug.TimerQuery; import net.coderbot.iris.gl.framebuffer.GlFramebuffer; import net.coderbot.iris.gl.image.GlImage; import net.coderbot.iris.gl.program.ComputeProgram; @@ -109,8 +111,9 @@ public CompositeRenderer(WorldRenderingPipeline pipeline, PackDirectives packDir ImmutableSet flippedAtLeastOnceSnapshot = flippedAtLeastOnce.build(); if (source == null || !source.isValid()) { - if (computes[i] != null) { + if (computes[i] != null && computes[i][0] != null) { ComputeOnlyPass pass = new ComputeOnlyPass(); + pass.name = computes[i][0].getName(); pass.computes = createComputes(computes[i], flipped, flippedAtLeastOnceSnapshot, shadowTargetsSupplier); passes.add(pass); } @@ -121,6 +124,7 @@ public CompositeRenderer(WorldRenderingPipeline pipeline, PackDirectives packDir ProgramDirectives directives = source.getDirectives(); pass.program = createProgram(source, flipped, flippedAtLeastOnceSnapshot, shadowTargetsSupplier); + pass.name = source.getName(); pass.blendModeOverride = source.getDirectives().getBlendModeOverride().orElse(null); pass.computes = createComputes(computes[i], flipped, flippedAtLeastOnceSnapshot, shadowTargetsSupplier); int[] drawBuffers = directives.getDrawBuffers(); @@ -205,6 +209,7 @@ private static class Pass { int viewWidth; int viewHeight; Program program; + String name; BlendModeOverride blendModeOverride; ComputeProgram[] computes; GlFramebuffer framebuffer; @@ -241,6 +246,8 @@ public void renderAll() { com.mojang.blaze3d.pipeline.RenderTarget main = Minecraft.getInstance().getMainRenderTarget(); for (Pass renderPass : passes) { + TimerQuery query = TimerQuerier.giveQuery(); + query.startQuery(renderPass.name); boolean ranCompute = false; for (ComputeProgram computeProgram : renderPass.computes) { if (computeProgram != null) { @@ -258,6 +265,7 @@ public void renderAll() { Program.unbind(); if (renderPass instanceof ComputeOnlyPass) { + query.startMonitoring(); continue; } @@ -287,6 +295,7 @@ public void renderAll() { FullScreenQuadRenderer.INSTANCE.renderQuad(); BlendModeOverride.restore(); + query.startMonitoring(); } FullScreenQuadRenderer.INSTANCE.end(); diff --git a/src/main/java/net/coderbot/iris/shadows/ShadowCompositeRenderer.java b/src/main/java/net/coderbot/iris/shadows/ShadowCompositeRenderer.java index 7e4a096d95..2416f307e1 100644 --- a/src/main/java/net/coderbot/iris/shadows/ShadowCompositeRenderer.java +++ b/src/main/java/net/coderbot/iris/shadows/ShadowCompositeRenderer.java @@ -7,6 +7,8 @@ import com.mojang.blaze3d.systems.RenderSystem; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.coderbot.iris.Iris; +import net.coderbot.iris.gl.debug.TimerQuerier; +import net.coderbot.iris.gl.debug.TimerQuery; import net.coderbot.iris.gl.image.GlImage; import net.coderbot.iris.features.FeatureFlags; import net.coderbot.iris.gl.IrisRenderSystem;