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 template; + private final FileResolution header; + + public VertexCompiler(Template 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