From a8842d4c6460588addd0090b160ddb5e93485a3a Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Tue, 28 Dec 2021 16:37:10 -0800 Subject: [PATCH 01/10] Shader sanity - Drastically lower shader boilerplate for instance materials - Somewhat lower boilerplate for contexts - VertexTypes are responsible for shader headers - Better shader compiler errors (at least on nvidia) - Simplify template classes - Begin work on lazy shader compilation --- .../flywheel/api/shader/FlexibleShader.java | 15 ++ .../flywheel/api/vertex/VertexType.java | 2 + .../jozufozu/flywheel/backend/Backend.java | 2 +- .../flywheel/backend/ShaderContext.java | 10 +- .../flywheel/backend/gl/GlNumericType.java | 15 +- .../flywheel/backend/gl/GlVertexArray.java | 4 +- .../flywheel/backend/gl/shader/GlShader.java | 36 ++++- .../instancing/InstancedMaterial.java | 56 +++---- .../instancing/InstancedMaterialGroup.java | 45 +++--- .../instancing/InstancingEngine.java | 6 +- .../backend/pipeline/InstancingTemplate.java | 78 ---------- ...aData.java => InstancingTemplateData.java} | 98 ++++++++++-- .../backend/pipeline/LazyCompiler.java | 33 ++++ .../backend/pipeline/OneShotTemplate.java | 68 -------- ...MetaData.java => OneShotTemplateData.java} | 70 +++++++-- ...rotoProgram.java => ProgramAssembler.java} | 43 ++---- .../backend/pipeline/ShaderCompiler.java | 145 ++++++++++++++++++ .../backend/pipeline/ShaderPipeline.java | 3 +- .../flywheel/backend/pipeline/Template.java | 30 ++-- .../backend/pipeline/TemplateData.java | 23 +++ .../backend/pipeline/WorldShader.java | 77 ---------- .../backend/pipeline/WorldShaderPipeline.java | 40 +---- .../backend/source/FileResolution.java | 9 +- .../flywheel/backend/source/Resolver.java | 2 +- .../source/ShaderLoadingException.java | 13 +- .../backend/source/ShaderSources.java | 12 +- .../flywheel/backend/source/SourceFile.java | 33 +++- .../{ISourceHolder.java => SourceFinder.java} | 5 +- .../flywheel/backend/source/SourceLines.java | 79 +++++----- .../backend/source/error/ErrorBuilder.java | 60 ++++++-- .../error/{Level.java => ErrorLevel.java} | 5 +- .../backend/source/error/ErrorReporter.java | 30 +++- .../backend/source/error/lines/ErrorLine.java | 8 +- .../source/error/lines/HeaderLine.java | 10 -- .../backend/source/error/lines/TextLine.java | 9 ++ .../backend/source/parse/ShaderFunction.java | 11 +- .../backend/source/parse/Variable.java | 38 +++-- .../com/jozufozu/flywheel/core/Contexts.java | 5 +- .../com/jozufozu/flywheel/core/Templates.java | 12 ++ .../jozufozu/flywheel/core/WorldContext.java | 16 +- .../flywheel/core/layout/BufferLayout.java | 4 +- .../flywheel/core/layout/CommonItems.java | 2 +- .../flywheel/core/layout/LayoutItem.java | 4 +- .../flywheel/core/layout/MatrixItems.java | 5 +- .../layout/{PaddingItem.java => Padding.java} | 7 +- .../flywheel/core/layout/PrimitiveItem.java | 5 +- .../flywheel/core/vertex/BlockVertex.java | 23 ++- .../core/vertex/PosTexNormalVertex.java | 21 ++- .../flywheel/flywheel/shaders/block.frag | 8 +- .../flywheel/shaders/context/crumbling.glsl | 13 +- .../flywheel/shaders/context/world.glsl | 12 +- .../flywheel/shaders/data/modelvertex.glsl | 5 - .../flywheel/flywheel/shaders/model.vert | 30 +--- .../flywheel/flywheel/shaders/oriented.vert | 31 +--- .../flywheel/shaders/smooth_oriented.glsl | 53 ------- 55 files changed, 813 insertions(+), 666 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/api/shader/FlexibleShader.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingTemplate.java rename src/main/java/com/jozufozu/flywheel/backend/pipeline/{InstancingProgramMetaData.java => InstancingTemplateData.java} (50%) create mode 100644 src/main/java/com/jozufozu/flywheel/backend/pipeline/LazyCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotTemplate.java rename src/main/java/com/jozufozu/flywheel/backend/pipeline/{OneShotProgramMetaData.java => OneShotTemplateData.java} (56%) rename src/main/java/com/jozufozu/flywheel/backend/pipeline/{ProtoProgram.java => ProgramAssembler.java} (56%) create mode 100644 src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderCompiler.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/pipeline/TemplateData.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShader.java rename src/main/java/com/jozufozu/flywheel/backend/source/{ISourceHolder.java => SourceFinder.java} (73%) rename src/main/java/com/jozufozu/flywheel/backend/source/error/{Level.java => ErrorLevel.java} (75%) create mode 100644 src/main/java/com/jozufozu/flywheel/backend/source/error/lines/TextLine.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/Templates.java rename src/main/java/com/jozufozu/flywheel/core/layout/{PaddingItem.java => Padding.java} (62%) delete mode 100644 src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl delete mode 100644 src/main/resources/assets/flywheel/flywheel/shaders/smooth_oriented.glsl diff --git a/src/main/java/com/jozufozu/flywheel/api/shader/FlexibleShader.java b/src/main/java/com/jozufozu/flywheel/api/shader/FlexibleShader.java new file mode 100644 index 000000000..a46802373 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/shader/FlexibleShader.java @@ -0,0 +1,15 @@ +package com.jozufozu.flywheel.api.shader; + +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; + +/** + * Represents a vertex format agnostic shader. + */ +public interface FlexibleShader

