Skip to content

Commit

Permalink
Item Renderer Optimization (#741)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cleptomania authored Nov 20, 2024
1 parent 81a000a commit c34d854
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,5 @@
* Embeddedt and Ferri_Arnus for [glsl-transformation-lib](https://github.com/TauMC/glsl-transformation-lib)
* Also for work on [Monocle](https://github.com/ferriarnus/Monocle) which was used as a reference for implementing glsl-transformation-lib
* Code from both glsl-transformation-lib and Monocle taken under their respective LGPL 3.0 licenses
* FalseTweaks
* FalsePattern for [FalseTweaks](https://github.com/falsepattern/falsetweaks) - Item Rendering Optimizations taken from FalseTweaks under the LGPL 3.0 license
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,15 @@ public class AngelicaConfig {
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
public static boolean enableZoom;

@Config.Comment("Optimizes in-world item rendering")
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
public static boolean optimizeInWorldItemRendering;

@Config.Comment("Max amount of display lists to cache for optimized item rendering. Higher number will use more VRAM")
@Config.DefaultInt(256)
@Config.RangeInt(min = 64, max = 1024)
public static int itemRendererDisplayListCacheSize;

}
5 changes: 5 additions & 0 deletions src/main/java/com/gtnewhorizons/angelica/mixins/Mixins.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ public enum Mixins {
.setApplyIf(() -> AngelicaConfig.dynamicItemRenderDistance)
.addTargetedMod(TargetedMod.VANILLA)),

ANGELICA_ITEM_DISPLAY_LIST_OPTIMIZATION(new Builder("Optimized item rendering by wrapping them with display lists")
.setPhase(Phase.EARLY).addMixinClasses("angelica.itemrenderer.MixinItemRenderer").setSide(Side.CLIENT)
.setApplyIf(() -> AngelicaConfig.optimizeInWorldItemRendering)
.addTargetedMod(TargetedMod.VANILLA)),

// Not compatible with the lwjgl debug callbacks, so disable if that's enabled
ARCHAIC_SPLASH(new Builder("ArchaicFix Splash").addTargetedMod(TargetedMod.VANILLA).setSide(Side.CLIENT)
.setPhase(Phase.EARLY).setApplyIf(() -> AngelicaConfig.showSplashMemoryBar && !AngelicaMod.lwjglDebug).addMixinClasses(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* This file is part of FalseTweaks.
*
* Copyright (C) 2022-2024 FalsePattern
* All Rights Reserved
*
* Modifications by Angelica in accordance with LGPL v3.0
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* FalseTweaks is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FalseTweaks is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FalseTweaks. If not, see <https://www.gnu.org/licenses/>.
*/

package com.gtnewhorizons.angelica.rendering;

import com.gtnewhorizons.angelica.config.AngelicaConfig;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.val;
import org.lwjgl.opengl.GL11;

import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ItemRenderListManager implements IResourceManagerReloadListener {
public static final ItemRenderListManager INSTANCE = new ItemRenderListManager();

private final Map<ItemProp, Integer> theMap = new HashMap<>();
private final List<ItemProp> propList = new ArrayList<>();
private final ItemProp prop = new ItemProp();
private int list = 0;

public boolean pre(float a, float b, float c, float d, int e, int f, float g) {
prop.set(a, b, c, d, e, f, g);
if (theMap.containsKey(prop)) {
val list = theMap.get(prop);
propList.add(propList.remove(propList.indexOf(prop)));
GL11.glCallList(list);
return true;
} else {
if (propList.size() >= AngelicaConfig.itemRendererDisplayListCacheSize) {
val oldProp = propList.remove(0);
GLAllocation.deleteDisplayLists(theMap.remove(oldProp));
}
list = GLAllocation.generateDisplayLists(1);
val newProp = new ItemProp(prop);
theMap.put(newProp, list);
propList.add(newProp);
GL11.glNewList(list, GL11.GL_COMPILE);
return false;
}
}

public void post() {
GL11.glEndList();
GL11.glCallList(list);
}

@Override
public void onResourceManagerReload(IResourceManager p_110549_1_) {
propList.clear();
theMap.forEach((key, value) -> GLAllocation.deleteDisplayLists(value));
theMap.clear();
}

@NoArgsConstructor
@Data
public class ItemProp {
private float a;
private float b;
private float c;
private float d;
private int e;
private int f;
private float g;

public ItemProp(ItemProp old) {
set(old.a, old.b, old.c, old.d, old.e, old.f, old.g);
}

public void set(float a, float b, float c, float d, int e, int f, float g) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.e = e;
this.f = f;
this.g = g;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,17 @@ public static OptionPage advanced() {
)
.build());

groups.add(OptionGroup.createBuilder()
.add(OptionImpl.createBuilder(int.class, angelicaOpts)
.setName(I18n.format("options.angelica.itemdisplaylistcount"))
.setTooltip(I18n.format("options.angelica.itemdisplaylistcount.tooltip"))
.setControl(o -> new SliderControl(o, 0, 1024, 1, ControlValueFormatter.number()))
.setImpact(OptionImpact.MEDIUM)
.setBinding((opts, value) -> AngelicaConfig.itemRendererDisplayListCacheSize = value, options -> AngelicaConfig.itemRendererDisplayListCacheSize)
.build()
)
.build());

groups.add(OptionGroup.createBuilder()
.add(Settings.MODE_GUI_BACKGROUND.option)
.add(Settings.GUI_BACKGROUND.option)
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/assets/angelica/lang/en_US.lang
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ options.dynamic_lights_shader_force=Dynamic Lights - Forced With Shaders
options.dynamic_lights_shader_force.tooltip=Enabled - Dynamic Lights are shown even when a shader is active, Disabled - Dynamic Lights are disabled when a shader is active.
options.angelica.droppedItemLimit=Dropped Item Render Limit
options.angelica.droppedItemLimit.tooltip=The maximum number of dropped items that will be rendered. Lower values can improve performance.
options.angelica.itemdisplaylistcount=Item Renderer Display List Cache Size
options.angelica.itemdisplaylistcount.tooltip=The maximum number of display lists to cache in the optimized item renderer. Higher values will increase performance but increase VRAM usage.
pack.iris.select.title=Select
pack.iris.configure.title=Configure
label.iris.true=On
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* This file is part of FalseTweaks.
*
* Copyright (C) 2022-2024 FalsePattern
* All Rights Reserved
*
* Modifications by Angelica in accordance with LGPL v3.0
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* FalseTweaks is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FalseTweaks is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FalseTweaks. If not, see <https://www.gnu.org/licenses/>.
*/

package com.gtnewhorizons.angelica.mixins.early.angelica.itemrenderer;

import com.gtnewhorizons.angelica.rendering.ItemRenderListManager;
import lombok.SneakyThrows;
import net.minecraft.client.renderer.ItemRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import net.minecraft.client.renderer.Tessellator;

@Mixin(ItemRenderer.class)
public abstract class MixinItemRenderer {
@SneakyThrows
@Inject(method = "renderItemIn2D",
at = @At("HEAD"),
cancellable = true,
require = 1)
private static void leFunnyRenderListStart(Tessellator tess, float a, float b, float c, float d, int e, int f, float g, CallbackInfo ci) {
if (ItemRenderListManager.INSTANCE.pre(a, b, c, d, e, f, g)) {
ci.cancel();
}
}

@Inject(method = "renderItemIn2D",
at = @At("RETURN"),
require = 1)
private static void leFunnyRenderListEnd(Tessellator tess, float a, float b, float c, float d, int e, int f, float g, CallbackInfo ci) {
ItemRenderListManager.INSTANCE.post();
}

@Redirect(method = "renderItemIn2D",
slice = @Slice(from = @At(value = "INVOKE",
target = "Lnet/minecraft/client/renderer/Tessellator;draw()I",
ordinal = 0),
to = @At(value = "INVOKE",
target = "Lnet/minecraft/client/renderer/Tessellator;startDrawingQuads()V",
ordinal = 5)),
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/renderer/Tessellator;draw()I"),
require = 5)
private static int batchDrawCalls1(Tessellator instance) {
return 0;
}

@Redirect(method = "renderItemIn2D",
slice = @Slice(from = @At(value = "INVOKE",
target = "Lnet/minecraft/client/renderer/Tessellator;draw()I",
ordinal = 0),
to = @At(value = "INVOKE",
target = "Lnet/minecraft/client/renderer/Tessellator;startDrawingQuads()V",
ordinal = 5)),
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/renderer/Tessellator;startDrawingQuads()V"),
require = 5)
private static void batchDrawCalls2(Tessellator instance) {

}
}

0 comments on commit c34d854

Please sign in to comment.