Skip to content

Commit

Permalink
Restore ability to enable stenciling (neoforged#1830)
Browse files Browse the repository at this point in the history
Co-authored-by: FiniteReality <[email protected]>
Co-authored-by: Sebastian Hartte <[email protected]>
  • Loading branch information
3 people authored and Soaryn committed Jan 21, 2025
1 parent d0c7955 commit 15c3f37
Show file tree
Hide file tree
Showing 12 changed files with 306 additions and 12 deletions.
42 changes: 42 additions & 0 deletions patches/com/mojang/blaze3d/pipeline/MainTarget.java.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
--- a/com/mojang/blaze3d/pipeline/MainTarget.java
+++ b/com/mojang/blaze3d/pipeline/MainTarget.java
@@ -16,7 +_,10 @@
static final MainTarget.Dimension DEFAULT_DIMENSIONS = new MainTarget.Dimension(854, 480);

public MainTarget(int p_166137_, int p_166138_) {
- super(true);
+ this(p_166137_, p_166138_, false);
+ }
+ public MainTarget(int p_166137_, int p_166138_, boolean enableStencil) {
+ super(true, enableStencil);
this.createFrameBuffer(p_166137_, p_166138_);
}

@@ -37,6 +_,14 @@
GlStateManager._texParameter(3553, 10242, 33071);
GlStateManager._texParameter(3553, 10243, 33071);
GlStateManager._glFramebufferTexture2D(36160, 36096, 3553, this.depthBufferId, 0);
+ if (this.useStencil) {
+ GlStateManager._glFramebufferTexture2D(
+ org.lwjgl.opengl.GL32.GL_FRAMEBUFFER,
+ org.lwjgl.opengl.GL32.GL_STENCIL_ATTACHMENT,
+ org.lwjgl.opengl.GL32.GL_TEXTURE_2D,
+ this.depthBufferId,
+ 0);
+ }
GlStateManager._bindTexture(0);
this.viewWidth = maintarget$dimension.width;
this.viewHeight = maintarget$dimension.height;
@@ -82,7 +_,11 @@
RenderSystem.assertOnRenderThreadOrInit();
GlStateManager._getError();
GlStateManager._bindTexture(this.depthBufferId);
- GlStateManager._texImage2D(3553, 0, 6402, p_166145_.width, p_166145_.height, 0, 6402, 5126, null);
+ if (!this.useStencil) {
+ GlStateManager._texImage2D(3553, 0, 6402, p_166145_.width, p_166145_.height, 0, 6402, 5126, null);
+ } else {
+ net.neoforged.neoforge.client.ClientHooks.texImageDepthStencil(p_166145_.width, p_166145_.height);
+ }
return GlStateManager._getError() != 1285;
}

66 changes: 66 additions & 0 deletions patches/com/mojang/blaze3d/pipeline/RenderTarget.java.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
--- a/com/mojang/blaze3d/pipeline/RenderTarget.java
+++ b/com/mojang/blaze3d/pipeline/RenderTarget.java
@@ -25,6 +_,7 @@
public int viewWidth;
public int viewHeight;
public final boolean useDepth;
+ public final boolean useStencil;
public int frameBufferId;
protected int colorTextureId;
protected int depthBufferId;
@@ -32,7 +_,15 @@
public int filterMode;

public RenderTarget(boolean p_166199_) {
- this.useDepth = p_166199_;
+ this(p_166199_, false);
+ }
+
+ public RenderTarget(boolean useDepth, boolean useStencil) {
+ if (useStencil && !useDepth) {
+ throw new IllegalArgumentException("Stencil can only be enabled if depth is enabled.");
+ }
+ this.useDepth = useDepth;
+ this.useStencil = useStencil;
this.frameBufferId = -1;
this.colorTextureId = -1;
this.depthBufferId = -1;
@@ -96,7 +_,11 @@
GlStateManager._texParameter(3553, 34892, 0);
GlStateManager._texParameter(3553, 10242, 33071);
GlStateManager._texParameter(3553, 10243, 33071);
- GlStateManager._texImage2D(3553, 0, 6402, this.width, this.height, 0, 6402, 5126, null);
+ if (!this.useStencil) {
+ GlStateManager._texImage2D(3553, 0, 6402, this.width, this.height, 0, 6402, 5126, null);
+ } else {
+ net.neoforged.neoforge.client.ClientHooks.texImageDepthStencil(this.width, this.height);
+ }
}

