From 178d39d8604cc21570d8762325d503ad31b53647 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Thu, 29 Sep 2022 20:41:44 -0700 Subject: [PATCH 1/9] Consolidated compilation - Note: heavily broken - Move all compilation logic into a single package - FlwCompiler is responsible for compilation - CompilationEnvironment generates combinations and performs analysis - Create source components for vertex/fragment ubershader codegen - More hacky glsl generation utils - Strip explicit uniform buffers from uniform shaders --- .../java/com/jozufozu/flywheel/Flywheel.java | 6 +- .../flywheel/api/uniform/UniformProvider.java | 20 +- .../flywheel/backend/BackendType.java | 5 + .../com/jozufozu/flywheel/backend/Loader.java | 56 +----- .../flywheel/backend/SimpleBackendType.java | 20 +- .../flywheel/backend/gl/shader/GlProgram.java | 19 +- .../flywheel/backend/gl/shader/GlShader.java | 2 +- .../backend/instancing/PipelineCompiler.java | 178 ------------------ .../compile/CompilationEnvironment.java | 59 ++++++ .../instancing}/compile/CompileUtil.java | 2 +- .../instancing/compile/FlwCompiler.java | 129 +++++++++++++ .../compile/FragmentMaterialComponent.java | 49 +++++ .../instancing/compile/PipelineContext.java | 65 +++++++ .../instancing}/compile/ProgramAssembler.java | 22 +-- .../compile/ShaderCompilationException.java | 2 +- .../instancing/compile/ShaderCompiler.java | 64 +++++++ .../instancing/compile/ShaderContext.java | 18 ++ .../compile/TransformedSourceComponent.java | 37 ++++ .../compile/VertexMaterialComponent.java | 71 +++++++ .../instancing/compile/package-info.java | 6 + .../indirect/ComputeCullerCompiler.java | 74 -------- .../indirect/IndirectComponent.java | 15 +- .../indirect/IndirectCullingGroup.java | 14 +- .../instancing/InstancedArraysComponent.java | 16 +- .../instancing/InstancingEngine.java | 9 +- .../jozufozu/flywheel/core/BackendTypes.java | 13 ++ .../flywheel/core/ComponentRegistry.java | 76 +++++++- .../jozufozu/flywheel/core/DebugRender.java | 104 ---------- .../jozufozu/flywheel/core/WorldProgram.java | 6 +- .../flywheel/core/compile/DebugCompiler.java | 95 ---------- .../flywheel/core/compile/Memoizer.java | 22 --- .../core/crumbling/CrumblingProgram.java | 6 +- .../core/source/CompilationContext.java | 6 +- .../flywheel/core/source/SourceFile.java | 4 +- .../core/source/generate/GlslBuilder.java | 112 ++++++++--- .../core/source/generate/GlslExpr.java | 62 ++++-- .../core/source/generate/GlslStmt.java | 60 ++++++ .../core/source/generate/LangItem.java | 7 + .../generate}/package-info.java | 2 +- .../flywheel/core/uniform/FogProvider.java | 66 +++++-- .../core/uniform/FrustumProvider.java | 70 ++++--- .../flywheel/core/uniform/UniformBuffer.java | 19 +- .../flywheel/core/uniform/ViewProvider.java | 109 ++++++----- .../flywheel/mixin/FogUpdateMixin.java | 4 +- .../java/com/jozufozu/flywheel/util/Pair.java | 5 + .../jozufozu/flywheel/util/ResourceUtil.java | 10 + .../flywheel/flywheel/api/fragment.glsl | 2 + .../assets/flywheel/flywheel/api/vertex.glsl | 3 + .../assets/flywheel/flywheel/compute/mat.glsl | 50 +++++ .../assets/flywheel/flywheel/uniform/fog.glsl | 9 +- .../flywheel/flywheel/uniform/frustum.glsl | 4 +- .../flywheel/flywheel/uniform/view.glsl | 8 +- 52 files changed, 1113 insertions(+), 779 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/PipelineCompiler.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationEnvironment.java rename src/main/java/com/jozufozu/flywheel/{core => backend/instancing}/compile/CompileUtil.java (96%) create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java rename src/main/java/com/jozufozu/flywheel/{core => backend/instancing}/compile/ProgramAssembler.java (67%) rename src/main/java/com/jozufozu/flywheel/{core => backend/instancing}/compile/ShaderCompilationException.java (92%) create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderContext.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/TransformedSourceComponent.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/package-info.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/DebugRender.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/Memoizer.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/LangItem.java rename src/main/java/com/jozufozu/flywheel/core/{compile => source/generate}/package-info.java (76%) create mode 100644 src/main/resources/assets/flywheel/flywheel/compute/mat.glsl diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index 28366c73b..ae55cd5de 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -7,14 +7,13 @@ import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.RenderWork; import com.jozufozu.flywheel.backend.ShadersModHandler; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.jozufozu.flywheel.backend.instancing.PipelineCompiler; import com.jozufozu.flywheel.backend.instancing.batching.DrawBuffer; +import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler; import com.jozufozu.flywheel.config.BackendTypeArgument; import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.core.BackendTypes; import com.jozufozu.flywheel.core.Components; -import com.jozufozu.flywheel.core.DebugRender; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.QuadConverter; import com.jozufozu.flywheel.core.StitchedSprite; @@ -81,7 +80,7 @@ public class Flywheel { forgeEventBus.addListener(FlwCommands::registerClientCommands); forgeEventBus.addListener(EventPriority.HIGHEST, QuadConverter::onReloadRenderers); - forgeEventBus.addListener(PipelineCompiler::onReloadRenderers); + forgeEventBus.addListener(FlwCompiler::onReloadRenderers); forgeEventBus.addListener(Models::onReloadRenderers); forgeEventBus.addListener(DrawBuffer::onReloadRenderers); @@ -108,7 +107,6 @@ public class Flywheel { // forgeEventBus.addListener(ExampleEffect::onReload); Components.init(); - DebugRender.init(); VanillaInstances.init(); diff --git a/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java b/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java index 06716f2bc..7c0fd2a30 100644 --- a/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java +++ b/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java @@ -2,21 +2,21 @@ package com.jozufozu.flywheel.api.uniform; import com.jozufozu.flywheel.core.source.FileResolution; -public abstract class UniformProvider { +public interface UniformProvider { - protected long ptr; - protected Notifier notifier; + int byteSize(); - public abstract int getActualByteSize(); + FileResolution uniformShader(); - public void updatePtr(long ptr, Notifier notifier) { - this.ptr = ptr; - this.notifier = notifier; + ActiveUniformProvider activate(long ptr, Notifier notifier); + + interface ActiveUniformProvider { + void delete(); + + void poll(); } - public abstract FileResolution getUniformShader(); - - public interface Notifier { + interface Notifier { void signalChanged(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/BackendType.java b/src/main/java/com/jozufozu/flywheel/backend/BackendType.java index d7124a3d9..0c870193e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/BackendType.java +++ b/src/main/java/com/jozufozu/flywheel/backend/BackendType.java @@ -1,5 +1,8 @@ package com.jozufozu.flywheel.backend; +import org.jetbrains.annotations.Nullable; + +import com.jozufozu.flywheel.api.pipeline.PipelineShader; import com.jozufozu.flywheel.backend.instancing.Engine; import net.minecraft.network.chat.Component; @@ -17,4 +20,6 @@ public interface BackendType { BackendType findFallback(); boolean supported(); + + @Nullable PipelineShader pipelineShader(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 2524be426..d9c1f3067 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -1,23 +1,10 @@ package com.jozufozu.flywheel.backend; -import java.util.List; - -import com.jozufozu.flywheel.api.context.ContextShader; -import com.jozufozu.flywheel.api.material.Material; -import com.jozufozu.flywheel.api.pipeline.PipelineShader; -import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.jozufozu.flywheel.backend.instancing.PipelineCompiler; -import com.jozufozu.flywheel.backend.instancing.indirect.ComputeCullerCompiler; -import com.jozufozu.flywheel.core.ComponentRegistry; -import com.jozufozu.flywheel.core.Components; -import com.jozufozu.flywheel.core.compile.ShaderCompilationException; +import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler; import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.core.source.ShaderLoadingException; import com.jozufozu.flywheel.core.source.ShaderSources; import com.jozufozu.flywheel.core.source.error.ErrorReporter; -import com.jozufozu.flywheel.util.StringUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; @@ -68,46 +55,7 @@ public class Loader implements ResourceManagerReloadListener { Backend.LOGGER.info("All shaders passed checks."); - long compileStart = System.nanoTime(); - int programCounter = 0; - boolean crash = false; - - for (Material material : ComponentRegistry.materials) { - for (StructType structType : ComponentRegistry.structTypes) { - for (VertexType vertexType : ComponentRegistry.vertexTypes) { - for (ContextShader contextShader : ComponentRegistry.contextShaders) { - for (PipelineShader pipelineShader : List.of(Components.INSTANCED_ARRAYS, Components.INDIRECT)) { - var ctx = new PipelineCompiler.Context(vertexType, material, structType, contextShader, pipelineShader); - try { - PipelineCompiler.INSTANCE.getProgram(ctx); - } catch (ShaderCompilationException e) { - Backend.LOGGER.error(e.errors); - crash = true; - } - programCounter++; - } - } - } - } - } - - for (StructType structType : ComponentRegistry.structTypes) { - try { - ComputeCullerCompiler.INSTANCE.get(structType); - } catch (ShaderCompilationException e) { - Backend.LOGGER.error(e.errors); - crash = true; - } - programCounter++; - } - - long compileEnd = System.nanoTime(); - - Backend.LOGGER.info("Compiled " + programCounter + " programs in " + StringUtil.formatTime(compileEnd - compileStart)); - - if (crash) { - throw new ShaderLoadingException("Compilation failed"); - } + FlwCompiler.INSTANCE.run(); ClientLevel level = Minecraft.getInstance().level; if (Backend.canUseInstancing(level)) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/SimpleBackendType.java b/src/main/java/com/jozufozu/flywheel/backend/SimpleBackendType.java index 1269c08dd..d832b7691 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/SimpleBackendType.java +++ b/src/main/java/com/jozufozu/flywheel/backend/SimpleBackendType.java @@ -3,6 +3,9 @@ package com.jozufozu.flywheel.backend; import java.util.function.BooleanSupplier; import java.util.function.Supplier; +import org.jetbrains.annotations.Nullable; + +import com.jozufozu.flywheel.api.pipeline.PipelineShader; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.core.BackendTypes; @@ -17,14 +20,16 @@ public class SimpleBackendType implements BackendType { private final Supplier engineSupplier; private final Supplier fallback; private final BooleanSupplier isSupported; + private final PipelineShader pipelineShader; - public SimpleBackendType(String properName, String shortName, Component engineMessage, Supplier engineSupplier, Supplier fallback, BooleanSupplier isSupported) { + public SimpleBackendType(String properName, String shortName, Component engineMessage, Supplier engineSupplier, Supplier fallback, BooleanSupplier isSupported, @Nullable PipelineShader pipelineShader) { this.properName = properName; this.shortName = shortName; this.engineMessage = engineMessage; this.engineSupplier = engineSupplier; this.fallback = fallback; this.isSupported = isSupported; + this.pipelineShader = pipelineShader; } public static Builder builder() { @@ -66,6 +71,11 @@ public class SimpleBackendType implements BackendType { return isSupported.getAsBoolean(); } + @Override + public @Nullable PipelineShader pipelineShader() { + return pipelineShader; + } + public static class Builder { private String properName; private String shortName; @@ -73,6 +83,7 @@ public class SimpleBackendType implements BackendType { private Supplier engineSupplier; private Supplier fallback; private BooleanSupplier isSupported; + private PipelineShader pipelineShader; public Builder properName(String properName) { this.properName = properName; @@ -104,8 +115,13 @@ public class SimpleBackendType implements BackendType { return this; } + public Builder pipelineShader(PipelineShader pipelineShader) { + this.pipelineShader = pipelineShader; + return this; + } + public BackendType register() { - return BackendTypes.register(new SimpleBackendType(properName, shortName, engineMessage, engineSupplier, fallback, isSupported)); + return BackendTypes.register(new SimpleBackendType(properName, shortName, engineMessage, engineSupplier, fallback, isSupported, pipelineShader)); } } } 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 ea80d4cf5..cea2fcfa3 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 @@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.gl.shader; import static org.lwjgl.opengl.GL20.glDeleteProgram; import static org.lwjgl.opengl.GL20.glGetUniformLocation; import static org.lwjgl.opengl.GL20.glUniform1i; -import static org.lwjgl.opengl.GL20.glUniformMatrix4fv; import org.jetbrains.annotations.NotNull; @@ -11,17 +10,13 @@ import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlObject; import com.mojang.blaze3d.shaders.ProgramManager; -import net.minecraft.resources.ResourceLocation; - public class GlProgram extends GlObject { - public final ResourceLocation name; - - public GlProgram(ResourceLocation name, int handle) { - this.name = name; + public GlProgram(int handle) { setHandle(handle); } + // TODO: Programs bind the uniform buffers they need public void bind() { ProgramManager.glUseProgram(handle()); } @@ -40,7 +35,7 @@ public class GlProgram extends GlObject { int index = glGetUniformLocation(this.handle(), uniform); if (index < 0) { - Backend.LOGGER.debug("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name); + Backend.LOGGER.debug("No active uniform '{}' exists. Could be unused.", uniform); } return index; @@ -69,17 +64,11 @@ public class GlProgram extends GlObject { glDeleteProgram(handle); } - @Override - public String toString() { - return "program " + name; - } - /** * A factory interface to create a {@link GlProgram}. */ public interface Factory { - @NotNull - GlProgram create(ResourceLocation name, int handle); + @NotNull GlProgram create(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 a93ec6046..0ffaa3485 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 @@ -10,7 +10,7 @@ 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.core.compile.ShaderCompilationException; +import com.jozufozu.flywheel.backend.instancing.compile.ShaderCompilationException; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/PipelineCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/PipelineCompiler.java deleted file mode 100644 index 5df7ae5b6..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/PipelineCompiler.java +++ /dev/null @@ -1,178 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing; - -import java.util.LinkedHashSet; -import java.util.List; - -import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.api.context.ContextShader; -import com.jozufozu.flywheel.api.material.Material; -import com.jozufozu.flywheel.api.pipeline.PipelineShader; -import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.backend.gl.GLSLVersion; -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.core.SourceComponent; -import com.jozufozu.flywheel.core.compile.CompileUtil; -import com.jozufozu.flywheel.core.compile.Memoizer; -import com.jozufozu.flywheel.core.compile.ProgramAssembler; -import com.jozufozu.flywheel.core.compile.ShaderCompilationException; -import com.jozufozu.flywheel.core.source.CompilationContext; -import com.jozufozu.flywheel.event.ReloadRenderersEvent; - -import net.minecraft.resources.ResourceLocation; - -/** - * 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. - *

- *

- * A ProgramCompiler is also responsible for deleting programs and shaders on renderer reload. - *

- */ -public class PipelineCompiler extends Memoizer { - - public static final PipelineCompiler INSTANCE = new PipelineCompiler(); - - private final ShaderCompiler shaderCompiler; - - private PipelineCompiler() { - this.shaderCompiler = new ShaderCompiler(); - } - - /** - * 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 GlProgram getProgram(PipelineCompiler.Context ctx) { - return super.get(ctx); - } - - @Override - public void invalidate() { - super.invalidate(); - shaderCompiler.invalidate(); - } - - @Override - protected GlProgram _create(PipelineCompiler.Context ctx) { - - var glslVersion = ctx.pipelineShader() - .glslVersion(); - - var vertex = new ShaderCompiler.Context(glslVersion, ShaderType.VERTEX, ctx.getVertexComponents()); - var fragment = new ShaderCompiler.Context(glslVersion, ShaderType.FRAGMENT, ctx.getFragmentComponents()); - - return new ProgramAssembler(ctx.structType.getInstanceShader() - .getFileLoc()).attachShader(shaderCompiler.get(vertex)) - .attachShader(shaderCompiler.get(fragment)) - .link() - .build(ctx.contextShader.factory()); - } - - @Override - protected void _destroy(GlProgram value) { - value.delete(); - } - - public static void onReloadRenderers(ReloadRenderersEvent event) { - INSTANCE.invalidate(); - } - - /** - * Represents the entire context of a program's usage. - * - * @param vertexType The vertexType the program should be adapted for. - * @param material The material shader to use. TODO: Flatten materials - * @param structType The instance shader to use. - * @param contextShader The context shader to use. - */ - public record Context(VertexType vertexType, Material material, StructType structType, - ContextShader contextShader, PipelineShader pipelineShader) { - - ImmutableList getVertexComponents() { - var layout = vertexType.getLayoutShader() - .getFile(); - var instanceAssembly = pipelineShader.assemble(vertexType, structType); - var instance = structType.getInstanceShader() - .getFile(); - var material = this.material.getVertexShader() - .getFile(); - var context = contextShader.getVertexShader(); - var pipeline = pipelineShader.vertex() - .getFile(); - return ImmutableList.of(layout, instanceAssembly, instance, material, context, pipeline); - } - - ImmutableList getFragmentComponents() { - var material = this.material.getFragmentShader() - .getFile(); - var context = contextShader.getFragmentShader(); - var pipeline = pipelineShader.fragment() - .getFile(); - return ImmutableList.of(material, context, pipeline); - } - } - - /** - * Handles compilation and deletion of vertex shaders. - */ - public static class ShaderCompiler extends Memoizer { - - private ShaderCompiler() { - } - - @Override - protected GlShader _create(Context key) { - StringBuilder finalSource = new StringBuilder(key.generateHeader()); - finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n"); - finalSource.append("#extension GL_ARB_conservative_depth : enable\n"); - - var ctx = new CompilationContext(); - - var names = ImmutableList.builder(); - var included = new LinkedHashSet(); // linked to preserve order - for (var component : key.sourceComponents) { - included.addAll(component.included()); - names.add(component.name()); - } - - for (var include : included) { - finalSource.append(include.source(ctx)); - } - - for (var component : key.sourceComponents) { - finalSource.append(component.source(ctx)); - } - - try { - return new GlShader(finalSource.toString(), key.shaderType, names.build()); - } catch (ShaderCompilationException e) { - throw e.withErrorLog(ctx); - } - } - - @Override - protected void _destroy(GlShader value) { - value.delete(); - } - - /** - * @param glslVersion The GLSL version to use. - * @param sourceComponents A list of shader components to stitch together, in order. - */ - public record Context(GLSLVersion glslVersion, ShaderType shaderType, List sourceComponents) { - - public String generateHeader() { - return CompileUtil.generateHeader(glslVersion, shaderType); - } - } - - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationEnvironment.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationEnvironment.java new file mode 100644 index 000000000..8f78af939 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationEnvironment.java @@ -0,0 +1,59 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import com.jozufozu.flywheel.api.context.ContextShader; +import com.jozufozu.flywheel.api.pipeline.PipelineShader; +import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.api.uniform.UniformProvider; +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.BackendTypes; +import com.jozufozu.flywheel.core.ComponentRegistry; +import com.jozufozu.flywheel.core.source.ShaderLoadingException; +import com.jozufozu.flywheel.util.StringUtil; + +class CompilationEnvironment { + final VertexMaterialComponent vertexMaterialComponent; + final FragmentMaterialComponent fragmentMaterialComponent; + + boolean needsCrash = false; + + final long compileStart = System.nanoTime(); + final Multimap, PipelineContext> uniformProviderGroups = ArrayListMultimap.create(); + final List pipelineContexts = new ArrayList<>(); + + CompilationEnvironment() { + for (PipelineShader pipelineShader : BackendTypes.availablePipelineShaders()) { + for (StructType structType : ComponentRegistry.structTypes) { + for (VertexType vertexType : ComponentRegistry.vertexTypes) { + for (ContextShader contextShader : ComponentRegistry.contextShaders) { + acknowledgeContext(new PipelineContext(vertexType, structType, contextShader, pipelineShader)); + } + } + } + } + this.vertexMaterialComponent = new VertexMaterialComponent(ComponentRegistry.materials.vertexSources()); + this.fragmentMaterialComponent = new FragmentMaterialComponent(ComponentRegistry.materials.fragmentSources()); + } + + private void acknowledgeContext(PipelineContext ctx) { + uniformProviderGroups.put(ctx.uniformProviders(), ctx); + + pipelineContexts.add(ctx); + } + + public void finish() { + long compileEnd = System.nanoTime(); + + Backend.LOGGER.info("Compiled " + pipelineContexts.size() + " programs in " + StringUtil.formatTime(compileEnd - compileStart)); + + if (needsCrash) { + throw new ShaderLoadingException("Compilation failed"); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompileUtil.java similarity index 96% rename from src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java rename to src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompileUtil.java index 545055281..219b3802e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompileUtil.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.compile; +package com.jozufozu.flywheel.backend.instancing.compile; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java new file mode 100644 index 000000000..49109b6d5 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java @@ -0,0 +1,129 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.api.context.ContextShader; +import com.jozufozu.flywheel.api.pipeline.PipelineShader; +import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.gl.GLSLVersion; +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.instancing.indirect.IndirectComponent; +import com.jozufozu.flywheel.core.ComponentRegistry; +import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.source.CompilationContext; +import com.jozufozu.flywheel.event.ReloadRenderersEvent; + +import net.minecraft.resources.ResourceLocation; + +public class FlwCompiler { + + public static final FlwCompiler INSTANCE = new FlwCompiler(); + + public static void onReloadRenderers(ReloadRenderersEvent t) { + + } + + private final ShaderCompiler shaderCompiler = new ShaderCompiler(); + public final Map pipelinePrograms = new HashMap<>(); + + public final Map, GlProgram> cullingPrograms = new HashMap<>(); + + private CompilationEnvironment environment; + + FlwCompiler() { + + } + + public void run() { + environment = new CompilationEnvironment(); + + for (PipelineContext context : environment.pipelineContexts) { + try { + var glProgram = compilePipelineContext(context); + pipelinePrograms.put(context, glProgram); + } catch (ShaderCompilationException e) { + environment.needsCrash = true; + Backend.LOGGER.error(e.errors); + } + } + + for (StructType type : ComponentRegistry.structTypes) { + try { + var glProgram = compileComputeCuller(type); + cullingPrograms.put(type, glProgram); + } catch (ShaderCompilationException e) { + environment.needsCrash = true; + Backend.LOGGER.error(e.errors); + } + } + + environment.finish(); + } + + public GlProgram getPipelineProgram(VertexType vertexType, StructType structType, ContextShader contextShader, PipelineShader pipelineShader) { + return pipelinePrograms.get(new PipelineContext(vertexType, structType, contextShader, pipelineShader)); + } + + public GlProgram getCullingProgram(StructType structType) { + return cullingPrograms.get(structType); + } + + protected GlProgram compilePipelineContext(PipelineContext ctx) throws ShaderCompilationException { + + var glslVersion = ctx.pipelineShader() + .glslVersion(); + + var vertex = new ShaderContext(glslVersion, ShaderType.VERTEX, ctx.getVertexComponents()); + var fragment = new ShaderContext(glslVersion, ShaderType.FRAGMENT, ctx.getFragmentComponents()); + + return ctx.contextShader() + .factory() + .create(new ProgramAssembler().attachShader(shaderCompiler.get(vertex)) + .attachShader(shaderCompiler.get(fragment)) + .link()); + } + + protected GlProgram compileComputeCuller(StructType structType) { + var location = structType.getInstanceShader(); + + var finalSource = new StringBuilder(); + CompilationContext context = new CompilationContext(); + var components = List.of(new IndirectComponent(structType.getLayout().layoutItems), location.getFile(), Components.Pipeline.INDIRECT_CULL.getFile()); + + var names = ImmutableList.builder(); + var included = new LinkedHashSet(); // linked to preserve order + for (var component : components) { + included.addAll(component.included()); + names.add(component.name()); + } + + finalSource.append(CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE)); + for (var include : included) { + finalSource.append(include.source(context)); + } + + for (var component : components) { + finalSource.append(component.source(context)); + } + + try { + var fileLoc = location.getFileLoc(); + var shader = new GlShader(finalSource.toString(), ShaderType.COMPUTE, ImmutableList.of(fileLoc)); + + var program = new ProgramAssembler().attachShader(shader) + .link(); + return new GlProgram(program); + } catch (ShaderCompilationException e) { + throw e.withErrorLog(context); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java new file mode 100644 index 000000000..85bb823c2 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java @@ -0,0 +1,49 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.Collection; +import java.util.List; + +import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.source.CompilationContext; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.generate.GlslExpr; +import com.jozufozu.flywheel.util.ResourceUtil; + +import net.minecraft.resources.ResourceLocation; + +public class FragmentMaterialComponent implements SourceComponent { + + private static final String flw_materialFragment = "flw_materialFragment"; + private static final String flw_discardPredicate = "flw_discardPredicate"; + private static final String flw_fogFilter = "flw_fogFilter"; + + private static final GlslExpr flw_materialFragmentID = GlslExpr.variable(flw_materialFragment + "ID"); + + private final List transformedMaterials; + + public FragmentMaterialComponent(List sourceMaterials) { + + this.transformedMaterials = sourceMaterials.stream() + .map(FileResolution::getFile) + .map(s -> { + var newName = flw_materialFragment + '_' + ResourceUtil.toSafeString(s.name()); + return new TransformedSourceComponent(s, flw_materialFragment, newName); + }) + .toList(); + } + + @Override + public Collection included() { + return transformedMaterials; + } + + @Override + public String source(CompilationContext ctx) { + return null; + } + + @Override + public ResourceLocation name() { + return null; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java new file mode 100644 index 000000000..b074ce19e --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java @@ -0,0 +1,65 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.api.context.ContextShader; +import com.jozufozu.flywheel.api.pipeline.PipelineShader; +import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.api.uniform.UniformProvider; +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.core.ComponentRegistry; +import com.jozufozu.flywheel.core.SourceComponent; + +/** + * Represents the entire context of a program's usage. + * + * @param vertexType The vertexType the program should be adapted for. + * @param structType The instance shader to use. + * @param contextShader The context shader to use. + */ +public record PipelineContext(VertexType vertexType, StructType structType, ContextShader contextShader, + PipelineShader pipelineShader) { + + @NotNull + public Set uniformProviders() { + var fragmentComponents = getFragmentComponents(); + var vertexComponents = getVertexComponents(); + + return Stream.concat(fragmentComponents.stream(), vertexComponents.stream()) + .map(SourceComponent::included) + .flatMap(Collection::stream) + .map(SourceComponent::name) + .mapMulti((component, consumer) -> { + var uniformProvider = ComponentRegistry.getUniformProvider(component); + if (uniformProvider != null) { + consumer.accept(uniformProvider); + } + }) + .collect(Collectors.toSet()); + } + + ImmutableList getVertexComponents() { + var layout = vertexType.getLayoutShader() + .getFile(); + var instanceAssembly = pipelineShader.assemble(vertexType, structType); + var instance = structType.getInstanceShader() + .getFile(); + var context = contextShader.getVertexShader(); + var pipeline = pipelineShader.vertex() + .getFile(); + return ImmutableList.of(layout, instanceAssembly, instance, context, pipeline); + } + + ImmutableList getFragmentComponents() { + var context = contextShader.getFragmentShader(); + var pipeline = pipelineShader.fragment() + .getFile(); + return ImmutableList.of(context, pipeline); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramAssembler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ProgramAssembler.java similarity index 67% rename from src/main/java/com/jozufozu/flywheel/core/compile/ProgramAssembler.java rename to src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ProgramAssembler.java index 8a549859d..75031a9ef 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramAssembler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ProgramAssembler.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.compile; +package com.jozufozu.flywheel.backend.instancing.compile; import static org.lwjgl.opengl.GL11.GL_TRUE; import static org.lwjgl.opengl.GL20.GL_LINK_STATUS; @@ -9,30 +9,26 @@ import static org.lwjgl.opengl.GL20.glGetProgrami; import static org.lwjgl.opengl.GL20.glLinkProgram; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlShader; -import net.minecraft.resources.ResourceLocation; - +@Deprecated public class ProgramAssembler { - public final int program; - private final ResourceLocation name; + private final int program; - public ProgramAssembler(ResourceLocation name) { - this.name = name; + public ProgramAssembler() { this.program = glCreateProgram(); } /** * Links the attached shaders to this program. */ - public ProgramAssembler link() { + public int link() { glLinkProgram(this.program); String log = glGetProgramInfoLog(this.program); if (!log.isEmpty()) { - Backend.LOGGER.debug("Program link log for " + name + ": " + log); + Backend.LOGGER.debug("Program link log: " + log); } int result = glGetProgrami(this.program, GL_LINK_STATUS); @@ -41,15 +37,11 @@ public class ProgramAssembler { throw new RuntimeException("Shader program linking failed, see log for details"); } - return this; + return program; } public ProgramAssembler attachShader(GlShader glShader) { glAttachShader(this.program, glShader.handle()); return this; } - - public GlProgram build(GlProgram.Factory factory) { - return factory.create(name, program); - } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompilationException.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompilationException.java similarity index 92% rename from src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompilationException.java rename to src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompilationException.java index caa848fc0..e66a6a2a2 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompilationException.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompilationException.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.compile; +package com.jozufozu.flywheel.backend.instancing.compile; import org.lwjgl.opengl.GL20; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java new file mode 100644 index 000000000..934ee2bbe --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java @@ -0,0 +1,64 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.backend.gl.GlObject; +import com.jozufozu.flywheel.backend.gl.shader.GlShader; +import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.source.CompilationContext; + +import net.minecraft.resources.ResourceLocation; + +/** + * Handles compilation and deletion of vertex shaders. + */ +public class ShaderCompiler { + + private final Map map = new HashMap<>(); + + ShaderCompiler() { + } + + public GlShader get(ShaderContext key) { + return map.computeIfAbsent(key, this::_create); + } + + protected GlShader _create(ShaderContext key) { + StringBuilder finalSource = new StringBuilder(key.generateHeader()); + finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n"); + finalSource.append("#extension GL_ARB_conservative_depth : enable\n"); + + var ctx = new CompilationContext(); + + var names = ImmutableList.builder(); + var included = new LinkedHashSet(); // linked to preserve order + for (var component : key.sourceComponents()) { + included.addAll(component.included()); + names.add(component.name()); + } + + for (var include : included) { + finalSource.append(include.source(ctx)); + } + + for (var component : key.sourceComponents()) { + finalSource.append(component.source(ctx)); + } + + try { + return new GlShader(finalSource.toString(), key.shaderType(), names.build()); + } catch (ShaderCompilationException e) { + throw e.withErrorLog(ctx); + } + } + + public void invalidate() { + map.values() + .forEach(GlObject::delete); + map.clear(); + } + +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderContext.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderContext.java new file mode 100644 index 000000000..28f04f6d0 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderContext.java @@ -0,0 +1,18 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.List; + +import com.jozufozu.flywheel.backend.gl.GLSLVersion; +import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.core.SourceComponent; + +/** + * @param glslVersion The GLSL version to use. + * @param sourceComponents A list of shader components to stitch together, in order. + */ +public record ShaderContext(GLSLVersion glslVersion, ShaderType shaderType, List sourceComponents) { + + public String generateHeader() { + return CompileUtil.generateHeader(glslVersion, shaderType); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/TransformedSourceComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/TransformedSourceComponent.java new file mode 100644 index 000000000..b6faefa4a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/TransformedSourceComponent.java @@ -0,0 +1,37 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.Collection; + +import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.source.CompilationContext; +import com.jozufozu.flywheel.util.ResourceUtil; + +import net.minecraft.resources.ResourceLocation; + +public final class TransformedSourceComponent implements SourceComponent { + final SourceComponent source; + final String find; + final String replacement; + + public TransformedSourceComponent(SourceComponent source, String find, String replacement) { + this.source = source; + this.find = find; + this.replacement = replacement; + } + + @Override + public String source(CompilationContext ctx) { + return source.source(ctx) + .replace(find, replacement); + } + + @Override + public ResourceLocation name() { + return ResourceUtil.subPath(source.name(), "_renamed"); + } + + @Override + public Collection included() { + return source.included(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java new file mode 100644 index 000000000..87b27e9d9 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java @@ -0,0 +1,71 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.Collection; +import java.util.List; + +import com.jozufozu.flywheel.Flywheel; +import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.source.CompilationContext; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.generate.GlslBuilder; +import com.jozufozu.flywheel.core.source.generate.GlslExpr; +import com.jozufozu.flywheel.util.ResourceUtil; + +import net.minecraft.resources.ResourceLocation; + +public class VertexMaterialComponent implements SourceComponent { + + private static final String flw_materialVertex = "flw_materialVertex"; + private static final GlslExpr flw_materialVertexID = GlslExpr.variable(flw_materialVertex + "ID"); + + private final List transformedMaterials; + + public VertexMaterialComponent(List sourceMaterials) { + + this.transformedMaterials = sourceMaterials.stream() + .map(FileResolution::getFile) + .map(s -> { + var newName = flw_materialVertex + '_' + ResourceUtil.toSafeString(s.name()); + return new TransformedSourceComponent(s, flw_materialVertex, newName); + }) + .toList(); + } + + @Override + public Collection included() { + return transformedMaterials; + } + + @Override + public String source(CompilationContext ctx) { + String out = genSource(); + return ctx.generatedHeader(out, "material adapter") + out; + } + + public String genSource() { + var builder = new GlslBuilder(); + + builder.function() + .returnType("void") + .name("flw_materialVertex") + .body(this::accept); + + return builder.build(); + } + + @Override + public ResourceLocation name() { + return Flywheel.rl("vertex_material_adapter"); + } + + private void accept(GlslBuilder.BlockBuilder body) { + var sw = new GlslBuilder.SwitchBuilder(flw_materialVertexID); + for (int i = 0; i < transformedMaterials.size(); i++) { + var variant = transformedMaterials.get(i).replacement; + + sw.case_(i, b -> b.eval(GlslExpr.call(variant)) + .break_()); + } + body.add(sw.build()); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/package-info.java new file mode 100644 index 000000000..ddcf60e2e --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/package-info.java @@ -0,0 +1,6 @@ +@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend.instancing.compile; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java deleted file mode 100644 index 4efda5bc0..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.indirect; - -import java.util.LinkedHashSet; -import java.util.List; - -import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.backend.gl.GLSLVersion; -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.core.Components; -import com.jozufozu.flywheel.core.SourceComponent; -import com.jozufozu.flywheel.core.compile.CompileUtil; -import com.jozufozu.flywheel.core.compile.Memoizer; -import com.jozufozu.flywheel.core.compile.ProgramAssembler; -import com.jozufozu.flywheel.core.compile.ShaderCompilationException; -import com.jozufozu.flywheel.core.source.CompilationContext; -import com.jozufozu.flywheel.event.ReloadRenderersEvent; - -import net.minecraft.resources.ResourceLocation; - -public class ComputeCullerCompiler extends Memoizer, GlProgram> { - - public static final ComputeCullerCompiler INSTANCE = new ComputeCullerCompiler(); - - private ComputeCullerCompiler() { - } - - @Override - protected GlProgram _create(StructType structType) { - var location = structType.getInstanceShader(); - - var finalSource = new StringBuilder(); - CompilationContext context = new CompilationContext(); - var components = List.of(new IndirectComponent(structType.getLayout().layoutItems), location.getFile(), Components.Pipeline.INDIRECT_CULL.getFile()); - - var names = ImmutableList.builder(); - var included = new LinkedHashSet(); // linked to preserve order - for (var component : components) { - included.addAll(component.included()); - names.add(component.name()); - } - - finalSource.append(CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE)); - for (var include : included) { - finalSource.append(include.source(context)); - } - - for (var component : components) { - finalSource.append(component.source(context)); - } - - try { - var fileLoc = location.getFileLoc(); - var shader = new GlShader(finalSource.toString(), ShaderType.COMPUTE, ImmutableList.of(fileLoc)); - - return new ProgramAssembler(fileLoc).attachShader(shader) - .link() - .build(GlProgram::new); - } catch (ShaderCompilationException e) { - throw e.withErrorLog(context); - } - } - - @Override - protected void _destroy(GlProgram value) { - value.delete(); - } - - public static void invalidateAll(ReloadRenderersEvent ignored) { - INSTANCE.invalidate(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java index 05f772b47..55668c4f7 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java @@ -2,7 +2,6 @@ package com.jozufozu.flywheel.backend.instancing.indirect; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.core.Components; @@ -60,17 +59,13 @@ public class IndirectComponent implements SourceComponent { builder.blankLine(); - var func = builder.function() + builder.function() .returnType(structName) .name("flw_unpackInstance") - .argumentIn(packedStructName, UNPACK_ARG); - - var args = layoutItems.stream() - .map(layoutItem -> layoutItem.unpackField(UNPACKING_VARIABLE)) - .map(GlslExpr::minPrint) - .collect(Collectors.joining(", ")); - - func.statement("return " + structName + "(" + args + ");"); + .argumentIn(packedStructName, UNPACK_ARG) + .body(b -> b.ret(GlslExpr.call(structName, layoutItems.stream() + .map(layoutItem -> layoutItem.unpackField(UNPACKING_VARIABLE)) + .toList()))); return builder.build(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java index fe426247d..9618c0f02 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java @@ -17,11 +17,9 @@ import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.backend.instancing.PipelineCompiler; +import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler; import com.jozufozu.flywheel.core.Components; -import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.QuadConverter; -import com.jozufozu.flywheel.core.uniform.UniformBuffer; public class IndirectCullingGroup { @@ -65,8 +63,8 @@ public class IndirectCullingGroup { .quads2Tris(2048).buffer.handle(); setupVertexArray(); - compute = ComputeCullerCompiler.INSTANCE.get(structType); - draw = PipelineCompiler.INSTANCE.get(new PipelineCompiler.Context(vertexType, Materials.SHULKER, structType, Components.WORLD, Components.INDIRECT)); + compute = FlwCompiler.INSTANCE.getCullingProgram(structType); + draw = FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, Components.WORLD, Components.INDIRECT); } private void setupVertexArray() { @@ -116,9 +114,6 @@ public class IndirectCullingGroup { uploadInstanceData(); uploadIndirectCommands(); - UniformBuffer.getInstance() - .sync(); - compute.bind(); buffers.bindAll(); @@ -137,9 +132,6 @@ public class IndirectCullingGroup { buffers.bindObjectAndTarget(); buffers.bindIndirectBuffer(); - UniformBuffer.getInstance() - .sync(); - memoryBarrier(); drawSet.submit(stage); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java index 2a7f28f8e..84fdf8498 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java @@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.instancing.instancing; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.core.SourceComponent; @@ -68,16 +67,13 @@ public class InstancedArraysComponent implements SourceComponent { builder.blankLine(); - var func = builder.function() + // unpacking function + builder.function() .returnType(structName) - .name("flw_unpackInstance"); - - var args = layoutItems.stream() - .map(it -> new GlslExpr.Variable(it.name() + ATTRIBUTE_SUFFIX)) - .map(GlslExpr::minPrint) - .collect(Collectors.joining(", ")); - - func.statement("return " + structName + "(" + args + ");"); + .name("flw_unpackInstance") + .body(b -> b.ret(GlslExpr.call(structName, layoutItems.stream() + .map(it -> new GlslExpr.Variable(it.name() + ATTRIBUTE_SUFFIX)) + .toList()))); return builder.build(); } 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 47096cb01..89e82c1a4 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 @@ -16,11 +16,10 @@ import com.jozufozu.flywheel.backend.gl.GlStateTracker; import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.InstanceManager; -import com.jozufozu.flywheel.backend.instancing.PipelineCompiler; import com.jozufozu.flywheel.backend.instancing.TaskEngine; +import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.RenderContext; -import com.jozufozu.flywheel.core.uniform.UniformBuffer; import com.jozufozu.flywheel.util.WeakHashSet; import com.mojang.blaze3d.systems.RenderSystem; @@ -124,12 +123,8 @@ public class InstancingEngine implements Engine { var structType = desc.instance(); var material = desc.material(); - var ctx = new PipelineCompiler.Context(vertexType, material, structType, context, Components.INSTANCED_ARRAYS); - - PipelineCompiler.INSTANCE.getProgram(ctx) + FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, context, Components.INSTANCED_ARRAYS) .bind(); - UniformBuffer.getInstance() - .sync(); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java b/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java index 5436279ad..7b8e256dc 100644 --- a/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java +++ b/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java @@ -4,9 +4,12 @@ import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; import org.jetbrains.annotations.Nullable; +import com.jozufozu.flywheel.api.pipeline.PipelineShader; import com.jozufozu.flywheel.backend.BackendType; import com.jozufozu.flywheel.backend.ShadersModHandler; import com.jozufozu.flywheel.backend.SimpleBackendType; @@ -55,6 +58,7 @@ public class BackendTypes { .fallback(() -> BackendTypes.BATCHING) .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance() .instancedArraysSupported()) + .pipelineShader(Components.INSTANCED_ARRAYS) .register(); /** @@ -68,6 +72,7 @@ public class BackendTypes { .fallback(() -> BackendTypes.INSTANCING) .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance() .supportsIndirect()) + .pipelineShader(Components.INDIRECT) .register(); public static BackendType register(BackendType type) { @@ -94,4 +99,12 @@ public class BackendTypes { } + public static Collection availablePipelineShaders() { + return BACKEND_TYPES.values() + .stream() + .filter(BackendType::supported) + .map(BackendType::pipelineShader) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java b/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java index c44251baf..4e0bf6b56 100644 --- a/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java +++ b/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java @@ -3,22 +3,29 @@ package com.jozufozu.flywheel.core; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import org.jetbrains.annotations.Nullable; + +import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.uniform.UniformProvider; import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.api.context.ContextShader; +import com.jozufozu.flywheel.core.source.FileResolution; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; import net.minecraft.resources.ResourceLocation; public class ComponentRegistry { private static final Registry uniformProviders = new Registry<>(); - public static final Set materials = new HashSet<>(); + public static final MaterialRegistry materials = new MaterialRegistry(); public static final Set> structTypes = new HashSet<>(); public static final Set vertexTypes = new HashSet<>(); public static final Set contextShaders = new HashSet<>(); @@ -26,8 +33,7 @@ public class ComponentRegistry { // TODO: fill out the rest of the registry public static T register(T material) { - materials.add(material); - return material; + return materials.add(material); } public static > T register(T type) { @@ -46,7 +52,7 @@ public class ComponentRegistry { } public static T register(T provider) { - return uniformProviders.register(provider.getUniformShader() + return uniformProviders.register(provider.uniformShader() .getFileLoc(), provider); } @@ -54,17 +60,71 @@ public class ComponentRegistry { return Collections.unmodifiableCollection(uniformProviders.objects); } + @Nullable + public static UniformProvider getUniformProvider(ResourceLocation loc) { + return uniformProviders.get(loc); + } + private static class Registry { - private final Set files = new HashSet<>(); + private final Map files = new HashMap<>(); private final List objects = new ArrayList<>(); public O register(ResourceLocation loc, O object) { - if (files.contains(loc)) { + if (files.containsKey(loc)) { throw new IllegalArgumentException("Shader file already registered: " + loc); } - files.add(loc); + files.put(loc, object); objects.add(object); return object; } + + @Nullable + public T get(ResourceLocation loc) { + return files.get(loc); + } + } + + public static class MaterialRegistry { + + private final Set materials = new HashSet<>(); + private final MaterialSources vertexSources = new MaterialSources(); + private final MaterialSources fragmentSources = new MaterialSources(); + + public T add(T material) { + materials.add(material); + + vertexSources.register(material, material.getVertexShader()); + fragmentSources.register(material, material.getFragmentShader()); + + return material; + } + + /** + * @return a list of vertex shader sources where the index in the list is the shader's ID. + */ + public List vertexSources() { + return vertexSources.sourceView; + } + + /** + * @return a list of fragment shader sources where the index in the list is the shader's ID. + */ + public List fragmentSources() { + return fragmentSources.sourceView; + } + + private static class MaterialSources { + private final Set registered = new HashSet<>(); + private final List orderedSources = new ArrayList<>(); + private final Reference2IntMap material2ID = new Reference2IntOpenHashMap<>(); + private final List sourceView = Collections.unmodifiableList(orderedSources); + + public void register(Material material, FileResolution vertexShader) { + if (registered.add(vertexShader)) { + material2ID.put(material, orderedSources.size()); + orderedSources.add(vertexShader); + } + } + } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/DebugRender.java b/src/main/java/com/jozufozu/flywheel/core/DebugRender.java deleted file mode 100644 index 10c8e414c..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/DebugRender.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.jozufozu.flywheel.core; - -import org.lwjgl.opengl.GL46; -import org.lwjgl.system.MemoryStack; - -import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.backend.gl.GlStateTracker; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.core.compile.DebugCompiler; -import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.util.Lazy; -import com.jozufozu.flywheel.util.joml.FrustumIntersection; -import com.mojang.blaze3d.systems.RenderSystem; - -public class DebugRender { - - private static final Lazy SHADER = Lazy.of(() -> DebugCompiler.INSTANCE.get(new DebugCompiler.Context(Files.VERTEX, Files.FRAGMENT))); - - private static final Lazy FRUSTUM_VBO = Lazy.of(Frustum::new); - - public static void init() { - Files.init(); - } - - public static void updateFrustum(FrustumIntersection culler) { - FRUSTUM_VBO.get() - .upload(culler); - } - - public static void drawFrustum() { - if (!FRUSTUM_VBO.isInitialized()) { - return; - } - - RenderSystem.disableCull(); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - - try (var ignored = GlStateTracker.getRestoreState()) { - SHADER.get() - .bind(); - FRUSTUM_VBO.get() - .draw(); - } - } - - public static class Files { - public static final FileResolution VERTEX = FileResolution.get(Flywheel.rl("debug/debug.vert")); - public static final FileResolution FRAGMENT = FileResolution.get(Flywheel.rl("debug/debug.frag")); - - public static void init() { - - } - } - - // FIXME: This never worked (and the thing it was meant to debug is already fixed), - // but it should be a quick turnaround - private static class Frustum { - private static final int[] indices = new int[]{ - 0, 2, 3, 0, 3, 1, - 2, 6, 7, 2, 7, 3, - 6, 4, 5, 6, 5, 7, - 4, 0, 1, 4, 1, 5, - 0, 4, 6, 0, 6, 2, - 1, 5, 7, 1, 7, 3, - }; - - private static final int elementCount = indices.length; - private static final int indicesSize = elementCount * 4; - private static final int verticesSize = 3 * 8 * 4; - private final int buffer; - private final int vao; - - public Frustum() { - // holy moly DSA is nice - buffer = GL46.glCreateBuffers(); - GL46.glNamedBufferStorage(buffer, verticesSize + indicesSize, GL46.GL_DYNAMIC_STORAGE_BIT); - GL46.glNamedBufferSubData(buffer, 0, indices); - - vao = GL46.glCreateVertexArrays(); - GL46.glEnableVertexArrayAttrib(vao, 0); - GL46.glVertexArrayElementBuffer(vao, buffer); - GL46.glVertexArrayVertexBuffer(vao, 0, buffer, indicesSize, 3 * 4); - GL46.glVertexArrayAttribFormat(vao, 0, 3, GL46.GL_FLOAT, false, 0); - } - - public void upload(FrustumIntersection culler) { - try (var stack = MemoryStack.stackPush()) { - var buf = stack.malloc(3 * 8 * 4); - - culler.getCorners(buf); - - GL46.glNamedBufferSubData(buffer, indicesSize, buf); - } - } - - public void draw() { - GL46.glEnableVertexArrayAttrib(vao, 0); - GL46.glVertexArrayElementBuffer(vao, buffer); - GL46.glBindVertexArray(vao); - GL46.glDrawElements(GL46.GL_TRIANGLES, elementCount, GL46.GL_UNSIGNED_INT, 0); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/WorldProgram.java b/src/main/java/com/jozufozu/flywheel/core/WorldProgram.java index 0be9030ce..4d53fb194 100644 --- a/src/main/java/com/jozufozu/flywheel/core/WorldProgram.java +++ b/src/main/java/com/jozufozu/flywheel/core/WorldProgram.java @@ -2,8 +2,6 @@ package com.jozufozu.flywheel.core; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import net.minecraft.resources.ResourceLocation; - public class WorldProgram extends GlProgram { // TODO: sampler registry? @@ -11,8 +9,8 @@ public class WorldProgram extends GlProgram { protected int overlayTex; protected int lightTex; - public WorldProgram(ResourceLocation name, int handle) { - super(name, handle); + public WorldProgram(int handle) { + super(handle); bind(); registerSamplers(); diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java deleted file mode 100644 index 322d2777f..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.jozufozu.flywheel.core.compile; - -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.gl.shader.GlShader; -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; -import com.jozufozu.flywheel.core.source.CompilationContext; -import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.event.ReloadRenderersEvent; - -/** - * Simple shader compiler that pulls no excessive tricks.

- * Useful for writing experimental shaders or - */ -public class DebugCompiler extends Memoizer { - - public static final DebugCompiler INSTANCE = new DebugCompiler(); - - private final ShaderCompiler shaderCompiler; - - private DebugCompiler() { - this.shaderCompiler = new ShaderCompiler(); - } - - @Override - public void invalidate() { - super.invalidate(); - shaderCompiler.invalidate(); - } - - @Override - protected GlProgram _create(DebugCompiler.Context ctx) { - - return new ProgramAssembler(ctx.vertex.getFileLoc()) - .attachShader(shaderCompiler.vertex(ctx.vertex)) - .attachShader(shaderCompiler.fragment(ctx.fragment)) - .link() - .build(GlProgram::new); - } - - @Override - protected void _destroy(GlProgram value) { - value.delete(); - } - - public static void invalidateAll(ReloadRenderersEvent ignored) { - INSTANCE.invalidate(); - } - - public record Context(FileResolution vertex, FileResolution fragment) { - } - - /** - * Handles compilation and deletion of vertex shaders. - */ - private static class ShaderCompiler extends Memoizer { - - public GlShader vertex(FileResolution source) { - return get(new Context(source, ShaderType.VERTEX)); - } - - public GlShader fragment(FileResolution source) { - return get(new Context(source, ShaderType.FRAGMENT)); - } - - @Override - protected GlShader _create(Context ctx) { - var index = new CompilationContext(); - - StringBuilder source = new StringBuilder(CompileUtil.generateHeader(GLSLVersion.V420, ctx.type)); - - var file = ctx.source.getFile(); - for (var include : file.flattenedImports) { - source.append(include.source(index)); - } - - source.append(file.source(index)); - - try { - return new GlShader(source.toString(), ctx.type, ImmutableList.of(ctx.source.getFileLoc())); - } catch (ShaderCompilationException e) { - throw e.withErrorLog(index); - } - } - - @Override - protected void _destroy(GlShader value) { - value.delete(); - } - - public record Context(FileResolution source, ShaderType type) { - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/Memoizer.java b/src/main/java/com/jozufozu/flywheel/core/compile/Memoizer.java deleted file mode 100644 index f2dbc95f1..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/compile/Memoizer.java +++ /dev/null @@ -1,22 +0,0 @@ -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/crumbling/CrumblingProgram.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingProgram.java index 777112ee6..f5be39ec6 100644 --- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingProgram.java +++ b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingProgram.java @@ -2,11 +2,9 @@ package com.jozufozu.flywheel.core.crumbling; import com.jozufozu.flywheel.core.WorldProgram; -import net.minecraft.resources.ResourceLocation; - public class CrumblingProgram extends WorldProgram { - public CrumblingProgram(ResourceLocation name, int handle) { - super(name, handle); + public CrumblingProgram(int handle) { + super(handle); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java b/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java index c962694d3..1f40d5ab5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java @@ -27,11 +27,11 @@ public class CompilationContext { generatedLines += lines; - if (comment != null) { - out += " // " + comment; + if (comment == null) { + comment = ""; } - return out + '\n'; + return out + " // (generated) " + comment + '\n'; } public boolean contains(SourceFile sourceFile) { diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java index b90528ec9..8b8161145 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java @@ -80,7 +80,7 @@ public class SourceFile implements SourceComponent { @Override public String source(CompilationContext ctx) { - return ctx.sourceHeader(this) + this.elideImports(); + return ctx.sourceHeader(this) + this.genFinalSource(); } @Override @@ -188,7 +188,7 @@ public class SourceFile implements SourceComponent { return "Source for shader '" + name + "':\n" + lines.printLinesWithNumbers(); } - private CharSequence elideImports() { + private CharSequence genFinalSource() { StringBuilder out = new StringBuilder(); int lastEnd = 0; diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java index b8d3bbd2a..ef31652f9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java @@ -2,13 +2,15 @@ package com.jozufozu.flywheel.core.source.generate; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import java.util.stream.Collectors; import com.jozufozu.flywheel.util.Pair; public class GlslBuilder { + public static final String INDENT = " "; - private final List elements = new ArrayList<>(); + private final List elements = new ArrayList<>(); public void define(String name, String value) { add(new Define(name, value)); @@ -26,7 +28,7 @@ public class GlslBuilder { return add(new VertexInputBuilder()); } - public T add(T element) { + public T add(T element) { elements.add(element); return element; } @@ -37,15 +39,19 @@ public class GlslBuilder { public String build() { return elements.stream() - .map(SourceElement::build) + .map(GlslRootElement::minPrint) .collect(Collectors.joining("\n")); } - public interface SourceElement { - String build(); + public static String indent(int indentation) { + return INDENT.repeat(indentation); } - public enum Separators implements SourceElement { + public interface GlslRootElement { + String minPrint(); + } + + public enum Separators implements GlslRootElement { BLANK_LINE(""), ; @@ -54,21 +60,21 @@ public class GlslBuilder { Separators(String separator) { this.separator = separator; } + @Override - public String build() { + public String minPrint() { return separator; } - } - public record Define(String name, String value) implements SourceElement { + public record Define(String name, String value) implements GlslRootElement { @Override - public String build() { + public String minPrint() { return "#define " + name + " " + value; } } - public static class VertexInputBuilder implements SourceElement { + public static class VertexInputBuilder implements GlslRootElement { private int binding; private String type; @@ -90,12 +96,12 @@ public class GlslBuilder { } @Override - public String build() { + public String minPrint() { return "layout(location = " + binding + ") in " + type + " " + name + ";"; } } - public static class StructBuilder implements SourceElement { + public static class StructBuilder implements GlslRootElement { private final List> fields = new ArrayList<>(); private String name; @@ -110,11 +116,11 @@ public class GlslBuilder { private String buildFields() { return fields.stream() - .map(p -> '\t' + p.first() + ' ' + p.second() + ';') + .map(p -> INDENT + p.first() + ' ' + p.second() + ';') .collect(Collectors.joining("\n")); } - public String build() { + public String minPrint() { return """ struct %s { %s @@ -123,9 +129,9 @@ public class GlslBuilder { } } - public static class FunctionBuilder implements SourceElement { + public static class FunctionBuilder implements GlslRootElement { private final List> arguments = new ArrayList<>(); - private final List body = new ArrayList<>(); + private final BlockBuilder body = new BlockBuilder(); private String returnType; private String name; @@ -149,24 +155,17 @@ public class GlslBuilder { return this; } - public FunctionBuilder statement(String statement) { - this.body.add(statement); + public FunctionBuilder body(Consumer f) { + f.accept(body); return this; } - - public String build() { + public String minPrint() { return """ %s %s(%s) { %s } - """.formatted(returnType, name, buildArguments(), buildBody()); - } - - private String buildBody() { - return body.stream() - .map(s -> '\t' + s) - .collect(Collectors.joining("\n")); + """.formatted(returnType, name, buildArguments(), body.prettyPrint()); } private String buildArguments() { @@ -175,4 +174,61 @@ public class GlslBuilder { .collect(Collectors.joining(", ")); } } + + public static class BlockBuilder implements LangItem { + private final List body = new ArrayList<>(); + + public BlockBuilder add(GlslStmt stmt) { + body.add(stmt); + return this; + } + + public BlockBuilder eval(GlslExpr expr) { + return add(GlslStmt.eval(expr)); + } + + public BlockBuilder switchOn(GlslExpr expr, Consumer f) { + var builder = new SwitchBuilder(expr); + f.accept(builder); + return add(builder.build()); + } + + public void ret(GlslExpr call) { + add(GlslStmt.ret(call)); + } + + public void break_() { + add(GlslStmt.BREAK); + } + + @Override + public String prettyPrint() { + return body.stream() + .map(GlslStmt::prettyPrint) + .collect(Collectors.joining("\n")); + } + + } + + public static class SwitchBuilder { + + private final GlslExpr on; + + private final List> cases = new ArrayList<>(); + + public SwitchBuilder(GlslExpr on) { + this.on = on; + } + + public SwitchBuilder case_(int expr, Consumer f) { + var builder = new BlockBuilder(); + f.accept(builder); + cases.add(Pair.of(GlslExpr.literal(expr), builder)); + return this; + } + + public GlslStmt.Switch build() { + return new GlslStmt.Switch(on, cases); + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java index 7ae03952b..5046e0afb 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java @@ -1,8 +1,12 @@ package com.jozufozu.flywheel.core.source.generate; +import java.util.Collection; import java.util.function.Function; +import java.util.stream.Collectors; -public sealed interface GlslExpr { +import com.google.common.collect.ImmutableList; + +public interface GlslExpr extends LangItem { /** * Create a glsl variable with the given name. @@ -14,7 +18,17 @@ public sealed interface GlslExpr { return new Variable(name); } - String minPrint(); + static FunctionCall call(String functionName, Collection args) { + return new FunctionCall(functionName, args); + } + + static FunctionCall0 call(String functionName) { + return new FunctionCall0(functionName); + } + + static GlslExpr literal(int expr) { + return new Literal(expr); + } /** * Call a one-parameter function with the given name on this expression. @@ -58,29 +72,55 @@ public sealed interface GlslExpr { record Variable(String name) implements GlslExpr { @Override - public String minPrint() { + public String prettyPrint() { return name; } + } - record FunctionCall(String name, GlslExpr target) implements GlslExpr { - @Override - public String minPrint() { - return name + "(" + target.minPrint() + ")"; + record FunctionCall(String name, Collection args) implements GlslExpr { + public FunctionCall(String name, GlslExpr target) { + this(name, ImmutableList.of(target)); } + + @Override + public String prettyPrint() { + var args = this.args.stream() + .map(GlslExpr::prettyPrint) + .collect(Collectors.joining(",")); + return name + "(" + args + ")"; + } + + } + + record FunctionCall0(String name) implements GlslExpr { + @Override + public String prettyPrint() { + return name + "()"; + } + } record Swizzle(GlslExpr target, String selection) implements GlslExpr { @Override - public String minPrint() { - return target.minPrint() + "." + selection; + public String prettyPrint() { + return target.prettyPrint() + "." + selection; } + } record Access(GlslExpr target, String argName) implements GlslExpr { @Override - public String minPrint() { - return target.minPrint() + "." + argName; + public String prettyPrint() { + return target.prettyPrint() + "." + argName; + } + + } + + record Literal(int value) implements GlslExpr { + @Override + public String prettyPrint() { + return Integer.toString(value); } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java new file mode 100644 index 000000000..241184112 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java @@ -0,0 +1,60 @@ +package com.jozufozu.flywheel.core.source.generate; + +import java.util.List; +import java.util.stream.Collectors; + +import com.jozufozu.flywheel.util.Pair; + +public interface GlslStmt extends LangItem { + + static GlslStmt eval(GlslExpr expr) { + return new Eval(expr); + } + + static GlslStmt ret(GlslExpr value) { + return new Return(value); + } + + static GlslStmt BREAK = () -> "break;"; + + static GlslStmt CONTINUE = () -> "continue;"; + + static GlslStmt RETURN = () -> "return;"; + + record Eval(GlslExpr expr) implements GlslStmt { + @Override + public String prettyPrint() { + return expr.prettyPrint() + ";"; + } + } + + record Return(GlslExpr expr) implements GlslStmt { + @Override + public String prettyPrint() { + return "return " + expr.prettyPrint() + ";"; + } + } + + record Switch(GlslExpr expr, List> body) implements GlslStmt { + @Override + public String prettyPrint() { + var cases = body.stream() + .map(Switch::prettyPrintCase) + .collect(Collectors.joining("\n")); + return """ + switch (%s) { + %s + }""".formatted(expr.prettyPrint(), cases); + } + + private static String prettyPrintCase(Pair p) { + var variant = p.first() + .prettyPrint(); + var block = p.second() + .prettyPrint(); + return """ + case %s: + %s""".formatted(variant, block); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/LangItem.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/LangItem.java new file mode 100644 index 000000000..0ae9d4e6c --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/LangItem.java @@ -0,0 +1,7 @@ +package com.jozufozu.flywheel.core.source.generate; + +public interface LangItem { + + String prettyPrint(); + +} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/package-info.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/package-info.java similarity index 76% rename from src/main/java/com/jozufozu/flywheel/core/compile/package-info.java rename to src/main/java/com/jozufozu/flywheel/core/source/generate/package-info.java index d81aeffbb..6fa0c353e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/package-info.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/package-info.java @@ -1,5 +1,5 @@ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.jozufozu.flywheel.core.compile; +package com.jozufozu.flywheel.core.source.generate; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java index 05cfdc8b3..c45806ace 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java @@ -7,33 +7,59 @@ import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.source.FileResolution; import com.mojang.blaze3d.systems.RenderSystem; -public class FogProvider extends UniformProvider { +public class FogProvider implements UniformProvider { + + public static boolean FOG_UPDATE = true; @Override - public int getActualByteSize() { + public int byteSize() { return 16 + 8 + 4; } - public void update() { - if (ptr == MemoryUtil.NULL) { - return; - } - - var color = RenderSystem.getShaderFogColor(); - - MemoryUtil.memPutFloat(ptr, color[0]); - MemoryUtil.memPutFloat(ptr + 4, color[1]); - MemoryUtil.memPutFloat(ptr + 8, color[2]); - MemoryUtil.memPutFloat(ptr + 12, color[3]); - MemoryUtil.memPutFloat(ptr + 16, RenderSystem.getShaderFogStart()); - MemoryUtil.memPutFloat(ptr + 20, RenderSystem.getShaderFogEnd()); - MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape().getIndex()); - - notifier.signalChanged(); + @Override + public FileResolution uniformShader() { + return Components.Files.FOG_UNIFORMS; } @Override - public FileResolution getUniformShader() { - return Components.Files.FOG_UNIFORMS; + public ActiveUniformProvider activate(long ptr, Notifier notifier) { + return new Active(ptr, notifier); + } + + public static class Active implements ActiveUniformProvider { + + private final long ptr; + private final Notifier notifier; + + public Active(long ptr, Notifier notifier) { + this.ptr = ptr; + this.notifier = notifier; + } + + @Override + public void delete() { + } + + @Override + public void poll() { + if (!FOG_UPDATE) { + return; + } + + var color = RenderSystem.getShaderFogColor(); + + MemoryUtil.memPutFloat(ptr, color[0]); + MemoryUtil.memPutFloat(ptr + 4, color[1]); + MemoryUtil.memPutFloat(ptr + 8, color[2]); + MemoryUtil.memPutFloat(ptr + 12, color[3]); + MemoryUtil.memPutFloat(ptr + 16, RenderSystem.getShaderFogStart()); + MemoryUtil.memPutFloat(ptr + 20, RenderSystem.getShaderFogEnd()); + MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape() + .getIndex()); + + notifier.signalChanged(); + + FOG_UPDATE = false; + } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java index 0f8346cad..58d3d1474 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java @@ -1,5 +1,7 @@ package com.jozufozu.flywheel.core.uniform; +import java.util.function.Consumer; + import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.api.uniform.UniformProvider; @@ -13,47 +15,71 @@ import net.minecraft.core.Vec3i; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.MinecraftForge; -public class FrustumProvider extends UniformProvider { +public class FrustumProvider implements UniformProvider { public static boolean PAUSED = false; public static boolean CAPTURE = false; - public FrustumProvider() { - MinecraftForge.EVENT_BUS.addListener(this::beginFrame); - } - @Override - public int getActualByteSize() { + public int byteSize() { return 96; } @Override - public FileResolution getUniformShader() { + public FileResolution uniformShader() { return Components.Files.FRUSTUM_UNIFORMS; } - public void beginFrame(BeginFrameEvent event) { - update(event.getContext()); + @Override + public ActiveUniformProvider activate(long ptr, Notifier notifier) { + return new Active(ptr, notifier); } - public void update(RenderContext context) { - if (ptr == MemoryUtil.NULL || (PAUSED && !CAPTURE)) { - return; + static class Active implements ActiveUniformProvider, Consumer { + + private final long ptr; + private final Notifier notifier; + + public Active(long ptr, Notifier notifier) { + this.ptr = ptr; + this.notifier = notifier; + MinecraftForge.EVENT_BUS.addListener(this); } - Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(context.level()); - Vec3 camera = context.camera() - .getPosition(); + @Override + public void delete() { + MinecraftForge.EVENT_BUS.unregister(this); + } - var camX = (float) (camera.x - originCoordinate.getX()); - var camY = (float) (camera.y - originCoordinate.getY()); - var camZ = (float) (camera.z - originCoordinate.getZ()); + @Override + public void poll() { - var shiftedCuller = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ); + } - shiftedCuller.getJozuPackedPlanes(ptr); + @Override + public void accept(BeginFrameEvent event) { + update(event.getContext()); + } - notifier.signalChanged(); - CAPTURE = false; + public void update(RenderContext context) { + if (ptr == MemoryUtil.NULL || (PAUSED && !CAPTURE)) { + return; + } + + Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(context.level()); + Vec3 camera = context.camera() + .getPosition(); + + var camX = (float) (camera.x - originCoordinate.getX()); + var camY = (float) (camera.y - originCoordinate.getY()); + var camZ = (float) (camera.z - originCoordinate.getZ()); + + var shiftedCuller = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ); + + shiftedCuller.getJozuPackedPlanes(ptr); + + notifier.signalChanged(); + CAPTURE = false; + } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java index e3ecee4ab..24d805012 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java @@ -45,7 +45,7 @@ public class UniformBuffer { int totalBytes = 0; int index = 0; for (UniformProvider provider : providers) { - int size = alignPo2(provider.getActualByteSize(), 16); + int size = align16(provider.byteSize()); builder.add(new Allocated(provider, totalBytes, size, index)); @@ -64,6 +64,7 @@ public class UniformBuffer { } public void sync() { + allocatedProviders.forEach(Allocated::pollActive); if (changedBytes.isEmpty()) { return; } @@ -88,8 +89,8 @@ public class UniformBuffer { } } - private static int alignPo2(int numToRound, int alignment) { - return (numToRound + alignment - 1) & -alignment; + private static int align16(int numToRound) { + return (numToRound + 16 - 1) & -16; } private class Allocated implements UniformProvider.Notifier { @@ -97,6 +98,7 @@ public class UniformBuffer { private final int offset; private final int size; private final int index; + private UniformProvider.ActiveUniformProvider activeProvider; private Allocated(UniformProvider provider, int offset, int size, int index) { this.provider = provider; @@ -111,7 +113,10 @@ public class UniformBuffer { } private void updatePtr(MemoryBlock bufferBase) { - provider.updatePtr(bufferBase.ptr() + offset, this); + if (activeProvider != null) { + activeProvider.delete(); + } + activeProvider = provider.activate(bufferBase.ptr() + offset, this); } public UniformProvider provider() { @@ -129,5 +134,11 @@ public class UniformBuffer { public int index() { return index; } + + public void pollActive() { + if (activeProvider != null) { + activeProvider.poll(); + } + } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java index 89175710e..9c82bf86f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java @@ -1,5 +1,7 @@ package com.jozufozu.flywheel.core.uniform; +import java.util.function.Consumer; + import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.api.uniform.UniformProvider; @@ -15,54 +17,75 @@ import net.minecraft.core.Vec3i; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.MinecraftForge; -public class ViewProvider extends UniformProvider { +public class ViewProvider implements UniformProvider { - public ViewProvider() { - MinecraftForge.EVENT_BUS.addListener(this::beginFrame); - } + public static final int SIZE = 4 * 16 + 16 + 4; - public void beginFrame(BeginFrameEvent event) { - update(event.getContext()); + @Override + public int byteSize() { + return SIZE; } @Override - public int getActualByteSize() { - return 4 * 16 + 16 + 4; - } - - public void update(RenderContext context) { - if (ptr == MemoryUtil.NULL) { - return; - } - - ClientLevel level = context.level(); - - int constantAmbientLight = level.effects() - .constantAmbientLight() ? 1 : 0; - - Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(level); - Vec3 camera = context.camera() - .getPosition(); - - var camX = (float) (camera.x - originCoordinate.getX()); - var camY = (float) (camera.y - originCoordinate.getY()); - var camZ = (float) (camera.z - originCoordinate.getZ()); - - // don't want to mutate viewProjection - var vp = context.viewProjection().copy(); - vp.multiplyWithTranslation(-camX, -camY, -camZ); - - MatrixWrite.writeUnsafe(vp, ptr); - MemoryUtil.memPutFloat(ptr + 64, camX); - MemoryUtil.memPutFloat(ptr + 68, camY); - MemoryUtil.memPutFloat(ptr + 72, camZ); - MemoryUtil.memPutInt(ptr + 76, constantAmbientLight); - - notifier.signalChanged(); - } - - @Override - public FileResolution getUniformShader() { + public FileResolution uniformShader() { return Components.Files.VIEW_UNIFORMS; } + + @Override + public ActiveUniformProvider activate(long ptr, Notifier notifier) { + return new Active(ptr, notifier); + } + + public static class Active implements ActiveUniformProvider, Consumer { + private final long ptr; + private final Notifier notifier; + + public Active(long ptr, Notifier notifier) { + this.ptr = ptr; + this.notifier = notifier; + MinecraftForge.EVENT_BUS.addListener(this); + } + + @Override + public void delete() { + MinecraftForge.EVENT_BUS.unregister(this); + } + + @Override + public void poll() { + } + + @Override + public void accept(BeginFrameEvent event) { + update(event.getContext()); + } + + public void update(RenderContext context) { + ClientLevel level = context.level(); + + int constantAmbientLight = level.effects() + .constantAmbientLight() ? 1 : 0; + + Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(level); + Vec3 camera = context.camera() + .getPosition(); + + var camX = (float) (camera.x - originCoordinate.getX()); + var camY = (float) (camera.y - originCoordinate.getY()); + var camZ = (float) (camera.z - originCoordinate.getZ()); + + // don't want to mutate viewProjection + var vp = context.viewProjection() + .copy(); + vp.multiplyWithTranslation(-camX, -camY, -camZ); + + MatrixWrite.writeUnsafe(vp, ptr); + MemoryUtil.memPutFloat(ptr + 64, camX); + MemoryUtil.memPutFloat(ptr + 68, camY); + MemoryUtil.memPutFloat(ptr + 72, camZ); + MemoryUtil.memPutInt(ptr + 76, constantAmbientLight); + + notifier.signalChanged(); + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java index 832949e1a..061b297bf 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java @@ -5,14 +5,14 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.uniform.FogProvider; import net.minecraft.client.renderer.FogRenderer; @Mixin(FogRenderer.class) public class FogUpdateMixin { private static void flywheel$updateFog() { - Components.FOG_PROVIDER.update(); + FogProvider.FOG_UPDATE = true; } @Inject(method = "setupNoFog", at = @At("TAIL")) diff --git a/src/main/java/com/jozufozu/flywheel/util/Pair.java b/src/main/java/com/jozufozu/flywheel/util/Pair.java index 6b3a48d7d..bc7dd61bb 100644 --- a/src/main/java/com/jozufozu/flywheel/util/Pair.java +++ b/src/main/java/com/jozufozu/flywheel/util/Pair.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.util; import java.util.Objects; +import java.util.function.Function; public record Pair(F first, S second) { @@ -8,6 +9,10 @@ public record Pair(F first, S second) { return new Pair<>(first, second); } + public static Function, Pair> both(Function map) { + return pair -> of(map.apply(pair.first), map.apply(pair.second)); + } + public Pair swap() { return Pair.of(second, first); } diff --git a/src/main/java/com/jozufozu/flywheel/util/ResourceUtil.java b/src/main/java/com/jozufozu/flywheel/util/ResourceUtil.java index 476ff33c8..c846f4203 100644 --- a/src/main/java/com/jozufozu/flywheel/util/ResourceUtil.java +++ b/src/main/java/com/jozufozu/flywheel/util/ResourceUtil.java @@ -1,9 +1,14 @@ package com.jozufozu.flywheel.util; +import java.util.regex.Pattern; + import net.minecraft.resources.ResourceLocation; public class ResourceUtil { + // Match the complement of alphanumeric and underscore. + private static final Pattern UNSAFE_CHARS = Pattern.compile("[^a-zA-Z0-9_]"); + public static ResourceLocation subPath(ResourceLocation root, String subPath) { return new ResourceLocation(root.getNamespace(), root.getPath() + subPath); } @@ -17,4 +22,9 @@ public class ResourceUtil { String path = loc.getPath(); return new ResourceLocation(loc.getNamespace(), path.substring(prefix.length(), path.length() - suffix.length())); } + + public static String toSafeString(ResourceLocation rl) { + return UNSAFE_CHARS.matcher(rl.toString()) + .replaceAll("_"); + } } diff --git a/src/main/resources/assets/flywheel/flywheel/api/fragment.glsl b/src/main/resources/assets/flywheel/flywheel/api/fragment.glsl index 11be92a1e..a8028e8b9 100644 --- a/src/main/resources/assets/flywheel/flywheel/api/fragment.glsl +++ b/src/main/resources/assets/flywheel/flywheel/api/fragment.glsl @@ -13,6 +13,8 @@ in vec4 flw_var1; in vec4 flw_var2; in vec4 flw_var3; +flat in uint flw_materialFragmentID; + // /*const*/ vec4 flw_sampleColor; diff --git a/src/main/resources/assets/flywheel/flywheel/api/vertex.glsl b/src/main/resources/assets/flywheel/flywheel/api/vertex.glsl index c00b99cbd..f823366de 100644 --- a/src/main/resources/assets/flywheel/flywheel/api/vertex.glsl +++ b/src/main/resources/assets/flywheel/flywheel/api/vertex.glsl @@ -1,4 +1,6 @@ #ifdef VERTEX_SHADER +uint flw_materialVertexID; + out vec4 flw_vertexPos; out vec4 flw_vertexColor; out vec2 flw_vertexTexCoord; @@ -12,4 +14,5 @@ out vec4 flw_var0; out vec4 flw_var1; out vec4 flw_var2; out vec4 flw_var3; +flat out uint flw_materialFragmentID; #endif diff --git a/src/main/resources/assets/flywheel/flywheel/compute/mat.glsl b/src/main/resources/assets/flywheel/flywheel/compute/mat.glsl new file mode 100644 index 000000000..4e0f5f8d1 --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/compute/mat.glsl @@ -0,0 +1,50 @@ +/* +This is what generated ubershaders should look like + +uint flw_materialVertexID = 0; +uint flw_materialFragmentID = 0; + +void flw_materialVertex() { + switch (flw_materialVertexID) { + case 0: flw_materialVertex_flywheel_cutout_vert(); break; + default: break; + } +} + +void flw_materialFragment() { + switch (flw_materialFragmentID) { + case 0: flw_materialFragment_flywheel_cutout_frag(); break; + default: break; + } +} + +bool flw_discardPredicate(vec4 finalColor) { + switch (flw_materialFragmentID) { + case 0: return flw_discardPredicate_flywheel_cutout_frag(finalColor); + default: return false; + } +} + +vec4 flw_fogFilter(vec4 color) { + switch (flw_materialFragmentID) { + case 0: return flw_fogFilter_flywheel_cutout_frag(color); + default: return color; + } +} + + +void flw_materialVertex_flywheel_cutout_vert() { +} + +void flw_materialFragment_flywheel_cutout_frag() { +} + +bool flw_discardPredicate_flywheel_cutout_frag(vec4 finalColor) { + return finalColor.a < 0.1; +} + +vec4 flw_fogFilter_flywheel_cutout_frag(vec4 color) { + return linear_fog(color, flw_distance, flw_fogRange.x, flw_fogRange.y, flw_fogColor); +} + +*/ diff --git a/src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl b/src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl index 2acbef9e1..8fc8ede95 100644 --- a/src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl +++ b/src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl @@ -1,5 +1,4 @@ -layout(std140, binding = 1) uniform flw_fog { - vec4 flw_fogColor; - vec2 flw_fogRange; - int flw_fogShape; -}; +// TODO: Transform uniform shaders +vec4 flw_fogColor; +vec2 flw_fogRange; +int flw_fogShape; diff --git a/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl b/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl index 39866a922..b619082cd 100644 --- a/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl +++ b/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl @@ -9,6 +9,4 @@ struct FLWPackedPlanes { vec2 zW; // }; -layout(std140, binding = 2) uniform FLWFrustum { - FLWPackedPlanes flw_planes; -}; +FLWPackedPlanes flw_planes; diff --git a/src/main/resources/assets/flywheel/flywheel/uniform/view.glsl b/src/main/resources/assets/flywheel/flywheel/uniform/view.glsl index 52170bccd..467d3fee9 100644 --- a/src/main/resources/assets/flywheel/flywheel/uniform/view.glsl +++ b/src/main/resources/assets/flywheel/flywheel/uniform/view.glsl @@ -1,5 +1,3 @@ -layout(std140, binding = 0) uniform flw_view { - mat4 flw_viewProjection; - vec4 flw_cameraPos; - int flw_constantAmbientLight; -}; +mat4 flw_viewProjection; +vec4 flw_cameraPos; +int flw_constantAmbientLight; From d0430762689da8a5beb63b79806a376bcefd7839 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Sat, 8 Oct 2022 14:02:54 -0700 Subject: [PATCH 2/9] Taxi shaders - Not *quite* ubershaders yet - Note: heavily broken - "Pull" based compilation - Sources are only ready when they are needed by the compiler - Compiler is responsible for import resolution - Compiler prepends file headers - Reduces need for FileResolution - May replace with ResourceLocations? - Not sure about the future of source checks - TODO: Lots of dead code left in FileResolution - PipelineShader -> Pipeline interface + Simple impl - Use Context object for assembler factory --- .../flywheel/api/context/ContextShader.java | 8 - .../{PipelineShader.java => Pipeline.java} | 20 +- .../flywheel/backend/BackendType.java | 4 +- .../com/jozufozu/flywheel/backend/Loader.java | 30 +-- .../flywheel/backend/SimpleBackendType.java | 12 +- .../compile/CompilationEnvironment.java | 59 ------ .../instancing/compile/FlwCompiler.java | 185 +++++++++++++---- .../compile/FragmentMaterialComponent.java | 34 +-- .../compile/MaterialAdapterComponent.java | 87 ++++++++ .../instancing/compile/PipelineContext.java | 52 +---- .../RenamedFunctionsSourceComponent.java | 49 +++++ .../instancing/compile/ShaderCompiler.java | 64 ------ .../instancing/compile/ShaderContext.java | 18 -- .../compile/TransformedSourceComponent.java | 37 ---- .../compile/VertexMaterialComponent.java | 54 +---- .../indirect/IndirectComponent.java | 25 ++- .../indirect/IndirectCullingGroup.java | 3 +- .../instancing/InstancedArraysComponent.java | 16 +- .../instancing/InstancingEngine.java | 4 +- .../jozufozu/flywheel/core/BackendTypes.java | 8 +- .../flywheel/core/ComponentRegistry.java | 2 +- .../jozufozu/flywheel/core/Components.java | 22 +- .../com/jozufozu/flywheel/core/Pipelines.java | 40 ++++ .../flywheel/core/SourceComponent.java | 4 +- .../core/pipeline/SimplePipeline.java | 86 ++++++++ .../core/source/CompilationContext.java | 2 +- .../flywheel/core/source/FileResolution.java | 45 +--- .../core/source/ShaderLoadingException.java | 4 + .../flywheel/core/source/ShaderSources.java | 101 +++++---- .../flywheel/core/source/SourceFile.java | 195 ++++++++---------- .../flywheel/core/source/SourceFinder.java | 15 -- .../flywheel/core/source/SourceLines.java | 32 ++- .../core/source/error/ErrorBuilder.java | 2 +- .../core/source/error/ErrorReporter.java | 38 ++-- .../source/parse/AbstractShaderElement.java | 13 -- .../flywheel/core/source/parse/Import.java | 45 +--- .../core/source/parse/ShaderField.java | 5 +- .../core/source/parse/ShaderFunction.java | 5 +- .../core/source/parse/ShaderStruct.java | 5 +- .../core/source/parse/ShaderVariable.java | 5 +- .../core/source/parse/StructField.java | 5 +- .../flywheel/core/source/span/Span.java | 2 +- .../flywheel/core/source/span/StringSpan.java | 3 +- .../jozufozu/flywheel/util/ResourceUtil.java | 5 + .../jozufozu/flywheel/util/StringUtil.java | 12 +- 45 files changed, 703 insertions(+), 759 deletions(-) rename src/main/java/com/jozufozu/flywheel/api/pipeline/{PipelineShader.java => Pipeline.java} (53%) delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationEnvironment.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RenamedFunctionsSourceComponent.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderContext.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/TransformedSourceComponent.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/Pipelines.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/pipeline/SimplePipeline.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/source/SourceFinder.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/source/parse/AbstractShaderElement.java diff --git a/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java b/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java index 37e9320ed..3074ff20d 100644 --- a/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java +++ b/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java @@ -2,15 +2,7 @@ package com.jozufozu.flywheel.api.context; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.core.source.SourceFile; public record ContextShader(GlProgram.Factory factory, FileResolution vertexShader, FileResolution fragmentShader) { - public SourceFile getVertexShader() { - return vertexShader.getFile(); - } - - public SourceFile getFragmentShader() { - return fragmentShader.getFile(); - } } diff --git a/src/main/java/com/jozufozu/flywheel/api/pipeline/PipelineShader.java b/src/main/java/com/jozufozu/flywheel/api/pipeline/Pipeline.java similarity index 53% rename from src/main/java/com/jozufozu/flywheel/api/pipeline/PipelineShader.java rename to src/main/java/com/jozufozu/flywheel/api/pipeline/Pipeline.java index f33c3b006..6e5b2460e 100644 --- a/src/main/java/com/jozufozu/flywheel/api/pipeline/PipelineShader.java +++ b/src/main/java/com/jozufozu/flywheel/api/pipeline/Pipeline.java @@ -1,27 +1,27 @@ package com.jozufozu.flywheel.api.pipeline; -import java.util.function.BiFunction; - import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.ShaderSources; -public record PipelineShader(GLSLVersion glslVersion, FileResolution vertex, FileResolution fragment, - InstanceAssemblerFactory factory) { +public interface Pipeline { + + GLSLVersion glslVersion(); + + FileResolution vertex(); + + FileResolution fragment(); /** * Generate the source component necessary to convert a packed {@link StructType} into its shader representation. * - * @param structType The struct type to convert. * @return A source component defining functions that unpack a representation of the given struct type. */ - public SourceComponent assemble(VertexType vertexType, StructType structType) { - return factory.apply(vertexType, structType); - } - - public interface InstanceAssemblerFactory extends BiFunction, SourceComponent> { + SourceComponent assemble(InstanceAssemblerContext context); + record InstanceAssemblerContext(ShaderSources sources, VertexType vertexType, StructType structType) { } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/BackendType.java b/src/main/java/com/jozufozu/flywheel/backend/BackendType.java index 0c870193e..0762e3596 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/BackendType.java +++ b/src/main/java/com/jozufozu/flywheel/backend/BackendType.java @@ -2,8 +2,8 @@ package com.jozufozu.flywheel.backend; import org.jetbrains.annotations.Nullable; -import com.jozufozu.flywheel.api.pipeline.PipelineShader; import com.jozufozu.flywheel.backend.instancing.Engine; +import com.jozufozu.flywheel.core.pipeline.SimplePipeline; import net.minecraft.network.chat.Component; @@ -21,5 +21,5 @@ public interface BackendType { boolean supported(); - @Nullable PipelineShader pipelineShader(); + @Nullable SimplePipeline pipelineShader(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index d9c1f3067..5287e135c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -2,7 +2,6 @@ package com.jozufozu.flywheel.backend; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler; -import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.source.ShaderSources; import com.jozufozu.flywheel.core.source.error.ErrorReporter; @@ -24,11 +23,12 @@ public class Loader implements ResourceManagerReloadListener { Loader() { // Can be null when running datagenerators due to the unfortunate time we call this Minecraft minecraft = Minecraft.getInstance(); - if (minecraft != null) { - ResourceManager manager = minecraft.getResourceManager(); - if (manager instanceof ReloadableResourceManager) { - ((ReloadableResourceManager) manager).registerReloadListener(this); - } + if (minecraft == null) { + return; + } + + if (minecraft.getResourceManager() instanceof ReloadableResourceManager reloadable) { + reloadable.registerReloadListener(this); } } @@ -39,23 +39,7 @@ public class Loader implements ResourceManagerReloadListener { var errorReporter = new ErrorReporter(); ShaderSources sources = new ShaderSources(errorReporter, manager); - Backend.LOGGER.info("Loaded all shader sources in " + sources.getLoadTime()); - - FileResolution.run(errorReporter, sources); - - if (errorReporter.hasErrored()) { - throw errorReporter.dump(); - } - - sources.postResolve(); - - Backend.LOGGER.info("Successfully resolved all source files."); - - FileResolution.checkAll(errorReporter); - - Backend.LOGGER.info("All shaders passed checks."); - - FlwCompiler.INSTANCE.run(); + FlwCompiler.INSTANCE = new FlwCompiler(sources); ClientLevel level = Minecraft.getInstance().level; if (Backend.canUseInstancing(level)) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/SimpleBackendType.java b/src/main/java/com/jozufozu/flywheel/backend/SimpleBackendType.java index d832b7691..9a4b90056 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/SimpleBackendType.java +++ b/src/main/java/com/jozufozu/flywheel/backend/SimpleBackendType.java @@ -5,9 +5,9 @@ import java.util.function.Supplier; import org.jetbrains.annotations.Nullable; -import com.jozufozu.flywheel.api.pipeline.PipelineShader; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.core.BackendTypes; +import com.jozufozu.flywheel.core.pipeline.SimplePipeline; import net.minecraft.network.chat.Component; @@ -20,9 +20,9 @@ public class SimpleBackendType implements BackendType { private final Supplier engineSupplier; private final Supplier fallback; private final BooleanSupplier isSupported; - private final PipelineShader pipelineShader; + private final SimplePipeline pipelineShader; - public SimpleBackendType(String properName, String shortName, Component engineMessage, Supplier engineSupplier, Supplier fallback, BooleanSupplier isSupported, @Nullable PipelineShader pipelineShader) { + public SimpleBackendType(String properName, String shortName, Component engineMessage, Supplier engineSupplier, Supplier fallback, BooleanSupplier isSupported, @Nullable SimplePipeline pipelineShader) { this.properName = properName; this.shortName = shortName; this.engineMessage = engineMessage; @@ -72,7 +72,7 @@ public class SimpleBackendType implements BackendType { } @Override - public @Nullable PipelineShader pipelineShader() { + public @Nullable SimplePipeline pipelineShader() { return pipelineShader; } @@ -83,7 +83,7 @@ public class SimpleBackendType implements BackendType { private Supplier engineSupplier; private Supplier fallback; private BooleanSupplier isSupported; - private PipelineShader pipelineShader; + private SimplePipeline pipelineShader; public Builder properName(String properName) { this.properName = properName; @@ -115,7 +115,7 @@ public class SimpleBackendType implements BackendType { return this; } - public Builder pipelineShader(PipelineShader pipelineShader) { + public Builder pipelineShader(SimplePipeline pipelineShader) { this.pipelineShader = pipelineShader; return this; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationEnvironment.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationEnvironment.java deleted file mode 100644 index 8f78af939..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationEnvironment.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.compile; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Multimap; -import com.jozufozu.flywheel.api.context.ContextShader; -import com.jozufozu.flywheel.api.pipeline.PipelineShader; -import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.api.uniform.UniformProvider; -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.core.BackendTypes; -import com.jozufozu.flywheel.core.ComponentRegistry; -import com.jozufozu.flywheel.core.source.ShaderLoadingException; -import com.jozufozu.flywheel.util.StringUtil; - -class CompilationEnvironment { - final VertexMaterialComponent vertexMaterialComponent; - final FragmentMaterialComponent fragmentMaterialComponent; - - boolean needsCrash = false; - - final long compileStart = System.nanoTime(); - final Multimap, PipelineContext> uniformProviderGroups = ArrayListMultimap.create(); - final List pipelineContexts = new ArrayList<>(); - - CompilationEnvironment() { - for (PipelineShader pipelineShader : BackendTypes.availablePipelineShaders()) { - for (StructType structType : ComponentRegistry.structTypes) { - for (VertexType vertexType : ComponentRegistry.vertexTypes) { - for (ContextShader contextShader : ComponentRegistry.contextShaders) { - acknowledgeContext(new PipelineContext(vertexType, structType, contextShader, pipelineShader)); - } - } - } - } - this.vertexMaterialComponent = new VertexMaterialComponent(ComponentRegistry.materials.vertexSources()); - this.fragmentMaterialComponent = new FragmentMaterialComponent(ComponentRegistry.materials.fragmentSources()); - } - - private void acknowledgeContext(PipelineContext ctx) { - uniformProviderGroups.put(ctx.uniformProviders(), ctx); - - pipelineContexts.add(ctx); - } - - public void finish() { - long compileEnd = System.nanoTime(); - - Backend.LOGGER.info("Compiled " + pipelineContexts.size() + " programs in " + StringUtil.formatTime(compileEnd - compileStart)); - - if (needsCrash) { - throw new ShaderLoadingException("Compilation failed"); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java index 49109b6d5..1b98f52b4 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java @@ -1,14 +1,21 @@ package com.jozufozu.flywheel.backend.instancing.compile; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Multimap; import com.jozufozu.flywheel.api.context.ContextShader; -import com.jozufozu.flywheel.api.pipeline.PipelineShader; +import com.jozufozu.flywheel.api.pipeline.Pipeline; import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.api.uniform.UniformProvider; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GLSLVersion; @@ -16,42 +23,64 @@ 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.instancing.indirect.IndirectComponent; +import com.jozufozu.flywheel.core.BackendTypes; import com.jozufozu.flywheel.core.ComponentRegistry; import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.Pipelines; import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.pipeline.SimplePipeline; import com.jozufozu.flywheel.core.source.CompilationContext; +import com.jozufozu.flywheel.core.source.ShaderLoadingException; +import com.jozufozu.flywheel.core.source.ShaderSources; +import com.jozufozu.flywheel.core.source.SourceFile; import com.jozufozu.flywheel.event.ReloadRenderersEvent; +import com.jozufozu.flywheel.util.StringUtil; import net.minecraft.resources.ResourceLocation; public class FlwCompiler { - public static final FlwCompiler INSTANCE = new FlwCompiler(); + public static FlwCompiler INSTANCE; public static void onReloadRenderers(ReloadRenderersEvent t) { } - private final ShaderCompiler shaderCompiler = new ShaderCompiler(); - public final Map pipelinePrograms = new HashMap<>(); + final Map pipelinePrograms = new HashMap<>(); + final Map, GlProgram> cullingPrograms = new HashMap<>(); - public final Map, GlProgram> cullingPrograms = new HashMap<>(); + boolean needsCrash = false; - private CompilationEnvironment environment; + final long compileStart = System.nanoTime(); + final Multimap, PipelineContext> uniformProviderGroups = ArrayListMultimap.create(); + final List pipelineContexts = new ArrayList<>(); - FlwCompiler() { + private final ShaderSources sources; + private final VertexMaterialComponent vertexMaterialComponent; + private final FragmentMaterialComponent fragmentMaterialComponent; - } + public FlwCompiler(ShaderSources sources) { + this.sources = sources; + this.vertexMaterialComponent = new VertexMaterialComponent(sources, ComponentRegistry.materials.vertexSources()); + this.fragmentMaterialComponent = new FragmentMaterialComponent(sources, ComponentRegistry.materials.fragmentSources()); - public void run() { - environment = new CompilationEnvironment(); + for (SimplePipeline pipelineShader : BackendTypes.availablePipelineShaders()) { + for (StructType structType : ComponentRegistry.structTypes) { + for (VertexType vertexType : ComponentRegistry.vertexTypes) { + // TODO: context ubershaders, or not? + pipelineContexts.add(new PipelineContext(vertexType, structType, Components.WORLD, pipelineShader)); + } + } + } - for (PipelineContext context : environment.pipelineContexts) { + // TODO: analyze uniform providers and group them into sets; break up this ctor + + for (PipelineContext context : pipelineContexts) { try { var glProgram = compilePipelineContext(context); pipelinePrograms.put(context, glProgram); } catch (ShaderCompilationException e) { - environment.needsCrash = true; + needsCrash = true; Backend.LOGGER.error(e.errors); } } @@ -61,15 +90,25 @@ public class FlwCompiler { var glProgram = compileComputeCuller(type); cullingPrograms.put(type, glProgram); } catch (ShaderCompilationException e) { - environment.needsCrash = true; + needsCrash = true; Backend.LOGGER.error(e.errors); } } - environment.finish(); + finish(); } - public GlProgram getPipelineProgram(VertexType vertexType, StructType structType, ContextShader contextShader, PipelineShader pipelineShader) { + public void finish() { + long compileEnd = System.nanoTime(); + + Backend.LOGGER.info("Compiled " + pipelineContexts.size() + " programs in " + StringUtil.formatTime(compileEnd - compileStart)); + + if (needsCrash) { + throw new ShaderLoadingException("Compilation failed"); + } + } + + public GlProgram getPipelineProgram(VertexType vertexType, StructType structType, ContextShader contextShader, SimplePipeline pipelineShader) { return pipelinePrograms.get(new PipelineContext(vertexType, structType, contextShader, pipelineShader)); } @@ -82,48 +121,110 @@ public class FlwCompiler { var glslVersion = ctx.pipelineShader() .glslVersion(); - var vertex = new ShaderContext(glslVersion, ShaderType.VERTEX, ctx.getVertexComponents()); - var fragment = new ShaderContext(glslVersion, ShaderType.FRAGMENT, ctx.getFragmentComponents()); + var vertex = compileShader(glslVersion, ShaderType.VERTEX, getVertexComponents(ctx)); + var fragment = compileShader(glslVersion, ShaderType.FRAGMENT, getFragmentComponents(ctx)); return ctx.contextShader() .factory() - .create(new ProgramAssembler().attachShader(shaderCompiler.get(vertex)) - .attachShader(shaderCompiler.get(fragment)) + .create(new ProgramAssembler().attachShader(vertex) + .attachShader(fragment) .link()); } protected GlProgram compileComputeCuller(StructType structType) { - var location = structType.getInstanceShader(); - var finalSource = new StringBuilder(); - CompilationContext context = new CompilationContext(); - var components = List.of(new IndirectComponent(structType.getLayout().layoutItems), location.getFile(), Components.Pipeline.INDIRECT_CULL.getFile()); + return new GlProgram(new ProgramAssembler().attachShader(compileShader(GLSLVersion.V460, ShaderType.COMPUTE, getComputeComponents(structType))) + .link()); + } + ImmutableList getVertexComponents(PipelineContext ctx) { + var instanceAssembly = ctx.pipelineShader() + .assemble(new Pipeline.InstanceAssemblerContext(sources, ctx.vertexType(), ctx.structType())); + + var layout = sources.find(ctx.vertexType() + .getLayoutShader() + .resourceLocation()); + var instance = sources.find(ctx.structType() + .getInstanceShader() + .resourceLocation()); + var context = sources.find(ctx.contextShader() + .vertexShader() + .resourceLocation()); + var pipeline = sources.find(ctx.pipelineShader() + .vertex() + .resourceLocation()); + + return ImmutableList.of(vertexMaterialComponent, instanceAssembly, layout, instance, context, pipeline); + } + + ImmutableList getFragmentComponents(PipelineContext ctx) { + var context = sources.find(ctx.contextShader() + .fragmentShader() + .resourceLocation()); + var pipeline = sources.find(ctx.pipelineShader() + .fragment() + .resourceLocation()); + return ImmutableList.of(fragmentMaterialComponent, context, pipeline); + } + + @NotNull ImmutableList getComputeComponents(StructType structType) { + var instanceAssembly = new IndirectComponent(sources, structType); + var instance = sources.find(structType.getInstanceShader() + .resourceLocation()); + var pipeline = sources.find(Pipelines.Files.INDIRECT_CULL.resourceLocation()); + + return ImmutableList.of(instanceAssembly, instance, pipeline); + } + + protected GlShader compileShader(GLSLVersion glslVersion, ShaderType shaderType, ImmutableList sourceComponents) { + StringBuilder finalSource = new StringBuilder(CompileUtil.generateHeader(glslVersion, shaderType)); + finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n"); + finalSource.append("#extension GL_ARB_conservative_depth : enable\n"); + + var ctx = new CompilationContext(); var names = ImmutableList.builder(); - var included = new LinkedHashSet(); // linked to preserve order - for (var component : components) { - included.addAll(component.included()); + + for (var include : depthFirstInclude(sourceComponents)) { + appendFinalSource(finalSource, ctx, include); + } + + for (var component : sourceComponents) { + appendFinalSource(finalSource, ctx, component); names.add(component.name()); } - finalSource.append(CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE)); - for (var include : included) { - finalSource.append(include.source(context)); - } - - for (var component : components) { - finalSource.append(component.source(context)); - } - try { - var fileLoc = location.getFileLoc(); - var shader = new GlShader(finalSource.toString(), ShaderType.COMPUTE, ImmutableList.of(fileLoc)); - - var program = new ProgramAssembler().attachShader(shader) - .link(); - return new GlProgram(program); + return new GlShader(finalSource.toString(), shaderType, names.build()); } catch (ShaderCompilationException e) { - throw e.withErrorLog(context); + throw e.withErrorLog(ctx); } } + + private static void appendFinalSource(StringBuilder finalSource, CompilationContext ctx, SourceComponent component) { + var source = component.source(); + + if (component instanceof SourceFile file) { + finalSource.append(ctx.sourceHeader(file)); + } else { + finalSource.append(ctx.generatedHeader(source, component.name() + .toString())); + } + + finalSource.append(source); + } + + protected static Set depthFirstInclude(ImmutableList root) { + var included = new LinkedHashSet(); // linked to preserve order + for (var component : root) { + recursiveDepthFirstInclude(included, component); + } + return included; + } + + protected static void recursiveDepthFirstInclude(Set included, SourceComponent component) { + for (var include : component.included()) { + recursiveDepthFirstInclude(included, include); + } + included.addAll(component.included()); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java index 85bb823c2..c47a831e8 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java @@ -1,49 +1,29 @@ package com.jozufozu.flywheel.backend.instancing.compile; -import java.util.Collection; import java.util.List; -import com.jozufozu.flywheel.core.SourceComponent; -import com.jozufozu.flywheel.core.source.CompilationContext; +import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.ShaderSources; import com.jozufozu.flywheel.core.source.generate.GlslExpr; -import com.jozufozu.flywheel.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; -public class FragmentMaterialComponent implements SourceComponent { +public class FragmentMaterialComponent extends MaterialAdapterComponent { private static final String flw_materialFragment = "flw_materialFragment"; private static final String flw_discardPredicate = "flw_discardPredicate"; private static final String flw_fogFilter = "flw_fogFilter"; + private static final List adaptedFunctions = List.of(flw_materialFragment, flw_discardPredicate, flw_fogFilter); private static final GlslExpr flw_materialFragmentID = GlslExpr.variable(flw_materialFragment + "ID"); - private final List transformedMaterials; - - public FragmentMaterialComponent(List sourceMaterials) { - - this.transformedMaterials = sourceMaterials.stream() - .map(FileResolution::getFile) - .map(s -> { - var newName = flw_materialFragment + '_' + ResourceUtil.toSafeString(s.name()); - return new TransformedSourceComponent(s, flw_materialFragment, newName); - }) - .toList(); - } - - @Override - public Collection included() { - return transformedMaterials; - } - - @Override - public String source(CompilationContext ctx) { - return null; + public FragmentMaterialComponent(ShaderSources sources, List sourceMaterials) { + super(sources, sourceMaterials, flw_materialFragmentID, adaptedFunctions); } @Override public ResourceLocation name() { - return null; + return Flywheel.rl("fragment_material_adapter"); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java new file mode 100644 index 000000000..abee3b981 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java @@ -0,0 +1,87 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.ShaderSources; +import com.jozufozu.flywheel.core.source.generate.GlslBuilder; +import com.jozufozu.flywheel.core.source.generate.GlslExpr; +import com.jozufozu.flywheel.util.ResourceUtil; + +import net.minecraft.resources.ResourceLocation; + +public abstract class MaterialAdapterComponent implements SourceComponent { + + // TODO: material id handling in pipeline shader + private final GlslExpr switchArg; + private final List adaptedFunctions; + private final List transformedMaterials; + + // TODO: Create builder and remove Fragment* and Vertex* classes + public MaterialAdapterComponent(ShaderSources sources, List sourceMaterials, GlslExpr switchArg, List adaptedFunctions) { + this.switchArg = switchArg; + this.adaptedFunctions = adaptedFunctions; + + var transformed = ImmutableList.builder(); + + for (FileResolution fileResolution : sourceMaterials) { + var loc = fileResolution.resourceLocation(); + var sourceFile = sources.find(loc); + + transformed.add(new RenamedFunctionsSourceComponent(sourceFile, createAdapterMap(adaptedFunctions, loc))); + } + + this.transformedMaterials = transformed.build(); + } + + @Override + public Collection included() { + return transformedMaterials; + } + + @Override + public String source() { + var builder = new GlslBuilder(); + + for (String adaptedFunction : adaptedFunctions) { + // TODO: support different function signatures + builder.function() + .returnType("void") + .name(adaptedFunction) + .body(body -> generateAdapter(body, adaptedFunction)); + } + + return builder.build(); + } + + private void generateAdapter(GlslBuilder.BlockBuilder body, String adaptedFunction) { + var sw = new GlslBuilder.SwitchBuilder(switchArg); + for (int i = 0; i < transformedMaterials.size(); i++) { + var variant = transformedMaterials.get(i) + .replacement(adaptedFunction); + + sw.case_(i, b -> b.eval(GlslExpr.call(variant)) + .break_()); + } + body.add(sw.build()); + } + + @NotNull + private static HashMap createAdapterMap(List adaptedFunctions, ResourceLocation loc) { + HashMap out = new HashMap<>(); + + var suffix = '_' + ResourceUtil.toSafeString(loc); + + for (String fnName : adaptedFunctions) { + out.put(fnName, fnName + suffix); + } + + return out; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java index b074ce19e..bf876f956 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java @@ -1,20 +1,9 @@ package com.jozufozu.flywheel.backend.instancing.compile; -import java.util.Collection; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.jetbrains.annotations.NotNull; - -import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.api.context.ContextShader; -import com.jozufozu.flywheel.api.pipeline.PipelineShader; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.api.uniform.UniformProvider; import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.core.ComponentRegistry; -import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.pipeline.SimplePipeline; /** * Represents the entire context of a program's usage. @@ -24,42 +13,5 @@ import com.jozufozu.flywheel.core.SourceComponent; * @param contextShader The context shader to use. */ public record PipelineContext(VertexType vertexType, StructType structType, ContextShader contextShader, - PipelineShader pipelineShader) { - - @NotNull - public Set uniformProviders() { - var fragmentComponents = getFragmentComponents(); - var vertexComponents = getVertexComponents(); - - return Stream.concat(fragmentComponents.stream(), vertexComponents.stream()) - .map(SourceComponent::included) - .flatMap(Collection::stream) - .map(SourceComponent::name) - .mapMulti((component, consumer) -> { - var uniformProvider = ComponentRegistry.getUniformProvider(component); - if (uniformProvider != null) { - consumer.accept(uniformProvider); - } - }) - .collect(Collectors.toSet()); - } - - ImmutableList getVertexComponents() { - var layout = vertexType.getLayoutShader() - .getFile(); - var instanceAssembly = pipelineShader.assemble(vertexType, structType); - var instance = structType.getInstanceShader() - .getFile(); - var context = contextShader.getVertexShader(); - var pipeline = pipelineShader.vertex() - .getFile(); - return ImmutableList.of(layout, instanceAssembly, instance, context, pipeline); - } - - ImmutableList getFragmentComponents() { - var context = contextShader.getFragmentShader(); - var pipeline = pipelineShader.fragment() - .getFile(); - return ImmutableList.of(context, pipeline); - } + SimplePipeline pipelineShader) { } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RenamedFunctionsSourceComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RenamedFunctionsSourceComponent.java new file mode 100644 index 000000000..32d1303bc --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RenamedFunctionsSourceComponent.java @@ -0,0 +1,49 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.Collection; +import java.util.Map; + +import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.util.ResourceUtil; + +import net.minecraft.resources.ResourceLocation; + +public final class RenamedFunctionsSourceComponent implements SourceComponent { + private final SourceComponent source; + private final Map replacements; + + public RenamedFunctionsSourceComponent(SourceComponent source, String find, String replace) { + this.source = source; + this.replacements = Map.of(find, replace); + } + + public RenamedFunctionsSourceComponent(SourceComponent source, Map replacements) { + this.source = source; + this.replacements = replacements; + } + + public String replacement(String name) { + return replacements.getOrDefault(name, name); + } + + @Override + public String source() { + var source = this.source.source(); + + for (var entry : replacements.entrySet()) { + source = source.replace(entry.getKey(), entry.getValue()); + } + + return source; + } + + @Override + public ResourceLocation name() { + return ResourceUtil.subPath(source.name(), "_renamed"); + } + + @Override + public Collection included() { + return source.included(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java deleted file mode 100644 index 934ee2bbe..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.compile; - -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; - -import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.backend.gl.GlObject; -import com.jozufozu.flywheel.backend.gl.shader.GlShader; -import com.jozufozu.flywheel.core.SourceComponent; -import com.jozufozu.flywheel.core.source.CompilationContext; - -import net.minecraft.resources.ResourceLocation; - -/** - * Handles compilation and deletion of vertex shaders. - */ -public class ShaderCompiler { - - private final Map map = new HashMap<>(); - - ShaderCompiler() { - } - - public GlShader get(ShaderContext key) { - return map.computeIfAbsent(key, this::_create); - } - - protected GlShader _create(ShaderContext key) { - StringBuilder finalSource = new StringBuilder(key.generateHeader()); - finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n"); - finalSource.append("#extension GL_ARB_conservative_depth : enable\n"); - - var ctx = new CompilationContext(); - - var names = ImmutableList.builder(); - var included = new LinkedHashSet(); // linked to preserve order - for (var component : key.sourceComponents()) { - included.addAll(component.included()); - names.add(component.name()); - } - - for (var include : included) { - finalSource.append(include.source(ctx)); - } - - for (var component : key.sourceComponents()) { - finalSource.append(component.source(ctx)); - } - - try { - return new GlShader(finalSource.toString(), key.shaderType(), names.build()); - } catch (ShaderCompilationException e) { - throw e.withErrorLog(ctx); - } - } - - public void invalidate() { - map.values() - .forEach(GlObject::delete); - map.clear(); - } - -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderContext.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderContext.java deleted file mode 100644 index 28f04f6d0..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderContext.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.compile; - -import java.util.List; - -import com.jozufozu.flywheel.backend.gl.GLSLVersion; -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; -import com.jozufozu.flywheel.core.SourceComponent; - -/** - * @param glslVersion The GLSL version to use. - * @param sourceComponents A list of shader components to stitch together, in order. - */ -public record ShaderContext(GLSLVersion glslVersion, ShaderType shaderType, List sourceComponents) { - - public String generateHeader() { - return CompileUtil.generateHeader(glslVersion, shaderType); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/TransformedSourceComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/TransformedSourceComponent.java deleted file mode 100644 index b6faefa4a..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/TransformedSourceComponent.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.compile; - -import java.util.Collection; - -import com.jozufozu.flywheel.core.SourceComponent; -import com.jozufozu.flywheel.core.source.CompilationContext; -import com.jozufozu.flywheel.util.ResourceUtil; - -import net.minecraft.resources.ResourceLocation; - -public final class TransformedSourceComponent implements SourceComponent { - final SourceComponent source; - final String find; - final String replacement; - - public TransformedSourceComponent(SourceComponent source, String find, String replacement) { - this.source = source; - this.find = find; - this.replacement = replacement; - } - - @Override - public String source(CompilationContext ctx) { - return source.source(ctx) - .replace(find, replacement); - } - - @Override - public ResourceLocation name() { - return ResourceUtil.subPath(source.name(), "_renamed"); - } - - @Override - public Collection included() { - return source.included(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java index 87b27e9d9..1bcb3f4a3 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java @@ -1,71 +1,27 @@ package com.jozufozu.flywheel.backend.instancing.compile; -import java.util.Collection; import java.util.List; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.core.SourceComponent; -import com.jozufozu.flywheel.core.source.CompilationContext; import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.core.source.generate.GlslBuilder; +import com.jozufozu.flywheel.core.source.ShaderSources; import com.jozufozu.flywheel.core.source.generate.GlslExpr; -import com.jozufozu.flywheel.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; -public class VertexMaterialComponent implements SourceComponent { +public class VertexMaterialComponent extends MaterialAdapterComponent { private static final String flw_materialVertex = "flw_materialVertex"; + private static final List adaptedFunctions = List.of(flw_materialVertex); private static final GlslExpr flw_materialVertexID = GlslExpr.variable(flw_materialVertex + "ID"); - private final List transformedMaterials; - public VertexMaterialComponent(List sourceMaterials) { - - this.transformedMaterials = sourceMaterials.stream() - .map(FileResolution::getFile) - .map(s -> { - var newName = flw_materialVertex + '_' + ResourceUtil.toSafeString(s.name()); - return new TransformedSourceComponent(s, flw_materialVertex, newName); - }) - .toList(); - } - - @Override - public Collection included() { - return transformedMaterials; - } - - @Override - public String source(CompilationContext ctx) { - String out = genSource(); - return ctx.generatedHeader(out, "material adapter") + out; - } - - public String genSource() { - var builder = new GlslBuilder(); - - builder.function() - .returnType("void") - .name("flw_materialVertex") - .body(this::accept); - - return builder.build(); + public VertexMaterialComponent(ShaderSources sources, List sourceMaterials) { + super(sources, sourceMaterials, flw_materialVertexID, adaptedFunctions); } @Override public ResourceLocation name() { return Flywheel.rl("vertex_material_adapter"); } - - private void accept(GlslBuilder.BlockBuilder body) { - var sw = new GlslBuilder.SwitchBuilder(flw_materialVertexID); - for (int i = 0; i < transformedMaterials.size(); i++) { - var variant = transformedMaterials.get(i).replacement; - - sw.case_(i, b -> b.eval(GlslExpr.call(variant)) - .break_()); - } - body.add(sw.build()); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java index 55668c4f7..1c1ba970c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java @@ -3,11 +3,15 @@ package com.jozufozu.flywheel.backend.instancing.indirect; import java.util.Collection; import java.util.List; +import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.api.pipeline.Pipeline; +import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.core.Pipelines; import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.layout.LayoutItem; -import com.jozufozu.flywheel.core.source.CompilationContext; +import com.jozufozu.flywheel.core.source.ShaderSources; +import com.jozufozu.flywheel.core.source.SourceFile; import com.jozufozu.flywheel.core.source.generate.GlslBuilder; import com.jozufozu.flywheel.core.source.generate.GlslExpr; @@ -19,14 +23,20 @@ public class IndirectComponent implements SourceComponent { private static final GlslExpr.Variable UNPACKING_VARIABLE = GlslExpr.variable(UNPACK_ARG); private final List layoutItems; + private final ImmutableList included; - public IndirectComponent(List layoutItems) { - this.layoutItems = layoutItems; + public IndirectComponent(Pipeline.InstanceAssemblerContext ctx) { + this(ctx.sources(), ctx.structType()); + } + + public IndirectComponent(ShaderSources sources, StructType structType) { + this.layoutItems = structType.getLayout().layoutItems; + included = ImmutableList.of(sources.find(Pipelines.Files.UTIL_TYPES.resourceLocation())); } @Override public Collection included() { - return List.of(Components.UTIL_TYPES.getFile()); + return included; } @Override @@ -35,9 +45,8 @@ public class IndirectComponent implements SourceComponent { } @Override - public String source(CompilationContext ctx) { - var generated = generateIndirect("IndirectStruct"); - return ctx.generatedHeader(generated, name().toString()) + generated; + public String source() { + return generateIndirect("IndirectStruct"); } public String generateIndirect(String structName) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java index 9618c0f02..d77a07e7a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java @@ -19,6 +19,7 @@ import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler; import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.Pipelines; import com.jozufozu.flywheel.core.QuadConverter; public class IndirectCullingGroup { @@ -64,7 +65,7 @@ public class IndirectCullingGroup { setupVertexArray(); compute = FlwCompiler.INSTANCE.getCullingProgram(structType); - draw = FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, Components.WORLD, Components.INDIRECT); + draw = FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, Components.WORLD, Pipelines.INDIRECT); } private void setupVertexArray() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java index 84fdf8498..1ea8dd912 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java @@ -5,9 +5,9 @@ import java.util.Collections; import java.util.List; import com.jozufozu.flywheel.Flywheel; +import com.jozufozu.flywheel.api.pipeline.Pipeline; import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.layout.LayoutItem; -import com.jozufozu.flywheel.core.source.CompilationContext; import com.jozufozu.flywheel.core.source.generate.GlslBuilder; import com.jozufozu.flywheel.core.source.generate.GlslExpr; @@ -19,9 +19,12 @@ public class InstancedArraysComponent implements SourceComponent { private final List layoutItems; private final int baseIndex; - public InstancedArraysComponent(List layoutItems, int baseIndex) { - this.layoutItems = layoutItems; - this.baseIndex = baseIndex; + public InstancedArraysComponent(Pipeline.InstanceAssemblerContext ctx) { + this.layoutItems = ctx.structType() + .getLayout().layoutItems; + this.baseIndex = ctx.vertexType() + .getLayout() + .getAttributeCount(); } @Override @@ -30,9 +33,8 @@ public class InstancedArraysComponent implements SourceComponent { } @Override - public String source(CompilationContext ctx) { - var generated = generateInstancedArrays("Instance"); - return ctx.generatedHeader(generated, name().toString()) + generated; + public String source() { + return generateInstancedArrays("Instance"); } @Override 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 89e82c1a4..2eefcb058 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 @@ -18,7 +18,7 @@ import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler; -import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.Pipelines; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.util.WeakHashSet; import com.mojang.blaze3d.systems.RenderSystem; @@ -123,7 +123,7 @@ public class InstancingEngine implements Engine { var structType = desc.instance(); var material = desc.material(); - FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, context, Components.INSTANCED_ARRAYS) + FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, context, Pipelines.INSTANCED_ARRAYS) .bind(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java b/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java index 7b8e256dc..22aa862c8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java +++ b/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java @@ -9,7 +9,6 @@ import java.util.stream.Collectors; import org.jetbrains.annotations.Nullable; -import com.jozufozu.flywheel.api.pipeline.PipelineShader; import com.jozufozu.flywheel.backend.BackendType; import com.jozufozu.flywheel.backend.ShadersModHandler; import com.jozufozu.flywheel.backend.SimpleBackendType; @@ -17,6 +16,7 @@ import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; import com.jozufozu.flywheel.backend.instancing.batching.BatchingEngine; import com.jozufozu.flywheel.backend.instancing.indirect.IndirectEngine; import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine; +import com.jozufozu.flywheel.core.pipeline.SimplePipeline; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.TextComponent; @@ -58,7 +58,7 @@ public class BackendTypes { .fallback(() -> BackendTypes.BATCHING) .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance() .instancedArraysSupported()) - .pipelineShader(Components.INSTANCED_ARRAYS) + .pipelineShader(Pipelines.INSTANCED_ARRAYS) .register(); /** @@ -72,7 +72,7 @@ public class BackendTypes { .fallback(() -> BackendTypes.INSTANCING) .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance() .supportsIndirect()) - .pipelineShader(Components.INDIRECT) + .pipelineShader(Pipelines.INDIRECT) .register(); public static BackendType register(BackendType type) { @@ -99,7 +99,7 @@ public class BackendTypes { } - public static Collection availablePipelineShaders() { + public static Collection availablePipelineShaders() { return BACKEND_TYPES.values() .stream() .filter(BackendType::supported) diff --git a/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java b/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java index 4e0bf6b56..0d11d1d04 100644 --- a/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java +++ b/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java @@ -53,7 +53,7 @@ public class ComponentRegistry { public static T register(T provider) { return uniformProviders.register(provider.uniformShader() - .getFileLoc(), provider); + .resourceLocation(), provider); } public static Collection getAllUniformProviders() { diff --git a/src/main/java/com/jozufozu/flywheel/core/Components.java b/src/main/java/com/jozufozu/flywheel/core/Components.java index c9231ce09..5b89ae03f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Components.java +++ b/src/main/java/com/jozufozu/flywheel/core/Components.java @@ -4,10 +4,6 @@ import java.util.function.BiConsumer; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.context.ContextShader; -import com.jozufozu.flywheel.api.pipeline.PipelineShader; -import com.jozufozu.flywheel.backend.gl.GLSLVersion; -import com.jozufozu.flywheel.backend.instancing.indirect.IndirectComponent; -import com.jozufozu.flywheel.backend.instancing.instancing.InstancedArraysComponent; import com.jozufozu.flywheel.core.crumbling.CrumblingProgram; import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.source.SourceChecks; @@ -31,28 +27,12 @@ public class Components { public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(WorldProgram::new, Files.WORLD_VERTEX, Files.WORLD_FRAGMENT)); public static final ContextShader CRUMBLING = ComponentRegistry.register(new ContextShader(CrumblingProgram::new, Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT)); - public static final PipelineShader INSTANCED_ARRAYS = new PipelineShader(GLSLVersion.V420, Pipeline.INSTANCED_ARRAYS_DRAW, Pipeline.DRAW_FRAGMENT, (vertexType, structType) -> new InstancedArraysComponent(structType.getLayout().layoutItems, vertexType.getLayout() - .getAttributeCount())); - public static final PipelineShader INDIRECT = new PipelineShader(GLSLVersion.V460, Pipeline.INDIRECT_DRAW, Pipeline.DRAW_FRAGMENT, (vertexType, structType) -> new IndirectComponent(structType.getLayout().layoutItems)); - public static final FileResolution UTIL_TYPES = FileResolution.get(Flywheel.rl("util/types.glsl")); - public static void init() { Files.init(); Formats.init(); StructTypes.init(); Materials.init(); - } - - public static class Pipeline { - public static final FileResolution DRAW_FRAGMENT = pipeline("pipeline/draw.frag"); - public static final FileResolution INSTANCED_ARRAYS_DRAW = pipeline("pipeline/instanced_arrays_draw.vert"); - public static final FileResolution INDIRECT_DRAW = pipeline("pipeline/indirect_draw.vert"); - public static final FileResolution INDIRECT_CULL = pipeline("pipeline/indirect_cull.glsl"); - - private static FileResolution pipeline(String name) { - return FileResolution.get(Flywheel.rl(name)) - .validateWith(Checks.PIPELINE); - } + Pipelines.init(); } public static class Files { diff --git a/src/main/java/com/jozufozu/flywheel/core/Pipelines.java b/src/main/java/com/jozufozu/flywheel/core/Pipelines.java new file mode 100644 index 000000000..4d2c249e2 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/Pipelines.java @@ -0,0 +1,40 @@ +package com.jozufozu.flywheel.core; + +import com.jozufozu.flywheel.Flywheel; +import com.jozufozu.flywheel.backend.gl.GLSLVersion; +import com.jozufozu.flywheel.backend.instancing.indirect.IndirectComponent; +import com.jozufozu.flywheel.backend.instancing.instancing.InstancedArraysComponent; +import com.jozufozu.flywheel.core.pipeline.SimplePipeline; +import com.jozufozu.flywheel.core.source.FileResolution; + +public class Pipelines { + public static final SimplePipeline INSTANCED_ARRAYS = SimplePipeline.builder() + .glslVersion(GLSLVersion.V420) + .vertex(Files.INSTANCED_ARRAYS_DRAW) + .fragment(Files.DRAW_FRAGMENT) + .assemblerFactory(InstancedArraysComponent::new) + .build(); + public static final SimplePipeline INDIRECT = SimplePipeline.builder() + .glslVersion(GLSLVersion.V460) + .vertex(Files.INDIRECT_DRAW) + .fragment(Files.DRAW_FRAGMENT) + .assemblerFactory(IndirectComponent::new) + .build(); + + public static void init() { + // noop + } + + public static class Files { + public static final FileResolution DRAW_FRAGMENT = pipeline("pipeline/draw.frag"); + public static final FileResolution INSTANCED_ARRAYS_DRAW = pipeline("pipeline/instanced_arrays_draw.vert"); + public static final FileResolution INDIRECT_DRAW = pipeline("pipeline/indirect_draw.vert"); + public static final FileResolution INDIRECT_CULL = pipeline("pipeline/indirect_cull.glsl"); + public static final FileResolution UTIL_TYPES = FileResolution.get(Flywheel.rl("util/types.glsl")); + + private static FileResolution pipeline(String name) { + return FileResolution.get(Flywheel.rl(name)) + .validateWith(Components.Checks.PIPELINE); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/SourceComponent.java b/src/main/java/com/jozufozu/flywheel/core/SourceComponent.java index 2adae92b6..16ae4102f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/SourceComponent.java +++ b/src/main/java/com/jozufozu/flywheel/core/SourceComponent.java @@ -2,14 +2,12 @@ package com.jozufozu.flywheel.core; import java.util.Collection; -import com.jozufozu.flywheel.core.source.CompilationContext; - import net.minecraft.resources.ResourceLocation; public interface SourceComponent { Collection included(); - String source(CompilationContext ctx); + String source(); ResourceLocation name(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/SimplePipeline.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/SimplePipeline.java new file mode 100644 index 000000000..3a7a680c1 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/SimplePipeline.java @@ -0,0 +1,86 @@ +package com.jozufozu.flywheel.core.pipeline; + +import com.jozufozu.flywheel.api.pipeline.Pipeline; +import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.backend.gl.GLSLVersion; +import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.source.FileResolution; + +public final class SimplePipeline implements Pipeline { + private final GLSLVersion glslVersion; + private final FileResolution vertex; + private final FileResolution fragment; + private final InstanceAssemblerFactory factory; + + public SimplePipeline(GLSLVersion glslVersion, FileResolution vertex, FileResolution fragment, InstanceAssemblerFactory factory) { + this.glslVersion = glslVersion; + this.vertex = vertex; + this.fragment = fragment; + this.factory = factory; + } + + /** + * Generate the source component necessary to convert a packed {@link StructType} into its shader representation. + * + * @return A source component defining functions that unpack a representation of the given struct type. + */ + @Override + public SourceComponent assemble(InstanceAssemblerContext context) { + return factory.apply(context); + } + + @Override + public GLSLVersion glslVersion() { + return glslVersion; + } + + @Override + public FileResolution vertex() { + return vertex; + } + + @Override + public FileResolution fragment() { + return fragment; + } + + @FunctionalInterface + public interface InstanceAssemblerFactory { + SourceComponent apply(InstanceAssemblerContext context); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private GLSLVersion glslVersion; + private FileResolution vertex; + private FileResolution fragment; + private InstanceAssemblerFactory factory; + + public Builder glslVersion(GLSLVersion glslVersion) { + this.glslVersion = glslVersion; + return this; + } + + public Builder vertex(FileResolution vertex) { + this.vertex = vertex; + return this; + } + + public Builder fragment(FileResolution fragment) { + this.fragment = fragment; + return this; + } + + public Builder assemblerFactory(InstanceAssemblerFactory factory) { + this.factory = factory; + return this; + } + + public SimplePipeline build() { + return new SimplePipeline(glslVersion, vertex, fragment, factory); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java b/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java index 1f40d5ab5..00af5da27 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java @@ -15,7 +15,7 @@ public class CompilationContext { private int generatedLines = 0; - String sourceHeader(SourceFile sourceFile) { + public String sourceHeader(SourceFile sourceFile) { return "#line " + 0 + ' ' + getOrCreateFileID(sourceFile) + " // " + sourceFile.name + '\n'; } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/FileResolution.java b/src/main/java/com/jozufozu/flywheel/core/source/FileResolution.java index ea4ca0d43..860532d59 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/FileResolution.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/FileResolution.java @@ -36,8 +36,6 @@ public class FileResolution { private final ResourceLocation fileLoc; private final boolean weak; - private SourceFile file; - private FileResolution(ResourceLocation fileLoc, boolean weak) { this.fileLoc = fileLoc; this.weak = weak; @@ -76,40 +74,12 @@ public class FileResolution { return WEAK.computeIfAbsent(file, loc -> new FileResolution(loc, true)); } - /** - * Try and resolve all referenced source files, printing errors if any aren't found. - */ - public static void run(ErrorReporter errorReporter, SourceFinder sources) { - for (FileResolution resolution : ALL.values()) { - resolution.resolve(errorReporter, sources); - } - - for (FileResolution resolution : WEAK.values()) { - resolution.resolve(errorReporter, sources); - } - - WEAK.clear(); - - tooLate = true; - } - public static void checkAll(ErrorReporter errorReporter) { for (FileResolution resolution : ALL.values()) { resolution.runChecks(errorReporter); } } - private void resolve(ErrorReporter errorReporter, SourceFinder sources) { - file = sources.findSource(fileLoc); - - if (file == null) { - reportMissing(errorReporter); - } - - // Let the GC do its thing - neededAt.clear(); - } - private void reportMissing(ErrorReporter errorReporter) { ErrorBuilder builder = errorReporter.error(String.format("could not find source for file %s", fileLoc)); for (Span location : neededAt) { @@ -119,22 +89,15 @@ public class FileResolution { } private void runChecks(ErrorReporter errorReporter) { - for (var check : checks) { - check.accept(errorReporter, file); - } + // for (var check : checks) { + // check.accept(errorReporter, file); + // } } - public ResourceLocation getFileLoc() { + public ResourceLocation resourceLocation() { 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; - } public boolean isWeak() { return weak; diff --git a/src/main/java/com/jozufozu/flywheel/core/source/ShaderLoadingException.java b/src/main/java/com/jozufozu/flywheel/core/source/ShaderLoadingException.java index e09dfa99b..13dfc9857 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/ShaderLoadingException.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/ShaderLoadingException.java @@ -5,4 +5,8 @@ public class ShaderLoadingException extends RuntimeException { public ShaderLoadingException(String message) { super(message); } + + public ShaderLoadingException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/ShaderSources.java b/src/main/java/com/jozufozu/flywheel/core/source/ShaderSources.java index 4d8a2284b..b534f932a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/ShaderSources.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/ShaderSources.java @@ -1,13 +1,14 @@ package com.jozufozu.flywheel.core.source; import java.io.IOException; +import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Collection; +import java.util.Deque; import java.util.HashMap; import java.util.Map; +import java.util.stream.Collectors; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import javax.annotation.Nonnull; import com.google.common.collect.Lists; import com.jozufozu.flywheel.core.source.error.ErrorReporter; @@ -15,72 +16,66 @@ import com.jozufozu.flywheel.util.ResourceUtil; import com.jozufozu.flywheel.util.StringUtil; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; /** * The main object for loading and parsing source files. */ -public class ShaderSources implements SourceFinder { +public class ShaderSources { public static final String SHADER_DIR = "flywheel/"; public static final ArrayList EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl"); - private final Map shaderSources = new HashMap<>(); + private final Map cache = new HashMap<>(); - public final Index index; + /** + * Tracks + */ + private final Deque findStack = new ArrayDeque<>(); - public final long loadTimeNs; - public final long indexTimeNs; - public final long totalTimeNs; + private final ResourceManager manager; + private final ErrorReporter errorReporter; public ShaderSources(ErrorReporter errorReporter, ResourceManager manager) { - long loadStart = System.nanoTime(); - - for (ResourceLocation location : getValidShaderFiles(manager)) { - try (Resource resource = manager.getResource(location)) { - String source = StringUtil.readToString(resource.getInputStream()); - - ResourceLocation name = ResourceUtil.removePrefixUnchecked(location, SHADER_DIR); - - shaderSources.put(name, new SourceFile(errorReporter, this, name, source)); - } catch (IOException e) { - // - } - } - long loadEnd = System.nanoTime(); - - long indexStart = System.nanoTime(); - index = new Index(shaderSources); - long indexEnd = System.nanoTime(); - - loadTimeNs = loadEnd - loadStart; - indexTimeNs = indexEnd - indexStart; - totalTimeNs = indexEnd - loadStart; + this.errorReporter = errorReporter; + this.manager = manager; } - public void postResolve() { - for (SourceFile file : shaderSources.values()) { - file.postResolve(); + @Nonnull + public SourceFile find(ResourceLocation location) { + if (findStack.contains(location)) { + generateRecursiveImportException(location); + } + findStack.add(location); + // Can't use computeIfAbsent because mutual recursion causes ConcurrentModificationExceptions + var out = cache.get(location); + if (out == null) { + out = load(location); + cache.put(location, out); + } + findStack.pop(); + return out; + } + + @Nonnull + private SourceFile load(ResourceLocation loc) { + try { + var resource = manager.getResource(ResourceUtil.prefixed(SHADER_DIR, loc)); + + var sourceString = StringUtil.readToString(resource.getInputStream()); + + return new SourceFile(this, loc, sourceString); + } catch (IOException ioException) { + throw new ShaderLoadingException("Could not load shader " + loc, ioException); } } - @Override - @Nullable - public SourceFile findSource(ResourceLocation name) { - return shaderSources.get(name); - } - - @NotNull - private static Collection getValidShaderFiles(ResourceManager manager) { - return manager.listResources(SHADER_DIR, s -> { - for (String ext : EXTENSIONS) { - if (s.endsWith(ext)) return true; - } - return false; - }); - } - - public String getLoadTime() { - return StringUtil.formatTime(totalTimeNs); + private void generateRecursiveImportException(ResourceLocation location) { + findStack.add(location); + String path = findStack.stream() + .dropWhile(l -> !l.equals(location)) + .map(ResourceLocation::toString) + .collect(Collectors.joining(" -> ")); + findStack.clear(); + throw new ShaderLoadingException("recursive import: " + path); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java index 8b8161145..fea1383af 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java @@ -1,20 +1,15 @@ package com.jozufozu.flywheel.core.source; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.regex.Matcher; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.jozufozu.flywheel.core.SourceComponent; -import com.jozufozu.flywheel.core.source.error.ErrorReporter; import com.jozufozu.flywheel.core.source.parse.Import; import com.jozufozu.flywheel.core.source.parse.ShaderField; import com.jozufozu.flywheel.core.source.parse.ShaderFunction; @@ -37,9 +32,8 @@ public class SourceFile implements SourceComponent { public final ResourceLocation name; public final ShaderSources parent; - public final String source; - public final SourceLines lines; + public final SourceLines source; /** * Function lookup by name. @@ -57,30 +51,45 @@ public class SourceFile implements SourceComponent { public final ImmutableList imports; public final ImmutableMap fields; - // POST-RESOLUTION - public List flattenedImports; + public final List included; - public SourceFile(ErrorReporter errorReporter, ShaderSources parent, ResourceLocation name, String source) { - this.parent = parent; + public SourceFile(ShaderSources sourceFinder, ResourceLocation name, String source) { + this.parent = sourceFinder; this.name = name; - this.source = source; - this.lines = new SourceLines(source); + this.source = new SourceLines(source); - this.imports = parseImports(errorReporter); - this.functions = parseFunctions(); - this.structs = parseStructs(); - this.fields = parseFields(); + this.imports = parseImports(source); + this.functions = parseFunctions(source); + this.structs = parseStructs(source); + this.fields = parseFields(source); + + this.included = imports.stream() + .map(i -> i.file) + .map(Span::toString) + .distinct() + .mapMulti((file, sink) -> { + try { + var loc = new ResourceLocation(file); + var sourceFile = sourceFinder.find(loc); + + if (sourceFile != null) { + sink.accept(sourceFile); + } + } catch (Exception ignored) { + } + }) + .toList(); } @Override public Collection included() { - return flattenedImports; + return included; } @Override - public String source(CompilationContext ctx) { - return ctx.sourceHeader(this) + this.genFinalSource(); + public String source() { + return this.genFinalSource(); } @Override @@ -88,52 +97,23 @@ public class SourceFile implements SourceComponent { return name; } - public void postResolve() { - this.flattenImports(); - } - - private void flattenImports() { - // somebody #used us and got resolved before we did - if (this.flattenedImports != null) { - return; - } - - if (this.imports.isEmpty()) { - this.flattenedImports = Collections.emptyList(); - return; - } - - ArrayList flat = new ArrayList<>(this.imports.size()); - - for (Import include : this.imports) { - SourceFile file = include.resolution.getFile(); - - file.flattenImports(); - - flat.addAll(file.flattenedImports); - flat.add(file); - } - - this.flattenedImports = flat.stream() - .distinct() - .toList(); - } - - 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 getLineSpan(int lineNo) { + int begin = source.getLineStart(lineNo); + int end = begin + source.getLine(lineNo) + .length(); + return new StringSpan(this, source.getCharPos(begin), source.getCharPos(end)); } public Span getLineSpanNoWhitespace(int line) { - int begin = lines.getLineStart(line); - int end = begin + lines.getLine(line).length(); + int begin = source.getLineStart(line); + int end = begin + source.getLine(line) + .length(); while (begin < end && Character.isWhitespace(source.charAt(begin))) { begin++; } - return new StringSpan(this, lines.getCharPos(begin), lines.getCharPos(end)); + return new StringSpan(this, source.getCharPos(begin), source.getCharPos(end)); } /** @@ -147,7 +127,7 @@ public class SourceFile implements SourceComponent { if (struct != null) return Optional.of(struct); - for (var include : flattenedImports) { + for (var include : included) { var external = include.structs.get(name); if (external != null) { @@ -169,7 +149,7 @@ public class SourceFile implements SourceComponent { if (local != null) return Optional.of(local); - for (var include : flattenedImports) { + for (var include : included) { var external = include.functions.get(name); if (external != null) { @@ -185,10 +165,10 @@ public class SourceFile implements SourceComponent { } public String printSource() { - return "Source for shader '" + name + "':\n" + lines.printLinesWithNumbers(); + return "Source for shader '" + name + "':\n" + source.printLinesWithNumbers(); } - private CharSequence genFinalSource() { + private String genFinalSource() { StringBuilder out = new StringBuilder(); int lastEnd = 0; @@ -203,13 +183,50 @@ public class SourceFile implements SourceComponent { out.append(this.source, lastEnd, this.source.length()); - return out; + return out.toString(); } + @Override + public String toString() { + return name.toString(); + } + + @Override + public boolean equals(Object o) { + // SourceFiles are only equal by reference. + return this == o; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + + /** + * Scan the source for {@code #use "..."} directives. + * Records the contents of the directive into an {@link Import} object, and marks the directive for elision. + */ + private ImmutableList parseImports(String source) { + Matcher uses = Import.PATTERN.matcher(source); + + var imports = ImmutableList.builder(); + + while (uses.find()) { + Span use = Span.fromMatcher(this, uses); + Span file = Span.fromMatcher(this, uses, 1); + + imports.add(new Import(use, file)); + } + + return imports.build(); + } + + /** * Scan the source for function definitions and "parse" them into objects that contain properties of the function. */ - private ImmutableMap parseFunctions() { + private ImmutableMap parseFunctions(String source) { Matcher matcher = ShaderFunction.PATTERN.matcher(source); Map functions = new HashMap<>(); @@ -220,7 +237,7 @@ public class SourceFile implements SourceComponent { Span args = Span.fromMatcher(this, matcher, 3); int blockStart = matcher.end(); - int blockEnd = findEndOfBlock(blockStart); + int blockEnd = findEndOfBlock(source, blockStart); Span self; Span body; @@ -243,7 +260,7 @@ public class SourceFile implements SourceComponent { /** * Scan the source for function definitions and "parse" them into objects that contain properties of the function. */ - private ImmutableMap parseStructs() { + private ImmutableMap parseStructs(String source) { Matcher matcher = ShaderStruct.PATTERN.matcher(source); ImmutableMap.Builder structs = ImmutableMap.builder(); @@ -263,7 +280,7 @@ public class SourceFile implements SourceComponent { /** * Scan the source for function definitions and "parse" them into objects that contain properties of the function. */ - private ImmutableMap parseFields() { + private ImmutableMap parseFields(String source) { Matcher matcher = ShaderField.PATTERN.matcher(source); ImmutableMap.Builder fields = ImmutableMap.builder(); @@ -280,36 +297,10 @@ public class SourceFile implements SourceComponent { return fields.build(); } - /** - * Scan the source for {@code #use "..."} directives. - * Records the contents of the directive into an {@link Import} object, and marks the directive for elision. - */ - private ImmutableList parseImports(ErrorReporter errorReporter) { - Matcher uses = Import.PATTERN.matcher(source); - - Set importedFiles = new HashSet<>(); - var imports = ImmutableList.builder(); - - while (uses.find()) { - Span use = Span.fromMatcher(this, uses); - Span file = Span.fromMatcher(this, uses, 1); - - String fileName = file.get(); - if (importedFiles.add(fileName)) { - var checked = Import.create(errorReporter, use, file); - if (checked != null) { - imports.add(checked); - } - } - } - - return imports.build(); - } - /** * Given the position of an opening brace, scans through the source for a paired closing brace. */ - private int findEndOfBlock(int start) { + private static int findEndOfBlock(String source, int start) { int blockDepth = 0; for (int i = start + 1; i < source.length(); i++) { char ch = source.charAt(i); @@ -324,20 +315,4 @@ public class SourceFile implements SourceComponent { return -1; } - - @Override - public String toString() { - return name.toString(); - } - - @Override - public boolean equals(Object o) { - // SourceFiles are only equal by reference. - return this == o; - } - - @Override - public int hashCode() { - return System.identityHashCode(this); - } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceFinder.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceFinder.java deleted file mode 100644 index 5a2a6c94f..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceFinder.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.jozufozu.flywheel.core.source; - -import org.jetbrains.annotations.Nullable; - -import net.minecraft.resources.ResourceLocation; - -/** - * A minimal source file lookup function. - */ -@FunctionalInterface -public interface SourceFinder { - - @Nullable - SourceFile findSource(ResourceLocation name); -} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java index f9ade475c..75dfd151c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java @@ -3,6 +3,8 @@ package com.jozufozu.flywheel.core.source; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.jetbrains.annotations.NotNull; + import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.source.span.CharPos; import com.jozufozu.flywheel.util.StringUtil; @@ -10,7 +12,7 @@ import com.jozufozu.flywheel.util.StringUtil; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; -public class SourceLines { +public class SourceLines implements CharSequence { private static final Pattern newLine = Pattern.compile("(\\r\\n|\\r|\\n)"); @@ -23,10 +25,12 @@ public class SourceLines { * 0-indexed line lookup */ private final ImmutableList lines; + public final String raw; - public SourceLines(String source) { - this.lineStarts = createLineLookup(source); - this.lines = getLines(source, lineStarts); + public SourceLines(String raw) { + this.raw = raw; + this.lineStarts = createLineLookup(raw); + this.lines = getLines(raw, lineStarts); } public int getLineCount() { @@ -38,7 +42,6 @@ public class SourceLines { } public int getLineStart(int lineNo) { - return lineStarts.getInt(lineNo); } @@ -99,4 +102,23 @@ public class SourceLines { return builder.build(); } + + @Override + public String toString() { + return raw; + } + + @NotNull + @Override + public CharSequence subSequence(int start, int end) { + return raw.subSequence(start, end); + } + + public char charAt(int i) { + return raw.charAt(i); + } + + public int length() { + return raw.length(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java index 6c156df7b..925b9dbb9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java @@ -100,7 +100,7 @@ public class ErrorBuilder { public ErrorBuilder pointAt(Span span, int ctxLines) { if (span.lines() == 1) { - SourceLines lines = span.getSourceFile().lines; + SourceLines lines = span.getSourceFile().source; int spanLine = span.firstLine(); diff --git a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java index 90224f0e2..607b8831b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java @@ -2,15 +2,11 @@ package com.jozufozu.flywheel.core.source.error; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.core.source.ShaderLoadingException; 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; @@ -23,15 +19,15 @@ public class ErrorReporter { } public void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg, CharSequence hint) { - Optional span = file.parent.index.getStructDefinitionsMatching(vertexName) - .stream() - .findFirst() - .map(ShaderStruct::getName); - - this.error(msg) - .pointAtFile(file) - .pointAt(vertexName, 1) - .hintIncludeFor(span.orElse(null), hint); + // Optional span = file.parent.index.getStructDefinitionsMatching(vertexName) + // .stream() + // .findFirst() + // .map(ShaderStruct::getName); + // + // this.error(msg) + // .pointAtFile(file) + // .pointAt(vertexName, 1) + // .hintIncludeFor(span.orElse(null), hint); } public void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg) { @@ -39,14 +35,14 @@ public class ErrorReporter { } public void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg, CharSequence hint) { - Optional span = file.parent.index.getFunctionDefinitionsMatching(functionName) - .stream() - .findFirst() - .map(ShaderFunction::getName); - - this.error(msg) - .pointAtFile(file) - .hintIncludeFor(span.orElse(null), hint); + // Optional span = file.parent.index.getFunctionDefinitionsMatching(functionName) + // .stream() + // .findFirst() + // .map(ShaderFunction::getName); + // + // this.error(msg) + // .pointAtFile(file) + // .hintIncludeFor(span.orElse(null), hint); } public ErrorBuilder generateFunctionArgumentCountError(String name, int requiredArguments, Span span) { diff --git a/src/main/java/com/jozufozu/flywheel/core/source/parse/AbstractShaderElement.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/AbstractShaderElement.java deleted file mode 100644 index d230d013e..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/source/parse/AbstractShaderElement.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.jozufozu.flywheel.core.source.parse; - -import com.jozufozu.flywheel.core.source.span.Span; - -public abstract class AbstractShaderElement { - - public final Span self; - - public AbstractShaderElement(Span self) { - this.self = self; - } - -} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/parse/Import.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/Import.java index 764bcc4ef..f348b5684 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/parse/Import.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/Import.java @@ -1,52 +1,19 @@ package com.jozufozu.flywheel.core.source.parse; -import java.util.Optional; import java.util.regex.Pattern; -import org.jetbrains.annotations.Nullable; - -import com.jozufozu.flywheel.core.source.FileResolution; -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.ResourceLocationException; -import net.minecraft.resources.ResourceLocation; - -public class Import extends AbstractShaderElement { +public class Import { public static final Pattern PATTERN = Pattern.compile("^\\s*#\\s*use\\s+\"(.*)\"", Pattern.MULTILINE); - public final FileResolution resolution; + public final Span self; + public final Span file; - protected Import(Span self, FileResolution resolution, Span file) { - super(self); - this.resolution = resolution.addSpan(file); + public Import(Span self, Span file) { + this.self = self; + this.file = file; } - @Nullable - public static Import create(ErrorReporter errorReporter, Span self, Span file) { - ResourceLocation fileLocation; - try { - fileLocation = new ResourceLocation(file.get()); - } catch (ResourceLocationException e) { - errorReporter.generateSpanError(file, "malformed source location"); - return null; - } - - return new Import(self, FileResolution.weak(fileLocation), file); - } - - public Optional getOptional() { - return Optional.ofNullable(resolution.getFile()); - } - - @Nullable - public SourceFile getFile() { - return resolution.getFile(); - } - - public ResourceLocation getFileLoc() { - return resolution.getFileLoc(); - } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderField.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderField.java index 39289ff22..82fe97e61 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderField.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderField.java @@ -6,16 +6,17 @@ import org.jetbrains.annotations.Nullable; import com.jozufozu.flywheel.core.source.span.Span; -public class ShaderField extends AbstractShaderElement { +public class ShaderField { public static final Pattern PATTERN = Pattern.compile("layout\\s*\\(location\\s*=\\s*(\\d+)\\)\\s+(in|out)\\s+([\\w\\d]+)\\s+" + "([\\w\\d]+)"); public final Span location; public final @Nullable Decoration decoration; public final Span type; public final Span name; + public final Span self; public ShaderField(Span self, Span location, Span inOut, Span type, Span name) { - super(self); + this.self = self; this.location = location; this.decoration = Decoration.fromSpan(inOut); diff --git a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderFunction.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderFunction.java index 2a817e4ca..ae20a67a7 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderFunction.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderFunction.java @@ -7,13 +7,14 @@ import java.util.stream.Collectors; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.source.span.Span; -public class ShaderFunction extends AbstractShaderElement { +public class ShaderFunction { // https://regexr.com/60n3d public static final Pattern PATTERN = Pattern.compile("(\\w+)\\s+(\\w+)\\s*\\(([\\w,\\s]*)\\)\\s*\\{"); public static final Pattern argument = Pattern.compile("(?:(inout|in|out) )?(\\w+)\\s+(\\w+)"); public static final Pattern assignment = Pattern.compile("(\\w+)\\s*="); + public final Span self; private final Span type; private final Span name; @@ -23,7 +24,7 @@ public class ShaderFunction extends AbstractShaderElement { private final ImmutableList parameters; public ShaderFunction(Span self, Span type, Span name, Span args, Span body) { - super(self); + this.self = self; this.type = type; this.name = name; this.args = args; diff --git a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderStruct.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderStruct.java index d89e5497e..2153dfa84 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderStruct.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderStruct.java @@ -7,19 +7,20 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.jozufozu.flywheel.core.source.span.Span; -public class ShaderStruct extends AbstractShaderElement { +public class ShaderStruct { // https://regexr.com/61rpe public static final Pattern PATTERN = Pattern.compile("struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d\\s,;]*)}\\s*;\\s"); public final Span name; public final Span body; + public final Span self; private final ImmutableList fields; private final ImmutableMap fields2Types; public ShaderStruct(Span self, Span name, Span body) { - super(self); + this.self = self; this.name = name; this.body = body; this.fields = parseFields(); diff --git a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderVariable.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderVariable.java index cf421e810..c202e8fa7 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderVariable.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderVariable.java @@ -2,15 +2,16 @@ package com.jozufozu.flywheel.core.source.parse; import com.jozufozu.flywheel.core.source.span.Span; -public class ShaderVariable extends AbstractShaderElement { +public class ShaderVariable { public final Span qualifierSpan; public final Span type; public final Span name; public final Qualifier qualifier; + public final Span self; public ShaderVariable(Span self, Span qualifier, Span type, Span name) { - super(self); + this.self = self; this.qualifierSpan = qualifier; this.type = type; this.name = name; diff --git a/src/main/java/com/jozufozu/flywheel/core/source/parse/StructField.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/StructField.java index 961ea3441..62b4649ab 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/parse/StructField.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/StructField.java @@ -4,14 +4,15 @@ import java.util.regex.Pattern; import com.jozufozu.flywheel.core.source.span.Span; -public class StructField extends AbstractShaderElement { +public class StructField { public static final Pattern fieldPattern = Pattern.compile("(\\S+)\\s*(\\S+);"); + public final Span self; public Span type; public Span name; public StructField(Span self, Span type, Span name) { - super(self); + this.self = self; this.type = type; this.name = name; } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/span/Span.java b/src/main/java/com/jozufozu/flywheel/core/source/span/Span.java index e295702b3..59bdb1f8a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/span/Span.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/span/Span.java @@ -23,7 +23,7 @@ public abstract class Span implements CharSequence, Comparable { protected final CharPos end; public Span(SourceFile in, int start, int end) { - this(in, in.lines.getCharPos(start), in.lines.getCharPos(end)); + this(in, in.source.getCharPos(start), in.source.getCharPos(end)); } public Span(SourceFile in, CharPos start, CharPos end) { diff --git a/src/main/java/com/jozufozu/flywheel/core/source/span/StringSpan.java b/src/main/java/com/jozufozu/flywheel/core/source/span/StringSpan.java index f91be1f6d..5e0ef31c9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/span/StringSpan.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/span/StringSpan.java @@ -19,8 +19,7 @@ public class StringSpan extends Span { @Override public String get() { - return in.source - .substring(start.pos(), end.pos()); + return in.source.raw.substring(start.pos(), end.pos()); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/util/ResourceUtil.java b/src/main/java/com/jozufozu/flywheel/util/ResourceUtil.java index c846f4203..1498752a0 100644 --- a/src/main/java/com/jozufozu/flywheel/util/ResourceUtil.java +++ b/src/main/java/com/jozufozu/flywheel/util/ResourceUtil.java @@ -27,4 +27,9 @@ public class ResourceUtil { return UNSAFE_CHARS.matcher(rl.toString()) .replaceAll("_"); } + + public static ResourceLocation prefixed(String basePath, ResourceLocation resourceLocation) { + String path = resourceLocation.getPath(); + return new ResourceLocation(resourceLocation.getNamespace(), basePath + path); + } } diff --git a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java index 4579e8ada..120af758a 100644 --- a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java +++ b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java @@ -13,6 +13,8 @@ import java.text.NumberFormat; import java.util.Arrays; import java.util.stream.Collectors; +import javax.annotation.Nonnull; + import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.backend.memory.FlwMemoryTracker; @@ -65,7 +67,8 @@ public class StringUtil { return value.substring(0, len); } - public static String readToString(InputStream is) { + @Nonnull + public static String readToString(InputStream is) throws IOException { ByteBuffer bytebuffer = null; try { @@ -73,17 +76,14 @@ public class StringUtil { int i = bytebuffer.position(); ((Buffer) bytebuffer).rewind(); return MemoryUtil.memASCII(bytebuffer, i); - } catch (IOException ignored) { - // } finally { if (bytebuffer != null) { FlwMemoryTracker.freeBuffer(bytebuffer); } } - - return null; } + @Nonnull public static ByteBuffer readToBuffer(InputStream is) throws IOException { if (is instanceof FileInputStream fileinputstream) { return readFileInputStream(fileinputstream); @@ -92,6 +92,7 @@ public class StringUtil { } } + @Nonnull private static ByteBuffer readInputStream(InputStream is) throws IOException { ByteBuffer bytebuffer = FlwMemoryTracker.mallocBuffer(8192); ReadableByteChannel readablebytechannel = Channels.newChannel(is); @@ -104,6 +105,7 @@ public class StringUtil { return bytebuffer; } + @Nonnull private static ByteBuffer readFileInputStream(FileInputStream fileinputstream) throws IOException { FileChannel filechannel = fileinputstream.getChannel(); ByteBuffer bytebuffer = FlwMemoryTracker.mallocBuffer((int) filechannel.size() + 1); From d17cfc8533c58af87eed4139454ad14d0843da7a Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Tue, 11 Oct 2022 20:16:15 -0700 Subject: [PATCH 3/9] Fix* the errors - *make the errors understandable without actually solving them - Straighten out shader compilation/error generation - Interpret errors in generated code - Compilation returns a result type instead of throwing an exception - Still need to reimplement source checks? - Make error messages prettier --- .../java/com/jozufozu/flywheel/Flywheel.java | 2 - .../com/jozufozu/flywheel/backend/Loader.java | 4 + .../flywheel/backend/gl/shader/GlShader.java | 50 +----- .../instancing/compile/Compilation.java | 149 +++++++++++++++ .../instancing/compile/CompilationResult.java | 29 +++ .../instancing/compile/FailedCompilation.java | 81 +++++++++ .../instancing/compile/FlwCompiler.java | 170 +++++++----------- .../compile/ShaderCompilationException.java | 32 ---- .../instancing/compile/ShaderCompiler.java | 99 ++++++++++ .../core/source/CompilationContext.java | 95 ---------- .../flywheel/core/source/SourceFile.java | 8 +- .../flywheel/core/source/SourceLines.java | 37 +++- .../core/source/error/ErrorBuilder.java | 125 +++++++------ .../core/source/error/ErrorLevel.java | 9 +- .../core/source/error/ErrorReporter.java | 18 +- .../core/source/error/lines/Divider.java | 2 +- .../core/source/error/lines/FileLine.java | 2 +- .../core/source/error/lines/HeaderLine.java | 2 +- .../core/source/generate/GlslBuilder.java | 27 ++- .../core/source/generate/GlslStmt.java | 2 +- .../jozufozu/flywheel/util/ConsoleColors.java | 77 ++++++++ .../com/jozufozu/flywheel/util/FlwUtil.java | 9 - .../jozufozu/flywheel/util/StringUtil.java | 13 ++ 23 files changed, 647 insertions(+), 395 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Compilation.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationResult.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FailedCompilation.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompilationException.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java create mode 100644 src/main/java/com/jozufozu/flywheel/util/ConsoleColors.java diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index ae55cd5de..5c0e809c7 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -8,7 +8,6 @@ import com.jozufozu.flywheel.backend.RenderWork; import com.jozufozu.flywheel.backend.ShadersModHandler; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.batching.DrawBuffer; -import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler; import com.jozufozu.flywheel.config.BackendTypeArgument; import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwConfig; @@ -80,7 +79,6 @@ public class Flywheel { forgeEventBus.addListener(FlwCommands::registerClientCommands); forgeEventBus.addListener(EventPriority.HIGHEST, QuadConverter::onReloadRenderers); - forgeEventBus.addListener(FlwCompiler::onReloadRenderers); forgeEventBus.addListener(Models::onReloadRenderers); forgeEventBus.addListener(DrawBuffer::onReloadRenderers); diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 5287e135c..07c940c10 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -39,6 +39,10 @@ public class Loader implements ResourceManagerReloadListener { var errorReporter = new ErrorReporter(); ShaderSources sources = new ShaderSources(errorReporter, manager); + if (FlwCompiler.INSTANCE != null) { + FlwCompiler.INSTANCE.delete(); + } + FlwCompiler.INSTANCE = new FlwCompiler(sources); ClientLevel level = Minecraft.getInstance().level; 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 0ffaa3485..a637b8298 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,38 +1,17 @@ package com.jozufozu.flywheel.backend.gl.shader; -import java.io.File; -import java.io.FileWriter; -import java.util.List; -import java.util.stream.Collectors; - 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.instancing.compile.ShaderCompilationException; - -import net.minecraft.client.Minecraft; -import net.minecraft.resources.ResourceLocation; public class GlShader extends GlObject { public final ShaderType type; - private final List parts; + private final String name; - public GlShader(String source, ShaderType type, List parts) throws ShaderCompilationException { - this.parts = parts; + public GlShader(int handle, ShaderType type, String name) { this.type = type; - int handle = GL20.glCreateShader(type.glEnum); - - GlCompat.safeShaderSource(handle, source); - GL20.glCompileShader(handle); - - dumpSource(source, type); - - if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) { - throw new ShaderCompilationException("Could not compile " + getName(), handle); - } + this.name = name; setHandle(handle); } @@ -42,26 +21,9 @@ public class GlShader extends GlObject { GL20.glDeleteShader(handle); } - public String getName() { - return parts.stream() - .map(ResourceLocation::toString) - .map(s -> s.replaceAll("/", "_") - .replaceAll(":", "\\$")) - .collect(Collectors.joining(";")); + @Override + public String toString() { + return "GlShader{" + type.name + handle() + " " + name + "}"; } - private void dumpSource(String source, ShaderType type) { - if (!Backend.DUMP_SHADER_SOURCE) { - return; - } - - File dir = new File(Minecraft.getInstance().gameDirectory, "flywheel_sources"); - dir.mkdirs(); - File file = new File(dir, type.getFileName(getName())); - try (FileWriter writer = new FileWriter(file)) { - writer.write(source); - } catch (Exception e) { - e.printStackTrace(); - } - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Compilation.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Compilation.java new file mode 100644 index 000000000..edb474865 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Compilation.java @@ -0,0 +1,149 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.io.File; +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.jetbrains.annotations.NotNull; +import org.lwjgl.opengl.GL20; + +import com.jozufozu.flywheel.backend.Backend; +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.gl.versioned.GlCompat; +import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.source.SourceFile; +import com.jozufozu.flywheel.util.StringUtil; + +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; + +/** + * Builder style class for compiling shaders. + *

+ * Keeps track of the source files and components used to compile a shader, + * and interprets/pretty prints any errors that occur. + */ +public class Compilation { + private final List files = new ArrayList<>(); + private final List componentNames = new ArrayList<>(); + private final StringBuilder generatedSource; + private final StringBuilder fullSource; + private final GLSLVersion glslVersion; + private final ShaderType shaderType; + private int generatedLines = 0; + + public Compilation(GLSLVersion glslVersion, ShaderType shaderType) { + this.generatedSource = new StringBuilder(); + this.fullSource = new StringBuilder(CompileUtil.generateHeader(glslVersion, shaderType)); + this.glslVersion = glslVersion; + this.shaderType = shaderType; + } + + @NotNull + public CompilationResult compile() { + int handle = GL20.glCreateShader(shaderType.glEnum); + var source = fullSource.toString(); + + GlCompat.safeShaderSource(handle, source); + GL20.glCompileShader(handle); + + var shaderName = buildShaderName(); + dumpSource(source, shaderType.getFileName(shaderName)); + + if (compiledSuccessfully(handle)) { + return CompilationResult.success(new GlShader(handle, shaderType, shaderName)); + } + + var errorLog = GL20.glGetShaderInfoLog(handle); + GL20.glDeleteShader(handle); + return CompilationResult.failure(new FailedCompilation(shaderName, files, generatedSource.toString(), errorLog)); + } + + public void enableExtension(String ext) { + fullSource.append("#extension ") + .append(ext) + .append(" : enable\n"); + } + + public void addComponentName(ResourceLocation name) { + componentNames.add(name); + } + + public void appendComponent(SourceComponent component) { + var source = component.source(); + + if (component instanceof SourceFile file) { + fullSource.append(sourceHeader(file)); + } else { + fullSource.append(generatedHeader(source, component.name() + .toString())); + } + + fullSource.append(source); + } + + private String sourceHeader(SourceFile sourceFile) { + return "#line " + 0 + ' ' + getOrCreateFileID(sourceFile) + " // " + sourceFile.name + '\n'; + } + + private String generatedHeader(String generatedCode, String comment) { + generatedSource.append(generatedCode); + int lines = StringUtil.countLines(generatedCode); + + // all generated code is put in file 0, + var out = "#line " + generatedLines + ' ' + 0; + + generatedLines += lines; + + return out + " // (generated) " + comment + '\n'; + } + + /** + * 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. + */ + private int getOrCreateFileID(SourceFile sourceFile) { + int i = files.indexOf(sourceFile); + if (i != -1) { + return i + 1; + } + + files.add(sourceFile); + return files.size(); + } + + @NotNull + private String buildShaderName() { + var components = componentNames.stream() + .map(ResourceLocation::toString) + .map(s -> s.replaceAll("/", "_") + .replaceAll(":", "\\$")) + .collect(Collectors.joining(";")); + return shaderType.name + glslVersion + ';' + components; + } + + private static void dumpSource(String source, String fileName) { + if (!Backend.DUMP_SHADER_SOURCE) { + return; + } + + File dir = new File(Minecraft.getInstance().gameDirectory, "flywheel_sources"); + dir.mkdirs(); + File file = new File(dir, fileName); + try (FileWriter writer = new FileWriter(file)) { + writer.write(source); + } catch (Exception e) { + Backend.LOGGER.error("Could not dump source.", e); + } + } + + private static boolean compiledSuccessfully(int handle) { + return GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) == GL20.GL_TRUE; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationResult.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationResult.java new file mode 100644 index 000000000..a5d352f73 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompilationResult.java @@ -0,0 +1,29 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import org.jetbrains.annotations.Nullable; + +import com.jozufozu.flywheel.backend.gl.shader.GlShader; + +public sealed interface CompilationResult { + @Nullable + default GlShader unwrap() { + if (this instanceof Success s) { + return s.shader(); + } + return null; + } + + record Success(GlShader shader) implements CompilationResult { + } + + record Failure(FailedCompilation failure) implements CompilationResult { + } + + static CompilationResult success(GlShader program) { + return new Success(program); + } + + static CompilationResult failure(FailedCompilation failure) { + return new Failure(failure); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FailedCompilation.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FailedCompilation.java new file mode 100644 index 000000000..8ef84b185 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FailedCompilation.java @@ -0,0 +1,81 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.jetbrains.annotations.NotNull; + +import com.jozufozu.flywheel.core.source.SourceFile; +import com.jozufozu.flywheel.core.source.SourceLines; +import com.jozufozu.flywheel.core.source.error.ErrorBuilder; +import com.jozufozu.flywheel.core.source.span.Span; +import com.jozufozu.flywheel.util.ConsoleColors; + +public class FailedCompilation { + private static final Pattern ERROR_LINE = Pattern.compile("(\\d+)\\((\\d+)\\) : (.*)"); + private final List files; + private final SourceLines generatedSource; + private final String errorLog; + private final String shaderName; + + public FailedCompilation(String shaderName, List files, String generatedSource, String errorLog) { + this.shaderName = shaderName; + this.files = files; + this.generatedSource = new SourceLines(generatedSource); + this.errorLog = errorLog; + } + + public String getMessage() { + return ConsoleColors.RED_BOLD_BRIGHT + "Failed to compile " + shaderName + ":\n" + errorString(); + } + + public String errorString() { + return errorStream().map(ErrorBuilder::build) + .collect(Collectors.joining("\n")); + } + + @NotNull + private Stream errorStream() { + return errorLog.lines() + .map(this::interpretErrorLine); + } + + private ErrorBuilder interpretErrorLine(String s) { + Matcher matcher = ERROR_LINE.matcher(s); + + if (matcher.find()) { + int fileId = Integer.parseInt(matcher.group(1)); + int lineNo = Integer.parseInt(matcher.group(2)); + var msg = matcher.group(3); + + if (fileId == 0) { + return interpretGeneratedError(lineNo, msg); + } else { + return interpretSourceError(fileId, lineNo, msg); + } + } + return ErrorBuilder.create() + .error(s); + } + + private ErrorBuilder interpretSourceError(int fileId, int lineNo, String msg) { + var sourceFile = files.get(fileId - 1); + Span span = sourceFile.getLineSpanNoWhitespace(lineNo); + + return ErrorBuilder.create() + .error(msg) + .pointAtFile(sourceFile) + .pointAt(span, 1); + } + + private ErrorBuilder interpretGeneratedError(int lineNo, String msg) { + return ErrorBuilder.create() + .error(msg) + .pointAtFile("[in generated source]") + .pointAtLine(generatedSource, lineNo, 1) + .note("This generally indicates a bug in Flywheel, not your shader code."); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java index 1b98f52b4..ab4370f58 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java @@ -2,12 +2,10 @@ package com.jozufozu.flywheel.backend.instancing.compile; import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; - -import org.jetbrains.annotations.NotNull; +import java.util.stream.Collectors; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; @@ -20,7 +18,6 @@ import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GLSLVersion; 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.instancing.indirect.IndirectComponent; import com.jozufozu.flywheel.core.BackendTypes; @@ -29,85 +26,73 @@ import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.Pipelines; import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.pipeline.SimplePipeline; -import com.jozufozu.flywheel.core.source.CompilationContext; import com.jozufozu.flywheel.core.source.ShaderLoadingException; import com.jozufozu.flywheel.core.source.ShaderSources; -import com.jozufozu.flywheel.core.source.SourceFile; -import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.util.StringUtil; -import net.minecraft.resources.ResourceLocation; - public class FlwCompiler { public static FlwCompiler INSTANCE; - public static void onReloadRenderers(ReloadRenderersEvent t) { - - } - - final Map pipelinePrograms = new HashMap<>(); - final Map, GlProgram> cullingPrograms = new HashMap<>(); - - boolean needsCrash = false; - final long compileStart = System.nanoTime(); - final Multimap, PipelineContext> uniformProviderGroups = ArrayListMultimap.create(); - final List pipelineContexts = new ArrayList<>(); - private final ShaderSources sources; private final VertexMaterialComponent vertexMaterialComponent; private final FragmentMaterialComponent fragmentMaterialComponent; + private final List pipelineContexts; + + + final ShaderCompiler shaderCompiler; + final Multimap, PipelineContext> uniformProviderGroups = ArrayListMultimap.create(); + final Map pipelinePrograms = new HashMap<>(); + final Map, GlProgram> cullingPrograms = new HashMap<>(); + final List errors = new ArrayList<>(); public FlwCompiler(ShaderSources sources) { + this.shaderCompiler = new ShaderCompiler(errors::add); this.sources = sources; this.vertexMaterialComponent = new VertexMaterialComponent(sources, ComponentRegistry.materials.vertexSources()); this.fragmentMaterialComponent = new FragmentMaterialComponent(sources, ComponentRegistry.materials.fragmentSources()); - for (SimplePipeline pipelineShader : BackendTypes.availablePipelineShaders()) { - for (StructType structType : ComponentRegistry.structTypes) { - for (VertexType vertexType : ComponentRegistry.vertexTypes) { - // TODO: context ubershaders, or not? - pipelineContexts.add(new PipelineContext(vertexType, structType, Components.WORLD, pipelineShader)); - } - } - } + this.pipelineContexts = buildPipelineSet(); // TODO: analyze uniform providers and group them into sets; break up this ctor for (PipelineContext context : pipelineContexts) { - try { - var glProgram = compilePipelineContext(context); - pipelinePrograms.put(context, glProgram); - } catch (ShaderCompilationException e) { - needsCrash = true; - Backend.LOGGER.error(e.errors); - } + compilePipelineContext(context); } for (StructType type : ComponentRegistry.structTypes) { - try { - var glProgram = compileComputeCuller(type); - cullingPrograms.put(type, glProgram); - } catch (ShaderCompilationException e) { - needsCrash = true; - Backend.LOGGER.error(e.errors); - } + compileComputeCuller(type); } finish(); } - public void finish() { + private void finish() { long compileEnd = System.nanoTime(); + int programCount = pipelineContexts.size() + ComponentRegistry.structTypes.size(); + int shaderCount = shaderCompiler.shaderCount(); + int errorCount = errors.size(); + var elapsed = StringUtil.formatTime(compileEnd - compileStart); - Backend.LOGGER.info("Compiled " + pipelineContexts.size() + " programs in " + StringUtil.formatTime(compileEnd - compileStart)); + Backend.LOGGER.info("Compiled " + programCount + " programs and " + shaderCount + " shaders in " + elapsed + " with " + errorCount + " errors."); - if (needsCrash) { - throw new ShaderLoadingException("Compilation failed"); + if (errorCount > 0) { + var details = errors.stream() + .map(FailedCompilation::getMessage) + .collect(Collectors.joining("\n")); + throw new ShaderLoadingException("Compilation failed.\n" + details); } } + public void delete() { + pipelinePrograms.values() + .forEach(GlProgram::delete); + cullingPrograms.values() + .forEach(GlProgram::delete); + shaderCompiler.delete(); + } + public GlProgram getPipelineProgram(VertexType vertexType, StructType structType, ContextShader contextShader, SimplePipeline pipelineShader) { return pipelinePrograms.get(new PipelineContext(vertexType, structType, contextShader, pipelineShader)); } @@ -116,28 +101,36 @@ public class FlwCompiler { return cullingPrograms.get(structType); } - protected GlProgram compilePipelineContext(PipelineContext ctx) throws ShaderCompilationException { - + private void compilePipelineContext(PipelineContext ctx) { var glslVersion = ctx.pipelineShader() .glslVersion(); - var vertex = compileShader(glslVersion, ShaderType.VERTEX, getVertexComponents(ctx)); - var fragment = compileShader(glslVersion, ShaderType.FRAGMENT, getFragmentComponents(ctx)); + var vertex = shaderCompiler.compile(glslVersion, ShaderType.VERTEX, getVertexComponents(ctx)); + var fragment = shaderCompiler.compile(glslVersion, ShaderType.FRAGMENT, getFragmentComponents(ctx)); - return ctx.contextShader() + if (vertex == null || fragment == null) { + return; + } + + pipelinePrograms.put(ctx, ctx.contextShader() .factory() .create(new ProgramAssembler().attachShader(vertex) .attachShader(fragment) - .link()); + .link())); } - protected GlProgram compileComputeCuller(StructType structType) { + private void compileComputeCuller(StructType structType) { + var result = shaderCompiler.compile(GLSLVersion.V460, ShaderType.COMPUTE, getComputeComponents(structType)); - return new GlProgram(new ProgramAssembler().attachShader(compileShader(GLSLVersion.V460, ShaderType.COMPUTE, getComputeComponents(structType))) - .link()); + if (result == null) { + return; + } + + cullingPrograms.put(structType, new GlProgram(new ProgramAssembler().attachShader(result) + .link())); } - ImmutableList getVertexComponents(PipelineContext ctx) { + private ImmutableList getVertexComponents(PipelineContext ctx) { var instanceAssembly = ctx.pipelineShader() .assemble(new Pipeline.InstanceAssemblerContext(sources, ctx.vertexType(), ctx.structType())); @@ -157,7 +150,7 @@ public class FlwCompiler { return ImmutableList.of(vertexMaterialComponent, instanceAssembly, layout, instance, context, pipeline); } - ImmutableList getFragmentComponents(PipelineContext ctx) { + private ImmutableList getFragmentComponents(PipelineContext ctx) { var context = sources.find(ctx.contextShader() .fragmentShader() .resourceLocation()); @@ -167,7 +160,7 @@ public class FlwCompiler { return ImmutableList.of(fragmentMaterialComponent, context, pipeline); } - @NotNull ImmutableList getComputeComponents(StructType structType) { + private ImmutableList getComputeComponents(StructType structType) { var instanceAssembly = new IndirectComponent(sources, structType); var instance = sources.find(structType.getInstanceShader() .resourceLocation()); @@ -176,55 +169,16 @@ public class FlwCompiler { return ImmutableList.of(instanceAssembly, instance, pipeline); } - protected GlShader compileShader(GLSLVersion glslVersion, ShaderType shaderType, ImmutableList sourceComponents) { - StringBuilder finalSource = new StringBuilder(CompileUtil.generateHeader(glslVersion, shaderType)); - finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n"); - finalSource.append("#extension GL_ARB_conservative_depth : enable\n"); - - var ctx = new CompilationContext(); - var names = ImmutableList.builder(); - - for (var include : depthFirstInclude(sourceComponents)) { - appendFinalSource(finalSource, ctx, include); + private static List buildPipelineSet() { + ImmutableList.Builder builder = ImmutableList.builder(); + for (SimplePipeline pipelineShader : BackendTypes.availablePipelineShaders()) { + for (StructType structType : ComponentRegistry.structTypes) { + for (VertexType vertexType : ComponentRegistry.vertexTypes) { + // TODO: context ubershaders, or not? + builder.add(new PipelineContext(vertexType, structType, Components.WORLD, pipelineShader)); + } + } } - - for (var component : sourceComponents) { - appendFinalSource(finalSource, ctx, component); - names.add(component.name()); - } - - try { - return new GlShader(finalSource.toString(), shaderType, names.build()); - } catch (ShaderCompilationException e) { - throw e.withErrorLog(ctx); - } - } - - private static void appendFinalSource(StringBuilder finalSource, CompilationContext ctx, SourceComponent component) { - var source = component.source(); - - if (component instanceof SourceFile file) { - finalSource.append(ctx.sourceHeader(file)); - } else { - finalSource.append(ctx.generatedHeader(source, component.name() - .toString())); - } - - finalSource.append(source); - } - - protected static Set depthFirstInclude(ImmutableList root) { - var included = new LinkedHashSet(); // linked to preserve order - for (var component : root) { - recursiveDepthFirstInclude(included, component); - } - return included; - } - - protected static void recursiveDepthFirstInclude(Set included, SourceComponent component) { - for (var include : component.included()) { - recursiveDepthFirstInclude(included, include); - } - included.addAll(component.included()); + return builder.build(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompilationException.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompilationException.java deleted file mode 100644 index e66a6a2a2..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompilationException.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.compile; - -import org.lwjgl.opengl.GL20; - -import com.jozufozu.flywheel.core.source.CompilationContext; -import com.jozufozu.flywheel.core.source.ShaderLoadingException; - -public class ShaderCompilationException extends ShaderLoadingException { - - private final int shaderHandle; - - public String errors = ""; - - public ShaderCompilationException(String message, int shaderHandle) { - super(message); - this.shaderHandle = shaderHandle; - } - - public ShaderLoadingException withErrorLog(CompilationContext ctx) { - if (this.shaderHandle == -1) - return this; - - this.errors = ctx.parseErrors(GL20.glGetShaderInfoLog(this.shaderHandle)); - - return this; - } - - @Override - public String getMessage() { - return super.getMessage() + '\n' + this.errors; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java new file mode 100644 index 000000000..a2a6e014a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java @@ -0,0 +1,99 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.google.common.collect.ImmutableList; +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.core.SourceComponent; + +public class ShaderCompiler { + private final Map shaderCache = new HashMap<>(); + private final Consumer errorConsumer; + + public ShaderCompiler(Consumer errorConsumer) { + this.errorConsumer = errorConsumer; + } + + public int shaderCount() { + return shaderCache.size(); + } + + @Nullable + public GlShader compile(GLSLVersion glslVersion, ShaderType shaderType, ImmutableList sourceComponents) { + var key = new ShaderKey(glslVersion, shaderType, sourceComponents); + var cached = shaderCache.get(key); + if (cached != null) { + return cached.unwrap(); + } + + CompilationResult out = compileUncached(glslVersion, shaderType, sourceComponents); + shaderCache.put(key, out); + return unwrapAndReportError(out); + } + + public void delete() { + shaderCache.values() + .stream() + .map(CompilationResult::unwrap) + .filter(Objects::nonNull) + .forEach(GlShader::delete); + } + + @Nullable + private GlShader unwrapAndReportError(CompilationResult result) { + if (result instanceof CompilationResult.Success s) { + return s.shader(); + } else if (result instanceof CompilationResult.Failure f) { + errorConsumer.accept(f.failure()); + } + return null; + } + + @NotNull + private static CompilationResult compileUncached(GLSLVersion glslVersion, ShaderType shaderType, ImmutableList sourceComponents) { + var ctx = new Compilation(glslVersion, shaderType); + ctx.enableExtension("GL_ARB_explicit_attrib_location"); + ctx.enableExtension("GL_ARB_conservative_depth"); + + for (var include : depthFirstInclude(sourceComponents)) { + ctx.appendComponent(include); + } + + for (var component : sourceComponents) { + ctx.appendComponent(component); + ctx.addComponentName(component.name()); + } + + return ctx.compile(); + } + + private static Set depthFirstInclude(ImmutableList root) { + var included = new LinkedHashSet(); // linked to preserve order + for (var component : root) { + recursiveDepthFirstInclude(included, component); + } + return included; + } + + private static void recursiveDepthFirstInclude(Set included, SourceComponent component) { + for (var include : component.included()) { + recursiveDepthFirstInclude(included, include); + } + included.addAll(component.included()); + } + + private record ShaderKey(GLSLVersion glslVersion, ShaderType shaderType, + ImmutableList sourceComponents) { + + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java b/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java deleted file mode 100644 index 00af5da27..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.jozufozu.flywheel.core.source; - -import java.util.ArrayList; -import java.util.List; - -import org.jetbrains.annotations.Nullable; - -import com.jozufozu.flywheel.core.source.error.ErrorBuilder; -import com.jozufozu.flywheel.core.source.span.Span; - -public class CompilationContext { - public final List files = new ArrayList<>(); - - private String generatedSource = ""; - private int generatedLines = 0; - - - public String sourceHeader(SourceFile sourceFile) { - return "#line " + 0 + ' ' + getOrCreateFileID(sourceFile) + " // " + sourceFile.name + '\n'; - } - - public String generatedHeader(String generatedCode, @Nullable String comment) { - generatedSource += generatedCode; - int lines = generatedCode.split("\n").length; - - var out = "#line " + generatedLines + ' ' + 0; - - generatedLines += lines; - - if (comment == null) { - comment = ""; - } - - return out + " // (generated) " + comment + '\n'; - } - - public boolean contains(SourceFile sourceFile) { - return files.contains(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. - */ - private int getOrCreateFileID(SourceFile sourceFile) { - int i = files.indexOf(sourceFile); - if (i != -1) { - return i + 1; - } - - files.add(sourceFile); - return files.size(); - } - - public Span getLineSpan(int fileId, int lineNo) { - if (fileId == 0) { - // TODO: Valid spans for generated code. - return null; - } - return getFile(fileId).getLineSpanNoWhitespace(lineNo); - } - - private SourceFile getFile(int fileId) { - return files.get(fileId - 1); - } - - public String parseErrors(String log) { - List lines = log.lines() - .toList(); - - 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'); - } - } - return errors.toString(); - } - - @Nullable - private ErrorBuilder parseCompilerError(String line) { - try { - return ErrorBuilder.fromLogLine(this, line); - } catch (Exception ignored) { - } - - return null; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java index fea1383af..9e72e0776 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java @@ -98,15 +98,15 @@ public class SourceFile implements SourceComponent { } public Span getLineSpan(int lineNo) { - int begin = source.getLineStart(lineNo); - int end = begin + source.getLine(lineNo) + int begin = source.lineStartIndex(lineNo); + int end = begin + source.lineString(lineNo) .length(); return new StringSpan(this, source.getCharPos(begin), source.getCharPos(end)); } public Span getLineSpanNoWhitespace(int line) { - int begin = source.getLineStart(line); - int end = begin + source.getLine(line) + int begin = source.lineStartIndex(line); + int end = begin + source.lineString(line) .length(); while (begin < end && Character.isWhitespace(source.charAt(begin))) { diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java index 75dfd151c..e4f1eada8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java @@ -11,6 +11,7 @@ import com.jozufozu.flywheel.util.StringUtil; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.ints.IntLists; public class SourceLines implements CharSequence { @@ -33,15 +34,15 @@ public class SourceLines implements CharSequence { this.lines = getLines(raw, lineStarts); } - public int getLineCount() { + public int count() { return lines.size(); } - public String getLine(int lineNo) { + public String lineString(int lineNo) { return lines.get(lineNo); } - public int getLineStart(int lineNo) { + public int lineStartIndex(int lineNo) { return lineStarts.getInt(lineNo); } @@ -76,9 +77,12 @@ public class SourceLines implements CharSequence { /** * Scan the source for line breaks, recording the position of the first character of each line. - * @param source */ private static IntList createLineLookup(String source) { + if (source.isEmpty()) { + return IntLists.emptyList(); + } + IntList l = new IntArrayList(); l.add(0); // first line is always at position 0 @@ -87,6 +91,7 @@ public class SourceLines implements CharSequence { while (matcher.find()) { l.add(matcher.end()); } + return l; } @@ -121,4 +126,28 @@ public class SourceLines implements CharSequence { public int length() { return raw.length(); } + + public int lineStartCol(int spanLine) { + return 0; + } + + public int lineWidth(int spanLine) { + return lines.get(spanLine) + .length(); + } + + public int lineStartColTrimmed(final int line) { + final var lineString = lineString(line); + final int end = lineString.length(); + + int col = 0; + while (col < end && Character.isWhitespace(charAt(col))) { + col++; + } + return col; + } + + public int lineStartPosTrimmed(final int line) { + return lineStartIndex(line) + lineStartColTrimmed(line); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java index 925b9dbb9..a234d9433 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java @@ -2,12 +2,9 @@ package com.jozufozu.flywheel.core.source.error; import java.util.ArrayList; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.jetbrains.annotations.Nullable; -import com.jozufozu.flywheel.core.source.CompilationContext; import com.jozufozu.flywheel.core.source.SourceFile; import com.jozufozu.flywheel.core.source.SourceLines; import com.jozufozu.flywheel.core.source.error.lines.ErrorLine; @@ -17,72 +14,61 @@ 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; +import com.jozufozu.flywheel.util.ConsoleColors; +import com.jozufozu.flywheel.util.StringUtil; public class ErrorBuilder { - private static final Pattern ERROR_LINE = Pattern.compile("(\\d+)\\((\\d+)\\) : (.*)"); - private final List lines = new ArrayList<>(); - public ErrorBuilder() { + private ErrorBuilder() { } - public static ErrorBuilder error(CharSequence msg) { - return new ErrorBuilder() - .header(ErrorLevel.ERROR, msg); + public static ErrorBuilder create() { + return new ErrorBuilder(); } - public static ErrorBuilder compError(CharSequence msg) { - return new ErrorBuilder() - .extra(msg); + public ErrorBuilder error(String msg) { + return header(ErrorLevel.ERROR, msg); } - public static ErrorBuilder warn(CharSequence msg) { - return new ErrorBuilder() - .header(ErrorLevel.WARN, msg); + public ErrorBuilder warn(String msg) { + return header(ErrorLevel.WARN, msg); } - @Nullable - public static ErrorBuilder fromLogLine(CompilationContext 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)); - - if (span == null) { - return ErrorBuilder.compError("Error in generated code"); - } - - return ErrorBuilder.compError(msg) - .pointAtFile(span.getSourceFile()) - .pointAt(span, 1); - } else { - return null; - } + public ErrorBuilder hint(String msg) { + return header(ErrorLevel.HINT, msg); } - public ErrorBuilder header(ErrorLevel level, CharSequence msg) { + public ErrorBuilder note(String msg) { + return header(ErrorLevel.NOTE, msg); + } + + public ErrorBuilder header(ErrorLevel level, String msg) { lines.add(new HeaderLine(level.toString(), msg)); return this; } - public ErrorBuilder extra(CharSequence msg) { - lines.add(new TextLine(msg.toString())); + public ErrorBuilder extra(String msg) { + lines.add(new TextLine(msg)); return this; } public ErrorBuilder pointAtFile(SourceFile file) { - lines.add(new FileLine(file.name.toString())); + return pointAtFile(file.name.toString()); + } + + public ErrorBuilder pointAtFile(String file) { + lines.add(new FileLine(file)); return this; } - public ErrorBuilder hintIncludeFor(@Nullable Span span, CharSequence msg) { - if (span == null) return this; + public ErrorBuilder hintIncludeFor(@Nullable Span span, String msg) { + if (span == null) { + return this; + } + SourceFile sourceFile = span.getSourceFile(); String builder = "add " + sourceFile.importStatement() + ' ' + msg + "\n defined here:"; @@ -98,28 +84,37 @@ public class ErrorBuilder { } public ErrorBuilder pointAt(Span span, int ctxLines) { - if (span.lines() == 1) { SourceLines lines = span.getSourceFile().source; int spanLine = span.firstLine(); + int firstCol = span.getStart() + .col(); + int lastCol = span.getEnd() + .col(); - int firstLine = Math.max(0, spanLine - ctxLines); - int lastLine = Math.min(lines.getLineCount(), spanLine + ctxLines); + pointAtLine(lines, spanLine, ctxLines, firstCol, lastCol); + } - int firstCol = span.getStart() - .col(); - int lastCol = span.getEnd() - .col(); + return this; + } - for (int i = firstLine; i <= lastLine; i++) { - CharSequence line = lines.getLine(i); + public ErrorBuilder pointAtLine(SourceLines lines, int spanLine, int ctxLines) { + return pointAtLine(lines, spanLine, ctxLines, lines.lineStartColTrimmed(spanLine), lines.lineWidth(spanLine)); + } - this.lines.add(SourceLine.numbered(i + 1, line.toString())); + public ErrorBuilder pointAtLine(SourceLines lines, int spanLine, int ctxLines, int firstCol, int lastCol) { + int firstLine = Math.max(0, spanLine - ctxLines); + int lastLine = Math.min(lines.count(), spanLine + ctxLines); - if (i == spanLine) { - this.lines.add(new SpanHighlightLine(firstCol, lastCol)); - } + + for (int i = firstLine; i <= lastLine; i++) { + CharSequence line = lines.lineString(i); + + this.lines.add(SourceLine.numbered(i + 1, line.toString())); + + if (i == spanLine) { + this.lines.add(new SpanHighlightLine(firstCol, lastCol)); } } @@ -127,23 +122,25 @@ public class ErrorBuilder { } public String build() { - - int maxLength = -1; + int maxMargin = -1; for (ErrorLine line : lines) { - int length = line.neededMargin(); + int neededMargin = line.neededMargin(); - if (length > maxLength) { - maxLength = length; + if (neededMargin > maxMargin) { + maxMargin = neededMargin; } } StringBuilder builder = new StringBuilder(); - builder.append('\n'); for (ErrorLine line : lines) { - int length = line.neededMargin(); + int neededMargin = line.neededMargin(); - builder.append(FlwUtil.repeatChar(' ', maxLength - length)) - .append(line.build()) + if (neededMargin >= 0) { + builder.append(StringUtil.repeatChar(' ', maxMargin - neededMargin)); + } + + builder.append(line.build()) + .append(ConsoleColors.RESET) .append('\n'); } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorLevel.java b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorLevel.java index e45345124..316e3ceff 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorLevel.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorLevel.java @@ -1,9 +1,12 @@ package com.jozufozu.flywheel.core.source.error; +import com.jozufozu.flywheel.util.ConsoleColors; + public enum ErrorLevel { - WARN("warn"), - ERROR("error"), - HINT("hint"), + WARN(ConsoleColors.YELLOW + "warn"), + ERROR(ConsoleColors.RED + "error"), + HINT(ConsoleColors.WHITE_BRIGHT + "hint"), + NOTE(ConsoleColors.WHITE_BRIGHT + "note"), ; private final String error; diff --git a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java index 607b8831b..b287f9627 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorReporter.java @@ -9,6 +9,7 @@ import com.jozufozu.flywheel.core.source.ShaderLoadingException; import com.jozufozu.flywheel.core.source.SourceFile; import com.jozufozu.flywheel.core.source.span.Span; import com.jozufozu.flywheel.util.FlwUtil; +import com.jozufozu.flywheel.util.StringUtil; public class ErrorReporter { @@ -60,18 +61,17 @@ public class ErrorReporter { public ErrorBuilder generateSpanError(Span span, String message) { SourceFile file = span.getSourceFile(); - return error(message) - .pointAtFile(file) + return error(message).pointAtFile(file) .pointAt(span, 2); } public ErrorBuilder generateFileError(SourceFile file, String message) { - return error(message) - .pointAtFile(file); + return error(message).pointAtFile(file); } - public ErrorBuilder error(CharSequence msg) { - var out = ErrorBuilder.error(msg); + public ErrorBuilder error(String msg) { + var out = ErrorBuilder.create() + .error(msg); reportedErrors.add(out); return out; } @@ -88,9 +88,7 @@ public class ErrorReporter { return new ShaderLoadingException(allErrors); } - public static void printLines(CharSequence source) { - String string = source.toString(); - + public static void printLines(String string) { List lines = string.lines() .toList(); @@ -103,7 +101,7 @@ public class ErrorReporter { for (int i = 0; i < size; i++) { builder.append(i) - .append(FlwUtil.repeatChar(' ', maxWidth - FlwUtil.numDigits(i))) + .append(StringUtil.repeatChar(' ', maxWidth - FlwUtil.numDigits(i))) .append("| ") .append(lines.get(i)) .append('\n'); diff --git a/src/main/java/com/jozufozu/flywheel/core/source/error/lines/Divider.java b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/Divider.java index c9206c740..bca13fdc4 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/error/lines/Divider.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/Divider.java @@ -2,7 +2,7 @@ package com.jozufozu.flywheel.core.source.error.lines; public enum Divider { BAR(" | "), - ARROW("-->"), + ARROW("-> "), ; private final String s; diff --git a/src/main/java/com/jozufozu/flywheel/core/source/error/lines/FileLine.java b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/FileLine.java index f1facc2d5..3bcf9cbe9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/error/lines/FileLine.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/FileLine.java @@ -4,7 +4,7 @@ public record FileLine(String fileName) implements ErrorLine { @Override public String left() { - return "--"; + return "-"; } @Override diff --git a/src/main/java/com/jozufozu/flywheel/core/source/error/lines/HeaderLine.java b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/HeaderLine.java index e806cc399..25cd63783 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/error/lines/HeaderLine.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/lines/HeaderLine.java @@ -4,7 +4,7 @@ public record HeaderLine(String level, CharSequence message) implements ErrorLin @Override public int neededMargin() { - return 0; + return -1; } @Override diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java index ef31652f9..45006833e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java @@ -8,8 +8,6 @@ import java.util.stream.Collectors; import com.jozufozu.flywheel.util.Pair; public class GlslBuilder { - public static final String INDENT = " "; - private final List elements = new ArrayList<>(); public void define(String name, String value) { @@ -39,16 +37,12 @@ public class GlslBuilder { public String build() { return elements.stream() - .map(GlslRootElement::minPrint) + .map(GlslRootElement::prettyPrint) .collect(Collectors.joining("\n")); } - public static String indent(int indentation) { - return INDENT.repeat(indentation); - } - public interface GlslRootElement { - String minPrint(); + String prettyPrint(); } public enum Separators implements GlslRootElement { @@ -62,14 +56,14 @@ public class GlslBuilder { } @Override - public String minPrint() { + public String prettyPrint() { return separator; } } public record Define(String name, String value) implements GlslRootElement { @Override - public String minPrint() { + public String prettyPrint() { return "#define " + name + " " + value; } } @@ -96,7 +90,7 @@ public class GlslBuilder { } @Override - public String minPrint() { + public String prettyPrint() { return "layout(location = " + binding + ") in " + type + " " + name + ";"; } } @@ -116,16 +110,16 @@ public class GlslBuilder { private String buildFields() { return fields.stream() - .map(p -> INDENT + p.first() + ' ' + p.second() + ';') + .map(p -> p.first() + ' ' + p.second() + ';') .collect(Collectors.joining("\n")); } - public String minPrint() { + public String prettyPrint() { return """ struct %s { %s }; - """.formatted(name, buildFields()); + """.formatted(name, buildFields().indent(4)); } } @@ -160,12 +154,13 @@ public class GlslBuilder { return this; } - public String minPrint() { + public String prettyPrint() { return """ %s %s(%s) { %s } - """.formatted(returnType, name, buildArguments(), body.prettyPrint()); + """.formatted(returnType, name, buildArguments(), body.prettyPrint() + .indent(4)); } private String buildArguments() { diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java index 241184112..89a3a9dc8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java @@ -54,7 +54,7 @@ public interface GlslStmt extends LangItem { .prettyPrint(); return """ case %s: - %s""".formatted(variant, block); + %s""".formatted(variant, block.indent(4)); } } } diff --git a/src/main/java/com/jozufozu/flywheel/util/ConsoleColors.java b/src/main/java/com/jozufozu/flywheel/util/ConsoleColors.java new file mode 100644 index 000000000..9a67f6d00 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/util/ConsoleColors.java @@ -0,0 +1,77 @@ +package com.jozufozu.flywheel.util; + +// https://stackoverflow.com/a/45444716 +public class ConsoleColors { + // Reset + public static final String RESET = "\033[0m"; // Text Reset + + // Regular Colors + public static final String BLACK = "\033[0;30m"; // BLACK + public static final String RED = "\033[0;31m"; // RED + public static final String GREEN = "\033[0;32m"; // GREEN + public static final String YELLOW = "\033[0;33m"; // YELLOW + public static final String BLUE = "\033[0;34m"; // BLUE + public static final String PURPLE = "\033[0;35m"; // PURPLE + public static final String CYAN = "\033[0;36m"; // CYAN + public static final String WHITE = "\033[0;37m"; // WHITE + + // Bold + public static final String BLACK_BOLD = "\033[1;30m"; // BLACK + public static final String RED_BOLD = "\033[1;31m"; // RED + public static final String GREEN_BOLD = "\033[1;32m"; // GREEN + public static final String YELLOW_BOLD = "\033[1;33m"; // YELLOW + public static final String BLUE_BOLD = "\033[1;34m"; // BLUE + public static final String PURPLE_BOLD = "\033[1;35m"; // PURPLE + public static final String CYAN_BOLD = "\033[1;36m"; // CYAN + public static final String WHITE_BOLD = "\033[1;37m"; // WHITE + + // Underline + public static final String BLACK_UNDERLINED = "\033[4;30m"; // BLACK + public static final String RED_UNDERLINED = "\033[4;31m"; // RED + public static final String GREEN_UNDERLINED = "\033[4;32m"; // GREEN + public static final String YELLOW_UNDERLINED = "\033[4;33m"; // YELLOW + public static final String BLUE_UNDERLINED = "\033[4;34m"; // BLUE + public static final String PURPLE_UNDERLINED = "\033[4;35m"; // PURPLE + public static final String CYAN_UNDERLINED = "\033[4;36m"; // CYAN + public static final String WHITE_UNDERLINED = "\033[4;37m"; // WHITE + + // Background + public static final String BLACK_BACKGROUND = "\033[40m"; // BLACK + public static final String RED_BACKGROUND = "\033[41m"; // RED + public static final String GREEN_BACKGROUND = "\033[42m"; // GREEN + public static final String YELLOW_BACKGROUND = "\033[43m"; // YELLOW + public static final String BLUE_BACKGROUND = "\033[44m"; // BLUE + public static final String PURPLE_BACKGROUND = "\033[45m"; // PURPLE + public static final String CYAN_BACKGROUND = "\033[46m"; // CYAN + public static final String WHITE_BACKGROUND = "\033[47m"; // WHITE + + // High Intensity + public static final String BLACK_BRIGHT = "\033[0;90m"; // BLACK + public static final String RED_BRIGHT = "\033[0;91m"; // RED + public static final String GREEN_BRIGHT = "\033[0;92m"; // GREEN + public static final String YELLOW_BRIGHT = "\033[0;93m"; // YELLOW + public static final String BLUE_BRIGHT = "\033[0;94m"; // BLUE + public static final String PURPLE_BRIGHT = "\033[0;95m"; // PURPLE + public static final String CYAN_BRIGHT = "\033[0;96m"; // CYAN + public static final String WHITE_BRIGHT = "\033[0;97m"; // WHITE + + // Bold High Intensity + public static final String BLACK_BOLD_BRIGHT = "\033[1;90m"; // BLACK + public static final String RED_BOLD_BRIGHT = "\033[1;91m"; // RED + public static final String GREEN_BOLD_BRIGHT = "\033[1;92m"; // GREEN + public static final String YELLOW_BOLD_BRIGHT = "\033[1;93m";// YELLOW + public static final String BLUE_BOLD_BRIGHT = "\033[1;94m"; // BLUE + public static final String PURPLE_BOLD_BRIGHT = "\033[1;95m";// PURPLE + public static final String CYAN_BOLD_BRIGHT = "\033[1;96m"; // CYAN + public static final String WHITE_BOLD_BRIGHT = "\033[1;97m"; // WHITE + + // High Intensity backgrounds + public static final String BLACK_BACKGROUND_BRIGHT = "\033[0;100m";// BLACK + public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m";// RED + public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m";// GREEN + public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m";// YELLOW + public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m";// BLUE + public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; // PURPLE + public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; // CYAN + public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; // WHITE +} diff --git a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java b/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java index be55e6518..ed3df090d 100644 --- a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java +++ b/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java @@ -1,6 +1,5 @@ package com.jozufozu.flywheel.util; -import java.util.Arrays; import java.util.Map; import java.util.stream.Stream; @@ -22,14 +21,6 @@ public class FlwUtil { return ((BlockEntityRenderDispatcherAccessor) mc.getBlockEntityRenderDispatcher()).flywheel$getRenderers(); } - public static String repeatChar(char c, int n) { - char[] arr = new char[n]; - - Arrays.fill(arr, c); - - return new String(arr); - } - public static PoseStack copyPoseStack(PoseStack stack) { PoseStack copy = new PoseStack(); copy.last().pose().load(stack.last().pose()); diff --git a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java index 120af758a..46c9e3d25 100644 --- a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java +++ b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java @@ -23,6 +23,11 @@ public class StringUtil { private static final NumberFormat THREE_DECIMAL_PLACES = new DecimalFormat("#0.000"); + public static int countLines(String s) { + return (int) s.lines() + .count(); + } + public static String formatBytes(long bytes) { if (bytes < 1024) { return bytes + " B"; @@ -114,4 +119,12 @@ public class StringUtil { } return bytebuffer; } + + public static String repeatChar(char c, int n) { + char[] arr = new char[n]; + + Arrays.fill(arr, c); + + return new String(arr); + } } From 0539a59da591bd0aa2bcbc0b5a8edc431de3c390 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Thu, 13 Oct 2022 18:00:59 -0700 Subject: [PATCH 4/9] Lyft shaders - The ubershaders actually compile, but uniforms/material ids are broken - Convert vertex/fragment adapter components into generic builder - Support arbitrary adapted function signatures - Make an attempt at cleaning up generation code --- .../jozufozu/flywheel/backend/Backend.java | 2 + .../instancing/compile/FlwCompiler.java | 30 ++- .../compile/FragmentMaterialComponent.java | 29 --- .../compile/MaterialAdapterComponent.java | 145 +++++++++++--- .../RenamedFunctionsSourceComponent.java | 13 +- .../compile/VertexMaterialComponent.java | 27 --- .../indirect/IndirectComponent.java | 36 ++-- .../instancing/InstancedArraysComponent.java | 28 +-- .../flywheel/core/layout/LayoutItem.java | 8 +- .../core/source/generate/FnSignature.java | 80 ++++++++ .../core/source/generate/GlslBlock.java | 39 ++++ .../core/source/generate/GlslBuilder.java | 185 ++---------------- .../core/source/generate/GlslExpr.java | 19 +- .../flywheel/core/source/generate/GlslFn.java | 28 +++ .../core/source/generate/GlslStmt.java | 39 +--- .../core/source/generate/GlslStruct.java | 35 ++++ .../core/source/generate/GlslSwitch.java | 64 ++++++ .../core/source/generate/GlslVertexInput.java | 28 +++ .../core/source/generate/LangItem.java | 7 - .../jozufozu/flywheel/util/StringUtil.java | 20 ++ 20 files changed, 520 insertions(+), 342 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/FnSignature.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBlock.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/GlslFn.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStruct.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/GlslSwitch.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/GlslVertexInput.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/LangItem.java diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index 9aa80daa9..aad101c44 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -1,5 +1,6 @@ package com.jozufozu.flywheel.backend; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -60,6 +61,7 @@ public class Backend { return TYPE != BackendTypes.OFF; } + @Contract("null -> false") public static boolean canUseInstancing(@Nullable Level level) { return isOn() && isFlywheelLevel(level); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java index ab4370f58..ae11d533a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java @@ -10,6 +10,7 @@ import java.util.stream.Collectors; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; +import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.pipeline.Pipeline; import com.jozufozu.flywheel.api.struct.StructType; @@ -28,6 +29,8 @@ import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.pipeline.SimplePipeline; import com.jozufozu.flywheel.core.source.ShaderLoadingException; import com.jozufozu.flywheel.core.source.ShaderSources; +import com.jozufozu.flywheel.core.source.generate.FnSignature; +import com.jozufozu.flywheel.core.source.generate.GlslExpr; import com.jozufozu.flywheel.util.StringUtil; public class FlwCompiler { @@ -36,11 +39,10 @@ public class FlwCompiler { final long compileStart = System.nanoTime(); private final ShaderSources sources; - private final VertexMaterialComponent vertexMaterialComponent; - private final FragmentMaterialComponent fragmentMaterialComponent; + private final MaterialAdapterComponent vertexMaterialComponent; + private final MaterialAdapterComponent fragmentMaterialComponent; private final List pipelineContexts; - final ShaderCompiler shaderCompiler; final Multimap, PipelineContext> uniformProviderGroups = ArrayListMultimap.create(); final Map pipelinePrograms = new HashMap<>(); @@ -50,8 +52,26 @@ public class FlwCompiler { public FlwCompiler(ShaderSources sources) { this.shaderCompiler = new ShaderCompiler(errors::add); this.sources = sources; - this.vertexMaterialComponent = new VertexMaterialComponent(sources, ComponentRegistry.materials.vertexSources()); - this.fragmentMaterialComponent = new FragmentMaterialComponent(sources, ComponentRegistry.materials.fragmentSources()); + this.vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter")) + .materialSources(ComponentRegistry.materials.vertexSources()) + .adapt(FnSignature.ofVoid("flw_materialVertex")) + .switchOn(GlslExpr.variable("flw_materialVertexID")) + .build(sources); + this.fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter")) + .materialSources(ComponentRegistry.materials.fragmentSources()) + .adapt(FnSignature.ofVoid("flw_materialFragment")) + .adapt(FnSignature.create() + .returnType("bool") + .name("flw_discardPredicate") + .arg("vec4", "color") + .build(), GlslExpr.literal(false)) + .adapt(FnSignature.create() + .returnType("vec4") + .name("flw_fogFilter") + .arg("vec4", "color") + .build(), GlslExpr.variable("color")) + .switchOn(GlslExpr.variable("flw_materialFragmentID")) + .build(sources); this.pipelineContexts = buildPipelineSet(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java deleted file mode 100644 index c47a831e8..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FragmentMaterialComponent.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.compile; - -import java.util.List; - -import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.core.source.ShaderSources; -import com.jozufozu.flywheel.core.source.generate.GlslExpr; - -import net.minecraft.resources.ResourceLocation; - -public class FragmentMaterialComponent extends MaterialAdapterComponent { - - private static final String flw_materialFragment = "flw_materialFragment"; - private static final String flw_discardPredicate = "flw_discardPredicate"; - private static final String flw_fogFilter = "flw_fogFilter"; - private static final List adaptedFunctions = List.of(flw_materialFragment, flw_discardPredicate, flw_fogFilter); - - private static final GlslExpr flw_materialFragmentID = GlslExpr.variable(flw_materialFragment + "ID"); - - public FragmentMaterialComponent(ShaderSources sources, List sourceMaterials) { - super(sources, sourceMaterials, flw_materialFragmentID, adaptedFunctions); - } - - @Override - public ResourceLocation name() { - return Flywheel.rl("fragment_material_adapter"); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java index abee3b981..ad93b6cec 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java @@ -1,87 +1,172 @@ package com.jozufozu.flywheel.backend.instancing.compile; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; +import javax.annotation.Nonnull; + import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.source.ShaderSources; +import com.jozufozu.flywheel.core.source.generate.FnSignature; +import com.jozufozu.flywheel.core.source.generate.GlslBlock; import com.jozufozu.flywheel.core.source.generate.GlslBuilder; import com.jozufozu.flywheel.core.source.generate.GlslExpr; +import com.jozufozu.flywheel.core.source.generate.GlslSwitch; import com.jozufozu.flywheel.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; -public abstract class MaterialAdapterComponent implements SourceComponent { +public class MaterialAdapterComponent implements SourceComponent { // TODO: material id handling in pipeline shader + private final ResourceLocation name; private final GlslExpr switchArg; - private final List adaptedFunctions; - private final List transformedMaterials; + private final List functionsToAdapt; + private final List adaptedComponents; - // TODO: Create builder and remove Fragment* and Vertex* classes - public MaterialAdapterComponent(ShaderSources sources, List sourceMaterials, GlslExpr switchArg, List adaptedFunctions) { + public MaterialAdapterComponent(ResourceLocation name, GlslExpr switchArg, List functionsToAdapt, List adaptedComponents) { + this.name = name; this.switchArg = switchArg; - this.adaptedFunctions = adaptedFunctions; + this.functionsToAdapt = functionsToAdapt; + this.adaptedComponents = adaptedComponents; + } - var transformed = ImmutableList.builder(); + public static Builder builder(ResourceLocation name) { + return new Builder(name); + } - for (FileResolution fileResolution : sourceMaterials) { - var loc = fileResolution.resourceLocation(); - var sourceFile = sources.find(loc); - - transformed.add(new RenamedFunctionsSourceComponent(sourceFile, createAdapterMap(adaptedFunctions, loc))); - } - - this.transformedMaterials = transformed.build(); + @Override + public ResourceLocation name() { + return name; } @Override public Collection included() { - return transformedMaterials; + return adaptedComponents; } @Override public String source() { var builder = new GlslBuilder(); - for (String adaptedFunction : adaptedFunctions) { - // TODO: support different function signatures + for (var adaptedFunction : functionsToAdapt) { builder.function() - .returnType("void") - .name(adaptedFunction) + .signature(adaptedFunction.signature()) .body(body -> generateAdapter(body, adaptedFunction)); } return builder.build(); } - private void generateAdapter(GlslBuilder.BlockBuilder body, String adaptedFunction) { - var sw = new GlslBuilder.SwitchBuilder(switchArg); - for (int i = 0; i < transformedMaterials.size(); i++) { - var variant = transformedMaterials.get(i) - .replacement(adaptedFunction); + private void generateAdapter(GlslBlock body, AdaptedFn adaptedFunction) { + var sw = GlslSwitch.on(switchArg); + var fnSignature = adaptedFunction.signature(); + var fnName = fnSignature.name(); + var isVoid = fnSignature.isVoid(); + var fnArgs = fnSignature.createArgExpressions(); - sw.case_(i, b -> b.eval(GlslExpr.call(variant)) - .break_()); + for (int i = 0; i < adaptedComponents.size(); i++) { + var component = adaptedComponents.get(i); + + if (!component.replaces(fnName)) { + continue; + } + + var adaptedCall = GlslExpr.call(component.remapFnName(fnName), fnArgs); + + var block = GlslBlock.create(); + if (isVoid) { + block.eval(adaptedCall) + .breakStmt(); + } else { + block.ret(adaptedCall); + } + + sw.intCase(i, block); } - body.add(sw.build()); + + if (!isVoid) { + var defaultReturn = adaptedFunction.defaultReturn; + if (defaultReturn == null) { + throw new IllegalStateException("Function " + fnName + " is not void, but no default return value was provided"); + } + sw.defaultCase(GlslBlock.create() + .ret(defaultReturn)); + } + + body.add(sw); } @NotNull - private static HashMap createAdapterMap(List adaptedFunctions, ResourceLocation loc) { + private static HashMap createAdapterMap(List adaptedFunctions, ResourceLocation loc) { HashMap out = new HashMap<>(); var suffix = '_' + ResourceUtil.toSafeString(loc); - for (String fnName : adaptedFunctions) { + for (var adapted : adaptedFunctions) { + var fnName = adapted.signature() + .name(); out.put(fnName, fnName + suffix); } return out; } + + private record AdaptedFn(FnSignature signature, @Nullable GlslExpr defaultReturn) { + } + + public static class Builder { + private final ResourceLocation name; + private final List sourceMaterials = new ArrayList<>(); + private final List adaptedFunctions = new ArrayList<>(); + private GlslExpr switchArg; + + public Builder(ResourceLocation name) { + this.name = name; + } + + public Builder materialSources(List sources) { + this.sourceMaterials.addAll(sources); + return this; + } + + public Builder adapt(FnSignature function) { + adaptedFunctions.add(new AdaptedFn(function, null)); + return this; + } + + public Builder adapt(FnSignature function, @Nonnull GlslExpr defaultReturn) { + adaptedFunctions.add(new AdaptedFn(function, defaultReturn)); + return this; + } + + public Builder switchOn(GlslExpr expr) { + this.switchArg = expr; + return this; + } + + public MaterialAdapterComponent build(ShaderSources sources) { + if (switchArg == null) { + throw new NullPointerException("Switch argument must be set"); + } + + var transformed = ImmutableList.builder(); + + for (FileResolution fileResolution : sourceMaterials) { + var loc = fileResolution.resourceLocation(); + var sourceFile = sources.find(loc); + + transformed.add(new RenamedFunctionsSourceComponent(sourceFile, createAdapterMap(adaptedFunctions, loc))); + } + + return new MaterialAdapterComponent(name, switchArg, adaptedFunctions, transformed.build()); + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RenamedFunctionsSourceComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RenamedFunctionsSourceComponent.java index 32d1303bc..1c863af77 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RenamedFunctionsSourceComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RenamedFunctionsSourceComponent.java @@ -11,24 +11,29 @@ import net.minecraft.resources.ResourceLocation; public final class RenamedFunctionsSourceComponent implements SourceComponent { private final SourceComponent source; private final Map replacements; + private final String sourceString; public RenamedFunctionsSourceComponent(SourceComponent source, String find, String replace) { - this.source = source; - this.replacements = Map.of(find, replace); + this(source, Map.of(find, replace)); } public RenamedFunctionsSourceComponent(SourceComponent source, Map replacements) { this.source = source; this.replacements = replacements; + this.sourceString = source.source(); } - public String replacement(String name) { + public String remapFnName(String name) { return replacements.getOrDefault(name, name); } + public boolean replaces(String name) { + return replacements.containsKey(name) && sourceString.contains(name); + } + @Override public String source() { - var source = this.source.source(); + var source = sourceString; for (var entry : replacements.entrySet()) { source = source.replace(entry.getKey(), entry.getValue()); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java deleted file mode 100644 index 1bcb3f4a3..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/VertexMaterialComponent.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.compile; - -import java.util.List; - -import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.core.source.ShaderSources; -import com.jozufozu.flywheel.core.source.generate.GlslExpr; - -import net.minecraft.resources.ResourceLocation; - -public class VertexMaterialComponent extends MaterialAdapterComponent { - - private static final String flw_materialVertex = "flw_materialVertex"; - private static final List adaptedFunctions = List.of(flw_materialVertex); - private static final GlslExpr flw_materialVertexID = GlslExpr.variable(flw_materialVertex + "ID"); - - - public VertexMaterialComponent(ShaderSources sources, List sourceMaterials) { - super(sources, sourceMaterials, flw_materialVertexID, adaptedFunctions); - } - - @Override - public ResourceLocation name() { - return Flywheel.rl("vertex_material_adapter"); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java index 1c1ba970c..05c207cf1 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java @@ -12,6 +12,8 @@ import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.layout.LayoutItem; import com.jozufozu.flywheel.core.source.ShaderSources; import com.jozufozu.flywheel.core.source.SourceFile; +import com.jozufozu.flywheel.core.source.generate.FnSignature; +import com.jozufozu.flywheel.core.source.generate.GlslBlock; import com.jozufozu.flywheel.core.source.generate.GlslBuilder; import com.jozufozu.flywheel.core.source.generate.GlslExpr; @@ -21,6 +23,8 @@ public class IndirectComponent implements SourceComponent { private static final String UNPACK_ARG = "p"; private static final GlslExpr.Variable UNPACKING_VARIABLE = GlslExpr.variable(UNPACK_ARG); + private static final String STRUCT_NAME = "IndirectStruct"; + private static final String PACKED_STRUCT_NAME = STRUCT_NAME + "_packed"; private final List layoutItems; private final ImmutableList included; @@ -46,20 +50,19 @@ public class IndirectComponent implements SourceComponent { @Override public String source() { - return generateIndirect("IndirectStruct"); + return generateIndirect(); } - public String generateIndirect(String structName) { + public String generateIndirect() { var builder = new GlslBuilder(); - final var packedStructName = structName + "_packed"; - builder.define("FlwInstance", structName); - builder.define("FlwPackedInstance", packedStructName); + builder.define("FlwInstance", STRUCT_NAME); + builder.define("FlwPackedInstance", PACKED_STRUCT_NAME); var packed = builder.struct(); builder.blankLine(); var instance = builder.struct(); - packed.setName(packedStructName); - instance.setName(structName); + packed.setName(PACKED_STRUCT_NAME); + instance.setName(STRUCT_NAME); for (var field : layoutItems) { field.addPackedToStruct(packed); @@ -69,13 +72,20 @@ public class IndirectComponent implements SourceComponent { builder.blankLine(); builder.function() - .returnType(structName) - .name("flw_unpackInstance") - .argumentIn(packedStructName, UNPACK_ARG) - .body(b -> b.ret(GlslExpr.call(structName, layoutItems.stream() - .map(layoutItem -> layoutItem.unpackField(UNPACKING_VARIABLE)) - .toList()))); + .signature(FnSignature.create() + .returnType(STRUCT_NAME) + .name("flw_unpackInstance") + .arg(PACKED_STRUCT_NAME, UNPACK_ARG) + .build()) + .body(this::generateUnpackingBody); return builder.build(); } + + private void generateUnpackingBody(GlslBlock b) { + var unpackedFields = layoutItems.stream() + .map(layoutItem -> layoutItem.unpackField(UNPACKING_VARIABLE)) + .toList(); + b.ret(GlslExpr.call(STRUCT_NAME, unpackedFields)); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java index 1ea8dd912..f894d7c63 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedArraysComponent.java @@ -8,6 +8,8 @@ import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.pipeline.Pipeline; import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.layout.LayoutItem; +import com.jozufozu.flywheel.core.source.generate.FnSignature; +import com.jozufozu.flywheel.core.source.generate.GlslBlock; import com.jozufozu.flywheel.core.source.generate.GlslBuilder; import com.jozufozu.flywheel.core.source.generate.GlslExpr; @@ -15,6 +17,7 @@ import net.minecraft.resources.ResourceLocation; public class InstancedArraysComponent implements SourceComponent { private static final String ATTRIBUTE_SUFFIX = "_vertex_in"; + private static final String STRUCT_NAME = "Instance"; private final List layoutItems; private final int baseIndex; @@ -32,19 +35,15 @@ public class InstancedArraysComponent implements SourceComponent { return Collections.emptyList(); } - @Override - public String source() { - return generateInstancedArrays("Instance"); - } - @Override public ResourceLocation name() { return Flywheel.rl("generated_instanced_arrays"); } - public String generateInstancedArrays(String structName) { + @Override + public String source() { var builder = new GlslBuilder(); - builder.define("FlwInstance", structName); + builder.define("FlwInstance", STRUCT_NAME); int i = baseIndex; for (var field : layoutItems) { @@ -61,7 +60,7 @@ public class InstancedArraysComponent implements SourceComponent { builder.blankLine(); var structBuilder = builder.struct(); - structBuilder.setName(structName); + structBuilder.setName(STRUCT_NAME); for (var field : layoutItems) { field.addToStruct(structBuilder); @@ -71,13 +70,16 @@ public class InstancedArraysComponent implements SourceComponent { // unpacking function builder.function() - .returnType(structName) - .name("flw_unpackInstance") - .body(b -> b.ret(GlslExpr.call(structName, layoutItems.stream() - .map(it -> new GlslExpr.Variable(it.name() + ATTRIBUTE_SUFFIX)) - .toList()))); + .signature(FnSignature.of(STRUCT_NAME, "flw_unpackInstance")) + .body(this::generateUnpackingBody); return builder.build(); } + private void generateUnpackingBody(GlslBlock b) { + var fields = layoutItems.stream() + .map(it -> new GlslExpr.Variable(it.name() + ATTRIBUTE_SUFFIX)) + .toList(); + b.ret(GlslExpr.call(STRUCT_NAME, fields)); + } } 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 50df64305..d94c817e5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/LayoutItem.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/LayoutItem.java @@ -1,7 +1,7 @@ package com.jozufozu.flywheel.core.layout; -import com.jozufozu.flywheel.core.source.generate.GlslBuilder; import com.jozufozu.flywheel.core.source.generate.GlslExpr; +import com.jozufozu.flywheel.core.source.generate.GlslStruct; public record LayoutItem(InputType type, String name) { public GlslExpr unpackField(GlslExpr.Variable struct) { @@ -9,11 +9,11 @@ public record LayoutItem(InputType type, String name) { .transform(type()::unpack); } - public void addToStruct(GlslBuilder.StructBuilder structBuilder) { - structBuilder.addField(type().typeName(), name()); + public void addToStruct(GlslStruct glslStruct) { + glslStruct.addField(type().typeName(), name()); } - public void addPackedToStruct(GlslBuilder.StructBuilder packed) { + public void addPackedToStruct(GlslStruct packed) { packed.addField(type().packedTypeName(), name()); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/FnSignature.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/FnSignature.java new file mode 100644 index 000000000..097da1c7e --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/FnSignature.java @@ -0,0 +1,80 @@ +package com.jozufozu.flywheel.core.source.generate; + +import java.util.Collection; +import java.util.stream.Collectors; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.util.Pair; + +public record FnSignature(String returnType, String name, ImmutableList> args) { + + public static Builder create() { + return new Builder(); + } + + public static FnSignature of(String returnType, String name) { + return FnSignature.create() + .returnType(returnType) + .name(name) + .build(); + } + + public static FnSignature ofVoid(String name) { + return new FnSignature("void", name, ImmutableList.of()); + } + + public Collection createArgExpressions() { + return args.stream() + .map(Pair::second) + .map(GlslExpr::variable) + .collect(Collectors.toList()); + } + + public boolean isVoid() { + return "void".equals(returnType); + } + + public String fullDeclaration() { + return returnType + ' ' + name + '(' + args.stream() + .map(p -> p.first() + ' ' + p.second()) + .collect(Collectors.joining(", ")) + ')'; + } + + public String signatureDeclaration() { + return returnType + ' ' + name + '(' + args.stream() + .map(Pair::first) + .collect(Collectors.joining(", ")) + ')'; + } + + public static class Builder { + private String returnType; + private String name; + private final ImmutableList.Builder> args = ImmutableList.builder(); + + public Builder returnType(String returnType) { + this.returnType = returnType; + return this; + } + + public Builder name(String name) { + this.name = name; + return this; + } + + public Builder arg(String type, String name) { + args.add(Pair.of(type, name)); + return this; + } + + public FnSignature build() { + if (returnType == null) { + throw new IllegalStateException("returnType not set"); + } + if (name == null) { + throw new IllegalStateException("name not set"); + } + return new FnSignature(returnType, name, args.build()); + } + } + +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBlock.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBlock.java new file mode 100644 index 000000000..af8a3705b --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBlock.java @@ -0,0 +1,39 @@ +package com.jozufozu.flywheel.core.source.generate; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class GlslBlock { + private final List body = new ArrayList<>(); + + public static GlslBlock create() { + return new GlslBlock(); + } + + public GlslBlock add(GlslStmt stmt) { + body.add(stmt); + return this; + } + + public GlslBlock eval(GlslExpr expr) { + return add(GlslStmt.eval(expr)); + } + + public GlslBlock ret(GlslExpr call) { + add(GlslStmt.ret(call)); + return this; + } + + public GlslBlock breakStmt() { + add(GlslStmt.BREAK); + return this; + } + + public String prettyPrint() { + return body.stream() + .map(GlslStmt::prettyPrint) + .collect(Collectors.joining("\n")); + } + +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java index 45006833e..53c8d3fc2 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java @@ -2,31 +2,28 @@ package com.jozufozu.flywheel.core.source.generate; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; import java.util.stream.Collectors; -import com.jozufozu.flywheel.util.Pair; - public class GlslBuilder { - private final List elements = new ArrayList<>(); + private final List elements = new ArrayList<>(); public void define(String name, String value) { add(new Define(name, value)); } - public StructBuilder struct() { - return add(new StructBuilder()); + public GlslStruct struct() { + return add(new GlslStruct()); } - public FunctionBuilder function() { - return add(new FunctionBuilder()); + public GlslFn function() { + return add(new GlslFn()); } - public VertexInputBuilder vertexInput() { - return add(new VertexInputBuilder()); + public GlslVertexInput vertexInput() { + return add(new GlslVertexInput()); } - public T add(T element) { + public T add(T element) { elements.add(element); return element; } @@ -37,15 +34,15 @@ public class GlslBuilder { public String build() { return elements.stream() - .map(GlslRootElement::prettyPrint) + .map(Declaration::prettyPrint) .collect(Collectors.joining("\n")); } - public interface GlslRootElement { + public interface Declaration { String prettyPrint(); } - public enum Separators implements GlslRootElement { + public enum Separators implements Declaration { BLANK_LINE(""), ; @@ -61,169 +58,11 @@ public class GlslBuilder { } } - public record Define(String name, String value) implements GlslRootElement { + public record Define(String name, String value) implements Declaration { @Override public String prettyPrint() { return "#define " + name + " " + value; } } - public static class VertexInputBuilder implements GlslRootElement { - - private int binding; - private String type; - private String name; - - public VertexInputBuilder binding(int binding) { - this.binding = binding; - return this; - } - - public VertexInputBuilder type(String type) { - this.type = type; - return this; - } - - public VertexInputBuilder name(String name) { - this.name = name; - return this; - } - - @Override - public String prettyPrint() { - return "layout(location = " + binding + ") in " + type + " " + name + ";"; - } - } - - public static class StructBuilder implements GlslRootElement { - - private final List> fields = new ArrayList<>(); - private String name; - - public void setName(String name) { - this.name = name; - } - - public void addField(String type, String name) { - fields.add(Pair.of(type, name)); - } - - private String buildFields() { - return fields.stream() - .map(p -> p.first() + ' ' + p.second() + ';') - .collect(Collectors.joining("\n")); - } - - public String prettyPrint() { - return """ - struct %s { - %s - }; - """.formatted(name, buildFields().indent(4)); - } - } - - public static class FunctionBuilder implements GlslRootElement { - private final List> arguments = new ArrayList<>(); - private final BlockBuilder body = new BlockBuilder(); - private String returnType; - private String name; - - public FunctionBuilder returnType(String returnType) { - this.returnType = returnType; - return this; - } - - public FunctionBuilder name(String name) { - this.name = name; - return this; - } - - public FunctionBuilder argument(String type, String name) { - arguments.add(Pair.of(type, name)); - return this; - } - - public FunctionBuilder argumentIn(String type, String name) { - arguments.add(Pair.of("in " + type, name)); - return this; - } - - public FunctionBuilder body(Consumer f) { - f.accept(body); - return this; - } - - public String prettyPrint() { - return """ - %s %s(%s) { - %s - } - """.formatted(returnType, name, buildArguments(), body.prettyPrint() - .indent(4)); - } - - private String buildArguments() { - return arguments.stream() - .map(p -> p.first() + ' ' + p.second()) - .collect(Collectors.joining(", ")); - } - } - - public static class BlockBuilder implements LangItem { - private final List body = new ArrayList<>(); - - public BlockBuilder add(GlslStmt stmt) { - body.add(stmt); - return this; - } - - public BlockBuilder eval(GlslExpr expr) { - return add(GlslStmt.eval(expr)); - } - - public BlockBuilder switchOn(GlslExpr expr, Consumer f) { - var builder = new SwitchBuilder(expr); - f.accept(builder); - return add(builder.build()); - } - - public void ret(GlslExpr call) { - add(GlslStmt.ret(call)); - } - - public void break_() { - add(GlslStmt.BREAK); - } - - @Override - public String prettyPrint() { - return body.stream() - .map(GlslStmt::prettyPrint) - .collect(Collectors.joining("\n")); - } - - } - - public static class SwitchBuilder { - - private final GlslExpr on; - - private final List> cases = new ArrayList<>(); - - public SwitchBuilder(GlslExpr on) { - this.on = on; - } - - public SwitchBuilder case_(int expr, Consumer f) { - var builder = new BlockBuilder(); - f.accept(builder); - cases.add(Pair.of(GlslExpr.literal(expr), builder)); - return this; - } - - public GlslStmt.Switch build() { - return new GlslStmt.Switch(on, cases); - } - } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java index 5046e0afb..cab45783f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java @@ -6,7 +6,7 @@ import java.util.stream.Collectors; import com.google.common.collect.ImmutableList; -public interface GlslExpr extends LangItem { +public interface GlslExpr { /** * Create a glsl variable with the given name. @@ -27,7 +27,11 @@ public interface GlslExpr extends LangItem { } static GlslExpr literal(int expr) { - return new Literal(expr); + return new IntLiteral(expr); + } + + static GlslExpr literal(boolean expr) { + return new BoolLiteral(expr); } /** @@ -70,6 +74,8 @@ public interface GlslExpr extends LangItem { return f.apply(this); } + String prettyPrint(); + record Variable(String name) implements GlslExpr { @Override public String prettyPrint() { @@ -117,10 +123,17 @@ public interface GlslExpr extends LangItem { } - record Literal(int value) implements GlslExpr { + record IntLiteral(int value) implements GlslExpr { @Override public String prettyPrint() { return Integer.toString(value); } } + + record BoolLiteral(boolean value) implements GlslExpr { + @Override + public String prettyPrint() { + return Boolean.toString(value); + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslFn.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslFn.java new file mode 100644 index 000000000..8a603b035 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslFn.java @@ -0,0 +1,28 @@ +package com.jozufozu.flywheel.core.source.generate; + +import java.util.function.Consumer; + +import com.jozufozu.flywheel.util.StringUtil; + +public class GlslFn implements GlslBuilder.Declaration { + private final GlslBlock body = new GlslBlock(); + private FnSignature signature; + + public GlslFn signature(FnSignature signature) { + this.signature = signature; + return this; + } + + public GlslFn body(Consumer f) { + f.accept(body); + return this; + } + + public String prettyPrint() { + return """ + %s { + %s + } + """.formatted(signature.fullDeclaration(), StringUtil.indent(body.prettyPrint(), 4)); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java index 89a3a9dc8..7b301af8d 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStmt.java @@ -1,11 +1,9 @@ package com.jozufozu.flywheel.core.source.generate; -import java.util.List; -import java.util.stream.Collectors; - -import com.jozufozu.flywheel.util.Pair; - -public interface GlslStmt extends LangItem { +public interface GlslStmt { + GlslStmt BREAK = () -> "break;"; + GlslStmt CONTINUE = () -> "continue;"; + GlslStmt RETURN = () -> "return;"; static GlslStmt eval(GlslExpr expr) { return new Eval(expr); @@ -15,11 +13,7 @@ public interface GlslStmt extends LangItem { return new Return(value); } - static GlslStmt BREAK = () -> "break;"; - - static GlslStmt CONTINUE = () -> "continue;"; - - static GlslStmt RETURN = () -> "return;"; + String prettyPrint(); record Eval(GlslExpr expr) implements GlslStmt { @Override @@ -34,27 +28,4 @@ public interface GlslStmt extends LangItem { return "return " + expr.prettyPrint() + ";"; } } - - record Switch(GlslExpr expr, List> body) implements GlslStmt { - @Override - public String prettyPrint() { - var cases = body.stream() - .map(Switch::prettyPrintCase) - .collect(Collectors.joining("\n")); - return """ - switch (%s) { - %s - }""".formatted(expr.prettyPrint(), cases); - } - - private static String prettyPrintCase(Pair p) { - var variant = p.first() - .prettyPrint(); - var block = p.second() - .prettyPrint(); - return """ - case %s: - %s""".formatted(variant, block.indent(4)); - } - } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStruct.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStruct.java new file mode 100644 index 000000000..a713117c9 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslStruct.java @@ -0,0 +1,35 @@ +package com.jozufozu.flywheel.core.source.generate; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.jozufozu.flywheel.util.Pair; + +public class GlslStruct implements GlslBuilder.Declaration { + + private final List> fields = new ArrayList<>(); + private String name; + + public void setName(String name) { + this.name = name; + } + + public void addField(String type, String name) { + fields.add(Pair.of(type, name)); + } + + private String buildFields() { + return fields.stream() + .map(p -> p.first() + ' ' + p.second() + ';') + .collect(Collectors.joining("\n")); + } + + public String prettyPrint() { + return """ + struct %s { + %s + }; + """.formatted(name, buildFields().indent(4)); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslSwitch.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslSwitch.java new file mode 100644 index 000000000..1e3fc0d6a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslSwitch.java @@ -0,0 +1,64 @@ +package com.jozufozu.flywheel.core.source.generate; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.jetbrains.annotations.NotNull; + +import com.jozufozu.flywheel.util.Pair; +import com.jozufozu.flywheel.util.StringUtil; + +public class GlslSwitch implements GlslStmt { + + private final GlslExpr on; + + private final List> cases = new ArrayList<>(); + private GlslBlock defaultCase = null; + + private GlslSwitch(GlslExpr on) { + this.on = on; + } + + public static GlslSwitch on(GlslExpr on) { + return new GlslSwitch(on); + } + + public void intCase(int expr, GlslBlock block) { + cases.add(Pair.of(GlslExpr.literal(expr), block)); + } + + public void defaultCase(GlslBlock block) { + defaultCase = block; + } + + @Override + public String prettyPrint() { + return """ + switch (%s) { + %s + }""".formatted(on.prettyPrint(), getCaseStream()); + } + + @NotNull + private String getCaseStream() { + var cases = this.cases.stream() + .map(GlslSwitch::prettyPrintCase) + .collect(Collectors.joining("\n")); + if (defaultCase != null) { + cases += "\ndefault:\n" + StringUtil.indent(defaultCase.prettyPrint(), 4); + } + return cases; + } + + private static String prettyPrintCase(Pair p) { + var variant = p.first() + .prettyPrint(); + var block = p.second() + .prettyPrint(); + return """ + case %s: + %s""".formatted(variant, StringUtil.indent(block, 4)); + } + +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslVertexInput.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslVertexInput.java new file mode 100644 index 000000000..ca52e4a89 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslVertexInput.java @@ -0,0 +1,28 @@ +package com.jozufozu.flywheel.core.source.generate; + +public class GlslVertexInput implements GlslBuilder.Declaration { + + private int binding; + private String type; + private String name; + + public GlslVertexInput binding(int binding) { + this.binding = binding; + return this; + } + + public GlslVertexInput type(String type) { + this.type = type; + return this; + } + + public GlslVertexInput name(String name) { + this.name = name; + return this; + } + + @Override + public String prettyPrint() { + return "layout(location = " + binding + ") in " + type + " " + name + ";"; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/LangItem.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/LangItem.java deleted file mode 100644 index 0ae9d4e6c..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/source/generate/LangItem.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.jozufozu.flywheel.core.source.generate; - -public interface LangItem { - - String prettyPrint(); - -} diff --git a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java index 46c9e3d25..e8a0650b5 100644 --- a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java +++ b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java @@ -12,6 +12,7 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Arrays; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -72,6 +73,25 @@ public class StringUtil { return value.substring(0, len); } + /** + * Copy of {@link String#indent(int)} with the trailing newline removed. + */ + public static String indent(String str, int n) { + if (str.isEmpty()) { + return ""; + } + Stream stream = str.lines(); + if (n > 0) { + final String spaces = repeatChar(' ', n); + stream = stream.map(s -> spaces + s); + } else if (n == Integer.MIN_VALUE) { + stream = stream.map(String::stripLeading); + } else if (n < 0) { + throw new IllegalArgumentException("Requested indentation (" + n + ") is unsupported"); + } + return stream.collect(Collectors.joining("\n")); + } + @Nonnull public static String readToString(InputStream is) throws IOException { ByteBuffer bytebuffer = null; From 4a1787ee94e1916a99560d84268884d5b6c0a016 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Tue, 20 Dec 2022 21:20:08 -0800 Subject: [PATCH 5/9] Finally have time off - Attempt at componentizing ShaderCompiler, starting with Includer - Begin refactoring uniform providers - Context as an interface - Separate ContextSet objects for Pipeline shaders and Culling shaders - Inline ProgramAssembler - Replace StringUtil#trimEnd with String#stripTrailing - Add StringUtil#trimPrefix and #trimSuffix --- .../flywheel/api/context/Context.java | 12 +++ .../flywheel/api/context/ContextShader.java | 16 ++- .../flywheel/api/uniform/UniformProvider.java | 13 +-- .../flywheel/backend/gl/shader/GlProgram.java | 2 +- .../instancing/compile/Compilation.java | 3 +- .../instancing/compile/CompileUtil.java | 44 +++++++-- .../instancing/compile/CullingContext.java | 6 ++ .../instancing/compile/CullingContextSet.java | 38 ++++++++ .../instancing/compile/FailedCompilation.java | 4 +- .../instancing/compile/FlwCompiler.java | 77 ++++++++------- .../backend/instancing/compile/Includer.java | 21 ++++ .../compile/PipelineContextSet.java | 48 +++++++++ .../instancing/compile/ProgramAssembler.java | 47 --------- .../instancing/compile/RecursiveIncluder.java | 38 ++++++++ .../instancing/compile/ShaderCompiler.java | 72 ++++++++------ .../flywheel/core/source/SourceLines.java | 4 +- .../core/source/generate/GlslBuilder.java | 15 +++ .../flywheel/core/uniform/FogProvider.java | 16 ++- .../core/uniform/FrustumProvider.java | 19 ++-- .../flywheel/core/uniform/UniformBuffer.java | 97 +++++++++---------- .../flywheel/core/uniform/ViewProvider.java | 18 ++-- .../com/jozufozu/flywheel/util/FlwUtil.java | 7 +- .../jozufozu/flywheel/util/StringUtil.java | 19 ++-- .../assets/flywheel/flywheel/uniform/fog.glsl | 10 +- .../flywheel/flywheel/uniform/frustum.glsl | 4 +- .../flywheel/flywheel/uniform/view.glsl | 8 +- 26 files changed, 437 insertions(+), 221 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/api/context/Context.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CullingContext.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CullingContextSet.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Includer.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContextSet.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ProgramAssembler.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RecursiveIncluder.java diff --git a/src/main/java/com/jozufozu/flywheel/api/context/Context.java b/src/main/java/com/jozufozu/flywheel/api/context/Context.java new file mode 100644 index 000000000..d4eb459ee --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/context/Context.java @@ -0,0 +1,12 @@ +package com.jozufozu.flywheel.api.context; + +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; +import com.jozufozu.flywheel.core.source.FileResolution; + +public interface Context { + void setup(GlProgram program); + + FileResolution vertexShader(); + + FileResolution fragmentShader(); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java b/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java index 3074ff20d..1a74be173 100644 --- a/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java +++ b/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java @@ -3,6 +3,20 @@ package com.jozufozu.flywheel.api.context; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.core.source.FileResolution; -public record ContextShader(GlProgram.Factory factory, FileResolution vertexShader, FileResolution fragmentShader) { +public record ContextShader(GlProgram.Factory factory, FileResolution vertexShader, + FileResolution fragmentShader) implements Context { + @Override + public void setup(GlProgram program) { + } + + @Override + public FileResolution vertexShader() { + return vertexShader; + } + + @Override + public FileResolution fragmentShader() { + return fragmentShader; + } } diff --git a/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java b/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java index 7c0fd2a30..7656318e0 100644 --- a/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java +++ b/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java @@ -8,15 +8,16 @@ public interface UniformProvider { FileResolution uniformShader(); - ActiveUniformProvider activate(long ptr, Notifier notifier); + ActiveUniformProvider activate(long ptr); interface ActiveUniformProvider { void delete(); - void poll(); - } - - interface Notifier { - void signalChanged(); + /** + * Poll the provider for changes. + * + * @return {@code true} if the provider updated its backing store. + */ + boolean poll(); } } 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 cea2fcfa3..b16c039e0 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 @@ -16,7 +16,7 @@ public class GlProgram extends GlObject { setHandle(handle); } - // TODO: Programs bind the uniform buffers they need + // TODO: Programs bind the uniform buffers they need, no more GlProgram inheritance public void bind() { ProgramManager.glUseProgram(handle()); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Compilation.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Compilation.java index edb474865..f8253f8f5 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Compilation.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Compilation.java @@ -83,7 +83,8 @@ public class Compilation { .toString())); } - fullSource.append(source); + fullSource.append(source) + .append('\n'); } private String sourceHeader(SourceFile sourceFile) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompileUtil.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompileUtil.java index 219b3802e..14a4631a4 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompileUtil.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CompileUtil.java @@ -1,5 +1,11 @@ package com.jozufozu.flywheel.backend.instancing.compile; +import static org.lwjgl.opengl.GL20.GL_LINK_STATUS; +import static org.lwjgl.opengl.GL20.GL_TRUE; +import static org.lwjgl.opengl.GL20.glGetProgramInfoLog; +import static org.lwjgl.opengl.GL20.glGetProgrami; +import static org.lwjgl.opengl.GL20.glLinkProgram; + import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -7,6 +13,7 @@ import java.util.stream.Stream; import org.jetbrains.annotations.NotNull; +import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.core.source.SourceFile; @@ -17,9 +24,7 @@ public class CompileUtil { public static final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$"); public static String generateHeader(GLSLVersion version, ShaderType type) { - return version.getVersionLine() - + type.getDefineStatement() - + '\n'; + return version.getVersionLine() + type.getDefineStatement() + '\n'; } public static int getElementCount(String type) { @@ -53,10 +58,31 @@ public class CompileUtil { return 1; } - @NotNull - public static String generateDebugName(SourceFile... stages) { - return Stream.of(stages) - .map(SourceFile::toString) - .collect(Collectors.joining(" -> ")); - } + @NotNull + public static String generateDebugName(SourceFile... stages) { + return Stream.of(stages) + .map(SourceFile::toString) + .collect(Collectors.joining(" -> ")); + } + + /** + * Check the program info log for errors. + * + * @param handle The handle of the program to check. + */ + public static void checkLinkLog(int handle) { + glLinkProgram(handle); + + String log = glGetProgramInfoLog(handle); + + if (!log.isEmpty()) { + Backend.LOGGER.debug("Program link log: " + log); + } + + int result = glGetProgrami(handle, GL_LINK_STATUS); + + if (result != GL_TRUE) { + throw new RuntimeException("Shader program linking failed, see log for details"); + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CullingContext.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CullingContext.java new file mode 100644 index 000000000..80464f50f --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CullingContext.java @@ -0,0 +1,6 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import com.jozufozu.flywheel.api.struct.StructType; + +public record CullingContext(StructType structType) { +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CullingContextSet.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CullingContextSet.java new file mode 100644 index 000000000..bd6981c4a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/CullingContextSet.java @@ -0,0 +1,38 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.core.ComponentRegistry; + +public class CullingContextSet { + static CullingContextSet create() { + var builder = new CullingContextSet(); + for (StructType structType : ComponentRegistry.structTypes) { + builder.add(structType); + } + return builder; + } + + private final List contexts = new ArrayList<>(); + private final List contextView = Collections.unmodifiableList(contexts); + + CullingContextSet() { + } + + public List all() { + return contextView; + } + + public int size() { + return contexts.size(); + } + + private void add(StructType structType) { + var ctx = new CullingContext(structType); + + contexts.add(ctx); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FailedCompilation.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FailedCompilation.java index 8ef84b185..fc44515bb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FailedCompilation.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FailedCompilation.java @@ -13,6 +13,7 @@ import com.jozufozu.flywheel.core.source.SourceLines; import com.jozufozu.flywheel.core.source.error.ErrorBuilder; import com.jozufozu.flywheel.core.source.span.Span; import com.jozufozu.flywheel.util.ConsoleColors; +import com.jozufozu.flywheel.util.StringUtil; public class FailedCompilation { private static final Pattern ERROR_LINE = Pattern.compile("(\\d+)\\((\\d+)\\) : (.*)"); @@ -49,7 +50,8 @@ public class FailedCompilation { if (matcher.find()) { int fileId = Integer.parseInt(matcher.group(1)); int lineNo = Integer.parseInt(matcher.group(2)); - var msg = matcher.group(3); + var msg = StringUtil.trimPrefix(matcher.group(3), "error") + .stripLeading(); if (fileId == 0) { return interpretGeneratedError(lineNo, msg); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java index ae11d533a..216afedca 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java @@ -1,5 +1,9 @@ package com.jozufozu.flywheel.backend.instancing.compile; +import static org.lwjgl.opengl.GL20.glAttachShader; +import static org.lwjgl.opengl.GL20.glCreateProgram; +import static org.lwjgl.opengl.GL20.glLinkProgram; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -21,9 +25,7 @@ import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.backend.instancing.indirect.IndirectComponent; -import com.jozufozu.flywheel.core.BackendTypes; import com.jozufozu.flywheel.core.ComponentRegistry; -import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.Pipelines; import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.pipeline.SimplePipeline; @@ -41,7 +43,9 @@ public class FlwCompiler { private final ShaderSources sources; private final MaterialAdapterComponent vertexMaterialComponent; private final MaterialAdapterComponent fragmentMaterialComponent; - private final List pipelineContexts; + + private final PipelineContextSet pipelineContexts; + private final CullingContextSet cullingContexts; final ShaderCompiler shaderCompiler; final Multimap, PipelineContext> uniformProviderGroups = ArrayListMultimap.create(); @@ -50,7 +54,10 @@ public class FlwCompiler { final List errors = new ArrayList<>(); public FlwCompiler(ShaderSources sources) { - this.shaderCompiler = new ShaderCompiler(errors::add); + this.shaderCompiler = ShaderCompiler.builder() + .errorConsumer(errors::add) + .build(); + this.sources = sources; this.vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter")) .materialSources(ComponentRegistry.materials.vertexSources()) @@ -73,21 +80,24 @@ public class FlwCompiler { .switchOn(GlslExpr.variable("flw_materialFragmentID")) .build(sources); - this.pipelineContexts = buildPipelineSet(); + this.pipelineContexts = PipelineContextSet.create(); + this.cullingContexts = CullingContextSet.create(); - // TODO: analyze uniform providers and group them into sets; break up this ctor - - for (PipelineContext context : pipelineContexts) { - compilePipelineContext(context); - } - - for (StructType type : ComponentRegistry.structTypes) { - compileComputeCuller(type); - } + doCompilation(); finish(); } + private void doCompilation() { + for (var ctx : pipelineContexts.all()) { + compilePipelineContext(ctx); + } + + for (var ctx : cullingContexts.all()) { + compileComputeCuller(ctx); + } + } + private void finish() { long compileEnd = System.nanoTime(); int programCount = pipelineContexts.size() + ComponentRegistry.structTypes.size(); @@ -132,22 +142,31 @@ public class FlwCompiler { return; } - pipelinePrograms.put(ctx, ctx.contextShader() - .factory() - .create(new ProgramAssembler().attachShader(vertex) - .attachShader(fragment) - .link())); + var glProgram = link(vertex.handle(), fragment.handle()); + ctx.contextShader() + .setup(glProgram); + pipelinePrograms.put(ctx, glProgram); } - private void compileComputeCuller(StructType structType) { - var result = shaderCompiler.compile(GLSLVersion.V460, ShaderType.COMPUTE, getComputeComponents(structType)); + private void compileComputeCuller(CullingContext ctx) { + var computeComponents = getComputeComponents(ctx.structType()); + var result = shaderCompiler.compile(GLSLVersion.V460, ShaderType.COMPUTE, computeComponents); if (result == null) { return; } - cullingPrograms.put(structType, new GlProgram(new ProgramAssembler().attachShader(result) - .link())); + cullingPrograms.put(ctx.structType(), link(result.handle())); + } + + private GlProgram link(int... shaders) { + var handle = glCreateProgram(); + for (var shader : shaders) { + glAttachShader(handle, shader); + } + glLinkProgram(handle); + CompileUtil.checkLinkLog(handle); + return new GlProgram(handle); } private ImmutableList getVertexComponents(PipelineContext ctx) { @@ -189,16 +208,4 @@ public class FlwCompiler { return ImmutableList.of(instanceAssembly, instance, pipeline); } - private static List buildPipelineSet() { - ImmutableList.Builder builder = ImmutableList.builder(); - for (SimplePipeline pipelineShader : BackendTypes.availablePipelineShaders()) { - for (StructType structType : ComponentRegistry.structTypes) { - for (VertexType vertexType : ComponentRegistry.vertexTypes) { - // TODO: context ubershaders, or not? - builder.add(new PipelineContext(vertexType, structType, Components.WORLD, pipelineShader)); - } - } - } - return builder.build(); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Includer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Includer.java new file mode 100644 index 000000000..b25b03920 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/Includer.java @@ -0,0 +1,21 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.function.Consumer; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.core.SourceComponent; + +/** + * A component of a ShaderCompiler, responsible for expanding root sources into the complete set of included sources. + */ +public interface Includer { + + /** + * Expand the given root sources into the complete set of included sources. + *

Each unique source will be seen exactly once. + * + * @param rootSources The root sources to expand. + * @param out A consumer to which all sources should be passed in the order they should be included. + */ + void expand(ImmutableList rootSources, Consumer out); +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContextSet.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContextSet.java new file mode 100644 index 000000000..099bc7096 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContextSet.java @@ -0,0 +1,48 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.jozufozu.flywheel.api.context.ContextShader; +import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.core.BackendTypes; +import com.jozufozu.flywheel.core.ComponentRegistry; +import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.pipeline.SimplePipeline; + +public class PipelineContextSet { + static PipelineContextSet create() { + var builder = new PipelineContextSet(); + for (SimplePipeline pipelineShader : BackendTypes.availablePipelineShaders()) { + for (StructType structType : ComponentRegistry.structTypes) { + for (VertexType vertexType : ComponentRegistry.vertexTypes) { + builder.add(vertexType, structType, Components.WORLD, pipelineShader); + } + } + } + return builder; + } + + private final List contexts = new ArrayList<>(); + private final List contextView = Collections.unmodifiableList(contexts); + + PipelineContextSet() { + } + + public List all() { + return contextView; + } + + public int size() { + return contexts.size(); + } + + private void add(VertexType vertexType, StructType structType, ContextShader world, SimplePipeline pipelineShader) { + var ctx = new PipelineContext(vertexType, structType, world, pipelineShader); + + + contexts.add(ctx); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ProgramAssembler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ProgramAssembler.java deleted file mode 100644 index 75031a9ef..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ProgramAssembler.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.compile; - -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.glCreateProgram; -import static org.lwjgl.opengl.GL20.glGetProgramInfoLog; -import static org.lwjgl.opengl.GL20.glGetProgrami; -import static org.lwjgl.opengl.GL20.glLinkProgram; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.gl.shader.GlShader; - -@Deprecated -public class ProgramAssembler { - private final int program; - - public ProgramAssembler() { - this.program = glCreateProgram(); - } - - /** - * Links the attached shaders to this program. - */ - public int link() { - glLinkProgram(this.program); - - String log = glGetProgramInfoLog(this.program); - - if (!log.isEmpty()) { - Backend.LOGGER.debug("Program link log: " + log); - } - - int result = glGetProgrami(this.program, GL_LINK_STATUS); - - if (result != GL_TRUE) { - throw new RuntimeException("Shader program linking failed, see log for details"); - } - - return program; - } - - public ProgramAssembler attachShader(GlShader glShader) { - glAttachShader(this.program, glShader.handle()); - return this; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RecursiveIncluder.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RecursiveIncluder.java new file mode 100644 index 000000000..c4409de72 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RecursiveIncluder.java @@ -0,0 +1,38 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.function.Consumer; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.core.SourceComponent; + +public class RecursiveIncluder implements Includer { + + public static final RecursiveIncluder INSTANCE = new RecursiveIncluder(); + + private RecursiveIncluder() { + } + + @Override + public void expand(ImmutableList rootSources, Consumer out) { + var included = depthFirstInclude(rootSources); + included.forEach(out); + rootSources.forEach(out); + } + + private static LinkedHashSet depthFirstInclude(ImmutableList root) { + var included = new LinkedHashSet(); // linked to preserve order + for (var component : root) { + recursiveDepthFirstInclude(included, component); + } + return included; + } + + private static void recursiveDepthFirstInclude(Set included, SourceComponent component) { + for (var include : component.included()) { + recursiveDepthFirstInclude(included, include); + } + included.addAll(component.included()); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java index a2a6e014a..ca570b1e9 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/ShaderCompiler.java @@ -1,10 +1,8 @@ package com.jozufozu.flywheel.backend.instancing.compile; import java.util.HashMap; -import java.util.LinkedHashSet; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.function.Consumer; import org.jetbrains.annotations.NotNull; @@ -15,13 +13,18 @@ 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.core.SourceComponent; +import com.jozufozu.flywheel.util.FlwUtil; public class ShaderCompiler { private final Map shaderCache = new HashMap<>(); private final Consumer errorConsumer; + private final CompilationFactory factory; + private final Includer includer; - public ShaderCompiler(Consumer errorConsumer) { + public ShaderCompiler(Consumer errorConsumer, CompilationFactory factory, Includer includer) { this.errorConsumer = errorConsumer; + this.factory = factory; + this.includer = includer; } public int shaderCount() { @@ -36,7 +39,7 @@ public class ShaderCompiler { return cached.unwrap(); } - CompilationResult out = compileUncached(glslVersion, shaderType, sourceComponents); + CompilationResult out = compileUncached(factory.create(glslVersion, shaderType), sourceComponents); shaderCache.put(key, out); return unwrapAndReportError(out); } @@ -60,40 +63,51 @@ public class ShaderCompiler { } @NotNull - private static CompilationResult compileUncached(GLSLVersion glslVersion, ShaderType shaderType, ImmutableList sourceComponents) { - var ctx = new Compilation(glslVersion, shaderType); + private CompilationResult compileUncached(Compilation ctx, ImmutableList sourceComponents) { ctx.enableExtension("GL_ARB_explicit_attrib_location"); ctx.enableExtension("GL_ARB_conservative_depth"); - for (var include : depthFirstInclude(sourceComponents)) { - ctx.appendComponent(include); - } - - for (var component : sourceComponents) { - ctx.appendComponent(component); - ctx.addComponentName(component.name()); - } + includer.expand(sourceComponents, ctx::appendComponent); return ctx.compile(); } - private static Set depthFirstInclude(ImmutableList root) { - var included = new LinkedHashSet(); // linked to preserve order - for (var component : root) { - recursiveDepthFirstInclude(included, component); - } - return included; - } - - private static void recursiveDepthFirstInclude(Set included, SourceComponent component) { - for (var include : component.included()) { - recursiveDepthFirstInclude(included, include); - } - included.addAll(component.included()); - } - private record ShaderKey(GLSLVersion glslVersion, ShaderType shaderType, ImmutableList sourceComponents) { } + + public static Builder builder() { + return new Builder(); + } + + @FunctionalInterface + public interface CompilationFactory { + Compilation create(GLSLVersion version, ShaderType shaderType); + } + + public static class Builder { + private Consumer errorConsumer = FlwUtil::noop; + private CompilationFactory factory = Compilation::new; + private Includer includer = RecursiveIncluder.INSTANCE; + + public Builder errorConsumer(Consumer errorConsumer) { + this.errorConsumer = errorConsumer; + return this; + } + + public Builder compilationFactory(CompilationFactory factory) { + this.factory = factory; + return this; + } + + public Builder includer(Includer includer) { + this.includer = includer; + return this; + } + + public ShaderCompiler build() { + return new ShaderCompiler(errorConsumer, factory, includer); + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java index e4f1eada8..7b1b18b8c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceLines.java @@ -7,7 +7,6 @@ import org.jetbrains.annotations.NotNull; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.source.span.CharPos; -import com.jozufozu.flywheel.util.StringUtil; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; @@ -102,7 +101,8 @@ public class SourceLines implements CharSequence { int start = lines.getInt(i - 1); int end = lines.getInt(i); - builder.add(StringUtil.trimEnd(source.substring(start, end))); + builder.add(source.substring(start, end) + .stripTrailing()); } return builder.build(); diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java index 53c8d3fc2..249f98ff8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java @@ -11,6 +11,10 @@ public class GlslBuilder { add(new Define(name, value)); } + public void undef(String key) { + add(new Undef(key)); + } + public GlslStruct struct() { return add(new GlslStruct()); } @@ -32,6 +36,10 @@ public class GlslBuilder { elements.add(Separators.BLANK_LINE); } + public void _addRaw(String sourceString) { + elements.add(() -> sourceString); + } + public String build() { return elements.stream() .map(Declaration::prettyPrint) @@ -65,4 +73,11 @@ public class GlslBuilder { } } + public record Undef(String name) implements Declaration { + @Override + public String prettyPrint() { + return "#undef " + name; + } + } + } diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java index c45806ace..1dd4f6e13 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java @@ -22,18 +22,16 @@ public class FogProvider implements UniformProvider { } @Override - public ActiveUniformProvider activate(long ptr, Notifier notifier) { - return new Active(ptr, notifier); + public ActiveUniformProvider activate(long ptr) { + return new Active(ptr); } public static class Active implements ActiveUniformProvider { private final long ptr; - private final Notifier notifier; - public Active(long ptr, Notifier notifier) { + public Active(long ptr) { this.ptr = ptr; - this.notifier = notifier; } @Override @@ -41,9 +39,9 @@ public class FogProvider implements UniformProvider { } @Override - public void poll() { + public boolean poll() { if (!FOG_UPDATE) { - return; + return false; } var color = RenderSystem.getShaderFogColor(); @@ -57,9 +55,9 @@ public class FogProvider implements UniformProvider { MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape() .getIndex()); - notifier.signalChanged(); - FOG_UPDATE = false; + + return true; } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java index 58d3d1474..32cc4ef0e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java @@ -31,18 +31,17 @@ public class FrustumProvider implements UniformProvider { } @Override - public ActiveUniformProvider activate(long ptr, Notifier notifier) { - return new Active(ptr, notifier); + public ActiveUniformProvider activate(long ptr) { + return new Active(ptr); } static class Active implements ActiveUniformProvider, Consumer { private final long ptr; - private final Notifier notifier; + private boolean dirty = true; - public Active(long ptr, Notifier notifier) { + public Active(long ptr) { this.ptr = ptr; - this.notifier = notifier; MinecraftForge.EVENT_BUS.addListener(this); } @@ -52,8 +51,12 @@ public class FrustumProvider implements UniformProvider { } @Override - public void poll() { - + public boolean poll() { + if (dirty) { + dirty = false; + return true; + } + return false; } @Override @@ -78,7 +81,7 @@ public class FrustumProvider implements UniformProvider { shiftedCuller.getJozuPackedPlanes(ptr); - notifier.signalChanged(); + dirty = true; CAPTURE = false; } } diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java index 24d805012..07a914560 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java @@ -22,7 +22,7 @@ public class UniformBuffer { private static final boolean PO2_ALIGNMENT = RenderMath.isPowerOf2(OFFSET_ALIGNMENT); private static UniformBuffer instance; - private final List allocatedProviders; + private final AllocatedProviderSet providerSet; public static UniformBuffer getInstance() { if (instance == null) { @@ -32,50 +32,19 @@ public class UniformBuffer { } private final GlBuffer buffer; - private final MemoryBlock data; - - private final BitSet changedBytes; private UniformBuffer() { buffer = new GlBuffer(GlBufferType.UNIFORM_BUFFER); - - Collection providers = ComponentRegistry.getAllUniformProviders(); - - var builder = ImmutableList.builder(); - int totalBytes = 0; - int index = 0; - for (UniformProvider provider : providers) { - int size = align16(provider.byteSize()); - - builder.add(new Allocated(provider, totalBytes, size, index)); - - totalBytes = alignUniformBuffer(totalBytes + size); - index++; - } - - allocatedProviders = builder.build(); - - data = MemoryBlock.mallocTracked(totalBytes); - changedBytes = new BitSet(totalBytes); - - for (Allocated p : allocatedProviders) { - p.updatePtr(data); - } + providerSet = new AllocatedProviderSet(ComponentRegistry.getAllUniformProviders()); } public void sync() { - allocatedProviders.forEach(Allocated::pollActive); - if (changedBytes.isEmpty()) { - return; - } + providerSet.sync(); - // TODO: upload only changed bytes - changedBytes.clear(); - - buffer.upload(data); + buffer.upload(providerSet.data); int handle = buffer.handle(); - for (Allocated p : allocatedProviders) { + for (Allocated p : providerSet.allocatedProviders) { GL32.glBindBufferRange(GL32.GL_UNIFORM_BUFFER, p.index, handle, p.offset, p.size); } } @@ -93,7 +62,7 @@ public class UniformBuffer { return (numToRound + 16 - 1) & -16; } - private class Allocated implements UniformProvider.Notifier { + private static class Allocated { private final UniformProvider provider; private final int offset; private final int size; @@ -107,20 +76,11 @@ public class UniformBuffer { this.index = index; } - @Override - public void signalChanged() { - changedBytes.set(offset, offset + size); - } - private void updatePtr(MemoryBlock bufferBase) { if (activeProvider != null) { activeProvider.delete(); } - activeProvider = provider.activate(bufferBase.ptr() + offset, this); - } - - public UniformProvider provider() { - return provider; + activeProvider = provider.activate(bufferBase.ptr() + offset); } public int offset() { @@ -135,9 +95,46 @@ public class UniformBuffer { return index; } - public void pollActive() { - if (activeProvider != null) { - activeProvider.poll(); + public boolean maybePoll() { + return activeProvider != null && activeProvider.poll(); + } + } + + private static class AllocatedProviderSet { + private final List allocatedProviders; + + private final MemoryBlock data; + + private final BitSet changedBytes; + + private AllocatedProviderSet(final Collection providers) { + var builder = ImmutableList.builder(); + int totalBytes = 0; + int index = 0; + for (UniformProvider provider : providers) { + int size = align16(provider.byteSize()); + + builder.add(new Allocated(provider, totalBytes, size, index)); + + totalBytes = alignUniformBuffer(totalBytes + size); + index++; + } + + allocatedProviders = builder.build(); + + data = MemoryBlock.mallocTracked(totalBytes); + changedBytes = new BitSet(totalBytes); + + for (Allocated p : allocatedProviders) { + p.updatePtr(data); + } + } + + public void sync() { + for (Allocated p : allocatedProviders) { + if (p.maybePoll()) { + changedBytes.set(p.offset(), p.offset() + p.size()); + } } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java index 9c82bf86f..f7a7253a7 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java @@ -32,17 +32,16 @@ public class ViewProvider implements UniformProvider { } @Override - public ActiveUniformProvider activate(long ptr, Notifier notifier) { - return new Active(ptr, notifier); + public ActiveUniformProvider activate(long ptr) { + return new Active(ptr); } public static class Active implements ActiveUniformProvider, Consumer { private final long ptr; - private final Notifier notifier; + private boolean dirty = true; - public Active(long ptr, Notifier notifier) { + public Active(long ptr) { this.ptr = ptr; - this.notifier = notifier; MinecraftForge.EVENT_BUS.addListener(this); } @@ -52,7 +51,12 @@ public class ViewProvider implements UniformProvider { } @Override - public void poll() { + public boolean poll() { + if (dirty) { + dirty = false; + return true; + } + return false; } @Override @@ -85,7 +89,7 @@ public class ViewProvider implements UniformProvider { MemoryUtil.memPutFloat(ptr + 72, camZ); MemoryUtil.memPutInt(ptr + 76, constantAmbientLight); - notifier.signalChanged(); + dirty = true; } } } diff --git a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java b/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java index ed3df090d..6742a19cf 100644 --- a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java +++ b/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java @@ -70,6 +70,11 @@ public class FlwUtil { } public static Stream mapValues(Map map) { - return map.values().stream(); + return map.values() + .stream(); + } + + public static void noop(T object) { + // noop } } diff --git a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java index e8a0650b5..1d316b47c 100644 --- a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java +++ b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java @@ -64,13 +64,20 @@ public class StringUtil { .collect(Collectors.joining(", ")) + ')'; } - public static String trimEnd(String value) { - int len = value.length(); - int st = 0; - while ((st < len) && Character.isWhitespace(value.charAt(len - 1))) { - len--; + public static String trimPrefix(String s, String prefix) { + if (s.startsWith(prefix)) { + return s.substring(prefix.length()); + } else { + return s; + } + } + + public static String trimSuffix(String s, String prefix) { + if (s.endsWith(prefix)) { + return s.substring(0, s.length() - prefix.length()); + } else { + return s; } - return value.substring(0, len); } /** diff --git a/src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl b/src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl index 8fc8ede95..9abc29093 100644 --- a/src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl +++ b/src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl @@ -1,4 +1,6 @@ -// TODO: Transform uniform shaders -vec4 flw_fogColor; -vec2 flw_fogRange; -int flw_fogShape; +// TODO: inject FLW_UNIFORM_BINDING definitions +layout(std140, binding = FLW_UNIFORM_BINDING) uniform flw_fog { + vec4 flw_fogColor; + vec2 flw_fogRange; + int flw_fogShape; +}; diff --git a/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl b/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl index b619082cd..2312ff4fc 100644 --- a/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl +++ b/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl @@ -9,4 +9,6 @@ struct FLWPackedPlanes { vec2 zW; // }; -FLWPackedPlanes flw_planes; +layout(std140, binding = FLW_UNIFORM_BINDING) uniform FLWFrustum { + FLWPackedPlanes flw_planes; +}; diff --git a/src/main/resources/assets/flywheel/flywheel/uniform/view.glsl b/src/main/resources/assets/flywheel/flywheel/uniform/view.glsl index 467d3fee9..94a82f2d8 100644 --- a/src/main/resources/assets/flywheel/flywheel/uniform/view.glsl +++ b/src/main/resources/assets/flywheel/flywheel/uniform/view.glsl @@ -1,3 +1,5 @@ -mat4 flw_viewProjection; -vec4 flw_cameraPos; -int flw_constantAmbientLight; +layout(std140, binding = FLW_UNIFORM_BINDING) uniform flw_view { + mat4 flw_viewProjection; + vec4 flw_cameraPos; + int flw_constantAmbientLight; +}; From 3eae6be05d505530edd57c94dccf3181f8265ce9 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Sat, 25 Mar 2023 13:41:45 -0700 Subject: [PATCH 6/9] Uniforms!!! - Basic idea is to let each mode get one uniform shader - Uniform shader provides a struct with the mod's id as its name - All structs get placed into one (1) ubo - Uniforms are implicitly available in all shaders - Add GlslUniformBlock for new codegen in UniformComponent - Condense old uniform providers into one object - ShaderStructs capture the optional variable name in struct definitions - Change RecursiveIncluder to interleave root components with included - GlProgram calls UniformBuffer#sync --- .../flywheel/backend/gl/shader/GlProgram.java | 8 +- .../instancing/compile/FlwCompiler.java | 41 ++--- .../compile/MaterialAdapterComponent.java | 14 +- .../instancing/compile/RecursiveIncluder.java | 19 +-- ...=> StringSubstitutionSourceComponent.java} | 8 +- .../instancing/compile/UniformComponent.java | 77 +++++++++ .../jozufozu/flywheel/config/FlwCommands.java | 8 +- .../jozufozu/flywheel/core/Components.java | 16 +- .../flywheel/core/source/SourceFile.java | 20 +-- .../core/source/generate/GlslBuilder.java | 32 ++-- .../core/source/generate/GlslSwitch.java | 26 +-- .../source/generate/GlslUniformBlock.java | 52 ++++++ .../core/source/parse/ShaderStruct.java | 6 +- .../flywheel/core/source/span/Span.java | 2 +- .../core/uniform/FlwUniformProvider.java | 148 ++++++++++++++++++ .../flywheel/core/uniform/FogProvider.java | 63 -------- .../core/uniform/FrustumProvider.java | 88 ----------- .../flywheel/core/uniform/UniformBuffer.java | 1 + .../flywheel/core/uniform/ViewProvider.java | 95 ----------- .../flywheel/mixin/FogUpdateMixin.java | 4 +- .../flywheel/flywheel/context/common.vert | 6 +- .../assets/flywheel/flywheel/debug/debug.vert | 4 +- .../flywheel/flywheel/material/cutout.frag | 3 +- .../flywheel/flywheel/material/default.frag | 3 +- .../flywheel/flywheel/material/shaded.vert | 3 +- .../flywheel/pipeline/indirect_cull.glsl | 5 +- .../flywheel/flywheel/uniform/flywheel.glsl | 20 +++ .../assets/flywheel/flywheel/uniform/fog.glsl | 6 - .../flywheel/flywheel/uniform/frustum.glsl | 14 -- .../flywheel/flywheel/uniform/view.glsl | 5 - 30 files changed, 403 insertions(+), 394 deletions(-) rename src/main/java/com/jozufozu/flywheel/backend/instancing/compile/{RenamedFunctionsSourceComponent.java => StringSubstitutionSourceComponent.java} (75%) create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/compile/UniformComponent.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/GlslUniformBlock.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/uniform/FlwUniformProvider.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java create mode 100644 src/main/resources/assets/flywheel/flywheel/uniform/flywheel.glsl delete mode 100644 src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl delete mode 100644 src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl delete mode 100644 src/main/resources/assets/flywheel/flywheel/uniform/view.glsl 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 b16c039e0..59b496b78 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 @@ -1,13 +1,12 @@ package com.jozufozu.flywheel.backend.gl.shader; -import static org.lwjgl.opengl.GL20.glDeleteProgram; -import static org.lwjgl.opengl.GL20.glGetUniformLocation; -import static org.lwjgl.opengl.GL20.glUniform1i; +import static org.lwjgl.opengl.GL20.*; import org.jetbrains.annotations.NotNull; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlObject; +import com.jozufozu.flywheel.core.uniform.UniformBuffer; import com.mojang.blaze3d.shaders.ProgramManager; public class GlProgram extends GlObject { @@ -18,6 +17,9 @@ public class GlProgram extends GlObject { // TODO: Programs bind the uniform buffers they need, no more GlProgram inheritance public void bind() { + // TODO: bind textures? + UniformBuffer.getInstance() + .sync(); ProgramManager.glUseProgram(handle()); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java index 216afedca..32d077f7a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java @@ -1,19 +1,14 @@ package com.jozufozu.flywheel.backend.instancing.compile; -import static org.lwjgl.opengl.GL20.glAttachShader; -import static org.lwjgl.opengl.GL20.glCreateProgram; -import static org.lwjgl.opengl.GL20.glLinkProgram; +import static org.lwjgl.opengl.GL20.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.stream.Collectors; -import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Multimap; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.pipeline.Pipeline; @@ -41,6 +36,7 @@ public class FlwCompiler { final long compileStart = System.nanoTime(); private final ShaderSources sources; + private final UniformComponent uniformComponent; private final MaterialAdapterComponent vertexMaterialComponent; private final MaterialAdapterComponent fragmentMaterialComponent; @@ -48,7 +44,6 @@ public class FlwCompiler { private final CullingContextSet cullingContexts; final ShaderCompiler shaderCompiler; - final Multimap, PipelineContext> uniformProviderGroups = ArrayListMultimap.create(); final Map pipelinePrograms = new HashMap<>(); final Map, GlProgram> cullingPrograms = new HashMap<>(); final List errors = new ArrayList<>(); @@ -69,16 +64,22 @@ public class FlwCompiler { .adapt(FnSignature.ofVoid("flw_materialFragment")) .adapt(FnSignature.create() .returnType("bool") - .name("flw_discardPredicate") - .arg("vec4", "color") - .build(), GlslExpr.literal(false)) - .adapt(FnSignature.create() - .returnType("vec4") - .name("flw_fogFilter") - .arg("vec4", "color") - .build(), GlslExpr.variable("color")) - .switchOn(GlslExpr.variable("flw_materialFragmentID")) - .build(sources); + .name("flw_discardPredicate") + .arg("vec4", "color") + .build(), GlslExpr.literal(false)) + .adapt(FnSignature.create() + .returnType("vec4") + .name("flw_fogFilter") + .arg("vec4", "color") + .build(), GlslExpr.variable("color")) + .switchOn(GlslExpr.variable("flw_materialFragmentID")) + .build(sources); + this.uniformComponent = UniformComponent.builder(Flywheel.rl("uniforms")) + .sources(ComponentRegistry.getAllUniformProviders() + .stream() + .map(UniformProvider::uniformShader) + .toList()) + .build(sources); this.pipelineContexts = PipelineContextSet.create(); this.cullingContexts = CullingContextSet.create(); @@ -186,7 +187,7 @@ public class FlwCompiler { .vertex() .resourceLocation()); - return ImmutableList.of(vertexMaterialComponent, instanceAssembly, layout, instance, context, pipeline); + return ImmutableList.of(uniformComponent, vertexMaterialComponent, instanceAssembly, layout, instance, context, pipeline); } private ImmutableList getFragmentComponents(PipelineContext ctx) { @@ -196,7 +197,7 @@ public class FlwCompiler { var pipeline = sources.find(ctx.pipelineShader() .fragment() .resourceLocation()); - return ImmutableList.of(fragmentMaterialComponent, context, pipeline); + return ImmutableList.of(uniformComponent, fragmentMaterialComponent, context, pipeline); } private ImmutableList getComputeComponents(StructType structType) { @@ -205,7 +206,7 @@ public class FlwCompiler { .resourceLocation()); var pipeline = sources.find(Pipelines.Files.INDIRECT_CULL.resourceLocation()); - return ImmutableList.of(instanceAssembly, instance, pipeline); + return ImmutableList.of(uniformComponent, instanceAssembly, instance, pipeline); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java index ad93b6cec..d28b9efad 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java @@ -14,11 +14,7 @@ import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.source.ShaderSources; -import com.jozufozu.flywheel.core.source.generate.FnSignature; -import com.jozufozu.flywheel.core.source.generate.GlslBlock; -import com.jozufozu.flywheel.core.source.generate.GlslBuilder; -import com.jozufozu.flywheel.core.source.generate.GlslExpr; -import com.jozufozu.flywheel.core.source.generate.GlslSwitch; +import com.jozufozu.flywheel.core.source.generate.*; import com.jozufozu.flywheel.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; @@ -29,9 +25,9 @@ public class MaterialAdapterComponent implements SourceComponent { private final ResourceLocation name; private final GlslExpr switchArg; private final List functionsToAdapt; - private final List adaptedComponents; + private final List adaptedComponents; - public MaterialAdapterComponent(ResourceLocation name, GlslExpr switchArg, List functionsToAdapt, List adaptedComponents) { + public MaterialAdapterComponent(ResourceLocation name, GlslExpr switchArg, List functionsToAdapt, List adaptedComponents) { this.name = name; this.switchArg = switchArg; this.functionsToAdapt = functionsToAdapt; @@ -157,13 +153,13 @@ public class MaterialAdapterComponent implements SourceComponent { throw new NullPointerException("Switch argument must be set"); } - var transformed = ImmutableList.builder(); + var transformed = ImmutableList.builder(); for (FileResolution fileResolution : sourceMaterials) { var loc = fileResolution.resourceLocation(); var sourceFile = sources.find(loc); - transformed.add(new RenamedFunctionsSourceComponent(sourceFile, createAdapterMap(adaptedFunctions, loc))); + transformed.add(new StringSubstitutionSourceComponent(sourceFile, createAdapterMap(adaptedFunctions, loc))); } return new MaterialAdapterComponent(name, switchArg, adaptedFunctions, transformed.build()); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RecursiveIncluder.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RecursiveIncluder.java index c4409de72..031371097 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RecursiveIncluder.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RecursiveIncluder.java @@ -16,18 +16,13 @@ public class RecursiveIncluder implements Includer { @Override public void expand(ImmutableList rootSources, Consumer out) { - var included = depthFirstInclude(rootSources); - included.forEach(out); - rootSources.forEach(out); - } - - private static LinkedHashSet depthFirstInclude(ImmutableList root) { - var included = new LinkedHashSet(); // linked to preserve order - for (var component : root) { - recursiveDepthFirstInclude(included, component); - } - return included; - } + var included = new LinkedHashSet(); // use hash set to deduplicate. linked to preserve order + for (var component : rootSources) { + recursiveDepthFirstInclude(included, component); + included.add(component); + } + included.forEach(out); + } private static void recursiveDepthFirstInclude(Set included, SourceComponent component) { for (var include : component.included()) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RenamedFunctionsSourceComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/StringSubstitutionSourceComponent.java similarity index 75% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RenamedFunctionsSourceComponent.java rename to src/main/java/com/jozufozu/flywheel/backend/instancing/compile/StringSubstitutionSourceComponent.java index 1c863af77..52c341ea9 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/RenamedFunctionsSourceComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/StringSubstitutionSourceComponent.java @@ -8,16 +8,16 @@ import com.jozufozu.flywheel.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; -public final class RenamedFunctionsSourceComponent implements SourceComponent { +public final class StringSubstitutionSourceComponent implements SourceComponent { private final SourceComponent source; private final Map replacements; private final String sourceString; - public RenamedFunctionsSourceComponent(SourceComponent source, String find, String replace) { + public StringSubstitutionSourceComponent(SourceComponent source, String find, String replace) { this(source, Map.of(find, replace)); } - public RenamedFunctionsSourceComponent(SourceComponent source, Map replacements) { + public StringSubstitutionSourceComponent(SourceComponent source, Map replacements) { this.source = source; this.replacements = replacements; this.sourceString = source.source(); @@ -44,7 +44,7 @@ public final class RenamedFunctionsSourceComponent implements SourceComponent { @Override public ResourceLocation name() { - return ResourceUtil.subPath(source.name(), "_renamed"); + return ResourceUtil.subPath(source.name(), "_string_substitution"); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/UniformComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/UniformComponent.java new file mode 100644 index 000000000..d1c2a073d --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/UniformComponent.java @@ -0,0 +1,77 @@ +package com.jozufozu.flywheel.backend.instancing.compile; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.ShaderSources; +import com.jozufozu.flywheel.core.source.SourceFile; +import com.jozufozu.flywheel.core.source.generate.GlslBuilder; + +import net.minecraft.resources.ResourceLocation; + +public class UniformComponent implements SourceComponent { + + private final ResourceLocation name; + private final ImmutableList uniformShaders; + + public static Builder builder(ResourceLocation uniforms) { + return new Builder(uniforms); + } + + private UniformComponent(ResourceLocation name, ImmutableList uniformShaders) { + this.name = name; + this.uniformShaders = uniformShaders; + } + + @Override + public Collection included() { + return uniformShaders; + } + + @Override + public String source() { + var builder = new GlslBuilder(); + + builder.uniformBlock() + .layout("std140") + .binding(0) + .name("FLWUniforms") + .member("flywheel_uniforms", "flywheel"); + + return builder.build(); + } + + @Override + public ResourceLocation name() { + return name; + } + + public static class Builder { + + private final ResourceLocation name; + private final List uniformShaders = new ArrayList<>(); + + public Builder(ResourceLocation name) { + this.name = name; + } + + public Builder sources(List sources) { + this.uniformShaders.addAll(sources); + return this; + } + + public UniformComponent build(ShaderSources sources) { + var out = ImmutableList.builder(); + + for (var fileResolution : uniformShaders) { + out.add(sources.find(fileResolution.resourceLocation())); + } + + return new UniformComponent(name, out.build()); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java index 393a0872d..e42654131 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java @@ -8,7 +8,7 @@ import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.BackendType; import com.jozufozu.flywheel.backend.SimpleBackendType; import com.jozufozu.flywheel.core.BackendTypes; -import com.jozufozu.flywheel.core.uniform.FrustumProvider; +import com.jozufozu.flywheel.core.uniform.FlwUniformProvider; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.IntegerArgumentType; @@ -111,17 +111,17 @@ public class FlwCommands { commandBuilder.command.then(Commands.literal("debugFrustum") .then(Commands.literal("pause") .executes(context -> { - FrustumProvider.PAUSED = true; + FlwUniformProvider.FRUSTUM_PAUSED = true; return 1; })) .then(Commands.literal("unpause") .executes(context -> { - FrustumProvider.PAUSED = false; + FlwUniformProvider.FRUSTUM_PAUSED = false; return 1; })) .then(Commands.literal("capture") .executes(context -> { - FrustumProvider.CAPTURE = true; + FlwUniformProvider.FRUSTUM_CAPTURE = true; return 1; }))); diff --git a/src/main/java/com/jozufozu/flywheel/core/Components.java b/src/main/java/com/jozufozu/flywheel/core/Components.java index 5b89ae03f..6f137b8e8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Components.java +++ b/src/main/java/com/jozufozu/flywheel/core/Components.java @@ -10,9 +10,7 @@ import com.jozufozu.flywheel.core.source.SourceChecks; import com.jozufozu.flywheel.core.source.SourceFile; import com.jozufozu.flywheel.core.source.error.ErrorReporter; import com.jozufozu.flywheel.core.structs.StructTypes; -import com.jozufozu.flywheel.core.uniform.FogProvider; -import com.jozufozu.flywheel.core.uniform.FrustumProvider; -import com.jozufozu.flywheel.core.uniform.ViewProvider; +import com.jozufozu.flywheel.core.uniform.FlwUniformProvider; import com.jozufozu.flywheel.core.vertex.Formats; import com.jozufozu.flywheel.util.ResourceUtil; @@ -21,10 +19,8 @@ import net.minecraft.resources.ResourceLocation; public class Components { - public static final ViewProvider VIEW_PROVIDER = ComponentRegistry.register(new ViewProvider()); - public static final FogProvider FOG_PROVIDER = ComponentRegistry.register(new FogProvider()); - public static final FrustumProvider FRUSTUM_PROVIDER = ComponentRegistry.register(new FrustumProvider()); - public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(WorldProgram::new, Files.WORLD_VERTEX, Files.WORLD_FRAGMENT)); + public static final FlwUniformProvider UNIFORM_PROVIDER = ComponentRegistry.register(new FlwUniformProvider()); + public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(WorldProgram::new, Files.WORLD_VERTEX, Files.WORLD_FRAGMENT)); public static final ContextShader CRUMBLING = ComponentRegistry.register(new ContextShader(CrumblingProgram::new, Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT)); public static void init() { @@ -37,10 +33,8 @@ public class Components { public static class Files { - public static final FileResolution VIEW_UNIFORMS = uniform(Flywheel.rl("uniform/view.glsl")); - public static final FileResolution FOG_UNIFORMS = uniform(Flywheel.rl("uniform/fog.glsl")); - public static final FileResolution FRUSTUM_UNIFORMS = uniform(Flywheel.rl("uniform/frustum.glsl")); - public static final FileResolution BLOCK_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.BLOCK, ".vert")); + public static final FileResolution UNIFORMS = uniform(Flywheel.rl("uniform/flywheel.glsl")); + public static final FileResolution BLOCK_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.BLOCK, ".vert")); public static final FileResolution POS_TEX_NORMAL_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert")); public static final FileResolution TRANSFORMED = instanceVertex(ResourceUtil.subPath(Names.TRANSFORMED, ".vert")); public static final FileResolution ORIENTED = instanceVertex(ResourceUtil.subPath(Names.ORIENTED, ".vert")); diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java index 9e72e0776..4e6e33c1d 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java @@ -1,10 +1,6 @@ package com.jozufozu.flywheel.core.source; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.regex.Matcher; import com.google.common.collect.ImmutableList; @@ -72,10 +68,7 @@ public class SourceFile implements SourceComponent { try { var loc = new ResourceLocation(file); var sourceFile = sourceFinder.find(loc); - - if (sourceFile != null) { - sink.accept(sourceFile); - } + sink.accept(sourceFile); } catch (Exception ignored) { } }) @@ -122,10 +115,12 @@ public class SourceFile implements SourceComponent { * @param name The name of the struct to find. * @return null if no definition matches the name. */ - public Optional findStruct(String name) { + public Optional findStructByName(String name) { ShaderStruct struct = structs.get(name); - if (struct != null) return Optional.of(struct); + if (struct != null) { + return Optional.of(struct); + } for (var include : included) { var external = include.structs.get(name); @@ -268,8 +263,9 @@ public class SourceFile implements SourceComponent { Span self = Span.fromMatcher(this, matcher); Span name = Span.fromMatcher(this, matcher, 1); Span body = Span.fromMatcher(this, matcher, 2); + Span variableName = Span.fromMatcher(this, matcher, 3); - ShaderStruct shaderStruct = new ShaderStruct(self, name, body); + ShaderStruct shaderStruct = new ShaderStruct(self, name, body, variableName); structs.put(name.get(), shaderStruct); } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java index 249f98ff8..67677abfb 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java @@ -17,24 +17,28 @@ public class GlslBuilder { public GlslStruct struct() { return add(new GlslStruct()); - } + } - public GlslFn function() { - return add(new GlslFn()); - } + public GlslFn function() { + return add(new GlslFn()); + } - public GlslVertexInput vertexInput() { - return add(new GlslVertexInput()); - } + public GlslVertexInput vertexInput() { + return add(new GlslVertexInput()); + } - public T add(T element) { - elements.add(element); - return element; - } + public GlslUniformBlock uniformBlock() { + return add(new GlslUniformBlock()); + } - public void blankLine() { - elements.add(Separators.BLANK_LINE); - } + public T add(T element) { + elements.add(element); + return element; + } + + public void blankLine() { + elements.add(Separators.BLANK_LINE); + } public void _addRaw(String sourceString) { elements.add(() -> sourceString); diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslSwitch.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslSwitch.java index 1e3fc0d6a..120cdac64 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslSwitch.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslSwitch.java @@ -35,21 +35,21 @@ public class GlslSwitch implements GlslStmt { @Override public String prettyPrint() { return """ - switch (%s) { - %s - }""".formatted(on.prettyPrint(), getCaseStream()); + switch (%s) { + %s + }""".formatted(on.prettyPrint(), formatCases()); } - @NotNull - private String getCaseStream() { - var cases = this.cases.stream() - .map(GlslSwitch::prettyPrintCase) - .collect(Collectors.joining("\n")); - if (defaultCase != null) { - cases += "\ndefault:\n" + StringUtil.indent(defaultCase.prettyPrint(), 4); - } - return cases; - } + @NotNull + private String formatCases() { + var cases = this.cases.stream() + .map(GlslSwitch::prettyPrintCase) + .collect(Collectors.joining("\n")); + if (defaultCase != null) { + cases += "\ndefault:\n" + StringUtil.indent(defaultCase.prettyPrint(), 4); + } + return cases; + } private static String prettyPrintCase(Pair p) { var variant = p.first() diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslUniformBlock.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslUniformBlock.java new file mode 100644 index 000000000..78f3df8cb --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslUniformBlock.java @@ -0,0 +1,52 @@ +package com.jozufozu.flywheel.core.source.generate; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.jozufozu.flywheel.util.Pair; +import com.jozufozu.flywheel.util.StringUtil; + +public class GlslUniformBlock implements GlslBuilder.Declaration { + + + private String qualifier; + private int binding; + private String name; + private final List> members = new ArrayList<>(); + + @Override + public String prettyPrint() { + return """ + layout(%s, binding = %d) uniform %s { + %s + }; + """.formatted(qualifier, binding, name, StringUtil.indent(formatMembers(), 4)); + } + + private String formatMembers() { + return members.stream() + .map(p -> p.first() + " " + p.second() + ";") + .collect(Collectors.joining("\n")); + } + + public GlslUniformBlock layout(String qualifier) { + this.qualifier = qualifier; + return this; + } + + public GlslUniformBlock binding(int i) { + binding = i; + return this; + } + + public GlslUniformBlock name(String name) { + this.name = name; + return this; + } + + public GlslUniformBlock member(String typeName, String variableName) { + members.add(Pair.of(typeName, variableName)); + return this; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderStruct.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderStruct.java index 2153dfa84..f273490ac 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderStruct.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderStruct.java @@ -10,19 +10,21 @@ import com.jozufozu.flywheel.core.source.span.Span; public class ShaderStruct { // https://regexr.com/61rpe - public static final Pattern PATTERN = Pattern.compile("struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d\\s,;]*)}\\s*;\\s"); + public static final Pattern PATTERN = Pattern.compile("struct\\s+([\\w_]*)\\s*\\{(.*?)}\\s*([\\w_]*)?\\s*;\\s", Pattern.DOTALL); public final Span name; public final Span body; public final Span self; + public final Span variableName; private final ImmutableList fields; private final ImmutableMap fields2Types; - public ShaderStruct(Span self, Span name, Span body) { + public ShaderStruct(Span self, Span name, Span body, Span variableName) { this.self = self; this.name = name; this.body = body; + this.variableName = variableName; this.fields = parseFields(); this.fields2Types = createTypeLookup(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/span/Span.java b/src/main/java/com/jozufozu/flywheel/core/source/span/Span.java index 59bdb1f8a..38abe6b36 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/span/Span.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/span/Span.java @@ -131,7 +131,7 @@ public abstract class Span implements CharSequence, Comparable { if (isErr()) { return Optional.empty(); } - return in.findStruct(this.toString()); + return in.findStructByName(this.toString()); } public Optional findFunction() { diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/FlwUniformProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FlwUniformProvider.java new file mode 100644 index 000000000..63ddb39f4 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/FlwUniformProvider.java @@ -0,0 +1,148 @@ +package com.jozufozu.flywheel.core.uniform; + +import java.util.function.Consumer; + +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.api.uniform.UniformProvider; +import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.RenderContext; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.event.BeginFrameEvent; +import com.jozufozu.flywheel.extension.MatrixWrite; +import com.mojang.blaze3d.systems.RenderSystem; + +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.Vec3i; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.MinecraftForge; + +public class FlwUniformProvider implements UniformProvider { + + public static final int SIZE = 224; + + public static boolean FRUSTUM_PAUSED = false; + public static boolean FRUSTUM_CAPTURE = false; + public static boolean FOG_UPDATE = true; + + @Override + public int byteSize() { + return SIZE; + } + + @Override + public FileResolution uniformShader() { + return Components.Files.UNIFORMS; + } + + @Override + public ActiveUniformProvider activate(long ptr) { + return new Active(ptr); + } + + public static class Active implements ActiveUniformProvider, Consumer { + private final long ptr; + + private boolean dirty; + + public Active(long ptr) { + this.ptr = ptr; + MinecraftForge.EVENT_BUS.addListener(this); + } + + @Override + public void delete() { + MinecraftForge.EVENT_BUS.unregister(this); + } + + @Override + public boolean poll() { + boolean updated = maybeUpdateFog(); + updated |= dirty; + dirty = false; + return updated; + } + + @Override + public void accept(BeginFrameEvent event) { + updateFrustum(event.getContext()); + updateView(event.getContext()); + } + + private boolean maybeUpdateFog() { + if (!FOG_UPDATE || ptr == MemoryUtil.NULL) { + return false; + } + + var color = RenderSystem.getShaderFogColor(); + + MemoryUtil.memPutFloat(ptr, color[0]); + MemoryUtil.memPutFloat(ptr + 4, color[1]); + MemoryUtil.memPutFloat(ptr + 8, color[2]); + MemoryUtil.memPutFloat(ptr + 12, color[3]); + MemoryUtil.memPutFloat(ptr + 16, RenderSystem.getShaderFogStart()); + MemoryUtil.memPutFloat(ptr + 20, RenderSystem.getShaderFogEnd()); + MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape() + .getIndex()); + + FOG_UPDATE = false; + + return true; + } + + public void updateFrustum(RenderContext context) { + if (ptr == MemoryUtil.NULL || (FRUSTUM_PAUSED && !FRUSTUM_CAPTURE)) { + return; + } + + Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(context.level()); + Vec3 camera = context.camera() + .getPosition(); + + var camX = (float) (camera.x - originCoordinate.getX()); + var camY = (float) (camera.y - originCoordinate.getY()); + var camZ = (float) (camera.z - originCoordinate.getZ()); + + var shiftedCuller = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ); + + shiftedCuller.getJozuPackedPlanes(ptr + 128); + + dirty = true; + FRUSTUM_CAPTURE = false; + } + + public void updateView(RenderContext context) { + if (ptr == MemoryUtil.NULL) { + return; + } + + ClientLevel level = context.level(); + + int constantAmbientLight = level.effects() + .constantAmbientLight() ? 1 : 0; + + Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(level); + Vec3 camera = context.camera() + .getPosition(); + + var camX = (float) (camera.x - originCoordinate.getX()); + var camY = (float) (camera.y - originCoordinate.getY()); + var camZ = (float) (camera.z - originCoordinate.getZ()); + + // don't want to mutate viewProjection + var vp = context.viewProjection() + .copy(); + vp.multiplyWithTranslation(-camX, -camY, -camZ); + + MatrixWrite.writeUnsafe(vp, ptr + 32); + MemoryUtil.memPutFloat(ptr + 96, camX); + MemoryUtil.memPutFloat(ptr + 100, camY); + MemoryUtil.memPutFloat(ptr + 104, camZ); + MemoryUtil.memPutFloat(ptr + 108, 0f); // vec4 alignment + MemoryUtil.memPutInt(ptr + 112, constantAmbientLight); + + dirty = true; + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java deleted file mode 100644 index 1dd4f6e13..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.jozufozu.flywheel.core.uniform; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.uniform.UniformProvider; -import com.jozufozu.flywheel.core.Components; -import com.jozufozu.flywheel.core.source.FileResolution; -import com.mojang.blaze3d.systems.RenderSystem; - -public class FogProvider implements UniformProvider { - - public static boolean FOG_UPDATE = true; - - @Override - public int byteSize() { - return 16 + 8 + 4; - } - - @Override - public FileResolution uniformShader() { - return Components.Files.FOG_UNIFORMS; - } - - @Override - public ActiveUniformProvider activate(long ptr) { - return new Active(ptr); - } - - public static class Active implements ActiveUniformProvider { - - private final long ptr; - - public Active(long ptr) { - this.ptr = ptr; - } - - @Override - public void delete() { - } - - @Override - public boolean poll() { - if (!FOG_UPDATE) { - return false; - } - - var color = RenderSystem.getShaderFogColor(); - - MemoryUtil.memPutFloat(ptr, color[0]); - MemoryUtil.memPutFloat(ptr + 4, color[1]); - MemoryUtil.memPutFloat(ptr + 8, color[2]); - MemoryUtil.memPutFloat(ptr + 12, color[3]); - MemoryUtil.memPutFloat(ptr + 16, RenderSystem.getShaderFogStart()); - MemoryUtil.memPutFloat(ptr + 20, RenderSystem.getShaderFogEnd()); - MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape() - .getIndex()); - - FOG_UPDATE = false; - - return true; - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java deleted file mode 100644 index 32cc4ef0e..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.jozufozu.flywheel.core.uniform; - -import java.util.function.Consumer; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.uniform.UniformProvider; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.jozufozu.flywheel.core.Components; -import com.jozufozu.flywheel.core.RenderContext; -import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.event.BeginFrameEvent; - -import net.minecraft.core.Vec3i; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.MinecraftForge; - -public class FrustumProvider implements UniformProvider { - - public static boolean PAUSED = false; - public static boolean CAPTURE = false; - - @Override - public int byteSize() { - return 96; - } - - @Override - public FileResolution uniformShader() { - return Components.Files.FRUSTUM_UNIFORMS; - } - - @Override - public ActiveUniformProvider activate(long ptr) { - return new Active(ptr); - } - - static class Active implements ActiveUniformProvider, Consumer { - - private final long ptr; - private boolean dirty = true; - - public Active(long ptr) { - this.ptr = ptr; - MinecraftForge.EVENT_BUS.addListener(this); - } - - @Override - public void delete() { - MinecraftForge.EVENT_BUS.unregister(this); - } - - @Override - public boolean poll() { - if (dirty) { - dirty = false; - return true; - } - return false; - } - - @Override - public void accept(BeginFrameEvent event) { - update(event.getContext()); - } - - public void update(RenderContext context) { - if (ptr == MemoryUtil.NULL || (PAUSED && !CAPTURE)) { - return; - } - - Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(context.level()); - Vec3 camera = context.camera() - .getPosition(); - - var camX = (float) (camera.x - originCoordinate.getX()); - var camY = (float) (camera.y - originCoordinate.getY()); - var camZ = (float) (camera.z - originCoordinate.getZ()); - - var shiftedCuller = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ); - - shiftedCuller.getJozuPackedPlanes(ptr); - - dirty = true; - CAPTURE = false; - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java index 07a914560..b184cd2b8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java @@ -34,6 +34,7 @@ public class UniformBuffer { private final GlBuffer buffer; private UniformBuffer() { + // TODO: put everything into one ubo buffer = new GlBuffer(GlBufferType.UNIFORM_BUFFER); providerSet = new AllocatedProviderSet(ComponentRegistry.getAllUniformProviders()); } diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java deleted file mode 100644 index f7a7253a7..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.jozufozu.flywheel.core.uniform; - -import java.util.function.Consumer; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.uniform.UniformProvider; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.jozufozu.flywheel.core.Components; -import com.jozufozu.flywheel.core.RenderContext; -import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.event.BeginFrameEvent; -import com.jozufozu.flywheel.extension.MatrixWrite; - -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.core.Vec3i; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.MinecraftForge; - -public class ViewProvider implements UniformProvider { - - public static final int SIZE = 4 * 16 + 16 + 4; - - @Override - public int byteSize() { - return SIZE; - } - - @Override - public FileResolution uniformShader() { - return Components.Files.VIEW_UNIFORMS; - } - - @Override - public ActiveUniformProvider activate(long ptr) { - return new Active(ptr); - } - - public static class Active implements ActiveUniformProvider, Consumer { - private final long ptr; - private boolean dirty = true; - - public Active(long ptr) { - this.ptr = ptr; - MinecraftForge.EVENT_BUS.addListener(this); - } - - @Override - public void delete() { - MinecraftForge.EVENT_BUS.unregister(this); - } - - @Override - public boolean poll() { - if (dirty) { - dirty = false; - return true; - } - return false; - } - - @Override - public void accept(BeginFrameEvent event) { - update(event.getContext()); - } - - public void update(RenderContext context) { - ClientLevel level = context.level(); - - int constantAmbientLight = level.effects() - .constantAmbientLight() ? 1 : 0; - - Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(level); - Vec3 camera = context.camera() - .getPosition(); - - var camX = (float) (camera.x - originCoordinate.getX()); - var camY = (float) (camera.y - originCoordinate.getY()); - var camZ = (float) (camera.z - originCoordinate.getZ()); - - // don't want to mutate viewProjection - var vp = context.viewProjection() - .copy(); - vp.multiplyWithTranslation(-camX, -camY, -camZ); - - MatrixWrite.writeUnsafe(vp, ptr); - MemoryUtil.memPutFloat(ptr + 64, camX); - MemoryUtil.memPutFloat(ptr + 68, camY); - MemoryUtil.memPutFloat(ptr + 72, camZ); - MemoryUtil.memPutInt(ptr + 76, constantAmbientLight); - - dirty = true; - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java index 061b297bf..4d13400f1 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java @@ -5,14 +5,14 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.jozufozu.flywheel.core.uniform.FogProvider; +import com.jozufozu.flywheel.core.uniform.FlwUniformProvider; import net.minecraft.client.renderer.FogRenderer; @Mixin(FogRenderer.class) public class FogUpdateMixin { private static void flywheel$updateFog() { - FogProvider.FOG_UPDATE = true; + FlwUniformProvider.FOG_UPDATE = true; } @Inject(method = "setupNoFog", at = @At("TAIL")) diff --git a/src/main/resources/assets/flywheel/flywheel/context/common.vert b/src/main/resources/assets/flywheel/flywheel/context/common.vert index 46730bb38..65e126de1 100644 --- a/src/main/resources/assets/flywheel/flywheel/context/common.vert +++ b/src/main/resources/assets/flywheel/flywheel/context/common.vert @@ -1,10 +1,8 @@ #use "flywheel:api/vertex.glsl" #use "flywheel:util/fog.glsl" -#use "flywheel:uniform/fog.glsl" -#use "flywheel:uniform/view.glsl" void flw_contextVertex() { - flw_distance = fog_distance(flw_vertexPos.xyz, flw_cameraPos.xyz, flw_fogShape); - gl_Position = flw_viewProjection * flw_vertexPos; + flw_distance = fog_distance(flw_vertexPos.xyz, flywheel.cameraPos.xyz, flywheel.fogShape); + gl_Position = flywheel.viewProjection * flw_vertexPos; flw_vertexNormal = normalize(flw_vertexNormal); } diff --git a/src/main/resources/assets/flywheel/flywheel/debug/debug.vert b/src/main/resources/assets/flywheel/flywheel/debug/debug.vert index 6a5d60ca1..d6c1e3380 100644 --- a/src/main/resources/assets/flywheel/flywheel/debug/debug.vert +++ b/src/main/resources/assets/flywheel/flywheel/debug/debug.vert @@ -1,7 +1,5 @@ -#use "flywheel:uniform/view.glsl" - layout(location = 0) in vec3 worldPos; void main() { - gl_Position = flw_viewProjection * vec4(worldPos, 1.0); + gl_Position = flywheel.viewProjection * vec4(worldPos, 1.0); } diff --git a/src/main/resources/assets/flywheel/flywheel/material/cutout.frag b/src/main/resources/assets/flywheel/flywheel/material/cutout.frag index 59342decf..c86c4202a 100644 --- a/src/main/resources/assets/flywheel/flywheel/material/cutout.frag +++ b/src/main/resources/assets/flywheel/flywheel/material/cutout.frag @@ -1,6 +1,5 @@ #use "flywheel:api/fragment.glsl" #use "flywheel:util/fog.glsl" -#use "flywheel:uniform/fog.glsl" void flw_materialFragment() { } @@ -11,5 +10,5 @@ bool flw_discardPredicate(vec4 finalColor) { } vec4 flw_fogFilter(vec4 color) { - return linear_fog(color, flw_distance, flw_fogRange.x, flw_fogRange.y, flw_fogColor); + return linear_fog(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y, flywheel.fogColor); } diff --git a/src/main/resources/assets/flywheel/flywheel/material/default.frag b/src/main/resources/assets/flywheel/flywheel/material/default.frag index 808233fb4..e5ea00f6c 100644 --- a/src/main/resources/assets/flywheel/flywheel/material/default.frag +++ b/src/main/resources/assets/flywheel/flywheel/material/default.frag @@ -1,10 +1,9 @@ #use "flywheel:api/fragment.glsl" #use "flywheel:util/fog.glsl" -#use "flywheel:uniform/fog.glsl" void flw_materialFragment() { } vec4 flw_fogFilter(vec4 color) { - return linear_fog(color, flw_distance, flw_fogRange.x, flw_fogRange.y, flw_fogColor); + return linear_fog(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y, flywheel.fogColor); } diff --git a/src/main/resources/assets/flywheel/flywheel/material/shaded.vert b/src/main/resources/assets/flywheel/flywheel/material/shaded.vert index f7ac29954..a14f8f826 100644 --- a/src/main/resources/assets/flywheel/flywheel/material/shaded.vert +++ b/src/main/resources/assets/flywheel/flywheel/material/shaded.vert @@ -1,12 +1,11 @@ #use "flywheel:api/vertex.glsl" #use "flywheel:util/diffuse.glsl" -#use "flywheel:uniform/view.glsl" void flw_materialVertex() { flw_vertexNormal = normalize(flw_vertexNormal); float diffuseFactor; - if (flw_constantAmbientLight == 1) { + if (flywheel.constantAmbientLight == 1) { diffuseFactor = diffuseNether(flw_vertexNormal); } else { diffuseFactor = diffuse(flw_vertexNormal); diff --git a/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl index b52c12d30..fe8efd6f7 100644 --- a/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl +++ b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl @@ -1,7 +1,6 @@ #define FLW_SUBGROUP_SIZE 32 layout(local_size_x = FLW_SUBGROUP_SIZE) in; #use "flywheel:api/cull.glsl" -#use "flywheel:uniform/frustum.glsl" #use "flywheel:util/types.glsl" struct MeshDrawCommand { @@ -33,8 +32,8 @@ layout(std430, binding = 3) restrict buffer DrawCommands { // 83 - 27 = 56 spirv instruction results bool testSphere(vec3 center, float radius) { - bvec4 xyInside = greaterThanEqual(fma(flw_planes.xyX, center.xxxx, fma(flw_planes.xyY, center.yyyy, fma(flw_planes.xyZ, center.zzzz, flw_planes.xyW))), -radius.xxxx); - bvec2 zInside = greaterThanEqual(fma(flw_planes.zX, center.xx, fma(flw_planes.zY, center.yy, fma(flw_planes.zZ, center.zz, flw_planes.zW))), -radius.xx); + bvec4 xyInside = greaterThanEqual(fma(flywheel.planes.xyX, center.xxxx, fma(flywheel.planes.xyY, center.yyyy, fma(flywheel.planes.xyZ, center.zzzz, flywheel.planes.xyW))), -radius.xxxx); + bvec2 zInside = greaterThanEqual(fma(flywheel.planes.zX, center.xx, fma(flywheel.planes.zY, center.yy, fma(flywheel.planes.zZ, center.zz, flywheel.planes.zW))), -radius.xx); return all(xyInside) && all(zInside); } diff --git a/src/main/resources/assets/flywheel/flywheel/uniform/flywheel.glsl b/src/main/resources/assets/flywheel/flywheel/uniform/flywheel.glsl new file mode 100644 index 000000000..645929821 --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/uniform/flywheel.glsl @@ -0,0 +1,20 @@ +struct FLWPackedPlanes { + vec4 xyX;// + vec4 xyY;// + vec4 xyZ;// + vec4 xyW;// + vec2 zX;// + vec2 zY;// + vec2 zZ;// + vec2 zW;// +}; + +struct flywheel_uniforms { + vec4 fogColor; + vec2 fogRange; + int fogShape; + mat4 viewProjection; + vec4 cameraPos; + int constantAmbientLight; + FLWPackedPlanes planes; +}; diff --git a/src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl b/src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl deleted file mode 100644 index 9abc29093..000000000 --- a/src/main/resources/assets/flywheel/flywheel/uniform/fog.glsl +++ /dev/null @@ -1,6 +0,0 @@ -// TODO: inject FLW_UNIFORM_BINDING definitions -layout(std140, binding = FLW_UNIFORM_BINDING) uniform flw_fog { - vec4 flw_fogColor; - vec2 flw_fogRange; - int flw_fogShape; -}; diff --git a/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl b/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl deleted file mode 100644 index 2312ff4fc..000000000 --- a/src/main/resources/assets/flywheel/flywheel/uniform/frustum.glsl +++ /dev/null @@ -1,14 +0,0 @@ -struct FLWPackedPlanes { - vec4 xyX; // - vec4 xyY; // - vec4 xyZ; // - vec4 xyW; // - vec2 zX; // - vec2 zY; // - vec2 zZ; // - vec2 zW; // -}; - -layout(std140, binding = FLW_UNIFORM_BINDING) uniform FLWFrustum { - FLWPackedPlanes flw_planes; -}; diff --git a/src/main/resources/assets/flywheel/flywheel/uniform/view.glsl b/src/main/resources/assets/flywheel/flywheel/uniform/view.glsl deleted file mode 100644 index 94a82f2d8..000000000 --- a/src/main/resources/assets/flywheel/flywheel/uniform/view.glsl +++ /dev/null @@ -1,5 +0,0 @@ -layout(std140, binding = FLW_UNIFORM_BINDING) uniform flw_view { - mat4 flw_viewProjection; - vec4 flw_cameraPos; - int flw_constantAmbientLight; -}; From e7dd801379a3af44cca8ae3ac11a665a50776cfc Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Sat, 25 Mar 2023 17:54:34 -0700 Subject: [PATCH 7/9] Indirectly materialized - Pass material IDs through the indirect draw buffer - Turns out buffers can be bound to both storage and draw indirect - Use indexOf in ComponentRegistry to determine IDs - Remove World/Crumbling Program and move sampler binding to ContextShader setup --- .../flywheel/api/context/Context.java | 2 +- .../flywheel/api/context/ContextShader.java | 11 +++--- .../flywheel/backend/gl/shader/GlProgram.java | 16 +-------- .../instancing/compile/FlwCompiler.java | 2 +- .../instancing/indirect/IndirectBuffers.java | 34 +++++-------------- .../indirect/IndirectCullingGroup.java | 16 ++------- .../instancing/indirect/IndirectDraw.java | 10 ++++++ .../instancing/indirect/IndirectDrawSet.java | 2 ++ .../flywheel/core/ComponentRegistry.java | 27 +++++++-------- .../jozufozu/flywheel/core/Components.java | 7 ++-- .../jozufozu/flywheel/core/WorldProgram.java | 25 -------------- .../core/crumbling/CrumblingProgram.java | 14 -------- .../flywheel/pipeline/indirect_cull.glsl | 11 +----- .../flywheel/pipeline/indirect_draw.vert | 14 ++++++++ .../pipeline/indirect_draw_command.glsl | 13 +++++++ 15 files changed, 76 insertions(+), 128 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/core/WorldProgram.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingProgram.java create mode 100644 src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw_command.glsl diff --git a/src/main/java/com/jozufozu/flywheel/api/context/Context.java b/src/main/java/com/jozufozu/flywheel/api/context/Context.java index d4eb459ee..93b9dd92e 100644 --- a/src/main/java/com/jozufozu/flywheel/api/context/Context.java +++ b/src/main/java/com/jozufozu/flywheel/api/context/Context.java @@ -4,7 +4,7 @@ import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.core.source.FileResolution; public interface Context { - void setup(GlProgram program); + void onProgramLink(GlProgram program); FileResolution vertexShader(); diff --git a/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java b/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java index 1a74be173..e908a6ae1 100644 --- a/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java +++ b/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java @@ -3,11 +3,14 @@ package com.jozufozu.flywheel.api.context; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.core.source.FileResolution; -public record ContextShader(GlProgram.Factory factory, FileResolution vertexShader, - FileResolution fragmentShader) implements Context { +public record ContextShader(FileResolution vertexShader, FileResolution fragmentShader) implements Context { @Override - public void setup(GlProgram program) { - + public void onProgramLink(GlProgram program) { + program.bind(); + program.setSamplerBinding("flw_diffuseTex", 0); + program.setSamplerBinding("flw_overlayTex", 1); + program.setSamplerBinding("flw_lightTex", 2); + GlProgram.unbind(); } @Override 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 59b496b78..edc21b543 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 @@ -2,8 +2,6 @@ package com.jozufozu.flywheel.backend.gl.shader; import static org.lwjgl.opengl.GL20.*; -import org.jetbrains.annotations.NotNull; - import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlObject; import com.jozufozu.flywheel.core.uniform.UniformBuffer; @@ -15,7 +13,6 @@ public class GlProgram extends GlObject { setHandle(handle); } - // TODO: Programs bind the uniform buffers they need, no more GlProgram inheritance public void bind() { // TODO: bind textures? UniformBuffer.getInstance() @@ -48,17 +45,13 @@ public class GlProgram extends GlObject { * * @param name The name of the sampler uniform. * @param binding The index of the texture unit. - * @return The sampler uniform's index. - * @throws NullPointerException If no uniform exists with the given name. */ - public int setSamplerBinding(String name, int binding) { + public void setSamplerBinding(String name, int binding) { int samplerUniform = getUniformLocation(name); if (samplerUniform >= 0) { glUniform1i(samplerUniform, binding); } - - return samplerUniform; } @Override @@ -66,11 +59,4 @@ public class GlProgram extends GlObject { glDeleteProgram(handle); } - /** - * A factory interface to create a {@link GlProgram}. - */ - public interface Factory { - - @NotNull GlProgram create(int handle); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java index 32d077f7a..ccde358de 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java @@ -145,7 +145,7 @@ public class FlwCompiler { var glProgram = link(vertex.handle(), fragment.handle()); ctx.contextShader() - .setup(glProgram); + .onProgramLink(glProgram); pipelinePrograms.put(ctx, glProgram); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectBuffers.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectBuffers.java index f99a6d799..2c9f5f7d1 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectBuffers.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectBuffers.java @@ -1,22 +1,7 @@ package com.jozufozu.flywheel.backend.instancing.indirect; import static org.lwjgl.opengl.GL45.glCreateBuffers; -import static org.lwjgl.opengl.GL46.GL_DRAW_INDIRECT_BUFFER; -import static org.lwjgl.opengl.GL46.GL_DYNAMIC_STORAGE_BIT; -import static org.lwjgl.opengl.GL46.GL_MAP_FLUSH_EXPLICIT_BIT; -import static org.lwjgl.opengl.GL46.GL_MAP_PERSISTENT_BIT; -import static org.lwjgl.opengl.GL46.GL_MAP_WRITE_BIT; -import static org.lwjgl.opengl.GL46.GL_SHADER_STORAGE_BUFFER; -import static org.lwjgl.opengl.GL46.glBindBuffer; -import static org.lwjgl.opengl.GL46.glCopyNamedBufferSubData; -import static org.lwjgl.opengl.GL46.glDeleteBuffers; -import static org.lwjgl.opengl.GL46.glFlushMappedNamedBufferRange; -import static org.lwjgl.opengl.GL46.glNamedBufferStorage; -import static org.lwjgl.opengl.GL46.nglBindBuffersRange; -import static org.lwjgl.opengl.GL46.nglCreateBuffers; -import static org.lwjgl.opengl.GL46.nglDeleteBuffers; -import static org.lwjgl.opengl.GL46.nglMapNamedBufferRange; -import static org.lwjgl.opengl.GL46.nglNamedBufferSubData; +import static org.lwjgl.opengl.GL46.*; import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.Pointer; @@ -30,7 +15,7 @@ public class IndirectBuffers { public static final long PTR_SIZE = Pointer.POINTER_SIZE; // DRAW COMMAND - public static final long DRAW_COMMAND_STRIDE = 36; + public static final long DRAW_COMMAND_STRIDE = 44; public static final long DRAW_COMMAND_OFFSET = 0; // BITS @@ -180,15 +165,16 @@ public class IndirectBuffers { FlwMemoryTracker._freeGPUMemory(maxDrawCount * DRAW_COMMAND_STRIDE); } - public void bindAll() { - bindN(BUFFER_COUNT); + public void bindForCompute() { + multiBind(BUFFER_COUNT); } - public void bindObjectAndTarget() { - bindN(2); + public void bindForDraw() { + multiBind(BUFFER_COUNT); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, draw); } - private void bindN(int bufferCount) { + private void multiBind(int bufferCount) { if (bufferCount > BUFFER_COUNT) { throw new IllegalArgumentException("Can't bind more than " + BUFFER_COUNT + " buffers"); } @@ -197,10 +183,6 @@ public class IndirectBuffers { nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, 0, bufferCount, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET); } - void bindIndirectBuffer() { - glBindBuffer(GL_DRAW_INDIRECT_BUFFER, draw); - } - void flushBatchIDs(long length) { glFlushMappedNamedBufferRange(batch, 0, length); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java index d77a07e7a..5ac29a0ec 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java @@ -3,18 +3,11 @@ package com.jozufozu.flywheel.backend.instancing.indirect; import static org.lwjgl.opengl.GL42.GL_COMMAND_BARRIER_BIT; import static org.lwjgl.opengl.GL42.glMemoryBarrier; import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BARRIER_BIT; -import static org.lwjgl.opengl.GL46.glBindVertexArray; -import static org.lwjgl.opengl.GL46.glCreateVertexArrays; -import static org.lwjgl.opengl.GL46.glDeleteVertexArrays; -import static org.lwjgl.opengl.GL46.glDispatchCompute; -import static org.lwjgl.opengl.GL46.glEnableVertexArrayAttrib; -import static org.lwjgl.opengl.GL46.glVertexArrayElementBuffer; -import static org.lwjgl.opengl.GL46.glVertexArrayVertexBuffer; +import static org.lwjgl.opengl.GL46.*; import com.jozufozu.flywheel.api.RenderStage; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler; @@ -26,7 +19,6 @@ public class IndirectCullingGroup { private static final int BARRIER_BITS = GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT; - final StructWriter storageBufferWriter; final GlProgram compute; final GlProgram draw; private final VertexType vertexType; @@ -47,7 +39,6 @@ public class IndirectCullingGroup { IndirectCullingGroup(StructType structType, VertexType vertexType) { this.vertexType = vertexType; - storageBufferWriter = structType.getWriter(); objectStride = structType.getLayout() .getStride(); @@ -116,7 +107,7 @@ public class IndirectCullingGroup { uploadIndirectCommands(); compute.bind(); - buffers.bindAll(); + buffers.bindForCompute(); var groupCount = (instanceCountThisFrame + 31) >> 5; // ceil(instanceCount / 32) glDispatchCompute(groupCount, 1, 1); @@ -130,8 +121,7 @@ public class IndirectCullingGroup { draw.bind(); glBindVertexArray(vertexArray); - buffers.bindObjectAndTarget(); - buffers.bindIndirectBuffer(); + buffers.bindForDraw(); memoryBarrier(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDraw.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDraw.java index c4d3cbaea..1985198d0 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDraw.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDraw.java @@ -4,6 +4,7 @@ import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.core.ComponentRegistry; public final class IndirectDraw { final IndirectInstancer instancer; @@ -11,12 +12,18 @@ public final class IndirectDraw { final Material material; int baseInstance = -1; + final int vertexMaterialID; + final int fragmentMaterialID; + boolean needsFullWrite = true; IndirectDraw(IndirectInstancer instancer, Material material, IndirectMeshPool.BufferedMesh mesh) { this.instancer = instancer; this.material = material; this.mesh = mesh; + + this.vertexMaterialID = ComponentRegistry.materials.getVertexID(material); + this.fragmentMaterialID = ComponentRegistry.materials.getFragmentID(material); } public void prepare(int baseInstance) { @@ -48,5 +55,8 @@ public final class IndirectDraw { MemoryUtil.memPutInt(ptr + 16, baseInstance); // baseInstance boundingSphere.getToAddress(ptr + 20); // boundingSphere + MemoryUtil.memPutInt(ptr + 36, vertexMaterialID); // vertexMaterialID + MemoryUtil.memPutInt(ptr + 40, fragmentMaterialID); // fragmentMaterialID + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawSet.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawSet.java index 5bf8c18fc..277087995 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawSet.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawSet.java @@ -10,6 +10,7 @@ import java.util.List; import com.jozufozu.flywheel.api.RenderStage; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.util.Textures; public class IndirectDrawSet { @@ -37,6 +38,7 @@ public class IndirectDrawSet { continue; } material.setup(); + Textures.bindActiveTextures(); glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, i * stride, 1, stride); material.clear(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java b/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java index 0d11d1d04..b18d46ded 100644 --- a/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java +++ b/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java @@ -1,13 +1,6 @@ package com.jozufozu.flywheel.core; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import org.jetbrains.annotations.Nullable; @@ -18,8 +11,6 @@ import com.jozufozu.flywheel.api.uniform.UniformProvider; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.core.source.FileResolution; -import it.unimi.dsi.fastutil.objects.Reference2IntMap; -import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; import net.minecraft.resources.ResourceLocation; public class ComponentRegistry { @@ -93,8 +84,8 @@ public class ComponentRegistry { public T add(T material) { materials.add(material); - vertexSources.register(material, material.getVertexShader()); - fragmentSources.register(material, material.getFragmentShader()); + vertexSources.register(material.getVertexShader()); + fragmentSources.register(material.getFragmentShader()); return material; } @@ -113,15 +104,21 @@ public class ComponentRegistry { return fragmentSources.sourceView; } + public int getVertexID(Material material) { + return vertexSources.orderedSources.indexOf(material.getVertexShader()); + } + + public int getFragmentID(Material material) { + return fragmentSources.orderedSources.indexOf(material.getFragmentShader()); + } + private static class MaterialSources { private final Set registered = new HashSet<>(); private final List orderedSources = new ArrayList<>(); - private final Reference2IntMap material2ID = new Reference2IntOpenHashMap<>(); private final List sourceView = Collections.unmodifiableList(orderedSources); - public void register(Material material, FileResolution vertexShader) { + public void register(FileResolution vertexShader) { if (registered.add(vertexShader)) { - material2ID.put(material, orderedSources.size()); orderedSources.add(vertexShader); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/Components.java b/src/main/java/com/jozufozu/flywheel/core/Components.java index 6f137b8e8..9e81348f6 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Components.java +++ b/src/main/java/com/jozufozu/flywheel/core/Components.java @@ -4,7 +4,6 @@ import java.util.function.BiConsumer; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.context.ContextShader; -import com.jozufozu.flywheel.core.crumbling.CrumblingProgram; import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.source.SourceChecks; import com.jozufozu.flywheel.core.source.SourceFile; @@ -19,9 +18,9 @@ import net.minecraft.resources.ResourceLocation; public class Components { - public static final FlwUniformProvider UNIFORM_PROVIDER = ComponentRegistry.register(new FlwUniformProvider()); - public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(WorldProgram::new, Files.WORLD_VERTEX, Files.WORLD_FRAGMENT)); - public static final ContextShader CRUMBLING = ComponentRegistry.register(new ContextShader(CrumblingProgram::new, Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT)); + public static final FlwUniformProvider UNIFORM_PROVIDER = ComponentRegistry.register(new FlwUniformProvider()); + public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(Files.WORLD_VERTEX, Files.WORLD_FRAGMENT)); + public static final ContextShader CRUMBLING = ComponentRegistry.register(new ContextShader(Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT)); public static void init() { Files.init(); diff --git a/src/main/java/com/jozufozu/flywheel/core/WorldProgram.java b/src/main/java/com/jozufozu/flywheel/core/WorldProgram.java deleted file mode 100644 index 4d53fb194..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/WorldProgram.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.jozufozu.flywheel.core; - -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; - -public class WorldProgram extends GlProgram { - - // TODO: sampler registry? - protected int diffuseTex; - protected int overlayTex; - protected int lightTex; - - public WorldProgram(int handle) { - super(handle); - - bind(); - registerSamplers(); - unbind(); - } - - protected void registerSamplers() { - diffuseTex = setSamplerBinding("flw_diffuseTex", 0); - overlayTex = setSamplerBinding("flw_overlayTex", 1); - lightTex = setSamplerBinding("flw_lightTex", 2); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingProgram.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingProgram.java deleted file mode 100644 index f5be39ec6..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingProgram.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.jozufozu.flywheel.core.crumbling; - -import com.jozufozu.flywheel.core.WorldProgram; - -public class CrumblingProgram extends WorldProgram { - public CrumblingProgram(int handle) { - super(handle); - } - - @Override - protected void registerSamplers() { - diffuseTex = setSamplerBinding("flw_diffuseTex", 0); - } -} diff --git a/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl index fe8efd6f7..0362e33da 100644 --- a/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl +++ b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl @@ -2,16 +2,7 @@ layout(local_size_x = FLW_SUBGROUP_SIZE) in; #use "flywheel:api/cull.glsl" #use "flywheel:util/types.glsl" - -struct MeshDrawCommand { - uint indexCount; - uint instanceCount; - uint firstIndex; - uint vertexOffset; - uint baseInstance; - - BoundingSphere boundingSphere; -}; +#use "flywheel:pipeline/indirect_draw_command.glsl" // populated by instancers layout(std430, binding = 0) restrict readonly buffer ObjectBuffer { diff --git a/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw.vert b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw.vert index 2a29b662b..84abac66d 100644 --- a/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw.vert +++ b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw.vert @@ -1,4 +1,5 @@ #use "flywheel:api/vertex.glsl" +#use "flywheel:pipeline/indirect_draw_command.glsl" layout(std430, binding = 0) restrict readonly buffer ObjectBuffer { FlwPackedInstance objects[]; @@ -8,9 +9,22 @@ layout(std430, binding = 1) restrict readonly buffer TargetBuffer { uint objectIDs[]; }; +layout(std430, binding = 2) restrict readonly buffer BatchBuffer { + uint batchIDs[]; +}; + +layout(std430, binding = 3) restrict readonly buffer DrawCommands { + MeshDrawCommand drawCommands[]; +}; + void main() { uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID]; + uint batchID = batchIDs[instanceIndex]; FlwInstance i = flw_unpackInstance(objects[instanceIndex]); + + flw_materialVertexID = drawCommands[batchID].vertexMaterialID; + flw_materialFragmentID = drawCommands[batchID].fragmentMaterialID; + flw_layoutVertex(); flw_instanceVertex(i); flw_materialVertex(); diff --git a/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw_command.glsl b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw_command.glsl new file mode 100644 index 000000000..6699bd126 --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw_command.glsl @@ -0,0 +1,13 @@ +#use "flywheel:util/types.glsl" + +struct MeshDrawCommand { + uint indexCount; + uint instanceCount; + uint firstIndex; + uint vertexOffset; + uint baseInstance; + + BoundingSphere boundingSphere; + uint vertexMaterialID; + uint fragmentMaterialID; +}; From 44b9a666c41e7698885d12611aae50c89cd46d2f Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Sun, 26 Mar 2023 00:39:35 -0700 Subject: [PATCH 8/9] Resolved to ashes - FileResolution was implemented to support a two-pass preprocessor/compiler. - The new architecture no longer needs its functionality. - It doesn't make sense to have implementors individually apply the "checks" to ensure their components are sound. - The component checking code - Remove FileResolution, replace all references with ResourceLocation - Small refactor to UniformBuffer to put everything into one UBO - Remove BlockEntityRenderDispatcherAccessor - Rename component resource location getters for consistency - Small cleanups here and there - Consolidate SourceChecks to SourceChecks.java for future use --- .../flywheel/api/context/Context.java | 7 +- .../flywheel/api/material/Material.java | 6 +- .../flywheel/api/pipeline/Pipeline.java | 7 +- .../flywheel/api/struct/StructType.java | 4 +- .../flywheel/api/uniform/ShaderUniforms.java | 29 ++++ .../flywheel/api/uniform/UniformProvider.java | 23 --- .../flywheel/api/vertex/VertexType.java | 5 +- .../instancing/compile/FlwCompiler.java | 37 ++--- .../compile/MaterialAdapterComponent.java | 55 ++++--- .../instancing/compile/PipelineContext.java | 8 +- .../compile/PipelineContextSet.java | 4 +- .../instancing/compile/UniformComponent.java | 13 +- .../indirect/IndirectComponent.java | 2 +- .../instancing/indirect/IndirectEngine.java | 6 +- .../instancing/InstancingEngine.java | 6 +- .../jozufozu/flywheel/config/FlwCommands.java | 8 +- .../flywheel/core/ComponentRegistry.java | 49 +++--- .../jozufozu/flywheel/core/Components.java | 97 +++--------- .../com/jozufozu/flywheel/core/Pipelines.java | 18 +-- .../context/SimpleContext.java} | 12 +- .../core/material/SimpleMaterial.java | 29 ++-- .../core/pipeline/SimplePipeline.java | 21 +-- .../flywheel/core/source/FileResolution.java | 149 ------------------ .../flywheel/core/source/ShaderSources.java | 20 ++- .../flywheel/core/source/SourceChecks.java | 11 ++ .../core/structs/oriented/OrientedType.java | 5 +- .../structs/transformed/TransformedType.java | 5 +- ...rmProvider.java => FlwShaderUniforms.java} | 98 ++++++------ .../flywheel/core/uniform/UniformBuffer.java | 79 +++------- .../flywheel/core/vertex/BlockVertex.java | 5 +- .../core/vertex/PosTexNormalVertex.java | 5 +- .../BlockEntityRenderDispatcherAccessor.java | 16 -- .../flywheel/mixin/FogUpdateMixin.java | 4 +- .../com/jozufozu/flywheel/util/FlwUtil.java | 18 +-- .../java/com/jozufozu/flywheel/util/Mods.java | 8 +- src/main/resources/flywheel.mixins.json | 1 - 36 files changed, 318 insertions(+), 552 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/api/uniform/ShaderUniforms.java delete mode 100644 src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java rename src/main/java/com/jozufozu/flywheel/{api/context/ContextShader.java => core/context/SimpleContext.java} (53%) delete mode 100644 src/main/java/com/jozufozu/flywheel/core/source/FileResolution.java rename src/main/java/com/jozufozu/flywheel/core/uniform/{FlwUniformProvider.java => FlwShaderUniforms.java} (70%) delete mode 100644 src/main/java/com/jozufozu/flywheel/mixin/BlockEntityRenderDispatcherAccessor.java diff --git a/src/main/java/com/jozufozu/flywheel/api/context/Context.java b/src/main/java/com/jozufozu/flywheel/api/context/Context.java index 93b9dd92e..0504e7fbf 100644 --- a/src/main/java/com/jozufozu/flywheel/api/context/Context.java +++ b/src/main/java/com/jozufozu/flywheel/api/context/Context.java @@ -1,12 +1,13 @@ package com.jozufozu.flywheel.api.context; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.core.source.FileResolution; + +import net.minecraft.resources.ResourceLocation; public interface Context { void onProgramLink(GlProgram program); - FileResolution vertexShader(); + ResourceLocation vertexShader(); - FileResolution fragmentShader(); + ResourceLocation fragmentShader(); } diff --git a/src/main/java/com/jozufozu/flywheel/api/material/Material.java b/src/main/java/com/jozufozu/flywheel/api/material/Material.java index dc0db130f..5104057e1 100644 --- a/src/main/java/com/jozufozu/flywheel/api/material/Material.java +++ b/src/main/java/com/jozufozu/flywheel/api/material/Material.java @@ -2,17 +2,17 @@ package com.jozufozu.flywheel.api.material; import com.jozufozu.flywheel.api.RenderStage; import com.jozufozu.flywheel.api.vertex.MutableVertexList; -import com.jozufozu.flywheel.core.source.FileResolution; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; public interface Material { RenderStage getRenderStage(); - FileResolution getVertexShader(); + ResourceLocation vertexShader(); - FileResolution getFragmentShader(); + ResourceLocation fragmentShader(); void setup(); diff --git a/src/main/java/com/jozufozu/flywheel/api/pipeline/Pipeline.java b/src/main/java/com/jozufozu/flywheel/api/pipeline/Pipeline.java index 6e5b2460e..ce4761393 100644 --- a/src/main/java/com/jozufozu/flywheel/api/pipeline/Pipeline.java +++ b/src/main/java/com/jozufozu/flywheel/api/pipeline/Pipeline.java @@ -4,16 +4,17 @@ import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.core.SourceComponent; -import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.source.ShaderSources; +import net.minecraft.resources.ResourceLocation; + public interface Pipeline { GLSLVersion glslVersion(); - FileResolution vertex(); + ResourceLocation vertexShader(); - FileResolution fragment(); + ResourceLocation fragmentShader(); /** * Generate the source component necessary to convert a packed {@link StructType} into its shader representation. diff --git a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java index ef14279de..86689b885 100644 --- a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java +++ b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java @@ -3,9 +3,9 @@ package com.jozufozu.flywheel.api.struct; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.vertex.MutableVertexList; import com.jozufozu.flywheel.core.layout.BufferLayout; -import com.jozufozu.flywheel.core.source.FileResolution; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.resources.ResourceLocation; /** * A StructType contains metadata for a specific instance struct that Flywheel can interface with. @@ -25,7 +25,7 @@ public interface StructType { StructWriter getWriter(); - FileResolution getInstanceShader(); + ResourceLocation instanceShader(); VertexTransformer getVertexTransformer(); diff --git a/src/main/java/com/jozufozu/flywheel/api/uniform/ShaderUniforms.java b/src/main/java/com/jozufozu/flywheel/api/uniform/ShaderUniforms.java new file mode 100644 index 000000000..535c775a8 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/uniform/ShaderUniforms.java @@ -0,0 +1,29 @@ +package com.jozufozu.flywheel.api.uniform; + +import net.minecraft.resources.ResourceLocation; + +public interface ShaderUniforms { + + Provider activate(long ptr); + + ResourceLocation uniformShader(); + + int byteSize(); + + interface Provider { + /** + * Delete this provider.

+ *

+ * Do not free the ptr passed to {@link #activate(long)}.
+ * Clean up other resources, and unsubscribe from events. + */ + void delete(); + + /** + * Poll the provider for changes. + * + * @return {@code true} if the provider updated its backing store. + */ + boolean poll(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java b/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java deleted file mode 100644 index 7656318e0..000000000 --- a/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.jozufozu.flywheel.api.uniform; - -import com.jozufozu.flywheel.core.source.FileResolution; - -public interface UniformProvider { - - int byteSize(); - - FileResolution uniformShader(); - - ActiveUniformProvider activate(long ptr); - - interface ActiveUniformProvider { - void delete(); - - /** - * Poll the provider for changes. - * - * @return {@code true} if the provider updated its backing store. - */ - boolean poll(); - } -} 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 72dab420d..cde253249 100644 --- a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java @@ -1,7 +1,8 @@ package com.jozufozu.flywheel.api.vertex; import com.jozufozu.flywheel.core.layout.BufferLayout; -import com.jozufozu.flywheel.core.source.FileResolution; + +import net.minecraft.resources.ResourceLocation; /** * A vertex type containing metadata about a specific vertex layout. @@ -13,7 +14,7 @@ public interface VertexType extends VertexListProvider { */ BufferLayout getLayout(); - FileResolution getLayoutShader(); + ResourceLocation layoutShader(); default int getStride() { return getLayout().getStride(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java index ccde358de..42635d642 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/FlwCompiler.java @@ -1,6 +1,8 @@ package com.jozufozu.flywheel.backend.instancing.compile; -import static org.lwjgl.opengl.GL20.*; +import static org.lwjgl.opengl.GL20.glAttachShader; +import static org.lwjgl.opengl.GL20.glCreateProgram; +import static org.lwjgl.opengl.GL20.glLinkProgram; import java.util.ArrayList; import java.util.HashMap; @@ -10,10 +12,9 @@ import java.util.stream.Collectors; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.pipeline.Pipeline; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.api.uniform.UniformProvider; +import com.jozufozu.flywheel.api.uniform.ShaderUniforms; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GLSLVersion; @@ -23,6 +24,7 @@ import com.jozufozu.flywheel.backend.instancing.indirect.IndirectComponent; import com.jozufozu.flywheel.core.ComponentRegistry; import com.jozufozu.flywheel.core.Pipelines; import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.context.SimpleContext; import com.jozufozu.flywheel.core.pipeline.SimplePipeline; import com.jozufozu.flywheel.core.source.ShaderLoadingException; import com.jozufozu.flywheel.core.source.ShaderSources; @@ -76,8 +78,8 @@ public class FlwCompiler { .build(sources); this.uniformComponent = UniformComponent.builder(Flywheel.rl("uniforms")) .sources(ComponentRegistry.getAllUniformProviders() - .stream() - .map(UniformProvider::uniformShader) + .stream() + .map(ShaderUniforms::uniformShader) .toList()) .build(sources); @@ -124,7 +126,7 @@ public class FlwCompiler { shaderCompiler.delete(); } - public GlProgram getPipelineProgram(VertexType vertexType, StructType structType, ContextShader contextShader, SimplePipeline pipelineShader) { + public GlProgram getPipelineProgram(VertexType vertexType, StructType structType, SimpleContext contextShader, SimplePipeline pipelineShader) { return pipelinePrograms.get(new PipelineContext(vertexType, structType, contextShader, pipelineShader)); } @@ -175,36 +177,29 @@ public class FlwCompiler { .assemble(new Pipeline.InstanceAssemblerContext(sources, ctx.vertexType(), ctx.structType())); var layout = sources.find(ctx.vertexType() - .getLayoutShader() - .resourceLocation()); + .layoutShader()); var instance = sources.find(ctx.structType() - .getInstanceShader() - .resourceLocation()); + .instanceShader()); var context = sources.find(ctx.contextShader() - .vertexShader() - .resourceLocation()); + .vertexShader()); var pipeline = sources.find(ctx.pipelineShader() - .vertex() - .resourceLocation()); + .vertexShader()); return ImmutableList.of(uniformComponent, vertexMaterialComponent, instanceAssembly, layout, instance, context, pipeline); } private ImmutableList getFragmentComponents(PipelineContext ctx) { var context = sources.find(ctx.contextShader() - .fragmentShader() - .resourceLocation()); + .fragmentShader()); var pipeline = sources.find(ctx.pipelineShader() - .fragment() - .resourceLocation()); + .fragmentShader()); return ImmutableList.of(uniformComponent, fragmentMaterialComponent, context, pipeline); } private ImmutableList getComputeComponents(StructType structType) { var instanceAssembly = new IndirectComponent(sources, structType); - var instance = sources.find(structType.getInstanceShader() - .resourceLocation()); - var pipeline = sources.find(Pipelines.Files.INDIRECT_CULL.resourceLocation()); + var instance = sources.find(structType.instanceShader()); + var pipeline = sources.find(Pipelines.Files.INDIRECT_CULL); return ImmutableList.of(uniformComponent, instanceAssembly, instance, pipeline); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java index d28b9efad..f3e575982 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/MaterialAdapterComponent.java @@ -12,9 +12,12 @@ import org.jetbrains.annotations.Nullable; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.SourceComponent; -import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.source.ShaderSources; -import com.jozufozu.flywheel.core.source.generate.*; +import com.jozufozu.flywheel.core.source.generate.FnSignature; +import com.jozufozu.flywheel.core.source.generate.GlslBlock; +import com.jozufozu.flywheel.core.source.generate.GlslBuilder; +import com.jozufozu.flywheel.core.source.generate.GlslExpr; +import com.jozufozu.flywheel.core.source.generate.GlslSwitch; import com.jozufozu.flywheel.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; @@ -100,27 +103,12 @@ public class MaterialAdapterComponent implements SourceComponent { body.add(sw); } - @NotNull - private static HashMap createAdapterMap(List adaptedFunctions, ResourceLocation loc) { - HashMap out = new HashMap<>(); - - var suffix = '_' + ResourceUtil.toSafeString(loc); - - for (var adapted : adaptedFunctions) { - var fnName = adapted.signature() - .name(); - out.put(fnName, fnName + suffix); - } - - return out; - } - private record AdaptedFn(FnSignature signature, @Nullable GlslExpr defaultReturn) { } public static class Builder { private final ResourceLocation name; - private final List sourceMaterials = new ArrayList<>(); + private final List materialSources = new ArrayList<>(); private final List adaptedFunctions = new ArrayList<>(); private GlslExpr switchArg; @@ -128,8 +116,8 @@ public class MaterialAdapterComponent implements SourceComponent { this.name = name; } - public Builder materialSources(List sources) { - this.sourceMaterials.addAll(sources); + public Builder materialSources(List sources) { + this.materialSources.addAll(sources); return this; } @@ -155,14 +143,31 @@ public class MaterialAdapterComponent implements SourceComponent { var transformed = ImmutableList.builder(); - for (FileResolution fileResolution : sourceMaterials) { - var loc = fileResolution.resourceLocation(); - var sourceFile = sources.find(loc); - - transformed.add(new StringSubstitutionSourceComponent(sourceFile, createAdapterMap(adaptedFunctions, loc))); + for (var rl : materialSources) { + var sourceFile = sources.find(rl); + var adapterMap = createAdapterMap(adaptedFunctions, getSuffix(rl)); + transformed.add(new StringSubstitutionSourceComponent(sourceFile, adapterMap)); } return new MaterialAdapterComponent(name, switchArg, adaptedFunctions, transformed.build()); } } + + @NotNull + private static HashMap createAdapterMap(List adaptedFunctions, String suffix) { + HashMap out = new HashMap<>(); + + for (var adapted : adaptedFunctions) { + var fnName = adapted.signature() + .name(); + out.put(fnName, fnName + suffix); + } + + return out; + } + + @NotNull + private static String getSuffix(ResourceLocation rl) { + return '_' + ResourceUtil.toSafeString(rl); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java index bf876f956..179924cfa 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContext.java @@ -1,9 +1,9 @@ package com.jozufozu.flywheel.backend.instancing.compile; -import com.jozufozu.flywheel.api.context.ContextShader; +import com.jozufozu.flywheel.api.context.Context; +import com.jozufozu.flywheel.api.pipeline.Pipeline; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.core.pipeline.SimplePipeline; /** * Represents the entire context of a program's usage. @@ -12,6 +12,6 @@ import com.jozufozu.flywheel.core.pipeline.SimplePipeline; * @param structType The instance shader to use. * @param contextShader The context shader to use. */ -public record PipelineContext(VertexType vertexType, StructType structType, ContextShader contextShader, - SimplePipeline pipelineShader) { +public record PipelineContext(VertexType vertexType, StructType structType, Context contextShader, + Pipeline pipelineShader) { } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContextSet.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContextSet.java index 099bc7096..e103c9fff 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContextSet.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/PipelineContextSet.java @@ -4,12 +4,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.core.BackendTypes; import com.jozufozu.flywheel.core.ComponentRegistry; import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.context.SimpleContext; import com.jozufozu.flywheel.core.pipeline.SimplePipeline; public class PipelineContextSet { @@ -39,7 +39,7 @@ public class PipelineContextSet { return contexts.size(); } - private void add(VertexType vertexType, StructType structType, ContextShader world, SimplePipeline pipelineShader) { + private void add(VertexType vertexType, StructType structType, SimpleContext world, SimplePipeline pipelineShader) { var ctx = new PipelineContext(vertexType, structType, world, pipelineShader); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/UniformComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/UniformComponent.java index d1c2a073d..4c334635d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/UniformComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/compile/UniformComponent.java @@ -6,7 +6,6 @@ import java.util.List; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.SourceComponent; -import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.source.ShaderSources; import com.jozufozu.flywheel.core.source.SourceFile; import com.jozufozu.flywheel.core.source.generate.GlslBuilder; @@ -53,22 +52,22 @@ public class UniformComponent implements SourceComponent { public static class Builder { private final ResourceLocation name; - private final List uniformShaders = new ArrayList<>(); + private final List uniformShaders = new ArrayList<>(); public Builder(ResourceLocation name) { this.name = name; } - public Builder sources(List sources) { - this.uniformShaders.addAll(sources); - return this; - } + public Builder sources(List sources) { + this.uniformShaders.addAll(sources); + return this; + } public UniformComponent build(ShaderSources sources) { var out = ImmutableList.builder(); for (var fileResolution : uniformShaders) { - out.add(sources.find(fileResolution.resourceLocation())); + out.add(sources.find(fileResolution)); } return new UniformComponent(name, out.build()); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java index 05c207cf1..a9f9d4606 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectComponent.java @@ -35,7 +35,7 @@ public class IndirectComponent implements SourceComponent { public IndirectComponent(ShaderSources sources, StructType structType) { this.layoutItems = structType.getLayout().layoutItems; - included = ImmutableList.of(sources.find(Pipelines.Files.UTIL_TYPES.resourceLocation())); + included = ImmutableList.of(sources.find(Pipelines.Files.UTIL_TYPES)); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java index 53bf9baba..ba214ca54 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java @@ -9,7 +9,6 @@ import org.jetbrains.annotations.NotNull; import org.lwjgl.opengl.GL32; import com.jozufozu.flywheel.api.RenderStage; -import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.backend.gl.GlStateTracker; @@ -18,6 +17,7 @@ import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.core.RenderContext; +import com.jozufozu.flywheel.core.context.SimpleContext; import com.jozufozu.flywheel.util.WeakHashSet; import com.mojang.blaze3d.systems.RenderSystem; @@ -38,12 +38,12 @@ public class IndirectEngine implements Engine { */ private final WeakHashSet> instanceManagers = new WeakHashSet<>(); - protected final ContextShader context; + protected final SimpleContext context; protected final int sqrMaxOriginDistance; protected BlockPos originCoordinate = BlockPos.ZERO; - public IndirectEngine(ContextShader context, int sqrMaxOriginDistance) { + public IndirectEngine(SimpleContext context, int sqrMaxOriginDistance) { this.context = context; this.sqrMaxOriginDistance = sqrMaxOriginDistance; } 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 2eefcb058..42470d76b 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 @@ -9,7 +9,6 @@ import org.jetbrains.annotations.NotNull; import org.lwjgl.opengl.GL32; import com.jozufozu.flywheel.api.RenderStage; -import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.backend.gl.GlStateTracker; @@ -20,6 +19,7 @@ import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler; import com.jozufozu.flywheel.core.Pipelines; import com.jozufozu.flywheel.core.RenderContext; +import com.jozufozu.flywheel.core.context.SimpleContext; import com.jozufozu.flywheel.util.WeakHashSet; import com.mojang.blaze3d.systems.RenderSystem; @@ -40,12 +40,12 @@ public class InstancingEngine implements Engine { */ private final WeakHashSet> instanceManagers = new WeakHashSet<>(); - protected final ContextShader context; + protected final SimpleContext context; protected final int sqrMaxOriginDistance; protected BlockPos originCoordinate = BlockPos.ZERO; - public InstancingEngine(ContextShader context, int sqrMaxOriginDistance) { + public InstancingEngine(SimpleContext context, int sqrMaxOriginDistance) { this.context = context; this.sqrMaxOriginDistance = sqrMaxOriginDistance; } diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java index e42654131..9b89fe2ce 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java @@ -8,7 +8,7 @@ import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.BackendType; import com.jozufozu.flywheel.backend.SimpleBackendType; import com.jozufozu.flywheel.core.BackendTypes; -import com.jozufozu.flywheel.core.uniform.FlwUniformProvider; +import com.jozufozu.flywheel.core.uniform.FlwShaderUniforms; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.IntegerArgumentType; @@ -111,17 +111,17 @@ public class FlwCommands { commandBuilder.command.then(Commands.literal("debugFrustum") .then(Commands.literal("pause") .executes(context -> { - FlwUniformProvider.FRUSTUM_PAUSED = true; + FlwShaderUniforms.FRUSTUM_PAUSED = true; return 1; })) .then(Commands.literal("unpause") .executes(context -> { - FlwUniformProvider.FRUSTUM_PAUSED = false; + FlwShaderUniforms.FRUSTUM_PAUSED = false; return 1; })) .then(Commands.literal("capture") .executes(context -> { - FlwUniformProvider.FRUSTUM_CAPTURE = true; + FlwShaderUniforms.FRUSTUM_CAPTURE = true; return 1; }))); diff --git a/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java b/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java index b18d46ded..8a05cea34 100644 --- a/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java +++ b/src/main/java/com/jozufozu/flywheel/core/ComponentRegistry.java @@ -1,25 +1,31 @@ package com.jozufozu.flywheel.core; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.jetbrains.annotations.Nullable; -import com.jozufozu.flywheel.api.context.ContextShader; +import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.api.uniform.UniformProvider; +import com.jozufozu.flywheel.api.uniform.ShaderUniforms; import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.core.source.FileResolution; import net.minecraft.resources.ResourceLocation; public class ComponentRegistry { - private static final Registry uniformProviders = new Registry<>(); + private static final Registry uniformProviders = new Registry<>(); public static final MaterialRegistry materials = new MaterialRegistry(); public static final Set> structTypes = new HashSet<>(); public static final Set vertexTypes = new HashSet<>(); - public static final Set contextShaders = new HashSet<>(); + public static final Set contextShaders = new HashSet<>(); // TODO: fill out the rest of the registry @@ -37,22 +43,21 @@ public class ComponentRegistry { return vertexType; } - public static ContextShader register(ContextShader contextShader) { + public static T register(T contextShader) { contextShaders.add(contextShader); return contextShader; } - public static T register(T provider) { - return uniformProviders.register(provider.uniformShader() - .resourceLocation(), provider); + public static T register(T provider) { + return uniformProviders.register(provider.uniformShader(), provider); } - public static Collection getAllUniformProviders() { + public static Collection getAllUniformProviders() { return Collections.unmodifiableCollection(uniformProviders.objects); } @Nullable - public static UniformProvider getUniformProvider(ResourceLocation loc) { + public static ShaderUniforms getUniformProvider(ResourceLocation loc) { return uniformProviders.get(loc); } @@ -84,8 +89,8 @@ public class ComponentRegistry { public T add(T material) { materials.add(material); - vertexSources.register(material.getVertexShader()); - fragmentSources.register(material.getFragmentShader()); + vertexSources.register(material.vertexShader()); + fragmentSources.register(material.fragmentShader()); return material; } @@ -93,31 +98,31 @@ public class ComponentRegistry { /** * @return a list of vertex shader sources where the index in the list is the shader's ID. */ - public List vertexSources() { + public List vertexSources() { return vertexSources.sourceView; } /** * @return a list of fragment shader sources where the index in the list is the shader's ID. */ - public List fragmentSources() { + public List fragmentSources() { return fragmentSources.sourceView; } public int getVertexID(Material material) { - return vertexSources.orderedSources.indexOf(material.getVertexShader()); + return vertexSources.orderedSources.indexOf(material.vertexShader()); } public int getFragmentID(Material material) { - return fragmentSources.orderedSources.indexOf(material.getFragmentShader()); + return fragmentSources.orderedSources.indexOf(material.fragmentShader()); } private static class MaterialSources { - private final Set registered = new HashSet<>(); - private final List orderedSources = new ArrayList<>(); - private final List sourceView = Collections.unmodifiableList(orderedSources); + private final Set registered = new HashSet<>(); + private final List orderedSources = new ArrayList<>(); + private final List sourceView = Collections.unmodifiableList(orderedSources); - public void register(FileResolution vertexShader) { + public void register(ResourceLocation vertexShader) { if (registered.add(vertexShader)) { orderedSources.add(vertexShader); } diff --git a/src/main/java/com/jozufozu/flywheel/core/Components.java b/src/main/java/com/jozufozu/flywheel/core/Components.java index 9e81348f6..a4502e3a7 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Components.java +++ b/src/main/java/com/jozufozu/flywheel/core/Components.java @@ -1,15 +1,9 @@ package com.jozufozu.flywheel.core; -import java.util.function.BiConsumer; - import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.api.context.ContextShader; -import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.core.source.SourceChecks; -import com.jozufozu.flywheel.core.source.SourceFile; -import com.jozufozu.flywheel.core.source.error.ErrorReporter; +import com.jozufozu.flywheel.core.context.SimpleContext; import com.jozufozu.flywheel.core.structs.StructTypes; -import com.jozufozu.flywheel.core.uniform.FlwUniformProvider; +import com.jozufozu.flywheel.core.uniform.FlwShaderUniforms; import com.jozufozu.flywheel.core.vertex.Formats; import com.jozufozu.flywheel.util.ResourceUtil; @@ -18,12 +12,11 @@ import net.minecraft.resources.ResourceLocation; public class Components { - public static final FlwUniformProvider UNIFORM_PROVIDER = ComponentRegistry.register(new FlwUniformProvider()); - public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(Files.WORLD_VERTEX, Files.WORLD_FRAGMENT)); - public static final ContextShader CRUMBLING = ComponentRegistry.register(new ContextShader(Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT)); + public static final FlwShaderUniforms UNIFORM_PROVIDER = ComponentRegistry.register(new FlwShaderUniforms()); + public static final SimpleContext WORLD = ComponentRegistry.register(new SimpleContext(Files.WORLD_VERTEX, Files.WORLD_FRAGMENT)); + public static final SimpleContext CRUMBLING = ComponentRegistry.register(new SimpleContext(Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT)); public static void init() { - Files.init(); Formats.init(); StructTypes.init(); Materials.init(); @@ -32,73 +25,19 @@ public class Components { public static class Files { - public static final FileResolution UNIFORMS = uniform(Flywheel.rl("uniform/flywheel.glsl")); - public static final FileResolution BLOCK_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.BLOCK, ".vert")); - public static final FileResolution POS_TEX_NORMAL_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert")); - public static final FileResolution TRANSFORMED = instanceVertex(ResourceUtil.subPath(Names.TRANSFORMED, ".vert")); - public static final FileResolution ORIENTED = instanceVertex(ResourceUtil.subPath(Names.ORIENTED, ".vert")); - public static final FileResolution DEFAULT_VERTEX = materialVertex(ResourceUtil.subPath(Names.DEFAULT, ".vert")); - public static final FileResolution SHADED_VERTEX = materialVertex(ResourceUtil.subPath(Names.SHADED, ".vert")); - public static final FileResolution DEFAULT_FRAGMENT = materialFragment(ResourceUtil.subPath(Names.DEFAULT, ".frag")); - public static final FileResolution CUTOUT_FRAGMENT = materialFragment(ResourceUtil.subPath(Names.CUTOUT, ".frag")); - public static final FileResolution WORLD_VERTEX = contextVertex(ResourceUtil.subPath(Names.WORLD, ".vert")); - public static final FileResolution WORLD_FRAGMENT = contextFragment(ResourceUtil.subPath(Names.WORLD, ".frag")); - public static final FileResolution CRUMBLING_VERTEX = contextVertex(ResourceUtil.subPath(Names.CRUMBLING, ".vert")); - public static final FileResolution CRUMBLING_FRAGMENT = contextFragment(ResourceUtil.subPath(Names.CRUMBLING, ".frag")); - - private static FileResolution compute(ResourceLocation rl) { - return FileResolution.get(rl); - } - - private static FileResolution uniform(ResourceLocation location) { - return FileResolution.get(location); - } - - private static FileResolution layoutVertex(ResourceLocation location) { - return FileResolution.get(location) - .validateWith(Checks.LAYOUT_VERTEX); - } - - private static FileResolution instanceVertex(ResourceLocation location) { - return FileResolution.get(location); // .validateWith(Checks.INSTANCE_VERTEX); - } - - private static FileResolution materialVertex(ResourceLocation location) { - return FileResolution.get(location) - .validateWith(Checks.MATERIAL_VERTEX); - } - - private static FileResolution materialFragment(ResourceLocation location) { - return FileResolution.get(location) - .validateWith(Checks.MATERIAL_FRAGMENT); - } - - private static FileResolution contextVertex(ResourceLocation location) { - return FileResolution.get(location) - .validateWith(Checks.CONTEXT_VERTEX); - } - - private static FileResolution contextFragment(ResourceLocation location) { - return FileResolution.get(location) - .validateWith(Checks.CONTEXT_FRAGMENT); - } - - public static void init() { - // noop, just in case - } - } - - public static class Checks { - - public static final BiConsumer LAYOUT_VERTEX = SourceChecks.checkFunctionArity("flw_layoutVertex", 0); - public static final BiConsumer INSTANCE_VERTEX = SourceChecks.checkFunctionParameterTypeExists("flw_instanceVertex", 1, 0); - public static final BiConsumer MATERIAL_VERTEX = SourceChecks.checkFunctionArity("flw_materialVertex", 0); - public static final BiConsumer MATERIAL_FRAGMENT = SourceChecks.checkFunctionArity("flw_materialFragment", 0); - public static final BiConsumer CONTEXT_VERTEX = SourceChecks.checkFunctionArity("flw_contextVertex", 0); - public static final BiConsumer CONTEXT_FRAGMENT = SourceChecks.checkFunctionArity("flw_contextFragment", 0) - .andThen(SourceChecks.checkFunctionArity("flw_initFragment", 0)); - - public static final BiConsumer PIPELINE = SourceChecks.checkFunctionArity("main", 0); + public static final ResourceLocation UNIFORMS = Flywheel.rl("uniform/flywheel.glsl"); + public static final ResourceLocation BLOCK_LAYOUT = ResourceUtil.subPath(Names.BLOCK, ".vert"); + public static final ResourceLocation POS_TEX_NORMAL_LAYOUT = ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert"); + public static final ResourceLocation TRANSFORMED = ResourceUtil.subPath(Names.TRANSFORMED, ".vert"); + public static final ResourceLocation ORIENTED = ResourceUtil.subPath(Names.ORIENTED, ".vert"); + public static final ResourceLocation DEFAULT_VERTEX = ResourceUtil.subPath(Names.DEFAULT, ".vert"); + public static final ResourceLocation SHADED_VERTEX = ResourceUtil.subPath(Names.SHADED, ".vert"); + public static final ResourceLocation DEFAULT_FRAGMENT = ResourceUtil.subPath(Names.DEFAULT, ".frag"); + public static final ResourceLocation CUTOUT_FRAGMENT = ResourceUtil.subPath(Names.CUTOUT, ".frag"); + public static final ResourceLocation WORLD_VERTEX = ResourceUtil.subPath(Names.WORLD, ".vert"); + public static final ResourceLocation WORLD_FRAGMENT = ResourceUtil.subPath(Names.WORLD, ".frag"); + public static final ResourceLocation CRUMBLING_VERTEX = ResourceUtil.subPath(Names.CRUMBLING, ".vert"); + public static final ResourceLocation CRUMBLING_FRAGMENT = ResourceUtil.subPath(Names.CRUMBLING, ".frag"); } public static class Names { diff --git a/src/main/java/com/jozufozu/flywheel/core/Pipelines.java b/src/main/java/com/jozufozu/flywheel/core/Pipelines.java index 4d2c249e2..c26f98c6a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Pipelines.java +++ b/src/main/java/com/jozufozu/flywheel/core/Pipelines.java @@ -5,7 +5,8 @@ import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.backend.instancing.indirect.IndirectComponent; import com.jozufozu.flywheel.backend.instancing.instancing.InstancedArraysComponent; import com.jozufozu.flywheel.core.pipeline.SimplePipeline; -import com.jozufozu.flywheel.core.source.FileResolution; + +import net.minecraft.resources.ResourceLocation; public class Pipelines { public static final SimplePipeline INSTANCED_ARRAYS = SimplePipeline.builder() @@ -26,15 +27,10 @@ public class Pipelines { } public static class Files { - public static final FileResolution DRAW_FRAGMENT = pipeline("pipeline/draw.frag"); - public static final FileResolution INSTANCED_ARRAYS_DRAW = pipeline("pipeline/instanced_arrays_draw.vert"); - public static final FileResolution INDIRECT_DRAW = pipeline("pipeline/indirect_draw.vert"); - public static final FileResolution INDIRECT_CULL = pipeline("pipeline/indirect_cull.glsl"); - public static final FileResolution UTIL_TYPES = FileResolution.get(Flywheel.rl("util/types.glsl")); - - private static FileResolution pipeline(String name) { - return FileResolution.get(Flywheel.rl(name)) - .validateWith(Components.Checks.PIPELINE); - } + public static final ResourceLocation DRAW_FRAGMENT = Flywheel.rl("pipeline/draw.frag"); + public static final ResourceLocation INSTANCED_ARRAYS_DRAW = Flywheel.rl("pipeline/instanced_arrays_draw.vert"); + public static final ResourceLocation INDIRECT_DRAW = Flywheel.rl("pipeline/indirect_draw.vert"); + public static final ResourceLocation INDIRECT_CULL = Flywheel.rl("pipeline/indirect_cull.glsl"); + public static final ResourceLocation UTIL_TYPES = Flywheel.rl("util/types.glsl"); } } diff --git a/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java b/src/main/java/com/jozufozu/flywheel/core/context/SimpleContext.java similarity index 53% rename from src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java rename to src/main/java/com/jozufozu/flywheel/core/context/SimpleContext.java index e908a6ae1..73ee24389 100644 --- a/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java +++ b/src/main/java/com/jozufozu/flywheel/core/context/SimpleContext.java @@ -1,9 +1,11 @@ -package com.jozufozu.flywheel.api.context; +package com.jozufozu.flywheel.core.context; +import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.core.source.FileResolution; -public record ContextShader(FileResolution vertexShader, FileResolution fragmentShader) implements Context { +import net.minecraft.resources.ResourceLocation; + +public record SimpleContext(ResourceLocation vertexShader, ResourceLocation fragmentShader) implements Context { @Override public void onProgramLink(GlProgram program) { program.bind(); @@ -14,12 +16,12 @@ public record ContextShader(FileResolution vertexShader, FileResolution fragment } @Override - public FileResolution vertexShader() { + public ResourceLocation vertexShader() { return vertexShader; } @Override - public FileResolution fragmentShader() { + public ResourceLocation fragmentShader() { return fragmentShader; } } diff --git a/src/main/java/com/jozufozu/flywheel/core/material/SimpleMaterial.java b/src/main/java/com/jozufozu/flywheel/core/material/SimpleMaterial.java index 0993f645d..57ac6e0b5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/material/SimpleMaterial.java +++ b/src/main/java/com/jozufozu/flywheel/core/material/SimpleMaterial.java @@ -4,21 +4,21 @@ import com.jozufozu.flywheel.api.RenderStage; import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.core.ComponentRegistry; import com.jozufozu.flywheel.core.Components; -import com.jozufozu.flywheel.core.source.FileResolution; import net.minecraft.client.renderer.RenderStateShard; import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; public class SimpleMaterial implements Material { protected final RenderStage stage; - protected final FileResolution vertexShader; - protected final FileResolution fragmentShader; + protected final ResourceLocation vertexShader; + protected final ResourceLocation fragmentShader; protected final Runnable setup; protected final Runnable clear; protected final RenderType batchingRenderType; protected final VertexTransformer vertexTransformer; - public SimpleMaterial(RenderStage stage, FileResolution vertexShader, FileResolution fragmentShader, Runnable setup, Runnable clear, RenderType batchingRenderType, VertexTransformer vertexTransformer) { + public SimpleMaterial(RenderStage stage, ResourceLocation vertexShader, ResourceLocation fragmentShader, Runnable setup, Runnable clear, RenderType batchingRenderType, VertexTransformer vertexTransformer) { this.stage = stage; this.vertexShader = vertexShader; this.fragmentShader = fragmentShader; @@ -38,12 +38,12 @@ public class SimpleMaterial implements Material { } @Override - public FileResolution getVertexShader() { + public ResourceLocation vertexShader() { return vertexShader; } @Override - public FileResolution getFragmentShader() { + public ResourceLocation fragmentShader() { return fragmentShader; } @@ -69,12 +69,15 @@ public class SimpleMaterial implements Material { public static class Builder { protected RenderStage stage = RenderStage.AFTER_SOLID_TERRAIN; - protected FileResolution vertexShader = Components.Files.DEFAULT_VERTEX; - protected FileResolution fragmentShader = Components.Files.DEFAULT_FRAGMENT; - protected Runnable setup = () -> {}; - protected Runnable clear = () -> {}; + protected ResourceLocation vertexShader = Components.Files.DEFAULT_VERTEX; + protected ResourceLocation fragmentShader = Components.Files.DEFAULT_FRAGMENT; + protected Runnable setup = () -> { + }; + protected Runnable clear = () -> { + }; protected RenderType batchingRenderType = RenderType.solid(); - protected VertexTransformer vertexTransformer = (vertexList, level) -> {}; + protected VertexTransformer vertexTransformer = (vertexList, level) -> { + }; public Builder() { } @@ -84,12 +87,12 @@ public class SimpleMaterial implements Material { return this; } - public Builder vertexShader(FileResolution vertexShader) { + public Builder vertexShader(ResourceLocation vertexShader) { this.vertexShader = vertexShader; return this; } - public Builder fragmentShader(FileResolution fragmentShader) { + public Builder fragmentShader(ResourceLocation fragmentShader) { this.fragmentShader = fragmentShader; return this; } diff --git a/src/main/java/com/jozufozu/flywheel/core/pipeline/SimplePipeline.java b/src/main/java/com/jozufozu/flywheel/core/pipeline/SimplePipeline.java index 3a7a680c1..8717a55c2 100644 --- a/src/main/java/com/jozufozu/flywheel/core/pipeline/SimplePipeline.java +++ b/src/main/java/com/jozufozu/flywheel/core/pipeline/SimplePipeline.java @@ -4,15 +4,16 @@ import com.jozufozu.flywheel.api.pipeline.Pipeline; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.core.SourceComponent; -import com.jozufozu.flywheel.core.source.FileResolution; + +import net.minecraft.resources.ResourceLocation; public final class SimplePipeline implements Pipeline { private final GLSLVersion glslVersion; - private final FileResolution vertex; - private final FileResolution fragment; + private final ResourceLocation vertex; + private final ResourceLocation fragment; private final InstanceAssemblerFactory factory; - public SimplePipeline(GLSLVersion glslVersion, FileResolution vertex, FileResolution fragment, InstanceAssemblerFactory factory) { + public SimplePipeline(GLSLVersion glslVersion, ResourceLocation vertex, ResourceLocation fragment, InstanceAssemblerFactory factory) { this.glslVersion = glslVersion; this.vertex = vertex; this.fragment = fragment; @@ -35,12 +36,12 @@ public final class SimplePipeline implements Pipeline { } @Override - public FileResolution vertex() { + public ResourceLocation vertexShader() { return vertex; } @Override - public FileResolution fragment() { + public ResourceLocation fragmentShader() { return fragment; } @@ -55,8 +56,8 @@ public final class SimplePipeline implements Pipeline { public static class Builder { private GLSLVersion glslVersion; - private FileResolution vertex; - private FileResolution fragment; + private ResourceLocation vertex; + private ResourceLocation fragment; private InstanceAssemblerFactory factory; public Builder glslVersion(GLSLVersion glslVersion) { @@ -64,12 +65,12 @@ public final class SimplePipeline implements Pipeline { return this; } - public Builder vertex(FileResolution vertex) { + public Builder vertex(ResourceLocation vertex) { this.vertex = vertex; return this; } - public Builder fragment(FileResolution fragment) { + public Builder fragment(ResourceLocation fragment) { this.fragment = fragment; return this; } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/FileResolution.java b/src/main/java/com/jozufozu/flywheel/core/source/FileResolution.java deleted file mode 100644 index 860532d59..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/source/FileResolution.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.jozufozu.flywheel.core.source; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.BiConsumer; - -import com.jozufozu.flywheel.core.source.error.ErrorBuilder; -import com.jozufozu.flywheel.core.source.error.ErrorReporter; -import com.jozufozu.flywheel.core.source.span.Span; - -import net.minecraft.resources.ResourceLocation; - -/** - * A reference to a source file that might not be loaded when the owning object is created. - * - *

- * FileResolutions are used primarily while parsing import statements. {@link FileResolution#file} is initially - * null, but will be populated later on, after all SourceFiles are loaded (assuming - * {@link FileResolution#fileLoc} references an actual file). - *

- */ -public class FileResolution { - - private static final Map ALL = new HashMap<>(); - private static final Map WEAK = new HashMap<>(); - private static boolean tooLate = false; - - /** - * Extra info about where this resolution is required. Includes shader Spans. - */ - private final List neededAt = new ArrayList<>(); - private final List> checks = new ArrayList<>(); - - private final ResourceLocation fileLoc; - private final boolean weak; - - private FileResolution(ResourceLocation fileLoc, boolean weak) { - this.fileLoc = fileLoc; - this.weak = weak; - } - - public static FileResolution get(ResourceLocation file) { - if (!tooLate) { - return ALL.computeIfAbsent(file, loc -> new FileResolution(loc, false)); - } else { - // Lock the map after resolution has run. - FileResolution fileResolution = ALL.get(file); - - // ...so crash immediately if the file isn't found. - if (fileResolution == null) { - throw new ShaderLoadingException("could not find source for file: " + file); - } - - return fileResolution; - } - } - - /** - * Weak resolutions don't persist through resource reloads.

- * This should be used inside parsing code. - * - * @param file The location of the file to resolve. - * @return A weak resolution for the given file. - */ - public static FileResolution weak(ResourceLocation file) { - FileResolution fileResolution = ALL.get(file); - - if (fileResolution != null) { - return fileResolution; - } - // never too late for weak resolutions. - return WEAK.computeIfAbsent(file, loc -> new FileResolution(loc, true)); - } - - public static void checkAll(ErrorReporter errorReporter) { - for (FileResolution resolution : ALL.values()) { - resolution.runChecks(errorReporter); - } - } - - private void reportMissing(ErrorReporter errorReporter) { - ErrorBuilder builder = errorReporter.error(String.format("could not find source for file %s", fileLoc)); - for (Span location : neededAt) { - builder.pointAtFile(location.getSourceFile()) - .pointAt(location); - } - } - - private void runChecks(ErrorReporter errorReporter) { - // for (var check : checks) { - // check.accept(errorReporter, file); - // } - } - - public ResourceLocation resourceLocation() { - return fileLoc; - } - - - public boolean isWeak() { - return weak; - } - - /** - * Store the given span so this resolution can know all the places that reference the file. - * - *

- * Used for error reporting. - *

- * @param span A span where this file is referenced. - */ - public FileResolution addSpan(Span span) { - neededAt.add(span); - return this; - } - - public FileResolution validateWith(BiConsumer check) { - checks.add(check); - return this; - } - - @Override - public String toString() { - return "FileResolution[" + fileLoc + "]"; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - FileResolution that = (FileResolution) o; - - return fileLoc.equals(that.fileLoc); - } - - @Override - public int hashCode() { - // FileResolutions are interned and therefore can be hashed based on object identity. - // Overriding this to make it explicit. - return System.identityHashCode(this); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/ShaderSources.java b/src/main/java/com/jozufozu/flywheel/core/source/ShaderSources.java index b534f932a..3e4a7f21c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/ShaderSources.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/ShaderSources.java @@ -28,7 +28,7 @@ public class ShaderSources { private final Map cache = new HashMap<>(); /** - * Tracks + * Tracks where we are in the mutual recursion to detect circular imports. */ private final Deque findStack = new ArrayDeque<>(); @@ -42,17 +42,14 @@ public class ShaderSources { @Nonnull public SourceFile find(ResourceLocation location) { - if (findStack.contains(location)) { - generateRecursiveImportException(location); - } - findStack.add(location); + pushFindStack(location); // Can't use computeIfAbsent because mutual recursion causes ConcurrentModificationExceptions var out = cache.get(location); if (out == null) { out = load(location); cache.put(location, out); } - findStack.pop(); + popFindStack(); return out; } @@ -78,4 +75,15 @@ public class ShaderSources { findStack.clear(); throw new ShaderLoadingException("recursive import: " + path); } + + private void pushFindStack(ResourceLocation location) { + if (findStack.contains(location)) { + generateRecursiveImportException(location); + } + findStack.add(location); + } + + private void popFindStack() { + findStack.pop(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceChecks.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceChecks.java index f04bcd005..e26b9b94a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceChecks.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceChecks.java @@ -12,6 +12,17 @@ import com.jozufozu.flywheel.core.source.parse.ShaderVariable; public class SourceChecks { + // TODO: recycle to be invoked by the shader compiler + + public static final BiConsumer LAYOUT_VERTEX = checkFunctionArity("flw_layoutVertex", 0); + public static final BiConsumer INSTANCE_VERTEX = checkFunctionParameterTypeExists("flw_instanceVertex", 1, 0); + public static final BiConsumer MATERIAL_VERTEX = checkFunctionArity("flw_materialVertex", 0); + public static final BiConsumer MATERIAL_FRAGMENT = checkFunctionArity("flw_materialFragment", 0); + public static final BiConsumer CONTEXT_VERTEX = checkFunctionArity("flw_contextVertex", 0); + public static final BiConsumer CONTEXT_FRAGMENT = checkFunctionArity("flw_contextFragment", 0).andThen(checkFunctionArity("flw_initFragment", 0)); + public static final BiConsumer PIPELINE = checkFunctionArity("main", 0); + + public static BiConsumer checkFunctionArity(String name, int arity) { return (errorReporter, file) -> checkFunctionArity(errorReporter, file, name, arity); } diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java index 166231bf9..d95539bad 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java @@ -5,13 +5,14 @@ import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.CommonItems; -import com.jozufozu.flywheel.core.source.FileResolution; import com.mojang.math.Matrix3f; import com.mojang.math.Matrix4f; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; import com.mojang.math.Vector4f; +import net.minecraft.resources.ResourceLocation; + public class OrientedType implements StructType { public static final BufferLayout FORMAT = BufferLayout.builder() @@ -38,7 +39,7 @@ public class OrientedType implements StructType { } @Override - public FileResolution getInstanceShader() { + public ResourceLocation instanceShader() { return Components.Files.ORIENTED; } diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedType.java b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedType.java index 2138e8743..9c02a3b35 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedType.java @@ -5,10 +5,11 @@ import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.CommonItems; -import com.jozufozu.flywheel.core.source.FileResolution; import com.mojang.math.Vector3f; import com.mojang.math.Vector4f; +import net.minecraft.resources.ResourceLocation; + public class TransformedType implements StructType { public static final BufferLayout FORMAT = BufferLayout.builder() @@ -34,7 +35,7 @@ public class TransformedType implements StructType { } @Override - public FileResolution getInstanceShader() { + public ResourceLocation instanceShader() { return Components.Files.TRANSFORMED; } diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/FlwUniformProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FlwShaderUniforms.java similarity index 70% rename from src/main/java/com/jozufozu/flywheel/core/uniform/FlwUniformProvider.java rename to src/main/java/com/jozufozu/flywheel/core/uniform/FlwShaderUniforms.java index 63ddb39f4..9ad05e878 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/FlwUniformProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/FlwShaderUniforms.java @@ -4,21 +4,20 @@ import java.util.function.Consumer; import org.lwjgl.system.MemoryUtil; -import com.jozufozu.flywheel.api.uniform.UniformProvider; +import com.jozufozu.flywheel.api.uniform.ShaderUniforms; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.RenderContext; -import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.extension.MatrixWrite; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.Vec3i; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.MinecraftForge; -public class FlwUniformProvider implements UniformProvider { +public class FlwShaderUniforms implements ShaderUniforms { public static final int SIZE = 224; @@ -32,16 +31,16 @@ public class FlwUniformProvider implements UniformProvider { } @Override - public FileResolution uniformShader() { + public ResourceLocation uniformShader() { return Components.Files.UNIFORMS; } @Override - public ActiveUniformProvider activate(long ptr) { + public Provider activate(long ptr) { return new Active(ptr); } - public static class Active implements ActiveUniformProvider, Consumer { + public static class Active implements Provider, Consumer { private final long ptr; private boolean dirty; @@ -66,8 +65,41 @@ public class FlwUniformProvider implements UniformProvider { @Override public void accept(BeginFrameEvent event) { - updateFrustum(event.getContext()); - updateView(event.getContext()); + if (ptr == MemoryUtil.NULL) { + return; + } + RenderContext context = event.getContext(); + + Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(context.level()); + Vec3 camera = context.camera() + .getPosition(); + + var camX = (float) (camera.x - originCoordinate.getX()); + var camY = (float) (camera.y - originCoordinate.getY()); + var camZ = (float) (camera.z - originCoordinate.getZ()); + + // don't want to mutate viewProjection + var vp = context.viewProjection() + .copy(); + vp.multiplyWithTranslation(-camX, -camY, -camZ); + + MatrixWrite.writeUnsafe(vp, ptr + 32); + MemoryUtil.memPutFloat(ptr + 96, camX); + MemoryUtil.memPutFloat(ptr + 100, camY); + MemoryUtil.memPutFloat(ptr + 104, camZ); + MemoryUtil.memPutFloat(ptr + 108, 0f); // vec4 alignment + MemoryUtil.memPutInt(ptr + 112, getConstantAmbientLightFlag(context)); + + updateFrustum(context, camX, camY, camZ); + + dirty = true; + } + + private static int getConstantAmbientLightFlag(RenderContext context) { + var constantAmbientLight = context.level() + .effects() + .constantAmbientLight(); + return constantAmbientLight ? 1 : 0; } private boolean maybeUpdateFog() { @@ -84,65 +116,23 @@ public class FlwUniformProvider implements UniformProvider { MemoryUtil.memPutFloat(ptr + 16, RenderSystem.getShaderFogStart()); MemoryUtil.memPutFloat(ptr + 20, RenderSystem.getShaderFogEnd()); MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape() - .getIndex()); + .getIndex()); FOG_UPDATE = false; return true; } - public void updateFrustum(RenderContext context) { - if (ptr == MemoryUtil.NULL || (FRUSTUM_PAUSED && !FRUSTUM_CAPTURE)) { + private void updateFrustum(RenderContext context, float camX, float camY, float camZ) { + if (FRUSTUM_PAUSED && !FRUSTUM_CAPTURE) { return; } - Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(context.level()); - Vec3 camera = context.camera() - .getPosition(); - - var camX = (float) (camera.x - originCoordinate.getX()); - var camY = (float) (camera.y - originCoordinate.getY()); - var camZ = (float) (camera.z - originCoordinate.getZ()); - var shiftedCuller = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ); shiftedCuller.getJozuPackedPlanes(ptr + 128); - dirty = true; FRUSTUM_CAPTURE = false; } - - public void updateView(RenderContext context) { - if (ptr == MemoryUtil.NULL) { - return; - } - - ClientLevel level = context.level(); - - int constantAmbientLight = level.effects() - .constantAmbientLight() ? 1 : 0; - - Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(level); - Vec3 camera = context.camera() - .getPosition(); - - var camX = (float) (camera.x - originCoordinate.getX()); - var camY = (float) (camera.y - originCoordinate.getY()); - var camZ = (float) (camera.z - originCoordinate.getZ()); - - // don't want to mutate viewProjection - var vp = context.viewProjection() - .copy(); - vp.multiplyWithTranslation(-camX, -camY, -camZ); - - MatrixWrite.writeUnsafe(vp, ptr + 32); - MemoryUtil.memPutFloat(ptr + 96, camX); - MemoryUtil.memPutFloat(ptr + 100, camY); - MemoryUtil.memPutFloat(ptr + 104, camZ); - MemoryUtil.memPutFloat(ptr + 108, 0f); // vec4 alignment - MemoryUtil.memPutInt(ptr + 112, constantAmbientLight); - - dirty = true; - } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java index b184cd2b8..348801fe0 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java @@ -1,17 +1,17 @@ package com.jozufozu.flywheel.core.uniform; -import java.util.BitSet; import java.util.Collection; import java.util.List; import org.lwjgl.opengl.GL32; import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.api.uniform.UniformProvider; +import com.jozufozu.flywheel.api.uniform.ShaderUniforms; import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.memory.MemoryBlock; import com.jozufozu.flywheel.core.ComponentRegistry; +import com.jozufozu.flywheel.util.FlwUtil; import com.jozufozu.flywheel.util.RenderMath; public class UniformBuffer { @@ -22,7 +22,7 @@ public class UniformBuffer { private static final boolean PO2_ALIGNMENT = RenderMath.isPowerOf2(OFFSET_ALIGNMENT); private static UniformBuffer instance; - private final AllocatedProviderSet providerSet; + private final ProviderSet providerSet; public static UniformBuffer getInstance() { if (instance == null) { @@ -34,20 +34,16 @@ public class UniformBuffer { private final GlBuffer buffer; private UniformBuffer() { - // TODO: put everything into one ubo buffer = new GlBuffer(GlBufferType.UNIFORM_BUFFER); - providerSet = new AllocatedProviderSet(ComponentRegistry.getAllUniformProviders()); + providerSet = new ProviderSet(ComponentRegistry.getAllUniformProviders()); } public void sync() { - providerSet.sync(); - - buffer.upload(providerSet.data); - - int handle = buffer.handle(); - for (Allocated p : providerSet.allocatedProviders) { - GL32.glBindBufferRange(GL32.GL_UNIFORM_BUFFER, p.index, handle, p.offset, p.size); + if (providerSet.pollUpdates()) { + buffer.upload(providerSet.data); } + + GL32.glBindBufferRange(GL32.GL_UNIFORM_BUFFER, 0, buffer.handle(), 0, providerSet.data.size()); } // https://stackoverflow.com/questions/3407012/rounding-up-to-the-nearest-multiple-of-a-number @@ -59,22 +55,16 @@ public class UniformBuffer { } } - private static int align16(int numToRound) { - return (numToRound + 16 - 1) & -16; - } - - private static class Allocated { - private final UniformProvider provider; + private static class LiveProvider { + private final ShaderUniforms provider; private final int offset; private final int size; - private final int index; - private UniformProvider.ActiveUniformProvider activeProvider; + private ShaderUniforms.Provider activeProvider; - private Allocated(UniformProvider provider, int offset, int size, int index) { + private LiveProvider(ShaderUniforms provider, int offset, int size) { this.provider = provider; this.offset = offset; this.size = size; - this.index = index; } private void updatePtr(MemoryBlock bufferBase) { @@ -84,59 +74,42 @@ public class UniformBuffer { activeProvider = provider.activate(bufferBase.ptr() + offset); } - public int offset() { - return offset; - } - - public int size() { - return size; - } - - public int index() { - return index; - } - public boolean maybePoll() { return activeProvider != null && activeProvider.poll(); } } - private static class AllocatedProviderSet { - private final List allocatedProviders; + private static class ProviderSet { + private final List allocatedProviders; private final MemoryBlock data; - private final BitSet changedBytes; - - private AllocatedProviderSet(final Collection providers) { - var builder = ImmutableList.builder(); + private ProviderSet(final Collection providers) { + var builder = ImmutableList.builder(); int totalBytes = 0; - int index = 0; - for (UniformProvider provider : providers) { - int size = align16(provider.byteSize()); + for (ShaderUniforms provider : providers) { + int size = FlwUtil.align16(provider.byteSize()); - builder.add(new Allocated(provider, totalBytes, size, index)); + builder.add(new LiveProvider(provider, totalBytes, size)); - totalBytes = alignUniformBuffer(totalBytes + size); - index++; + totalBytes += size; } allocatedProviders = builder.build(); data = MemoryBlock.mallocTracked(totalBytes); - changedBytes = new BitSet(totalBytes); - for (Allocated p : allocatedProviders) { + for (LiveProvider p : allocatedProviders) { p.updatePtr(data); } } - public void sync() { - for (Allocated p : allocatedProviders) { - if (p.maybePoll()) { - changedBytes.set(p.offset(), p.offset() + p.size()); - } + public boolean pollUpdates() { + boolean changed = false; + for (LiveProvider p : allocatedProviders) { + changed |= p.maybePoll(); } + return changed; } } } 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 e95692529..9ccf3245c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java @@ -4,7 +4,8 @@ import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.CommonItems; -import com.jozufozu.flywheel.core.source.FileResolution; + +import net.minecraft.resources.ResourceLocation; public class BlockVertex implements VertexType { public static final BufferLayout FORMAT = BufferLayout.builder() @@ -22,7 +23,7 @@ public class BlockVertex implements VertexType { } @Override - public FileResolution getLayoutShader() { + public ResourceLocation layoutShader() { return Components.Files.BLOCK_LAYOUT; } 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 9d0ad7856..9df21e521 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java @@ -4,7 +4,8 @@ import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.CommonItems; -import com.jozufozu.flywheel.core.source.FileResolution; + +import net.minecraft.resources.ResourceLocation; public class PosTexNormalVertex implements VertexType { public static final BufferLayout FORMAT = BufferLayout.builder() @@ -19,7 +20,7 @@ public class PosTexNormalVertex implements VertexType { } @Override - public FileResolution getLayoutShader() { + public ResourceLocation layoutShader() { return Components.Files.POS_TEX_NORMAL_LAYOUT; } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/BlockEntityRenderDispatcherAccessor.java b/src/main/java/com/jozufozu/flywheel/mixin/BlockEntityRenderDispatcherAccessor.java deleted file mode 100644 index 7f7830218..000000000 --- a/src/main/java/com/jozufozu/flywheel/mixin/BlockEntityRenderDispatcherAccessor.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.jozufozu.flywheel.mixin; - -import java.util.Map; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; -import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; -import net.minecraft.world.level.block.entity.BlockEntityType; - -@Mixin(BlockEntityRenderDispatcher.class) -public interface BlockEntityRenderDispatcherAccessor { - @Accessor("renderers") - Map, BlockEntityRenderer> flywheel$getRenderers(); -} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java index 4d13400f1..69a30e22a 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/FogUpdateMixin.java @@ -5,14 +5,14 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.jozufozu.flywheel.core.uniform.FlwUniformProvider; +import com.jozufozu.flywheel.core.uniform.FlwShaderUniforms; import net.minecraft.client.renderer.FogRenderer; @Mixin(FogRenderer.class) public class FogUpdateMixin { private static void flywheel$updateFog() { - FlwUniformProvider.FOG_UPDATE = true; + FlwShaderUniforms.FOG_UPDATE = true; } @Inject(method = "setupNoFog", at = @At("TAIL")) diff --git a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java b/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java index 6742a19cf..f9bb502ab 100644 --- a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java +++ b/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java @@ -3,24 +3,10 @@ package com.jozufozu.flywheel.util; import java.util.Map; import java.util.stream.Stream; -import com.jozufozu.flywheel.mixin.BlockEntityRenderDispatcherAccessor; import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; -import net.minecraft.world.level.block.entity.BlockEntityType; - public class FlwUtil { - /** - * Get the (effectively global) map of BlockEntityTypes to Renderers. - * @return An immutable map of BlockEntityTypes to BlockEntityRenderers. - */ - public static Map, BlockEntityRenderer> getBlockEntityRenderers() { - Minecraft mc = Minecraft.getInstance(); - return ((BlockEntityRenderDispatcherAccessor) mc.getBlockEntityRenderDispatcher()).flywheel$getRenderers(); - } - public static PoseStack copyPoseStack(PoseStack stack) { PoseStack copy = new PoseStack(); copy.last().pose().load(stack.last().pose()); @@ -77,4 +63,8 @@ public class FlwUtil { public static void noop(T object) { // noop } + + public static int align16(int numToRound) { + return (numToRound + 16 - 1) & -16; + } } diff --git a/src/main/java/com/jozufozu/flywheel/util/Mods.java b/src/main/java/com/jozufozu/flywheel/util/Mods.java index 27c0cb2f2..8ca9b6380 100644 --- a/src/main/java/com/jozufozu/flywheel/util/Mods.java +++ b/src/main/java/com/jozufozu/flywheel/util/Mods.java @@ -18,7 +18,7 @@ public enum Mods { } /** - * @return a boolean of whether the mod is loaded or not based on mod id + * @return a whether the mod is loaded or not based on mod id */ public boolean isLoaded() { return ModList.get().isLoaded(id); @@ -30,8 +30,10 @@ public enum Mods { * @return Optional.empty() if the mod is not loaded, otherwise an Optional of the return value of the given supplier */ public Optional runIfInstalled(Supplier> toRun) { - if (isLoaded()) - return Optional.of(toRun.get().get()); + if (isLoaded()) { + return Optional.of(toRun.get() + .get()); + } return Optional.empty(); } diff --git a/src/main/resources/flywheel.mixins.json b/src/main/resources/flywheel.mixins.json index e190d6a30..5bcbcf761 100644 --- a/src/main/resources/flywheel.mixins.json +++ b/src/main/resources/flywheel.mixins.json @@ -5,7 +5,6 @@ "compatibilityLevel": "JAVA_17", "refmap": "flywheel.refmap.json", "client": [ - "BlockEntityRenderDispatcherAccessor", "BlockEntityTypeMixin", "BufferBuilderMixin", "ChunkRebuildHooksMixin", From 7e5884916042eeae713c580cc9f955356e30a775 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Tue, 28 Mar 2023 16:20:01 -0700 Subject: [PATCH 9/9] No hacks here no sir - Ubershaders working on instancing - Just declare a uniform and fetch/set it right before we draw --- .../instancing/instancing/InstancingEngine.java | 10 ++++++++-- .../flywheel/pipeline/instanced_arrays_draw.vert | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) 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 42470d76b..c701611f0 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 @@ -17,6 +17,7 @@ import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler; +import com.jozufozu.flywheel.core.ComponentRegistry; import com.jozufozu.flywheel.core.Pipelines; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.core.context.SimpleContext; @@ -123,8 +124,13 @@ public class InstancingEngine implements Engine { var structType = desc.instance(); var material = desc.material(); - FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, context, Pipelines.INSTANCED_ARRAYS) - .bind(); + var program = FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, context, Pipelines.INSTANCED_ARRAYS); + program.bind(); + + var uniformLocation = program.getUniformLocation("_flw_materialID_instancing"); + var vertexID = ComponentRegistry.materials.getVertexID(material); + var fragmentID = ComponentRegistry.materials.getFragmentID(material); + GL32.glUniform2ui(uniformLocation, vertexID, fragmentID); } @Override diff --git a/src/main/resources/assets/flywheel/flywheel/pipeline/instanced_arrays_draw.vert b/src/main/resources/assets/flywheel/flywheel/pipeline/instanced_arrays_draw.vert index 47a939bf4..4e69ffbc7 100644 --- a/src/main/resources/assets/flywheel/flywheel/pipeline/instanced_arrays_draw.vert +++ b/src/main/resources/assets/flywheel/flywheel/pipeline/instanced_arrays_draw.vert @@ -1,7 +1,13 @@ #use "flywheel:api/vertex.glsl" +uniform uvec2 _flw_materialID_instancing; + void main() { flw_layoutVertex(); + + flw_materialVertexID = _flw_materialID_instancing.x; + flw_materialFragmentID = _flw_materialID_instancing.y; + FlwInstance i = flw_unpackInstance(); flw_instanceVertex(i); flw_materialVertex();