From 5be57681afd2e6d36c2e203379e68dd000710512 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 10 Apr 2022 18:36:36 +0200 Subject: [PATCH] Completely bypass Minecraft when window is resized during rendering Should fix issues where resizing affects the render result. --- .../render/gui/progress/VirtualWindow.java | 74 ++++++++++++------- .../render/hooks/MinecraftClientExt.java | 12 +++ .../render/mixin/MainWindowAccessor.java | 8 -- ...SuppressFramebufferResizeDuringRender.java | 39 ++++++++++ .../render/rendering/VideoRenderer.java | 2 - .../resources/mixins.render.replaymod.json | 1 + .../com/replaymod/core/versions/Window.java | 5 -- .../render/mixin/MainWindowAccessor.java | 2 - versions/1.14.4-forge/mapping.txt | 1 + versions/1.8.9/mapping.txt | 1 + 10 files changed, 102 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/replaymod/render/hooks/MinecraftClientExt.java create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_SuppressFramebufferResizeDuringRender.java diff --git a/src/main/java/com/replaymod/render/gui/progress/VirtualWindow.java b/src/main/java/com/replaymod/render/gui/progress/VirtualWindow.java index 8dd8617b..82977526 100644 --- a/src/main/java/com/replaymod/render/gui/progress/VirtualWindow.java +++ b/src/main/java/com/replaymod/render/gui/progress/VirtualWindow.java @@ -1,5 +1,6 @@ package com.replaymod.render.gui.progress; +import com.replaymod.render.hooks.MinecraftClientExt; import com.replaymod.render.mixin.MainWindowAccessor; import de.johni0702.minecraft.gui.function.Closeable; import net.minecraft.client.MinecraftClient; @@ -16,6 +17,7 @@ public class VirtualWindow implements Closeable { private final MainWindowAccessor acc; private final Framebuffer guiFramebuffer; + private boolean isBound; private int framebufferWidth, framebufferHeight; private int gameWidth, gameHeight; @@ -26,7 +28,8 @@ public class VirtualWindow implements Closeable { this.window = mc.getWindow(); this.acc = (MainWindowAccessor) (Object) this.window; - updateFramebufferSize(); + framebufferWidth = acc.getFramebufferWidth(); + framebufferHeight = acc.getFramebufferHeight(); //#if MC>=11700 //$$ guiFramebuffer = new WindowFramebuffer(framebufferWidth, framebufferHeight); @@ -37,11 +40,15 @@ public class VirtualWindow implements Closeable { //#endif ); //#endif + + MinecraftClientExt.get(mc).setWindowDelegate(this); } @Override public void close() { guiFramebuffer.delete(); + + MinecraftClientExt.get(mc).setWindowDelegate(null); } public void bind() { @@ -49,11 +56,13 @@ public class VirtualWindow implements Closeable { gameHeight = acc.getFramebufferHeight(); acc.setFramebufferWidth(framebufferWidth); acc.setFramebufferHeight(framebufferHeight); + isBound = true; } public void unbind() { acc.setFramebufferWidth(gameWidth); acc.setFramebufferHeight(gameHeight); + isBound = false; } public void beginWrite() { @@ -82,36 +91,45 @@ public class VirtualWindow implements Closeable { //#endif } - public void updateSize() { - // Resize the GUI framebuffer if the display size changed - if (framebufferSizeChanged()) { - updateFramebufferSize(); - //#if MC>=11400 - guiFramebuffer.resize(framebufferWidth, framebufferHeight - //#if MC>=11400 - , false - //#endif - ); - //#else - //$$ guiFramebuffer.createBindFramebuffer(framebufferWidth, framebufferHeight); - //#endif - } - } - - private boolean framebufferSizeChanged() { - int realWidth = mc.getWindow().getFramebufferWidth(); - int realHeight = mc.getWindow().getFramebufferHeight(); - if (realWidth == 0 || realHeight == 0) { + /** + * Updates the size of the window's framebuffer. Must only be called while this window is bound. + */ + public void onResolutionChanged(int newWidth, int newHeight) { + if (newWidth == 0 || newHeight == 0) { // These can be zero on Windows if minimized. // Creating zero-sized framebuffers however will throw an error, so we never want to switch to zero values. - return false; + return; + } + + if (framebufferWidth == newWidth && framebufferHeight == newHeight) { + return; // size is unchanged, nothing to do + } + + framebufferWidth = newWidth; + framebufferHeight = newHeight; + + //#if MC>=11400 + guiFramebuffer.resize(newWidth, newHeight + //#if MC>=11400 + , false + //#endif + ); + //#else + //$$ guiFramebuffer.createBindFramebuffer(newWidth, newHeight); + //#endif + + applyScaleFactor(); + if (mc.currentScreen != null) { + mc.currentScreen.resize(mc, window.getScaledWidth(), window.getScaledHeight()); } - return framebufferWidth != realWidth || framebufferHeight != realHeight; } - private void updateFramebufferSize() { - framebufferWidth = mc.getWindow().getFramebufferWidth(); - framebufferHeight = mc.getWindow().getFramebufferHeight(); + private void applyScaleFactor() { + //#if MC>=11400 + window.setScaleFactor(window.calculateScaleFactor(mc.options.guiScale, mc.forcesUnicodeFont())); + //#else + //$$ // Nothing to do, ScaledResolution re-computes the scale factor every time it is created + //#endif } public int getFramebufferWidth() { @@ -121,4 +139,8 @@ public class VirtualWindow implements Closeable { public int getFramebufferHeight() { return framebufferHeight; } + + public boolean isBound() { + return isBound; + } } diff --git a/src/main/java/com/replaymod/render/hooks/MinecraftClientExt.java b/src/main/java/com/replaymod/render/hooks/MinecraftClientExt.java new file mode 100644 index 00000000..6b4295bb --- /dev/null +++ b/src/main/java/com/replaymod/render/hooks/MinecraftClientExt.java @@ -0,0 +1,12 @@ +package com.replaymod.render.hooks; + +import com.replaymod.render.gui.progress.VirtualWindow; +import net.minecraft.client.MinecraftClient; + +public interface MinecraftClientExt { + void setWindowDelegate(VirtualWindow window); + + static MinecraftClientExt get(MinecraftClient mc) { + return (MinecraftClientExt) mc; + } +} diff --git a/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java b/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java index a54dd178..c24af52b 100644 --- a/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java +++ b/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java @@ -15,12 +15,4 @@ public interface MainWindowAccessor { int getFramebufferHeight(); @Accessor void setFramebufferHeight(int value); - // FIXME preprocessor should be able to infer this mapping - // FIXME preprocessor should be able to remap this one when the mapping is given manually - //#if MC>=11500 - @Invoker - //#else - //$$ @Invoker("method_4483") - //#endif - void invokeUpdateFramebufferSize(); } diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_SuppressFramebufferResizeDuringRender.java b/src/main/java/com/replaymod/render/mixin/Mixin_SuppressFramebufferResizeDuringRender.java new file mode 100644 index 00000000..707f6952 --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_SuppressFramebufferResizeDuringRender.java @@ -0,0 +1,39 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.gui.progress.VirtualWindow; +import com.replaymod.render.hooks.MinecraftClientExt; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.util.Window; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(MinecraftClient.class) +public class Mixin_SuppressFramebufferResizeDuringRender implements MinecraftClientExt { + + @Unique + private VirtualWindow windowDelegate; + + @Override + public void setWindowDelegate(VirtualWindow window) { + this.windowDelegate = window; + } + + //#if MC>=11400 + @Inject(method = "onResolutionChanged", at = @At("HEAD"), cancellable = true) + //#else + //$$ @Inject(method = "resize", at = @At("HEAD"), cancellable = true) + //#endif + private void suppressResizeDuringRender(CallbackInfo ci) { + VirtualWindow delegate = this.windowDelegate; + if (delegate != null && delegate.isBound()) { + Window window = ((MinecraftClient) (Object) this).getWindow(); + delegate.onResolutionChanged(window.getFramebufferWidth(), window.getFramebufferHeight()); + ci.cancel(); + } + } +} diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index d51cc04b..a6b31504 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -462,8 +462,6 @@ public class VideoRenderer implements RenderInfo { return false; } - guiWindow.updateSize(); - pushMatrix(); GlStateManager.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT //#if MC>=11400 diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index 092aa958..ff833a38 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -21,6 +21,7 @@ "Mixin_StabilizeCamera", "Mixin_Stereoscopic_Camera", "Mixin_Stereoscopic_HandRenderPass", + "Mixin_SuppressFramebufferResizeDuringRender", //#if MC>=11600 "Mixin_AddIrisOdsShaderUniforms", "Mixin_LoadIrisOdsShaderPack", diff --git a/versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java b/versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java index 40e2278f..3f620619 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java +++ b/versions/1.12.2/src/main/java/com/replaymod/core/versions/Window.java @@ -33,11 +33,6 @@ public class Window implements MainWindowAccessor { mc.displayHeight = value; } - @Override - public void invokeUpdateFramebufferSize() { - // no-op, pre-LWJGL3 MC doesn't differentiate between window and framebuffer size - } - public long getHandle() { return 0; } diff --git a/versions/1.12.2/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java b/versions/1.12.2/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java index a6166095..697dd601 100644 --- a/versions/1.12.2/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java +++ b/versions/1.12.2/src/main/java/com/replaymod/render/mixin/MainWindowAccessor.java @@ -15,6 +15,4 @@ public interface MainWindowAccessor { int getFramebufferHeight(); @Accessor("displayHeight") void setFramebufferHeight(int value); - @Invoker - void invokeUpdateFramebufferSize(); } diff --git a/versions/1.14.4-forge/mapping.txt b/versions/1.14.4-forge/mapping.txt index 2096663b..52a22ceb 100644 --- a/versions/1.14.4-forge/mapping.txt +++ b/versions/1.14.4-forge/mapping.txt @@ -181,6 +181,7 @@ net.minecraft.client.gui.screen.Screen hasShiftDown() isShiftKeyDown() net.minecraft.client.gui.screen.Screen init() setWorldAndResolution() net.minecraft.client.gui.screen.Screen minecraft mc net.minecraft.client.gui.screen.Screen net.minecraft.client.gui.GuiScreen +net.minecraft.client.gui.screen.Screen resize() onResize() net.minecraft.client.gui.screen.Screen passEvents allowUserInput net.minecraft.client.gui.screen.Screen removed() onGuiClosed() net.minecraft.client.gui.screen.Screen renderBackground() drawDefaultBackground() diff --git a/versions/1.8.9/mapping.txt b/versions/1.8.9/mapping.txt index 43123ad0..2dfdbda5 100644 --- a/versions/1.8.9/mapping.txt +++ b/versions/1.8.9/mapping.txt @@ -1,3 +1,4 @@ +net.minecraft.client.gui.GuiScreen onResize() func_175273_b() net.minecraft.entity.player.EntityPlayer isWearing() func_175148_a() net.minecraft.client.renderer.WorldRenderer begin() startDrawing() net.minecraft.network.play.server.S38PacketPlayerListItem getAction() func_179768_b()