diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index ca06060b5..8bede29e4 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -24,6 +24,8 @@ import net.minecraft.util.math.vector.Matrix4f; import net.minecraft.world.IWorld; import net.minecraft.world.World; +import javax.annotation.Nullable; + public class Backend { public static final Logger log = LogManager.getLogger(Backend.class); @@ -175,8 +177,14 @@ public class Backend { /** * Used to avoid calling Flywheel functions on (fake) worlds that don't specifically support it. */ - public static boolean isFlywheelWorld(IWorld world) { - return (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel()) || world == Minecraft.getInstance().world; + public static boolean isFlywheelWorld(@Nullable IWorld world) { + if (world == null) + return false; + + if (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel()) + return true; + + return world == Minecraft.getInstance().world; } public static boolean isGameActive() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java b/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java index 9cbfe3d54..086169c72 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java +++ b/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java @@ -58,6 +58,7 @@ public abstract class ShaderContext

implements IShaderConte @Override public void delete() { programs.values().forEach(IMultiProgram::delete); + programs.clear(); } /** diff --git a/src/main/java/com/jozufozu/flywheel/backend/ShaderSources.java b/src/main/java/com/jozufozu/flywheel/backend/ShaderSources.java index 03fa61d27..d4af509c9 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/ShaderSources.java +++ b/src/main/java/com/jozufozu/flywheel/backend/ShaderSources.java @@ -19,6 +19,15 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; +import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.event.ForgeEvents; + +import net.minecraft.client.Minecraft; + +import net.minecraft.client.world.ClientWorld; + +import net.minecraftforge.event.world.WorldEvent; + import org.lwjgl.system.MemoryUtil; import com.google.common.collect.Lists; @@ -89,9 +98,14 @@ public class ShaderSources implements ISelectiveResourceReloadListener { } Backend.log.info("Loaded all shader programs."); - + // no need to hog all that memory shaderSource.clear(); + + ClientWorld world = Minecraft.getInstance().world; + if (Backend.isFlywheelWorld(world)) { + InstancedRenderDispatcher.loadAllInWorld(world); + } } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlObject.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlObject.java index d07872204..801a93cd8 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/GlObject.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlObject.java @@ -18,7 +18,9 @@ public abstract class GlObject { protected final void checkHandle() { if (!this.isHandleValid()) { - throw new IllegalStateException("Handle is not valid"); + String descriptor = getDescriptor(); + String message = (descriptor == null ? "" : (descriptor + " ")) + "handle is not valid."; + throw new IllegalStateException(message); } } @@ -32,7 +34,9 @@ public abstract class GlObject { public void delete() { if (!isHandleValid()) { - throw new IllegalStateException("Handle already deleted."); + String descriptor = getDescriptor(); + String message = (descriptor == null ? "" : (descriptor + " ")) + "handle already deleted."; + throw new IllegalStateException(message); } deleteInternal(handle); @@ -40,4 +44,8 @@ public abstract class GlObject { } protected abstract void deleteInternal(int handle); + + protected String getDescriptor() { + return ""; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java index e62ba84df..73aadabff 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java @@ -74,4 +74,8 @@ public abstract class GlProgram extends GlObject { glDeleteProgram(handle); } + @Override + public String toString() { + return "program " + name; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java index 250880e61..5f42395ff 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java @@ -37,7 +37,7 @@ public abstract class InstanceManager implements MaterialManager.OriginShiftL this.dynamicInstances = new Object2ObjectOpenHashMap<>(); this.tickableInstances = new Object2ObjectOpenHashMap<>(); - materialManager.onOriginShift(this); + materialManager.addListener(this); } public void tick(double cameraX, double cameraY, double cameraZ) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java index cbe2028b7..e1c7bab74 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -40,7 +40,6 @@ import net.minecraft.util.LazyValue; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Matrix4f; import net.minecraft.world.IWorld; -import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.event.TickEvent; @@ -124,15 +123,7 @@ public class InstancedRenderDispatcher { public static void onReloadRenderers(ReloadRenderersEvent event) { ClientWorld world = event.getWorld(); if (Backend.getInstance().canUseInstancing() && world != null) { - Contexts.WORLD.getMaterialManager(world).delete(); - - TileInstanceManager tiles = getTiles(world); - tiles.invalidate(); - world.loadedTileEntityList.forEach(tiles::add); - - EntityInstanceManager entities = getEntities(world); - entities.invalidate(); - world.getAllEntities().forEach(entities::add); + loadAllInWorld(world); } } @@ -188,4 +179,14 @@ public class InstancedRenderDispatcher { if (breaking != null) glBindTexture(GL_TEXTURE_2D, breaking.getGlTextureId()); } + + public static void loadAllInWorld(ClientWorld world) { + Contexts.WORLD.getMaterialManager(world).delete(); + + TileInstanceManager tiles = tileInstanceManager.replace(world); + world.loadedTileEntityList.forEach(tiles::add); + + EntityInstanceManager entities = entityInstanceManager.replace(world); + world.getAllEntities().forEach(entities::add); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialManager.java index 96c18077e..dcaaa1b12 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialManager.java @@ -91,8 +91,11 @@ public class MaterialManager

{ public void delete() { atlasMaterials.values().forEach(InstanceMaterial::delete); - materials.values().stream().flatMap(m -> m.values().stream()).forEach(InstanceMaterial::delete); + + atlasMaterials.clear(); + atlasRenderers.clear(); + materials.clear(); } @SuppressWarnings("unchecked") @@ -131,7 +134,7 @@ public class MaterialManager

{ return originCoordinate; } - public void onOriginShift(OriginShiftListener listener) { + public void addListener(OriginShiftListener listener) { listeners.add(listener); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/package-info.java new file mode 100644 index 000000000..027f3e6a3 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend; + +import mcp.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java index 1aff5eee7..d0694b649 100644 --- a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java @@ -21,7 +21,6 @@ import com.jozufozu.flywheel.backend.loading.Shader; import com.jozufozu.flywheel.backend.loading.ShaderLoadingException; import com.jozufozu.flywheel.backend.loading.ShaderTransformer; import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram; -import com.jozufozu.flywheel.core.shader.IMultiProgram; import com.jozufozu.flywheel.core.shader.StateSensitiveMultiProgram; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.util.WorldAttached; @@ -38,7 +37,7 @@ public class WorldContext

extends ShaderContext

{ protected Supplier> specStream; protected TemplateFactory templateFactory; - private final WorldAttached> materialManager = new WorldAttached<>($ -> new MaterialManager<>(this)); + private final WorldAttached> worldAttachedMMs = new WorldAttached<>($ -> new MaterialManager<>(this)); private final Map builtins = new EnumMap<>(ShaderType.class); private final Map builtinSources = new EnumMap<>(ShaderType.class); @@ -71,7 +70,7 @@ public class WorldContext

extends ShaderContext

{ } public MaterialManager

getMaterialManager(IWorld world) { - return materialManager.get(world); + return worldAttachedMMs.get(world); } public WorldContext

withSpecStream(Supplier> specStream) { @@ -89,8 +88,6 @@ public class WorldContext

extends ShaderContext

{ @Override public void load() { - programs.values().forEach(IMultiProgram::delete); - programs.clear(); Backend.log.info("Loading context '{}'", name); @@ -130,7 +127,7 @@ public class WorldContext

extends ShaderContext

{ public void delete() { super.delete(); - materialManager.forEach(MaterialManager::delete); + worldAttachedMMs.empty(MaterialManager::delete); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/ExtensibleGlProgram.java b/src/main/java/com/jozufozu/flywheel/core/shader/ExtensibleGlProgram.java index 7da1e8b14..9b041680a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/ExtensibleGlProgram.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/ExtensibleGlProgram.java @@ -49,10 +49,19 @@ public class ExtensibleGlProgram extends GlProgram { @Override public String toString() { - return "ExtensibleGlProgram{" + - "name=" + name + - ", extensions=" + extensions + - '}'; + StringBuilder builder = new StringBuilder(); + builder.append("program ") + .append(name) + .append('['); + + for (IExtensionInstance extension : extensions) { + builder.append(extension) + .append('+'); + } + + builder.append(']'); + + return builder.toString(); } /** diff --git a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java index 50b1a4fc9..e4d2abce5 100644 --- a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java +++ b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java @@ -4,8 +4,6 @@ import java.util.ArrayList; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager; -import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager; import net.minecraft.client.Minecraft; import net.minecraft.client.world.ClientWorld; @@ -42,15 +40,8 @@ public class ForgeEvents { IWorld world = event.getWorld(); if (Backend.isFlywheelWorld(world)) { - ClientWorld clientWorld = (ClientWorld) world; - - TileInstanceManager tiles = InstancedRenderDispatcher.getTiles(world); - tiles.invalidate(); - clientWorld.loadedTileEntityList.forEach(tiles::add); - - EntityInstanceManager entities = InstancedRenderDispatcher.getEntities(world); - entities.invalidate(); - clientWorld.getAllEntities().forEach(entities::add); + InstancedRenderDispatcher.loadAllInWorld((ClientWorld) world); } } + } diff --git a/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java b/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java index 74531aa96..1be10f4d9 100644 --- a/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java +++ b/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java @@ -2,19 +2,21 @@ package com.jozufozu.flywheel.util; import java.util.HashMap; import java.util.Map; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import net.minecraft.world.IWorld; public class WorldAttached { Map attached; - private final WorldAttacher factory; + private final Function factory; - public WorldAttached(WorldAttacher factory) { + public WorldAttached(Function factory) { this.factory = factory; attached = new HashMap<>(); } @@ -24,7 +26,7 @@ public class WorldAttached { T t = attached.get(world); if (t != null) return t; - T entry = factory.attach(world); + T entry = factory.apply(world); put(world, entry); return entry; } @@ -33,20 +35,46 @@ public class WorldAttached { attached.put(world, entry); } - public void forEach(Consumer consumer) { + /** + * Replaces the entry with a new one from the factory and returns the new entry. + */ + @Nonnull + public T replace(IWorld world) { + attached.remove(world); + + return get(world); + } + + /** + * Replaces the entry with a new one from the factory and returns the new entry. + */ + @Nonnull + public T replace(IWorld world, Consumer finalizer) { + T remove = attached.remove(world); + + finalizer.accept(remove); + + return get(world); + } + + /** + * Deletes all entries after calling a function on them. + * + * @param finalizer Do something with all of the world-value pairs + */ + public void empty(BiConsumer finalizer) { + attached.forEach(finalizer); + attached.clear(); + } + + /** + * Deletes all entries after calling a function on them. + * + * @param finalizer Do something with all of the values + */ + public void empty(Consumer finalizer) { attached.values() - .forEach(consumer); + .forEach(finalizer); + attached.clear(); } - - @FunctionalInterface - public interface WorldAttacher extends Function { - @Nonnull - T attach(IWorld world); - - @Override - default T apply(IWorld world) { - return attach(world); - } - } - }