{ + + /** + * Get a version of this shader that accepts the given VertexType as input. + */ + P get(VertexType type); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java index f785f4ac3..165512540 100644 --- a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java @@ -39,4 +39,6 @@ public interface VertexType { default int byteOffset(int vertexIndex) { return getStride() * vertexIndex; } + + String writeShaderHeader(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index b8ec0ff04..1d5f931eb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -115,7 +115,7 @@ public class Backend { enabled = switch (engine) { case OFF -> false; - case BATCHING -> !usingShaders; + case BATCHING -> true; case INSTANCING -> !usingShaders && compat.instancedArraysSupported(); }; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java b/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java index 66585908e..96c5e563d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java +++ b/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java @@ -1,19 +1,19 @@ package com.jozufozu.flywheel.backend; -import java.util.function.Supplier; - +import com.jozufozu.flywheel.api.shader.FlexibleShader; +import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import net.minecraft.resources.ResourceLocation; public interface ShaderContext

{ - default P getProgram(ResourceLocation loc) { + default P getProgram(ResourceLocation loc, VertexType inputType) { return this.getProgramSupplier(loc) - .get(); + .get(inputType); } - Supplier

getProgramSupplier(ResourceLocation loc); + FlexibleShader

getProgramSupplier(ResourceLocation loc); /** * Load all programs associated with this context. This might be just one, if the context is very specialized. diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlNumericType.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlNumericType.java index 29baffd7f..aaf69e61d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/GlNumericType.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlNumericType.java @@ -26,15 +26,15 @@ public enum GlNumericType { private static final GlNumericType[] VALUES = values(); private static final Map NAME_LOOKUP = Arrays.stream(VALUES) - .collect(Collectors.toMap(GlNumericType::getDisplayName, type -> type)); + .collect(Collectors.toMap(GlNumericType::getTypeName, type -> type)); private final int byteWidth; - private final String displayName; + private final String typeName; private final int glEnum; GlNumericType(int bytes, String name, int glEnum) { this.byteWidth = bytes; - this.displayName = name; + this.typeName = name; this.glEnum = glEnum; } @@ -42,8 +42,8 @@ public enum GlNumericType { return this.byteWidth; } - public String getDisplayName() { - return this.displayName; + public String getTypeName() { + return this.typeName; } public int getGlEnum() { @@ -64,4 +64,9 @@ public enum GlNumericType { public static GlNumericType byName(String name) { return name == null ? null : NAME_LOOKUP.get(name.toLowerCase(Locale.ROOT)); } + + @Override + public String toString() { + return typeName; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java index 1ec315fa9..c50681c7f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java @@ -39,8 +39,8 @@ public class GlVertexArray extends GlObject { int offset = 0; for (LayoutItem spec : type.getLayoutItems()) { spec.vertexAttribPointer(type.getStride(), startIndex, offset); - startIndex += spec.getAttributeCount(); - offset += spec.getSize(); + startIndex += spec.attributeCount(); + offset += spec.size(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java index c386294ba..f6464778c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java @@ -1,10 +1,16 @@ package com.jozufozu.flywheel.backend.gl.shader; +import java.util.List; + import org.lwjgl.opengl.GL20; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlObject; import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; +import com.jozufozu.flywheel.backend.pipeline.ShaderCompiler; +import com.jozufozu.flywheel.backend.source.ShaderLoadingException; +import com.jozufozu.flywheel.backend.source.error.ErrorBuilder; +import com.jozufozu.flywheel.backend.source.error.ErrorReporter; import net.minecraft.resources.ResourceLocation; @@ -13,8 +19,8 @@ public class GlShader extends GlObject { public final ResourceLocation name; public final ShaderType type; - public GlShader(ResourceLocation name, ShaderType type, CharSequence source) { - this.name = name; + public GlShader(ShaderCompiler env, ShaderType type, String source) { + name = env.name; this.type = type; int handle = GL20.glCreateShader(type.glEnum); @@ -24,13 +30,31 @@ public class GlShader extends GlObject { String log = GL20.glGetShaderInfoLog(handle); if (!log.isEmpty()) { - Backend.log.error("Shader compilation log for " + name + ": " + log); - Backend.log.error(source); + List lines = log.lines() + .toList(); + + boolean needsSourceDump = false; + + StringBuilder errors = new StringBuilder(); + for (String line : lines) { + ErrorBuilder builder = env.parseCompilerError(line); + + if (builder != null) { + errors.append(builder.build()); + } else { + errors.append(line).append('\n'); + needsSourceDump = true; + } + } + Backend.log.error("Errors compiling '" + name + "': \n" + errors); + if (needsSourceDump) { + // TODO: generated code gets its own "file" + ErrorReporter.printLines(source); + } } - //Backend.log.debug(shader.printSource()); if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) { - throw new RuntimeException("Could not compile " + name + ". See log for details."); + throw new ShaderLoadingException("Could not compile " + name + ". See log for details."); } setHandle(handle); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java index a72dcf415..becb71114 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java @@ -1,20 +1,17 @@ package com.jozufozu.flywheel.backend.instancing.instancing; -import java.util.concurrent.ExecutionException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.function.Supplier; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.Instancer; import com.jozufozu.flywheel.api.Material; import com.jozufozu.flywheel.api.struct.Instanced; -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.RenderWork; -import com.jozufozu.flywheel.backend.model.ImmediateAllocator; import com.jozufozu.flywheel.backend.model.ModelAllocator; -import com.jozufozu.flywheel.backend.model.ModelPool; -import com.jozufozu.flywheel.core.Formats; import com.jozufozu.flywheel.core.model.Model; /** @@ -23,24 +20,14 @@ import com.jozufozu.flywheel.core.model.Model; */ public class InstancedMaterial implements Material { - final ModelAllocator allocator; - protected final Cache> models; + protected final ModelAllocator allocator; + protected final Map> models = new HashMap<>(); protected final Instanced type; + protected final List> uninitialized = new ArrayList<>(); - public InstancedMaterial(Instanced type) { + public InstancedMaterial(Instanced type, ModelAllocator allocator) { this.type = type; - - if (Backend.getInstance().compat.onAMDWindows()) { - allocator = ImmediateAllocator.INSTANCE; - } else { - allocator = new ModelPool(Formats.POS_TEX_NORMAL, 64); - } - this.models = CacheBuilder.newBuilder() - .removalListener(notification -> { - GPUInstancer instancer = (GPUInstancer) notification.getValue(); - RenderWork.enqueue(instancer::delete); - }) - .build(); + this.allocator = allocator; } /** @@ -52,32 +39,33 @@ public class InstancedMaterial implements Material { */ @Override public Instancer model(Object key, Supplier modelSupplier) { - try { - return models.get(key, () -> new GPUInstancer<>(type, modelSupplier.get(), allocator)); - } catch (ExecutionException e) { - throw new RuntimeException("error creating instancer", e); - } + return models.computeIfAbsent(key, $ -> { + GPUInstancer instancer = new GPUInstancer<>(type, modelSupplier.get(), allocator); + uninitialized.add(instancer); + return instancer; + }); } public boolean nothingToRender() { - return models.size() > 0 && models.asMap() - .values() + return models.size() > 0 && models.values() .stream() .allMatch(GPUInstancer::isEmpty); } public void delete() { - models.invalidateAll(); - if (allocator instanceof ModelPool pool) pool.delete(); + models.values().forEach(GPUInstancer::delete); + models.clear(); } /** * Clear all instance data without freeing resources. */ public void clear() { - models.asMap() - .values() + models.values() .forEach(GPUInstancer::clear); } + public Collection> getAllInstancers() { + return models.values(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java index 8938686f1..c558213cd 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java @@ -1,6 +1,5 @@ package com.jozufozu.flywheel.backend.instancing.instancing; -import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -8,7 +7,11 @@ import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.MaterialGroup; import com.jozufozu.flywheel.api.struct.Instanced; import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.model.ImmediateAllocator; +import com.jozufozu.flywheel.backend.model.ModelAllocator; import com.jozufozu.flywheel.backend.model.ModelPool; +import com.jozufozu.flywheel.core.Formats; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.util.Textures; import com.mojang.math.Matrix4f; @@ -27,17 +30,23 @@ public class InstancedMaterialGroup

implements MaterialG protected final RenderType type; private final Map, InstancedMaterial> materials = new HashMap<>(); + private final ModelAllocator allocator; public InstancedMaterialGroup(InstancingEngine

owner, RenderType type) { this.owner = owner; this.type = type; + if (Backend.getInstance().compat.onAMDWindows()) { + this.allocator = ImmediateAllocator.INSTANCE; + } else { + this.allocator = new ModelPool(Formats.POS_TEX_NORMAL, 2048); + } } @SuppressWarnings("unchecked") @Override public InstancedMaterial material(StructType type) { if (type instanceof Instanced instanced) { - return (InstancedMaterial) materials.computeIfAbsent(instanced, InstancedMaterial::new); + return (InstancedMaterial) materials.computeIfAbsent(instanced, t -> new InstancedMaterial<>(t, allocator)); } else { throw new ClassCastException("Cannot use type '" + type + "' with GPU instancing."); } @@ -51,25 +60,25 @@ public class InstancedMaterialGroup

implements MaterialG } protected void renderAll(Matrix4f viewProjection, double camX, double camY, double camZ) { + // initialize all uninitialized instancers... + for (InstancedMaterial material : materials.values()) { + for (GPUInstancer instancer : material.uninitialized) { + instancer.init(); + } + material.uninitialized.clear(); + } + + if (allocator instanceof ModelPool pool) { + // ...and then flush the model arena in case anything was marked for upload + pool.flush(); + } + for (Map.Entry, InstancedMaterial> entry : materials.entrySet()) { InstancedMaterial material = entry.getValue(); if (material.nothingToRender()) continue; - Collection> instancers = material.models.asMap() - .values(); - - // initialize all uninitialized instancers... - for (GPUInstancer gpuInstancer : instancers) { - gpuInstancer.init(); - } - - if (material.allocator instanceof ModelPool pool) { - // ...and then flush the model arena in case anything was marked for upload - pool.flush(); - } - - P program = owner.getProgram(entry.getKey() - .getProgramSpec()).get(); + P program = owner.context.getProgram(entry.getKey() + .getProgramSpec(), Formats.POS_TEX_NORMAL); program.bind(); program.uploadViewProjection(viewProjection); @@ -77,7 +86,7 @@ public class InstancedMaterialGroup

implements MaterialG setup(program); - for (GPUInstancer instancer : instancers) { + for (GPUInstancer instancer : material.getAllInstancers()) { instancer.render(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index 7f30b541e..4366b5091 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -3,17 +3,17 @@ package com.jozufozu.flywheel.backend.instancing.instancing; import java.util.EnumMap; import java.util.HashMap; import java.util.Map; -import java.util.function.Supplier; import java.util.stream.Stream; import javax.annotation.Nullable; import com.jozufozu.flywheel.api.MaterialGroup; -import com.jozufozu.flywheel.backend.instancing.TaskEngine; +import com.jozufozu.flywheel.api.shader.FlexibleShader; import com.jozufozu.flywheel.backend.RenderLayer; import com.jozufozu.flywheel.backend.gl.GlVertexArray; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.instancing.Engine; +import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.core.WorldContext; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.event.RenderLayerEvent; @@ -126,7 +126,7 @@ public class InstancingEngine

implements Engine { } } - public Supplier

getProgram(ResourceLocation name) { + public FlexibleShader

getProgram(ResourceLocation name) { return context.getProgramSupplier(name); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingTemplate.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingTemplate.java deleted file mode 100644 index fdb4e4381..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingTemplate.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.jozufozu.flywheel.backend.pipeline; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; -import com.jozufozu.flywheel.backend.source.SourceFile; - -public class InstancingTemplate extends Template { - - public static final InstancingTemplate INSTANCE = new InstancingTemplate(); - - public InstancingTemplate() { - super(InstancingProgramMetaData::new); - } - - @Override - public void generateTemplateSource(StringBuilder builder, ShaderType type, SourceFile file) { - if (type == ShaderType.VERTEX) { - vertexFooter(builder, file); - } else if (type == ShaderType.FRAGMENT) { - fragmentFooter(builder, file); - } - } - - @Override - public Collection getShaderInputs(SourceFile file) { - InstancingProgramMetaData data = getMetadata(file); - - List inputs = new ArrayList<>(ShaderInput.fromStruct(data.vertex, "a_v_")); - inputs.addAll(ShaderInput.fromStruct(data.instance, "a_i_")); - - return inputs; - } - - public void vertexFooter(StringBuilder template, SourceFile file) { - InstancingProgramMetaData data = getMetadata(file); - - Template.prefixFields(template, data.vertex, "in", "a_v_"); - Template.prefixFields(template, data.instance, "in", "a_i_"); - Template.prefixFields(template, data.interpolant, "out", "v2f_"); - - template.append("void main() {\n"); - template.append(data.vertexName) - .append(" v;\n"); - Template.assignFields(template, data.vertex, "v.", "a_v_"); - - template.append(data.instanceName) - .append(" i;\n"); - Template.assignFields(template, data.instance, "i.", "a_i_"); - - template.append(data.interpolantName) - .append(" o = ") - .append(data.vertexMain.call("v", "i")) - .append(";\n"); - - Template.assignFields(template, data.interpolant, "v2f_", "o."); - - template.append('}'); - } - - public void fragmentFooter(StringBuilder template, SourceFile file) { - InstancingProgramMetaData data = getMetadata(file); - - Template.prefixFields(template, data.interpolant, "in", "v2f_"); - - template.append("void main() {\n"); - template.append(data.interpolantName) - .append(" o;\n"); - Template.assignFields(template, data.interpolant, "o.", "v2f_"); - - template.append(data.fragmentMain.call("o")) - .append(";\n"); - - template.append('}'); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingProgramMetaData.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingTemplateData.java similarity index 50% rename from src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingProgramMetaData.java rename to src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingTemplateData.java index c033b7b8c..2eb6f74be 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingProgramMetaData.java +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingTemplateData.java @@ -3,15 +3,17 @@ package com.jozufozu.flywheel.backend.pipeline; import java.util.Optional; import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.source.ShaderLoadingException; import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.backend.source.error.ErrorReporter; import com.jozufozu.flywheel.backend.source.parse.ShaderFunction; import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; +import com.jozufozu.flywheel.backend.source.parse.StructField; import com.jozufozu.flywheel.backend.source.parse.Variable; import com.jozufozu.flywheel.backend.source.span.Span; -public class InstancingProgramMetaData { +public class InstancingTemplateData implements TemplateData { public final SourceFile file; public final ShaderFunction vertexMain; @@ -20,10 +22,9 @@ public class InstancingProgramMetaData { public final Span vertexName; public final Span instanceName; public final ShaderStruct interpolant; - public final ShaderStruct vertex; public final ShaderStruct instance; - public InstancingProgramMetaData(SourceFile file) { + public InstancingTemplateData(SourceFile file) { this.file = file; Optional vertexFunc = file.findFunction("vertex"); @@ -54,20 +55,25 @@ public class InstancingProgramMetaData { throw new ShaderLoadingException(); } - interpolantName = vertexMain.getType(); - vertexName = vertexParams.get(0) - .typeName(); - instanceName = vertexParams.get(1) - .typeName(); + Variable vertexParam = vertexParams.get(0); + vertexName = vertexParam.type; + + boolean namedVertex = vertexParam.type + .toString() + .equals("Vertex"); + + + if (!(namedVertex && vertexParam.qualifier == Variable.Qualifier.INOUT)) { + ErrorReporter.generateSpanError(vertexParam.qualifierSpan, "first parameter must be inout Vertex"); + throw new ShaderLoadingException(); + } + + interpolantName = parameters.get(0).type; + instanceName = vertexParams.get(1).type; Optional maybeInterpolant = file.findStruct(interpolantName); - Optional maybeVertex = file.findStruct(vertexName); Optional maybeInstance = file.findStruct(instanceName); - if (maybeVertex.isEmpty()) { - ErrorReporter.generateMissingStruct(file, vertexName, "struct not defined"); - } - if (maybeInterpolant.isEmpty()) { ErrorReporter.generateMissingStruct(file, interpolantName, "struct not defined"); } @@ -76,12 +82,74 @@ public class InstancingProgramMetaData { ErrorReporter.generateMissingStruct(file, instanceName, "struct not defined"); } - if (maybeVertex.isEmpty() || maybeInterpolant.isEmpty() || maybeInstance.isEmpty()) { + if (maybeInterpolant.isEmpty() || maybeInstance.isEmpty()) { throw new ShaderLoadingException(); } interpolant = maybeInterpolant.get(); - vertex = maybeVertex.get(); instance = maybeInstance.get(); } + + public void vertexFooter(StringBuilder template, ShaderCompiler shader) { + ImmutableList fields = instance.getFields(); + VertexType vertexType = shader.vertexType; + + int attributeBinding = vertexType.getLayout() + .getAttributeCount(); + + for (StructField field : fields) { + template.append("layout(location = ") + .append(attributeBinding) + .append(") in") + .append(' ') + .append(field.type) + .append(' ') + .append("a_i_") + .append(field.name) + .append(";\n"); + attributeBinding += ShaderInput.from(field).attribCount; + } + Template.prefixFields(template, interpolant, "out", "v2f_"); + + template.append(String.format(""" + void main() { + Vertex v = FLWCreateVertex(); + %s i; + %s + vertex(v, i); + gl_Position = FLWVertex(v); + v.normal = normalize(v.normal); + + v2f_color = v.color; + v2f_texCoords = v.texCoords; + v2f_light = v.light; + v2f_diffuse = diffuse(v.normal); + #if defined(DEBUG_NORMAL) + v2f_color = vec4(v.normal, 1.); + #endif + } + """, + instanceName, + Template.assignFields(instance, "i.", "a_i_") + )); + } + + public void fragmentFooter(StringBuilder template, ShaderCompiler shader) { + Template.prefixFields(template, interpolant, "in", "v2f_"); + + template.append(String.format(""" + void main() { + Fragment o; + o.color = v2f_color; + o.texCoords = v2f_texCoords; + o.light = v2f_light; + o.diffuse = v2f_diffuse; + + vec4 color = %s; + FLWFinalizeColor(color); + } + """, + fragmentMain.call("o") + )); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/LazyCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/LazyCompiler.java new file mode 100644 index 000000000..a8b57c4ba --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/LazyCompiler.java @@ -0,0 +1,33 @@ +package com.jozufozu.flywheel.backend.pipeline; + +import java.util.HashMap; +import java.util.Map; + +import com.jozufozu.flywheel.api.shader.FlexibleShader; +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.core.shader.ContextAwareProgram; +import com.jozufozu.flywheel.core.shader.WorldProgram; +import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; + +public class LazyCompiler

implements FlexibleShader

{ + + private final ShaderPipeline

pipeline; + private final ProgramSpec spec; + + private final Map> cache = new HashMap<>(); + + public LazyCompiler(ShaderPipeline

pipeline, ProgramSpec spec) { + + this.pipeline = pipeline; + this.spec = spec; + } + + public void delete() { + cache.values().forEach(ContextAwareProgram::delete); + } + + @Override + public P get(VertexType type) { + return cache.computeIfAbsent(type, t -> pipeline.compile(spec, t)).get(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotTemplate.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotTemplate.java deleted file mode 100644 index f457ebfc4..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotTemplate.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.jozufozu.flywheel.backend.pipeline; - -import java.util.Collection; - -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; -import com.jozufozu.flywheel.backend.source.SourceFile; - -public class OneShotTemplate extends Template { - - public static final OneShotTemplate INSTANCE = new OneShotTemplate(); - - public OneShotTemplate() { - super(OneShotProgramMetaData::new); - } - - @Override - public void generateTemplateSource(StringBuilder builder, ShaderType type, SourceFile file) { - if (type == ShaderType.VERTEX) { - vertexFooter(builder, file); - } else if (type == ShaderType.FRAGMENT) { - fragmentFooter(builder, file); - } - } - - @Override - public Collection getShaderInputs(SourceFile file) { - OneShotProgramMetaData data = getMetadata(file); - - return ShaderInput.fromStruct(data.vertex, "a_v_"); - } - - public void vertexFooter(StringBuilder template, SourceFile file) { - OneShotProgramMetaData data = getMetadata(file); - - Template.prefixFields(template, data.vertex, "in", "a_v_"); - Template.prefixFields(template, data.interpolant, "out", "v2f_"); - - template.append("void main() {\n"); - template.append(data.vertexName) - .append(" v;\n"); - Template.assignFields(template, data.vertex, "v.", "a_v_"); - - template.append(data.interpolantName) - .append(" o = ") - .append(data.vertexMain.call("v")) - .append(";\n"); - - Template.assignFields(template, data.interpolant, "v2f_", "o."); - - template.append('}'); - } - - public void fragmentFooter(StringBuilder template, SourceFile file) { - OneShotProgramMetaData data = getMetadata(file); - - Template.prefixFields(template, data.interpolant, "in", "v2f_"); - - template.append("void main() {\n"); - template.append(data.interpolant.name) - .append(" o;\n"); - Template.assignFields(template, data.interpolant, "o.", "v2f_"); - - template.append(data.fragmentMain.call("o")) - .append(";\n"); - - template.append('}'); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotProgramMetaData.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotTemplateData.java similarity index 56% rename from src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotProgramMetaData.java rename to src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotTemplateData.java index 67562a68b..b46945cfa 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotProgramMetaData.java +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotTemplateData.java @@ -3,6 +3,7 @@ package com.jozufozu.flywheel.backend.pipeline; import java.util.Optional; import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.backend.source.ShaderLoadingException; import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.backend.source.error.ErrorReporter; import com.jozufozu.flywheel.backend.source.parse.ShaderFunction; @@ -10,17 +11,15 @@ import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; import com.jozufozu.flywheel.backend.source.parse.Variable; import com.jozufozu.flywheel.backend.source.span.Span; -public class OneShotProgramMetaData { +public class OneShotTemplateData implements TemplateData { public final SourceFile file; public final ShaderFunction vertexMain; public final Span interpolantName; - public final Span vertexName; public final ShaderStruct interpolant; - public final ShaderStruct vertex; public final ShaderFunction fragmentMain; - public OneShotProgramMetaData(SourceFile file) { + public OneShotTemplateData(SourceFile file) { this.file = file; Optional maybeVertexMain = file.findFunction("vertex"); @@ -55,24 +54,67 @@ public class OneShotProgramMetaData { throw new RuntimeException(); } - interpolantName = vertexMain.getType(); - vertexName = vertexParameters.get(0) - .typeName(); + Variable vertexParam = vertexMain.getParameters().get(0); + + boolean namedVertex = vertexParam.type + .toString() + .equals("Vertex"); + + if (!(namedVertex && vertexParam.qualifier == Variable.Qualifier.INOUT)) { + ErrorReporter.generateSpanError(vertexParam.qualifierSpan, "first parameter must be inout Vertex"); + throw new ShaderLoadingException(); + } + + interpolantName = fragmentMain.getParameters().get(0).type; Optional maybeInterpolant = file.findStruct(interpolantName); - Optional maybeVertex = file.findStruct(vertexName); - if (maybeVertex.isEmpty()) - ErrorReporter.generateMissingStruct(file, vertexName, "struct not defined"); - - if (maybeInterpolant.isEmpty()) + if (maybeInterpolant.isEmpty()) { ErrorReporter.generateMissingStruct(file, interpolantName, "struct not defined"); - if (maybeVertex.isEmpty() || maybeInterpolant.isEmpty()) { throw new RuntimeException(); } interpolant = maybeInterpolant.get(); - vertex = maybeVertex.get(); + } + + public void vertexFooter(StringBuilder template, ShaderCompiler file) { + Template.prefixFields(template, interpolant, "out", "v2f_"); + + template.append(""" + void main() { + Vertex v = FLWCreateVertex(); + vertex(v); + gl_Position = FLWVertex(v); + v.normal = normalize(v.normal); + + v2f_color = v.color; + v2f_texCoords = v.texCoords; + v2f_light = v.light; + v2f_diffuse = diffuse(v.normal); + #if defined(DEBUG_NORMAL) + v2f_color = vec4(v.normal, 1.); + #endif + } + """); + } + + public void fragmentFooter(StringBuilder template, ShaderCompiler file) { + Template.prefixFields(template, interpolant, "in", "v2f_"); + + template.append(String.format(""" + void main() { + Fragment o; + o.color = v2f_color; + o.texCoords = v2f_texCoords; + o.light = v2f_light; + o.diffuse = v2f_diffuse; + + vec4 color = %s; + FLWFinalizeColor(color); + } + """, + fragmentMain.call("o") + )); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ProtoProgram.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ProgramAssembler.java similarity index 56% rename from src/main/java/com/jozufozu/flywheel/backend/pipeline/ProtoProgram.java rename to src/main/java/com/jozufozu/flywheel/backend/pipeline/ProgramAssembler.java index caa331d79..c3abd0e40 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ProtoProgram.java +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ProgramAssembler.java @@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.pipeline; import static org.lwjgl.opengl.GL11.GL_TRUE; import static org.lwjgl.opengl.GL20.GL_LINK_STATUS; import static org.lwjgl.opengl.GL20.glAttachShader; -import static org.lwjgl.opengl.GL20.glBindAttribLocation; import static org.lwjgl.opengl.GL20.glCreateProgram; import static org.lwjgl.opengl.GL20.glGetProgramInfoLog; import static org.lwjgl.opengl.GL20.glGetProgrami; @@ -13,44 +12,33 @@ import java.util.List; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.shader.GlShader; -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram; +import com.jozufozu.flywheel.core.shader.WorldProgram; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.resources.ResourceLocation; -public class ProtoProgram { +public class ProgramAssembler { public final int program; - public final WorldShader parent; + private final ResourceLocation name; - private int attributeIndex; + private final List shaders = new ObjectArrayList<>(); - private final List shaders; - - public ProtoProgram(WorldShader parent) { - this.parent = parent; + public ProgramAssembler(ResourceLocation name) { + this.name = name; this.program = glCreateProgram(); - shaders = new ObjectArrayList<>(); - } - - public ProtoProgram compilePart(ShaderType type) { - GlShader shader = parent.compile(type); - attachShader(shader); - return this; } /** * Links the attached shaders to this program. */ - public ProtoProgram link() { - - parent.template.getShaderInputs(parent.mainFile) - .forEach(this::addAttribute); - + public ProgramAssembler link() { glLinkProgram(this.program); String log = glGetProgramInfoLog(this.program); if (!log.isEmpty()) { - Backend.log.debug("Program link log for " + parent.name + ": " + log); + Backend.log.debug("Program link log for " + name + ": " + log); } int result = glGetProgrami(this.program, GL_LINK_STATUS); @@ -62,19 +50,18 @@ public class ProtoProgram { return this; } - public ProtoProgram deleteLinkedShaders() { + public ProgramAssembler deleteLinkedShaders() { shaders.forEach(GlShader::delete); return this; } - private void attachShader(GlShader glShader) { + public ProgramAssembler attachShader(GlShader glShader) { shaders.add(glShader); glAttachShader(this.program, glShader.handle()); + return this; } - private void addAttribute(ShaderInput shaderInput) { - glBindAttribLocation(this.program, attributeIndex, shaderInput.name); - attributeIndex += shaderInput.attribCount; + public

P build(ExtensibleGlProgram.Factory

factory) { + return factory.create(name, program); } - } diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderCompiler.java new file mode 100644 index 000000000..cd1ce9608 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderCompiler.java @@ -0,0 +1,145 @@ +package com.jozufozu.flywheel.backend.pipeline; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.api.vertex.VertexType; +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.backend.source.error.ErrorBuilder; +import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram; +import com.jozufozu.flywheel.core.shader.WorldProgram; +import com.jozufozu.flywheel.core.shader.spec.ProgramState; + +import net.minecraft.resources.ResourceLocation; + +public class ShaderCompiler { + + public final ResourceLocation name; + public final Template template; + private final FileResolution header; + + @Nullable + private ProgramState variant; + + public final VertexType vertexType; + + public SourceFile mainFile; + + public ShaderCompiler(ResourceLocation name, SourceFile mainSource, Template template, FileResolution header, VertexType vertexType) { + this.name = name; + this.template = template; + this.header = header; + this.mainFile = mainSource; + this.vertexType = vertexType; + } + + public ShaderCompiler setMainSource(SourceFile file) { + if (mainFile == file) return this; + + mainFile = file; + + return this; + } + + public GlShader compile(ShaderType type) { + + StringBuilder finalSource = new StringBuilder(); + + finalSource.append("#version ") + .append(template.getVersion()) + .append('\n') + .append("#extension GL_ARB_explicit_attrib_location : enable\n") + .append("#extension GL_ARB_conservative_depth : enable\n") + .append("#define ") + .append(type.define) // special case shader type declaration + .append('\n'); + + ProgramState variant = getVariant(); + if (variant != null) { + for (String def : variant.defines()) { + finalSource.append("#define ") + .append(def) + .append('\n'); + } + } + + if (type == ShaderType.VERTEX) { + finalSource.append(""" + struct Vertex { + vec3 pos; + vec4 color; + vec2 texCoords; + vec2 light; + vec3 normal; + }; + """); + finalSource.append(vertexType.writeShaderHeader()); + } + + files.clear(); + if (header.getFile() != null) { + header.getFile().generateFinalSource(this, finalSource); + } + mainFile.generateFinalSource(this, finalSource); + + template.getMetadata(mainFile).generateFooter(finalSource, type, this); + + return new GlShader(this, type, finalSource.toString()); + } + + @Nullable + public ProgramState getVariant() { + return variant; + } + + public void setVariant(@Nullable ProgramState variant) { + this.variant = variant; + } + + private final List files = new ArrayList<>(); + + public int allocateFile(SourceFile sourceFile) { + int i = files.indexOf(sourceFile); + if (i != -1) { + return i; + } + + int size = files.size(); + files.add(sourceFile); + return size; + } + + public Span getLineSpan(int fileId, int lineNo) { + SourceFile file = files.get(fileId); + + return file.getLineSpanNoWhitespace(lineNo); + } + + @Nullable + public ErrorBuilder parseCompilerError(String line) { + try { + ErrorBuilder error = ErrorBuilder.fromLogLine(this, line); + if (error != null) { + return error; + } + } catch (Exception ignored) { + } + + return null; + } + + public

P compile(ExtensibleGlProgram.Factory

worldShaderPipeline) { + return new ProgramAssembler(this.name) + .attachShader(compile(ShaderType.VERTEX)) + .attachShader(compile(ShaderType.FRAGMENT)) + .link() + .deleteLinkedShaders() + .build(worldShaderPipeline); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderPipeline.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderPipeline.java index 0caa59d57..a6f94413f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderPipeline.java +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderPipeline.java @@ -1,5 +1,6 @@ package com.jozufozu.flywheel.backend.pipeline; +import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.core.shader.ContextAwareProgram; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; @@ -10,6 +11,6 @@ import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; */ public interface ShaderPipeline

{ - ContextAwareProgram

compile(ProgramSpec spec); + ContextAwareProgram

compile(ProgramSpec spec, VertexType vertexType); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/Template.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/Template.java index 8b5b621e8..3906cbecc 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/Template.java +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/Template.java @@ -1,13 +1,11 @@ package com.jozufozu.flywheel.backend.pipeline; -import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.function.Function; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.backend.gl.GLSLVersion; -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; import com.jozufozu.flywheel.backend.source.parse.StructField; @@ -21,37 +19,25 @@ import com.jozufozu.flywheel.backend.source.parse.StructField; *

* @param Holds metadata, generates errors. */ -public abstract class Template { +public class Template { private final Map metadata = new HashMap<>(); private final Function reader; + private final GLSLVersion glslVersion; - protected Template(Function reader) { + public Template(GLSLVersion glslVersion, Function reader) { this.reader = reader; + this.glslVersion = glslVersion; } - /** - * Generate the necessary glue code here. - * - *

- * See {@link InstancingTemplate} and {@link OneShotTemplate} for examples. - *

- * @param builder The builder to generate the source into. - * @param type The shader stage glue code is needed for. - * @param file The SourceFile with user written code. - */ - public abstract void generateTemplateSource(StringBuilder builder, ShaderType type, SourceFile file); - - public abstract Collection getShaderInputs(SourceFile file); - public D getMetadata(SourceFile file) { // lazily read files, cache results return metadata.computeIfAbsent(file, reader); } public GLSLVersion getVersion() { - return GLSLVersion.V150; + return glslVersion; } public static void prefixFields(StringBuilder builder, ShaderStruct struct, String qualifier, String prefix) { @@ -68,9 +54,11 @@ public abstract class Template { } } - public static void assignFields(StringBuilder builder, ShaderStruct struct, String prefix1, String prefix2) { + public static StringBuilder assignFields(ShaderStruct struct, String prefix1, String prefix2) { ImmutableList fields = struct.getFields(); + StringBuilder builder = new StringBuilder(); + for (StructField field : fields) { builder.append(prefix1) .append(field.name) @@ -79,5 +67,7 @@ public abstract class Template { .append(field.name) .append(";\n"); } + + return builder; } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/TemplateData.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/TemplateData.java new file mode 100644 index 000000000..50603fdf0 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/TemplateData.java @@ -0,0 +1,23 @@ +package com.jozufozu.flywheel.backend.pipeline; + +import com.jozufozu.flywheel.backend.gl.shader.ShaderType; + +public interface TemplateData { + void vertexFooter(StringBuilder builder, ShaderCompiler file); + void fragmentFooter(StringBuilder builder, ShaderCompiler file); + + /** + * Generate the necessary glue code here. + * + * @param builder The builder to generate the source into. + * @param type The shader stage glue code is needed for. + * @param file The SourceFile with user written code. + */ + default void generateFooter(StringBuilder builder, ShaderType type, ShaderCompiler file) { + if (type == ShaderType.VERTEX) { + vertexFooter(builder, file); + } else if (type == ShaderType.FRAGMENT) { + fragmentFooter(builder, file); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShader.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShader.java deleted file mode 100644 index cffa9142b..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShader.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.jozufozu.flywheel.backend.pipeline; - -import java.util.List; -import java.util.Optional; - -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 net.minecraft.resources.ResourceLocation; - -public class WorldShader { - - public final ResourceLocation name; - public final Template template; - public final CharSequence header; - - public SourceFile mainFile; - - private CharSequence source; - private StringBuilder defines; - - public WorldShader(ResourceLocation name, Template template, FileResolution header) { - this.name = name; - this.template = template; - this.header = Optional.ofNullable(header.getFile()) - .map(SourceFile::generateFinalSource) - .orElse(""); - } - - public WorldShader setDefines(List defs) { - defines = new StringBuilder(); - - for (String def : defs) { - defines.append("#define ") - .append(def) - .append('\n'); - } - return this; - } - - public WorldShader setMainSource(SourceFile file) { - if (mainFile == file) return this; - - mainFile = file; - source = file.generateFinalSource(); - - return this; - } - - public GlShader compile(ShaderType type) { - - StringBuilder finalSource = new StringBuilder(); - - finalSource.append("#version ") - .append(template.getVersion()) - .append('\n') - .append("#extension GL_ARB_conservative_depth : enable\n") - .append("#define ") - .append(type.define) // special case shader type declaration - .append('\n') - .append(defines != null ? defines : "") - .append(header) - .append('\n') - .append(source) - .append('\n'); - - template.generateTemplateSource(finalSource, type, mainFile); - - return new GlShader(name, type, finalSource); - } - - public ProtoProgram createProgram() { - return new ProtoProgram(this); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShaderPipeline.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShaderPipeline.java index 9129cb514..c46dcbe28 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShaderPipeline.java +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShaderPipeline.java @@ -1,10 +1,6 @@ package com.jozufozu.flywheel.backend.pipeline; -import java.util.List; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.source.FileResolution; import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.core.shader.ContextAwareProgram; @@ -14,8 +10,6 @@ import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; import com.jozufozu.flywheel.core.shader.spec.ProgramState; -import net.minecraft.resources.ResourceLocation; - public class WorldShaderPipeline

implements ShaderPipeline

{ private final ExtensibleGlProgram.Factory

factory; @@ -29,38 +23,18 @@ public class WorldShaderPipeline

implements ShaderPipeli this.header = header; } - public ContextAwareProgram

compile(ProgramSpec spec) { + public ContextAwareProgram

compile(ProgramSpec spec, VertexType vertexType) { SourceFile file = spec.getSource().getFile(); - return compile(spec.name, file, spec.getStates()); - } + ShaderCompiler shader = new ShaderCompiler(spec.name, file, template, header, vertexType); - public ContextAwareProgram

compile(ResourceLocation name, SourceFile file, List variants) { - WorldShader shader = new WorldShader(name, template, header) - .setMainSource(file); - - GameStateProgram.Builder

builder = GameStateProgram.builder(compile(shader, null)); - - for (ProgramState variant : variants) { - builder.withVariant(variant.context(), compile(shader, variant)); + GameStateProgram.Builder

builder = GameStateProgram.builder(shader.compile(this.factory)); + for (ProgramState variant : spec.getStates()) { + shader.setVariant(variant); + builder.withVariant(variant.context(), shader.compile(this.factory)); } return builder.build(); } - - private P compile(WorldShader shader, @Nullable ProgramState variant) { - - if (variant != null) { - shader.setDefines(variant.defines()); - } - - ProtoProgram program = shader.createProgram() - .compilePart(ShaderType.VERTEX) - .compilePart(ShaderType.FRAGMENT) - .link() - .deleteLinkedShaders(); - - return factory.create(shader.name, program.program); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java b/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java index ba4e5f343..00f1593a6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java @@ -62,16 +62,15 @@ public class FileResolution { * Called after all files are loaded. If we can't find the file here, it doesn't exist. *

*/ - void resolve(ISourceHolder sources) { + void resolve(SourceFinder sources) { + file = sources.findSource(fileLoc); - try { - file = sources.findSource(fileLoc); - } catch (RuntimeException error) { + if (file == null) { ErrorBuilder builder = ErrorBuilder.error(String.format("could not find source for file %s", fileLoc)); // print the location of all places where this file was referenced for (Span span : foundSpans) { builder.pointAtFile(span.getSourceFile()) - .pointAt(span, 2); + .pointAt(span, 1); } Backend.log.error(builder.build()); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/Resolver.java b/src/main/java/com/jozufozu/flywheel/backend/source/Resolver.java index 185fcd4af..202b7a94d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/Resolver.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/Resolver.java @@ -28,7 +28,7 @@ public class Resolver { /** * Try and resolve all referenced source files, printing errors if any aren't found. */ - public void resolve(ISourceHolder sources) { + public void resolve(SourceFinder sources) { for (FileResolution resolution : resolutions.values()) { resolution.resolve(sources); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/ShaderLoadingException.java b/src/main/java/com/jozufozu/flywheel/backend/source/ShaderLoadingException.java index 02e013091..19024e686 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/ShaderLoadingException.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/ShaderLoadingException.java @@ -1,22 +1,11 @@ package com.jozufozu.flywheel.backend.source; public class ShaderLoadingException extends RuntimeException { + public ShaderLoadingException() { } public ShaderLoadingException(String message) { super(message); } - - public ShaderLoadingException(String message, Throwable cause) { - super(message, cause); - } - - public ShaderLoadingException(Throwable cause) { - super(cause); - } - - public ShaderLoadingException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/ShaderSources.java b/src/main/java/com/jozufozu/flywheel/backend/source/ShaderSources.java index 00898a238..97f4acead 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/ShaderSources.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/ShaderSources.java @@ -6,6 +6,8 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import javax.annotation.Nullable; + import com.google.common.collect.Lists; import com.jozufozu.flywheel.util.ResourceUtil; import com.jozufozu.flywheel.util.StringUtil; @@ -17,7 +19,7 @@ import net.minecraft.server.packs.resources.ResourceManager; /** * The main object for loading and parsing source files. */ -public class ShaderSources implements ISourceHolder { +public class ShaderSources implements SourceFinder { public static final String SHADER_DIR = "flywheel/shaders/"; public static final ArrayList EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl"); @@ -51,13 +53,9 @@ public class ShaderSources implements ISourceHolder { } @Override + @Nullable public SourceFile findSource(ResourceLocation name) { - SourceFile source = shaderSources.get(name); - if (source == null) { - throw new ShaderLoadingException(String.format("shader '%s' does not exist", name)); - } - - return source; + return shaderSources.get(name); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java index ab055553d..2b93d7168 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java @@ -10,6 +10,7 @@ import java.util.regex.Pattern; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.jozufozu.flywheel.backend.pipeline.ShaderCompiler; import com.jozufozu.flywheel.backend.source.parse.Import; import com.jozufozu.flywheel.backend.source.parse.ShaderFunction; import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; @@ -74,6 +75,23 @@ public class SourceFile { this.elided = elideSource(source, elisions).toString(); } + public Span getLineSpan(int line) { + int begin = lines.getLineStart(line); + int end = begin + lines.getLine(line).length(); + return new StringSpan(this, lines.getCharPos(begin), lines.getCharPos(end)); + } + + public Span getLineSpanNoWhitespace(int line) { + int begin = lines.getLineStart(line); + int end = begin + lines.getLine(line).length(); + + while (begin < end && Character.isWhitespace(source.charAt(begin))) { + begin++; + } + + return new StringSpan(this, lines.getCharPos(begin), lines.getCharPos(end)); + } + /** * Search this file and recursively search all imports to find a struct definition matching the given name. * @@ -120,18 +138,25 @@ public class SourceFile { return "#use " + '"' + name + '"'; } - public CharSequence generateFinalSource() { + public CharSequence generateFinalSource(ShaderCompiler env) { StringBuilder builder = new StringBuilder(); - generateFinalSource(builder); + generateFinalSource(env, builder); return builder; } - public void generateFinalSource(StringBuilder source) { + public void generateFinalSource(ShaderCompiler env, StringBuilder source) { for (Import include : imports) { SourceFile file = include.getFile(); - if (file != null) file.generateFinalSource(source); + if (file != null) file.generateFinalSource(env, source); } + + int i = env.allocateFile(this); + source.append("#line ") + .append(0) + .append(' ') + .append(i) + .append('\n'); source.append(elided); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/ISourceHolder.java b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFinder.java similarity index 73% rename from src/main/java/com/jozufozu/flywheel/backend/source/ISourceHolder.java rename to src/main/java/com/jozufozu/flywheel/backend/source/SourceFinder.java index df209dcf7..09d5f8d90 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/ISourceHolder.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFinder.java @@ -1,12 +1,15 @@ package com.jozufozu.flywheel.backend.source; +import javax.annotation.Nullable; + import net.minecraft.resources.ResourceLocation; /** * A minimal source file lookup function. */ @FunctionalInterface -public interface ISourceHolder { +public interface SourceFinder { + @Nullable SourceFile findSource(ResourceLocation name); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/SourceLines.java b/src/main/java/com/jozufozu/flywheel/backend/source/SourceLines.java index 1c04bdee7..6fd722744 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/SourceLines.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/SourceLines.java @@ -29,6 +29,48 @@ public class SourceLines { this.lines = getLines(source, lineStarts); } + public int getLineCount() { + return lines.size(); + } + + public String getLine(int lineNo) { + return lines.get(lineNo); + } + + public int getLineStart(int lineNo) { + + return lineStarts.getInt(lineNo); + } + + public CharPos getCharPos(int charPos) { + int lineNo = 0; + for (; lineNo < lineStarts.size(); lineNo++) { + int ls = lineStarts.getInt(lineNo); + + if (charPos < ls) { + break; + } + } + + lineNo -= 1; + + int lineStart = lineStarts.getInt(lineNo); + + return new CharPos(charPos, lineNo, charPos - lineStart); + } + + public String printLinesWithNumbers() { + StringBuilder builder = new StringBuilder(); + + for (int i = 0, linesSize = lines.size(); i < linesSize; i++) { + builder.append(String.format("%1$4s: ", i + 1)) + .append(lines.get(i)) + .append('\n'); + } + + return builder.toString(); + } + /** * Scan the source for line breaks, recording the position of the first character of each line. * @param source @@ -57,41 +99,4 @@ public class SourceLines { return builder.build(); } - - public CharPos getCharPos(int charPos) { - int lineNo = 0; - for (; lineNo < lineStarts.size(); lineNo++) { - int ls = lineStarts.getInt(lineNo); - - if (charPos < ls) { - break; - } - } - - lineNo -= 1; - - int lineStart = lineStarts.getInt(lineNo); - - return new CharPos(charPos, lineNo, charPos - lineStart); - } - - public int getLineCount() { - return lines.size(); - } - - public String getLine(int lineNo) { - return lines.get(lineNo); - } - - public String printLinesWithNumbers() { - StringBuilder builder = new StringBuilder(); - - for (int i = 0, linesSize = lines.size(); i < linesSize; i++) { - builder.append(String.format("%1$4s: ", i + 1)) - .append(lines.get(i)) - .append('\n'); - } - - return builder.toString(); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java index 8a908f6dc..b1ef7b2b5 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java @@ -2,9 +2,12 @@ package com.jozufozu.flywheel.backend.source.error; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.annotation.Nullable; +import com.jozufozu.flywheel.backend.pipeline.ShaderCompiler; import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.backend.source.SourceLines; import com.jozufozu.flywheel.backend.source.error.lines.ErrorLine; @@ -12,27 +15,60 @@ import com.jozufozu.flywheel.backend.source.error.lines.FileLine; import com.jozufozu.flywheel.backend.source.error.lines.HeaderLine; import com.jozufozu.flywheel.backend.source.error.lines.SourceLine; import com.jozufozu.flywheel.backend.source.error.lines.SpanHighlightLine; +import com.jozufozu.flywheel.backend.source.error.lines.TextLine; import com.jozufozu.flywheel.backend.source.span.Span; import com.jozufozu.flywheel.util.FlwUtil; public class ErrorBuilder { + private static final Pattern ERROR_LINE = Pattern.compile("(\\d+)\\((\\d+)\\) : (.*)"); + private final List lines = new ArrayList<>(); - private final Level level; + public ErrorBuilder() { - public ErrorBuilder(Level level, CharSequence msg) { - this.level = level; - - lines.add(new HeaderLine(level.toString(), msg)); } public static ErrorBuilder error(CharSequence msg) { - return new ErrorBuilder(Level.ERROR, msg); + return new ErrorBuilder() + .header(ErrorLevel.ERROR, msg); + } + + public static ErrorBuilder compError(CharSequence msg) { + return new ErrorBuilder() + .extra(msg); } public static ErrorBuilder warn(CharSequence msg) { - return new ErrorBuilder(Level.WARN, msg); + return new ErrorBuilder() + .header(ErrorLevel.WARN, msg); + } + + @Nullable + public static ErrorBuilder fromLogLine(ShaderCompiler env, String s) { + Matcher matcher = ERROR_LINE.matcher(s); + + if (matcher.find()) { + String fileId = matcher.group(1); + String lineNo = matcher.group(2); + String msg = matcher.group(3); + Span span = env.getLineSpan(Integer.parseInt(fileId), Integer.parseInt(lineNo)); + return ErrorBuilder.compError(msg) + .pointAtFile(span.getSourceFile()) + .pointAt(span, 1); + } else { + return null; + } + } + + public ErrorBuilder header(ErrorLevel level, CharSequence msg) { + lines.add(new HeaderLine(level.toString(), msg)); + return this; + } + + public ErrorBuilder extra(CharSequence msg) { + lines.add(new TextLine(msg.toString())); + return this; } public ErrorBuilder pointAtFile(SourceFile file) { @@ -42,14 +78,14 @@ public class ErrorBuilder { public ErrorBuilder hintIncludeFor(@Nullable Span span, CharSequence msg) { if (span == null) return this; + SourceFile sourceFile = span.getSourceFile(); - String builder = "add " + span.getSourceFile() - .importStatement() + ' ' + msg; + String builder = "add " + sourceFile.importStatement() + ' ' + msg + "\n defined here:"; - lines.add(new HeaderLine("hint", builder)); + header(ErrorLevel.HINT, builder); - return this.pointAtFile(span.getSourceFile()) - .pointAt(span, 1); + return this.pointAtFile(sourceFile) + .pointAt(span, 0); } public ErrorBuilder pointAt(Span span, int ctxLines) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/Level.java b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorLevel.java similarity index 75% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/Level.java rename to src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorLevel.java index ecf151fdd..cbd161969 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/Level.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorLevel.java @@ -1,13 +1,14 @@ package com.jozufozu.flywheel.backend.source.error; -public enum Level { +public enum ErrorLevel { WARN("warn"), ERROR("error"), + HINT("hint"), ; private final String error; - Level(String error) { + ErrorLevel(String error) { this.error = error; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorReporter.java b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorReporter.java index 97232a6c4..5829a8279 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorReporter.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorReporter.java @@ -1,12 +1,15 @@ package com.jozufozu.flywheel.backend.source.error; +import java.util.List; import java.util.Optional; +import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.backend.source.parse.ShaderFunction; import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.util.FlwUtil; public class ErrorReporter { @@ -42,7 +45,7 @@ public class ErrorReporter { ErrorBuilder error = ErrorBuilder.error(msg) .pointAtFile(file) - .pointAt(vertexName, 2) + .pointAt(vertexName, 1) .hintIncludeFor(span.orElse(null), hint); Backend.log.error(error.build()); @@ -64,4 +67,29 @@ public class ErrorReporter { Backend.log.error(error.build()); } + + public static void printLines(CharSequence source) { + String string = source.toString(); + + List lines = string.lines() + .toList(); + + int size = lines.size(); + + int maxWidth = FlwUtil.numDigits(size) + 1; + + StringBuilder builder = new StringBuilder().append('\n'); + + for (int i = 0; i < size; i++) { + + builder.append(i) + .append(FlwUtil.repeatChar(' ', maxWidth - FlwUtil.numDigits(i))) + .append("| ") + .append(lines.get(i)) + .append('\n'); + } + + Flywheel.LOGGER.error(builder.toString()); + } + } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/ErrorLine.java b/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/ErrorLine.java index fe3f6ec57..cac9900cb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/ErrorLine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/ErrorLine.java @@ -14,6 +14,10 @@ public interface ErrorLine { return left() + divider() + right(); } - String left(); - String right(); + default String left() { + return ""; + } + default String right() { + return ""; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/HeaderLine.java b/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/HeaderLine.java index 2488095e8..5ed78ec06 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/HeaderLine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/HeaderLine.java @@ -11,14 +11,4 @@ public record HeaderLine(String level, CharSequence message) implements ErrorLin public String build() { return level + ": " + message; } - - @Override - public String left() { - return null; - } - - @Override - public String right() { - return null; - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/TextLine.java b/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/TextLine.java new file mode 100644 index 000000000..beb66c60c --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/TextLine.java @@ -0,0 +1,9 @@ +package com.jozufozu.flywheel.backend.source.error.lines; + +public record TextLine(String msg) implements ErrorLine { + + @Override + public String build() { + return msg; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/parse/ShaderFunction.java b/src/main/java/com/jozufozu/flywheel/backend/source/parse/ShaderFunction.java index 1621debf7..92feb12a8 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/parse/ShaderFunction.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/parse/ShaderFunction.java @@ -9,7 +9,7 @@ import com.jozufozu.flywheel.backend.source.span.Span; public class ShaderFunction extends AbstractShaderElement { - public static final Pattern argument = Pattern.compile("(\\w+)\\s+(\\w+)"); + public static final Pattern argument = Pattern.compile("(?:(inout|in|out) )?(\\w+)\\s+(\\w+)"); public static final Pattern assignment = Pattern.compile("(\\w+)\\s*="); private final Span type; @@ -66,10 +66,11 @@ public class ShaderFunction extends AbstractShaderElement { while (arguments.find()) { Span self = Span.fromMatcher(args, arguments); - Span type = Span.fromMatcher(args, arguments, 1); - Span name = Span.fromMatcher(args, arguments, 2); + Span qualifier = Span.fromMatcher(args, arguments, 1); + Span type = Span.fromMatcher(args, arguments, 2); + Span name = Span.fromMatcher(args, arguments, 3); - builder.add(new Variable(self, type, name)); + builder.add(new Variable(self, qualifier, type, name)); } return builder.build(); @@ -79,7 +80,7 @@ public class ShaderFunction extends AbstractShaderElement { public String toString() { String p = parameters.stream() - .map(Variable::typeName) + .map(variable -> variable.type) .map(Span::get) .collect(Collectors.joining(",")); diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/parse/Variable.java b/src/main/java/com/jozufozu/flywheel/backend/source/parse/Variable.java index 270acee61..342684a73 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/parse/Variable.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/parse/Variable.java @@ -4,25 +4,41 @@ import com.jozufozu.flywheel.backend.source.span.Span; public class Variable extends AbstractShaderElement { - private final Span type; - private final Span name; + public final Span qualifierSpan; + public final Span type; + public final Span name; + public final Qualifier qualifier; - public Variable(Span self, Span type, Span name) { + public Variable(Span self, Span qualifier, Span type, Span name) { super(self); + this.qualifierSpan = qualifier; this.type = type; this.name = name; - } - - public Span typeName() { - return type; - } - - public Span getName() { - return name; + this.qualifier = Qualifier.fromSpan(qualifierSpan); } @Override public String toString() { return type + " " + name; } + + public enum Qualifier { + NONE, + IN, + OUT, + INOUT, + ERROR; + + public static Qualifier fromSpan(Span s) { + String span = s.toString(); + + return switch (span) { + case "" -> NONE; + case "in" -> IN; + case "inout" -> INOUT; + case "out" -> OUT; + default -> ERROR; + }; + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/Contexts.java b/src/main/java/com/jozufozu/flywheel/core/Contexts.java index 744ef5ae6..3261cd19d 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Contexts.java +++ b/src/main/java/com/jozufozu/flywheel/core/Contexts.java @@ -3,7 +3,6 @@ package com.jozufozu.flywheel.core; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.GameStateRegistry; -import com.jozufozu.flywheel.backend.pipeline.InstancingTemplate; import com.jozufozu.flywheel.backend.pipeline.ShaderPipeline; import com.jozufozu.flywheel.backend.pipeline.WorldShaderPipeline; import com.jozufozu.flywheel.backend.source.FileResolution; @@ -32,8 +31,8 @@ public class Contexts { FileResolution crumblingBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.CRUMBLING, ".glsl")); FileResolution worldBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.WORLD, ".glsl")); - ShaderPipeline crumblingPipeline = new WorldShaderPipeline<>(CrumblingProgram::new, InstancingTemplate.INSTANCE, crumblingBuiltins); - ShaderPipeline worldPipeline = new WorldShaderPipeline<>(WorldProgram::new, InstancingTemplate.INSTANCE, worldBuiltins); + ShaderPipeline crumblingPipeline = new WorldShaderPipeline<>(CrumblingProgram::new, Templates.INSTANCING, crumblingBuiltins); + ShaderPipeline worldPipeline = new WorldShaderPipeline<>(WorldProgram::new, Templates.INSTANCING, worldBuiltins); CRUMBLING = backend.register(WorldContext.builder(backend, Names.CRUMBLING).build(crumblingPipeline)); WORLD = backend.register(WorldContext.builder(backend, Names.WORLD).build(worldPipeline)); diff --git a/src/main/java/com/jozufozu/flywheel/core/Templates.java b/src/main/java/com/jozufozu/flywheel/core/Templates.java new file mode 100644 index 000000000..7bd3f718f --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/Templates.java @@ -0,0 +1,12 @@ +package com.jozufozu.flywheel.core; + +import com.jozufozu.flywheel.backend.gl.GLSLVersion; +import com.jozufozu.flywheel.backend.pipeline.InstancingTemplateData; +import com.jozufozu.flywheel.backend.pipeline.OneShotTemplateData; +import com.jozufozu.flywheel.backend.pipeline.Template; + +public class Templates { + + public static final Template INSTANCING = new Template<>(GLSLVersion.V330, InstancingTemplateData::new); + public static final Template ONE_SHOT = new Template<>(GLSLVersion.V150, OneShotTemplateData::new); +} diff --git a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java index 5306d605c..d9b608608 100644 --- a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java @@ -6,11 +6,13 @@ import java.util.Objects; import java.util.function.Supplier; import java.util.stream.Stream; +import com.jozufozu.flywheel.api.shader.FlexibleShader; import com.jozufozu.flywheel.api.struct.Instanced; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.ShaderContext; +import com.jozufozu.flywheel.backend.pipeline.LazyCompiler; import com.jozufozu.flywheel.backend.pipeline.ShaderPipeline; -import com.jozufozu.flywheel.core.shader.ContextAwareProgram; +import com.jozufozu.flywheel.backend.source.ShaderLoadingException; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; @@ -18,7 +20,7 @@ import net.minecraft.resources.ResourceLocation; public class WorldContext

implements ShaderContext

{ public final Backend backend; - protected final Map> programs = new HashMap<>(); + protected final Map> programs = new HashMap<>(); protected final ResourceLocation name; protected final Supplier> specStream; @@ -44,25 +46,27 @@ public class WorldContext

implements ShaderContext

{ private void loadSpec(ProgramSpec spec) { try { - programs.put(spec.name, pipeline.compile(spec)); + programs.put(spec.name, new LazyCompiler<>(pipeline, spec)); Backend.log.debug("Loaded program {}", spec.name); } catch (Exception e) { Backend.log.error("Error loading program {}", spec.name); - Backend.log.error("", e); + if (!(e instanceof ShaderLoadingException)) { + Backend.log.error("", e); + } backend.loader.notifyError(); } } @Override - public Supplier

getProgramSupplier(ResourceLocation spec) { + public FlexibleShader

getProgramSupplier(ResourceLocation spec) { return programs.get(spec); } @Override public void delete() { programs.values() - .forEach(ContextAwareProgram::delete); + .forEach(LazyCompiler::delete); programs.clear(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java b/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java index d7111f706..ecdde9ea3 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java @@ -27,8 +27,8 @@ public class BufferLayout { int numAttributes = 0, stride = 0; for (LayoutItem spec : allAttributes) { - numAttributes += spec.getAttributeCount(); - stride += spec.getSize(); + numAttributes += spec.attributeCount(); + stride += spec.size(); } this.numAttributes = numAttributes; this.stride = stride; diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java b/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java index 1021296ac..232879964 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java @@ -19,6 +19,6 @@ public class CommonItems { public static final PrimitiveItem LIGHT_SHORT = new PrimitiveItem(GlNumericType.USHORT, 2, true); public static final PrimitiveItem NORMALIZED_BYTE = new PrimitiveItem(GlNumericType.BYTE, 1, true); - public static final LayoutItem PADDING_BYTE = new PaddingItem(1); + public static final LayoutItem PADDING_BYTE = new Padding(1); } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/LayoutItem.java b/src/main/java/com/jozufozu/flywheel/core/layout/LayoutItem.java index ae910dc51..cc0f6fabe 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/LayoutItem.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/LayoutItem.java @@ -4,7 +4,7 @@ public interface LayoutItem { void vertexAttribPointer(int stride, int index, int offset); - int getSize(); + int size(); - int getAttributeCount(); + int attributeCount(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/MatrixItems.java b/src/main/java/com/jozufozu/flywheel/core/layout/MatrixItems.java index f9d8ffe2e..1ca6f2fec 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/MatrixItems.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/MatrixItems.java @@ -26,12 +26,13 @@ public enum MatrixItems implements LayoutItem { } @Override - public int getSize() { + public int size() { return GlNumericType.FLOAT.getByteWidth() * rows * cols; } @Override - public int getAttributeCount() { + public int attributeCount() { return rows; } + } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/PaddingItem.java b/src/main/java/com/jozufozu/flywheel/core/layout/Padding.java similarity index 62% rename from src/main/java/com/jozufozu/flywheel/core/layout/PaddingItem.java rename to src/main/java/com/jozufozu/flywheel/core/layout/Padding.java index 788aa9b3d..7b3abbed3 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/PaddingItem.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/Padding.java @@ -1,6 +1,6 @@ package com.jozufozu.flywheel.core.layout; -record PaddingItem(int bytes) implements LayoutItem { +record Padding(int bytes) implements LayoutItem { @Override public void vertexAttribPointer(int stride, int index, int offset) { @@ -8,12 +8,13 @@ record PaddingItem(int bytes) implements LayoutItem { } @Override - public int getSize() { + public int size() { return bytes; } @Override - public int getAttributeCount() { + public int attributeCount() { return 0; } + } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java b/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java index be1373867..c7c1bd6c0 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java @@ -30,12 +30,13 @@ public class PrimitiveItem implements LayoutItem { } @Override - public int getSize() { + public int size() { return size; } @Override - public int getAttributeCount() { + public int attributeCount() { return attributeCount; } + } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java index eb77286fc..4a4cb1021 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java @@ -4,8 +4,8 @@ import java.nio.ByteBuffer; import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.core.layout.CommonItems; import com.jozufozu.flywheel.core.layout.BufferLayout; +import com.jozufozu.flywheel.core.layout.CommonItems; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.datafixers.util.Pair; @@ -36,6 +36,27 @@ public class BlockVertex implements VertexType { return new BlockVertexListUnsafe(buffer, vertexCount); } + @Override + public String writeShaderHeader() { + return """ +layout (location = 0) in vec3 _flw_v_pos; +layout (location = 1) in vec4 _flw_v_color; +layout (location = 2) in vec2 _flw_v_texCoords; +layout (location = 3) in vec2 _flw_v_light; +layout (location = 4) in vec3 _flw_v_normal; + +Vertex FLWCreateVertex() { + Vertex v; + v.pos = _flw_v_pos; + v.color = _flw_v_color; + v.texCoords = _flw_v_texCoords; + v.light = _flw_v_light; + v.normal = _flw_v_normal; + return v; +} + """; + } + public VertexList createReader(BufferBuilder bufferBuilder) { // TODO: try to avoid virtual model rendering Pair pair = bufferBuilder.popNextBuffer(); diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java index feb7ff348..63610ee87 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java @@ -3,8 +3,8 @@ package com.jozufozu.flywheel.core.vertex; import java.nio.ByteBuffer; import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.core.layout.CommonItems; import com.jozufozu.flywheel.core.layout.BufferLayout; +import com.jozufozu.flywheel.core.layout.CommonItems; public class PosTexNormalVertex implements VertexType { @@ -26,4 +26,23 @@ public class PosTexNormalVertex implements VertexType { public PosTexNormalVertexListUnsafe createReader(ByteBuffer buffer, int vertexCount) { return new PosTexNormalVertexListUnsafe(buffer, vertexCount); } + + @Override + public String writeShaderHeader() { + return """ +layout (location = 0) in vec3 _flw_v_pos; +layout (location = 1) in vec2 _flw_v_texCoords; +layout (location = 2) in vec3 _flw_v_normal; + +Vertex FLWCreateVertex() { + Vertex v; + v.pos = _flw_v_pos; + v.color = vec4(1.); + v.texCoords = _flw_v_texCoords; + v.light = vec2(0.); + v.normal = _flw_v_normal; + return v; +} + """; + } } diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/block.frag b/src/main/resources/assets/flywheel/flywheel/shaders/block.frag index d8e5169fe..70bbe95f4 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/block.frag +++ b/src/main/resources/assets/flywheel/flywheel/shaders/block.frag @@ -1,5 +1,5 @@ -struct BlockFrag { +struct Fragment { vec2 texCoords; vec4 color; float diffuse; @@ -7,11 +7,9 @@ struct BlockFrag { }; #if defined(FRAGMENT_SHADER) -void fragment(BlockFrag r) { +vec4 fragment(Fragment r) { vec4 tex = FLWBlockTexture(r.texCoords); - vec4 color = vec4(tex.rgb * FLWLight(r.light).rgb * r.diffuse, tex.a) * r.color; - - FLWFinalizeColor(color); + return vec4(tex.rgb * FLWLight(r.light).rgb * r.diffuse, tex.a) * r.color; } #endif diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/context/crumbling.glsl b/src/main/resources/assets/flywheel/flywheel/shaders/context/crumbling.glsl index c9ab41cbe..958941126 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/context/crumbling.glsl +++ b/src/main/resources/assets/flywheel/flywheel/shaders/context/crumbling.glsl @@ -1,4 +1,5 @@ #use "flywheel:context/fog.glsl" +#use "flywheel:core/diffuse.glsl" uniform float uTime; uniform mat4 uViewProjection; @@ -11,17 +12,11 @@ uniform sampler2D uCrumbling; uniform vec2 uWindowSize; -void FLWFinalizeNormal(inout vec3 normal) { - // noop -} - #if defined(VERTEX_SHADER) -void FLWFinalizeWorldPos(inout vec4 worldPos) { - #if defined(USE_FOG) - FragDistance = cylindrical_distance(worldPos.xyz, uCameraPos); - #endif +vec4 FLWVertex(inout Vertex v) { + FragDistance = cylindrical_distance(v.pos, uCameraPos); - gl_Position = uViewProjection * worldPos; + return uViewProjection * vec4(v.pos, 1.); } #elif defined(FRAGMENT_SHADER) diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl b/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl index 1503ed993..58ad850b6 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl +++ b/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl @@ -1,4 +1,5 @@ #use "flywheel:context/fog.glsl" +#use "flywheel:core/diffuse.glsl" uniform float uTime; uniform mat4 uViewProjection; @@ -10,15 +11,12 @@ uniform sampler2D uLightMap; uniform vec2 uWindowSize; -void FLWFinalizeNormal(inout vec3 normal) { - // noop -} - #if defined(VERTEX_SHADER) -void FLWFinalizeWorldPos(inout vec4 worldPos) { - FragDistance = cylindrical_distance(worldPos.xyz, uCameraPos); - gl_Position = uViewProjection * worldPos; +vec4 FLWVertex(inout Vertex v) { + FragDistance = cylindrical_distance(v.pos, uCameraPos); + + return uViewProjection * vec4(v.pos, 1.); } #elif defined(FRAGMENT_SHADER) diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl b/src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl deleted file mode 100644 index 48e713b43..000000000 --- a/src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl +++ /dev/null @@ -1,5 +0,0 @@ -struct Vertex { - vec3 pos; - vec2 texCoords; - vec3 normal; -}; diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/model.vert b/src/main/resources/assets/flywheel/flywheel/shaders/model.vert index 603d17e54..075269708 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/model.vert +++ b/src/main/resources/assets/flywheel/flywheel/shaders/model.vert @@ -1,7 +1,7 @@ -#use "flywheel:core/diffuse.glsl" -#use "flywheel:data/modelvertex.glsl" #use "flywheel:block.frag" +#if defined(VERTEX_SHADER) + struct Instance { vec2 light; vec4 color; @@ -9,26 +9,10 @@ struct Instance { mat3 normalMat; }; -#if defined(VERTEX_SHADER) -BlockFrag vertex(Vertex v, Instance i) { - vec4 worldPos = i.transform * vec4(v.pos, 1.); - - vec3 norm = i.normalMat * v.normal; - - FLWFinalizeWorldPos(worldPos); - FLWFinalizeNormal(norm); - - norm = normalize(norm); - - BlockFrag b; - b.diffuse = diffuse(norm); - b.texCoords = v.texCoords; - b.light = i.light; - #if defined(DEBUG_NORMAL) - b.color = vec4(norm, 1.); - #else - b.color = i.color; - #endif - return b; +void vertex(inout Vertex v, Instance i) { + v.pos = (i.transform * vec4(v.pos, 1.)).xyz; + v.normal = i.normalMat * v.normal; + v.color = i.color; + v.light = i.light; } #endif diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/oriented.vert b/src/main/resources/assets/flywheel/flywheel/shaders/oriented.vert index bac28858b..b89479a8b 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/oriented.vert +++ b/src/main/resources/assets/flywheel/flywheel/shaders/oriented.vert @@ -1,9 +1,8 @@ -#use "flywheel:core/quaternion.glsl" -#use "flywheel:core/diffuse.glsl" - -#use "flywheel:data/modelvertex.glsl" #use "flywheel:block.frag" +#if defined(VERTEX_SHADER) +#use "flywheel:core/quaternion.glsl" + struct Oriented { vec2 light; vec4 color; @@ -12,24 +11,10 @@ struct Oriented { vec4 rotation; }; -#if defined(VERTEX_SHADER) -BlockFrag vertex(Vertex v, Oriented o) { - vec4 worldPos = vec4(rotateVertexByQuat(v.pos - o.pivot, o.rotation) + o.pivot + o.pos, 1.); - - vec3 norm = rotateVertexByQuat(v.normal, o.rotation); - - FLWFinalizeWorldPos(worldPos); - FLWFinalizeNormal(norm); - - BlockFrag b; - b.diffuse = diffuse(norm); - b.texCoords = v.texCoords; - b.light = o.light; - #if defined(DEBUG_NORMAL) - b.color = vec4(norm, 1.); - #else - b.color = o.color; - #endif - return b; +void vertex(inout Vertex v, Oriented o) { + v.pos = rotateVertexByQuat(v.pos - o.pivot, o.rotation) + o.pivot + o.pos; + v.normal = rotateVertexByQuat(v.normal, o.rotation); + v.color = o.color; + v.light = o.light; } #endif diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/smooth_oriented.glsl b/src/main/resources/assets/flywheel/flywheel/shaders/smooth_oriented.glsl deleted file mode 100644 index c657678aa..000000000 --- a/src/main/resources/assets/flywheel/flywheel/shaders/smooth_oriented.glsl +++ /dev/null @@ -1,53 +0,0 @@ -#use "flywheel:core/matutils.glsl" -#use "flywheel:core/quaternion.glsl" -#use "flywheel:core/diffuse.glsl" - -struct Oriented { -// each vec 4 is 2 light coords packed -// x z - vec4 lightA;// lo, lo - vec4 lightB;// hi, lo - vec4 lightC;// hi, hi - vec4 lightD;// lo, hi - - vec3 loCorner; - vec3 size; - - vec4 color; - vec3 pos; - vec3 pivot; - vec4 rotation; -}; - -#use "flywheel:data/modelvertex.glsl" -#use "flywheel:block.frag" - -BlockFrag vertex(Vertex v, Oriented o) { - vec4 worldPos = vec4(rotateVertexByQuat(v.pos - o.pivot, o.rotation) + o.pivot + o.pos, 1.); - - vec3 norm = rotateVertexByQuat(v.normal, o.rotation); - - FLWFinalizeWorldPos(worldPos); - FLWFinalizeNormal(norm); - - // manual trilinear interpolation - vec3 lightPos = (worldPos.xyz - o.loCorner) / o.size; - - vec4 lightLoZ = mix(lightA, lightB, lightPos.x);// lo z - vec4 lightHiZ = mix(lightD, lightC, lightPos.x);// hi z - - vec4 lightE = mix(lightLoZ, lightHiZ, lightPos.z);// - - vec2 lightCoord = mix(lightE.xy, lightE.zw, lightPos.y); - - BlockFrag b; - b.diffuse = diffuse(norm); - b.texCoords = v.texCoords; - b.light = lightCoord; - #if defined(DEBUG_NORMAL) - b.color = vec4(norm, 1.); - #else - b.color = o.color; - #endif - return b; -} From 1f5f2a547634aba26e67f4b92e154c65ef4d27f7 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Fri, 31 Dec 2021 12:08:07 -0800 Subject: [PATCH 02/10] Compile everything on the fly - Simplify game state system - Need some way to re-add errors on load. - Streamline shader compilation, reduce map lookups - Move pipeline package from backend to core - Simplify interfaces and remove unnecessary classes --- .../flywheel/api/shader/FlexibleShader.java | 15 --- .../flywheel/backend/ShaderContext.java | 8 +- .../flywheel/backend/gl/shader/GlShader.java | 30 +---- .../instancing/InstancingEngine.java | 6 - .../backend/pipeline/LazyCompiler.java | 33 ------ .../flywheel/backend/pipeline/Shader.java | 6 - .../backend/pipeline/ShaderInput.java | 38 ------- .../backend/pipeline/ShaderPipeline.java | 16 --- .../backend/pipeline/WorldShaderPipeline.java | 40 ------- .../backend/source/FileResolution.java | 4 +- .../flywheel/backend/source/SourceFile.java | 20 +--- .../backend/source/error/ErrorBuilder.java | 2 +- .../com/jozufozu/flywheel/core/Contexts.java | 8 +- .../com/jozufozu/flywheel/core/Templates.java | 6 +- .../jozufozu/flywheel/core/WorldContext.java | 32 +++--- .../flywheel/core/materials/BasicData.java | 10 ++ .../core/pipeline/CachingCompiler.java | 38 +++++++ .../core/pipeline/CompilationContext.java | 35 ++++++ .../pipeline/InstancingTemplateData.java | 4 +- .../pipeline/OneShotTemplateData.java | 2 +- .../core/pipeline/PipelineCompiler.java | 13 +++ .../pipeline/ProgramAssembler.java | 2 +- .../pipeline/ShaderCompiler.java | 103 ++++++++++-------- .../{backend => core}/pipeline/Template.java | 2 +- .../pipeline/TemplateData.java | 2 +- .../pipeline/TypeHelper.java | 2 +- .../flywheel/core/pipeline/WorldCompiler.java | 33 ++++++ .../pipeline/package-info.java | 2 +- .../core/shader/ContextAwareProgram.java | 26 ----- .../core/shader/GameStateProgram.java | 62 ----------- .../shader/gamestate/IGameStateProvider.java | 2 +- .../gamestate/NormalDebugStateProvider.java | 3 +- .../spec/BooleanGameStateCondition.java | 37 ------- .../shader/spec/IBooleanStateProvider.java | 13 --- .../core/shader/spec/IGameStateCondition.java | 14 --- .../core/shader/spec/ProgramSpec.java | 40 ++++++- .../core/shader/spec/ProgramState.java | 21 +--- .../shader/spec/SpecificValueCondition.java | 43 -------- .../flywheel/flywheel/programs/model.json | 5 +- .../flywheel/flywheel/programs/oriented.json | 5 +- 40 files changed, 269 insertions(+), 514 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/api/shader/FlexibleShader.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/pipeline/LazyCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/pipeline/Shader.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderInput.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderPipeline.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShaderPipeline.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/pipeline/CachingCompiler.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java rename src/main/java/com/jozufozu/flywheel/{backend => core}/pipeline/InstancingTemplateData.java (97%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/pipeline/OneShotTemplateData.java (98%) create mode 100644 src/main/java/com/jozufozu/flywheel/core/pipeline/PipelineCompiler.java rename src/main/java/com/jozufozu/flywheel/{backend => core}/pipeline/ProgramAssembler.java (97%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/pipeline/ShaderCompiler.java (62%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/pipeline/Template.java (97%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/pipeline/TemplateData.java (93%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/pipeline/TypeHelper.java (94%) create mode 100644 src/main/java/com/jozufozu/flywheel/core/pipeline/WorldCompiler.java rename src/main/java/com/jozufozu/flywheel/{backend => core}/pipeline/package-info.java (78%) delete mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/ContextAwareProgram.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/GameStateProgram.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/spec/BooleanGameStateCondition.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/spec/IBooleanStateProvider.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/spec/IGameStateCondition.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/spec/SpecificValueCondition.java diff --git a/src/main/java/com/jozufozu/flywheel/api/shader/FlexibleShader.java b/src/main/java/com/jozufozu/flywheel/api/shader/FlexibleShader.java deleted file mode 100644 index a46802373..000000000 --- a/src/main/java/com/jozufozu/flywheel/api/shader/FlexibleShader.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.jozufozu.flywheel.api.shader; - -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; - -/** - * Represents a vertex format agnostic shader. - */ -public interface FlexibleShader

{ - - /** - * Get a version of this shader that accepts the given VertexType as input. - */ - P get(VertexType type); -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java b/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java index 96c5e563d..4367194eb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java +++ b/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java @@ -1,6 +1,5 @@ package com.jozufozu.flywheel.backend; -import com.jozufozu.flywheel.api.shader.FlexibleShader; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; @@ -8,12 +7,7 @@ import net.minecraft.resources.ResourceLocation; public interface ShaderContext

{ - default P getProgram(ResourceLocation loc, VertexType inputType) { - return this.getProgramSupplier(loc) - .get(inputType); - } - - FlexibleShader

getProgramSupplier(ResourceLocation loc); + P getProgram(ResourceLocation loc, VertexType vertexType); /** * Load all programs associated with this context. This might be just one, if the context is very specialized. diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java index bde532d88..c1f63c1bd 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java @@ -1,16 +1,11 @@ package com.jozufozu.flywheel.backend.gl.shader; -import java.util.List; - import org.lwjgl.opengl.GL20; -import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlObject; import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; -import com.jozufozu.flywheel.backend.pipeline.ShaderCompiler; import com.jozufozu.flywheel.backend.source.ShaderLoadingException; -import com.jozufozu.flywheel.backend.source.error.ErrorBuilder; -import com.jozufozu.flywheel.backend.source.error.ErrorReporter; +import com.jozufozu.flywheel.core.pipeline.ShaderCompiler; import net.minecraft.resources.ResourceLocation; @@ -30,27 +25,7 @@ public class GlShader extends GlObject { String log = GL20.glGetShaderInfoLog(handle); if (!log.isEmpty()) { - List lines = log.lines() - .toList(); - - boolean needsSourceDump = false; - - StringBuilder errors = new StringBuilder(); - for (String line : lines) { - ErrorBuilder builder = env.parseCompilerError(line); - - if (builder != null) { - errors.append(builder.build()); - } else { - errors.append(line).append('\n'); - needsSourceDump = true; - } - } - Backend.LOGGER.error("Errors compiling '" + name + "': \n" + errors); - if (needsSourceDump) { - // TODO: generated code gets its own "file" - ErrorReporter.printLines(source); - } + env.printShaderInfoLog(source, log, this.name); } if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) { @@ -64,4 +39,5 @@ public class GlShader extends GlObject { protected void deleteInternal(int handle) { GL20.glDeleteShader(handle); } + } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index 4366b5091..41b102cff 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -8,7 +8,6 @@ import java.util.stream.Stream; import javax.annotation.Nullable; import com.jozufozu.flywheel.api.MaterialGroup; -import com.jozufozu.flywheel.api.shader.FlexibleShader; import com.jozufozu.flywheel.backend.RenderLayer; import com.jozufozu.flywheel.backend.gl.GlVertexArray; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; @@ -24,7 +23,6 @@ import net.minecraft.client.Camera; import net.minecraft.client.renderer.RenderType; import net.minecraft.core.BlockPos; import net.minecraft.core.Vec3i; -import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; public class InstancingEngine

implements Engine { @@ -126,10 +124,6 @@ public class InstancingEngine

implements Engine { } } - public FlexibleShader

getProgram(ResourceLocation name) { - return context.getProgramSupplier(name); - } - @Override public Vec3i getOriginCoordinate() { return originCoordinate; diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/LazyCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/LazyCompiler.java deleted file mode 100644 index a8b57c4ba..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/LazyCompiler.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.jozufozu.flywheel.backend.pipeline; - -import java.util.HashMap; -import java.util.Map; - -import com.jozufozu.flywheel.api.shader.FlexibleShader; -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.core.shader.ContextAwareProgram; -import com.jozufozu.flywheel.core.shader.WorldProgram; -import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; - -public class LazyCompiler

implements FlexibleShader

{ - - private final ShaderPipeline

pipeline; - private final ProgramSpec spec; - - private final Map> cache = new HashMap<>(); - - public LazyCompiler(ShaderPipeline

pipeline, ProgramSpec spec) { - - this.pipeline = pipeline; - this.spec = spec; - } - - public void delete() { - cache.values().forEach(ContextAwareProgram::delete); - } - - @Override - public P get(VertexType type) { - return cache.computeIfAbsent(type, t -> pipeline.compile(spec, t)).get(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/Shader.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/Shader.java deleted file mode 100644 index bf7aece43..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/Shader.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.jozufozu.flywheel.backend.pipeline; - -public class Shader { - - -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderInput.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderInput.java deleted file mode 100644 index bf9b3b95c..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderInput.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.jozufozu.flywheel.backend.pipeline; - -import java.util.Collection; -import java.util.stream.Collectors; - -import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; -import com.jozufozu.flywheel.backend.source.parse.StructField; - -/** - * A single input to a shader. - */ -public class ShaderInput { - public final CharSequence name; - public final int attribCount; - - public ShaderInput(CharSequence name, int attribCount) { - this.name = name; - this.attribCount = attribCount; - } - - public ShaderInput withPrefix(CharSequence prefix) { - return new ShaderInput(prefix.toString() + name, attribCount); - } - - public static Collection fromStruct(ShaderStruct struct, String prefix) { - return struct.getFields() - .stream() - .map(ShaderInput::from) - .map(a -> a.withPrefix(prefix)) - .collect(Collectors.toList()); - } - - public static ShaderInput from(StructField field) { - int attributeCount = TypeHelper.getAttributeCount(field.type); - - return new ShaderInput(field.name, attributeCount); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderPipeline.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderPipeline.java deleted file mode 100644 index a6f94413f..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderPipeline.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.jozufozu.flywheel.backend.pipeline; - -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.core.shader.ContextAwareProgram; -import com.jozufozu.flywheel.core.shader.WorldProgram; -import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; - -/** - * The main interface for compiling usable shaders from program specs. - * @param

the type of the program that this pipeline compiles. - */ -public interface ShaderPipeline

{ - - ContextAwareProgram

compile(ProgramSpec spec, VertexType vertexType); - -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShaderPipeline.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShaderPipeline.java deleted file mode 100644 index c46dcbe28..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShaderPipeline.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.jozufozu.flywheel.backend.pipeline; - -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.backend.source.FileResolution; -import com.jozufozu.flywheel.backend.source.SourceFile; -import com.jozufozu.flywheel.core.shader.ContextAwareProgram; -import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram; -import com.jozufozu.flywheel.core.shader.GameStateProgram; -import com.jozufozu.flywheel.core.shader.WorldProgram; -import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; -import com.jozufozu.flywheel.core.shader.spec.ProgramState; - -public class WorldShaderPipeline

implements ShaderPipeline

{ - - private final ExtensibleGlProgram.Factory

factory; - - private final Template template; - private final FileResolution header; - - public WorldShaderPipeline(ExtensibleGlProgram.Factory

factory, Template template, FileResolution header) { - this.factory = factory; - this.template = template; - this.header = header; - } - - public ContextAwareProgram

compile(ProgramSpec spec, VertexType vertexType) { - - SourceFile file = spec.getSource().getFile(); - - ShaderCompiler shader = new ShaderCompiler(spec.name, file, template, header, vertexType); - - GameStateProgram.Builder

builder = GameStateProgram.builder(shader.compile(this.factory)); - for (ProgramState variant : spec.getStates()) { - shader.setVariant(variant); - builder.withVariant(variant.context(), shader.compile(this.factory)); - } - - return builder.build(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java b/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java index f186543aa..42b5f8dac 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java @@ -3,8 +3,6 @@ package com.jozufozu.flywheel.backend.source; import java.util.ArrayList; import java.util.List; -import javax.annotation.Nullable; - import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.source.error.ErrorBuilder; import com.jozufozu.flywheel.backend.source.span.Span; @@ -37,7 +35,6 @@ public class FileResolution { return fileLoc; } - @Nullable public SourceFile getFile() { return file; } @@ -73,6 +70,7 @@ public class FileResolution { .pointAt(span, 1); } Backend.LOGGER.error(builder.build()); + throw new ShaderLoadingException(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java index 2b93d7168..65ba34a3e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java @@ -10,13 +10,13 @@ import java.util.regex.Pattern; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.jozufozu.flywheel.backend.pipeline.ShaderCompiler; import com.jozufozu.flywheel.backend.source.parse.Import; import com.jozufozu.flywheel.backend.source.parse.ShaderFunction; import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; import com.jozufozu.flywheel.backend.source.span.ErrorSpan; import com.jozufozu.flywheel.backend.source.span.Span; import com.jozufozu.flywheel.backend.source.span.StringSpan; +import com.jozufozu.flywheel.core.pipeline.ShaderCompiler; import net.minecraft.resources.ResourceLocation; @@ -138,12 +138,6 @@ public class SourceFile { return "#use " + '"' + name + '"'; } - public CharSequence generateFinalSource(ShaderCompiler env) { - StringBuilder builder = new StringBuilder(); - generateFinalSource(env, builder); - return builder; - } - public void generateFinalSource(ShaderCompiler env, StringBuilder source) { for (Import include : imports) { SourceFile file = include.getFile(); @@ -151,24 +145,16 @@ public class SourceFile { if (file != null) file.generateFinalSource(env, source); } - int i = env.allocateFile(this); source.append("#line ") .append(0) .append(' ') - .append(i) + .append(env.getFileID(this)) .append('\n'); source.append(elided); } public String printSource() { - StringBuilder builder = new StringBuilder(); - - builder.append("Source for shader '") - .append(name) - .append("':\n") - .append(lines.printLinesWithNumbers()); - - return builder.toString(); + return "Source for shader '" + name + "':\n" + lines.printLinesWithNumbers(); } private static CharSequence elideSource(String source, List elisions) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java index b1ef7b2b5..d917ca186 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java @@ -7,7 +7,6 @@ import java.util.regex.Pattern; import javax.annotation.Nullable; -import com.jozufozu.flywheel.backend.pipeline.ShaderCompiler; import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.backend.source.SourceLines; import com.jozufozu.flywheel.backend.source.error.lines.ErrorLine; @@ -17,6 +16,7 @@ import com.jozufozu.flywheel.backend.source.error.lines.SourceLine; import com.jozufozu.flywheel.backend.source.error.lines.SpanHighlightLine; import com.jozufozu.flywheel.backend.source.error.lines.TextLine; import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.core.pipeline.ShaderCompiler; import com.jozufozu.flywheel.util.FlwUtil; public class ErrorBuilder { diff --git a/src/main/java/com/jozufozu/flywheel/core/Contexts.java b/src/main/java/com/jozufozu/flywheel/core/Contexts.java index 3261cd19d..0180f98a8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Contexts.java +++ b/src/main/java/com/jozufozu/flywheel/core/Contexts.java @@ -3,11 +3,11 @@ package com.jozufozu.flywheel.core; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.GameStateRegistry; -import com.jozufozu.flywheel.backend.pipeline.ShaderPipeline; -import com.jozufozu.flywheel.backend.pipeline.WorldShaderPipeline; import com.jozufozu.flywheel.backend.source.FileResolution; import com.jozufozu.flywheel.backend.source.Resolver; import com.jozufozu.flywheel.core.crumbling.CrumblingProgram; +import com.jozufozu.flywheel.core.pipeline.PipelineCompiler; +import com.jozufozu.flywheel.core.pipeline.WorldCompiler; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.core.shader.gamestate.NormalDebugStateProvider; import com.jozufozu.flywheel.event.GatherContextEvent; @@ -31,8 +31,8 @@ public class Contexts { FileResolution crumblingBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.CRUMBLING, ".glsl")); FileResolution worldBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.WORLD, ".glsl")); - ShaderPipeline crumblingPipeline = new WorldShaderPipeline<>(CrumblingProgram::new, Templates.INSTANCING, crumblingBuiltins); - ShaderPipeline worldPipeline = new WorldShaderPipeline<>(WorldProgram::new, Templates.INSTANCING, worldBuiltins); + PipelineCompiler crumblingPipeline = new WorldCompiler<>(CrumblingProgram::new, Templates.INSTANCING, crumblingBuiltins); + PipelineCompiler worldPipeline = new WorldCompiler<>(WorldProgram::new, Templates.INSTANCING, worldBuiltins); CRUMBLING = backend.register(WorldContext.builder(backend, Names.CRUMBLING).build(crumblingPipeline)); WORLD = backend.register(WorldContext.builder(backend, Names.WORLD).build(worldPipeline)); diff --git a/src/main/java/com/jozufozu/flywheel/core/Templates.java b/src/main/java/com/jozufozu/flywheel/core/Templates.java index 7bd3f718f..df6f04b35 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Templates.java +++ b/src/main/java/com/jozufozu/flywheel/core/Templates.java @@ -1,9 +1,9 @@ package com.jozufozu.flywheel.core; import com.jozufozu.flywheel.backend.gl.GLSLVersion; -import com.jozufozu.flywheel.backend.pipeline.InstancingTemplateData; -import com.jozufozu.flywheel.backend.pipeline.OneShotTemplateData; -import com.jozufozu.flywheel.backend.pipeline.Template; +import com.jozufozu.flywheel.core.pipeline.InstancingTemplateData; +import com.jozufozu.flywheel.core.pipeline.OneShotTemplateData; +import com.jozufozu.flywheel.core.pipeline.Template; public class Templates { diff --git a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java index de1d1bea5..6b3cd99b0 100644 --- a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java @@ -6,13 +6,13 @@ import java.util.Objects; import java.util.function.Supplier; import java.util.stream.Stream; -import com.jozufozu.flywheel.api.shader.FlexibleShader; import com.jozufozu.flywheel.api.struct.Instanced; +import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.ShaderContext; -import com.jozufozu.flywheel.backend.pipeline.LazyCompiler; -import com.jozufozu.flywheel.backend.pipeline.ShaderPipeline; import com.jozufozu.flywheel.backend.source.ShaderLoadingException; +import com.jozufozu.flywheel.core.pipeline.CachingCompiler; +import com.jozufozu.flywheel.core.pipeline.PipelineCompiler; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; @@ -20,17 +20,16 @@ import net.minecraft.resources.ResourceLocation; public class WorldContext

implements ShaderContext

{ public final Backend backend; - protected final Map> programs = new HashMap<>(); + protected final Map programs = new HashMap<>(); protected final ResourceLocation name; protected final Supplier> specStream; + private final CachingCompiler

programCache; - public final ShaderPipeline

pipeline; - - public WorldContext(Backend backend, ResourceLocation name, Supplier> specStream, ShaderPipeline

pipeline) { + public WorldContext(Backend backend, ResourceLocation name, Supplier> specStream, PipelineCompiler

pipeline) { this.backend = backend; this.name = name; this.specStream = specStream; - this.pipeline = pipeline; + this.programCache = new CachingCompiler<>(pipeline); } @Override @@ -46,7 +45,7 @@ public class WorldContext

implements ShaderContext

{ private void loadSpec(ProgramSpec spec) { try { - programs.put(spec.name, new LazyCompiler<>(pipeline, spec)); + programs.put(spec.name, spec); Backend.LOGGER.debug("Loaded program {}", spec.name); } catch (Exception e) { @@ -59,14 +58,19 @@ public class WorldContext

implements ShaderContext

{ } @Override - public FlexibleShader

getProgramSupplier(ResourceLocation spec) { - return programs.get(spec); + public P getProgram(ResourceLocation loc, VertexType vertexType) { + ProgramSpec spec = programs.get(loc); + + if (spec == null) { + throw new NullPointerException("Cannot compile shader because '" + loc + "' is not recognized."); + } + + return programCache.getProgram(spec, vertexType); } @Override public void delete() { - programs.values() - .forEach(LazyCompiler::delete); + programCache.invalidate(); programs.clear(); } @@ -89,7 +93,7 @@ public class WorldContext

implements ShaderContext

{ return this; } - public

WorldContext

build(ShaderPipeline

pipeline) { + public

WorldContext

build(PipelineCompiler

pipeline) { if (specStream == null) { specStream = () -> backend.allMaterials() .stream() diff --git a/src/main/java/com/jozufozu/flywheel/core/materials/BasicData.java b/src/main/java/com/jozufozu/flywheel/core/materials/BasicData.java index 955aba918..8f1e07de8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/materials/BasicData.java +++ b/src/main/java/com/jozufozu/flywheel/core/materials/BasicData.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.core.materials; import com.jozufozu.flywheel.api.InstanceData; +import com.jozufozu.flywheel.util.Color; import net.minecraft.client.renderer.LightTexture; @@ -33,6 +34,15 @@ public abstract class BasicData extends InstanceData implements FlatLit The class that the PipelineCompiler outputs. + */ +public class CachingCompiler

{ + protected final Map cache = new HashMap<>(); + private final PipelineCompiler

pipeline; + + public CachingCompiler(PipelineCompiler

pipeline) { + this.pipeline = pipeline; + } + + /** + * Get or compile a spec to the given vertex type, accounting for all game state conditions specified by the spec. + * + * @param spec The ProgramSpec to target. + * @param vertexType The VertexType to target. + * @return A compiled GlProgram. + */ + public P getProgram(ProgramSpec spec, VertexType vertexType) { + return cache.computeIfAbsent(new CompilationContext(vertexType, spec, spec.getCurrentStateID()), this.pipeline::compile); + } + + public void invalidate() { + cache.values().forEach(P::delete); + cache.clear(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java new file mode 100644 index 000000000..b05da4d35 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java @@ -0,0 +1,35 @@ +package com.jozufozu.flywheel.core.pipeline; + +import java.util.Objects; + +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.source.SourceFile; +import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; + +/** + * Represents the entire context of a program's usage. + * + * @param vertexType The vertexType the program should be adapted for. + * @param spec The generic program name. + * @param ctx An ID representing the state at the time of usage. + */ +public record CompilationContext(VertexType vertexType, ProgramSpec spec, long ctx) { + + public SourceFile getFile() { + return spec().getSource(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CompilationContext that = (CompilationContext) o; + // override for instance equality on vertexType + return ctx == that.ctx && vertexType == that.vertexType && spec.equals(that.spec); + } + + @Override + public int hashCode() { + return Objects.hash(vertexType, spec, ctx); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingTemplateData.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/InstancingTemplateData.java similarity index 97% rename from src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingTemplateData.java rename to src/main/java/com/jozufozu/flywheel/core/pipeline/InstancingTemplateData.java index 2eb6f74be..a18c08f3f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/InstancingTemplateData.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/InstancingTemplateData.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.pipeline; +package com.jozufozu.flywheel.core.pipeline; import java.util.Optional; @@ -107,7 +107,7 @@ public class InstancingTemplateData implements TemplateData { .append("a_i_") .append(field.name) .append(";\n"); - attributeBinding += ShaderInput.from(field).attribCount; + attributeBinding += TypeHelper.getAttributeCount(field.type); } Template.prefixFields(template, interpolant, "out", "v2f_"); diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotTemplateData.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/OneShotTemplateData.java similarity index 98% rename from src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotTemplateData.java rename to src/main/java/com/jozufozu/flywheel/core/pipeline/OneShotTemplateData.java index b46945cfa..c000e506c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/OneShotTemplateData.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/OneShotTemplateData.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.pipeline; +package com.jozufozu.flywheel.core.pipeline; import java.util.Optional; diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/PipelineCompiler.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/PipelineCompiler.java new file mode 100644 index 000000000..a831480e5 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/PipelineCompiler.java @@ -0,0 +1,13 @@ +package com.jozufozu.flywheel.core.pipeline; + +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; + +/** + * The main interface for compiling usable shaders from program specs. + * @param

the type of the program that this pipeline compiles. + */ +public interface PipelineCompiler

{ + + P compile(CompilationContext vertexType); + +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ProgramAssembler.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/ProgramAssembler.java similarity index 97% rename from src/main/java/com/jozufozu/flywheel/backend/pipeline/ProgramAssembler.java rename to src/main/java/com/jozufozu/flywheel/core/pipeline/ProgramAssembler.java index 09cc90041..c5fc72d63 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ProgramAssembler.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/ProgramAssembler.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.pipeline; +package com.jozufozu.flywheel.core.pipeline; import static org.lwjgl.opengl.GL11.GL_TRUE; import static org.lwjgl.opengl.GL20.GL_LINK_STATUS; diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderCompiler.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/ShaderCompiler.java similarity index 62% rename from src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderCompiler.java rename to src/main/java/com/jozufozu/flywheel/core/pipeline/ShaderCompiler.java index cd1ce9608..11a451a4f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/ShaderCompiler.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.pipeline; +package com.jozufozu.flywheel.core.pipeline; import java.util.ArrayList; import java.util.List; @@ -6,15 +6,16 @@ import java.util.List; import javax.annotation.Nullable; import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.Backend; 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.backend.source.error.ErrorBuilder; +import com.jozufozu.flywheel.backend.source.error.ErrorReporter; import com.jozufozu.flywheel.backend.source.span.Span; import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram; import com.jozufozu.flywheel.core.shader.WorldProgram; -import com.jozufozu.flywheel.core.shader.spec.ProgramState; import net.minecraft.resources.ResourceLocation; @@ -24,27 +25,22 @@ public class ShaderCompiler { public final Template template; private final FileResolution header; - @Nullable - private ProgramState variant; + private final List defines; public final VertexType vertexType; - public SourceFile mainFile; + public final SourceFile mainFile; - public ShaderCompiler(ResourceLocation name, SourceFile mainSource, Template template, FileResolution header, VertexType vertexType) { - this.name = name; + private final List files = new ArrayList<>(); + + public ShaderCompiler(CompilationContext usage, Template template, FileResolution header) { + this.name = usage.spec().name; this.template = template; this.header = header; - this.mainFile = mainSource; - this.vertexType = vertexType; - } - - public ShaderCompiler setMainSource(SourceFile file) { - if (mainFile == file) return this; - - mainFile = file; - - return this; + this.mainFile = usage.getFile(); + this.defines = usage.spec() + .getDefines(usage.ctx()); + this.vertexType = usage.vertexType(); } public GlShader compile(ShaderType type) { @@ -60,13 +56,10 @@ public class ShaderCompiler { .append(type.define) // special case shader type declaration .append('\n'); - ProgramState variant = getVariant(); - if (variant != null) { - for (String def : variant.defines()) { - finalSource.append("#define ") - .append(def) - .append('\n'); - } + for (String def : defines) { + finalSource.append("#define ") + .append(def) + .append('\n'); } if (type == ShaderType.VERTEX) { @@ -83,9 +76,7 @@ public class ShaderCompiler { } files.clear(); - if (header.getFile() != null) { - header.getFile().generateFinalSource(this, finalSource); - } + header.getFile().generateFinalSource(this, finalSource); mainFile.generateFinalSource(this, finalSource); template.getMetadata(mainFile).generateFooter(finalSource, type, this); @@ -93,18 +84,21 @@ public class ShaderCompiler { return new GlShader(this, type, finalSource.toString()); } - @Nullable - public ProgramState getVariant() { - return variant; + public

P compile(ExtensibleGlProgram.Factory

worldShaderPipeline) { + return new ProgramAssembler(this.name) + .attachShader(compile(ShaderType.VERTEX)) + .attachShader(compile(ShaderType.FRAGMENT)) + .link() + .deleteLinkedShaders() + .build(worldShaderPipeline); } - public void setVariant(@Nullable ProgramState variant) { - this.variant = variant; - } - - private final List files = new ArrayList<>(); - - public int allocateFile(SourceFile sourceFile) { + /** + * Returns an arbitrary file ID for use this compilation context, or generates one if missing. + * @param sourceFile The file to retrieve the ID for. + * @return A file ID unique to the given sourceFile. + */ + public int getFileID(SourceFile sourceFile) { int i = files.indexOf(sourceFile); if (i != -1) { return i; @@ -121,8 +115,32 @@ public class ShaderCompiler { return file.getLineSpanNoWhitespace(lineNo); } + public void printShaderInfoLog(String source, String log, ResourceLocation name) { + List lines = log.lines() + .toList(); + + boolean needsSourceDump = false; + + StringBuilder errors = new StringBuilder(); + for (String line : lines) { + ErrorBuilder builder = parseCompilerError(line); + + if (builder != null) { + errors.append(builder.build()); + } else { + errors.append(line).append('\n'); + needsSourceDump = true; + } + } + Backend.LOGGER.error("Errors compiling '" + name + "': \n" + errors); + if (needsSourceDump) { + // TODO: generated code gets its own "file" + ErrorReporter.printLines(source); + } + } + @Nullable - public ErrorBuilder parseCompilerError(String line) { + private ErrorBuilder parseCompilerError(String line) { try { ErrorBuilder error = ErrorBuilder.fromLogLine(this, line); if (error != null) { @@ -133,13 +151,4 @@ public class ShaderCompiler { return null; } - - public

P compile(ExtensibleGlProgram.Factory

worldShaderPipeline) { - return new ProgramAssembler(this.name) - .attachShader(compile(ShaderType.VERTEX)) - .attachShader(compile(ShaderType.FRAGMENT)) - .link() - .deleteLinkedShaders() - .build(worldShaderPipeline); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/Template.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/Template.java similarity index 97% rename from src/main/java/com/jozufozu/flywheel/backend/pipeline/Template.java rename to src/main/java/com/jozufozu/flywheel/core/pipeline/Template.java index 3906cbecc..1a872d2b4 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/Template.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/Template.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.pipeline; +package com.jozufozu.flywheel.core.pipeline; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/TemplateData.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/TemplateData.java similarity index 93% rename from src/main/java/com/jozufozu/flywheel/backend/pipeline/TemplateData.java rename to src/main/java/com/jozufozu/flywheel/core/pipeline/TemplateData.java index 50603fdf0..90ea7e01f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/TemplateData.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/TemplateData.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.pipeline; +package com.jozufozu.flywheel.core.pipeline; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/TypeHelper.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/TypeHelper.java similarity index 94% rename from src/main/java/com/jozufozu/flywheel/backend/pipeline/TypeHelper.java rename to src/main/java/com/jozufozu/flywheel/core/pipeline/TypeHelper.java index 283f51a69..065755eaa 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/TypeHelper.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/TypeHelper.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.pipeline; +package com.jozufozu.flywheel.core.pipeline; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/WorldCompiler.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/WorldCompiler.java new file mode 100644 index 000000000..5bf2980a8 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/WorldCompiler.java @@ -0,0 +1,33 @@ +package com.jozufozu.flywheel.core.pipeline; + +import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.backend.source.FileResolution; +import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram; +import com.jozufozu.flywheel.core.shader.WorldProgram; + +public class WorldCompiler

implements PipelineCompiler

{ + + private final ExtensibleGlProgram.Factory

factory; + + private final Template template; + private final FileResolution header; + + public WorldCompiler(ExtensibleGlProgram.Factory

factory, Template template, FileResolution header) { + this.factory = factory; + this.template = template; + this.header = header; + } + + @Override + public P compile(CompilationContext usage) { + ShaderCompiler compiler = new ShaderCompiler(usage, template, header); + + return new ProgramAssembler(compiler.name) + .attachShader(compiler.compile(ShaderType.VERTEX)) + .attachShader(compiler.compile(ShaderType.FRAGMENT)) + .link() + .deleteLinkedShaders() + .build(this.factory); + } + +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/package-info.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/package-info.java similarity index 78% rename from src/main/java/com/jozufozu/flywheel/backend/pipeline/package-info.java rename to src/main/java/com/jozufozu/flywheel/core/pipeline/package-info.java index 25c300762..e51c6e616 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/pipeline/package-info.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/package-info.java @@ -1,5 +1,5 @@ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.jozufozu.flywheel.backend.pipeline; +package com.jozufozu.flywheel.core.pipeline; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/ContextAwareProgram.java b/src/main/java/com/jozufozu/flywheel/core/shader/ContextAwareProgram.java deleted file mode 100644 index c10affa04..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/shader/ContextAwareProgram.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.jozufozu.flywheel.core.shader; - -import java.util.function.Supplier; - -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; - -/** - * Encapsulates any number of shader programs for use in similar contexts. - * Allows the implementor to choose which shader program to use based on arbitrary state. - * - * @param

- */ -public interface ContextAwareProgram

extends Supplier

{ - - /** - * Get the shader program most suited for the current game state. - * - * @return The one true program. - */ - P get(); - - /** - * Delete all shader programs encapsulated by your implementation. - */ - void delete(); -} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProgram.java b/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProgram.java deleted file mode 100644 index 12bc659ad..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProgram.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.jozufozu.flywheel.core.shader; - -import java.util.ArrayList; -import java.util.List; - -import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.core.shader.spec.IGameStateCondition; -import com.jozufozu.flywheel.util.Pair; - -public class GameStateProgram

implements ContextAwareProgram

{ - - private final List> variants; - private final P fallback; - - protected GameStateProgram(List> variants, P fallback) { - this.variants = variants; - this.fallback = fallback; - } - - @Override - public P get() { - for (Pair variant : variants) { - if (variant.first() - .isMet()) return variant.second(); - } - - return fallback; - } - - @Override - public void delete() { - for (Pair variant : variants) { - variant.second() - .delete(); - } - - fallback.delete(); - } - - public static

Builder

builder(P fallback) { - return new Builder<>(fallback); - } - - public static class Builder

{ - private final P fallback; - private final List> variants = new ArrayList<>(); - - public Builder(P fallback) { - this.fallback = fallback; - } - - public Builder

withVariant(IGameStateCondition condition, P program) { - variants.add(Pair.of(condition, program)); - return this; - } - - public ContextAwareProgram

build() { - return new GameStateProgram<>(ImmutableList.copyOf(variants), fallback); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/IGameStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/IGameStateProvider.java index 8e472de72..78fb00d07 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/IGameStateProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/IGameStateProvider.java @@ -11,5 +11,5 @@ public interface IGameStateProvider { ResourceLocation getID(); - Object getValue(); + boolean isTrue(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/NormalDebugStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/NormalDebugStateProvider.java index f7ddbbea0..73b0a2f9b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/NormalDebugStateProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/NormalDebugStateProvider.java @@ -2,11 +2,10 @@ package com.jozufozu.flywheel.core.shader.gamestate; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.config.FlwConfig; -import com.jozufozu.flywheel.core.shader.spec.IBooleanStateProvider; import net.minecraft.resources.ResourceLocation; -public class NormalDebugStateProvider implements IBooleanStateProvider { +public class NormalDebugStateProvider implements IGameStateProvider { public static final NormalDebugStateProvider INSTANCE = new NormalDebugStateProvider(); public static final ResourceLocation NAME = Flywheel.rl("normal_debug"); diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/spec/BooleanGameStateCondition.java b/src/main/java/com/jozufozu/flywheel/core/shader/spec/BooleanGameStateCondition.java deleted file mode 100644 index 6293ade94..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/shader/spec/BooleanGameStateCondition.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.jozufozu.flywheel.core.shader.spec; - -import com.jozufozu.flywheel.core.shader.gamestate.IGameStateProvider; -import com.mojang.serialization.Codec; - -import net.minecraft.resources.ResourceLocation; - -public class BooleanGameStateCondition implements IGameStateCondition { - - public static final Codec BOOLEAN_SUGAR = IGameStateProvider.CODEC.xmap(gameContext -> { - if (gameContext instanceof IBooleanStateProvider) { - return new BooleanGameStateCondition(((IBooleanStateProvider) gameContext)); - } - - return null; - }, IGameStateCondition::getStateProvider); - protected final IBooleanStateProvider context; - - public BooleanGameStateCondition(IBooleanStateProvider context) { - this.context = context; - } - - @Override - public ResourceLocation getID() { - return context.getID(); - } - - @Override - public IGameStateProvider getStateProvider() { - return context; - } - - @Override - public boolean isMet() { - return context.isTrue(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/spec/IBooleanStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/spec/IBooleanStateProvider.java deleted file mode 100644 index 1f1265724..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/shader/spec/IBooleanStateProvider.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.jozufozu.flywheel.core.shader.spec; - -import com.jozufozu.flywheel.core.shader.gamestate.IGameStateProvider; - -public interface IBooleanStateProvider extends IGameStateProvider { - - boolean isTrue(); - - @Override - default Boolean getValue() { - return isTrue(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/spec/IGameStateCondition.java b/src/main/java/com/jozufozu/flywheel/core/shader/spec/IGameStateCondition.java deleted file mode 100644 index 08fd87dc3..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/shader/spec/IGameStateCondition.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.jozufozu.flywheel.core.shader.spec; - -import com.jozufozu.flywheel.core.shader.gamestate.IGameStateProvider; - -import net.minecraft.resources.ResourceLocation; - -public interface IGameStateCondition { - - ResourceLocation getID(); - - IGameStateProvider getStateProvider(); - - boolean isMet(); -} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramSpec.java b/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramSpec.java index 3716caef2..f9e105f98 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramSpec.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramSpec.java @@ -1,8 +1,10 @@ package com.jozufozu.flywheel.core.shader.spec; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.backend.source.FileResolution; import com.jozufozu.flywheel.backend.source.Resolver; import com.jozufozu.flywheel.backend.source.SourceFile; @@ -38,11 +40,11 @@ public class ProgramSpec { public ResourceLocation name; public final FileResolution source; - public final List states; + public final ImmutableList states; public ProgramSpec(ResourceLocation source, List states) { this.source = Resolver.INSTANCE.findShader(source); - this.states = states; + this.states = ImmutableList.copyOf(states); } public void setName(ResourceLocation name) { @@ -53,12 +55,40 @@ public class ProgramSpec { return source.getFileLoc(); } - public FileResolution getSource() { - return source; + public SourceFile getSource() { + return source.getFile(); } - public List getStates() { + public ImmutableList getStates() { return states; } + /** + * Calculate a unique ID representing the current game state. + */ + public long getCurrentStateID() { + long ctx = 0; + for (ProgramState state : states) { + if (state.context().isTrue()) { + ctx |= 1; + } + ctx <<= 1; + } + return ctx; + } + + /** + * Given the stateID, get a list of defines to include at the top of a compiling program. + */ + public List getDefines(long stateID) { + List defines = new ArrayList<>(); + + for (ProgramState state : states) { + if ((stateID & 1) == 1) { + defines.addAll(state.defines()); + } + stateID >>= 1; + } + return defines; + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramState.java b/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramState.java index e680c4e85..6f2b08bd9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramState.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramState.java @@ -3,29 +3,14 @@ package com.jozufozu.flywheel.core.shader.spec; import java.util.Collections; import java.util.List; +import com.jozufozu.flywheel.core.shader.gamestate.IGameStateProvider; import com.jozufozu.flywheel.util.CodecUtil; -import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; import com.mojang.serialization.codecs.RecordCodecBuilder; -public record ProgramState(IGameStateCondition context, List defines) { +public record ProgramState(IGameStateProvider context, List defines) { - // TODO: Use Codec.dispatch - private static final Codec WHEN = Codec.either(BooleanGameStateCondition.BOOLEAN_SUGAR, SpecificValueCondition.CODEC) - .flatXmap(either -> either.map(DataResult::success, DataResult::success), any -> { - if (any instanceof BooleanGameStateCondition) { - return DataResult.success(Either.left((BooleanGameStateCondition) any)); - } - - if (any instanceof SpecificValueCondition) { - return DataResult.success(Either.right((SpecificValueCondition) any)); - } - - return DataResult.error("unknown context condition"); - }); - - public static final Codec CODEC = RecordCodecBuilder.create(state -> state.group(WHEN.fieldOf("when") + public static final Codec CODEC = RecordCodecBuilder.create(state -> state.group(IGameStateProvider.CODEC.fieldOf("when") .forGetter(ProgramState::context), CodecUtil.oneOrMore(Codec.STRING) .optionalFieldOf("define", Collections.emptyList()) .forGetter(ProgramState::defines)) diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/spec/SpecificValueCondition.java b/src/main/java/com/jozufozu/flywheel/core/shader/spec/SpecificValueCondition.java deleted file mode 100644 index 69e40a08d..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/shader/spec/SpecificValueCondition.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.jozufozu.flywheel.core.shader.spec; - -import com.jozufozu.flywheel.core.shader.gamestate.IGameStateProvider; -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; - -import net.minecraft.resources.ResourceLocation; - -public class SpecificValueCondition implements IGameStateCondition { - - public static final Codec CODEC = RecordCodecBuilder.create(condition -> condition.group(IGameStateProvider.CODEC.fieldOf("provider") - .forGetter(SpecificValueCondition::getStateProvider), Codec.STRING.fieldOf("value") - .forGetter(SpecificValueCondition::getValue)) - .apply(condition, SpecificValueCondition::new)); - - private final String required; - private final IGameStateProvider context; - - public SpecificValueCondition(IGameStateProvider context, String required) { - this.required = required; - this.context = context; - } - - @Override - public ResourceLocation getID() { - return context.getID(); - } - - public String getValue() { - return required; - } - - @Override - public IGameStateProvider getStateProvider() { - return context; - } - - @Override - public boolean isMet() { - return required.equals(context.getValue() - .toString()); - } -} diff --git a/src/main/resources/assets/flywheel/flywheel/programs/model.json b/src/main/resources/assets/flywheel/flywheel/programs/model.json index 1352b31b2..921a6e093 100644 --- a/src/main/resources/assets/flywheel/flywheel/programs/model.json +++ b/src/main/resources/assets/flywheel/flywheel/programs/model.json @@ -2,10 +2,7 @@ "source": "flywheel:model.vert", "states": [ { - "when": { - "provider": "flywheel:normal_debug", - "value": "true" - }, + "when": "flywheel:normal_debug", "define": "DEBUG_NORMAL" } ] diff --git a/src/main/resources/assets/flywheel/flywheel/programs/oriented.json b/src/main/resources/assets/flywheel/flywheel/programs/oriented.json index a22a568cf..9f0709ebf 100644 --- a/src/main/resources/assets/flywheel/flywheel/programs/oriented.json +++ b/src/main/resources/assets/flywheel/flywheel/programs/oriented.json @@ -2,10 +2,7 @@ "source": "flywheel:oriented.vert", "states": [ { - "when": { - "provider": "flywheel:normal_debug", - "value": "true" - }, + "when": "flywheel:normal_debug", "define": "DEBUG_NORMAL" } ] From c196ed5d7801c8c54e5297eda1f610cb902e6c20 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Sat, 1 Jan 2022 15:19:49 -0800 Subject: [PATCH 03/10] Consider RenderLayer when compiling shaders - Disabled cutout logic in other layers --- .../flywheel/backend/ShaderContext.java | 2 +- .../instancing/InstancedMaterialGroup.java | 13 +++++++------ .../instancing/InstancingEngine.java | 2 +- ...eAllocator.java => FallbackAllocator.java} | 5 ++--- .../jozufozu/flywheel/core/WorldContext.java | 6 ++++-- .../core/crumbling/CrumblingGroup.java | 5 +++-- .../core/pipeline/CachingCompiler.java | 9 +++------ .../core/pipeline/CompilationContext.java | 12 +++++++++--- .../core/pipeline/ShaderCompiler.java | 19 +++++++++++++------ .../flywheel/shaders/context/world.glsl | 2 -- 10 files changed, 43 insertions(+), 32 deletions(-) rename src/main/java/com/jozufozu/flywheel/backend/model/{ImmediateAllocator.java => FallbackAllocator.java} (66%) diff --git a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java b/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java index 4367194eb..1e3d68f8a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java +++ b/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java @@ -7,7 +7,7 @@ import net.minecraft.resources.ResourceLocation; public interface ShaderContext

{ - P getProgram(ResourceLocation loc, VertexType vertexType); + P getProgram(ResourceLocation loc, VertexType vertexType, RenderLayer layer); /** * Load all programs associated with this context. This might be just one, if the context is very specialized. diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java index c558213cd..6d243973a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java @@ -8,7 +8,8 @@ import com.jozufozu.flywheel.api.MaterialGroup; import com.jozufozu.flywheel.api.struct.Instanced; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.model.ImmediateAllocator; +import com.jozufozu.flywheel.backend.RenderLayer; +import com.jozufozu.flywheel.backend.model.FallbackAllocator; import com.jozufozu.flywheel.backend.model.ModelAllocator; import com.jozufozu.flywheel.backend.model.ModelPool; import com.jozufozu.flywheel.core.Formats; @@ -36,7 +37,7 @@ public class InstancedMaterialGroup

implements MaterialG this.owner = owner; this.type = type; if (Backend.getInstance().compat.onAMDWindows()) { - this.allocator = ImmediateAllocator.INSTANCE; + this.allocator = FallbackAllocator.INSTANCE; } else { this.allocator = new ModelPool(Formats.POS_TEX_NORMAL, 2048); } @@ -52,14 +53,14 @@ public class InstancedMaterialGroup

implements MaterialG } } - public void render(Matrix4f viewProjection, double camX, double camY, double camZ) { + public void render(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) { type.setupRenderState(); Textures.bindActiveTextures(); - renderAll(viewProjection, camX, camY, camZ); + renderAll(viewProjection, camX, camY, camZ, layer); type.clearRenderState(); } - protected void renderAll(Matrix4f viewProjection, double camX, double camY, double camZ) { + protected void renderAll(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) { // initialize all uninitialized instancers... for (InstancedMaterial material : materials.values()) { for (GPUInstancer instancer : material.uninitialized) { @@ -78,7 +79,7 @@ public class InstancedMaterialGroup

implements MaterialG if (material.nothingToRender()) continue; P program = owner.context.getProgram(entry.getKey() - .getProgramSpec(), Formats.POS_TEX_NORMAL); + .getProgramSpec(), Formats.POS_TEX_NORMAL, layer); program.bind(); program.uploadViewProjection(viewProjection); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index 41b102cff..6d91b3563 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -95,7 +95,7 @@ public class InstancingEngine

implements Engine { viewProjection = event.viewProjection; } - getGroupsToRender(event.getLayer()).forEach(group -> group.render(viewProjection, camX, camY, camZ)); + getGroupsToRender(event.getLayer()).forEach(group -> group.render(viewProjection, camX, camY, camZ, event.getLayer())); GlBufferType.ELEMENT_ARRAY_BUFFER.unbind(); GlBufferType.ARRAY_BUFFER.unbind(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/ImmediateAllocator.java b/src/main/java/com/jozufozu/flywheel/backend/model/FallbackAllocator.java similarity index 66% rename from src/main/java/com/jozufozu/flywheel/backend/model/ImmediateAllocator.java rename to src/main/java/com/jozufozu/flywheel/backend/model/FallbackAllocator.java index 30240d8d8..7520afff2 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/ImmediateAllocator.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/FallbackAllocator.java @@ -2,9 +2,8 @@ package com.jozufozu.flywheel.backend.model; import com.jozufozu.flywheel.core.model.Model; -public class ImmediateAllocator implements ModelAllocator { - - public static final ImmediateAllocator INSTANCE = new ImmediateAllocator(); +public enum FallbackAllocator implements ModelAllocator { + INSTANCE; @Override public BufferedModel alloc(Model model, Callback allocationCallback) { diff --git a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java index 6b3cd99b0..85be2a530 100644 --- a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java @@ -9,9 +9,11 @@ import java.util.stream.Stream; import com.jozufozu.flywheel.api.struct.Instanced; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.RenderLayer; import com.jozufozu.flywheel.backend.ShaderContext; import com.jozufozu.flywheel.backend.source.ShaderLoadingException; import com.jozufozu.flywheel.core.pipeline.CachingCompiler; +import com.jozufozu.flywheel.core.pipeline.CompilationContext; import com.jozufozu.flywheel.core.pipeline.PipelineCompiler; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; @@ -58,14 +60,14 @@ public class WorldContext

implements ShaderContext

{ } @Override - public P getProgram(ResourceLocation loc, VertexType vertexType) { + public P getProgram(ResourceLocation loc, VertexType vertexType, RenderLayer layer) { ProgramSpec spec = programs.get(loc); if (spec == null) { throw new NullPointerException("Cannot compile shader because '" + loc + "' is not recognized."); } - return programCache.getProgram(spec, vertexType); + return programCache.getProgram(CompilationContext.create(vertexType, layer, spec)); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingGroup.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingGroup.java index 19385b5a3..ac27997f3 100644 --- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingGroup.java +++ b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingGroup.java @@ -1,5 +1,6 @@ package com.jozufozu.flywheel.core.crumbling; +import com.jozufozu.flywheel.backend.RenderLayer; import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterialGroup; import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine; import com.jozufozu.flywheel.util.Textures; @@ -18,7 +19,7 @@ public class CrumblingGroup

extends InstancedMateria } @Override - public void render(Matrix4f viewProjection, double camX, double camY, double camZ) { + public void render(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) { type.setupRenderState(); int renderTex = RenderSystem.getShaderTexture(0); @@ -35,7 +36,7 @@ public class CrumblingGroup

extends InstancedMateria RenderSystem.setShaderTexture(4, breakingTex); Textures.bindActiveTextures(); - renderAll(viewProjection, camX, camY, camZ); + renderAll(viewProjection, camX, camY, camZ, layer); CrumblingRenderer._currentLayer.clearRenderState(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/CachingCompiler.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/CachingCompiler.java index 728286b90..b29b75c30 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/CachingCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/CachingCompiler.java @@ -3,9 +3,7 @@ package com.jozufozu.flywheel.core.pipeline; import java.util.HashMap; import java.util.Map; -import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; /** * Lazily compiles shader programs, caching the results. @@ -23,12 +21,11 @@ public class CachingCompiler

{ /** * Get or compile a spec to the given vertex type, accounting for all game state conditions specified by the spec. * - * @param spec The ProgramSpec to target. - * @param vertexType The VertexType to target. + * @param context The context of compilation. * @return A compiled GlProgram. */ - public P getProgram(ProgramSpec spec, VertexType vertexType) { - return cache.computeIfAbsent(new CompilationContext(vertexType, spec, spec.getCurrentStateID()), this.pipeline::compile); + public P getProgram(CompilationContext context) { + return cache.computeIfAbsent(context, this.pipeline::compile); } public void invalidate() { diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java index b05da4d35..bc4469574 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java @@ -3,17 +3,23 @@ package com.jozufozu.flywheel.core.pipeline; import java.util.Objects; import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.RenderLayer; import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; /** * Represents the entire context of a program's usage. * + * @param layer * @param vertexType The vertexType the program should be adapted for. * @param spec The generic program name. * @param ctx An ID representing the state at the time of usage. */ -public record CompilationContext(VertexType vertexType, ProgramSpec spec, long ctx) { +public record CompilationContext(RenderLayer layer, VertexType vertexType, ProgramSpec spec, long ctx) { + + public static CompilationContext create(VertexType vertexType, RenderLayer layer, ProgramSpec spec) { + return new CompilationContext(layer, vertexType, spec, spec.getCurrentStateID()); + } public SourceFile getFile() { return spec().getSource(); @@ -25,11 +31,11 @@ public record CompilationContext(VertexType vertexType, ProgramSpec spec, long c if (o == null || getClass() != o.getClass()) return false; CompilationContext that = (CompilationContext) o; // override for instance equality on vertexType - return ctx == that.ctx && vertexType == that.vertexType && spec.equals(that.spec); + return layer == that.layer && ctx == that.ctx && vertexType == that.vertexType && spec.equals(that.spec); } @Override public int hashCode() { - return Objects.hash(vertexType, spec, ctx); + return Objects.hash(layer, vertexType, spec, ctx); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/ShaderCompiler.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/ShaderCompiler.java index 11a451a4f..c2da3e63a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/ShaderCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/ShaderCompiler.java @@ -7,6 +7,7 @@ import javax.annotation.Nullable; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.RenderLayer; import com.jozufozu.flywheel.backend.gl.shader.GlShader; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.backend.source.FileResolution; @@ -27,20 +28,22 @@ public class ShaderCompiler { private final List defines; + private final RenderLayer layer; public final VertexType vertexType; public final SourceFile mainFile; private final List files = new ArrayList<>(); - public ShaderCompiler(CompilationContext usage, Template template, FileResolution header) { - this.name = usage.spec().name; + public ShaderCompiler(CompilationContext context, Template template, FileResolution header) { + this.name = context.spec().name; this.template = template; this.header = header; - this.mainFile = usage.getFile(); - this.defines = usage.spec() - .getDefines(usage.ctx()); - this.vertexType = usage.vertexType(); + this.mainFile = context.getFile(); + this.defines = context.spec() + .getDefines(context.ctx()); + this.vertexType = context.vertexType(); + layer = context.layer(); } public GlShader compile(ShaderType type) { @@ -56,6 +59,10 @@ public class ShaderCompiler { .append(type.define) // special case shader type declaration .append('\n'); + if (layer == RenderLayer.CUTOUT) { + finalSource.append("#define ALPHA_DISCARD 0.1\n"); + } + for (String def : defines) { finalSource.append("#define ") .append(def) diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl b/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl index 58ad850b6..28e36ab3d 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl +++ b/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl @@ -21,8 +21,6 @@ vec4 FLWVertex(inout Vertex v) { #elif defined(FRAGMENT_SHADER) #use "flywheel:core/lightutil.glsl" - -#define ALPHA_DISCARD 0.1 // optimize discard usage #if defined(ALPHA_DISCARD) #if defined(GL_ARB_conservative_depth) From 06e1d5a901741d25db88c3bb50155bf88b7fbd2a Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Fri, 7 Jan 2022 12:01:03 -0800 Subject: [PATCH 04/10] Flatten core.shader and fix residual merge conflicts --- .../jozufozu/flywheel/backend/Backend.java | 2 +- .../flywheel/backend/GameStateRegistry.java | 2 +- .../com/jozufozu/flywheel/backend/Loader.java | 2 +- .../com/jozufozu/flywheel/core/Contexts.java | 2 +- .../jozufozu/flywheel/core/WorldContext.java | 2 +- .../core/pipeline/CompilationContext.java | 2 +- .../core/shader/ExtensibleGlProgram.java | 1 - .../{extension => }/ExtensionInstance.java | 2 +- .../{gamestate => }/GameStateProvider.java | 2 +- .../NormalDebugStateProvider.java | 4 ++-- .../core/shader/{spec => }/ProgramSpec.java | 2 +- .../core/shader/{spec => }/ProgramState.java | 7 +++--- .../core/shader/{extension => }/WorldFog.java | 2 +- .../flywheel/core/shader/WorldProgram.java | 1 - .../extension/UnitExtensionInstance.java | 24 ------------------- .../shader/spec/BooleanStateProvider.java | 13 ---------- 16 files changed, 15 insertions(+), 55 deletions(-) rename src/main/java/com/jozufozu/flywheel/core/shader/{extension => }/ExtensionInstance.java (82%) rename src/main/java/com/jozufozu/flywheel/core/shader/{gamestate => }/GameStateProvider.java (87%) rename src/main/java/com/jozufozu/flywheel/core/shader/{gamestate => }/NormalDebugStateProvider.java (80%) rename src/main/java/com/jozufozu/flywheel/core/shader/{spec => }/ProgramSpec.java (98%) rename src/main/java/com/jozufozu/flywheel/core/shader/{spec => }/ProgramState.java (63%) rename src/main/java/com/jozufozu/flywheel/core/shader/{extension => }/WorldFog.java (94%) delete mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/extension/UnitExtensionInstance.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/spec/BooleanStateProvider.java diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index b365f2458..ec0d3d368 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -19,7 +19,7 @@ import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.config.FlwEngine; -import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; +import com.jozufozu.flywheel.core.shader.ProgramSpec; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/GameStateRegistry.java b/src/main/java/com/jozufozu/flywheel/backend/GameStateRegistry.java index 04aa431e6..e0aa48885 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/GameStateRegistry.java +++ b/src/main/java/com/jozufozu/flywheel/backend/GameStateRegistry.java @@ -3,7 +3,7 @@ package com.jozufozu.flywheel.backend; import java.util.HashMap; import java.util.Map; -import com.jozufozu.flywheel.core.shader.gamestate.GameStateProvider; +import com.jozufozu.flywheel.core.shader.GameStateProvider; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 188900381..b9d411025 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -10,7 +10,7 @@ import com.jozufozu.flywheel.backend.source.Resolver; import com.jozufozu.flywheel.backend.source.ShaderLoadingException; import com.jozufozu.flywheel.backend.source.ShaderSources; import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer; -import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; +import com.jozufozu.flywheel.core.shader.ProgramSpec; import com.jozufozu.flywheel.event.GatherContextEvent; import com.jozufozu.flywheel.util.ResourceUtil; import com.jozufozu.flywheel.util.StringUtil; diff --git a/src/main/java/com/jozufozu/flywheel/core/Contexts.java b/src/main/java/com/jozufozu/flywheel/core/Contexts.java index 0180f98a8..2d067a0b8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Contexts.java +++ b/src/main/java/com/jozufozu/flywheel/core/Contexts.java @@ -8,8 +8,8 @@ import com.jozufozu.flywheel.backend.source.Resolver; import com.jozufozu.flywheel.core.crumbling.CrumblingProgram; import com.jozufozu.flywheel.core.pipeline.PipelineCompiler; import com.jozufozu.flywheel.core.pipeline.WorldCompiler; +import com.jozufozu.flywheel.core.shader.NormalDebugStateProvider; import com.jozufozu.flywheel.core.shader.WorldProgram; -import com.jozufozu.flywheel.core.shader.gamestate.NormalDebugStateProvider; import com.jozufozu.flywheel.event.GatherContextEvent; import com.jozufozu.flywheel.util.ResourceUtil; diff --git a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java index 85be2a530..fa56a87ba 100644 --- a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java @@ -15,8 +15,8 @@ import com.jozufozu.flywheel.backend.source.ShaderLoadingException; import com.jozufozu.flywheel.core.pipeline.CachingCompiler; import com.jozufozu.flywheel.core.pipeline.CompilationContext; import com.jozufozu.flywheel.core.pipeline.PipelineCompiler; +import com.jozufozu.flywheel.core.shader.ProgramSpec; import com.jozufozu.flywheel.core.shader.WorldProgram; -import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java index bc4469574..74cae594b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java @@ -5,7 +5,7 @@ import java.util.Objects; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.RenderLayer; import com.jozufozu.flywheel.backend.source.SourceFile; -import com.jozufozu.flywheel.core.shader.spec.ProgramSpec; +import com.jozufozu.flywheel.core.shader.ProgramSpec; /** * Represents the entire context of a program's usage. 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 05ef8dc73..927092e9b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/ExtensibleGlProgram.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/ExtensibleGlProgram.java @@ -7,7 +7,6 @@ import javax.annotation.Nonnull; import com.jozufozu.flywheel.backend.ShaderContext; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.core.shader.extension.ExtensionInstance; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/extension/ExtensionInstance.java b/src/main/java/com/jozufozu/flywheel/core/shader/ExtensionInstance.java similarity index 82% rename from src/main/java/com/jozufozu/flywheel/core/shader/extension/ExtensionInstance.java rename to src/main/java/com/jozufozu/flywheel/core/shader/ExtensionInstance.java index 6499820c9..4875df7bf 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/extension/ExtensionInstance.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/ExtensionInstance.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.shader.extension; +package com.jozufozu.flywheel.core.shader; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/GameStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java similarity index 87% rename from src/main/java/com/jozufozu/flywheel/core/shader/gamestate/GameStateProvider.java rename to src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java index 152ee113d..fc9fe728d 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/GameStateProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.shader.gamestate; +package com.jozufozu.flywheel.core.shader; import com.jozufozu.flywheel.backend.GameStateRegistry; import com.mojang.serialization.Codec; diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/NormalDebugStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java similarity index 80% rename from src/main/java/com/jozufozu/flywheel/core/shader/gamestate/NormalDebugStateProvider.java rename to src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java index 73b0a2f9b..61f0e50ac 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/NormalDebugStateProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java @@ -1,11 +1,11 @@ -package com.jozufozu.flywheel.core.shader.gamestate; +package com.jozufozu.flywheel.core.shader; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.config.FlwConfig; import net.minecraft.resources.ResourceLocation; -public class NormalDebugStateProvider implements IGameStateProvider { +public class NormalDebugStateProvider implements GameStateProvider { public static final NormalDebugStateProvider INSTANCE = new NormalDebugStateProvider(); public static final ResourceLocation NAME = Flywheel.rl("normal_debug"); diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramSpec.java b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java similarity index 98% rename from src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramSpec.java rename to src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java index f79169806..d0ffe8068 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramSpec.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.shader.spec; +package com.jozufozu.flywheel.core.shader; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramState.java b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramState.java similarity index 63% rename from src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramState.java rename to src/main/java/com/jozufozu/flywheel/core/shader/ProgramState.java index 6f2b08bd9..ae8d00248 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/spec/ProgramState.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramState.java @@ -1,16 +1,15 @@ -package com.jozufozu.flywheel.core.shader.spec; +package com.jozufozu.flywheel.core.shader; import java.util.Collections; import java.util.List; -import com.jozufozu.flywheel.core.shader.gamestate.IGameStateProvider; import com.jozufozu.flywheel.util.CodecUtil; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; -public record ProgramState(IGameStateProvider context, List defines) { +public record ProgramState(GameStateProvider context, List defines) { - public static final Codec CODEC = RecordCodecBuilder.create(state -> state.group(IGameStateProvider.CODEC.fieldOf("when") + public static final Codec CODEC = RecordCodecBuilder.create(state -> state.group(GameStateProvider.CODEC.fieldOf("when") .forGetter(ProgramState::context), CodecUtil.oneOrMore(Codec.STRING) .optionalFieldOf("define", Collections.emptyList()) .forGetter(ProgramState::defines)) diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/extension/WorldFog.java b/src/main/java/com/jozufozu/flywheel/core/shader/WorldFog.java similarity index 94% rename from src/main/java/com/jozufozu/flywheel/core/shader/extension/WorldFog.java rename to src/main/java/com/jozufozu/flywheel/core/shader/WorldFog.java index dd371debd..b6aa01a11 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/extension/WorldFog.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/WorldFog.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.shader.extension; +package com.jozufozu.flywheel.core.shader; import org.lwjgl.opengl.GL20; diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/WorldProgram.java b/src/main/java/com/jozufozu/flywheel/core/shader/WorldProgram.java index 226fbd28e..3754969b8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/WorldProgram.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/WorldProgram.java @@ -4,7 +4,6 @@ import static org.lwjgl.opengl.GL20.glUniform1f; import static org.lwjgl.opengl.GL20.glUniform2f; import static org.lwjgl.opengl.GL20.glUniform3f; -import com.jozufozu.flywheel.core.shader.extension.WorldFog; import com.jozufozu.flywheel.util.AnimationTickHolder; import com.mojang.blaze3d.platform.Window; import com.mojang.math.Matrix4f; diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/extension/UnitExtensionInstance.java b/src/main/java/com/jozufozu/flywheel/core/shader/extension/UnitExtensionInstance.java deleted file mode 100644 index 70d1bff4b..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/shader/extension/UnitExtensionInstance.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.jozufozu.flywheel.core.shader.extension; - -import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; - -import net.minecraft.resources.ResourceLocation; - -public class UnitExtensionInstance implements ExtensionInstance { - - public static final ResourceLocation NAME = Flywheel.rl("unit"); - - public UnitExtensionInstance(GlProgram program) { - } - - @Override - public void bind() { - - } - - @Override - public ResourceLocation name() { - return NAME; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/spec/BooleanStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/spec/BooleanStateProvider.java deleted file mode 100644 index 1cf0b1da2..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/shader/spec/BooleanStateProvider.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.jozufozu.flywheel.core.shader.spec; - -import com.jozufozu.flywheel.core.shader.gamestate.GameStateProvider; - -public interface BooleanStateProvider extends GameStateProvider { - - boolean isTrue(); - - @Override - default Boolean getValue() { - return isTrue(); - } -} From bfe123d167eaa7b7091593f02ada7a8099b50894 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Fri, 7 Jan 2022 22:46:29 -0800 Subject: [PATCH 05/10] Almost sane shaders - No more ShaderContext. Programs are directly retrieved through ProgramCompilers. - Templates don't need generics - Remove ExtensibleGlProgram --- .../jozufozu/flywheel/backend/Backend.java | 18 +-- .../com/jozufozu/flywheel/backend/Loader.java | 19 +-- .../flywheel/backend/ShaderContext.java | 18 --- .../flywheel/backend/gl/shader/GlProgram.java | 11 ++ .../flywheel/backend/gl/shader/GlShader.java | 2 +- .../backend/gl/shader/ShaderType.java | 4 + .../instancing/InstancedMaterialGroup.java | 5 +- .../instancing/InstancingEngine.java | 16 +-- .../backend/source/FileResolution.java | 37 ++++-- .../flywheel/backend/source/Resolver.java | 39 +++++-- .../flywheel/backend/source/SourceFile.java | 4 +- .../backend/source/error/ErrorBuilder.java | 3 +- .../flywheel/backend/source/parse/Import.java | 2 +- .../com/jozufozu/flywheel/core/Contexts.java | 21 ++-- .../com/jozufozu/flywheel/core/Materials.java | 1 + .../com/jozufozu/flywheel/core/Templates.java | 10 +- .../jozufozu/flywheel/core/WorldContext.java | 109 ------------------ .../flywheel/core/compile/FileIndex.java | 13 +++ .../InstancingTemplateData.java | 4 +- .../OneShotTemplateData.java | 4 +- .../ProgramAssembler.java | 7 +- .../core/compile/ProgramCompiler.java | 58 ++++++++++ .../flywheel/core/compile/ProgramContext.java | 71 ++++++++++++ .../{pipeline => compile}/ShaderCompiler.java | 48 +++++--- .../core/{pipeline => compile}/Template.java | 26 +++-- .../{pipeline => compile}/TemplateData.java | 4 +- .../{pipeline => compile}/TypeHelper.java | 2 +- .../{pipeline => compile}/package-info.java | 2 +- .../core/pipeline/CachingCompiler.java | 35 ------ .../core/pipeline/CompilationContext.java | 41 ------- .../core/pipeline/PipelineCompiler.java | 13 --- .../flywheel/core/pipeline/WorldCompiler.java | 33 ------ .../core/shader/ExtensibleGlProgram.java | 63 ---------- .../flywheel/core/shader/ProgramSpec.java | 3 +- .../flywheel/core/shader/WorldProgram.java | 8 +- .../flywheel/core/shader/package-info.java | 6 + .../flywheel/flywheel/programs/passthru.json | 9 ++ .../flywheel/flywheel/shaders/passthru.vert | 7 ++ 38 files changed, 339 insertions(+), 437 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/WorldContext.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/FileIndex.java rename src/main/java/com/jozufozu/flywheel/core/{pipeline => compile}/InstancingTemplateData.java (97%) rename src/main/java/com/jozufozu/flywheel/core/{pipeline => compile}/OneShotTemplateData.java (96%) rename src/main/java/com/jozufozu/flywheel/core/{pipeline => compile}/ProgramAssembler.java (87%) create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/ProgramContext.java rename src/main/java/com/jozufozu/flywheel/core/{pipeline => compile}/ShaderCompiler.java (80%) rename src/main/java/com/jozufozu/flywheel/core/{pipeline => compile}/Template.java (65%) rename src/main/java/com/jozufozu/flywheel/core/{pipeline => compile}/TemplateData.java (85%) rename src/main/java/com/jozufozu/flywheel/core/{pipeline => compile}/TypeHelper.java (94%) rename src/main/java/com/jozufozu/flywheel/core/{pipeline => compile}/package-info.java (79%) delete mode 100644 src/main/java/com/jozufozu/flywheel/core/pipeline/CachingCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/pipeline/PipelineCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/pipeline/WorldCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/ExtensibleGlProgram.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/package-info.java create mode 100644 src/main/resources/assets/flywheel/flywheel/programs/passthru.json create mode 100644 src/main/resources/assets/flywheel/flywheel/shaders/passthru.vert diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index ec0d3d368..b4f94e0af 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -1,9 +1,7 @@ package com.jozufozu.flywheel.backend; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; import javax.annotation.Nullable; @@ -40,7 +38,6 @@ public class Backend { public GlCompat compat; public final Loader loader; - private final List> contexts = new ArrayList<>(); private final Map> materialRegistry = new HashMap<>(); private final Map programSpecRegistry = new HashMap<>(); @@ -74,14 +71,6 @@ public class Backend { return spec; } - /** - * Register a shader context. - */ - public > C register(C spec) { - contexts.add(spec); - return spec; - } - /** * Register an instancing material. */ @@ -96,6 +85,7 @@ public class Backend { return spec; } + @Nullable public ProgramSpec getSpec(ResourceLocation name) { return programSpecRegistry.get(name); } @@ -118,10 +108,6 @@ public class Backend { return programSpecRegistry.values(); } - public Collection> allContexts() { - return contexts; - } - public static boolean isOn() { return getInstance().engine != FlwEngine.OFF; } @@ -157,8 +143,6 @@ public class Backend { void _clearContexts() { GameStateRegistry.clear(); programSpecRegistry.clear(); - contexts.forEach(ShaderContext::delete); - contexts.clear(); materialRegistry.clear(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index b9d411025..49d9a5fab 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -7,7 +7,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.source.Resolver; -import com.jozufozu.flywheel.backend.source.ShaderLoadingException; import com.jozufozu.flywheel.backend.source.ShaderSources; import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer; import com.jozufozu.flywheel.core.shader.ProgramSpec; @@ -39,7 +38,6 @@ public class Loader implements ResourceManagerReloadListener { private static final Gson GSON = new GsonBuilder().create(); private final Backend backend; - private boolean shouldCrash; private boolean firstLoad = true; @@ -56,15 +54,10 @@ public class Loader implements ResourceManagerReloadListener { } } - public void notifyError() { - shouldCrash = true; - } - @Override public void onResourceManagerReload(ResourceManager manager) { backend.refresh(); - shouldCrash = false; backend._clearContexts(); Resolver.INSTANCE.invalidate(); @@ -75,17 +68,9 @@ public class Loader implements ResourceManagerReloadListener { loadProgramSpecs(manager); - Resolver.INSTANCE.resolve(sources); + Resolver.INSTANCE.run(sources); - for (ShaderContext context : backend.allContexts()) { - context.load(); - } - - if (shouldCrash) { - throw new ShaderLoadingException("Could not load all shaders, see log for details"); - } - - Backend.LOGGER.info("Loaded all shader programs."); + Backend.LOGGER.info("Loaded all shader sources."); ClientLevel world = Minecraft.getInstance().level; if (Backend.canUseInstancing(world)) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java b/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java deleted file mode 100644 index 1e3d68f8a..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jozufozu.flywheel.backend; - -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; - -import net.minecraft.resources.ResourceLocation; - -public interface ShaderContext

{ - - P getProgram(ResourceLocation loc, VertexType vertexType, RenderLayer layer); - - /** - * Load all programs associated with this context. This might be just one, if the context is very specialized. - */ - void load(); - - void delete(); -} 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 432575f5e..c73a5f428 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 @@ -7,6 +7,8 @@ import static org.lwjgl.opengl.GL20.glUniformMatrix4fv; import java.nio.FloatBuffer; +import javax.annotation.Nonnull; + import org.lwjgl.system.MemoryStack; import com.jozufozu.flywheel.backend.Backend; @@ -87,4 +89,13 @@ public abstract class GlProgram extends GlObject { public String toString() { return "program " + name; } + + /** + * A factory interface to create a {@link GlProgram}. + */ + public interface Factory

{ + + @Nonnull + P create(ResourceLocation name, int handle); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java index c1f63c1bd..67e31c833 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java @@ -5,7 +5,7 @@ import org.lwjgl.opengl.GL20; import com.jozufozu.flywheel.backend.gl.GlObject; import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; import com.jozufozu.flywheel.backend.source.ShaderLoadingException; -import com.jozufozu.flywheel.core.pipeline.ShaderCompiler; +import com.jozufozu.flywheel.core.compile.ShaderCompiler; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/ShaderType.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/ShaderType.java index a7146ef56..2b10e7578 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/ShaderType.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/ShaderType.java @@ -16,4 +16,8 @@ public enum ShaderType { this.define = define; this.glEnum = glEnum; } + + public String getDefineStatement() { + return "#define " + define + "\n"; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java index 6d243973a..c16a9ef97 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java @@ -13,6 +13,7 @@ import com.jozufozu.flywheel.backend.model.FallbackAllocator; import com.jozufozu.flywheel.backend.model.ModelAllocator; import com.jozufozu.flywheel.backend.model.ModelPool; import com.jozufozu.flywheel.core.Formats; +import com.jozufozu.flywheel.core.compile.ProgramContext; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.util.Textures; import com.mojang.math.Matrix4f; @@ -78,8 +79,8 @@ public class InstancedMaterialGroup

implements MaterialG InstancedMaterial material = entry.getValue(); if (material.nothingToRender()) continue; - P program = owner.context.getProgram(entry.getKey() - .getProgramSpec(), Formats.POS_TEX_NORMAL, layer); + P program = owner.context.getProgram(ProgramContext.create(entry.getKey() + .getProgramSpec(), Formats.POS_TEX_NORMAL, layer)); program.bind(); program.uploadViewProjection(viewProjection); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index 5dc89870c..37f4669b0 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -13,7 +13,7 @@ import com.jozufozu.flywheel.backend.gl.GlVertexArray; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.TaskEngine; -import com.jozufozu.flywheel.core.WorldContext; +import com.jozufozu.flywheel.core.compile.ProgramCompiler; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.event.RenderLayerEvent; import com.jozufozu.flywheel.util.WeakHashSet; @@ -31,7 +31,7 @@ public class InstancingEngine

implements Engine { protected BlockPos originCoordinate = BlockPos.ZERO; - protected final WorldContext

context; + protected final ProgramCompiler

context; protected final GroupFactory

groupFactory; protected final boolean ignoreOriginCoordinate; @@ -39,15 +39,11 @@ public class InstancingEngine

implements Engine { private final WeakHashSet listeners; - public InstancingEngine(WorldContext

context, TaskEngine taskEngine) { - this(context, InstancedMaterialGroup::new, false); - } - - public static

Builder

builder(WorldContext

context) { + public static

Builder

builder(ProgramCompiler

context) { return new Builder<>(context); } - public InstancingEngine(WorldContext

context, GroupFactory

groupFactory, boolean ignoreOriginCoordinate) { + public InstancingEngine(ProgramCompiler

context, GroupFactory

groupFactory, boolean ignoreOriginCoordinate) { this.context = context; this.ignoreOriginCoordinate = ignoreOriginCoordinate; @@ -180,11 +176,11 @@ public class InstancingEngine

implements Engine { } public static class Builder

{ - protected final WorldContext

context; + protected final ProgramCompiler

context; protected GroupFactory

groupFactory = InstancedMaterialGroup::new; protected boolean ignoreOriginCoordinate; - public Builder(WorldContext

context) { + public Builder(ProgramCompiler

context) { this.context = context; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java b/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java index 42b5f8dac..9a5d2fd9c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.source; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.source.error.ErrorBuilder; @@ -21,13 +22,13 @@ import net.minecraft.resources.ResourceLocation; public class FileResolution { /** - * Spans that have references that resolved to this. + * Extra info about where this resolution is required. Includes ProgramSpecs and shader Spans. */ - private final List foundSpans = new ArrayList<>(); + private final List> extraCrashInfoProviders = new ArrayList<>(); private final ResourceLocation fileLoc; private SourceFile file; - public FileResolution(ResourceLocation fileLoc) { + FileResolution(ResourceLocation fileLoc) { this.fileLoc = fileLoc; } @@ -35,6 +36,10 @@ public class FileResolution { return fileLoc; } + /** + * Non-null if this file is resolved because there would have been a crash otherwise. + * @return The file that this resolution resolves to. + */ public SourceFile getFile() { return file; } @@ -48,34 +53,44 @@ public class FileResolution { * @param span A span where this file is referenced. */ public FileResolution addSpan(Span span) { - foundSpans.add(span); + extraCrashInfoProviders.add(builder -> builder.pointAtFile(span.getSourceFile()) + .pointAt(span, 1)); return this; } + public void addSpec(ResourceLocation name) { + extraCrashInfoProviders.add(builder -> builder.extra("needed by spec: " + name + ".json")); + } + /** * Check to see if this file actually resolves to something. * *

* Called after all files are loaded. If we can't find the file here, it doesn't exist. *

+ * + * @return True if this file is resolved. */ - void resolve(SourceFinder sources) { + boolean resolve(SourceFinder sources) { file = sources.findSource(fileLoc); if (file == null) { ErrorBuilder builder = ErrorBuilder.error(String.format("could not find source for file %s", fileLoc)); - // print the location of all places where this file was referenced - for (Span span : foundSpans) { - builder.pointAtFile(span.getSourceFile()) - .pointAt(span, 1); + for (Consumer consumer : extraCrashInfoProviders) { + consumer.accept(builder); } Backend.LOGGER.error(builder.build()); - throw new ShaderLoadingException(); + + return false; } + + // Let the GC do its thing + extraCrashInfoProviders.clear(); + return true; } void invalidate() { - foundSpans.clear(); + extraCrashInfoProviders.clear(); file = null; } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/Resolver.java b/src/main/java/com/jozufozu/flywheel/backend/source/Resolver.java index 202b7a94d..c48eb0b6e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/Resolver.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/Resolver.java @@ -9,29 +9,51 @@ import net.minecraft.resources.ResourceLocation; * Manages deferred file resolution. * *

- * Interns all referenced files in all sources, duplicating the final lookups and allowing for more dev-friendly - * error reporting. - *

- * See {@link FileResolution} for more information. + * Interns all file names in shader sources and program specs, deduplicating the final lookups and allowing for more + * dev-friendly error reporting. *

+ * + * @see FileResolution */ public class Resolver { public static final Resolver INSTANCE = new Resolver(); private final Map resolutions = new HashMap<>(); + private boolean hasRun = false; - public FileResolution findShader(ResourceLocation fileLoc) { - return resolutions.computeIfAbsent(fileLoc, FileResolution::new); + public FileResolution get(ResourceLocation file) { + if (!hasRun) { + return resolutions.computeIfAbsent(file, FileResolution::new); + } else { + // Lock the map after resolution has run. + FileResolution fileResolution = resolutions.get(file); + + // ...so crash immediately if the file isn't found. + if (fileResolution == null) { + throw new RuntimeException("could not find source for file: " + file); + } + + return fileResolution; + } } /** * Try and resolve all referenced source files, printing errors if any aren't found. */ - public void resolve(SourceFinder sources) { + public void run(SourceFinder sources) { + boolean needsCrash = false; for (FileResolution resolution : resolutions.values()) { - resolution.resolve(sources); + if (!resolution.resolve(sources)) { + needsCrash = true; + } } + + if (needsCrash) { + throw new ShaderLoadingException("Failed to resolve all source files, see log for details"); + } + + hasRun = true; } /** @@ -43,5 +65,6 @@ public class Resolver { */ public void invalidate() { resolutions.values().forEach(FileResolution::invalidate); + hasRun = false; } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java index 5692b5273..e69653336 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java @@ -16,7 +16,7 @@ import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; import com.jozufozu.flywheel.backend.source.span.ErrorSpan; import com.jozufozu.flywheel.backend.source.span.Span; import com.jozufozu.flywheel.backend.source.span.StringSpan; -import com.jozufozu.flywheel.core.pipeline.ShaderCompiler; +import com.jozufozu.flywheel.core.compile.FileIndex; import net.minecraft.resources.ResourceLocation; @@ -138,7 +138,7 @@ public class SourceFile { return "#use " + '"' + name + '"'; } - public void generateFinalSource(ShaderCompiler env, StringBuilder source) { + public void generateFinalSource(FileIndex env, StringBuilder source) { for (Import include : imports) { SourceFile file = include.getFile(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java index d917ca186..afda73953 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java @@ -16,7 +16,7 @@ import com.jozufozu.flywheel.backend.source.error.lines.SourceLine; import com.jozufozu.flywheel.backend.source.error.lines.SpanHighlightLine; import com.jozufozu.flywheel.backend.source.error.lines.TextLine; import com.jozufozu.flywheel.backend.source.span.Span; -import com.jozufozu.flywheel.core.pipeline.ShaderCompiler; +import com.jozufozu.flywheel.core.compile.ShaderCompiler; import com.jozufozu.flywheel.util.FlwUtil; public class ErrorBuilder { @@ -127,6 +127,7 @@ public class ErrorBuilder { } StringBuilder builder = new StringBuilder(); + builder.append('\n'); for (ErrorLine line : lines) { int length = line.neededMargin(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/parse/Import.java b/src/main/java/com/jozufozu/flywheel/backend/source/parse/Import.java index 23a7f279a..239518d84 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/parse/Import.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/parse/Import.java @@ -26,7 +26,7 @@ public class Import extends AbstractShaderElement { super(self); this.file = file; - resolution = resolver.findShader(toRL(file)) + resolution = resolver.get(toRL(file)) .addSpan(file); IMPORTS.add(this); diff --git a/src/main/java/com/jozufozu/flywheel/core/Contexts.java b/src/main/java/com/jozufozu/flywheel/core/Contexts.java index 2d067a0b8..f4dc621cd 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Contexts.java +++ b/src/main/java/com/jozufozu/flywheel/core/Contexts.java @@ -1,13 +1,11 @@ package com.jozufozu.flywheel.core; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.GameStateRegistry; import com.jozufozu.flywheel.backend.source.FileResolution; import com.jozufozu.flywheel.backend.source.Resolver; +import com.jozufozu.flywheel.core.compile.ProgramCompiler; import com.jozufozu.flywheel.core.crumbling.CrumblingProgram; -import com.jozufozu.flywheel.core.pipeline.PipelineCompiler; -import com.jozufozu.flywheel.core.pipeline.WorldCompiler; import com.jozufozu.flywheel.core.shader.NormalDebugStateProvider; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.event.GatherContextEvent; @@ -20,22 +18,17 @@ import net.minecraftforge.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class Contexts { - public static WorldContext WORLD; - public static WorldContext CRUMBLING; + public static ProgramCompiler WORLD; + public static ProgramCompiler CRUMBLING; public static void flwInit(GatherContextEvent event) { - Backend backend = event.getBackend(); - GameStateRegistry.register(NormalDebugStateProvider.INSTANCE); - FileResolution crumblingBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.CRUMBLING, ".glsl")); - FileResolution worldBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.WORLD, ".glsl")); + FileResolution worldBuiltins = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.WORLD, ".glsl")); + FileResolution crumblingBuiltins = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.CRUMBLING, ".glsl")); - PipelineCompiler crumblingPipeline = new WorldCompiler<>(CrumblingProgram::new, Templates.INSTANCING, crumblingBuiltins); - PipelineCompiler worldPipeline = new WorldCompiler<>(WorldProgram::new, Templates.INSTANCING, worldBuiltins); - - CRUMBLING = backend.register(WorldContext.builder(backend, Names.CRUMBLING).build(crumblingPipeline)); - WORLD = backend.register(WorldContext.builder(backend, Names.WORLD).build(worldPipeline)); + WORLD = Templates.INSTANCING.programCompiler(WorldProgram::new, worldBuiltins); + CRUMBLING = Templates.INSTANCING.programCompiler(CrumblingProgram::new, crumblingBuiltins); } public static class Names { diff --git a/src/main/java/com/jozufozu/flywheel/core/Materials.java b/src/main/java/com/jozufozu/flywheel/core/Materials.java index f5470dc83..238a6b052 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Materials.java +++ b/src/main/java/com/jozufozu/flywheel/core/Materials.java @@ -28,5 +28,6 @@ public class Materials { public static class Names { public static final ResourceLocation MODEL = Flywheel.rl("model"); public static final ResourceLocation ORIENTED = Flywheel.rl("oriented"); + public static final ResourceLocation PASSTHRU = Flywheel.rl("passthru"); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/Templates.java b/src/main/java/com/jozufozu/flywheel/core/Templates.java index df6f04b35..0946a6e94 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Templates.java +++ b/src/main/java/com/jozufozu/flywheel/core/Templates.java @@ -1,12 +1,12 @@ package com.jozufozu.flywheel.core; import com.jozufozu.flywheel.backend.gl.GLSLVersion; -import com.jozufozu.flywheel.core.pipeline.InstancingTemplateData; -import com.jozufozu.flywheel.core.pipeline.OneShotTemplateData; -import com.jozufozu.flywheel.core.pipeline.Template; +import com.jozufozu.flywheel.core.compile.InstancingTemplateData; +import com.jozufozu.flywheel.core.compile.OneShotTemplateData; +import com.jozufozu.flywheel.core.compile.Template; public class Templates { - public static final Template INSTANCING = new Template<>(GLSLVersion.V330, InstancingTemplateData::new); - public static final Template ONE_SHOT = new Template<>(GLSLVersion.V150, OneShotTemplateData::new); + public static final Template INSTANCING = new Template(GLSLVersion.V330, InstancingTemplateData::new); + public static final Template ONE_SHOT = new Template(GLSLVersion.V150, OneShotTemplateData::new); } diff --git a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java b/src/main/java/com/jozufozu/flywheel/core/WorldContext.java deleted file mode 100644 index fa56a87ba..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/WorldContext.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.jozufozu.flywheel.core; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.function.Supplier; -import java.util.stream.Stream; - -import com.jozufozu.flywheel.api.struct.Instanced; -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.RenderLayer; -import com.jozufozu.flywheel.backend.ShaderContext; -import com.jozufozu.flywheel.backend.source.ShaderLoadingException; -import com.jozufozu.flywheel.core.pipeline.CachingCompiler; -import com.jozufozu.flywheel.core.pipeline.CompilationContext; -import com.jozufozu.flywheel.core.pipeline.PipelineCompiler; -import com.jozufozu.flywheel.core.shader.ProgramSpec; -import com.jozufozu.flywheel.core.shader.WorldProgram; - -import net.minecraft.resources.ResourceLocation; - -public class WorldContext

implements ShaderContext

{ - public final Backend backend; - protected final Map programs = new HashMap<>(); - protected final ResourceLocation name; - protected final Supplier> specStream; - private final CachingCompiler

programCache; - - public WorldContext(Backend backend, ResourceLocation name, Supplier> specStream, PipelineCompiler

pipeline) { - this.backend = backend; - this.name = name; - this.specStream = specStream; - this.programCache = new CachingCompiler<>(pipeline); - } - - @Override - public void load() { - - Backend.LOGGER.info("Loading context '{}'", name); - - specStream.get() - .map(backend::getSpec) - .forEach(this::loadSpec); - } - - private void loadSpec(ProgramSpec spec) { - - try { - programs.put(spec.name, spec); - - Backend.LOGGER.debug("Loaded program {}", spec.name); - } catch (Exception e) { - Backend.LOGGER.error("Error loading program {}", spec.name); - if (!(e instanceof ShaderLoadingException)) { - Backend.LOGGER.error("", e); - } - backend.loader.notifyError(); - } - } - - @Override - public P getProgram(ResourceLocation loc, VertexType vertexType, RenderLayer layer) { - ProgramSpec spec = programs.get(loc); - - if (spec == null) { - throw new NullPointerException("Cannot compile shader because '" + loc + "' is not recognized."); - } - - return programCache.getProgram(CompilationContext.create(vertexType, layer, spec)); - } - - @Override - public void delete() { - programCache.invalidate(); - programs.clear(); - } - - public static Builder builder(Backend backend, ResourceLocation name) { - return new Builder(backend, name); - } - - public static class Builder { - private final Backend backend; - private final ResourceLocation name; - private Supplier> specStream; - - public Builder(Backend backend, ResourceLocation name) { - this.backend = backend; - this.name = name; - } - - public Builder setSpecStream(Supplier> specStream) { - this.specStream = specStream; - return this; - } - - public

WorldContext

build(PipelineCompiler

pipeline) { - if (specStream == null) { - specStream = () -> backend.allMaterials() - .stream() - .map(t -> t instanceof Instanced i ? i : null) - .filter(Objects::nonNull) - .map(Instanced::getProgramSpec); - } - return new WorldContext<>(backend, name, specStream, pipeline); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FileIndex.java b/src/main/java/com/jozufozu/flywheel/core/compile/FileIndex.java new file mode 100644 index 000000000..ec08aade6 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/compile/FileIndex.java @@ -0,0 +1,13 @@ +package com.jozufozu.flywheel.core.compile; + +import com.jozufozu.flywheel.backend.source.SourceFile; + +public interface FileIndex { + /** + * Returns an arbitrary file ID for use this compilation context, or generates one if missing. + * + * @param sourceFile The file to retrieve the ID for. + * @return A file ID unique to the given sourceFile. + */ + int getFileID(SourceFile sourceFile); +} diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/InstancingTemplateData.java b/src/main/java/com/jozufozu/flywheel/core/compile/InstancingTemplateData.java similarity index 97% rename from src/main/java/com/jozufozu/flywheel/core/pipeline/InstancingTemplateData.java rename to src/main/java/com/jozufozu/flywheel/core/compile/InstancingTemplateData.java index a18c08f3f..ba3db483c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/InstancingTemplateData.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/InstancingTemplateData.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.pipeline; +package com.jozufozu.flywheel.core.compile; import java.util.Optional; @@ -134,7 +134,7 @@ public class InstancingTemplateData implements TemplateData { )); } - public void fragmentFooter(StringBuilder template, ShaderCompiler shader) { + public void fragmentFooter(StringBuilder template, FileIndex shader) { Template.prefixFields(template, interpolant, "in", "v2f_"); template.append(String.format(""" diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/OneShotTemplateData.java b/src/main/java/com/jozufozu/flywheel/core/compile/OneShotTemplateData.java similarity index 96% rename from src/main/java/com/jozufozu/flywheel/core/pipeline/OneShotTemplateData.java rename to src/main/java/com/jozufozu/flywheel/core/compile/OneShotTemplateData.java index c000e506c..49d409faf 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/OneShotTemplateData.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/OneShotTemplateData.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.pipeline; +package com.jozufozu.flywheel.core.compile; import java.util.Optional; @@ -99,7 +99,7 @@ public class OneShotTemplateData implements TemplateData { """); } - public void fragmentFooter(StringBuilder template, ShaderCompiler file) { + public void fragmentFooter(StringBuilder template, FileIndex file) { Template.prefixFields(template, interpolant, "in", "v2f_"); template.append(String.format(""" diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/ProgramAssembler.java b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramAssembler.java similarity index 87% rename from src/main/java/com/jozufozu/flywheel/core/pipeline/ProgramAssembler.java rename to src/main/java/com/jozufozu/flywheel/core/compile/ProgramAssembler.java index c5fc72d63..420859520 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/ProgramAssembler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramAssembler.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.pipeline; +package com.jozufozu.flywheel.core.compile; import static org.lwjgl.opengl.GL11.GL_TRUE; import static org.lwjgl.opengl.GL20.GL_LINK_STATUS; @@ -11,9 +11,8 @@ import static org.lwjgl.opengl.GL20.glLinkProgram; import java.util.List; import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlShader; -import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram; -import com.jozufozu.flywheel.core.shader.WorldProgram; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.resources.ResourceLocation; @@ -61,7 +60,7 @@ public class ProgramAssembler { return this; } - public

P build(ExtensibleGlProgram.Factory

factory) { + public

P build(GlProgram.Factory

factory) { return factory.create(name, program); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java new file mode 100644 index 000000000..fe0f84423 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java @@ -0,0 +1,58 @@ +package com.jozufozu.flywheel.core.compile; + +import java.util.HashMap; +import java.util.Map; + +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; +import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.backend.source.FileResolution; + +/** + * A caching compiler. + * + *

+ * This class is responsible for compiling programs on the fly. An instance of this class will keep a cache of + * compiled programs, and will only compile a program if it is not already in the cache. + *

+ */ +public class ProgramCompiler

{ + + protected final Map cache = new HashMap<>(); + private final GlProgram.Factory

factory; + + private final Template template; + private final FileResolution header; + + public ProgramCompiler(GlProgram.Factory

factory, Template template, FileResolution header) { + this.factory = factory; + this.template = template; + this.header = header; + } + + /** + * Get or compile a spec to the given vertex type, accounting for all game state conditions specified by the spec. + * + * @param ctx The context of compilation. + * @return A compiled GlProgram. + */ + public P getProgram(ProgramContext ctx) { + return cache.computeIfAbsent(ctx, this::compile); + } + + public void invalidate() { + cache.values().forEach(P::delete); + cache.clear(); + } + + private P compile(ProgramContext ctx) { + ShaderCompiler compiler = new ShaderCompiler(ctx, template, header); + + return new ProgramAssembler(compiler.name) + .attachShader(compiler.compile(ShaderType.VERTEX)) + .attachShader(compiler.compile(ShaderType.FRAGMENT)) + .link() + .deleteLinkedShaders() + .build(this.factory); + } + +} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramContext.java b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramContext.java new file mode 100644 index 000000000..6b0450ed0 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramContext.java @@ -0,0 +1,71 @@ +package com.jozufozu.flywheel.core.compile; + +import java.util.Objects; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.RenderLayer; +import com.jozufozu.flywheel.backend.source.SourceFile; +import com.jozufozu.flywheel.core.shader.ProgramSpec; + +import net.minecraft.resources.ResourceLocation; + +/** + * Represents the entire context of a program's usage. + * + * @param alphaDiscard Alpha threshold below which pixels are discarded. + * @param vertexType The vertexType the program should be adapted for. + * @param spec The generic program name. + * @param ctx An ID representing the state at the time of usage. + */ +public record ProgramContext(float alphaDiscard, VertexType vertexType, ProgramSpec spec, long ctx) { + + /** + * Creates a compilation context for the given program, vertex type and render layer. + * + * @param programName The name of the program to use. + * @param vertexType The vertex type to use. + * @param layer If cutout, the alpha discard threshold is 0.1, otherwise 0. + * @return A compilation context. + */ + public static ProgramContext create(ResourceLocation programName, VertexType vertexType, @Nullable RenderLayer layer) { + ProgramSpec spec = Backend.getInstance() + .getSpec(programName); + + if (spec == null) { + throw new NullPointerException("Cannot compile shader because '" + programName + "' is not recognized."); + } + + 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 SourceFile getFile() { + return spec().getSource(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ProgramContext that = (ProgramContext) o; + // override for instance equality on vertexType + return alphaDiscard == that.alphaDiscard && ctx == that.ctx && vertexType == that.vertexType && spec.equals(that.spec); + } + + @Override + public int hashCode() { + return Objects.hash(alphaDiscard, vertexType, spec, ctx); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/ShaderCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompiler.java similarity index 80% rename from src/main/java/com/jozufozu/flywheel/core/pipeline/ShaderCompiler.java rename to src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompiler.java index c2da3e63a..fb5a3ffd5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/ShaderCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompiler.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.pipeline; +package com.jozufozu.flywheel.core.compile; import java.util.ArrayList; import java.util.List; @@ -7,7 +7,7 @@ import javax.annotation.Nullable; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.RenderLayer; +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlShader; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.backend.source.FileResolution; @@ -15,27 +15,50 @@ import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.backend.source.error.ErrorBuilder; import com.jozufozu.flywheel.backend.source.error.ErrorReporter; import com.jozufozu.flywheel.backend.source.span.Span; -import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram; import com.jozufozu.flywheel.core.shader.WorldProgram; import net.minecraft.resources.ResourceLocation; -public class ShaderCompiler { +/** + * Compiles a shader program. + */ +public class ShaderCompiler implements FileIndex { + /** + * The name of the file responsible for this compilation. + */ public final ResourceLocation name; - public final Template template; + + /** + * The template we'll be using to generate the final source. + */ + public final Template template; + private final FileResolution header; + /** + * Extra {@code #define}s to be added to the shader. + */ private final List defines; - private final RenderLayer layer; + /** + * Alpha threshold below which pixels are discarded. + */ + private final float alphaDiscard; + + /** + * The vertex type to use. + */ public final VertexType vertexType; + /** + * The main file to compile. + */ public final SourceFile mainFile; private final List files = new ArrayList<>(); - public ShaderCompiler(CompilationContext context, Template template, FileResolution header) { + public ShaderCompiler(ProgramContext context, Template template, FileResolution header) { this.name = context.spec().name; this.template = template; this.header = header; @@ -43,7 +66,7 @@ public class ShaderCompiler { this.defines = context.spec() .getDefines(context.ctx()); this.vertexType = context.vertexType(); - layer = context.layer(); + this.alphaDiscard = context.alphaDiscard(); } public GlShader compile(ShaderType type) { @@ -55,11 +78,9 @@ public class ShaderCompiler { .append('\n') .append("#extension GL_ARB_explicit_attrib_location : enable\n") .append("#extension GL_ARB_conservative_depth : enable\n") - .append("#define ") - .append(type.define) // special case shader type declaration - .append('\n'); + .append(type.getDefineStatement()); // special case shader type declaration - if (layer == RenderLayer.CUTOUT) { + if (alphaDiscard > 0) { finalSource.append("#define ALPHA_DISCARD 0.1\n"); } @@ -91,7 +112,7 @@ public class ShaderCompiler { return new GlShader(this, type, finalSource.toString()); } - public

P compile(ExtensibleGlProgram.Factory

worldShaderPipeline) { + public

P compile(GlProgram.Factory

worldShaderPipeline) { return new ProgramAssembler(this.name) .attachShader(compile(ShaderType.VERTEX)) .attachShader(compile(ShaderType.FRAGMENT)) @@ -105,6 +126,7 @@ public class ShaderCompiler { * @param sourceFile The file to retrieve the ID for. * @return A file ID unique to the given sourceFile. */ + @Override public int getFileID(SourceFile sourceFile) { int i = files.indexOf(sourceFile); if (i != -1) { diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/Template.java b/src/main/java/com/jozufozu/flywheel/core/compile/Template.java similarity index 65% rename from src/main/java/com/jozufozu/flywheel/core/pipeline/Template.java rename to src/main/java/com/jozufozu/flywheel/core/compile/Template.java index 1a872d2b4..995218b2d 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/Template.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/Template.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.pipeline; +package com.jozufozu.flywheel.core.compile; import java.util.HashMap; import java.util.Map; @@ -6,6 +6,8 @@ import java.util.function.Function; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.backend.gl.GLSLVersion; +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; +import com.jozufozu.flywheel.backend.source.FileResolution; import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; import com.jozufozu.flywheel.backend.source.parse.StructField; @@ -17,25 +19,35 @@ import com.jozufozu.flywheel.backend.source.parse.StructField; * Shader files are written somewhat abstractly. Subclasses of Template handle those abstractions, using SourceFile * metadata to generate shader code that OpenGL can use to call into our shader programs. *

- * @param Holds metadata, generates errors. */ -public class Template { +public class Template { - private final Map metadata = new HashMap<>(); + private final Map metadata = new HashMap<>(); - private final Function reader; + private final Function reader; private final GLSLVersion glslVersion; - public Template(GLSLVersion glslVersion, Function reader) { + public Template(GLSLVersion glslVersion, Function reader) { this.reader = reader; this.glslVersion = glslVersion; } - public D getMetadata(SourceFile file) { + public TemplateData getMetadata(SourceFile file) { // lazily read files, cache results return metadata.computeIfAbsent(file, reader); } + /** + * Creates a program compiler using this template. + * @param factory A factory to add meaning to compiled programs. + * @param header The header file to use for the program. + * @param

The type of program to compile. + * @return A program compiler. + */ + public

ProgramCompiler

programCompiler(GlProgram.Factory

factory, FileResolution header) { + return new ProgramCompiler<>(factory, this, header); + } + public GLSLVersion getVersion() { return glslVersion; } diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/TemplateData.java b/src/main/java/com/jozufozu/flywheel/core/compile/TemplateData.java similarity index 85% rename from src/main/java/com/jozufozu/flywheel/core/pipeline/TemplateData.java rename to src/main/java/com/jozufozu/flywheel/core/compile/TemplateData.java index 90ea7e01f..60c68d080 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/TemplateData.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/TemplateData.java @@ -1,10 +1,10 @@ -package com.jozufozu.flywheel.core.pipeline; +package com.jozufozu.flywheel.core.compile; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; public interface TemplateData { void vertexFooter(StringBuilder builder, ShaderCompiler file); - void fragmentFooter(StringBuilder builder, ShaderCompiler file); + void fragmentFooter(StringBuilder builder, FileIndex file); /** * Generate the necessary glue code here. diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/TypeHelper.java b/src/main/java/com/jozufozu/flywheel/core/compile/TypeHelper.java similarity index 94% rename from src/main/java/com/jozufozu/flywheel/core/pipeline/TypeHelper.java rename to src/main/java/com/jozufozu/flywheel/core/compile/TypeHelper.java index 065755eaa..148168e7b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/TypeHelper.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/TypeHelper.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.pipeline; +package com.jozufozu.flywheel.core.compile; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/package-info.java b/src/main/java/com/jozufozu/flywheel/core/compile/package-info.java similarity index 79% rename from src/main/java/com/jozufozu/flywheel/core/pipeline/package-info.java rename to src/main/java/com/jozufozu/flywheel/core/compile/package-info.java index e51c6e616..d81aeffbb 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/package-info.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/package-info.java @@ -1,5 +1,5 @@ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.jozufozu.flywheel.core.pipeline; +package com.jozufozu.flywheel.core.compile; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/CachingCompiler.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/CachingCompiler.java deleted file mode 100644 index b29b75c30..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/CachingCompiler.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.jozufozu.flywheel.core.pipeline; - -import java.util.HashMap; -import java.util.Map; - -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; - -/** - * Lazily compiles shader programs, caching the results. - * - * @param

The class that the PipelineCompiler outputs. - */ -public class CachingCompiler

{ - protected final Map cache = new HashMap<>(); - private final PipelineCompiler

pipeline; - - public CachingCompiler(PipelineCompiler

pipeline) { - this.pipeline = pipeline; - } - - /** - * Get or compile a spec to the given vertex type, accounting for all game state conditions specified by the spec. - * - * @param context The context of compilation. - * @return A compiled GlProgram. - */ - public P getProgram(CompilationContext context) { - return cache.computeIfAbsent(context, this.pipeline::compile); - } - - public void invalidate() { - cache.values().forEach(P::delete); - cache.clear(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java deleted file mode 100644 index 74cae594b..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/CompilationContext.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.jozufozu.flywheel.core.pipeline; - -import java.util.Objects; - -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.backend.RenderLayer; -import com.jozufozu.flywheel.backend.source.SourceFile; -import com.jozufozu.flywheel.core.shader.ProgramSpec; - -/** - * Represents the entire context of a program's usage. - * - * @param layer - * @param vertexType The vertexType the program should be adapted for. - * @param spec The generic program name. - * @param ctx An ID representing the state at the time of usage. - */ -public record CompilationContext(RenderLayer layer, VertexType vertexType, ProgramSpec spec, long ctx) { - - public static CompilationContext create(VertexType vertexType, RenderLayer layer, ProgramSpec spec) { - return new CompilationContext(layer, vertexType, spec, spec.getCurrentStateID()); - } - - public SourceFile getFile() { - return spec().getSource(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - CompilationContext that = (CompilationContext) o; - // override for instance equality on vertexType - return layer == that.layer && ctx == that.ctx && vertexType == that.vertexType && spec.equals(that.spec); - } - - @Override - public int hashCode() { - return Objects.hash(layer, vertexType, spec, ctx); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/PipelineCompiler.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/PipelineCompiler.java deleted file mode 100644 index a831480e5..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/PipelineCompiler.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.jozufozu.flywheel.core.pipeline; - -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; - -/** - * The main interface for compiling usable shaders from program specs. - * @param

the type of the program that this pipeline compiles. - */ -public interface PipelineCompiler

{ - - P compile(CompilationContext vertexType); - -} diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/WorldCompiler.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/WorldCompiler.java deleted file mode 100644 index 5bf2980a8..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/WorldCompiler.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.jozufozu.flywheel.core.pipeline; - -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; -import com.jozufozu.flywheel.backend.source.FileResolution; -import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram; -import com.jozufozu.flywheel.core.shader.WorldProgram; - -public class WorldCompiler

implements PipelineCompiler

{ - - private final ExtensibleGlProgram.Factory

factory; - - private final Template template; - private final FileResolution header; - - public WorldCompiler(ExtensibleGlProgram.Factory

factory, Template template, FileResolution header) { - this.factory = factory; - this.template = template; - this.header = header; - } - - @Override - public P compile(CompilationContext usage) { - ShaderCompiler compiler = new ShaderCompiler(usage, template, header); - - return new ProgramAssembler(compiler.name) - .attachShader(compiler.compile(ShaderType.VERTEX)) - .attachShader(compiler.compile(ShaderType.FRAGMENT)) - .link() - .deleteLinkedShaders() - .build(this.factory); - } - -} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/ExtensibleGlProgram.java b/src/main/java/com/jozufozu/flywheel/core/shader/ExtensibleGlProgram.java deleted file mode 100644 index 927092e9b..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/shader/ExtensibleGlProgram.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.jozufozu.flywheel.core.shader; - -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nonnull; - -import com.jozufozu.flywheel.backend.ShaderContext; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; - -import net.minecraft.resources.ResourceLocation; - -/** - * A shader program that be arbitrarily "extended". This class can take in any number of program extensions, and - * will initialize them and then call their {@link ExtensionInstance#bind() bind} function every subsequent time this - * program is bound. An "extension" is something that interacts with the shader program in a way that is invisible to - * the caller using the program. This is used by some programs to implement the different fog modes. Other uses might - * include binding extra textures to allow for blocks to have normal maps, for example. As the extensions are - * per-program, this also allows for same extra specialization within a - * {@link ShaderContext ShaderContext}. - */ -public class ExtensibleGlProgram extends GlProgram { - - protected final List extensions = new ArrayList<>(); - - public ExtensibleGlProgram(ResourceLocation name, int handle) { - super(name, handle); - } - - @Override - public void bind() { - super.bind(); - - extensions.forEach(ExtensionInstance::bind); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("program ") - .append(name) - .append('['); - - for (ExtensionInstance extension : extensions) { - builder.append(extension) - .append('+'); - } - - builder.append(']'); - - return builder.toString(); - } - - /** - * A factory interface to create {@link GlProgram}s parameterized by a list of extensions. This doesn't necessarily - * have to return an {@link ExtensibleGlProgram} if implementors want more flexibility for whatever reason. - */ - public interface Factory

{ - - @Nonnull - P create(ResourceLocation name, int handle); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java index d0ffe8068..34111f068 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java @@ -43,12 +43,13 @@ public class ProgramSpec { public final ImmutableList states; public ProgramSpec(ResourceLocation source, List states) { - this.source = Resolver.INSTANCE.findShader(source); + this.source = Resolver.INSTANCE.get(source); this.states = ImmutableList.copyOf(states); } public void setName(ResourceLocation name) { this.name = name; + this.source.addSpec(name); } public ResourceLocation getSourceLoc() { diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/WorldProgram.java b/src/main/java/com/jozufozu/flywheel/core/shader/WorldProgram.java index 3754969b8..0dce27d7d 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/WorldProgram.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/WorldProgram.java @@ -4,6 +4,7 @@ import static org.lwjgl.opengl.GL20.glUniform1f; import static org.lwjgl.opengl.GL20.glUniform2f; import static org.lwjgl.opengl.GL20.glUniform3f; +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.util.AnimationTickHolder; import com.mojang.blaze3d.platform.Window; import com.mojang.math.Matrix4f; @@ -11,11 +12,12 @@ import com.mojang.math.Matrix4f; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; -public class WorldProgram extends ExtensibleGlProgram { +public class WorldProgram extends GlProgram { protected final int uTime = getUniformLocation("uTime"); protected final int uViewProjection = getUniformLocation("uViewProjection"); protected final int uCameraPos = getUniformLocation("uCameraPos"); protected final int uWindowSize = getUniformLocation("uWindowSize"); + private final WorldFog fog; protected int uBlockAtlas; protected int uLightMap; @@ -23,7 +25,7 @@ public class WorldProgram extends ExtensibleGlProgram { public WorldProgram(ResourceLocation name, int handle) { super(name, handle); - this.extensions.add(new WorldFog(this)); + fog = new WorldFog(this); super.bind(); registerSamplers(); @@ -66,7 +68,7 @@ public class WorldProgram extends ExtensibleGlProgram { @Override public void bind() { super.bind(); - + fog.bind(); uploadWindowSize(); uploadTime(AnimationTickHolder.getRenderTime()); } diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/package-info.java b/src/main/java/com/jozufozu/flywheel/core/shader/package-info.java new file mode 100644 index 000000000..d25693290 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/shader/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.core.shader; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/resources/assets/flywheel/flywheel/programs/passthru.json b/src/main/resources/assets/flywheel/flywheel/programs/passthru.json new file mode 100644 index 000000000..bdb8aabff --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/programs/passthru.json @@ -0,0 +1,9 @@ +{ + "source": "flywheel:passthru.vert", + "states": [ + { + "when": "flywheel:normal_debug", + "define": "DEBUG_NORMAL" + } + ] +} diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/passthru.vert b/src/main/resources/assets/flywheel/flywheel/shaders/passthru.vert new file mode 100644 index 000000000..a598d8ebd --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/shaders/passthru.vert @@ -0,0 +1,7 @@ +#use "flywheel:block.frag" + +#if defined(VERTEX_SHADER) +void vertex(inout Vertex v) { + +} +#endif From 2d63d8c7dbb5d0875d1d4c17e9f8498a32fc2e59 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Mon, 10 Jan 2022 14:38:26 -0800 Subject: [PATCH 06/10] Separate vertex and fragment shaders and templates --- .../flywheel/api/vertex/VertexType.java | 4 +- .../flywheel/backend/gl/shader/GlShader.java | 11 +- .../instancing/InstancingEngine.java | 4 - .../backend/source/error/ErrorBuilder.java | 4 +- .../com/jozufozu/flywheel/core/Contexts.java | 4 +- .../com/jozufozu/flywheel/core/Templates.java | 6 +- .../flywheel/core/compile/FileIndex.java | 7 + .../flywheel/core/compile/FileIndexImpl.java | 77 +++++++ .../flywheel/core/compile/FragmentData.java | 8 + .../core/compile/FragmentTemplateData.java | 88 ++++++++ .../core/compile/InstancingTemplateData.java | 73 +++--- .../core/compile/OneShotTemplateData.java | 92 ++------ .../core/compile/ProgramCompiler.java | 35 ++- .../flywheel/core/compile/ProgramContext.java | 6 +- .../flywheel/core/compile/ShaderCompiler.java | 211 +++++------------- .../flywheel/core/compile/Template.java | 60 +---- .../flywheel/core/compile/TemplateData.java | 23 -- .../flywheel/core/compile/VertexData.java | 11 + .../flywheel/core/shader/ProgramSpec.java | 29 ++- .../flywheel/core/vertex/BlockVertex.java | 2 +- .../core/vertex/PosTexNormalVertex.java | 2 +- .../flywheel/flywheel/programs/model.json | 3 +- .../flywheel/flywheel/programs/oriented.json | 3 +- .../flywheel/flywheel/programs/passthru.json | 3 +- .../flywheel/flywheel/shaders/block.frag | 2 - .../flywheel/flywheel/shaders/model.vert | 4 - .../flywheel/flywheel/shaders/oriented.vert | 4 - .../flywheel/flywheel/shaders/passthru.vert | 3 - 28 files changed, 379 insertions(+), 400 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/FileIndexImpl.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/FragmentData.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/FragmentTemplateData.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/TemplateData.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/VertexData.java diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java index 165512540..5b7afb654 100644 --- a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java @@ -32,6 +32,8 @@ public interface VertexType { */ VertexList createReader(ByteBuffer buffer, int vertexCount); + String getShaderHeader(); + default int getStride() { return getLayout().getStride(); } @@ -39,6 +41,4 @@ public interface VertexType { default int byteOffset(int vertexIndex) { return getStride() * vertexIndex; } - - String writeShaderHeader(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java index 67e31c833..575e43c42 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java @@ -5,7 +5,6 @@ import org.lwjgl.opengl.GL20; import com.jozufozu.flywheel.backend.gl.GlObject; import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; import com.jozufozu.flywheel.backend.source.ShaderLoadingException; -import com.jozufozu.flywheel.core.compile.ShaderCompiler; import net.minecraft.resources.ResourceLocation; @@ -14,8 +13,8 @@ public class GlShader extends GlObject { public final ResourceLocation name; public final ShaderType type; - public GlShader(ShaderCompiler env, ShaderType type, String source) { - name = env.name; + public GlShader(ResourceLocation name, ShaderType type, String source) { + this.name = name; this.type = type; int handle = GL20.glCreateShader(type.glEnum); @@ -24,9 +23,9 @@ public class GlShader extends GlObject { String log = GL20.glGetShaderInfoLog(handle); - if (!log.isEmpty()) { - env.printShaderInfoLog(source, log, this.name); - } +// if (!log.isEmpty()) { +// env.printShaderInfoLog(source, log, this.name); +// } if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) { throw new ShaderLoadingException("Could not compile " + name + ". See log for details."); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index c7848e19a..72a03d5dc 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -3,15 +3,12 @@ package com.jozufozu.flywheel.backend.instancing.instancing; import java.util.EnumMap; import java.util.HashMap; import java.util.Map; -import java.util.function.Supplier; import java.util.stream.Stream; import javax.annotation.Nullable; import com.jozufozu.flywheel.api.MaterialGroup; import com.jozufozu.flywheel.backend.RenderLayer; -import com.jozufozu.flywheel.backend.gl.GlVertexArray; -import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.core.compile.ProgramCompiler; @@ -24,7 +21,6 @@ import net.minecraft.client.Camera; import net.minecraft.client.renderer.RenderType; import net.minecraft.core.BlockPos; import net.minecraft.core.Vec3i; -import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; public class InstancingEngine

implements Engine { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java index afda73953..04578dc41 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java @@ -16,7 +16,7 @@ import com.jozufozu.flywheel.backend.source.error.lines.SourceLine; import com.jozufozu.flywheel.backend.source.error.lines.SpanHighlightLine; import com.jozufozu.flywheel.backend.source.error.lines.TextLine; import com.jozufozu.flywheel.backend.source.span.Span; -import com.jozufozu.flywheel.core.compile.ShaderCompiler; +import com.jozufozu.flywheel.core.compile.FileIndex; import com.jozufozu.flywheel.util.FlwUtil; public class ErrorBuilder { @@ -45,7 +45,7 @@ public class ErrorBuilder { } @Nullable - public static ErrorBuilder fromLogLine(ShaderCompiler env, String s) { + public static ErrorBuilder fromLogLine(FileIndex env, String s) { Matcher matcher = ERROR_LINE.matcher(s); if (matcher.find()) { diff --git a/src/main/java/com/jozufozu/flywheel/core/Contexts.java b/src/main/java/com/jozufozu/flywheel/core/Contexts.java index f4dc621cd..66bf2b0f5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Contexts.java +++ b/src/main/java/com/jozufozu/flywheel/core/Contexts.java @@ -27,8 +27,8 @@ public class Contexts { FileResolution worldBuiltins = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.WORLD, ".glsl")); FileResolution crumblingBuiltins = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.CRUMBLING, ".glsl")); - WORLD = Templates.INSTANCING.programCompiler(WorldProgram::new, worldBuiltins); - CRUMBLING = Templates.INSTANCING.programCompiler(CrumblingProgram::new, crumblingBuiltins); + WORLD = ProgramCompiler.create(Templates.INSTANCING, WorldProgram::new, worldBuiltins); + CRUMBLING = ProgramCompiler.create(Templates.INSTANCING, CrumblingProgram::new, crumblingBuiltins); } public static class Names { diff --git a/src/main/java/com/jozufozu/flywheel/core/Templates.java b/src/main/java/com/jozufozu/flywheel/core/Templates.java index 0946a6e94..59b538a2f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Templates.java +++ b/src/main/java/com/jozufozu/flywheel/core/Templates.java @@ -1,12 +1,14 @@ package com.jozufozu.flywheel.core; import com.jozufozu.flywheel.backend.gl.GLSLVersion; +import com.jozufozu.flywheel.core.compile.FragmentTemplateData; import com.jozufozu.flywheel.core.compile.InstancingTemplateData; import com.jozufozu.flywheel.core.compile.OneShotTemplateData; import com.jozufozu.flywheel.core.compile.Template; public class Templates { - public static final Template INSTANCING = new Template(GLSLVersion.V330, InstancingTemplateData::new); - public static final Template ONE_SHOT = new Template(GLSLVersion.V150, OneShotTemplateData::new); + public static final Template INSTANCING = new Template<>(GLSLVersion.V330, InstancingTemplateData::new); + public static final Template ONE_SHOT = new Template<>(GLSLVersion.V150, OneShotTemplateData::new); + public static final Template FRAGMENT = new Template<>(GLSLVersion.V150, FragmentTemplateData::new); } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FileIndex.java b/src/main/java/com/jozufozu/flywheel/core/compile/FileIndex.java index ec08aade6..48e435a6c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/FileIndex.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/FileIndex.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.core.compile; import com.jozufozu.flywheel.backend.source.SourceFile; +import com.jozufozu.flywheel.backend.source.span.Span; public interface FileIndex { /** @@ -10,4 +11,10 @@ public interface FileIndex { * @return A file ID unique to the given sourceFile. */ int getFileID(SourceFile sourceFile); + + SourceFile getFile(int fileID); + + default Span getLineSpan(int fileId, int lineNo) { + return getFile(fileId).getLineSpanNoWhitespace(lineNo); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FileIndexImpl.java b/src/main/java/com/jozufozu/flywheel/core/compile/FileIndexImpl.java new file mode 100644 index 000000000..0958c094e --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/compile/FileIndexImpl.java @@ -0,0 +1,77 @@ +package com.jozufozu.flywheel.core.compile; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.source.SourceFile; +import com.jozufozu.flywheel.backend.source.error.ErrorBuilder; +import com.jozufozu.flywheel.backend.source.error.ErrorReporter; + +import net.minecraft.resources.ResourceLocation; + +public class FileIndexImpl implements FileIndex { + public final List files = new ArrayList<>(); + + /** + * Returns an arbitrary file ID for use this compilation context, or generates one if missing. + * @param sourceFile The file to retrieve the ID for. + * @return A file ID unique to the given sourceFile. + */ + @Override + public int getFileID(SourceFile sourceFile) { + int i = files.indexOf(sourceFile); + if (i != -1) { + return i; + } + + int size = files.size(); + files.add(sourceFile); + return size; + } + + @Override + public SourceFile getFile(int fileId) { + return files.get(fileId); + } + + + public void printShaderInfoLog(String source, String log, ResourceLocation name) { + List lines = log.lines() + .toList(); + + boolean needsSourceDump = false; + + StringBuilder errors = new StringBuilder(); + for (String line : lines) { + ErrorBuilder builder = parseCompilerError(line); + + if (builder != null) { + errors.append(builder.build()); + } else { + errors.append(line).append('\n'); + needsSourceDump = true; + } + } + Backend.LOGGER.error("Errors compiling '" + name + "': \n" + errors); + if (needsSourceDump) { + // TODO: generated code gets its own "file" + ErrorReporter.printLines(source); + } + } + + @Nullable + private ErrorBuilder parseCompilerError(String line) { + try { + ErrorBuilder error = ErrorBuilder.fromLogLine(this, line); + if (error != null) { + return error; + } + } catch (Exception ignored) { + } + + return null; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FragmentData.java b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentData.java new file mode 100644 index 000000000..b50d3b2c5 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentData.java @@ -0,0 +1,8 @@ +package com.jozufozu.flywheel.core.compile; + +public interface FragmentData { + /** + * Generate the necessary glue code here. + */ + String generateFooter(); +} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FragmentTemplateData.java b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentTemplateData.java new file mode 100644 index 000000000..6e041d732 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentTemplateData.java @@ -0,0 +1,88 @@ +package com.jozufozu.flywheel.core.compile; + +import java.util.Optional; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.backend.source.SourceFile; +import com.jozufozu.flywheel.backend.source.error.ErrorReporter; +import com.jozufozu.flywheel.backend.source.parse.ShaderFunction; +import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; +import com.jozufozu.flywheel.backend.source.parse.StructField; +import com.jozufozu.flywheel.backend.source.parse.Variable; +import com.jozufozu.flywheel.backend.source.span.Span; + +public class FragmentTemplateData implements FragmentData { + public final SourceFile file; + public final Span interpolantName; + public final ShaderStruct interpolant; + public final ShaderFunction fragmentMain; + + public FragmentTemplateData(SourceFile file) { + this.file = file; + + Optional maybeFragmentMain = file.findFunction("fragment"); + + if (maybeFragmentMain.isEmpty()) { + ErrorReporter.generateMissingFunction(file, "fragment", "\"fragment\" function not defined"); + throw new RuntimeException(); + } + + fragmentMain = maybeFragmentMain.get(); + ImmutableList fragmentParameters = fragmentMain.getParameters(); + + + if (fragmentParameters.size() != 1) { + ErrorReporter.generateSpanError(fragmentMain.getArgs(), "fragment function must have exactly one argument"); + throw new RuntimeException(); + } + + interpolantName = fragmentMain.getParameters().get(0).type; + + Optional maybeInterpolant = file.findStruct(interpolantName); + + if (maybeInterpolant.isEmpty()) { + ErrorReporter.generateMissingStruct(file, interpolantName, "struct not defined"); + + throw new RuntimeException(); + } + + interpolant = maybeInterpolant.get(); + } + + @Override + public String generateFooter() { + StringBuilder builder = new StringBuilder(); + prefixFields(builder, interpolant, "in", "v2f_"); + + builder.append(String.format(""" + void main() { + Fragment o; + o.color = v2f_color; + o.texCoords = v2f_texCoords; + o.light = v2f_light; + o.diffuse = v2f_diffuse; + + vec4 color = %s; + FLWFinalizeColor(color); + } + """, + fragmentMain.call("o") + )); + + return builder.toString(); + } + + public static void prefixFields(StringBuilder builder, ShaderStruct struct, String qualifier, String prefix) { + ImmutableList fields = struct.getFields(); + + for (StructField field : fields) { + builder.append(qualifier) + .append(' ') + .append(field.type) + .append(' ') + .append(prefix) + .append(field.name) + .append(";\n"); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/InstancingTemplateData.java b/src/main/java/com/jozufozu/flywheel/core/compile/InstancingTemplateData.java index ba3db483c..875c806d9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/InstancingTemplateData.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/InstancingTemplateData.java @@ -13,43 +13,27 @@ import com.jozufozu.flywheel.backend.source.parse.StructField; import com.jozufozu.flywheel.backend.source.parse.Variable; import com.jozufozu.flywheel.backend.source.span.Span; -public class InstancingTemplateData implements TemplateData { +public class InstancingTemplateData implements VertexData { public final SourceFile file; public final ShaderFunction vertexMain; - public final ShaderFunction fragmentMain; - public final Span interpolantName; public final Span vertexName; public final Span instanceName; - public final ShaderStruct interpolant; public final ShaderStruct instance; public InstancingTemplateData(SourceFile file) { this.file = file; Optional vertexFunc = file.findFunction("vertex"); - Optional fragmentFunc = file.findFunction("fragment"); - if (fragmentFunc.isEmpty()) { - ErrorReporter.generateMissingFunction(file, "fragment", "\"fragment\" function not defined"); - } if (vertexFunc.isEmpty()) { ErrorReporter.generateFileError(file, "could not find \"vertex\" function"); - } - - if (fragmentFunc.isEmpty() || vertexFunc.isEmpty()) { throw new ShaderLoadingException(); } - fragmentMain = fragmentFunc.get(); vertexMain = vertexFunc.get(); - ImmutableList parameters = fragmentMain.getParameters(); ImmutableList vertexParams = vertexMain.getParameters(); - if (parameters.size() != 1) { - ErrorReporter.generateSpanError(fragmentMain.getArgs(), "instancing requires fragment function to have 1 argument"); - } - if (vertexParams.size() != 2) { ErrorReporter.generateSpanError(vertexMain.getArgs(), "instancing requires vertex function to have 2 arguments"); throw new ShaderLoadingException(); @@ -68,35 +52,27 @@ public class InstancingTemplateData implements TemplateData { throw new ShaderLoadingException(); } - interpolantName = parameters.get(0).type; instanceName = vertexParams.get(1).type; - Optional maybeInterpolant = file.findStruct(interpolantName); Optional maybeInstance = file.findStruct(instanceName); - if (maybeInterpolant.isEmpty()) { - ErrorReporter.generateMissingStruct(file, interpolantName, "struct not defined"); - } - if (maybeInstance.isEmpty()) { ErrorReporter.generateMissingStruct(file, instanceName, "struct not defined"); - } - - if (maybeInterpolant.isEmpty() || maybeInstance.isEmpty()) { throw new ShaderLoadingException(); } - interpolant = maybeInterpolant.get(); instance = maybeInstance.get(); } - public void vertexFooter(StringBuilder template, ShaderCompiler shader) { + @Override + public String generateFooter(FileIndex shader, VertexType vertexType) { ImmutableList fields = instance.getFields(); - VertexType vertexType = shader.vertexType; int attributeBinding = vertexType.getLayout() .getAttributeCount(); + StringBuilder template = new StringBuilder(); + for (StructField field : fields) { template.append("layout(location = ") .append(attributeBinding) @@ -109,9 +85,12 @@ public class InstancingTemplateData implements TemplateData { .append(";\n"); attributeBinding += TypeHelper.getAttributeCount(field.type); } - Template.prefixFields(template, interpolant, "out", "v2f_"); - template.append(String.format(""" + out vec4 v2f_color; + out vec2 v2f_texCoords; + out vec2 v2f_light; + out float v2f_diffuse; + void main() { Vertex v = FLWCreateVertex(); %s i; @@ -130,26 +109,26 @@ public class InstancingTemplateData implements TemplateData { } """, instanceName, - Template.assignFields(instance, "i.", "a_i_") + assignFields(instance, "i.", "a_i_") )); + + return template.toString(); } - public void fragmentFooter(StringBuilder template, FileIndex shader) { - Template.prefixFields(template, interpolant, "in", "v2f_"); + public static StringBuilder assignFields(ShaderStruct struct, String prefix1, String prefix2) { + ImmutableList fields = struct.getFields(); - template.append(String.format(""" - void main() { - Fragment o; - o.color = v2f_color; - o.texCoords = v2f_texCoords; - o.light = v2f_light; - o.diffuse = v2f_diffuse; + StringBuilder builder = new StringBuilder(); - vec4 color = %s; - FLWFinalizeColor(color); - } - """, - fragmentMain.call("o") - )); + for (StructField field : fields) { + builder.append(prefix1) + .append(field.name) + .append(" = ") + .append(prefix2) + .append(field.name) + .append(";\n"); + } + + return builder; } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/OneShotTemplateData.java b/src/main/java/com/jozufozu/flywheel/core/compile/OneShotTemplateData.java index 49d409faf..21c4eda4d 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/OneShotTemplateData.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/OneShotTemplateData.java @@ -3,54 +3,33 @@ package com.jozufozu.flywheel.core.compile; import java.util.Optional; import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.source.ShaderLoadingException; import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.backend.source.error.ErrorReporter; import com.jozufozu.flywheel.backend.source.parse.ShaderFunction; -import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; import com.jozufozu.flywheel.backend.source.parse.Variable; -import com.jozufozu.flywheel.backend.source.span.Span; -public class OneShotTemplateData implements TemplateData { +public class OneShotTemplateData implements VertexData { public final SourceFile file; public final ShaderFunction vertexMain; - public final Span interpolantName; - public final ShaderStruct interpolant; - public final ShaderFunction fragmentMain; public OneShotTemplateData(SourceFile file) { this.file = file; Optional maybeVertexMain = file.findFunction("vertex"); - Optional maybeFragmentMain = file.findFunction("fragment"); if (maybeVertexMain.isEmpty()) { ErrorReporter.generateFileError(file, "could not find \"vertex\" function"); - } - - if (maybeFragmentMain.isEmpty()) { - ErrorReporter.generateMissingFunction(file, "fragment", "\"fragment\" function not defined"); - } - - if (maybeVertexMain.isEmpty() || maybeFragmentMain.isEmpty()) { throw new RuntimeException(); } vertexMain = maybeVertexMain.get(); - fragmentMain = maybeFragmentMain.get(); - ImmutableList fragmentParameters = fragmentMain.getParameters(); ImmutableList vertexParameters = vertexMain.getParameters(); if (vertexParameters.size() != 1) { ErrorReporter.generateSpanError(vertexMain.getArgs(), "a basic model requires vertex function to have one argument"); - } - - if (fragmentParameters.size() != 1) { - ErrorReporter.generateSpanError(fragmentMain.getArgs(), "fragment function must have exactly one argument"); - } - - if (vertexParameters.size() != 1 || fragmentParameters.size() != 1) { throw new RuntimeException(); } @@ -64,57 +43,30 @@ public class OneShotTemplateData implements TemplateData { ErrorReporter.generateSpanError(vertexParam.qualifierSpan, "first parameter must be inout Vertex"); throw new ShaderLoadingException(); } - - interpolantName = fragmentMain.getParameters().get(0).type; - - Optional maybeInterpolant = file.findStruct(interpolantName); - - if (maybeInterpolant.isEmpty()) { - ErrorReporter.generateMissingStruct(file, interpolantName, "struct not defined"); - - throw new RuntimeException(); - } - - interpolant = maybeInterpolant.get(); } - public void vertexFooter(StringBuilder template, ShaderCompiler file) { - Template.prefixFields(template, interpolant, "out", "v2f_"); + @Override + public String generateFooter(FileIndex file, VertexType vertexType) { + return """ + out vec4 v2f_color; + out vec2 v2f_texCoords; + out vec2 v2f_light; + out float v2f_diffuse; - template.append(""" - void main() { - Vertex v = FLWCreateVertex(); - vertex(v); - gl_Position = FLWVertex(v); - v.normal = normalize(v.normal); - - v2f_color = v.color; - v2f_texCoords = v.texCoords; - v2f_light = v.light; - v2f_diffuse = diffuse(v.normal); - #if defined(DEBUG_NORMAL) - v2f_color = vec4(v.normal, 1.); - #endif - } - """); - } - - public void fragmentFooter(StringBuilder template, FileIndex file) { - Template.prefixFields(template, interpolant, "in", "v2f_"); - - template.append(String.format(""" void main() { - Fragment o; - o.color = v2f_color; - o.texCoords = v2f_texCoords; - o.light = v2f_light; - o.diffuse = v2f_diffuse; + Vertex v = FLWCreateVertex(); + vertex(v); + gl_Position = FLWVertex(v); + v.normal = normalize(v.normal); - vec4 color = %s; - FLWFinalizeColor(color); + v2f_color = v.color; + v2f_texCoords = v.texCoords; + v2f_light = v.light; + v2f_diffuse = diffuse(v.normal); + #if defined(DEBUG_NORMAL) + v2f_color = vec4(v.normal, 1.); + #endif } - """, - fragmentMain.call("o") - )); - } + """; + } } 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 fe0f84423..d08745fcd 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java @@ -2,10 +2,12 @@ package com.jozufozu.flywheel.core.compile; import java.util.HashMap; import java.util.Map; +import java.util.function.Function; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.backend.gl.shader.GlShader; import com.jozufozu.flywheel.backend.source.FileResolution; +import com.jozufozu.flywheel.core.Templates; /** * A caching compiler. @@ -18,15 +20,27 @@ import com.jozufozu.flywheel.backend.source.FileResolution; public class ProgramCompiler

{ protected final Map cache = new HashMap<>(); + private final GlProgram.Factory

factory; + private final Function vertexCompiler; + private final Function fragmentCompiler; - private final Template template; - private final FileResolution header; - - public ProgramCompiler(GlProgram.Factory

factory, Template template, FileResolution header) { + public ProgramCompiler(GlProgram.Factory

factory, Function vertexCompiler, Function fragmentCompiler) { this.factory = factory; - this.template = template; - this.header = header; + this.vertexCompiler = vertexCompiler; + this.fragmentCompiler = fragmentCompiler; + } + + /** + * Creates a program compiler using this template. + * @param template The vertex template to use. + * @param factory A factory to add meaning to compiled programs. + * @param header The header file to use for the program. + * @param

The type of program to compile. + * @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)); } /** @@ -45,11 +59,10 @@ public class ProgramCompiler

{ } private P compile(ProgramContext ctx) { - ShaderCompiler compiler = new ShaderCompiler(ctx, template, header); - return new ProgramAssembler(compiler.name) - .attachShader(compiler.compile(ShaderType.VERTEX)) - .attachShader(compiler.compile(ShaderType.FRAGMENT)) + return new ProgramAssembler(ctx.spec().name) + .attachShader(vertexCompiler.apply(ctx)) + .attachShader(fragmentCompiler.apply(ctx)) .link() .deleteLinkedShaders() .build(this.factory); 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 6b0450ed0..fdb87be5c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramContext.java @@ -1,5 +1,6 @@ package com.jozufozu.flywheel.core.compile; +import java.util.List; import java.util.Objects; import javax.annotation.Nullable; @@ -7,7 +8,6 @@ import javax.annotation.Nullable; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.RenderLayer; -import com.jozufozu.flywheel.backend.source.SourceFile; import com.jozufozu.flywheel.core.shader.ProgramSpec; import net.minecraft.resources.ResourceLocation; @@ -51,8 +51,8 @@ public record ProgramContext(float alphaDiscard, VertexType vertexType, ProgramS return layer == RenderLayer.CUTOUT ? 0.1f : 0f; } - public SourceFile getFile() { - return spec().getSource(); + public List createDefines() { + return spec().getDefines(ctx()); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompiler.java index fb5a3ffd5..a5f3428ea 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompiler.java @@ -1,183 +1,88 @@ package com.jozufozu.flywheel.core.compile; -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nullable; - -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; +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.backend.source.SourceFile; -import com.jozufozu.flywheel.backend.source.error.ErrorBuilder; -import com.jozufozu.flywheel.backend.source.error.ErrorReporter; -import com.jozufozu.flywheel.backend.source.span.Span; -import com.jozufozu.flywheel.core.shader.WorldProgram; - -import net.minecraft.resources.ResourceLocation; +import com.jozufozu.flywheel.core.shader.ProgramSpec; /** * Compiles a shader program. */ -public class ShaderCompiler implements FileIndex { - - /** - * The name of the file responsible for this compilation. - */ - public final ResourceLocation name; - - /** - * The template we'll be using to generate the final source. - */ - public final Template template; - - private final FileResolution header; - - /** - * Extra {@code #define}s to be added to the shader. - */ - private final List defines; - - /** - * Alpha threshold below which pixels are discarded. - */ - private final float alphaDiscard; - - /** - * The vertex type to use. - */ - public final VertexType vertexType; - - /** - * The main file to compile. - */ - public final SourceFile mainFile; - - private final List files = new ArrayList<>(); - - public ShaderCompiler(ProgramContext context, Template template, FileResolution header) { - this.name = context.spec().name; - this.template = template; - this.header = header; - this.mainFile = context.getFile(); - this.defines = context.spec() - .getDefines(context.ctx()); - this.vertexType = context.vertexType(); - this.alphaDiscard = context.alphaDiscard(); - } - - public GlShader compile(ShaderType type) { +public class ShaderCompiler { + public static GlShader compileVertex(ProgramContext context, Template template, FileResolution header) { StringBuilder finalSource = new StringBuilder(); - finalSource.append("#version ") - .append(template.getVersion()) - .append('\n') - .append("#extension GL_ARB_explicit_attrib_location : enable\n") - .append("#extension GL_ARB_conservative_depth : enable\n") - .append(type.getDefineStatement()); // special case shader type declaration + finalSource.append(generateHeader(template.getVersion(), ShaderType.VERTEX)); - if (alphaDiscard > 0) { - finalSource.append("#define ALPHA_DISCARD 0.1\n"); - } - - for (String def : defines) { + for (String def : context.createDefines()) { finalSource.append("#define ") .append(def) .append('\n'); } - if (type == ShaderType.VERTEX) { - finalSource.append(""" - struct Vertex { - vec3 pos; - vec4 color; - vec2 texCoords; - vec2 light; - vec3 normal; - }; - """); - finalSource.append(vertexType.writeShaderHeader()); - } + finalSource.append(""" + struct Vertex { + vec3 pos; + vec4 color; + vec2 texCoords; + vec2 light; + vec3 normal; + }; + """); + finalSource.append(context.vertexType() + .getShaderHeader()); - files.clear(); - header.getFile().generateFinalSource(this, finalSource); - mainFile.generateFinalSource(this, finalSource); + FileIndexImpl index = new FileIndexImpl(); - template.getMetadata(mainFile).generateFooter(finalSource, type, this); + header.getFile() + .generateFinalSource(index, finalSource); + ProgramSpec spec = context.spec(); + spec.getVertexFile() + .generateFinalSource(index, finalSource); - return new GlShader(this, type, finalSource.toString()); + T appliedTemplate = template.apply(spec.getVertexFile()); + finalSource.append(appliedTemplate.generateFooter(index, context.vertexType())); + + return new GlShader(spec.name, ShaderType.VERTEX, finalSource.toString()); } - public

P compile(GlProgram.Factory

worldShaderPipeline) { - return new ProgramAssembler(this.name) - .attachShader(compile(ShaderType.VERTEX)) - .attachShader(compile(ShaderType.FRAGMENT)) - .link() - .deleteLinkedShaders() - .build(worldShaderPipeline); - } + public static GlShader compileFragment(ProgramContext context, Template template, FileResolution header) { - /** - * Returns an arbitrary file ID for use this compilation context, or generates one if missing. - * @param sourceFile The file to retrieve the ID for. - * @return A file ID unique to the given sourceFile. - */ - @Override - public int getFileID(SourceFile sourceFile) { - int i = files.indexOf(sourceFile); - if (i != -1) { - return i; + StringBuilder finalSource = new StringBuilder(); + + finalSource.append(generateHeader(template.getVersion(), ShaderType.FRAGMENT)); + for (String def : context.createDefines()) { + finalSource.append("#define ") + .append(def) + .append('\n'); } - int size = files.size(); - files.add(sourceFile); - return size; - } - - public Span getLineSpan(int fileId, int lineNo) { - SourceFile file = files.get(fileId); - - return file.getLineSpanNoWhitespace(lineNo); - } - - public void printShaderInfoLog(String source, String log, ResourceLocation name) { - List lines = log.lines() - .toList(); - - boolean needsSourceDump = false; - - StringBuilder errors = new StringBuilder(); - for (String line : lines) { - ErrorBuilder builder = parseCompilerError(line); - - if (builder != null) { - errors.append(builder.build()); - } else { - errors.append(line).append('\n'); - needsSourceDump = true; - } - } - Backend.LOGGER.error("Errors compiling '" + name + "': \n" + errors); - if (needsSourceDump) { - // TODO: generated code gets its own "file" - ErrorReporter.printLines(source); - } - } - - @Nullable - private ErrorBuilder parseCompilerError(String line) { - try { - ErrorBuilder error = ErrorBuilder.fromLogLine(this, line); - if (error != null) { - return error; - } - } catch (Exception ignored) { + if (context.alphaDiscard() > 0) { + finalSource.append("#define ALPHA_DISCARD 0.1\n"); } - return null; + + 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/Template.java b/src/main/java/com/jozufozu/flywheel/core/compile/Template.java index 995218b2d..d5eb6a725 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/Template.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/Template.java @@ -4,13 +4,8 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Function; -import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.backend.gl.GLSLVersion; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.backend.source.FileResolution; import com.jozufozu.flywheel.backend.source.SourceFile; -import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; -import com.jozufozu.flywheel.backend.source.parse.StructField; /** * A class that generates glsl glue code given a SourceFile. @@ -20,66 +15,33 @@ import com.jozufozu.flywheel.backend.source.parse.StructField; * metadata to generate shader code that OpenGL can use to call into our shader programs. *

*/ -public class Template { +public class Template { - private final Map metadata = new HashMap<>(); + private final Map metadata = new HashMap<>(); - private final Function reader; + private final Function reader; private final GLSLVersion glslVersion; - public Template(GLSLVersion glslVersion, Function reader) { + public Template(GLSLVersion glslVersion, Function reader) { this.reader = reader; this.glslVersion = glslVersion; } - public TemplateData getMetadata(SourceFile file) { + /** + * Verify that the given SourceFile is valid for this Template and return the metadata. + * @param file The SourceFile to apply this Template to. + * @return The applied template metadata. + */ + public T apply(SourceFile file) { // lazily read files, cache results return metadata.computeIfAbsent(file, reader); } /** - * Creates a program compiler using this template. - * @param factory A factory to add meaning to compiled programs. - * @param header The header file to use for the program. - * @param

The type of program to compile. - * @return A program compiler. + * @return The GLSL version this template requires. */ - public

ProgramCompiler

programCompiler(GlProgram.Factory

factory, FileResolution header) { - return new ProgramCompiler<>(factory, this, header); - } - public GLSLVersion getVersion() { return glslVersion; } - public static void prefixFields(StringBuilder builder, ShaderStruct struct, String qualifier, String prefix) { - ImmutableList fields = struct.getFields(); - - for (StructField field : fields) { - builder.append(qualifier) - .append(' ') - .append(field.type) - .append(' ') - .append(prefix) - .append(field.name) - .append(";\n"); - } - } - - public static StringBuilder assignFields(ShaderStruct struct, String prefix1, String prefix2) { - ImmutableList fields = struct.getFields(); - - StringBuilder builder = new StringBuilder(); - - for (StructField field : fields) { - builder.append(prefix1) - .append(field.name) - .append(" = ") - .append(prefix2) - .append(field.name) - .append(";\n"); - } - - return builder; - } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/TemplateData.java b/src/main/java/com/jozufozu/flywheel/core/compile/TemplateData.java deleted file mode 100644 index 60c68d080..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/compile/TemplateData.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.jozufozu.flywheel.core.compile; - -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; - -public interface TemplateData { - void vertexFooter(StringBuilder builder, ShaderCompiler file); - void fragmentFooter(StringBuilder builder, FileIndex file); - - /** - * Generate the necessary glue code here. - * - * @param builder The builder to generate the source into. - * @param type The shader stage glue code is needed for. - * @param file The SourceFile with user written code. - */ - default void generateFooter(StringBuilder builder, ShaderType type, ShaderCompiler file) { - if (type == ShaderType.VERTEX) { - vertexFooter(builder, file); - } else if (type == ShaderType.FRAGMENT) { - fragmentFooter(builder, file); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/VertexData.java b/src/main/java/com/jozufozu/flywheel/core/compile/VertexData.java new file mode 100644 index 000000000..4865ef0f3 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/compile/VertexData.java @@ -0,0 +1,11 @@ +package com.jozufozu.flywheel.core.compile; + +import com.jozufozu.flywheel.api.vertex.VertexType; + +public interface VertexData { + /** + * Generate the necessary glue code here. + * @param file The SourceFile with user written code. + */ + String generateFooter(FileIndex file, VertexType vertexType); +} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java index 34111f068..bbaca28f1 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java @@ -30,34 +30,47 @@ public class ProgramSpec { // TODO: Block model style inheritance? public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - ResourceLocation.CODEC.fieldOf("source") + ResourceLocation.CODEC.fieldOf("vertex") .forGetter(ProgramSpec::getSourceLoc), + ResourceLocation.CODEC.fieldOf("fragment") + .forGetter(ProgramSpec::getFragmentLoc), ProgramState.CODEC.listOf() .optionalFieldOf("states", Collections.emptyList()) .forGetter(ProgramSpec::getStates)) .apply(instance, ProgramSpec::new)); public ResourceLocation name; - public final FileResolution source; + public final FileResolution vertex; + public final FileResolution fragment; public final ImmutableList states; - public ProgramSpec(ResourceLocation source, List states) { - this.source = Resolver.INSTANCE.get(source); + public ProgramSpec(ResourceLocation vertex, ResourceLocation fragment, List states) { + this.vertex = Resolver.INSTANCE.get(vertex); + this.fragment = Resolver.INSTANCE.get(fragment); this.states = ImmutableList.copyOf(states); } public void setName(ResourceLocation name) { this.name = name; - this.source.addSpec(name); + this.vertex.addSpec(name); + this.fragment.addSpec(name); } public ResourceLocation getSourceLoc() { - return source.getFileLoc(); + return vertex.getFileLoc(); } - public SourceFile getSource() { - return source.getFile(); + public ResourceLocation getFragmentLoc() { + return fragment.getFileLoc(); + } + + public SourceFile getVertexFile() { + return vertex.getFile(); + } + + public SourceFile getFragmentFile() { + return fragment.getFile(); } public ImmutableList getStates() { diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java index 4a4cb1021..e382d0ab7 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java @@ -37,7 +37,7 @@ public class BlockVertex implements VertexType { } @Override - public String writeShaderHeader() { + public String getShaderHeader() { return """ layout (location = 0) in vec3 _flw_v_pos; layout (location = 1) in vec4 _flw_v_color; diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java index 63610ee87..b10139c88 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java @@ -28,7 +28,7 @@ public class PosTexNormalVertex implements VertexType { } @Override - public String writeShaderHeader() { + public String getShaderHeader() { return """ layout (location = 0) in vec3 _flw_v_pos; layout (location = 1) in vec2 _flw_v_texCoords; diff --git a/src/main/resources/assets/flywheel/flywheel/programs/model.json b/src/main/resources/assets/flywheel/flywheel/programs/model.json index 921a6e093..d6c2b6d73 100644 --- a/src/main/resources/assets/flywheel/flywheel/programs/model.json +++ b/src/main/resources/assets/flywheel/flywheel/programs/model.json @@ -1,5 +1,6 @@ { - "source": "flywheel:model.vert", + "vertex": "flywheel:model.vert", + "fragment": "flywheel:block.frag", "states": [ { "when": "flywheel:normal_debug", diff --git a/src/main/resources/assets/flywheel/flywheel/programs/oriented.json b/src/main/resources/assets/flywheel/flywheel/programs/oriented.json index 9f0709ebf..33ebc3291 100644 --- a/src/main/resources/assets/flywheel/flywheel/programs/oriented.json +++ b/src/main/resources/assets/flywheel/flywheel/programs/oriented.json @@ -1,5 +1,6 @@ { - "source": "flywheel:oriented.vert", + "vertex": "flywheel:oriented.vert", + "fragment": "flywheel:block.frag", "states": [ { "when": "flywheel:normal_debug", diff --git a/src/main/resources/assets/flywheel/flywheel/programs/passthru.json b/src/main/resources/assets/flywheel/flywheel/programs/passthru.json index bdb8aabff..5934f447c 100644 --- a/src/main/resources/assets/flywheel/flywheel/programs/passthru.json +++ b/src/main/resources/assets/flywheel/flywheel/programs/passthru.json @@ -1,5 +1,6 @@ { - "source": "flywheel:passthru.vert", + "vertex": "flywheel:passthru.vert", + "fragment": "flywheel:block.frag", "states": [ { "when": "flywheel:normal_debug", diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/block.frag b/src/main/resources/assets/flywheel/flywheel/shaders/block.frag index 70bbe95f4..366d2cc63 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/block.frag +++ b/src/main/resources/assets/flywheel/flywheel/shaders/block.frag @@ -6,10 +6,8 @@ struct Fragment { vec2 light; }; -#if defined(FRAGMENT_SHADER) vec4 fragment(Fragment r) { vec4 tex = FLWBlockTexture(r.texCoords); return vec4(tex.rgb * FLWLight(r.light).rgb * r.diffuse, tex.a) * r.color; } -#endif diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/model.vert b/src/main/resources/assets/flywheel/flywheel/shaders/model.vert index 075269708..0feeb9a1b 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/model.vert +++ b/src/main/resources/assets/flywheel/flywheel/shaders/model.vert @@ -1,6 +1,3 @@ -#use "flywheel:block.frag" - -#if defined(VERTEX_SHADER) struct Instance { vec2 light; @@ -15,4 +12,3 @@ void vertex(inout Vertex v, Instance i) { v.color = i.color; v.light = i.light; } -#endif diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/oriented.vert b/src/main/resources/assets/flywheel/flywheel/shaders/oriented.vert index b89479a8b..8478e8b4a 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/oriented.vert +++ b/src/main/resources/assets/flywheel/flywheel/shaders/oriented.vert @@ -1,6 +1,3 @@ -#use "flywheel:block.frag" - -#if defined(VERTEX_SHADER) #use "flywheel:core/quaternion.glsl" struct Oriented { @@ -17,4 +14,3 @@ void vertex(inout Vertex v, Oriented o) { v.color = o.color; v.light = o.light; } -#endif diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/passthru.vert b/src/main/resources/assets/flywheel/flywheel/shaders/passthru.vert index a598d8ebd..a7642d2ab 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/passthru.vert +++ b/src/main/resources/assets/flywheel/flywheel/shaders/passthru.vert @@ -1,7 +1,4 @@ -#use "flywheel:block.frag" -#if defined(VERTEX_SHADER) void vertex(inout Vertex v) { } -#endif From 7d4055f263d05ac999f3da339f72217494775564 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Tue, 11 Jan 2022 13:17:55 -0800 Subject: [PATCH 07/10] More organized shader compilation --- .../com/jozufozu/flywheel/FlywheelClient.java | 5 ++ .../flywheel/backend/RenderLayer.java | 15 +++- .../instancing/instancing/GPUInstancer.java | 8 +- .../flywheel/backend/struct/BufferWriter.java | 2 +- .../flywheel/core/compile/CompileUtil.java | 16 ++++ .../core/compile/FragmentCompiler.java | 44 ++++++++++ .../flywheel/core/compile/Memoizer.java | 22 +++++ .../core/compile/ProgramCompiler.java | 45 ++++++---- .../flywheel/core/compile/ProgramContext.java | 30 ++++--- .../flywheel/core/compile/ShaderCompiler.java | 88 ------------------- .../core/compile/ShaderConstants.java | 51 +++++++++++ .../flywheel/core/compile/VertexCompiler.java | 56 ++++++++++++ .../flywheel/event/RenderLayerEvent.java | 2 +- 13 files changed, 262 insertions(+), 122 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/Memoizer.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompiler.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/ShaderConstants.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java 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 From a62bc660607bfd7adcfe05767914135507ad1db4 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Wed, 12 Jan 2022 00:19:37 -0800 Subject: [PATCH 08/10] Better memoized shader compilation and global game state - Properly separate compilation of vertex and fragment shaders - Game state is no longer per-program - Needs organization --- .../flywheel/backend/GameStateRegistry.java | 26 +++++++ .../flywheel/backend/source/SourceFile.java | 4 ++ .../core/compile/FragmentCompiler.java | 54 ++++++++++++-- .../core/compile/ProgramCompiler.java | 6 +- .../flywheel/core/compile/ProgramContext.java | 72 ++++++++++--------- .../flywheel/core/compile/VertexCompiler.java | 49 +++++++++---- .../core/shader/GameStateProvider.java | 7 +- .../core/shader/NormalDebugStateProvider.java | 6 ++ .../flywheel/core/shader/ProgramSpec.java | 50 ++----------- .../flywheel/core/shader/ProgramState.java | 17 ----- .../flywheel/core/shader/StateSnapshot.java | 12 ++++ .../flywheel/flywheel/programs/model.json | 8 +-- .../flywheel/flywheel/programs/oriented.json | 8 +-- .../flywheel/flywheel/programs/passthru.json | 8 +-- 14 files changed, 187 insertions(+), 140 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/ProgramState.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java diff --git a/src/main/java/com/jozufozu/flywheel/backend/GameStateRegistry.java b/src/main/java/com/jozufozu/flywheel/backend/GameStateRegistry.java index e0aa48885..2bdd425c0 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/GameStateRegistry.java +++ b/src/main/java/com/jozufozu/flywheel/backend/GameStateRegistry.java @@ -3,7 +3,9 @@ package com.jozufozu.flywheel.backend; import java.util.HashMap; import java.util.Map; +import com.jozufozu.flywheel.core.compile.ShaderConstants; import com.jozufozu.flywheel.core.shader.GameStateProvider; +import com.jozufozu.flywheel.core.shader.StateSnapshot; import net.minecraft.resources.ResourceLocation; @@ -32,4 +34,28 @@ public class GameStateRegistry { registeredStateProviders.put(context.getID(), context); } + + public static StateSnapshot takeSnapshot() { + long ctx = 0; + for (GameStateProvider state : registeredStateProviders.values()) { + if (state.isTrue()) { + ctx |= 1; + } + ctx <<= 1; + } + return new StateSnapshot(ctx); + } + + public static ShaderConstants getDefines(long ctx) { + long stateID = ctx; + ShaderConstants shaderConstants = new ShaderConstants(); + + for (GameStateProvider state : registeredStateProviders.values()) { + if ((stateID & 1) == 1) { + state.alterConstants(shaderConstants); + } + stateID >>= 1; + } + return shaderConstants; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java index e69653336..6f4b04e87 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java @@ -268,4 +268,8 @@ public class SourceFile { return -1; } + @Override + public String toString() { + return name.toString(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java index 80d8b2229..3eaf09a42 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java @@ -1,12 +1,14 @@ package com.jozufozu.flywheel.core.compile; +import java.util.Objects; + 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; +import com.jozufozu.flywheel.core.shader.StateSnapshot; -public class FragmentCompiler extends Memoizer { +public class FragmentCompiler extends Memoizer { private final FileResolution header; private final Template fragment; @@ -16,9 +18,8 @@ public class FragmentCompiler extends Memoizer { } @Override - protected GlShader _create(ProgramContext key) { - ProgramSpec spec = key.spec(); - SourceFile fragmentFile = spec.getFragmentFile(); + protected GlShader _create(Context key) { + SourceFile fragmentFile = key.file; FragmentTemplateData appliedTemplate = fragment.apply(fragmentFile); StringBuilder builder = new StringBuilder(); @@ -34,11 +35,52 @@ public class FragmentCompiler extends Memoizer { builder.append(appliedTemplate.generateFooter()); - return new GlShader(spec.name, ShaderType.FRAGMENT, builder.toString()); + return new GlShader(fragmentFile.name, ShaderType.FRAGMENT, builder.toString()); } @Override protected void _destroy(GlShader value) { value.delete(); } + + public static final class Context { + private final SourceFile file; + private final StateSnapshot ctx; + private final float alphaDiscard; + + public Context(SourceFile file, StateSnapshot ctx, float alphaDiscard) { + this.file = file; + this.ctx = ctx; + this.alphaDiscard = alphaDiscard; + } + + public ShaderConstants getShaderConstants() { + ShaderConstants shaderConstants = ctx.getDefines(); + + if (alphaDiscard > 0) { + shaderConstants.define("ALPHA_DISCARD", alphaDiscard); + } + + return shaderConstants; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (Context) obj; + return this.file == that.file && Objects.equals(this.ctx, that.ctx) && Float.floatToIntBits(this.alphaDiscard) == Float.floatToIntBits(that.alphaDiscard); + } + + @Override + public int hashCode() { + return Objects.hash(file, ctx, alphaDiscard); + } + + @Override + public String toString() { + return "Context[" + "file=" + file + ", " + "ctx=" + ctx + ", " + "alphaDiscard=" + alphaDiscard + ']'; + } + + } } 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 cce67bd8d..0be2aa56b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java @@ -62,9 +62,9 @@ public class ProgramCompiler

extends Memoizer 0) { - shaderConstants.define("ALPHA_DISCARD", alphaDiscard); - } - - return shaderConstants; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ProgramContext that = (ProgramContext) o; - // override for instance equality on vertexType - return alphaDiscard == that.alphaDiscard && ctx == that.ctx && vertexType == that.vertexType && spec.equals(that.spec); - } - - @Override - public int hashCode() { - return Objects.hash(alphaDiscard, vertexType, spec, ctx); + return new ProgramContext(spec, getAlphaDiscard(layer), vertexType, GameStateRegistry.takeSnapshot()); } /** @@ -74,4 +46,40 @@ public record ProgramContext(float alphaDiscard, VertexType vertexType, ProgramS public static float getAlphaDiscard(@Nullable RenderLayer layer) { return layer == RenderLayer.CUTOUT ? 0.1f : 0f; } + + public final ProgramSpec spec; + public final float alphaDiscard; + public final VertexType vertexType; + public final StateSnapshot ctx; + + /** + * @param spec The program to use. + * @param alphaDiscard Alpha threshold below which pixels are discarded. + * @param vertexType The vertexType the program should be adapted for. + * @param ctx A snapshot of the game state. + */ + public ProgramContext(ProgramSpec spec, float alphaDiscard, VertexType vertexType, StateSnapshot ctx) { + this.spec = spec; + this.alphaDiscard = alphaDiscard; + this.vertexType = vertexType; + this.ctx = ctx; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + var that = (ProgramContext) o; + return spec == that.spec && vertexType == that.vertexType && ctx.equals(that.ctx) && Float.floatToIntBits(alphaDiscard) == Float.floatToIntBits(that.alphaDiscard); + } + + @Override + public int hashCode() { + return Objects.hash(spec, alphaDiscard, vertexType, ctx); + } + + @Override + public String toString() { + return "ProgramContext{" + "spec=" + spec + ", alphaDiscard=" + alphaDiscard + ", vertexType=" + vertexType + ", ctx=" + ctx + '}'; + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java index 1e0e6c925..2de890fdb 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java @@ -1,12 +1,15 @@ package com.jozufozu.flywheel.core.compile; +import java.util.Objects; + +import com.jozufozu.flywheel.api.vertex.VertexType; 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; +import com.jozufozu.flywheel.core.shader.StateSnapshot; -public class VertexCompiler extends Memoizer { +public class VertexCompiler extends Memoizer { private final Template template; private final FileResolution header; @@ -16,12 +19,12 @@ public class VertexCompiler extends Memoizer { } @Override - protected GlShader _create(ProgramContext key) { + protected GlShader _create(Context key) { StringBuilder finalSource = new StringBuilder(); finalSource.append(CompileUtil.generateHeader(template.getVersion(), ShaderType.VERTEX)); - key.getShaderConstants().writeInto(finalSource); + key.ctx.getDefines().writeInto(finalSource); finalSource.append(""" struct Vertex { @@ -32,25 +35,47 @@ public class VertexCompiler extends Memoizer { vec3 normal; }; """); - finalSource.append(key.vertexType() - .getShaderHeader()); + 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); + key.file.generateFinalSource(index, finalSource); - VertexData appliedTemplate = template.apply(vertexFile); - finalSource.append(appliedTemplate.generateFooter(index, key.vertexType())); + VertexData appliedTemplate = template.apply(key.file); + finalSource.append(appliedTemplate.generateFooter(index, key.vertexType)); - return new GlShader(spec.name, ShaderType.VERTEX, finalSource.toString()); + return new GlShader(key.file.name, ShaderType.VERTEX, finalSource.toString()); } @Override protected void _destroy(GlShader value) { value.delete(); } + + public static class Context { + private final SourceFile file; + private final StateSnapshot ctx; + private final VertexType vertexType; + + public Context(SourceFile file, StateSnapshot ctx, VertexType vertexType) { + this.file = file; + this.ctx = ctx; + this.vertexType = vertexType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + var that = (Context) o; + return file == that.file && vertexType == that.vertexType && ctx.equals(that.ctx); + } + + @Override + public int hashCode() { + return Objects.hash(file, ctx, vertexType); + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java index fc9fe728d..9bf698ac9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java @@ -1,15 +1,14 @@ package com.jozufozu.flywheel.core.shader; -import com.jozufozu.flywheel.backend.GameStateRegistry; -import com.mojang.serialization.Codec; +import com.jozufozu.flywheel.core.compile.ShaderConstants; import net.minecraft.resources.ResourceLocation; public interface GameStateProvider { - Codec CODEC = ResourceLocation.CODEC.xmap(GameStateRegistry::getStateProvider, GameStateProvider::getID); - ResourceLocation getID(); boolean isTrue(); + + void alterConstants(ShaderConstants constants); } diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java index 61f0e50ac..b8a340448 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.core.shader; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.config.FlwConfig; +import com.jozufozu.flywheel.core.compile.ShaderConstants; import net.minecraft.resources.ResourceLocation; @@ -24,4 +25,9 @@ public class NormalDebugStateProvider implements GameStateProvider { public ResourceLocation getID() { return NAME; } + + @Override + public void alterConstants(ShaderConstants constants) { + constants.define("DEBUG_NORMAL"); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java index bbaca28f1..fb03631f2 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java @@ -1,10 +1,5 @@ package com.jozufozu.flywheel.core.shader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.backend.source.FileResolution; import com.jozufozu.flywheel.backend.source.Resolver; import com.jozufozu.flywheel.backend.source.SourceFile; @@ -28,27 +23,20 @@ import net.minecraft.resources.ResourceLocation; */ public class ProgramSpec { - // TODO: Block model style inheritance? public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( ResourceLocation.CODEC.fieldOf("vertex") .forGetter(ProgramSpec::getSourceLoc), ResourceLocation.CODEC.fieldOf("fragment") - .forGetter(ProgramSpec::getFragmentLoc), - ProgramState.CODEC.listOf() - .optionalFieldOf("states", Collections.emptyList()) - .forGetter(ProgramSpec::getStates)) + .forGetter(ProgramSpec::getFragmentLoc)) .apply(instance, ProgramSpec::new)); public ResourceLocation name; public final FileResolution vertex; public final FileResolution fragment; - public final ImmutableList states; - - public ProgramSpec(ResourceLocation vertex, ResourceLocation fragment, List states) { + public ProgramSpec(ResourceLocation vertex, ResourceLocation fragment) { this.vertex = Resolver.INSTANCE.get(vertex); this.fragment = Resolver.INSTANCE.get(fragment); - this.states = ImmutableList.copyOf(states); } public void setName(ResourceLocation name) { @@ -73,36 +61,8 @@ public class ProgramSpec { return fragment.getFile(); } - public ImmutableList getStates() { - return states; - } - - /** - * Calculate a unique ID representing the current game state. - */ - public long getCurrentStateID() { - long ctx = 0; - for (ProgramState state : states) { - if (state.context().isTrue()) { - ctx |= 1; - } - ctx <<= 1; - } - return ctx; - } - - /** - * Given the stateID, get a list of defines to include at the top of a compiling program. - */ - public List getDefines(long stateID) { - List defines = new ArrayList<>(); - - for (ProgramState state : states) { - if ((stateID & 1) == 1) { - defines.addAll(state.defines()); - } - stateID >>= 1; - } - return defines; + @Override + public String toString() { + return name.toString(); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/ProgramState.java b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramState.java deleted file mode 100644 index ae8d00248..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/shader/ProgramState.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.jozufozu.flywheel.core.shader; - -import java.util.Collections; -import java.util.List; - -import com.jozufozu.flywheel.util.CodecUtil; -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; - -public record ProgramState(GameStateProvider context, List defines) { - - public static final Codec CODEC = RecordCodecBuilder.create(state -> state.group(GameStateProvider.CODEC.fieldOf("when") - .forGetter(ProgramState::context), CodecUtil.oneOrMore(Codec.STRING) - .optionalFieldOf("define", Collections.emptyList()) - .forGetter(ProgramState::defines)) - .apply(state, ProgramState::new)); -} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java b/src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java new file mode 100644 index 000000000..e11b7c0f2 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java @@ -0,0 +1,12 @@ +package com.jozufozu.flywheel.core.shader; + +import com.jozufozu.flywheel.backend.GameStateRegistry; +import com.jozufozu.flywheel.core.compile.ShaderConstants; + +public record StateSnapshot(long ctx) { + // TODO: is this needed? + + public ShaderConstants getDefines() { + return GameStateRegistry.getDefines(ctx); + } +} diff --git a/src/main/resources/assets/flywheel/flywheel/programs/model.json b/src/main/resources/assets/flywheel/flywheel/programs/model.json index d6c2b6d73..dbee0ddd4 100644 --- a/src/main/resources/assets/flywheel/flywheel/programs/model.json +++ b/src/main/resources/assets/flywheel/flywheel/programs/model.json @@ -1,10 +1,4 @@ { "vertex": "flywheel:model.vert", - "fragment": "flywheel:block.frag", - "states": [ - { - "when": "flywheel:normal_debug", - "define": "DEBUG_NORMAL" - } - ] + "fragment": "flywheel:block.frag" } diff --git a/src/main/resources/assets/flywheel/flywheel/programs/oriented.json b/src/main/resources/assets/flywheel/flywheel/programs/oriented.json index 33ebc3291..f012f819b 100644 --- a/src/main/resources/assets/flywheel/flywheel/programs/oriented.json +++ b/src/main/resources/assets/flywheel/flywheel/programs/oriented.json @@ -1,10 +1,4 @@ { "vertex": "flywheel:oriented.vert", - "fragment": "flywheel:block.frag", - "states": [ - { - "when": "flywheel:normal_debug", - "define": "DEBUG_NORMAL" - } - ] + "fragment": "flywheel:block.frag" } diff --git a/src/main/resources/assets/flywheel/flywheel/programs/passthru.json b/src/main/resources/assets/flywheel/flywheel/programs/passthru.json index 5934f447c..9e180f2de 100644 --- a/src/main/resources/assets/flywheel/flywheel/programs/passthru.json +++ b/src/main/resources/assets/flywheel/flywheel/programs/passthru.json @@ -1,10 +1,4 @@ { "vertex": "flywheel:passthru.vert", - "fragment": "flywheel:block.frag", - "states": [ - { - "when": "flywheel:normal_debug", - "define": "DEBUG_NORMAL" - } - ] + "fragment": "flywheel:block.frag" } From 298ca3e9f187cabdcd3a9eec04bb44a1d36843f8 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Wed, 12 Jan 2022 21:25:03 -0800 Subject: [PATCH 09/10] Reorganize and simplify - StructTypes no longer need to be registered - Move backend.source to core.source - Move GameStateRegistry to core - Backend is static again - Loader maintains state internally --- .../com/jozufozu/flywheel/FlywheelClient.java | 7 +- .../jozufozu/flywheel/backend/Backend.java | 98 ++++--------------- .../com/jozufozu/flywheel/backend/Loader.java | 39 ++++++-- .../flywheel/backend/gl/buffer/GlBuffer.java | 2 +- .../backend/gl/buffer/PersistentGlBuffer.java | 2 +- .../flywheel/backend/gl/shader/GlShader.java | 2 +- .../backend/gl/versioned/GlCompat.java | 5 +- .../backend/instancing/InstanceWorld.java | 3 +- .../instancing/instancing/GPUInstancer.java | 2 +- .../instancing/InstancedMaterialGroup.java | 2 +- .../com/jozufozu/flywheel/core/Contexts.java | 5 +- .../{backend => core}/GameStateRegistry.java | 6 +- .../com/jozufozu/flywheel/core/Materials.java | 8 -- .../flywheel/core/compile/CompileUtil.java | 33 +++++++ .../core/compile/FragmentCompiler.java | 20 +++- .../core/compile/FragmentTemplateData.java | 14 +-- .../core/compile/InstancingTemplateData.java | 19 ++-- .../core/compile/OneShotTemplateData.java | 11 ++- .../core/compile/ProgramCompiler.java | 2 +- .../flywheel/core/compile/ProgramContext.java | 6 +- .../flywheel/core/compile/Template.java | 19 ++-- .../flywheel/core/compile/TypeHelper.java | 37 ------- .../flywheel/core/compile/VertexCompiler.java | 16 ++- .../flywheel/core/compile/VertexData.java | 1 + .../core/shader/ExtensionInstance.java | 13 --- .../core/shader/GameStateProvider.java | 2 - .../core/shader/NormalDebugStateProvider.java | 1 - .../flywheel/core/shader/ProgramSpec.java | 6 +- .../{compile => shader}/ShaderConstants.java | 8 +- .../flywheel/core/shader/StateSnapshot.java | 3 +- .../flywheel/core/shader/WorldFog.java | 13 +-- .../core/{compile => source}/FileIndex.java | 5 +- .../{compile => source}/FileIndexImpl.java | 7 +- .../source/FileResolution.java | 6 +- .../{backend => core}/source/Index.java | 6 +- .../{backend => core}/source/Resolver.java | 2 +- .../source/ShaderLoadingException.java | 2 +- .../source/ShaderSources.java | 2 +- .../{backend => core}/source/SourceFile.java | 15 ++- .../source/SourceFinder.java | 2 +- .../{backend => core}/source/SourceLines.java | 4 +- .../source/error/ErrorBuilder.java | 22 ++--- .../source/error/ErrorLevel.java | 2 +- .../source/error/ErrorReporter.java | 10 +- .../source/error/lines/Divider.java | 2 +- .../source/error/lines/ErrorLine.java | 2 +- .../source/error/lines/FileLine.java | 2 +- .../source/error/lines/HeaderLine.java | 2 +- .../source/error/lines/SourceLine.java | 2 +- .../source/error/lines/SpanHighlightLine.java | 2 +- .../source/error/lines/TextLine.java | 2 +- .../source/error}/package-info.java | 2 +- .../source/package-info.java | 2 +- .../source/parse/AbstractShaderElement.java | 4 +- .../source/parse/Import.java | 12 +-- .../source/parse/ShaderFunction.java | 4 +- .../source/parse/ShaderStruct.java | 4 +- .../source/parse/StructField.java | 4 +- .../source/parse/Variable.java | 4 +- .../source/parse/package-info.java | 2 +- .../source/span/CharPos.java | 2 +- .../source/span/ErrorSpan.java | 4 +- .../{backend => core}/source/span/Span.java | 4 +- .../source/span/StringSpan.java | 4 +- .../source/span}/package-info.java | 2 +- .../jozufozu/flywheel/event/ForgeEvents.java | 3 +- .../flywheel/event/GatherContextEvent.java | 10 +- .../flywheel/mixin/LevelRendererMixin.java | 3 +- 68 files changed, 257 insertions(+), 317 deletions(-) rename src/main/java/com/jozufozu/flywheel/{backend => core}/GameStateRegistry.java (92%) delete mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/TypeHelper.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/shader/ExtensionInstance.java rename src/main/java/com/jozufozu/flywheel/core/{compile => shader}/ShaderConstants.java (86%) rename src/main/java/com/jozufozu/flywheel/core/{compile => source}/FileIndex.java (73%) rename src/main/java/com/jozufozu/flywheel/core/{compile => source}/FileIndexImpl.java (87%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/FileResolution.java (93%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/Index.java (85%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/Resolver.java (97%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/ShaderLoadingException.java (79%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/ShaderSources.java (97%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/SourceFile.java (93%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/SourceFinder.java (84%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/SourceLines.java (95%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/error/ErrorBuilder.java (82%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/error/ErrorLevel.java (80%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/error/ErrorReporter.java (89%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/error/lines/Divider.java (75%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/error/lines/ErrorLine.java (83%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/error/lines/FileLine.java (80%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/error/lines/HeaderLine.java (78%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/error/lines/SourceLine.java (84%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/error/lines/SpanHighlightLine.java (88%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/error/lines/TextLine.java (66%) rename src/main/java/com/jozufozu/flywheel/{backend/source/span => core/source/error}/package-info.java (77%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/package-info.java (78%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/parse/AbstractShaderElement.java (57%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/parse/Import.java (76%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/parse/ShaderFunction.java (94%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/parse/ShaderStruct.java (93%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/parse/StructField.java (82%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/parse/Variable.java (87%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/parse/package-info.java (76%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/span/CharPos.java (63%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/span/ErrorSpan.java (85%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/span/Span.java (95%) rename src/main/java/com/jozufozu/flywheel/{backend => core}/source/span/StringSpan.java (82%) rename src/main/java/com/jozufozu/flywheel/{backend/source/error => core/source/span}/package-info.java (76%) diff --git a/src/main/java/com/jozufozu/flywheel/FlywheelClient.java b/src/main/java/com/jozufozu/flywheel/FlywheelClient.java index 9846813f7..4b74ab5ce 100644 --- a/src/main/java/com/jozufozu/flywheel/FlywheelClient.java +++ b/src/main/java/com/jozufozu/flywheel/FlywheelClient.java @@ -1,8 +1,8 @@ package com.jozufozu.flywheel; import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.OptifineHandler; 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; @@ -18,15 +18,14 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; public class FlywheelClient { public static void clientInit() { - CrashReportCallables.registerCrashCallable("Flywheel Backend", () -> - Backend.getInstance().getBackendDescriptor()); + CrashReportCallables.registerCrashCallable("Flywheel Backend", Backend::getBackendDescriptor); + OptifineHandler.init(); Backend.init(); IEventBus modEventBus = FMLJavaModLoadingContext.get() .getModEventBus(); modEventBus.addListener(Contexts::flwInit); - modEventBus.addListener(Materials::flwInit); modEventBus.addListener(PartialModel::onModelRegistry); modEventBus.addListener(PartialModel::onModelBake); modEventBus.addListener(StitchedSprite::onTextureStitchPre); diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index b4f94e0af..b8cd61e82 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -1,19 +1,11 @@ package com.jozufozu.flywheel.backend; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - import javax.annotation.Nullable; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.lwjgl.opengl.GL; -import org.lwjgl.opengl.GLCapabilities; import com.jozufozu.flywheel.api.FlywheelWorld; -import com.jozufozu.flywheel.api.InstanceData; -import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.config.FlwEngine; @@ -27,89 +19,39 @@ import net.minecraft.world.level.LevelAccessor; public class Backend { public static final Logger LOGGER = LogManager.getLogger(Backend.class); - protected static final Backend INSTANCE = new Backend(); - public static Backend getInstance() { - return INSTANCE; - } + private static FlwEngine engine; - private FlwEngine engine; + public static GlCompat compat; - public GLCapabilities capabilities; - public GlCompat compat; - - public final Loader loader; - private final Map> materialRegistry = new HashMap<>(); - private final Map programSpecRegistry = new HashMap<>(); - - protected Backend() { - loader = new Loader(this); - - OptifineHandler.init(); - } + private static final Loader loader = new Loader(); /** * Get a string describing the Flywheel backend. When there are eventually multiple backends * (Meshlet, MDI, GL31 Draw Instanced are planned), this will name which one is in use. */ - public String getBackendDescriptor() { + public static String getBackendDescriptor() { return engine == null ? "" : engine.getProperName(); } - public FlwEngine getEngine() { + public static FlwEngine getEngine() { return engine; } - /** - * Register a shader program. - */ - public ProgramSpec register(ProgramSpec spec) { - ResourceLocation name = spec.name; - if (programSpecRegistry.containsKey(name)) { - throw new IllegalStateException("Program spec '" + name + "' already registered."); - } - programSpecRegistry.put(name, spec); - return spec; - } - - /** - * Register an instancing material. - */ - public StructType register(ResourceLocation name, StructType spec) { - if (materialRegistry.containsKey(name)) { - throw new IllegalStateException("Material spec '" + name + "' already registered."); - } - materialRegistry.put(name, spec); - - LOGGER.debug("registered material '" + name + "' with instance size " + spec.getLayout().getStride()); - - return spec; - } - @Nullable - public ProgramSpec getSpec(ResourceLocation name) { - return programSpecRegistry.get(name); + public static ProgramSpec getSpec(ResourceLocation name) { + return loader.get(name); } - public void refresh() { + public static void refresh() { OptifineHandler.refresh(); - capabilities = GL.createCapabilities(); - - compat = new GlCompat(capabilities); + compat = new GlCompat(); engine = chooseEngine(compat); } - public Collection> allMaterials() { - return materialRegistry.values(); - } - - public Collection allPrograms() { - return programSpecRegistry.values(); - } - public static boolean isOn() { - return getInstance().engine != FlwEngine.OFF; + return engine != FlwEngine.OFF; } public static boolean canUseInstancing(@Nullable Level world) { @@ -137,18 +79,6 @@ public class Backend { RenderWork.enqueue(Minecraft.getInstance().levelRenderer::allChanged); } - /** - * INTERNAL USE ONLY - */ - void _clearContexts() { - GameStateRegistry.clear(); - programSpecRegistry.clear(); - materialRegistry.clear(); - } - - public static void init() { - } - private static FlwEngine chooseEngine(GlCompat compat) { FlwEngine preferredChoice = FlwConfig.get() .getEngine(); @@ -162,4 +92,12 @@ public class Backend { return canUseEngine ? preferredChoice : FlwEngine.OFF; } + + public static void init() { + // noop + } + + private Backend() { + throw new UnsupportedOperationException("Backend is a static class!"); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 49d9a5fab..9f0f9b43c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -1,15 +1,20 @@ package com.jozufozu.flywheel.backend; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Nullable; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.jozufozu.flywheel.backend.source.Resolver; -import com.jozufozu.flywheel.backend.source.ShaderSources; +import com.jozufozu.flywheel.core.GameStateRegistry; import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer; import com.jozufozu.flywheel.core.shader.ProgramSpec; +import com.jozufozu.flywheel.core.source.Resolver; +import com.jozufozu.flywheel.core.source.ShaderSources; import com.jozufozu.flywheel.event.GatherContextEvent; import com.jozufozu.flywheel.util.ResourceUtil; import com.jozufozu.flywheel.util.StringUtil; @@ -37,13 +42,11 @@ public class Loader implements ResourceManagerReloadListener { public static final String PROGRAM_DIR = "flywheel/programs/"; private static final Gson GSON = new GsonBuilder().create(); - private final Backend backend; + private final Map programSpecRegistry = new HashMap<>(); private boolean firstLoad = true; - public Loader(Backend backend) { - this.backend = backend; - + Loader() { // Can be null when running datagenerators due to the unfortunate time we call this Minecraft minecraft = Minecraft.getInstance(); if (minecraft != null) { @@ -54,15 +57,20 @@ public class Loader implements ResourceManagerReloadListener { } } + @Nullable + public ProgramSpec get(ResourceLocation name) { + return programSpecRegistry.get(name); + } + @Override public void onResourceManagerReload(ResourceManager manager) { - backend.refresh(); + Backend.refresh(); - backend._clearContexts(); + GameStateRegistry._clear(); Resolver.INSTANCE.invalidate(); ModLoader.get() - .postEvent(new GatherContextEvent(backend, firstLoad)); + .postEvent(new GatherContextEvent(firstLoad)); ShaderSources sources = new ShaderSources(manager); @@ -101,10 +109,21 @@ public class Loader implements ResourceManagerReloadListener { spec.setName(specName); - backend.register(spec); + register(spec); } catch (Exception e) { Backend.LOGGER.error(e); } } } + + /** + * Register a shader program. + */ + private void register(ProgramSpec spec) { + ResourceLocation name = spec.name; + if (programSpecRegistry.containsKey(name)) { + throw new IllegalStateException("Program spec '" + name + "' already registered."); + } + programSpecRegistry.put(name, spec); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java index 2c2e31e25..346db8814 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java @@ -21,7 +21,7 @@ public abstract class GlBuffer extends GlObject { * @return A buffer that will be persistent if the driver supports it. */ public static GlBuffer requestPersistent(GlBufferType type) { - if (Backend.getInstance().compat.bufferStorageSupported()) { + if (Backend.compat.bufferStorageSupported()) { return new PersistentGlBuffer(type); } else { return new MappedGlBuffer(type); diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java index fb783dc4f..6c4b474cd 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java @@ -46,7 +46,7 @@ public class PersistentGlBuffer extends GlBuffer implements Mappable { fence.clear(); - Backend.getInstance().compat.bufferStorage.bufferStorage(type, size, flags); + Backend.compat.bufferStorage.bufferStorage(type, size, flags); ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, 0, size, flags); diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java index 575e43c42..7148e134e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlShader.java @@ -4,7 +4,7 @@ import org.lwjgl.opengl.GL20; import com.jozufozu.flywheel.backend.gl.GlObject; import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; -import com.jozufozu.flywheel.backend.source.ShaderLoadingException; +import com.jozufozu.flywheel.core.source.ShaderLoadingException; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java index c44355940..0d550124f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java @@ -4,6 +4,7 @@ import java.nio.ByteBuffer; import java.util.Arrays; import org.lwjgl.PointerBuffer; +import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL20C; import org.lwjgl.opengl.GLCapabilities; import org.lwjgl.system.MemoryStack; @@ -23,11 +24,11 @@ public class GlCompat { public final BufferStorage bufferStorage; public final boolean amd; - public GlCompat(GLCapabilities caps) { + public GlCompat() { + GLCapabilities caps = GL.createCapabilities(); instancedArrays = getLatest(InstancedArrays.class, caps); bufferStorage = getLatest(BufferStorage.class, caps); - if (Util.getPlatform() == Util.OS.WINDOWS) { String vendor = GL20C.glGetString(GL20C.GL_VENDOR); // vendor string I got was "ATI Technologies Inc." diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java index 8274a2e06..387c1c1c4 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java @@ -39,8 +39,7 @@ public class InstanceWorld { this.taskEngine = new ParallelTaskEngine("Flywheel " + world.dimension().location()); this.taskEngine.startWorkers(); - FlwEngine engine = Backend.getInstance() - .getEngine(); + FlwEngine engine = Backend.getEngine(); switch (engine) { case INSTANCING -> { 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 8705da724..ffac02ae3 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 @@ -198,7 +198,7 @@ public class GPUInstancer extends AbstractInstancer { vao.bindAttributes(attributeBaseIndex, instanceFormat); for (int i = 0; i < instanceFormat.getAttributeCount(); i++) { - Backend.getInstance().compat.instancedArrays.vertexAttribDivisor(attributeBaseIndex + i, 1); + Backend.compat.instancedArrays.vertexAttribDivisor(attributeBaseIndex + i, 1); } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java index c16a9ef97..3e1ba850d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java @@ -37,7 +37,7 @@ public class InstancedMaterialGroup

implements MaterialG public InstancedMaterialGroup(InstancingEngine

owner, RenderType type) { this.owner = owner; this.type = type; - if (Backend.getInstance().compat.onAMDWindows()) { + if (Backend.compat.onAMDWindows()) { this.allocator = FallbackAllocator.INSTANCE; } else { this.allocator = new ModelPool(Formats.POS_TEX_NORMAL, 2048); diff --git a/src/main/java/com/jozufozu/flywheel/core/Contexts.java b/src/main/java/com/jozufozu/flywheel/core/Contexts.java index 66bf2b0f5..db5d448f6 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Contexts.java +++ b/src/main/java/com/jozufozu/flywheel/core/Contexts.java @@ -1,13 +1,12 @@ package com.jozufozu.flywheel.core; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.backend.GameStateRegistry; -import com.jozufozu.flywheel.backend.source.FileResolution; -import com.jozufozu.flywheel.backend.source.Resolver; import com.jozufozu.flywheel.core.compile.ProgramCompiler; import com.jozufozu.flywheel.core.crumbling.CrumblingProgram; import com.jozufozu.flywheel.core.shader.NormalDebugStateProvider; import com.jozufozu.flywheel.core.shader.WorldProgram; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.Resolver; import com.jozufozu.flywheel.event.GatherContextEvent; import com.jozufozu.flywheel.util.ResourceUtil; diff --git a/src/main/java/com/jozufozu/flywheel/backend/GameStateRegistry.java b/src/main/java/com/jozufozu/flywheel/core/GameStateRegistry.java similarity index 92% rename from src/main/java/com/jozufozu/flywheel/backend/GameStateRegistry.java rename to src/main/java/com/jozufozu/flywheel/core/GameStateRegistry.java index 2bdd425c0..c8626668e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/GameStateRegistry.java +++ b/src/main/java/com/jozufozu/flywheel/core/GameStateRegistry.java @@ -1,10 +1,10 @@ -package com.jozufozu.flywheel.backend; +package com.jozufozu.flywheel.core; import java.util.HashMap; import java.util.Map; -import com.jozufozu.flywheel.core.compile.ShaderConstants; import com.jozufozu.flywheel.core.shader.GameStateProvider; +import com.jozufozu.flywheel.core.shader.ShaderConstants; import com.jozufozu.flywheel.core.shader.StateSnapshot; import net.minecraft.resources.ResourceLocation; @@ -13,7 +13,7 @@ public class GameStateRegistry { private static final Map registeredStateProviders = new HashMap<>(); - static void clear() { + public static void _clear() { registeredStateProviders.clear(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/Materials.java b/src/main/java/com/jozufozu/flywheel/core/Materials.java index 238a6b052..fbf704aaa 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Materials.java +++ b/src/main/java/com/jozufozu/flywheel/core/Materials.java @@ -2,12 +2,10 @@ package com.jozufozu.flywheel.core; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.core.materials.model.ModelType; import com.jozufozu.flywheel.core.materials.oriented.OrientedData; import com.jozufozu.flywheel.core.materials.oriented.OrientedType; -import com.jozufozu.flywheel.event.GatherContextEvent; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; @@ -19,12 +17,6 @@ public class Materials { public static final StructType ORIENTED = new OrientedType(); public static final StructType TRANSFORMED = new ModelType(); - public static void flwInit(GatherContextEvent event) { - Backend backend = event.getBackend(); - backend.register(Names.ORIENTED, ORIENTED); - backend.register(Names.MODEL, TRANSFORMED); - } - public static class Names { public static final ResourceLocation MODEL = Flywheel.rl("model"); public static final ResourceLocation ORIENTED = Flywheel.rl("oriented"); diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java b/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java index d6a3b8bed..ca312e347 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java @@ -1,10 +1,16 @@ package com.jozufozu.flywheel.core.compile; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; public class CompileUtil { + public static final Pattern vecType = Pattern.compile("^[biud]?vec([234])$"); + public static final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$"); + protected static String generateHeader(GLSLVersion version, ShaderType type) { return "#version " + version @@ -13,4 +19,31 @@ public class CompileUtil { + "#extension GL_ARB_conservative_depth : enable\n" + type.getDefineStatement(); } + + public static int getElementCount(String type) { + Matcher vec = vecType.matcher(type); + if (vec.find()) return Integer.parseInt(vec.group(1)); + + Matcher mat = matType.matcher(type); + if (mat.find()) { + int n = Integer.parseInt(mat.group(1)); + + String m = mat.group(2); + + if (m != null) return Integer.parseInt(m) * n; + + return n; + } + + return 1; + } + + public static int getAttributeCount(CharSequence type) { + Matcher mat = matType.matcher(type); + if (mat.find()) { + return Integer.parseInt(mat.group(1)); + } + + return 1; + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java index 3eaf09a42..535b688c5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java @@ -4,9 +4,11 @@ import java.util.Objects; 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.ShaderConstants; import com.jozufozu.flywheel.core.shader.StateSnapshot; +import com.jozufozu.flywheel.core.source.FileIndexImpl; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.SourceFile; public class FragmentCompiler extends Memoizer { private final FileResolution header; @@ -43,9 +45,23 @@ public class FragmentCompiler extends Memoizer */ -public class Template { - - private final Map metadata = new HashMap<>(); +public class Template extends Memoizer { private final Function reader; private final GLSLVersion glslVersion; @@ -34,7 +30,7 @@ public class Template { */ public T apply(SourceFile file) { // lazily read files, cache results - return metadata.computeIfAbsent(file, reader); + return super.get(file); } /** @@ -44,4 +40,13 @@ public class Template { return glslVersion; } + @Override + protected T _create(SourceFile key) { + return reader.apply(key); + } + + @Override + protected void _destroy(T value) { + // noop + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/TypeHelper.java b/src/main/java/com/jozufozu/flywheel/core/compile/TypeHelper.java deleted file mode 100644 index 148168e7b..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/compile/TypeHelper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.jozufozu.flywheel.core.compile; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class TypeHelper { - - public static final Pattern vecType = Pattern.compile("^[biud]?vec([234])$"); - public static final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$"); - - public static int getElementCount(String type) { - Matcher vec = vecType.matcher(type); - if (vec.find()) return Integer.parseInt(vec.group(1)); - - Matcher mat = matType.matcher(type); - if (mat.find()) { - int n = Integer.parseInt(mat.group(1)); - - String m = mat.group(2); - - if (m != null) return Integer.parseInt(m) * n; - - return n; - } - - return 1; - } - - public static int getAttributeCount(CharSequence type) { - Matcher mat = matType.matcher(type); - if (mat.find()) { - return Integer.parseInt(mat.group(1)); - } - - return 1; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java index 2de890fdb..defec44c5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java @@ -5,9 +5,10 @@ import java.util.Objects; import com.jozufozu.flywheel.api.vertex.VertexType; 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.StateSnapshot; +import com.jozufozu.flywheel.core.source.FileIndexImpl; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.SourceFile; public class VertexCompiler extends Memoizer { private final Template template; @@ -55,8 +56,19 @@ public class VertexCompiler extends Memoizer { } public static class Context { + /** + * The file to compile. + */ private final SourceFile file; + + /** + * The shader constants to apply. + */ private final StateSnapshot ctx; + + /** + * The vertex type to use. + */ private final VertexType vertexType; public Context(SourceFile file, StateSnapshot ctx, VertexType vertexType) { diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/VertexData.java b/src/main/java/com/jozufozu/flywheel/core/compile/VertexData.java index 4865ef0f3..7e3e40b34 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/VertexData.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/VertexData.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.core.compile; import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.core.source.FileIndex; public interface VertexData { /** diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/ExtensionInstance.java b/src/main/java/com/jozufozu/flywheel/core/shader/ExtensionInstance.java deleted file mode 100644 index 4875df7bf..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/shader/ExtensionInstance.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.jozufozu.flywheel.core.shader; - -import net.minecraft.resources.ResourceLocation; - -public interface ExtensionInstance { - - /** - * Bind the extra program state. It is recommended to grab the state information from global variables. - */ - void bind(); - - ResourceLocation name(); -} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java index 9bf698ac9..0e9f26bed 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java @@ -1,7 +1,5 @@ package com.jozufozu.flywheel.core.shader; -import com.jozufozu.flywheel.core.compile.ShaderConstants; - import net.minecraft.resources.ResourceLocation; public interface GameStateProvider { diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java index b8a340448..b907d0b0a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java @@ -2,7 +2,6 @@ package com.jozufozu.flywheel.core.shader; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.config.FlwConfig; -import com.jozufozu.flywheel.core.compile.ShaderConstants; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java index fb03631f2..729203ba8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/ProgramSpec.java @@ -1,8 +1,8 @@ package com.jozufozu.flywheel.core.shader; -import com.jozufozu.flywheel.backend.source.FileResolution; -import com.jozufozu.flywheel.backend.source.Resolver; -import com.jozufozu.flywheel.backend.source.SourceFile; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.Resolver; +import com.jozufozu.flywheel.core.source.SourceFile; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ShaderConstants.java b/src/main/java/com/jozufozu/flywheel/core/shader/ShaderConstants.java similarity index 86% rename from src/main/java/com/jozufozu/flywheel/core/compile/ShaderConstants.java rename to src/main/java/com/jozufozu/flywheel/core/shader/ShaderConstants.java index 165e25112..ed56ab006 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/ShaderConstants.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/ShaderConstants.java @@ -1,12 +1,16 @@ -package com.jozufozu.flywheel.core.compile; +package com.jozufozu.flywheel.core.shader; import java.util.HashMap; import java.util.List; import java.util.Map; +/** + * A class for manipulating a list of {@code #define} directives. + * + *

Based loosely on code by jellysquid3. + */ public class ShaderConstants { - private final Map definitions = new HashMap<>(); public ShaderConstants define(String def) { diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java b/src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java index e11b7c0f2..b55dd84bb 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java @@ -1,7 +1,6 @@ package com.jozufozu.flywheel.core.shader; -import com.jozufozu.flywheel.backend.GameStateRegistry; -import com.jozufozu.flywheel.core.compile.ShaderConstants; +import com.jozufozu.flywheel.core.GameStateRegistry; public record StateSnapshot(long ctx) { // TODO: is this needed? diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/WorldFog.java b/src/main/java/com/jozufozu/flywheel/core/shader/WorldFog.java index b6aa01a11..6d94a42c5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/WorldFog.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/WorldFog.java @@ -2,15 +2,10 @@ package com.jozufozu.flywheel.core.shader; import org.lwjgl.opengl.GL20; -import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.resources.ResourceLocation; - -public class WorldFog implements ExtensionInstance { - - public static final ResourceLocation NAME = Flywheel.rl("fog"); +public class WorldFog { private final int uFogColor; private final int uFogRange; @@ -20,14 +15,8 @@ public class WorldFog implements ExtensionInstance { this.uFogRange = program.getUniformLocation("uFogRange"); } - @Override public void bind() { GL20.glUniform2f(uFogRange, RenderSystem.getShaderFogStart(), RenderSystem.getShaderFogEnd()); GL20.glUniform4fv(uFogColor, RenderSystem.getShaderFogColor()); } - - @Override - public ResourceLocation name() { - return NAME; - } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FileIndex.java b/src/main/java/com/jozufozu/flywheel/core/source/FileIndex.java similarity index 73% rename from src/main/java/com/jozufozu/flywheel/core/compile/FileIndex.java rename to src/main/java/com/jozufozu/flywheel/core/source/FileIndex.java index 48e435a6c..91ce1e36e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/FileIndex.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/FileIndex.java @@ -1,7 +1,6 @@ -package com.jozufozu.flywheel.core.compile; +package com.jozufozu.flywheel.core.source; -import com.jozufozu.flywheel.backend.source.SourceFile; -import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.core.source.span.Span; public interface FileIndex { /** diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FileIndexImpl.java b/src/main/java/com/jozufozu/flywheel/core/source/FileIndexImpl.java similarity index 87% rename from src/main/java/com/jozufozu/flywheel/core/compile/FileIndexImpl.java rename to src/main/java/com/jozufozu/flywheel/core/source/FileIndexImpl.java index 0958c094e..90a1cc4ba 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/FileIndexImpl.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/FileIndexImpl.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.compile; +package com.jozufozu.flywheel.core.source; import java.util.ArrayList; import java.util.List; @@ -6,9 +6,8 @@ import java.util.List; import javax.annotation.Nullable; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.source.SourceFile; -import com.jozufozu.flywheel.backend.source.error.ErrorBuilder; -import com.jozufozu.flywheel.backend.source.error.ErrorReporter; +import com.jozufozu.flywheel.core.source.error.ErrorBuilder; +import com.jozufozu.flywheel.core.source.error.ErrorReporter; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java b/src/main/java/com/jozufozu/flywheel/core/source/FileResolution.java similarity index 93% rename from src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java rename to src/main/java/com/jozufozu/flywheel/core/source/FileResolution.java index 9a5d2fd9c..86c9dadd0 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/FileResolution.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/FileResolution.java @@ -1,12 +1,12 @@ -package com.jozufozu.flywheel.backend.source; +package com.jozufozu.flywheel.core.source; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.source.error.ErrorBuilder; -import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.core.source.error.ErrorBuilder; +import com.jozufozu.flywheel.core.source.span.Span; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/Index.java b/src/main/java/com/jozufozu/flywheel/core/source/Index.java similarity index 85% rename from src/main/java/com/jozufozu/flywheel/backend/source/Index.java rename to src/main/java/com/jozufozu/flywheel/core/source/Index.java index 4ebc6540c..dfcad42c5 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/Index.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/Index.java @@ -1,12 +1,12 @@ -package com.jozufozu.flywheel.backend.source; +package com.jozufozu.flywheel.core.source; import java.util.Collection; import java.util.Map; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; -import com.jozufozu.flywheel.backend.source.parse.ShaderFunction; -import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; +import com.jozufozu.flywheel.core.source.parse.ShaderFunction; +import com.jozufozu.flywheel.core.source.parse.ShaderStruct; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/Resolver.java b/src/main/java/com/jozufozu/flywheel/core/source/Resolver.java similarity index 97% rename from src/main/java/com/jozufozu/flywheel/backend/source/Resolver.java rename to src/main/java/com/jozufozu/flywheel/core/source/Resolver.java index c48eb0b6e..9abea7354 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/Resolver.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/Resolver.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source; +package com.jozufozu.flywheel.core.source; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/ShaderLoadingException.java b/src/main/java/com/jozufozu/flywheel/core/source/ShaderLoadingException.java similarity index 79% rename from src/main/java/com/jozufozu/flywheel/backend/source/ShaderLoadingException.java rename to src/main/java/com/jozufozu/flywheel/core/source/ShaderLoadingException.java index 19024e686..36ca1dc73 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/ShaderLoadingException.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/ShaderLoadingException.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source; +package com.jozufozu.flywheel.core.source; public class ShaderLoadingException extends RuntimeException { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/ShaderSources.java b/src/main/java/com/jozufozu/flywheel/core/source/ShaderSources.java similarity index 97% rename from src/main/java/com/jozufozu/flywheel/backend/source/ShaderSources.java rename to src/main/java/com/jozufozu/flywheel/core/source/ShaderSources.java index 97f4acead..b7e29c2a4 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/ShaderSources.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/ShaderSources.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source; +package com.jozufozu.flywheel.core.source; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java similarity index 93% rename from src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java rename to src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java index 6f4b04e87..c2a13f21c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source; +package com.jozufozu.flywheel.core.source; import java.util.ArrayList; import java.util.HashMap; @@ -10,13 +10,12 @@ import java.util.regex.Pattern; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.jozufozu.flywheel.backend.source.parse.Import; -import com.jozufozu.flywheel.backend.source.parse.ShaderFunction; -import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; -import com.jozufozu.flywheel.backend.source.span.ErrorSpan; -import com.jozufozu.flywheel.backend.source.span.Span; -import com.jozufozu.flywheel.backend.source.span.StringSpan; -import com.jozufozu.flywheel.core.compile.FileIndex; +import com.jozufozu.flywheel.core.source.parse.Import; +import com.jozufozu.flywheel.core.source.parse.ShaderFunction; +import com.jozufozu.flywheel.core.source.parse.ShaderStruct; +import com.jozufozu.flywheel.core.source.span.ErrorSpan; +import com.jozufozu.flywheel.core.source.span.Span; +import com.jozufozu.flywheel.core.source.span.StringSpan; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFinder.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceFinder.java similarity index 84% rename from src/main/java/com/jozufozu/flywheel/backend/source/SourceFinder.java rename to src/main/java/com/jozufozu/flywheel/core/source/SourceFinder.java index 09d5f8d90..50ced811f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/SourceFinder.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceFinder.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source; +package com.jozufozu.flywheel.core.source; import javax.annotation.Nullable; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/SourceLines.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java similarity index 95% rename from src/main/java/com/jozufozu/flywheel/backend/source/SourceLines.java rename to src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java index 6fd722744..f9ade475c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/SourceLines.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java @@ -1,10 +1,10 @@ -package com.jozufozu.flywheel.backend.source; +package com.jozufozu.flywheel.core.source; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.backend.source.span.CharPos; +import com.jozufozu.flywheel.core.source.span.CharPos; import com.jozufozu.flywheel.util.StringUtil; import it.unimi.dsi.fastutil.ints.IntArrayList; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java similarity index 82% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java rename to src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java index 04578dc41..2732a97fb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source.error; +package com.jozufozu.flywheel.core.source.error; import java.util.ArrayList; import java.util.List; @@ -7,16 +7,16 @@ import java.util.regex.Pattern; import javax.annotation.Nullable; -import com.jozufozu.flywheel.backend.source.SourceFile; -import com.jozufozu.flywheel.backend.source.SourceLines; -import com.jozufozu.flywheel.backend.source.error.lines.ErrorLine; -import com.jozufozu.flywheel.backend.source.error.lines.FileLine; -import com.jozufozu.flywheel.backend.source.error.lines.HeaderLine; -import com.jozufozu.flywheel.backend.source.error.lines.SourceLine; -import com.jozufozu.flywheel.backend.source.error.lines.SpanHighlightLine; -import com.jozufozu.flywheel.backend.source.error.lines.TextLine; -import com.jozufozu.flywheel.backend.source.span.Span; -import com.jozufozu.flywheel.core.compile.FileIndex; +import com.jozufozu.flywheel.core.source.FileIndex; +import com.jozufozu.flywheel.core.source.SourceFile; +import com.jozufozu.flywheel.core.source.SourceLines; +import com.jozufozu.flywheel.core.source.error.lines.ErrorLine; +import com.jozufozu.flywheel.core.source.error.lines.FileLine; +import com.jozufozu.flywheel.core.source.error.lines.HeaderLine; +import com.jozufozu.flywheel.core.source.error.lines.SourceLine; +import com.jozufozu.flywheel.core.source.error.lines.SpanHighlightLine; +import com.jozufozu.flywheel.core.source.error.lines.TextLine; +import com.jozufozu.flywheel.core.source.span.Span; import com.jozufozu.flywheel.util.FlwUtil; public class ErrorBuilder { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorLevel.java b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorLevel.java similarity index 80% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorLevel.java rename to src/main/java/com/jozufozu/flywheel/core/source/error/ErrorLevel.java index cbd161969..e45345124 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorLevel.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorLevel.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source.error; +package com.jozufozu.flywheel.core.source.error; public enum ErrorLevel { WARN("warn"), diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorReporter.java b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java similarity index 89% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorReporter.java rename to src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java index 7a11ee253..fc9a1568d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/ErrorReporter.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java @@ -1,14 +1,14 @@ -package com.jozufozu.flywheel.backend.source.error; +package com.jozufozu.flywheel.core.source.error; import java.util.List; import java.util.Optional; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.source.SourceFile; -import com.jozufozu.flywheel.backend.source.parse.ShaderFunction; -import com.jozufozu.flywheel.backend.source.parse.ShaderStruct; -import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.core.source.SourceFile; +import com.jozufozu.flywheel.core.source.parse.ShaderFunction; +import com.jozufozu.flywheel.core.source.parse.ShaderStruct; +import com.jozufozu.flywheel.core.source.span.Span; import com.jozufozu.flywheel.util.FlwUtil; public class ErrorReporter { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/Divider.java b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/Divider.java similarity index 75% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/lines/Divider.java rename to src/main/java/com/jozufozu/flywheel/core/source/error/lines/Divider.java index a24c21c4b..c9206c740 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/Divider.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/Divider.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source.error.lines; +package com.jozufozu.flywheel.core.source.error.lines; public enum Divider { BAR(" | "), diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/ErrorLine.java b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/ErrorLine.java similarity index 83% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/lines/ErrorLine.java rename to src/main/java/com/jozufozu/flywheel/core/source/error/lines/ErrorLine.java index cac9900cb..985275be6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/ErrorLine.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/ErrorLine.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source.error.lines; +package com.jozufozu.flywheel.core.source.error.lines; public interface ErrorLine { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/FileLine.java b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/FileLine.java similarity index 80% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/lines/FileLine.java rename to src/main/java/com/jozufozu/flywheel/core/source/error/lines/FileLine.java index b39bf3494..f1facc2d5 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/FileLine.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/FileLine.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source.error.lines; +package com.jozufozu.flywheel.core.source.error.lines; public record FileLine(String fileName) implements ErrorLine { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/HeaderLine.java b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/HeaderLine.java similarity index 78% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/lines/HeaderLine.java rename to src/main/java/com/jozufozu/flywheel/core/source/error/lines/HeaderLine.java index 5ed78ec06..e806cc399 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/HeaderLine.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/HeaderLine.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source.error.lines; +package com.jozufozu.flywheel.core.source.error.lines; public record HeaderLine(String level, CharSequence message) implements ErrorLine { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/SourceLine.java b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/SourceLine.java similarity index 84% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/lines/SourceLine.java rename to src/main/java/com/jozufozu/flywheel/core/source/error/lines/SourceLine.java index 496e411fc..f790fd08c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/SourceLine.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/SourceLine.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source.error.lines; +package com.jozufozu.flywheel.core.source.error.lines; public record SourceLine(String number, String line) implements ErrorLine { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/SpanHighlightLine.java b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/SpanHighlightLine.java similarity index 88% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/lines/SpanHighlightLine.java rename to src/main/java/com/jozufozu/flywheel/core/source/error/lines/SpanHighlightLine.java index 379ab82ea..2d2bf9431 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/SpanHighlightLine.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/SpanHighlightLine.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source.error.lines; +package com.jozufozu.flywheel.core.source.error.lines; public class SpanHighlightLine implements ErrorLine { private final String line; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/TextLine.java b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/TextLine.java similarity index 66% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/lines/TextLine.java rename to src/main/java/com/jozufozu/flywheel/core/source/error/lines/TextLine.java index beb66c60c..e5ff86ff0 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/lines/TextLine.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/TextLine.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source.error.lines; +package com.jozufozu.flywheel.core.source.error.lines; public record TextLine(String msg) implements ErrorLine { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/span/package-info.java b/src/main/java/com/jozufozu/flywheel/core/source/error/package-info.java similarity index 77% rename from src/main/java/com/jozufozu/flywheel/backend/source/span/package-info.java rename to src/main/java/com/jozufozu/flywheel/core/source/error/package-info.java index 4119b8241..3533088ae 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/span/package-info.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/package-info.java @@ -1,5 +1,5 @@ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.jozufozu.flywheel.backend.source.span; +package com.jozufozu.flywheel.core.source.error; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/package-info.java b/src/main/java/com/jozufozu/flywheel/core/source/package-info.java similarity index 78% rename from src/main/java/com/jozufozu/flywheel/backend/source/package-info.java rename to src/main/java/com/jozufozu/flywheel/core/source/package-info.java index bb8d86f6d..18f315f87 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/package-info.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/package-info.java @@ -1,5 +1,5 @@ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.jozufozu.flywheel.backend.source; +package com.jozufozu.flywheel.core.source; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/parse/AbstractShaderElement.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/AbstractShaderElement.java similarity index 57% rename from src/main/java/com/jozufozu/flywheel/backend/source/parse/AbstractShaderElement.java rename to src/main/java/com/jozufozu/flywheel/core/source/parse/AbstractShaderElement.java index 594ae4d02..d230d013e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/parse/AbstractShaderElement.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/AbstractShaderElement.java @@ -1,6 +1,6 @@ -package com.jozufozu.flywheel.backend.source.parse; +package com.jozufozu.flywheel.core.source.parse; -import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.core.source.span.Span; public abstract class AbstractShaderElement { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/parse/Import.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/Import.java similarity index 76% rename from src/main/java/com/jozufozu/flywheel/backend/source/parse/Import.java rename to src/main/java/com/jozufozu/flywheel/core/source/parse/Import.java index 239518d84..0a357671b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/parse/Import.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/Import.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source.parse; +package com.jozufozu.flywheel.core.source.parse; import java.util.ArrayList; import java.util.List; @@ -6,11 +6,11 @@ import java.util.Optional; import javax.annotation.Nullable; -import com.jozufozu.flywheel.backend.source.FileResolution; -import com.jozufozu.flywheel.backend.source.Resolver; -import com.jozufozu.flywheel.backend.source.SourceFile; -import com.jozufozu.flywheel.backend.source.error.ErrorReporter; -import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.Resolver; +import com.jozufozu.flywheel.core.source.SourceFile; +import com.jozufozu.flywheel.core.source.error.ErrorReporter; +import com.jozufozu.flywheel.core.source.span.Span; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/parse/ShaderFunction.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderFunction.java similarity index 94% rename from src/main/java/com/jozufozu/flywheel/backend/source/parse/ShaderFunction.java rename to src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderFunction.java index 92feb12a8..9dfe551de 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/parse/ShaderFunction.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderFunction.java @@ -1,11 +1,11 @@ -package com.jozufozu.flywheel.backend.source.parse; +package com.jozufozu.flywheel.core.source.parse; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.core.source.span.Span; public class ShaderFunction extends AbstractShaderElement { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/parse/ShaderStruct.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderStruct.java similarity index 93% rename from src/main/java/com/jozufozu/flywheel/backend/source/parse/ShaderStruct.java rename to src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderStruct.java index 80200ff32..e3db7fd29 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/parse/ShaderStruct.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderStruct.java @@ -1,11 +1,11 @@ -package com.jozufozu.flywheel.backend.source.parse; +package com.jozufozu.flywheel.core.source.parse; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.core.source.span.Span; public class ShaderStruct extends AbstractShaderElement { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/parse/StructField.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/StructField.java similarity index 82% rename from src/main/java/com/jozufozu/flywheel/backend/source/parse/StructField.java rename to src/main/java/com/jozufozu/flywheel/core/source/parse/StructField.java index 77e03f555..961ea3441 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/parse/StructField.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/StructField.java @@ -1,8 +1,8 @@ -package com.jozufozu.flywheel.backend.source.parse; +package com.jozufozu.flywheel.core.source.parse; import java.util.regex.Pattern; -import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.core.source.span.Span; public class StructField extends AbstractShaderElement { public static final Pattern fieldPattern = Pattern.compile("(\\S+)\\s*(\\S+);"); diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/parse/Variable.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/Variable.java similarity index 87% rename from src/main/java/com/jozufozu/flywheel/backend/source/parse/Variable.java rename to src/main/java/com/jozufozu/flywheel/core/source/parse/Variable.java index 342684a73..0d6f9aa99 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/parse/Variable.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/Variable.java @@ -1,6 +1,6 @@ -package com.jozufozu.flywheel.backend.source.parse; +package com.jozufozu.flywheel.core.source.parse; -import com.jozufozu.flywheel.backend.source.span.Span; +import com.jozufozu.flywheel.core.source.span.Span; public class Variable extends AbstractShaderElement { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/parse/package-info.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/package-info.java similarity index 76% rename from src/main/java/com/jozufozu/flywheel/backend/source/parse/package-info.java rename to src/main/java/com/jozufozu/flywheel/core/source/parse/package-info.java index 61225f714..0984aedc8 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/parse/package-info.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/package-info.java @@ -1,6 +1,6 @@ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.jozufozu.flywheel.backend.source.parse; +package com.jozufozu.flywheel.core.source.parse; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/span/CharPos.java b/src/main/java/com/jozufozu/flywheel/core/source/span/CharPos.java similarity index 63% rename from src/main/java/com/jozufozu/flywheel/backend/source/span/CharPos.java rename to src/main/java/com/jozufozu/flywheel/core/source/span/CharPos.java index d402a65fc..617cfa0a7 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/span/CharPos.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/span/CharPos.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.source.span; +package com.jozufozu.flywheel.core.source.span; /** * A position in a file. diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/span/ErrorSpan.java b/src/main/java/com/jozufozu/flywheel/core/source/span/ErrorSpan.java similarity index 85% rename from src/main/java/com/jozufozu/flywheel/backend/source/span/ErrorSpan.java rename to src/main/java/com/jozufozu/flywheel/core/source/span/ErrorSpan.java index c73ba195e..5c4cd39e1 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/span/ErrorSpan.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/span/ErrorSpan.java @@ -1,6 +1,6 @@ -package com.jozufozu.flywheel.backend.source.span; +package com.jozufozu.flywheel.core.source.span; -import com.jozufozu.flywheel.backend.source.SourceFile; +import com.jozufozu.flywheel.core.source.SourceFile; /** * Represents a (syntactically) malformed segment of code. diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/span/Span.java b/src/main/java/com/jozufozu/flywheel/core/source/span/Span.java similarity index 95% rename from src/main/java/com/jozufozu/flywheel/backend/source/span/Span.java rename to src/main/java/com/jozufozu/flywheel/core/source/span/Span.java index 1b812fde9..61961a979 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/span/Span.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/span/Span.java @@ -1,8 +1,8 @@ -package com.jozufozu.flywheel.backend.source.span; +package com.jozufozu.flywheel.core.source.span; import java.util.regex.Matcher; -import com.jozufozu.flywheel.backend.source.SourceFile; +import com.jozufozu.flywheel.core.source.SourceFile; /** * A segment of code in a {@link SourceFile}. diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/span/StringSpan.java b/src/main/java/com/jozufozu/flywheel/core/source/span/StringSpan.java similarity index 82% rename from src/main/java/com/jozufozu/flywheel/backend/source/span/StringSpan.java rename to src/main/java/com/jozufozu/flywheel/core/source/span/StringSpan.java index 4712c6b74..f91be1f6d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/span/StringSpan.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/span/StringSpan.java @@ -1,6 +1,6 @@ -package com.jozufozu.flywheel.backend.source.span; +package com.jozufozu.flywheel.core.source.span; -import com.jozufozu.flywheel.backend.source.SourceFile; +import com.jozufozu.flywheel.core.source.SourceFile; public class StringSpan extends Span { diff --git a/src/main/java/com/jozufozu/flywheel/backend/source/error/package-info.java b/src/main/java/com/jozufozu/flywheel/core/source/span/package-info.java similarity index 76% rename from src/main/java/com/jozufozu/flywheel/backend/source/error/package-info.java rename to src/main/java/com/jozufozu/flywheel/core/source/span/package-info.java index 250db26d8..1ee6ddb46 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/source/error/package-info.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/span/package-info.java @@ -1,5 +1,5 @@ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.jozufozu.flywheel.backend.source.error; +package com.jozufozu.flywheel.core.source.span; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java index c91713235..9ca6cd351 100644 --- a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java +++ b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java @@ -24,8 +24,7 @@ public class ForgeEvents { ArrayList right = event.getRight(); - String text = "Flywheel: " + Backend.getInstance() - .getBackendDescriptor(); + String text = "Flywheel: " + Backend.getBackendDescriptor(); if (right.size() < 10) { right.add(""); right.add(text); diff --git a/src/main/java/com/jozufozu/flywheel/event/GatherContextEvent.java b/src/main/java/com/jozufozu/flywheel/event/GatherContextEvent.java index df5a6307b..ffbc76341 100644 --- a/src/main/java/com/jozufozu/flywheel/event/GatherContextEvent.java +++ b/src/main/java/com/jozufozu/flywheel/event/GatherContextEvent.java @@ -1,24 +1,16 @@ package com.jozufozu.flywheel.event; -import com.jozufozu.flywheel.backend.Backend; - import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.event.IModBusEvent; public class GatherContextEvent extends Event implements IModBusEvent { - private final Backend backend; private final boolean firstLoad; - public GatherContextEvent(Backend backend, boolean firstLoad) { - this.backend = backend; + public GatherContextEvent(boolean firstLoad) { this.firstLoad = firstLoad; } - public Backend getBackend() { - return backend; - } - /** * @return true iff it is the first time the event is fired. */ diff --git a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java index 026105389..f45d12978 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java @@ -67,8 +67,7 @@ public class LevelRendererMixin { @Inject(at = @At("TAIL"), method = "allChanged") private void refresh(CallbackInfo ci) { - Backend.getInstance() - .refresh(); + Backend.refresh(); MinecraftForge.EVENT_BUS.post(new ReloadRenderersEvent(level)); } From b351baa824344763f936dcf30c1bb7f94476f094 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Thu, 13 Jan 2022 15:58:51 -0800 Subject: [PATCH 10/10] Handle arbitrary numbers of GameStateProviders - Use bitset instead of long. - We only ever iterate over the GameStateProviders, so use a list instead of a map. - GameStateProviders don't need IDs. --- .../flywheel/core/GameStateRegistry.java | 71 +++++++++---------- .../core/compile/FragmentCompiler.java | 2 +- .../flywheel/core/compile/VertexCompiler.java | 2 +- .../core/shader/GameStateProvider.java | 15 ++-- .../core/shader/NormalDebugStateProvider.java | 18 +---- .../flywheel/core/shader/StateSnapshot.java | 8 ++- 6 files changed, 54 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/jozufozu/flywheel/core/GameStateRegistry.java b/src/main/java/com/jozufozu/flywheel/core/GameStateRegistry.java index c8626668e..67a5c2b44 100644 --- a/src/main/java/com/jozufozu/flywheel/core/GameStateRegistry.java +++ b/src/main/java/com/jozufozu/flywheel/core/GameStateRegistry.java @@ -1,61 +1,58 @@ package com.jozufozu.flywheel.core; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; import com.jozufozu.flywheel.core.shader.GameStateProvider; import com.jozufozu.flywheel.core.shader.ShaderConstants; import com.jozufozu.flywheel.core.shader.StateSnapshot; -import net.minecraft.resources.ResourceLocation; - public class GameStateRegistry { - private static final Map registeredStateProviders = new HashMap<>(); + private static final List PROVIDERS = new ArrayList<>(); - public static void _clear() { - registeredStateProviders.clear(); - } - - public static GameStateProvider getStateProvider(ResourceLocation location) { - GameStateProvider out = registeredStateProviders.get(location); - - if (out == null) { - throw new IllegalArgumentException("State provider '" + location + "' does not exist."); - } - - return out; - } - - public static void register(GameStateProvider context) { - if (registeredStateProviders.containsKey(context.getID())) { - throw new IllegalStateException("Duplicate game state provider: " + context.getID()); - } - - registeredStateProviders.put(context.getID(), context); + /** + * Registers a game state provider. + * @param provider The provider to register. + */ + public static void register(GameStateProvider provider) { + PROVIDERS.add(provider); } + /** + * Takes a snapshot of the current game state, storing it in a bit set. + * @return An object that represents the current game state. + */ public static StateSnapshot takeSnapshot() { - long ctx = 0; - for (GameStateProvider state : registeredStateProviders.values()) { - if (state.isTrue()) { - ctx |= 1; + BitSet bitSet = new BitSet(PROVIDERS.size()); + + for (int i = 0, listSize = PROVIDERS.size(); i < listSize; i++) { + if (PROVIDERS.get(i).isTrue()) { + bitSet.set(i); } - ctx <<= 1; } - return new StateSnapshot(ctx); + return new StateSnapshot(bitSet); } - public static ShaderConstants getDefines(long ctx) { - long stateID = ctx; + /** + * Based on the given snapshot, gathers shader constants to be injected during shader compilation. + * @param snapshot The snapshot to use. + * @return A list of shader constants. + */ + public static ShaderConstants getShaderConstants(StateSnapshot snapshot) { + BitSet ctx = snapshot.ctx(); ShaderConstants shaderConstants = new ShaderConstants(); - for (GameStateProvider state : registeredStateProviders.values()) { - if ((stateID & 1) == 1) { - state.alterConstants(shaderConstants); + for (int i = 0, listSize = PROVIDERS.size(); i < listSize; i++) { + if (ctx.get(i)) { + PROVIDERS.get(i).alterConstants(shaderConstants); } - stateID >>= 1; } return shaderConstants; } + + public static void _clear() { + PROVIDERS.clear(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java index 535b688c5..e5600cc66 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java @@ -71,7 +71,7 @@ public class FragmentCompiler extends Memoizer 0) { shaderConstants.define("ALPHA_DISCARD", alphaDiscard); diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java index defec44c5..6487c45c4 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java @@ -25,7 +25,7 @@ public class VertexCompiler extends Memoizer { finalSource.append(CompileUtil.generateHeader(template.getVersion(), ShaderType.VERTEX)); - key.ctx.getDefines().writeInto(finalSource); + key.ctx.getShaderConstants().writeInto(finalSource); finalSource.append(""" struct Vertex { diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java index 0e9f26bed..2ec67744e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/GameStateProvider.java @@ -1,12 +1,19 @@ package com.jozufozu.flywheel.core.shader; -import net.minecraft.resources.ResourceLocation; - +/** + * An object that provides a view of the current game state for shader compilation. + */ public interface GameStateProvider { - ResourceLocation getID(); - + /** + * Get the status of this game state provider. + * @return Returning {@code true} will cause #alterConstants to be called before compiling a shader. + */ boolean isTrue(); + /** + * Alter the constants for shader compilation. + * @param constants The shader constants. + */ void alterConstants(ShaderConstants constants); } diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java index b907d0b0a..50efebd9f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/NormalDebugStateProvider.java @@ -1,18 +1,9 @@ package com.jozufozu.flywheel.core.shader; -import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.config.FlwConfig; -import net.minecraft.resources.ResourceLocation; - -public class NormalDebugStateProvider implements GameStateProvider { - - public static final NormalDebugStateProvider INSTANCE = new NormalDebugStateProvider(); - public static final ResourceLocation NAME = Flywheel.rl("normal_debug"); - - protected NormalDebugStateProvider() { - - } +public enum NormalDebugStateProvider implements GameStateProvider { + INSTANCE; @Override public boolean isTrue() { @@ -20,11 +11,6 @@ public class NormalDebugStateProvider implements GameStateProvider { .debugNormals(); } - @Override - public ResourceLocation getID() { - return NAME; - } - @Override public void alterConstants(ShaderConstants constants) { constants.define("DEBUG_NORMAL"); diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java b/src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java index b55dd84bb..6a01a90f1 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/StateSnapshot.java @@ -1,11 +1,13 @@ package com.jozufozu.flywheel.core.shader; +import java.util.BitSet; + import com.jozufozu.flywheel.core.GameStateRegistry; -public record StateSnapshot(long ctx) { +public record StateSnapshot(BitSet ctx) { // TODO: is this needed? - public ShaderConstants getDefines() { - return GameStateRegistry.getDefines(ctx); + public ShaderConstants getShaderConstants() { + return GameStateRegistry.getShaderConstants(this); } }