mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-10-26 14:24:30 +00:00
Thread safe biome cache & VAO Redirection (#1367)
* Thread safe biome cache * VAO Redirection * Delegate GLSM VAO calls to UniversalVAO * Redirect usages of UniversalVAO & LWJGLService VAO functions to GLSM * Avoid infinite recursion
This commit is contained in:
1 parent
bd56ccc4b8
commit
aaab8fd0bc
8 files changed
+82
-23
No files matched your search
+1
-1
@@ -71,7 +71,7 @@ dependencies {
|
||||
|
||||
// Iris Shaders
|
||||
compileOnly('org.jetbrains:annotations:26.0.2')
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.9.9:dev")
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.9.10:dev")
|
||||
|
||||
shadowImplementation("org.anarres:jcpp:1.4.14") // Apache 2.0
|
||||
shadowImplementation("org.taumc:glsl-transformation-lib:0.2.0-26.g5ee7d96-GTNH") {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.opengl.UniversalVAO;
|
||||
import com.mitchej123.glsm.GLStateManagerService;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -149,17 +150,17 @@ public class AngelicaGLStateManagerService implements GLStateManagerService {
|
||||
|
||||
@Override
|
||||
public int glGenVertexArrays() {
|
||||
return GL30.glGenVertexArrays();
|
||||
return UniversalVAO.genVertexArrays();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void glBindVertexArray(int array) {
|
||||
GL30.glBindVertexArray(array);
|
||||
GLStateManager.glBindVertexArray(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void glDeleteVertexArrays(int array) {
|
||||
GL30.glDeleteVertexArrays(array);
|
||||
UniversalVAO.deleteVertexArrays(array);
|
||||
}
|
||||
|
||||
// ===================== BUFFER OPERATIONS =====================
|
||||
|
||||
@@ -58,7 +58,7 @@ import org.joml.Vector3d;
|
||||
import org.joml.Vector3f;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.opengl.APPLEVertexArrayObject;
|
||||
import com.gtnewhorizon.gtnhlib.client.opengl.UniversalVAO;
|
||||
import org.lwjgl.opengl.ARBMultitexture;
|
||||
import org.lwjgl.opengl.ContextCapabilities;
|
||||
import org.lwjgl.opengl.Display;
|
||||
@@ -3778,20 +3778,12 @@ public class GLStateManager {
|
||||
}
|
||||
if (boundVAO != array) {
|
||||
boundVAO = array;
|
||||
GL30.glBindVertexArray(array);
|
||||
UniversalVAO.bindVertexArray(array);
|
||||
}
|
||||
}
|
||||
|
||||
public static void glBindVertexArrayAPPLE(int array) {
|
||||
if (DisplayListManager.isRecording()) {
|
||||
DisplayListManager.recordBindVAO(array);
|
||||
// Since the vao needs to be bound to do stuff like state setup & data upload, it'll still execute the bind call.
|
||||
// This is technically wrong, but I'm not sure if there's a better solution here.
|
||||
}
|
||||
if (boundVAO != array) {
|
||||
boundVAO = array;
|
||||
APPLEVertexArrayObject.glBindVertexArrayAPPLE(array);
|
||||
}
|
||||
glBindVertexArray(array);
|
||||
}
|
||||
|
||||
public static boolean isVBOBound() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.glsm.recording;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vao.VAOManager;
|
||||
import com.gtnewhorizon.gtnhlib.client.opengl.UniversalVAO;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFlags;
|
||||
import com.gtnewhorizons.angelica.glsm.DisplayListManager;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
@@ -519,7 +519,7 @@ public final class CommandBufferExecutor {
|
||||
ptr += 4;
|
||||
}
|
||||
case GLCommand.BIND_VAO -> {
|
||||
VAOManager.VAO.glBindVertexArray(memGetInt(ptr));
|
||||
UniversalVAO.bindVertexArray(memGetInt(ptr));
|
||||
ptr += 4;
|
||||
}
|
||||
|
||||
|
||||
+57
-2
@@ -54,6 +54,18 @@ public final class AngelicaRedirector {
|
||||
private static final String OpenGlHelper = "net/minecraft/client/renderer/OpenGlHelper";
|
||||
private static final String EXTBlendFunc = "org/lwjgl/opengl/EXTBlendFuncSeparate";
|
||||
private static final String ARBMultiTexture = "org/lwjgl/opengl/ARBMultitexture";
|
||||
|
||||
// Redirect VAO related calls from NHLib and LWJGLService
|
||||
private static final String UniversalVAO = "com/gtnewhorizon/gtnhlib/client/opengl/UniversalVAO";
|
||||
private static final String UniversalVAODot = "com.gtnewhorizon.gtnhlib.client.opengl.UniversalVAO";
|
||||
private static final String VaoFunctions = "com/gtnewhorizon/gtnhlib/client/renderer/vao/VaoFunctions";
|
||||
private static final String LWJGLService = "com/mitchej123/lwjgl/LWJGLService";
|
||||
|
||||
// Don't redirect these items inside of UniversalVAO, since we might be delegating to them
|
||||
private static final Set<String> UniversalVAOSkippedMethods = ImmutableSet.of(
|
||||
"glBindVertexArray", "glGenVertexArrays", "glDeleteVertexArrays", "glIsVertexArray"
|
||||
);
|
||||
|
||||
private static final String MinecraftClient = "net.minecraft.client";
|
||||
private static final String SplashProgress = "cpw.mods.fml.client.SplashProgress";
|
||||
private static final Set<String> ExcludedMinecraftMainThreadChecks = ImmutableSet.of(
|
||||
@@ -63,6 +75,7 @@ public final class AngelicaRedirector {
|
||||
|
||||
private static final ClassConstantPoolParser cstPoolParser = new ClassConstantPoolParser(GL11, GL12, GL13, GL14, GL20, OpenGlHelper, EXTBlendFunc, ARBMultiTexture, Project);
|
||||
private static final Map<String, Map<String, String>> methodRedirects = new HashMap<>();
|
||||
private static final Map<String, Map<String, String>> interfaceRedirects = new HashMap<>();
|
||||
private static final Map<Integer, String> glCapRedirects = new HashMap<>();
|
||||
|
||||
static {
|
||||
@@ -270,12 +283,29 @@ public final class AngelicaRedirector {
|
||||
|
||||
// APPLE
|
||||
methodRedirects.put(APPLEVertexArrayObject, RedirectMap.newMap()
|
||||
.add("glBindVertexArrayAPPLE")
|
||||
.add("glBindVertexArrayAPPLE", "glBindVertexArray")
|
||||
);
|
||||
|
||||
// GTNHLib VAO
|
||||
methodRedirects.put(UniversalVAO, RedirectMap.newMap()
|
||||
.add("bindVertexArray", "glBindVertexArray")
|
||||
);
|
||||
|
||||
// OTHER
|
||||
methodRedirects.put(Project, RedirectMap.newMap().add("gluPerspective"));
|
||||
|
||||
// Interface/virtual redirects — callers invoke these on a receiver object
|
||||
interfaceRedirects.put(VaoFunctions, RedirectMap.newMap()
|
||||
.add("glBindVertexArray")
|
||||
);
|
||||
interfaceRedirects.put(LWJGLService, RedirectMap.newMap()
|
||||
.add("glBindVertexArray")
|
||||
);
|
||||
|
||||
cstPoolParser.addString(UniversalVAO);
|
||||
cstPoolParser.addString(VaoFunctions);
|
||||
cstPoolParser.addString(LWJGLService);
|
||||
|
||||
final String glPrefix = "org/lwjgl/opengl/GL";
|
||||
for (var entry : new HashMap<>(methodRedirects).entrySet()) {
|
||||
if (entry.getKey().startsWith(glPrefix)) {
|
||||
@@ -356,7 +386,8 @@ public final class AngelicaRedirector {
|
||||
final Map<String, String> redirects = methodRedirects.get(mNode.owner);
|
||||
if (redirects != null) {
|
||||
final String glsmName = redirects.get(mNode.name);
|
||||
if (glsmName != null) {
|
||||
// Skip VAO method redirects inside UniversalVAO
|
||||
if (glsmName != null && !(transformedName.startsWith(UniversalVAODot) && UniversalVAOSkippedMethods.contains(glsmName))) {
|
||||
if (LOG_SPAM) {
|
||||
final String shortOwner = mNode.owner.substring(mNode.owner.lastIndexOf("/") + 1);
|
||||
LOGGER.info("Redirecting call in {} from {}.{}{} to GLStateManager.{}{}", transformedName, shortOwner, mNode.name, mNode.desc, glsmName, mNode.desc);
|
||||
@@ -367,6 +398,30 @@ public final class AngelicaRedirector {
|
||||
redirectInMethod = true;
|
||||
}
|
||||
}
|
||||
// Interface/virtual redirects: rewrite receiver-based calls to static GLStateManager calls
|
||||
if ((mNode.getOpcode() == Opcodes.INVOKEINTERFACE || mNode.getOpcode() == Opcodes.INVOKEVIRTUAL) && mNode.desc.equals("(I)V")) {
|
||||
final Map<String, String> ifaceRedirects = interfaceRedirects.get(mNode.owner);
|
||||
if (ifaceRedirects != null) {
|
||||
final String glsmName = ifaceRedirects.get(mNode.name);
|
||||
if (glsmName != null && !(transformedName.startsWith(UniversalVAODot) && UniversalVAOSkippedMethods.contains(glsmName))) {
|
||||
if (LOG_SPAM) {
|
||||
final String shortOwner = mNode.owner.substring(mNode.owner.lastIndexOf("/") + 1);
|
||||
LOGGER.info("Redirecting interface call in {} from {}.{}{} to GLStateManager.{}{}", transformedName, shortOwner, mNode.name, mNode.desc, glsmName, "(I)V");
|
||||
}
|
||||
// Stack is: [receiver, int_arg]. We need just [int_arg] for static call.
|
||||
// Insert SWAP + POP before the call to remove the receiver.
|
||||
mn.instructions.insertBefore(mNode, new InsnNode(Opcodes.SWAP));
|
||||
mn.instructions.insertBefore(mNode, new InsnNode(Opcodes.POP));
|
||||
mNode.setOpcode(Opcodes.INVOKESTATIC);
|
||||
mNode.owner = GLStateManager;
|
||||
mNode.name = glsmName;
|
||||
mNode.desc = "(I)V";
|
||||
mNode.itf = false;
|
||||
changed = true;
|
||||
redirectInMethod = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -28,9 +28,9 @@ public class AngelicaMainThreadMeshingTask extends AngelicaChunkBuilderMeshingTa
|
||||
final int minZ = this.render.getOriginZ();
|
||||
|
||||
final var world = Minecraft.getMinecraft().theWorld;
|
||||
this.blockAccess = new ChunkCache(world, minX - 1, minY - 1, minZ - 1, minX + 17, minY + 17, minZ + 17, 1);
|
||||
this.biomeColorCache = ((WorldClientExtension) world).celeritas$getSmoothBiomeColorCache();
|
||||
this.biomeColorCache.update(new SectionPos(this.render.getChunkX(), this.render.getChunkY(), this.render.getChunkZ()));
|
||||
this.blockAccess = new ChunkCache(world, minX - 1, minY - 1, minZ - 1, minX + 17, minY + 17, minZ + 17, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-3
@@ -54,15 +54,14 @@ public class ThreadedAngelicaChunkBuilderMeshingTask extends AngelicaChunkBuilde
|
||||
final WorldSlice worldSlice = buildContext.getWorldSlice();
|
||||
worldSlice.copyData(this.renderContext);
|
||||
this.blockAccess = worldSlice;
|
||||
this.biomeColorCache = new SmoothBiomeColorCache(worldSlice);
|
||||
this.biomeColorCache.update(new SectionPos(this.render.getChunkX(), this.render.getChunkY(), this.render.getChunkZ()));
|
||||
this.biomeColorCache = worldSlice.getBiomeColorCache();
|
||||
buildContext.setupLightPipeline(minX, minY, minZ);
|
||||
} else {
|
||||
// Fallback: direct world access (main thread only)
|
||||
final var world = Minecraft.getMinecraft().theWorld;
|
||||
this.blockAccess = new ChunkCache(world, minX - 1, minY - 1, minZ - 1, minX + 17, minY + 17, minZ + 17, 1);
|
||||
this.biomeColorCache = ((WorldClientExtension) world).celeritas$getSmoothBiomeColorCache();
|
||||
this.biomeColorCache.update(new SectionPos(this.render.getChunkX(), this.render.getChunkY(), this.render.getChunkZ()));
|
||||
this.blockAccess = new ChunkCache(world, minX - 1, minY - 1, minZ - 1, minX + 17, minY + 17, minZ + 17, 1);
|
||||
buildContext.setupLightPipeline(this.blockAccess, minX, minY, minZ);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,13 @@ import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.CompatMathHelper;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.IDynamicLightSource;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.SmoothBiomeColorCache;
|
||||
|
||||
import java.util.List;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.cloned.ChunkRenderContext;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.cloned.ClonedChunkSection;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.cloned.ClonedChunkSectionCache;
|
||||
import org.embeddedt.embeddium.impl.util.position.SectionPos;
|
||||
import cpw.mods.fml.common.Optional;
|
||||
import mega.fluidlogged.api.FLBlockAccess;
|
||||
import net.minecraft.block.Block;
|
||||
@@ -98,6 +100,8 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
|
||||
private ChunkSectionPos origin;
|
||||
private StructureBoundingBox volume;
|
||||
|
||||
private final SmoothBiomeColorCache biomeColorCache;
|
||||
|
||||
private List<IDynamicLightSource> chunkLightSources;
|
||||
private DynamicLights dynamicLightsInstance;
|
||||
|
||||
@@ -175,6 +179,8 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.biomeColorCache = new SmoothBiomeColorCache(this);
|
||||
}
|
||||
|
||||
public void copyData(ChunkRenderContext context) {
|
||||
@@ -182,6 +188,8 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
|
||||
this.sections = context.getSections();
|
||||
this.volume = context.getVolume();
|
||||
|
||||
this.biomeColorCache.update(new SectionPos(origin.x, origin.y, origin.z));
|
||||
|
||||
this.baseX = (this.origin.x - NEIGHBOR_CHUNK_RADIUS) << 4;
|
||||
this.baseY = (this.origin.y - NEIGHBOR_CHUNK_RADIUS) << 4;
|
||||
this.baseZ = (this.origin.z - NEIGHBOR_CHUNK_RADIUS) << 4;
|
||||
@@ -221,6 +229,10 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
|
||||
return this.origin;
|
||||
}
|
||||
|
||||
public SmoothBiomeColorCache getBiomeColorCache() {
|
||||
return this.biomeColorCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightBrightnessForSkyBlocks(int x, int y, int z, int min) {
|
||||
if (y < 0 || y >= 256 || x < -30_000_000 || z < -30_000_000 || x >= 30_000_000 || z >= 30_000_000) {
|
||||
|
||||
Reference in new issue
Block a user