diff --git a/src/main/java/com/jozufozu/flywheel/FlywheelClient.java b/src/main/java/com/jozufozu/flywheel/FlywheelClient.java
index d3a46a9a7..9846813f7 100644
--- a/src/main/java/com/jozufozu/flywheel/FlywheelClient.java
+++ b/src/main/java/com/jozufozu/flywheel/FlywheelClient.java
@@ -5,9 +5,12 @@ import com.jozufozu.flywheel.core.Contexts;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.core.StitchedSprite;
+import com.jozufozu.flywheel.core.compile.ProgramCompiler;
+import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.mixin.PausedPartialTickAccessor;
import com.jozufozu.flywheel.vanilla.VanillaInstances;
+import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.CrashReportCallables;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
@@ -29,6 +32,8 @@ public class FlywheelClient {
modEventBus.addListener(StitchedSprite::onTextureStitchPre);
modEventBus.addListener(StitchedSprite::onTextureStitchPost);
+ MinecraftForge.EVENT_BUS.addListener(ProgramCompiler::invalidateAll);
+
VanillaInstances.init();
// https://github.com/Jozufozu/Flywheel/issues/69
diff --git a/src/main/java/com/jozufozu/flywheel/backend/RenderLayer.java b/src/main/java/com/jozufozu/flywheel/backend/RenderLayer.java
index 615187b43..3f5a6dcaa 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/RenderLayer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/RenderLayer.java
@@ -38,7 +38,7 @@ public enum RenderLayer {
;
@Nullable
- public static RenderLayer fromRenderType(RenderType type) {
+ public static RenderLayer getPrimaryLayer(RenderType type) {
if (type == RenderType.solid()) {
return SOLID;
} else if (type == RenderType.cutoutMipped()) {
@@ -49,4 +49,17 @@ public enum RenderLayer {
return null;
}
+
+ @Nullable
+ public static RenderLayer getLayer(RenderType type) {
+ if (type == RenderType.solid()) {
+ return SOLID;
+ } else if (type == RenderType.cutoutMipped() || type == RenderType.cutout()) {
+ return CUTOUT;
+ } else if (type == RenderType.translucent()) {
+ return TRANSPARENT;
+ }
+
+ return null;
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java
index 5d0e20bd2..8705da724 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java
@@ -151,11 +151,17 @@ public class GPUInstancer extends AbstractInstancer {
final StructWriter writer = instancedType.getWriter(mapped);
+ boolean sequential = true;
for (int i = 0; i < size; i++) {
final D element = data.get(i);
if (element.checkDirtyAndClear()) {
- writer.seek(i);
+ if (!sequential) {
+ writer.seek(i);
+ }
writer.write(element);
+ sequential = true;
+ } else {
+ sequential = false;
}
}
} catch (Exception e) {
diff --git a/src/main/java/com/jozufozu/flywheel/backend/struct/BufferWriter.java b/src/main/java/com/jozufozu/flywheel/backend/struct/BufferWriter.java
index 0033496b3..31a23c472 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/struct/BufferWriter.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/struct/BufferWriter.java
@@ -33,6 +33,6 @@ public abstract class BufferWriter implements StructWriter {
@Override
public void seek(int pos) {
- backingBuffer.position(pos * stride);
+ backingBuffer.position(pos * stride);
}
}
diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java b/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java
new file mode 100644
index 000000000..d6a3b8bed
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java
@@ -0,0 +1,16 @@
+package com.jozufozu.flywheel.core.compile;
+
+import com.jozufozu.flywheel.backend.gl.GLSLVersion;
+import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
+
+public class CompileUtil {
+
+ protected static String generateHeader(GLSLVersion version, ShaderType type) {
+ return "#version "
+ + version
+ + '\n'
+ + "#extension GL_ARB_explicit_attrib_location : enable\n"
+ + "#extension GL_ARB_conservative_depth : enable\n"
+ + type.getDefineStatement();
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java
new file mode 100644
index 000000000..80d8b2229
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java
@@ -0,0 +1,44 @@
+package com.jozufozu.flywheel.core.compile;
+
+import com.jozufozu.flywheel.backend.gl.shader.GlShader;
+import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
+import com.jozufozu.flywheel.backend.source.FileResolution;
+import com.jozufozu.flywheel.backend.source.SourceFile;
+import com.jozufozu.flywheel.core.shader.ProgramSpec;
+
+public class FragmentCompiler extends Memoizer {
+ private final FileResolution header;
+ private final Template fragment;
+
+ public FragmentCompiler(Template fragment, FileResolution header) {
+ this.header = header;
+ this.fragment = fragment;
+ }
+
+ @Override
+ protected GlShader _create(ProgramContext key) {
+ ProgramSpec spec = key.spec();
+ SourceFile fragmentFile = spec.getFragmentFile();
+ FragmentTemplateData appliedTemplate = fragment.apply(fragmentFile);
+
+ StringBuilder builder = new StringBuilder();
+
+ builder.append(CompileUtil.generateHeader(fragment.getVersion(), ShaderType.FRAGMENT));
+
+ key.getShaderConstants().writeInto(builder);
+
+ FileIndexImpl index = new FileIndexImpl();
+
+ header.getFile().generateFinalSource(index, builder);
+ fragmentFile.generateFinalSource(index, builder);
+
+ builder.append(appliedTemplate.generateFooter());
+
+ return new GlShader(spec.name, ShaderType.FRAGMENT, builder.toString());
+ }
+
+ @Override
+ protected void _destroy(GlShader value) {
+ value.delete();
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/Memoizer.java b/src/main/java/com/jozufozu/flywheel/core/compile/Memoizer.java
new file mode 100644
index 000000000..f2dbc95f1
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/core/compile/Memoizer.java
@@ -0,0 +1,22 @@
+package com.jozufozu.flywheel.core.compile;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class Memoizer {
+
+ private final Map map = new HashMap<>();
+
+ public V get(K key) {
+ return map.computeIfAbsent(key, this::_create);
+ }
+
+ public void invalidate() {
+ map.values().forEach(this::_destroy);
+ map.clear();
+ }
+
+ protected abstract V _create(K key);
+
+ protected abstract void _destroy(V value);
+}
diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java
index d08745fcd..cce67bd8d 100644
--- a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java
+++ b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java
@@ -1,13 +1,12 @@
package com.jozufozu.flywheel.core.compile;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Function;
+import java.util.ArrayList;
+import java.util.List;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
-import com.jozufozu.flywheel.backend.gl.shader.GlShader;
import com.jozufozu.flywheel.backend.source.FileResolution;
import com.jozufozu.flywheel.core.Templates;
+import com.jozufozu.flywheel.event.ReloadRenderersEvent;
/**
* A caching compiler.
@@ -17,18 +16,20 @@ import com.jozufozu.flywheel.core.Templates;
* compiled programs, and will only compile a program if it is not already in the cache.
*
*/
-public class ProgramCompiler {
+public class ProgramCompiler
extends Memoizer {
- protected final Map cache = new HashMap<>();
+ private static final List> ALL_COMPILERS = new ArrayList<>();
private final GlProgram.Factory factory;
- private final Function vertexCompiler;
- private final Function fragmentCompiler;
+ private final VertexCompiler vertexCompiler;
+ private final FragmentCompiler fragmentCompiler;
- public ProgramCompiler(GlProgram.Factory factory, Function vertexCompiler, Function fragmentCompiler) {
+ public ProgramCompiler(GlProgram.Factory factory, VertexCompiler vertexCompiler, FragmentCompiler fragmentCompiler) {
this.factory = factory;
this.vertexCompiler = vertexCompiler;
this.fragmentCompiler = fragmentCompiler;
+
+ ALL_COMPILERS.add(this);
}
/**
@@ -40,7 +41,7 @@ public class ProgramCompiler
{
* @return A program compiler.
*/
public static ProgramCompiler create(Template template, GlProgram.Factory factory, FileResolution header) {
- return new ProgramCompiler<>(factory, ctx -> ShaderCompiler.compileVertex(ctx, template, header), ctx -> ShaderCompiler.compileFragment(ctx, Templates.FRAGMENT, header));
+ return new ProgramCompiler<>(factory, new VertexCompiler(template, header), new FragmentCompiler(Templates.FRAGMENT, header));
}
/**
@@ -50,22 +51,30 @@ public class ProgramCompiler
{
* @return A compiled GlProgram.
*/
public P getProgram(ProgramContext ctx) {
- return cache.computeIfAbsent(ctx, this::compile);
+ return super.get(ctx);
}
public void invalidate() {
- cache.values().forEach(P::delete);
- cache.clear();
+ super.invalidate();
+ vertexCompiler.invalidate();
+ fragmentCompiler.invalidate();
}
- private P compile(ProgramContext ctx) {
-
+ @Override
+ protected P _create(ProgramContext ctx) {
return new ProgramAssembler(ctx.spec().name)
- .attachShader(vertexCompiler.apply(ctx))
- .attachShader(fragmentCompiler.apply(ctx))
+ .attachShader(vertexCompiler.get(ctx))
+ .attachShader(fragmentCompiler.get(ctx))
.link()
- .deleteLinkedShaders()
.build(this.factory);
}
+ @Override
+ protected void _destroy(P value) {
+ value.delete();
+ }
+
+ public static void invalidateAll(ReloadRenderersEvent event) {
+ ALL_COMPILERS.forEach(ProgramCompiler::invalidate);
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramContext.java b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramContext.java
index fdb87be5c..e5dc5da13 100644
--- a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramContext.java
+++ b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramContext.java
@@ -1,6 +1,5 @@
package com.jozufozu.flywheel.core.compile;
-import java.util.List;
import java.util.Objects;
import javax.annotation.Nullable;
@@ -41,18 +40,15 @@ public record ProgramContext(float alphaDiscard, VertexType vertexType, ProgramS
return new ProgramContext(getAlphaDiscard(layer), vertexType, spec, spec.getCurrentStateID());
}
- /**
- * Gets the alpha discard threshold for the given render layer.
- *
- * @param layer The render layer to get the alpha discard threshold for.
- * @return The alpha discard threshold.
- */
- public static float getAlphaDiscard(@Nullable RenderLayer layer) {
- return layer == RenderLayer.CUTOUT ? 0.1f : 0f;
- }
+ public ShaderConstants getShaderConstants() {
+ ShaderConstants shaderConstants = new ShaderConstants();
+ shaderConstants.defineAll(spec.getDefines(ctx));
- public List createDefines() {
- return spec().getDefines(ctx());
+ if (alphaDiscard > 0) {
+ shaderConstants.define("ALPHA_DISCARD", alphaDiscard);
+ }
+
+ return shaderConstants;
}
@Override
@@ -68,4 +64,14 @@ public record ProgramContext(float alphaDiscard, VertexType vertexType, ProgramS
public int hashCode() {
return Objects.hash(alphaDiscard, vertexType, spec, ctx);
}
+
+ /**
+ * Gets the alpha discard threshold for the given render layer.
+ *
+ * @param layer The render layer to get the alpha discard threshold for.
+ * @return The alpha discard threshold.
+ */
+ public static float getAlphaDiscard(@Nullable RenderLayer layer) {
+ return layer == RenderLayer.CUTOUT ? 0.1f : 0f;
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompiler.java
deleted file mode 100644
index a5f3428ea..000000000
--- a/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompiler.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.jozufozu.flywheel.core.compile;
-
-import com.jozufozu.flywheel.backend.gl.GLSLVersion;
-import com.jozufozu.flywheel.backend.gl.shader.GlShader;
-import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
-import com.jozufozu.flywheel.backend.source.FileResolution;
-import com.jozufozu.flywheel.core.shader.ProgramSpec;
-
-/**
- * Compiles a shader program.
- */
-public class ShaderCompiler {
-
- public static GlShader compileVertex(ProgramContext context, Template template, FileResolution header) {
- StringBuilder finalSource = new StringBuilder();
-
- finalSource.append(generateHeader(template.getVersion(), ShaderType.VERTEX));
-
- for (String def : context.createDefines()) {
- finalSource.append("#define ")
- .append(def)
- .append('\n');
- }
-
- finalSource.append("""
- struct Vertex {
- vec3 pos;
- vec4 color;
- vec2 texCoords;
- vec2 light;
- vec3 normal;
- };
- """);
- finalSource.append(context.vertexType()
- .getShaderHeader());
-
- FileIndexImpl index = new FileIndexImpl();
-
- header.getFile()
- .generateFinalSource(index, finalSource);
- ProgramSpec spec = context.spec();
- spec.getVertexFile()
- .generateFinalSource(index, finalSource);
-
- T appliedTemplate = template.apply(spec.getVertexFile());
- finalSource.append(appliedTemplate.generateFooter(index, context.vertexType()));
-
- return new GlShader(spec.name, ShaderType.VERTEX, finalSource.toString());
- }
-
- public static GlShader compileFragment(ProgramContext context, Template template, FileResolution header) {
-
- StringBuilder finalSource = new StringBuilder();
-
- finalSource.append(generateHeader(template.getVersion(), ShaderType.FRAGMENT));
- for (String def : context.createDefines()) {
- finalSource.append("#define ")
- .append(def)
- .append('\n');
- }
-
- if (context.alphaDiscard() > 0) {
- finalSource.append("#define ALPHA_DISCARD 0.1\n");
- }
-
-
- FileIndexImpl index = new FileIndexImpl();
-
- ProgramSpec spec = context.spec();
- header.getFile().generateFinalSource(index, finalSource);
- spec.getFragmentFile()
- .generateFinalSource(index, finalSource);
-
- T appliedTemplate = template.apply(spec.getFragmentFile());
- finalSource.append(appliedTemplate.generateFooter());
-
- return new GlShader(spec.name, ShaderType.FRAGMENT, finalSource.toString());
- }
-
- protected static String generateHeader(GLSLVersion version, ShaderType type) {
- return "#version "
- + version
- + '\n'
- + "#extension GL_ARB_explicit_attrib_location : enable\n"
- + "#extension GL_ARB_conservative_depth : enable\n"
- + type.getDefineStatement();
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ShaderConstants.java b/src/main/java/com/jozufozu/flywheel/core/compile/ShaderConstants.java
new file mode 100644
index 000000000..165e25112
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/core/compile/ShaderConstants.java
@@ -0,0 +1,51 @@
+package com.jozufozu.flywheel.core.compile;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ShaderConstants {
+
+
+ private final Map definitions = new HashMap<>();
+
+ public ShaderConstants define(String def) {
+ definitions.put(def, "");
+ return this;
+ }
+
+ public ShaderConstants define(String def, String value) {
+ definitions.put(def, value);
+ return this;
+ }
+
+ public ShaderConstants define(String def, float value) {
+ definitions.put(def, Float.toString(value));
+ return this;
+ }
+
+ public ShaderConstants defineAll(List defines) {
+ for (String def : defines) {
+ definitions.put(def, "");
+ }
+ return this;
+ }
+
+ public String build() {
+ final StringBuilder acc = new StringBuilder();
+ writeInto(acc);
+ return acc.toString();
+ }
+
+ public void writeInto(final StringBuilder acc) {
+ for (Map.Entry e : definitions.entrySet()) {
+ acc.append("#define ")
+ .append(e.getKey());
+ if (e.getValue().length() > 0) {
+ acc.append(' ')
+ .append(e.getValue());
+ }
+ acc.append('\n');
+ }
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java
new file mode 100644
index 000000000..1e0e6c925
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java
@@ -0,0 +1,56 @@
+package com.jozufozu.flywheel.core.compile;
+
+import com.jozufozu.flywheel.backend.gl.shader.GlShader;
+import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
+import com.jozufozu.flywheel.backend.source.FileResolution;
+import com.jozufozu.flywheel.backend.source.SourceFile;
+import com.jozufozu.flywheel.core.shader.ProgramSpec;
+
+public class VertexCompiler extends Memoizer {
+ private final Template extends VertexData> template;
+ private final FileResolution header;
+
+ public VertexCompiler(Template extends VertexData> template, FileResolution header) {
+ this.template = template;
+ this.header = header;
+ }
+
+ @Override
+ protected GlShader _create(ProgramContext key) {
+ StringBuilder finalSource = new StringBuilder();
+
+ finalSource.append(CompileUtil.generateHeader(template.getVersion(), ShaderType.VERTEX));
+
+ key.getShaderConstants().writeInto(finalSource);
+
+ finalSource.append("""
+ struct Vertex {
+ vec3 pos;
+ vec4 color;
+ vec2 texCoords;
+ vec2 light;
+ vec3 normal;
+ };
+ """);
+ finalSource.append(key.vertexType()
+ .getShaderHeader());
+
+ FileIndexImpl index = new FileIndexImpl();
+
+ header.getFile().generateFinalSource(index, finalSource);
+ ProgramSpec spec = key.spec();
+ SourceFile vertexFile = spec.getVertexFile();
+
+ vertexFile.generateFinalSource(index, finalSource);
+
+ VertexData appliedTemplate = template.apply(vertexFile);
+ finalSource.append(appliedTemplate.generateFooter(index, key.vertexType()));
+
+ return new GlShader(spec.name, ShaderType.VERTEX, finalSource.toString());
+ }
+
+ @Override
+ protected void _destroy(GlShader value) {
+ value.delete();
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/event/RenderLayerEvent.java b/src/main/java/com/jozufozu/flywheel/event/RenderLayerEvent.java
index 9aacbe054..f0b54fc49 100644
--- a/src/main/java/com/jozufozu/flywheel/event/RenderLayerEvent.java
+++ b/src/main/java/com/jozufozu/flywheel/event/RenderLayerEvent.java
@@ -38,7 +38,7 @@ public class RenderLayerEvent extends Event {
this.camY = camY;
this.camZ = camZ;
- this.layer = RenderLayer.fromRenderType(type);
+ this.layer = RenderLayer.getPrimaryLayer(type);
}
@Nullable