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);