this.setFilterMode(9728, true);
@@ -109,6 +_,14 @@
if (this.useDepth) {
GlStateManager._glFramebufferTexture2D(36160, 36096, 3553, this.depthBufferId, 0);
}
+ if (this.useStencil) {
+ GlStateManager._glFramebufferTexture2D(
+ org.lwjgl.opengl.GL32.GL_FRAMEBUFFER,
+ org.lwjgl.opengl.GL32.GL_STENCIL_ATTACHMENT,
+ org.lwjgl.opengl.GL32.GL_TEXTURE_2D,
+ this.depthBufferId,
+ 0);
+ }

this.checkStatus();
this.clear();
@@ -217,6 +_,10 @@
if (this.useDepth) {
GlStateManager._clearDepth(1.0);
i |= 256;
+ }
+ if (this.useStencil) {
+ GlStateManager._clearStencil(0);
+ i |= org.lwjgl.opengl.GL32.GL_STENCIL_BUFFER_BIT;
}

GlStateManager._clear(i);
14 changes: 14 additions & 0 deletions patches/com/mojang/blaze3d/pipeline/TextureTarget.java.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--- a/com/mojang/blaze3d/pipeline/TextureTarget.java
+++ b/com/mojang/blaze3d/pipeline/TextureTarget.java
@@ -7,7 +_,10 @@
@OnlyIn(Dist.CLIENT)
public class TextureTarget extends RenderTarget {
public TextureTarget(int p_166213_, int p_166214_, boolean p_166215_) {
- super(p_166215_);
+ this(p_166213_, p_166214_, p_166215_, false);
+ }
+ public TextureTarget(int p_166213_, int p_166214_, boolean p_166215_, boolean useStencil) {
+ super(p_166215_, useStencil);
RenderSystem.assertOnRenderThreadOrInit();
this.resize(p_166213_, p_166214_);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--- a/com/mojang/blaze3d/resource/RenderTargetDescriptor.java
+++ b/com/mojang/blaze3d/resource/RenderTargetDescriptor.java
@@ -6,9 +_,13 @@
import net.neoforged.api.distmarker.OnlyIn;

@OnlyIn(Dist.CLIENT)
-public record RenderTargetDescriptor(int width, int height, boolean useDepth) implements ResourceDescriptor<RenderTarget> {
+public record RenderTargetDescriptor(int width, int height, boolean useDepth, boolean useStencil) implements ResourceDescriptor<RenderTarget> {
+ public RenderTargetDescriptor(int width, int height, boolean useDepth) {
+ this(width, height, useDepth, false);
+ }
+
public RenderTarget allocate() {
- return new TextureTarget(this.width, this.height, this.useDepth);
+ return new TextureTarget(this.width, this.height, this.useDepth, this.useStencil);
}

public void free(RenderTarget p_363223_) {
8 changes: 5 additions & 3 deletions patches/net/minecraft/client/Minecraft.java.patch
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
this.demo = p_91084_.game.demo;
this.allowsMultiplayer = !p_91084_.game.disableMultiplayer;
this.allowsChat = !p_91084_.game.disableChat;
@@ -483,15 +_,17 @@
@@ -483,15 +_,18 @@
LOGGER.error("Couldn't set icon", (Throwable)ioexception);
}

Expand All @@ -18,11 +18,13 @@
this.keyboardHandler = new KeyboardHandler(this);
- this.keyboardHandler.setup(this.window.getWindow());
RenderSystem.initRenderer(this.options.glDebugVerbosity, false);
this.mainRenderTarget = new MainTarget(this.window.getWidth(), this.window.getHeight());
- this.mainRenderTarget = new MainTarget(this.window.getWidth(), this.window.getHeight());
+ net.neoforged.neoforge.client.loading.ClientModLoader.begin(this);
+ this.mainRenderTarget = net.neoforged.neoforge.client.ClientHooks.instantiateMainTarget(this.window.getWidth(), this.window.getHeight());
this.mainRenderTarget.setClearColor(0.0F, 0.0F, 0.0F, 0.0F);
this.mainRenderTarget.clear();
this.resourceManager = new ReloadableResourceManager(PackType.CLIENT_RESOURCES);
+ net.neoforged.neoforge.client.loading.ClientModLoader.begin(this, this.resourcePackRepository, this.resourceManager);
+ net.neoforged.neoforge.client.loading.ClientModLoader.finish(this.resourcePackRepository, this.resourceManager);
+ //Move client bootstrap to after mod loading so that events can be fired for it.
+ ClientBootstrap.bootstrap();
this.resourcePackRepository.reload();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
--- a/net/minecraft/client/renderer/LevelRenderer.java
+++ b/net/minecraft/client/renderer/LevelRenderer.java
@@ -459,7 +_,7 @@
this.targets.main = framegraphbuilder.importExternal("main", this.minecraft.getMainRenderTarget());
int i = this.minecraft.getMainRenderTarget().width;
int j = this.minecraft.getMainRenderTarget().height;
- RenderTargetDescriptor rendertargetdescriptor = new RenderTargetDescriptor(i, j, true);
+ RenderTargetDescriptor rendertargetdescriptor = new RenderTargetDescriptor(i, j, true, this.minecraft.getMainRenderTarget().useStencil);
PostChain postchain = this.getTransparencyChain();
if (postchain != null) {
this.targets.translucent = framegraphbuilder.createInternal("translucent", rendertargetdescriptor);
@@ -473,6 +_,9 @@
this.targets.entityOutline = framegraphbuilder.importExternal("entity_outline", this.entityOutlineTarget);
}
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/net/neoforged/neoforge/client/ClientHooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableMap;
import com.mojang.blaze3d.framegraph.FrameGraphBuilder;
import com.mojang.blaze3d.pipeline.MainTarget;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.platform.Window;
import com.mojang.blaze3d.resource.RenderTargetDescriptor;
Expand Down Expand Up @@ -144,6 +146,7 @@
import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent;
import net.neoforged.neoforge.client.event.ClientTickEvent;
import net.neoforged.neoforge.client.event.ComputeFovModifierEvent;
import net.neoforged.neoforge.client.event.ConfigureMainRenderTargetEvent;
import net.neoforged.neoforge.client.event.CustomizeGuiOverlayEvent;
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
import net.neoforged.neoforge.client.event.FrameGraphSetupEvent;
Expand Down Expand Up @@ -182,6 +185,7 @@
import net.neoforged.neoforge.client.model.data.ModelData;
import net.neoforged.neoforge.client.renderstate.RegisterRenderStateModifiersEvent;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.common.NeoForgeConfig;
import net.neoforged.neoforge.common.NeoForgeMod;
import net.neoforged.neoforge.forge.snapshots.ForgeSnapshotsModClient;
import net.neoforged.neoforge.gametest.GameTestHooks;
Expand All @@ -195,6 +199,7 @@
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.joml.Vector4f;
import org.lwjgl.opengl.GL32;

/**
* Class for various client-side-only hooks.
Expand Down Expand Up @@ -1099,4 +1104,29 @@ public static Map<ResourceLocation, ResourceLocation> gatherMaterialAtlases(Map<
public static FrameGraphSetupEvent fireFrameGraphSetup(FrameGraphBuilder builder, LevelTargetBundle targets, RenderTargetDescriptor renderTargetDescriptor, Frustum frustum, Camera camera, Matrix4f modelViewMatrix, Matrix4f projectionMatrix, DeltaTracker deltaTracker, ProfilerFiller profiler) {
return NeoForge.EVENT_BUS.post(new FrameGraphSetupEvent(builder, targets, renderTargetDescriptor, frustum, camera, modelViewMatrix, projectionMatrix, deltaTracker, profiler));
}

@ApiStatus.Internal
public static MainTarget instantiateMainTarget(int width, int height) {
var e = ModLoader.postEventWithReturn(new ConfigureMainRenderTargetEvent());
return new MainTarget(width, height, e.isStencilEnabled());
}

/**
* Called by our stencil hooks to specify the depth+stencil texture.
*/
@ApiStatus.Internal
public static void texImageDepthStencil(int width, int height) {
var reducedPrecision = NeoForgeConfig.CLIENT.reducedDepthStencilFormat.getAsBoolean();
GlStateManager._texImage2D(
GL32.GL_TEXTURE_2D,
0,
reducedPrecision ? GL32.GL_DEPTH24_STENCIL8 : GL32.GL_DEPTH32F_STENCIL8,
width, height,
0,
GL32.GL_DEPTH_STENCIL,
// Since data is null, the format here does not matter as long as it matches internalFormat.
// So the usage, for depth, of unsigned int in one case and float in the other case, is not a problem.
reducedPrecision ? GL32.GL_UNSIGNED_INT_24_8 : GL32.GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.client.event;

import com.mojang.blaze3d.pipeline.MainTarget;
import net.neoforged.bus.api.Event;
import net.neoforged.bus.api.ICancellableEvent;
import net.neoforged.fml.LogicalSide;
import net.neoforged.fml.event.IModBusEvent;

/**
* Fired when configuring the {@linkplain MainTarget main render target} during startup.
* <p>
* This event is not {@linkplain ICancellableEvent cancellable}.
* <p>
* This event is fired on the mod-specific event bus, only on the {@linkplain LogicalSide#CLIENT logical client}.
*/
public class ConfigureMainRenderTargetEvent extends Event implements IModBusEvent {
private boolean enableStencil;

/**
* Returns whether enabling the stencil buffer on the main render target was requested.
*
* @return <code>true</code>, if the stencil buffer is enabled, or <code>false</code> otherwise.
*/
public boolean isStencilEnabled() {
return this.enableStencil;
}

/**
* Enables the stencil buffer for the main render target.
*/
public void enableStencil() {
this.enableStencil = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class ClientModLoader extends CommonModLoader {
@Nullable
private static ModLoadingException error;

public static void begin(final Minecraft minecraft, final PackRepository defaultResourcePacks, final ReloadableResourceManager mcResourceManager) {
public static void begin(final Minecraft minecraft) {
// force log4j to shutdown logging in a shutdown hook. This is because we disable default shutdown hook so the server properly logs it's shutdown
Runtime.getRuntime().addShutdownHook(new Thread(LogManager::shutdown));
ImmediateWindowHandler.updateProgress("Loading mods");
Expand All @@ -60,6 +60,9 @@ public static void begin(final Minecraft minecraft, final PackRepository default
} catch (ModLoadingException e) {
error = e;
}
}

public static void finish(final PackRepository defaultResourcePacks, final ReloadableResourceManager mcResourceManager) {
if (error == null) {
ResourcePackLoader.populatePackRepository(defaultResourcePacks, PackType.CLIENT_RESOURCES, false);
DataPackConfig.DEFAULT.addModPacks(ResourcePackLoader.getPackNames(PackType.SERVER_DATA));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ public static class Client {

public final BooleanValue logUntranslatedConfigurationWarnings;

public final BooleanValue reducedDepthStencilFormat;

Client(ModConfigSpec.Builder builder) {
experimentalForgeLightPipelineEnabled = builder
.comment("EXPERIMENTAL: Enable the NeoForge block rendering pipeline - fixes the lighting of custom models.")
Expand All @@ -114,6 +116,11 @@ public static class Client {
.comment("A config option mainly for developers. Logs out configuration values that do not have translations when running a client in a development environment.")
.translation("neoforge.configgui.logUntranslatedConfigurationWarnings")
.define("logUntranslatedConfigurationWarnings", true);

reducedDepthStencilFormat = builder
.comment("Configures how many bits are used for the depth buffer when stenciling has been enabled by a mod. Set to true for 24+8 bits and to false for 32+8 bits. Setting to true will slightly reduce VRAM usage, but risks introducing visual artifacts.")
.translation("neoforge.configgui.reducedDepthStencilFormat")
.define("reducedDepthStencilFormat", false);
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/assets/neoforge/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@
"neoforge.configgui.logUntranslatedItemTagWarnings.tooltip": "A config option mainly for developers. Logs out modded item tags that do not have translations when running on integrated server. Format desired is tag.item.<namespace>.<path> for the translation key. Defaults to SILENCED.",
"neoforge.configgui.permissionHandler": "Permission Handler",
"neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.",
"neoforge.configgui.reducedDepthStencilFormat": "Reduced Depth+Stencil Format",
"neoforge.configgui.reducedDepthStencilFormat.tooltip": "Configures how many bits are used for the depth buffer when stenciling has been enabled by a mod. Set to true for 24+8 bits and to false for 32+8 bits. Setting to true will slightly reduce VRAM usage, but risks introducing visual artifacts.",
"neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities",
"neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.",
"neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.",
Expand Down
Loading

0 comments on commit 15c3f37

Please sign in to comment.