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; +};