Skip to content

Commit

Permalink
atlasSize now properly reflects the texture currently bound to the te…
Browse files Browse the repository at this point in the history
…x/texture/gtexture sampler

Fixes IrisShaders#648
Closes IrisShaders#549
  • Loading branch information
coderbot16 committed Sep 29, 2021
1 parent 3a4894b commit fcd6275
Show file tree
Hide file tree
Showing 13 changed files with 232 additions and 45 deletions.
8 changes: 8 additions & 0 deletions docs/changelogs/1.1.3/full.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ WIP, up-to-date as of:
- 1.16.x: https://github.com/IrisShaders/Iris/commit/12623519a039d62479c65e70e756a0f9307f55af
- 1.17.x: https://github.com/IrisShaders/Iris/commit/2767fbf6d70a177cc33ce1848f724a10cb6d1e8b

## New Shader Features and Fixes

- Witches and drowned now have emissive parts when running with Complementary Shaders
- Previously, they did not because atlasSize did not properly reflect the size of the currently bound atlas texture
- Rather, it was always the size of the block atlas texture
- With this fixed, the emissive features in Complementary's Integrated PBR now works properly

## 1.17-specific fixes

- The bottom face of end portal blocks is now properly positioned when shaders are enabled
Expand All @@ -22,3 +29,4 @@ WIP, up-to-date as of:
- Iris now includes an expression parser written by Kroppeb, a critical part of implementing custom uniforms.
- Iris now uses Mojang Mappings instead of Yarn Mappings. This doesn't change anything for users, but it does streamline our development process & workflow for handling Minecraft updates.
- Iris no longer depends on fabric-api-base and fabric-lifecycle-events, shrinking the released JAR size by around 60 kB.
- Code has been added to support the addition of Iris-exclusive shader features in a way that allows shader authors to detect their presence.
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ public class StateUpdateNotifiers {
public static ValueUpdateNotifier fogToggleNotifier;
public static ValueUpdateNotifier fogModeNotifier;
public static ValueUpdateNotifier fogDensityNotifier;
public static ValueUpdateNotifier atlasTextureNotifier;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package net.coderbot.iris.gl.uniform;

import com.mojang.math.Vector4f;
import net.coderbot.iris.vendored.joml.Vector2i;

import java.util.function.DoubleSupplier;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
Expand Down Expand Up @@ -32,6 +34,12 @@ default DynamicLocationalUniformHolder uniform1i(String name, IntSupplier value,
return this;
}

default DynamicLocationalUniformHolder uniform2i(String name, Supplier<Vector2i> value, ValueUpdateNotifier notifier) {
location(name, UniformType.VEC2I).ifPresent(id -> addDynamicUniform(new Vector2IntegerJomlUniform(id, value, notifier), notifier));

return this;
}

default DynamicUniformHolder uniform4f(String name, Supplier<Vector4f> value, ValueUpdateNotifier notifier) {
location(name, UniformType.VEC4).ifPresent(id -> addDynamicUniform(new Vector4Uniform(id, value, notifier), notifier));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package net.coderbot.iris.gl.uniform;

import com.mojang.math.Vector4f;
import net.coderbot.iris.vendored.joml.Vector2i;

import java.util.function.DoubleSupplier;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
Expand All @@ -10,5 +12,6 @@ public interface DynamicUniformHolder extends UniformHolder {
DynamicUniformHolder uniform1f(String name, IntSupplier value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform1f(String name, DoubleSupplier value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform1i(String name, IntSupplier value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform2i(String name, Supplier<Vector2i> value, ValueUpdateNotifier notifier);
DynamicUniformHolder uniform4f(String name, Supplier<Vector4f> value, ValueUpdateNotifier notifier);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package net.coderbot.iris.gl.uniform;

import net.coderbot.iris.vendored.joml.Vector2i;
import org.lwjgl.opengl.GL20;

import java.util.function.Supplier;

public class Vector2IntegerJomlUniform extends Uniform {
private Vector2i cachedValue;
private final Supplier<Vector2i> value;

Vector2IntegerJomlUniform(int location, Supplier<Vector2i> value) {
this(location, value, null);
}

Vector2IntegerJomlUniform(int location, Supplier<Vector2i> value, ValueUpdateNotifier notifier) {
super(location, notifier);

this.cachedValue = null;
this.value = value;
}

@Override
public void update() {
updateValue();

if (notifier != null) {
notifier.setListener(this::updateValue);
}
}

private void updateValue() {
Vector2i newValue = value.get();

if (cachedValue == null || !newValue.equals(cachedValue)) {
cachedValue = newValue;
GL20.glUniform2i(this.location, newValue.x, newValue.y);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package net.coderbot.iris.mixin;

import com.mojang.blaze3d.platform.GlStateManager;
import net.coderbot.iris.gl.state.StateUpdateNotifiers;
import net.coderbot.iris.samplers.TextureAtlasTracker;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.nio.IntBuffer;

@Mixin(GlStateManager.class)
public class MixinGlStateManager_AtlasTracking {
private static Runnable atlasTextureListener;

@Shadow
private static int activeTexture;

@Inject(method = "_texImage2D(IIIIIIIILjava/nio/IntBuffer;)V", at = @At("HEAD"))
private static void iris$onTexImage2D(int target, int level, int internalformat, int width, int height, int border,
int format, int type, @Nullable IntBuffer pixels, CallbackInfo ci) {
TextureAtlasTracker.INSTANCE.trackTexImage2D(GlStateManager.getActiveTextureName(), level, width, height);
}

@Inject(method = "_bindTexture(I)V", at = @At("HEAD"))
private static void iris$onBindTexture(int id, CallbackInfo ci) {
if (activeTexture == 0 && atlasTextureListener != null) {
atlasTextureListener.run();
}
}

@Inject(method = "_deleteTexture(I)V", at = @At("HEAD"))
private static void iris$onDeleteTexture(int id, CallbackInfo ci) {
TextureAtlasTracker.INSTANCE.trackDeleteTextures(id);
}

@Inject(method = "_deleteTextures([I)V", at = @At("HEAD"))
private static void iris$onDeleteTextures(int[] ids, CallbackInfo ci) {
for (int id : ids) {
TextureAtlasTracker.INSTANCE.trackDeleteTextures(id);
}
}

static {
StateUpdateNotifiers.atlasTextureNotifier = listener -> atlasTextureListener = listener;
}
}
50 changes: 16 additions & 34 deletions src/main/java/net/coderbot/iris/mixin/MixinTextureAtlas.java
Original file line number Diff line number Diff line change
@@ -1,57 +1,39 @@
package net.coderbot.iris.mixin;

import com.mojang.blaze3d.systems.RenderSystem;
import net.coderbot.iris.samplers.TextureAtlasTracker;
import net.coderbot.iris.texunits.TextureAtlasInterface;
import net.minecraft.client.renderer.texture.AbstractTexture;
import net.minecraft.client.renderer.texture.Stitcher;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.phys.Vec2;
import org.lwjgl.opengl.GL20C;
import org.spongepowered.asm.mixin.Mixin;
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.CallbackInfoReturnable;

import java.util.List;

@Mixin(TextureAtlas.class)
public abstract class MixinTextureAtlas extends AbstractTexture implements TextureAtlasInterface {
@Unique
private Vec2 atlasSize;

@Inject(method = "getLoadedSprites", at = @At("HEAD"))
private void getAtlasSize(ResourceManager resourceManager, Stitcher stitcher, int i, CallbackInfoReturnable<List<TextureAtlasSprite>> cir) {
this.atlasSize = new Vec2(stitcher.getWidth(), stitcher.getHeight());
@Override
public int getId() {
int id = super.getId();

TextureAtlasTracker.INSTANCE.trackAtlas(id, (TextureAtlas) (Object) this);

return id;
}

@Override
public Vec2 getAtlasSize() {
if (this.atlasSize == null) {
iris$setAtlasSizeFromGlState();
public void setAtlasSize(int sizeX, int sizeY) {
if (sizeX == 0 && sizeY == 0) {
this.atlasSize = Vec2.ZERO;
} else {
this.atlasSize = new Vec2(sizeX, sizeY);
}

return this.atlasSize;
}

@Unique
private void iris$setAtlasSizeFromGlState() {
// support for DashLoader (and other mods which might mess with the other code path)
int glId = this.getId();

// Keep track of what texture was bound before
int existingGlId = GL20C.glGetInteger(GL20C.GL_TEXTURE_BINDING_2D);

// Bind this texture and grab the atlas size from it.
RenderSystem.bindTexture(glId);
int width = GL20C.glGetTexLevelParameteri(GL20C.GL_TEXTURE_2D, 0, GL20C.GL_TEXTURE_WIDTH);
int height = GL20C.glGetTexLevelParameteri(GL20C.GL_TEXTURE_2D, 0, GL20C.GL_TEXTURE_HEIGHT);
this.atlasSize = new Vec2(width, height);

// Make sure to re-bind the previous texture to avoid issues.
RenderSystem.bindTexture(existingGlId);
@Override
public Vec2 getAtlasSize() {
return this.atlasSize;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@ public interface GlStateManagerAccessor {
static GlStateManager.FogState getFOG() {
throw new AssertionError();
}

@Accessor("TEXTURES")
static GlStateManager.TextureState[] getTEXTURES() {
throw new AssertionError();
}
}
81 changes: 81 additions & 0 deletions src/main/java/net/coderbot/iris/samplers/TextureAtlasTracker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package net.coderbot.iris.samplers;

import com.mojang.blaze3d.systems.RenderSystem;
import net.coderbot.iris.texunits.TextureAtlasInterface;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.world.phys.Vec2;
import org.lwjgl.opengl.GL20C;

import java.util.WeakHashMap;

public class TextureAtlasTracker {
public static final TextureAtlasTracker INSTANCE = new TextureAtlasTracker();

private final WeakHashMap<Integer, TextureAtlas> atlases;

private TextureAtlasTracker() {
atlases = new WeakHashMap<>();
}

public void trackAtlas(int id, TextureAtlas atlas) {
TextureAtlas previous = atlases.put(id, atlas);

if (previous != atlas) {
TextureAtlasInterface atlasI = (TextureAtlasInterface) atlas;
atlasI.setAtlasSize(0, 0);
}
}

public void trackTexImage2D(int id, int level, int sizeX, int sizeY) {
if (level != 0) {
return;
}

TextureAtlas atlas = atlases.get(id);

if (atlas != null) {
((TextureAtlasInterface) atlas).setAtlasSize(sizeX, sizeY);
}
}

public Vec2 getAtlasSize(int id) {
TextureAtlas atlas = atlases.get(id);
Vec2 size = Vec2.ZERO;

if (atlas != null) {
size = ((TextureAtlasInterface) atlas).getAtlasSize();

if (Vec2.ZERO.equals(size)) {
fetchAtlasSizeFromGlState(atlas);
size = ((TextureAtlasInterface) atlas).getAtlasSize();
}
}

return size;
}

public void trackDeleteTextures(int id) {
atlases.remove(id);
}

/**
* Fallback path to support DashLoader (and other mods which might mess with the other code path)
*
* @author Kroppeb
*/
private void fetchAtlasSizeFromGlState(TextureAtlas atlas) {
// Keep track of what texture was bound before
int existingGlId = GL20C.glGetInteger(GL20C.GL_TEXTURE_BINDING_2D);

// Bind this texture and grab the atlas size from it.
RenderSystem.bindTexture(atlas.getId());
int width = GL20C.glGetTexLevelParameteri(GL20C.GL_TEXTURE_2D, 0, GL20C.GL_TEXTURE_WIDTH);
int height = GL20C.glGetTexLevelParameteri(GL20C.GL_TEXTURE_2D, 0, GL20C.GL_TEXTURE_HEIGHT);

TextureAtlasInterface atlasI = (TextureAtlasInterface) atlas;
atlasI.setAtlasSize(width, height);

// Make sure to re-bind the previous texture to avoid issues.
RenderSystem.bindTexture(existingGlId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
import net.minecraft.world.phys.Vec2;

public interface TextureAtlasInterface {
void setAtlasSize(int sizeX, int sizeY);
Vec2 getAtlasSize();
}
24 changes: 15 additions & 9 deletions src/main/java/net/coderbot/iris/uniforms/CommonUniforms.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@
import java.util.Objects;
import java.util.function.IntSupplier;

import net.coderbot.iris.gl.state.StateUpdateNotifiers;
import net.coderbot.iris.gl.uniform.DynamicUniformHolder;
import net.coderbot.iris.gl.uniform.UniformHolder;
import net.coderbot.iris.layer.EntityColorRenderStateShard;
import net.coderbot.iris.mixin.statelisteners.GlStateManagerAccessor;
import net.coderbot.iris.samplers.TextureAtlasTracker;
import net.coderbot.iris.shaderpack.IdMap;
import net.coderbot.iris.shaderpack.PackDirectives;
import net.coderbot.iris.texunits.TextureAtlasInterface;
import net.coderbot.iris.uniforms.transforms.SmoothedFloat;
import net.coderbot.iris.uniforms.transforms.SmoothedVec2f;
import net.coderbot.iris.vendored.joml.Vector2i;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.core.BlockPos;
import net.minecraft.tags.FluidTags;
import net.minecraft.world.InteractionHand;
Expand Down Expand Up @@ -70,6 +72,16 @@ public static void addCommonUniforms(DynamicUniformHolder uniforms, IdMap idMap,
return new Vector4f(0.0f, 0.0f, 0.0f, 0.0f);
}, EntityColorRenderStateShard.getUpdateNotifier());

// TODO: OptiFine doesn't think that atlasSize is a "dynamic" uniform,
// but we do. How will custom uniforms depending on atlasSize work?
uniforms.uniform2i("atlasSize", () -> {
int glId = GlStateManagerAccessor.getTEXTURES()[0].binding;

Vec2 atlasSize = TextureAtlasTracker.INSTANCE.getAtlasSize(glId);

return new Vector2i((int) atlasSize.x, (int) atlasSize.y);
}, StateUpdateNotifiers.atlasTextureNotifier);

CommonUniforms.generalCommonUniforms(uniforms, updateNotifier);
}

Expand All @@ -93,13 +105,7 @@ public static void generalCommonUniforms(UniformHolder uniforms, FrameUpdateNoti
// TODO: Parse the value of const float wetnessHalfLife and const float drynessHalfLife from the shaderpack's fragment shader configuration
.uniform1f(PER_TICK, "wetness", new SmoothedFloat(600f, CommonUniforms::getRainStrength, updateNotifier))
.uniform3d(PER_FRAME, "skyColor", CommonUniforms::getSkyColor)
.uniform3d(PER_FRAME, "fogColor", CapturedRenderingState.INSTANCE::getFogColor)
.uniform2i(ONCE, "atlasSize", CommonUniforms::getAtlasSize);
}

private static Vec2 getAtlasSize() {
// TODO: is the block atlas used for this uniform all the time???
return ((TextureAtlasInterface) Minecraft.getInstance().getModelManager().getAtlas(TextureAtlas.LOCATION_BLOCKS)).getAtlasSize();
.uniform3d(PER_FRAME, "fogColor", CapturedRenderingState.INSTANCE::getFogColor);
}

private static Vec3 getSkyColor() {
Expand Down
5 changes: 3 additions & 2 deletions src/main/resources/iris.accesswidener
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
accessWidener v1 named
accessible class com/mojang/blaze3d/platform/GlStateManager$FogState
accessWidener v1 named
accessible class com/mojang/blaze3d/platform/GlStateManager$FogState
accessible class com/mojang/blaze3d/platform/GlStateManager$TextureState
1 change: 1 addition & 0 deletions src/main/resources/mixins.iris.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"MixinGameRenderer",
"MixinGlStateManager",
"MixinGlStateManager_AmdCrashFix",
"MixinGlStateManager_AtlasTracking",
"MixinLevelRenderer",
"MixinLivingEntityRenderer",
"MixinMinecraft",
Expand Down

0 comments on commit fcd6275

Please sign in to comment.