diff --git a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/CaptureGate.java b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/CaptureGate.java index 6472f71e7..9e8b4141b 100644 --- a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/CaptureGate.java +++ b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/CaptureGate.java @@ -26,12 +26,20 @@ public final class CaptureGate { public static final boolean TOOL_ATTACHED = detectCaptureTool(); public static boolean markersThisFrame = true; public static boolean tracyConnected; + private static boolean toolAttached = TOOL_ATTACHED; private CaptureGate() {} public static void refresh() { tracyConnected = Tracy.isConnected(); - markersThisFrame = gateValue(FORCED, TOOL_ATTACHED, tracyConnected); + markersThisFrame = gateValue(FORCED, toolAttached, tracyConnected); + } + + static void probeGlTool() { + if (RenderSystem.hasExtension("GL_EXT_debug_tool")) { + toolAttached = true; + LOGGER.info("Capture tool detected via GL_EXT_debug_tool; instrumentation enabled"); + } } static boolean gateValue(boolean forced, boolean toolAttached, boolean tracyConnected) { @@ -39,7 +47,7 @@ public final class CaptureGate { } public static boolean enabledAtStartup() { - return FORCED || TOOL_ATTACHED; + return FORCED || toolAttached; } private static boolean detectCaptureTool() { diff --git a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java index 6c4be63a6..a283aa7c3 100644 --- a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java +++ b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/GLStateManager.java @@ -458,6 +458,7 @@ public class GLStateManager { static void init(Runnable initCallback) { final GLContextState glCtx = ctx(); RenderSystem.initRenderer(); + CaptureGate.probeGlTool(); GLSMFramebuffer.queryDefaultDrawBuffer(); diff --git a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/RenderSystem.java b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/RenderSystem.java index b433d1d54..b103b60db 100644 --- a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/RenderSystem.java +++ b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/RenderSystem.java @@ -443,7 +443,7 @@ public class RenderSystem { return clipDistanceEmulated; } - private static boolean hasExtension(String name) { + static boolean hasExtension(String name) { final int count = GLSMQueries.glGetInteger(GL30.GL_NUM_EXTENSIONS); for (int i = 0; i < count; i++) { if (name.equals(GLSMQueries.glGetStringi(GL11.GL_EXTENSIONS, i))) return true; diff --git a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/hooks/FrameHooks.java b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/hooks/FrameHooks.java index 3266b7a20..21bf56774 100644 --- a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/hooks/FrameHooks.java +++ b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/hooks/FrameHooks.java @@ -6,6 +6,7 @@ import com.gtnewhorizons.angelica.glsm.GLDebug; import com.gtnewhorizons.angelica.glsm.GLSMTextureLifetime; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.glsm.backend.BackendManager; +import com.gtnewhorizons.angelica.glsm.profiling.Tracy; import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND; @@ -16,11 +17,18 @@ public final class FrameHooks { private static boolean gameLoopStarted; private static long frameCounter; private static boolean frameGroupActive; + private static String framePrefix = "frame:"; + private static String buildLabel = ""; public static void bootstrapFirstFrame() { DisplayListManager.abortIfLeaked(); if (!gameLoopStarted) { gameLoopStarted = true; + final GLSMInitConfig config = GLStateManager.getInitConfig(); + if (config != null && !config.getBuildLabel().isEmpty()) { + buildLabel = config.getBuildLabel(); + framePrefix = buildLabel + " frame:"; + } RENDER_BACKEND.onFrameBegin(); pushFrameGroup(); } @@ -48,8 +56,10 @@ public final class FrameHooks { } private static void pushFrameGroup() { + final boolean wasConnected = CaptureGate.tracyConnected; CaptureGate.refresh(); - GLDebug.pushGroup("frame:", frameCounter); + if (CaptureGate.tracyConnected && !wasConnected && !buildLabel.isEmpty()) Tracy.message(buildLabel); + GLDebug.pushGroup(framePrefix, frameCounter); frameGroupActive = true; } diff --git a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/hooks/GLSMInitConfig.java b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/hooks/GLSMInitConfig.java index c4cd7986a..9dee15886 100644 --- a/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/hooks/GLSMInitConfig.java +++ b/glsm/src/main/java/com/gtnewhorizons/angelica/glsm/hooks/GLSMInitConfig.java @@ -17,6 +17,7 @@ public final class GLSMInitConfig { @Getter private final Runnable postInitCallback; private final boolean dsaEnabled; @Getter private final boolean noErrorChecks; + @Getter private final String buildLabel; private GLSMInitConfig(Builder builder) { this.lwjglDebug = builder.lwjglDebug; @@ -27,6 +28,7 @@ public final class GLSMInitConfig { this.displayHeight = builder.displayHeight; this.postInitCallback = builder.postInitCallback; this.dsaEnabled = builder.dsaEnabled; + this.buildLabel = builder.buildLabel; } public boolean isDSAEnabled() { @@ -46,6 +48,7 @@ public final class GLSMInitConfig { private Runnable postInitCallback = null; private boolean dsaEnabled = true; private boolean noErrorChecks; + private String buildLabel = ""; private Builder() {} @@ -85,6 +88,11 @@ public final class GLSMInitConfig { return this; } + public Builder buildLabel(String buildLabel) { + this.buildLabel = buildLabel == null ? "" : buildLabel; + return this; + } + public GLSMInitConfig build() { return new GLSMInitConfig(this); } diff --git a/gradle/angelica-run-common.gradle.kts b/gradle/angelica-run-common.gradle.kts index 6ed70f691..3d491d402 100644 --- a/gradle/angelica-run-common.gradle.kts +++ b/gradle/angelica-run-common.gradle.kts @@ -36,6 +36,7 @@ tasks.withType().matching { it.name.startsWith("runClient") }.configur for (name in forwardedRunProperties) { jvmArgs("-D$name=${System.getProperty(name)}") } + jvmArgs("-Dangelica.buildVersion=${project.version}") } val isMacOs = org.gradle.internal.os.OperatingSystem.current().isMacOsX diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/spark/SparkKnownSources.java b/src/main/java/com/gtnewhorizons/angelica/compat/spark/SparkKnownSources.java new file mode 100644 index 000000000..534359e0b --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/spark/SparkKnownSources.java @@ -0,0 +1,77 @@ +package com.gtnewhorizons.angelica.compat.spark; + +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.ModContainer; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.io.InputStream; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public final class SparkKnownSources { + private static final Logger LOGGER = LogManager.getLogger("Angelica"); + private static final String PLUGIN = "me/lucko/spark/forge/plugin/Forge1710SparkPlugin"; + private static final String SOURCE_METADATA = "me.lucko.spark.common.sampler.source.SourceMetadata"; + + private static MethodHandle constructor; + private static boolean failed; + + private SparkKnownSources() {} + + public static boolean mixinApplies() { + try (InputStream stream = SparkKnownSources.class.getResourceAsStream("/" + PLUGIN + ".class")) { + if (stream == null) { + return false; + } + final boolean[] declared = new boolean[1]; + new ClassReader(stream).accept(new ClassVisitor(Opcodes.ASM5) { + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if ("getKnownSources".equals(name) && "()Ljava/util/Collection;".equals(desc)) { + declared[0] = true; + } + return null; + } + }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + if (declared[0]) { + LOGGER.info("spark already reports mod sources; skipping"); + return false; + } + return true; + } catch (Throwable t) { + LOGGER.warn("Could not inspect spark plugin class; not adding mod sources", t); + return false; + } + } + + public static Collection gather(ClassLoader loader) { + if (failed) { + return Collections.emptyList(); + } + try { + if (constructor == null) constructor = MethodHandles.publicLookup().findConstructor(Class.forName(SOURCE_METADATA, false, loader), + MethodType.methodType(void.class, String.class, String.class, String.class, String.class)); + final List mods = Loader.instance().getActiveModList(); + final List sources = new ArrayList<>(mods.size()); + for (int i = 0; i < mods.size(); i++) { + final ModContainer mod = mods.get(i); + sources.add(constructor.invoke(mod.getModId(), mod.getVersion(), (String) null, (String) null)); + } + return sources; + } catch (Throwable t) { + failed = true; + LOGGER.warn("Could not build spark mod sources; profiles will omit mod versions", t); + return Collections.emptyList(); + } + } +} diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java index 9c5061070..27c43ce98 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java @@ -3,6 +3,7 @@ package com.gtnewhorizons.angelica.mixins; import com.gtnewhorizon.gtnhmixins.builders.IMixins; import com.gtnewhorizon.gtnhmixins.builders.MixinBuilder; import com.gtnewhorizons.angelica.api.BlockLightProvider; +import com.gtnewhorizons.angelica.compat.spark.SparkKnownSources; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.config.CompatConfig; import com.gtnewhorizons.angelica.config.SystemProperties; @@ -641,6 +642,13 @@ public enum Mixins implements IMixins { ) ), + SPARK_MOD_SOURCES(new MixinBuilder("Mod versions in spark 1.7.10 profiles") + .setPhase(Phase.LATE) + .addRequiredMod(TargetedMod.SPARK) + .setApplyIf(SparkKnownSources::mixinApplies) + .addClientMixins("spark.MixinForge1710SparkPlugin") + ), + ANGELICA_TEXTURE(new MixinBuilder() .setPhase(Phase.EARLY) .addClientMixins( diff --git a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java index f52076c8d..53a2bdc4d 100644 --- a/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java +++ b/src/main/java/com/gtnewhorizons/angelica/mixins/TargetedMod.java @@ -32,6 +32,7 @@ public enum TargetedMod implements ITargetMod { OPENBLOCKS(null, "OpenBlocks"), RAILCRAFT(null, "Railcraft"), SECURITYCRAFT(null, "securitycraft"), + SPARK(null, "spark"), STARMINER("jp.mc.ancientred.starminer.core.SMPlugin", "modJ_StarMiner"), SUPERNOVA("com.mitchej123.supernova.core.SupernovaCore", "supernova"), THAUMCRAFT(null, "Thaumcraft"), diff --git a/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinInitGLStateManager.java b/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinInitGLStateManager.java index 6f72cd277..d26ebaaaa 100644 --- a/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinInitGLStateManager.java +++ b/src/mixin/java/com/gtnewhorizons/angelica/mixins/early/angelica/startup/MixinInitGLStateManager.java @@ -2,6 +2,7 @@ package com.gtnewhorizons.angelica.mixins.early.angelica.startup; import com.gtnewhorizon.gtnhlib.core.GTNHLibCore; import com.gtnewhorizons.angelica.AngelicaMod; +import com.gtnewhorizons.angelica.Tags; import com.gtnewhorizons.angelica.client.rendering.TextureTracker; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.config.SystemProperties; @@ -47,6 +48,7 @@ public class MixinInitGLStateManager { .noErrorChecks(AngelicaConfig.disableErrorChecks && GTNHLibCore.isObf() && !AngelicaMod.lwjglDebug) .enableDSA(AngelicaConfig.enableDSA) .postInitCallback(SelectionBoxRenderer::init) + .buildLabel("Angelica " + Tags.VERSION) .build()); BackendStartGuard.disarm(); diff --git a/src/mixin/java/com/gtnewhorizons/angelica/mixins/late/spark/MixinForge1710SparkPlugin.java b/src/mixin/java/com/gtnewhorizons/angelica/mixins/late/spark/MixinForge1710SparkPlugin.java new file mode 100644 index 000000000..08e861564 --- /dev/null +++ b/src/mixin/java/com/gtnewhorizons/angelica/mixins/late/spark/MixinForge1710SparkPlugin.java @@ -0,0 +1,17 @@ +package com.gtnewhorizons.angelica.mixins.late.spark; + +import com.gtnewhorizons.angelica.compat.spark.SparkKnownSources; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.Unique; + +import java.util.Collection; + +@Pseudo +@Mixin(targets = "me.lucko.spark.forge.plugin.Forge1710SparkPlugin", remap = false) +public abstract class MixinForge1710SparkPlugin { + @Unique + public Collection getKnownSources() { + return SparkKnownSources.gather(getClass().getClassLoader()); + } +}