Flyby and OSX improvements (#2061)

This commit is contained in:
Jason Mitchell authored and GitHub committed 2026-09-03 22:27:35 -07:00
1 parent a66db1517a
commit 0dfffca88e
8 files changed
+97 -7

No files matched your search

+3
View File
@@ -187,6 +187,9 @@ fun Test.configureAngelicaJava8() {
}
dependsOn(tasks.extractNatives2)
jvmArgs("-Djava.library.path=${tasks.extractNatives2.get().destinationFolder.asFile.get().path}")
if (isMacOs) {
jvmArgs("-Dapple.awt.UIElement=true")
}
testLogging { events("passed", "skipped", "failed") }
val swaps = mapOf(
+3
View File
@@ -224,6 +224,9 @@ fun Test.configureGlsmJava8() {
val extractNatives = rootProject.tasks.named("extractNatives2")
dependsOn(extractNatives)
jvmArgs("-Djava.library.path=${extractNatives.get().property("destinationFolder").let { (it as DirectoryProperty).asFile.get().path }}")
if (System.getProperty("os.name").lowercase().contains("mac")) {
jvmArgs("-Dapple.awt.UIElement=true")
}
}
tasks.test {
@@ -47,6 +47,7 @@ public final class SystemProperties {
// Flyby
public static final String FLYBY_ROUTE = System.getProperty("angelica.flyby.route", "");
public static final boolean FLYBY_WAIT_FOR_TRACY = Boolean.getBoolean("angelica.flyby.waitForTracy");
public static final boolean FLYBY_WAIT_FOR_FOCUS = Boolean.getBoolean("angelica.flyby.waitForFocus");
public static final int FLYBY_WARMUP_TICKS = Integer.getInteger("angelica.flyby.warmupTicks", 400);
public static final int FLYBY_LENGTH = Integer.getInteger("angelica.flyby.length", 0); // Blocks for moving routes, ticks for stationary
public static final double FLYBY_SPEED = parseDouble("angelica.flyby.speed"); // Travel speed in blocks per tick
@@ -6,6 +6,7 @@ import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
import com.gtnewhorizons.angelica.sdlgpu.frame.FrameManager;
import com.gtnewhorizons.angelica.sdlgpu.resource.ResourceManager;
import org.lwjgl.sdl.SDLError;
import org.lwjgl.sdl.SDLHints;
import org.lwjgl.sdl.SDLInit;
import java.lang.reflect.Field;
@@ -67,8 +68,13 @@ public final class SdlTestRig {
private static final int SHADER_FORMATS = SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_DXBC | SDL_GPU_SHADERFORMAT_DXIL;
public static void initSdlVideo() {
SDLHints.SDL_SetHint(SDLHints.SDL_HINT_MAC_BACKGROUND_APP, "1");
assumeTrue(SDLInit.SDL_Init(SDL_INIT_VIDEO), () -> "SDL_Init failed: " + SDLError.SDL_GetError());
}
public static SdlTestRig acquireRealDevice() throws ReflectiveOperationException {
assumeTrue(SDLInit.SDL_Init(SDL_INIT_VIDEO), "SDL_Init failed: " + SDLError.SDL_GetError());
initSdlVideo();
realSdlDevice = SDL_CreateGPUDevice(SHADER_FORMATS, true, (CharSequence) null);
assumeTrue(realSdlDevice != 0, "No SDL GPU device: " + SDLError.SDL_GetError());
@@ -1,16 +1,14 @@
package com.gtnewhorizons.angelica.sdlgpu.device;
import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.lwjgl.sdl.SDLError;
import org.lwjgl.sdl.SDLInit;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.lwjgl.sdl.SDLInit.SDL_INIT_VIDEO;
class DeviceLifecycleGpuTest {
@@ -18,7 +16,7 @@ class DeviceLifecycleGpuTest {
@BeforeAll
static void initSdl() {
assumeTrue(SDLInit.SDL_Init(SDL_INIT_VIDEO), () -> "SDL_Init failed: " + SDLError.SDL_GetError());
SdlTestRig.initSdlVideo();
}
@AfterEach
@@ -0,0 +1,33 @@
package com.gtnewhorizons.angelica.sdlgpu.frame;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class AcquireAffinityTest {
private static final Thread WINDOW = new Thread("window");
private static final Thread OTHER = new Thread("other");
@Test
void acquiringOnTheWindowThreadIsTheOnlyAcceptedCase() {
assertFalse(FrameManager.acquireAffinityViolated(WINDOW, WINDOW, 0));
}
@Test
void acquiringOnAnyOtherThreadViolatesTheSdlContract() {
assertTrue(FrameManager.acquireAffinityViolated(OTHER, WINDOW, 0));
}
@Test
void aLaterAcquireFromASecondThreadViolatesEvenWhenTheFirstWasCorrect() {
assertTrue(FrameManager.acquireAffinityViolated(WINDOW, WINDOW, 1),
"drift after a correct first acquire must still be caught");
}
@Test
void anUnknownWindowThreadCannotBeJudged() {
assertFalse(FrameManager.acquireAffinityViolated(OTHER, null, 3));
}
}
@@ -0,0 +1,22 @@
package com.gtnewhorizons.angelica.sdlgpu.splash;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class SplashDispatcherTest {
private static final long INTERVAL = 16_000_000L;
@Test
void theIntervalGateSwallowsFramesArrivingTooSoon() {
assertFalse(SplashDispatcher.intervalElapsed(INTERVAL - 1, 0L, false));
assertTrue(SplashDispatcher.intervalElapsed(INTERVAL, 0L, false));
}
@Test
void theFinalFrameIsNotSwallowedByTheIntervalGate() {
assertTrue(SplashDispatcher.intervalElapsed(1L, 0L, true), "teardown must present the last splash frame whenever it arrives");
}
}
@@ -13,6 +13,7 @@ import net.minecraft.util.EnumChatFormatting;
import net.minecraft.world.WorldServer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.Display;
import java.util.Arrays;
@@ -41,9 +42,12 @@ public final class FlybyRunner {
private int runTicks;
private int tick;
private boolean waitForTracy;
private boolean waitForFocus;
private boolean exitWhenDone;
private boolean startedFromProperties;
private volatile boolean freezeRequested;
private boolean pauseOnLostFocusSaved;
private boolean pauseOnLostFocusOverridden;
private double originX, originY, originZ;
private float originYaw, originPitch;
@@ -83,10 +87,11 @@ public final class FlybyRunner {
this.startedFromProperties = true;
this.start(configured, SystemProperties.FLYBY_LENGTH, SystemProperties.FLYBY_WARMUP_TICKS, SystemProperties.FLYBY_SPEED);
this.waitForTracy = SystemProperties.FLYBY_WAIT_FOR_TRACY;
this.waitForFocus = SystemProperties.FLYBY_WAIT_FOR_FOCUS;
this.exitWhenDone = SystemProperties.FLYBY_EXIT_WHEN_DONE;
LOGGER.info("Flyby started from properties: route={} warmup={} length={} {} ({} ticks) waitForTracy={} exitWhenDone={}",
LOGGER.info("Flyby started from properties: route={} warmup={} length={} {} ({} ticks) waitForTracy={} waitForFocus={} exitWhenDone={}",
configured.id(), this.warmupTicks, this.runLength, configured.lengthUnit(), this.runTicks,
this.waitForTracy, this.exitWhenDone);
this.waitForTracy, this.waitForFocus, this.exitWhenDone);
}
public void start(FlybyRoute route, int length, int warmupTicks, double speed) {
@@ -99,6 +104,7 @@ public final class FlybyRunner {
this.frameCount = 0;
this.framesTruncated = false;
this.waitForTracy = false;
this.waitForFocus = false;
this.exitWhenDone = false;
this.state = State.WAITING;
}
@@ -123,6 +129,7 @@ public final class FlybyRunner {
switch (this.state) {
case WAITING -> {
if (this.waitForTracy && !Tracy.isConnected()) return;
if (this.waitForFocus && !Display.isActive()) return;
this.begin(mc, player);
}
case WARMUP -> {
@@ -172,6 +179,15 @@ public final class FlybyRunner {
}
private void begin(Minecraft mc, EntityClientPlayerMP player) {
if (mc.currentScreen != null) {
mc.displayGuiScreen(null);
}
if (!this.pauseOnLostFocusOverridden) {
this.pauseOnLostFocusSaved = mc.gameSettings.pauseOnLostFocus;
this.pauseOnLostFocusOverridden = true;
mc.gameSettings.pauseOnLostFocus = false;
}
this.originX = player.posX;
this.originY = player.posY;
this.originZ = player.posZ;
@@ -397,11 +413,18 @@ public final class FlybyRunner {
Tracy.message("flyby teardown");
this.returnToOrigin(player);
this.restorePauseOnLostFocus(mc);
this.tick = 0;
this.state = this.exitWhenDone ? State.EXITING : State.DONE;
}
private void restorePauseOnLostFocus(Minecraft mc) {
if (!this.pauseOnLostFocusOverridden) return;
mc.gameSettings.pauseOnLostFocus = this.pauseOnLostFocusSaved;
this.pauseOnLostFocusOverridden = false;
}
private void returnToOrigin(EntityClientPlayerMP player) {
player.motionX = 0.0D;
player.motionY = 0.0D;
@@ -448,6 +471,7 @@ public final class FlybyRunner {
Tracy.sectionLeave(this.runSection);
this.runSection = 0L;
FramePacer.endStats();
this.restorePauseOnLostFocus(Minecraft.getMinecraft());
}
}