Completely bypass Minecraft when window is resized during rendering

Should fix issues where resizing affects the render result.
This commit is contained in:
Jonas Herzig
2022-04-10 18:36:36 +02:00
parent fd9be55f79
commit 5be57681af
10 changed files with 102 additions and 43 deletions

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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();
}
}
}

View File

@@ -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

View File

@@ -21,6 +21,7 @@
"Mixin_StabilizeCamera",
"Mixin_Stereoscopic_Camera",
"Mixin_Stereoscopic_HandRenderPass",
"Mixin_SuppressFramebufferResizeDuringRender",
//#if MC>=11600
"Mixin_AddIrisOdsShaderUniforms",
"Mixin_LoadIrisOdsShaderPack",

View File

@@ -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;
}

View File

@@ -15,6 +15,4 @@ public interface MainWindowAccessor {
int getFramebufferHeight();
@Accessor("displayHeight")
void setFramebufferHeight(int value);
@Invoker
void invokeUpdateFramebufferSize();
}

View File

@@ -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()

View File

@@ -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()