From 6844d05480a2a35375bec4c9c640a85547b6a026 Mon Sep 17 00:00:00 2001 From: Saad Nadeem Date: Wed, 19 Aug 2026 16:48:13 -0400 Subject: [PATCH 1/2] fix(hud): prevent flicker when opening/closing OneConfig --- .../mixin/events/Mixin_HudRenderEvent.java | 1 + .../oneconfig/internal/ui/compose/SkiaCtx.kt | 29 +++++++++++++++++++ .../ui/compose/impls/OneConfigUIScreen.kt | 15 +++++++++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/events/Mixin_HudRenderEvent.java b/minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/events/Mixin_HudRenderEvent.java index 0da7c4a85..48b91765f 100644 --- a/minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/events/Mixin_HudRenderEvent.java +++ b/minecraft/src/main/java/org/polyfrost/oneconfig/internal/mixin/events/Mixin_HudRenderEvent.java @@ -26,6 +26,7 @@ public class Mixin_HudRenderEvent { @Inject(method = "extractRenderState", at = @At("TAIL")) private void renderHudCallback(GuiGraphicsExtractor ctx, DeltaTracker deltaTracker, CallbackInfo ci) { OneConfig.render(ctx, deltaTracker.getRealtimeDeltaTicks()); + //~ if < 1.21.8 '.suppressInGameHudRender' -> '.shouldSuppressInGameHudRender()' if (!SkiaCtx.INSTANCE.suppressInGameHudRender) { SkiaCtx.INSTANCE.blitHud(ctx); } diff --git a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/SkiaCtx.kt b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/SkiaCtx.kt index 680a3c9f1..a8e8bb31f 100644 --- a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/SkiaCtx.kt +++ b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/SkiaCtx.kt @@ -74,6 +74,9 @@ object SkiaCtx { private var hudRealIsGeneral = false private var composeRealIsGeneral = false + //? if < 1.21.8 + //private var clearComposeAfterDraw = false + @Volatile private var composeActive = false @Volatile @@ -82,6 +85,8 @@ object SkiaCtx { private var composeRender: (() -> Unit)? = null fun submitComposeFrame(dirty: Boolean, render: Runnable) { + //? if < 1.21.8 + //clearComposeAfterDraw = false composeActive = true if (dirty || composeRender == null) { composeRender = { render.run() } @@ -90,9 +95,17 @@ object SkiaCtx { } fun clearComposeFrame() { + //? if >= 1.21.8 { composeActive = false composeDirty = false composeRender = null + //?} else { + /*// Screen removal calls this before the frame's final Skia draw. + // Clearing immediately would leave that frame without a HUD. + // Keep the cached Compose surface for that draw so the HUD remains visible. + clearComposeAfterDraw = true + composeDirty = false + *///?} } //? >= 1.21.5 { @@ -329,6 +342,15 @@ object SkiaCtx { @JvmField var suppressInGameHudRender = false + //? if < 1.21.8 { + /*// The HUD pass runs before the Compose surface exists, so keep the HUD visible until then. + fun shouldSuppressInGameHudRender(): Boolean = suppressInGameHudRender && composeSurface != null + + fun prepareComposeSurface() { + if (this::directContext.isInitialized) resolveComposeSurface() + } + *///? } + fun blitHud(guiGraphics: GuiGraphicsExtractor) { val rt = hudTarget ?: return val w = rt.width @@ -504,6 +526,13 @@ object SkiaCtx { } } finally { currentSurface = null + //? if < 1.21.8 { + /*if (clearComposeAfterDraw) { + clearComposeAfterDraw = false + composeActive = false + composeRender = null + } + *///?} } } diff --git a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt index bcac29862..f1b6400de 100644 --- a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt +++ b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt @@ -29,6 +29,7 @@ import org.polyfrost.oneconfig.internal.ui.shell.ShellState import org.polyfrost.oneconfig.internal.ui.sound.UiSoundEvent import org.polyfrost.oneconfig.internal.ui.sound.UiSounds import org.polyfrost.oneconfig.api.platform.v1.Platform +import org.polyfrost.oneconfig.internal.OneConfig import kotlin.math.pow class OneConfigUIScreen @JvmOverloads constructor( @@ -111,7 +112,7 @@ class OneConfigUIScreen @JvmOverloads constructor( } override fun init() { - org.polyfrost.oneconfig.internal.OneConfig.dismissFirstLaunchToast() + OneConfig.dismissFirstLaunchToast() ConfigRegistry.loadFrom(ConfigManager.active(), ConfigSource.OC) initialTree?.let { ConfigRegistry.registerTree(it, ConfigSource.OC) } @@ -163,6 +164,12 @@ class OneConfigUIScreen @JvmOverloads constructor( ShellState.versionLabel = "OneConfig" } + //? if < 1.21.8 { + /*// Compose normally creates its surface after the HUD pass. + // Create the surface now to avoid drawing the HUD twice. + SkiaCtx.prepareComposeSurface() + *///?} + SkiaCtx.suppressInGameHudRender = true HudManager.overrideShowInScreens = true HudManager.isConfigUiOpen = true @@ -257,6 +264,12 @@ class OneConfigUIScreen @JvmOverloads constructor( if (Platform.screen().current() !== this) return if (closeRequested && System.currentTimeMillis() - closeRequestedAt >= closeAnimationMs) { Platform.screen().close() + //? if >= 1.21.8 { + // This frame skipped normal HUD rendering because OneConfig was open. + // Closing removes the Compose copy as well, so add the normal HUD back. + OneConfig.render(ctx, tickDelta) + SkiaCtx.blitHud(ctx) + //?} return } if (client.level == null) { From f4e2c26d231f0b87fa026a1cc76d7c7a9839b72d Mon Sep 17 00:00:00 2001 From: Julian Chang Date: Thu, 20 Aug 2026 17:06:08 +0700 Subject: [PATCH 2/2] some fixes --- .../oneconfig/internal/OneConfig.java | 1 + .../oneconfig/internal/ui/compose/SkiaCtx.kt | 44 +++++++++++++++---- .../ui/compose/impls/OneConfigUIScreen.kt | 8 +++- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/minecraft/src/main/java/org/polyfrost/oneconfig/internal/OneConfig.java b/minecraft/src/main/java/org/polyfrost/oneconfig/internal/OneConfig.java index 1aed22a26..657b96b87 100644 --- a/minecraft/src/main/java/org/polyfrost/oneconfig/internal/OneConfig.java +++ b/minecraft/src/main/java/org/polyfrost/oneconfig/internal/OneConfig.java @@ -183,6 +183,7 @@ public static void render(GuiGraphicsExtractor graphics, float partial) { HudManager.targetPixelWidth = Platform.screen().viewportWidth(); HudManager.targetPixelHeight = Platform.screen().viewportHeight(); + //~ if < 1.21.8 '.suppressInGameHudRender' -> '.shouldSuppressInGameHudRender()' if (!SkiaCtx.INSTANCE.suppressInGameHudRender) { LegacyHudRenderer.INSTANCE.renderLive(graphics); } diff --git a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/SkiaCtx.kt b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/SkiaCtx.kt index a8e8bb31f..239e78d74 100644 --- a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/SkiaCtx.kt +++ b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/SkiaCtx.kt @@ -74,8 +74,13 @@ object SkiaCtx { private var hudRealIsGeneral = false private var composeRealIsGeneral = false - //? if < 1.21.8 - //private var clearComposeAfterDraw = false + //? if < 1.21.8 { + /*@Volatile + private var clearComposeAfterDraw = false + + @Volatile + private var hudBlitSuppressed = false + *///? } @Volatile private var composeActive = false @@ -108,6 +113,21 @@ object SkiaCtx { *///?} } + //? if < 1.21.8 { + /*fun discardComposeFrame() { + clearComposeAfterDraw = false + composeActive = false + composeDirty = false + composeRender = null + } + + private fun finishComposeClear() { + clearComposeAfterDraw = false + composeActive = false + composeRender = null + } + *///? } + //? >= 1.21.5 { private val HUD_TEXTURE_LOC = Identifier.fromNamespaceAndPath("oneconfig", "hud_skia") private val COMPOSE_TEXTURE_LOC = Identifier.fromNamespaceAndPath("oneconfig", "compose_skia") @@ -344,10 +364,15 @@ object SkiaCtx { //? if < 1.21.8 { /*// The HUD pass runs before the Compose surface exists, so keep the HUD visible until then. - fun shouldSuppressInGameHudRender(): Boolean = suppressInGameHudRender && composeSurface != null + fun shouldSuppressInGameHudRender(): Boolean { + val suppress = suppressInGameHudRender && composeSurface != null + hudBlitSuppressed = suppress + return suppress + } fun prepareComposeSurface() { - if (this::directContext.isInitialized) resolveComposeSurface() + if (!isReady || currentSurface != null) return + resolveComposeSurface() } *///? } @@ -461,6 +486,11 @@ object SkiaCtx { fun draw() { if (!this::directContext.isInitialized) return + //? if < 1.21.8 { + /*val composeStandsInForHud = hudBlitSuppressed + hudBlitSuppressed = false + if (clearComposeAfterDraw && !composeStandsInForHud) finishComposeClear() + *///? } runWarmups() val draws = queuedDraws.toList() queuedDraws.clear() @@ -527,11 +557,7 @@ object SkiaCtx { } finally { currentSurface = null //? if < 1.21.8 { - /*if (clearComposeAfterDraw) { - clearComposeAfterDraw = false - composeActive = false - composeRender = null - } + /*if (clearComposeAfterDraw) finishComposeClear() *///?} } } diff --git a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt index f1b6400de..5045879e5 100644 --- a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt +++ b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt @@ -269,7 +269,13 @@ class OneConfigUIScreen @JvmOverloads constructor( // Closing removes the Compose copy as well, so add the normal HUD back. OneConfig.render(ctx, tickDelta) SkiaCtx.blitHud(ctx) - //?} + //?} else { + /*if (closeAnimationMs <= 0L) { + SkiaCtx.discardComposeFrame() + OneConfig.render(ctx, tickDelta) + SkiaCtx.blitHud(ctx) + } + *///?} return } if (client.level == null) {