mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-13 15:56:07 +01:00
Building shade
- Use builder pattern for defining shader compiler flows - If only java had type inference extending to builders :whywheel: - Support glsl 330 on instancing again - Set uniform block binding at link time - Remove associated glsl builder code - Use explicit uint literals in material adapter switch cases - No need to enable GL_ARB_explicit_attrib_location
This commit is contained in:
parent
6e6779093a
commit
863958fb00
20 changed files with 276 additions and 256 deletions
|
@ -1,5 +1,7 @@
|
||||||
package com.jozufozu.flywheel.api.context;
|
package com.jozufozu.flywheel.api.context;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.registry.Registry;
|
import com.jozufozu.flywheel.api.registry.Registry;
|
||||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||||
import com.jozufozu.flywheel.impl.RegistryImpl;
|
import com.jozufozu.flywheel.impl.RegistryImpl;
|
||||||
|
@ -9,7 +11,7 @@ import net.minecraft.resources.ResourceLocation;
|
||||||
public interface Context {
|
public interface Context {
|
||||||
static Registry<Context> REGISTRY = RegistryImpl.create();
|
static Registry<Context> REGISTRY = RegistryImpl.create();
|
||||||
|
|
||||||
void onProgramLink(GlProgram program);
|
void onProgramLink(@NotNull GlProgram program);
|
||||||
|
|
||||||
ResourceLocation vertexShader();
|
ResourceLocation vertexShader();
|
||||||
|
|
||||||
|
|
|
@ -13,30 +13,29 @@ import com.jozufozu.flywheel.backend.compile.core.ShaderCompiler;
|
||||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||||
|
|
||||||
public abstract class AbstractCompiler<K> {
|
public class CompilationHarness<K> {
|
||||||
protected final SourceLoader sourceLoader;
|
private final KeyCompiler<K> compiler;
|
||||||
protected final ShaderCompiler shaderCompiler;
|
private final SourceLoader sourceLoader;
|
||||||
protected final ProgramLinker programLinker;
|
private final ShaderCompiler shaderCompiler;
|
||||||
|
private final ProgramLinker programLinker;
|
||||||
private final ImmutableList<K> keys;
|
private final ImmutableList<K> keys;
|
||||||
private final CompilerStats stats = new CompilerStats();
|
private final CompilerStats stats = new CompilerStats();
|
||||||
|
|
||||||
public AbstractCompiler(ShaderSources sources, ImmutableList<K> keys) {
|
public CompilationHarness(ShaderSources sources, ImmutableList<K> keys, KeyCompiler<K> compiler) {
|
||||||
this.keys = keys;
|
this.keys = keys;
|
||||||
|
|
||||||
|
this.compiler = compiler;
|
||||||
sourceLoader = new SourceLoader(sources, stats);
|
sourceLoader = new SourceLoader(sources, stats);
|
||||||
shaderCompiler = new ShaderCompiler(stats);
|
shaderCompiler = new ShaderCompiler(stats);
|
||||||
programLinker = new ProgramLinker(stats);
|
programLinker = new ProgramLinker(stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
protected abstract GlProgram compile(K key);
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Map<K, GlProgram> compileAndReportErrors() {
|
public Map<K, GlProgram> compileAndReportErrors() {
|
||||||
stats.start();
|
stats.start();
|
||||||
Map<K, GlProgram> out = new HashMap<>();
|
Map<K, GlProgram> out = new HashMap<>();
|
||||||
for (var key : keys) {
|
for (var key : keys) {
|
||||||
GlProgram glProgram = compile(key);
|
GlProgram glProgram = compiler.compile(key, sourceLoader, shaderCompiler, programLinker);
|
||||||
if (out != null && glProgram != null) {
|
if (out != null && glProgram != null) {
|
||||||
out.put(key, glProgram);
|
out.put(key, glProgram);
|
||||||
} else {
|
} else {
|
||||||
|
@ -56,4 +55,8 @@ public abstract class AbstractCompiler<K> {
|
||||||
public void delete() {
|
public void delete() {
|
||||||
shaderCompiler.delete();
|
shaderCompiler.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface KeyCompiler<K> {
|
||||||
|
@Nullable GlProgram compile(K key, SourceLoader loader, ShaderCompiler shaderCompiler, ProgramLinker programLinker);
|
||||||
|
}
|
||||||
}
|
}
|
132
src/main/java/com/jozufozu/flywheel/backend/compile/Compile.java
Normal file
132
src/main/java/com/jozufozu/flywheel/backend/compile/Compile.java
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
package com.jozufozu.flywheel.backend.compile;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.compile.core.ProgramLinker;
|
||||||
|
import com.jozufozu.flywheel.backend.compile.core.ShaderCompiler;
|
||||||
|
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||||
|
import com.jozufozu.flywheel.gl.shader.GlShader;
|
||||||
|
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
||||||
|
import com.jozufozu.flywheel.glsl.GLSLVersion;
|
||||||
|
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||||
|
import com.jozufozu.flywheel.util.NotNullFunction;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public class Compile {
|
||||||
|
public static <K> ShaderCompilerBuilder<K> shader(GLSLVersion glslVersion, ShaderType shaderType) {
|
||||||
|
return new ShaderCompilerBuilder<>(glslVersion, shaderType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K> ProgramLinkBuilder<K> program() {
|
||||||
|
return new ProgramLinkBuilder<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ProgramLinkBuilder<K> implements CompilationHarness.KeyCompiler<K> {
|
||||||
|
private final Map<ShaderType, ShaderCompilerBuilder<K>> compilers = new EnumMap<>(ShaderType.class);
|
||||||
|
private BiConsumer<K, GlProgram> onLink = (k, p) -> {
|
||||||
|
};
|
||||||
|
|
||||||
|
public ProgramLinkBuilder<K> link(ShaderCompilerBuilder<K> compilerBuilder) {
|
||||||
|
if (compilers.containsKey(compilerBuilder.shaderType)) {
|
||||||
|
throw new IllegalArgumentException("Duplicate shader type: " + compilerBuilder.shaderType);
|
||||||
|
}
|
||||||
|
compilers.put(compilerBuilder.shaderType, compilerBuilder);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgramLinkBuilder<K> then(BiConsumer<K, GlProgram> onLink) {
|
||||||
|
this.onLink = onLink;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public GlProgram compile(K key, SourceLoader loader, ShaderCompiler shaderCompiler, ProgramLinker programLinker) {
|
||||||
|
if (compilers.isEmpty()) {
|
||||||
|
throw new IllegalStateException("No shader compilers were added!");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GlShader> shaders = new ArrayList<>();
|
||||||
|
|
||||||
|
boolean ok = true;
|
||||||
|
for (ShaderCompilerBuilder<K> compiler : compilers.values()) {
|
||||||
|
var shader = compiler.compile(key, shaderCompiler, loader);
|
||||||
|
if (shader == null) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
shaders.add(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var out = programLinker.link(shaders);
|
||||||
|
|
||||||
|
if (out != null) {
|
||||||
|
onLink.accept(key, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ShaderCompilerBuilder<K> {
|
||||||
|
private final GLSLVersion glslVersion;
|
||||||
|
private final ShaderType shaderType;
|
||||||
|
private final List<BiFunction<K, SourceLoader, SourceComponent>> fetchers = new ArrayList<>();
|
||||||
|
|
||||||
|
public ShaderCompilerBuilder(GLSLVersion glslVersion, ShaderType shaderType) {
|
||||||
|
this.glslVersion = glslVersion;
|
||||||
|
this.shaderType = shaderType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompilerBuilder<K> with(BiFunction<K, SourceLoader, SourceComponent> fetch) {
|
||||||
|
fetchers.add(fetch);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompilerBuilder<K> withComponent(SourceComponent component) {
|
||||||
|
return withComponent($ -> component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompilerBuilder<K> withComponent(NotNullFunction<K, SourceComponent> sourceFetcher) {
|
||||||
|
return with((key, $) -> sourceFetcher.apply(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompilerBuilder<K> withResource(NotNullFunction<K, ResourceLocation> sourceFetcher) {
|
||||||
|
return with((key, loader) -> loader.find(sourceFetcher.apply(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompilerBuilder<K> withResource(ResourceLocation resourceLocation) {
|
||||||
|
return withResource($ -> resourceLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private GlShader compile(K key, ShaderCompiler compiler, SourceLoader loader) {
|
||||||
|
var components = new ArrayList<SourceComponent>();
|
||||||
|
boolean ok = true;
|
||||||
|
for (var fetcher : fetchers) {
|
||||||
|
SourceComponent apply = fetcher.apply(key, loader);
|
||||||
|
if (apply == null) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
components.add(apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return compiler.compile(glslVersion, shaderType, components);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,59 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend.compile;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
|
||||||
import com.jozufozu.flywheel.backend.compile.component.IndirectComponent;
|
|
||||||
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
|
||||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
|
||||||
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
|
||||||
import com.jozufozu.flywheel.glsl.GLSLVersion;
|
|
||||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
|
||||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
|
|
||||||
public class CullingCompiler extends AbstractCompiler<InstanceType<?>> {
|
|
||||||
private final UniformComponent uniformComponent;
|
|
||||||
private final SourceFile pipelineCompute;
|
|
||||||
|
|
||||||
public static CullingCompiler create(SourceLoader sourceLoader, ImmutableList<InstanceType<?>> keys, UniformComponent uniformComponent) {
|
|
||||||
var sourceFile = sourceLoader.find(Files.INDIRECT_CULL);
|
|
||||||
|
|
||||||
return new CullingCompiler(sourceLoader.sources, keys, uniformComponent, sourceFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CullingCompiler(ShaderSources sources, ImmutableList<InstanceType<?>> keys, UniformComponent uniformComponent, SourceFile pipeline) {
|
|
||||||
super(sources, keys);
|
|
||||||
|
|
||||||
this.uniformComponent = uniformComponent;
|
|
||||||
this.pipelineCompute = pipeline;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
protected GlProgram compile(InstanceType<?> key) {
|
|
||||||
var instanceAssembly = IndirectComponent.create(key);
|
|
||||||
ResourceLocation rl = key.instanceShader();
|
|
||||||
var instance = sourceLoader.find(rl);
|
|
||||||
|
|
||||||
if (instance == null || uniformComponent == null || pipelineCompute == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var computeComponents = ImmutableList.of(uniformComponent, instanceAssembly, instance, pipelineCompute);
|
|
||||||
var compute = shaderCompiler.compile(GLSLVersion.V460, ShaderType.COMPUTE, computeComponents);
|
|
||||||
|
|
||||||
if (compute == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return programLinker.link(compute);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class Files {
|
|
||||||
public static final ResourceLocation INDIRECT_CULL = Flywheel.rl("internal/indirect_cull.glsl");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -31,8 +31,8 @@ public class FlwPrograms {
|
||||||
var vertexMaterialComponent = createVertexMaterialComponent(loadChecker);
|
var vertexMaterialComponent = createVertexMaterialComponent(loadChecker);
|
||||||
var fragmentMaterialComponent = createFragmentMaterialComponent(loadChecker);
|
var fragmentMaterialComponent = createFragmentMaterialComponent(loadChecker);
|
||||||
|
|
||||||
InstancingPrograms.reload(loadChecker, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
InstancingPrograms.reload(sources, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||||
IndirectPrograms.reload(loadChecker, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
IndirectPrograms.reload(sources, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||||
|
|
||||||
if (preLoadStats.errored()) {
|
if (preLoadStats.errored()) {
|
||||||
Flywheel.LOGGER.error(preLoadStats.generateErrorLog());
|
Flywheel.LOGGER.error(preLoadStats.generateErrorLog());
|
||||||
|
@ -47,7 +47,7 @@ public class FlwPrograms {
|
||||||
.returnType("bool")
|
.returnType("bool")
|
||||||
.name("flw_discardPredicate")
|
.name("flw_discardPredicate")
|
||||||
.arg("vec4", "color")
|
.arg("vec4", "color")
|
||||||
.build(), GlslExpr.literal(false))
|
.build(), GlslExpr.boolLiteral(false))
|
||||||
.adapt(FnSignature.create()
|
.adapt(FnSignature.create()
|
||||||
.returnType("vec4")
|
.returnType("vec4")
|
||||||
.name("flw_fogFilter")
|
.name("flw_fogFilter")
|
||||||
|
|
|
@ -9,9 +9,15 @@ import com.jozufozu.flywheel.Flywheel;
|
||||||
import com.jozufozu.flywheel.api.context.Context;
|
import com.jozufozu.flywheel.api.context.Context;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||||
|
import com.jozufozu.flywheel.backend.compile.component.IndirectComponent;
|
||||||
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
|
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
|
||||||
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
||||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||||
|
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
||||||
|
import com.jozufozu.flywheel.glsl.GLSLVersion;
|
||||||
|
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
public class IndirectPrograms {
|
public class IndirectPrograms {
|
||||||
public static IndirectPrograms instance;
|
public static IndirectPrograms instance;
|
||||||
|
@ -23,10 +29,10 @@ public class IndirectPrograms {
|
||||||
this.culling = culling;
|
this.culling = culling;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reload(SourceLoader loadChecker, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
||||||
_delete();
|
_delete();
|
||||||
var pipelineCompiler = PipelineCompiler.create(loadChecker, Pipelines.INDIRECT, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||||
var cullingCompiler = CullingCompiler.create(loadChecker, createCullingKeys(), uniformComponent);
|
var cullingCompiler = createCullingCompiler(uniformComponent, sources);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var pipelineResult = pipelineCompiler.compileAndReportErrors();
|
var pipelineResult = pipelineCompiler.compileAndReportErrors();
|
||||||
|
@ -66,6 +72,18 @@ public class IndirectPrograms {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static CompilationHarness<InstanceType<?>> createCullingCompiler(UniformComponent uniformComponent, ShaderSources sources) {
|
||||||
|
return new CompilationHarness<>(sources, createCullingKeys(), Compile.<InstanceType<?>>program()
|
||||||
|
.link(Compile.<InstanceType<?>>shader(GLSLVersion.V460, ShaderType.COMPUTE)
|
||||||
|
.withComponent(uniformComponent)
|
||||||
|
.withComponent(IndirectComponent::create)
|
||||||
|
.withResource(InstanceType::instanceShader)
|
||||||
|
.withResource(Files.INDIRECT_CULL))
|
||||||
|
.then((InstanceType<?> key, GlProgram program) -> {
|
||||||
|
program.setUniformBlockBinding("FLWUniforms", 0);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
public GlProgram getIndirectProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) {
|
public GlProgram getIndirectProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) {
|
||||||
return pipeline.get(new PipelineProgramKey(vertexType, instanceType, contextShader));
|
return pipeline.get(new PipelineProgramKey(vertexType, instanceType, contextShader));
|
||||||
}
|
}
|
||||||
|
@ -80,4 +98,8 @@ public class IndirectPrograms {
|
||||||
culling.values()
|
culling.values()
|
||||||
.forEach(GlProgram::delete);
|
.forEach(GlProgram::delete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class Files {
|
||||||
|
public static final ResourceLocation INDIRECT_CULL = Flywheel.rl("internal/indirect_cull.glsl");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
|
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
|
||||||
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
||||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||||
|
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||||
|
|
||||||
public class InstancingPrograms {
|
public class InstancingPrograms {
|
||||||
static InstancingPrograms instance;
|
static InstancingPrograms instance;
|
||||||
|
@ -21,9 +22,9 @@ public class InstancingPrograms {
|
||||||
this.pipeline = pipeline;
|
this.pipeline = pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reload(SourceLoader loadChecker, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
||||||
_delete();
|
_delete();
|
||||||
var instancingCompiler = PipelineCompiler.create(loadChecker, Pipelines.INSTANCED_ARRAYS, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
var instancingCompiler = PipelineCompiler.create(sources, Pipelines.INSTANCED_ARRAYS, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var result = instancingCompiler.compileAndReportErrors();
|
var result = instancingCompiler.compileAndReportErrors();
|
||||||
|
|
|
@ -1,158 +1,37 @@
|
||||||
package com.jozufozu.flywheel.backend.compile;
|
package com.jozufozu.flywheel.backend.compile;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
|
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
|
||||||
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
||||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||||
import com.jozufozu.flywheel.gl.shader.GlShader;
|
|
||||||
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
||||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
public class PipelineCompiler {
|
||||||
|
static CompilationHarness<PipelineProgramKey> create(ShaderSources sources, Pipeline pipeline, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
||||||
public class PipelineCompiler extends AbstractCompiler<PipelineProgramKey> {
|
return new CompilationHarness<>(sources, pipelineKeys, Compile.<PipelineProgramKey>program()
|
||||||
private final Pipeline pipeline;
|
.link(Compile.<PipelineProgramKey>shader(pipeline.glslVersion(), ShaderType.VERTEX)
|
||||||
private final List<SourceComponent> vertexPrelude = new ArrayList<>();
|
.withComponent(uniformComponent)
|
||||||
private final List<SourceComponent> vertexPostlude = new ArrayList<>();
|
.withComponent(vertexMaterialComponent)
|
||||||
private final List<SourceComponent> fragmentPrelude = new ArrayList<>();
|
.withComponent(key -> pipeline.assembler()
|
||||||
private final List<SourceComponent> fragmentPostlude = new ArrayList<>();
|
.assemble(new Pipeline.InstanceAssemblerContext(key.vertexType(), key.instanceType())))
|
||||||
|
.withResource(key -> key.vertexType()
|
||||||
public PipelineCompiler(ShaderSources sources, ImmutableList<PipelineProgramKey> keys, Pipeline pipeline) {
|
.layoutShader())
|
||||||
super(sources, keys);
|
.withResource(key -> key.instanceType()
|
||||||
this.pipeline = pipeline;
|
.instanceShader())
|
||||||
}
|
.withResource(key -> key.contextShader()
|
||||||
|
.vertexShader())
|
||||||
static PipelineCompiler create(SourceLoader sourceLoader, Pipeline pipeline, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
.withResource(pipeline.vertexShader()))
|
||||||
var fragmentPipeline = sourceLoader.find(pipeline.fragmentShader());
|
.link(Compile.<PipelineProgramKey>shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
|
||||||
var vertexPipeline = sourceLoader.find(pipeline.vertexShader());
|
.withComponent(uniformComponent)
|
||||||
|
.withComponent(fragmentMaterialComponent)
|
||||||
return new PipelineCompiler(sourceLoader.sources, pipelineKeys, pipeline).addPrelude(uniformComponent)
|
.withResource(key -> key.contextShader()
|
||||||
.addFragmentPrelude(fragmentMaterialComponent)
|
.fragmentShader())
|
||||||
.addVertexPrelude(vertexMaterialComponent)
|
.withResource(pipeline.fragmentShader()))
|
||||||
.addFragmentPostlude(fragmentPipeline)
|
.then((PipelineProgramKey key, GlProgram program) -> {
|
||||||
.addVertexPostlude(vertexPipeline);
|
key.contextShader()
|
||||||
}
|
.onProgramLink(program);
|
||||||
|
program.setUniformBlockBinding("FLWUniforms", 0);
|
||||||
public PipelineCompiler addPrelude(SourceComponent component) {
|
}));
|
||||||
addVertexPrelude(component);
|
|
||||||
addFragmentPrelude(component);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PipelineCompiler addVertexPrelude(SourceComponent component) {
|
|
||||||
vertexPrelude.add(component);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PipelineCompiler addVertexPostlude(SourceComponent component) {
|
|
||||||
vertexPostlude.add(component);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PipelineCompiler addFragmentPrelude(SourceComponent component) {
|
|
||||||
fragmentPrelude.add(component);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PipelineCompiler addFragmentPostlude(SourceComponent component) {
|
|
||||||
fragmentPostlude.add(component);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
protected GlProgram compile(PipelineProgramKey key) {
|
|
||||||
GlShader vertex = compileVertex(key);
|
|
||||||
GlShader fragment = compileFragment(key);
|
|
||||||
|
|
||||||
if (vertex == null || fragment == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var glProgram = programLinker.link(vertex, fragment);
|
|
||||||
key.contextShader()
|
|
||||||
.onProgramLink(glProgram);
|
|
||||||
return glProgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private GlShader compileVertex(PipelineProgramKey key) {
|
|
||||||
var vertexComponents = getVertexComponents(key);
|
|
||||||
if (vertexComponents == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return shaderCompiler.compile(pipeline.glslVersion(), ShaderType.VERTEX, vertexComponents);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private GlShader compileFragment(PipelineProgramKey key) {
|
|
||||||
var fragmentComponents = getFragmentComponents(key);
|
|
||||||
if (fragmentComponents == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return shaderCompiler.compile(pipeline.glslVersion(), ShaderType.FRAGMENT, fragmentComponents);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private List<SourceComponent> getVertexComponents(PipelineProgramKey key) {
|
|
||||||
var instanceAssembly = pipeline.assembler()
|
|
||||||
.assemble(new Pipeline.InstanceAssemblerContext(key.vertexType(), key.instanceType()));
|
|
||||||
|
|
||||||
var layout = sourceLoader.find(key.vertexType()
|
|
||||||
.layoutShader());
|
|
||||||
var instance = sourceLoader.find(key.instanceType()
|
|
||||||
.instanceShader());
|
|
||||||
var context = sourceLoader.find(key.contextShader()
|
|
||||||
.vertexShader());
|
|
||||||
|
|
||||||
if (instanceAssembly == null || layout == null || instance == null || context == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check this here to do a full dry-run in case of a preloading error.
|
|
||||||
if (vertexPrelude.stream()
|
|
||||||
.anyMatch(Objects::isNull) || vertexPostlude.stream()
|
|
||||||
.anyMatch(Objects::isNull)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ImmutableList.<SourceComponent>builder()
|
|
||||||
.addAll(vertexPrelude)
|
|
||||||
.add(instanceAssembly, layout, instance, context)
|
|
||||||
.addAll(vertexPostlude)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private List<SourceComponent> getFragmentComponents(PipelineProgramKey key) {
|
|
||||||
ResourceLocation rl = key.contextShader()
|
|
||||||
.fragmentShader();
|
|
||||||
var context = sourceLoader.find(rl);
|
|
||||||
|
|
||||||
if (context == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check this here to do a full dry-run in case of a preloading error.
|
|
||||||
if (fragmentPrelude.stream()
|
|
||||||
.anyMatch(Objects::isNull) || fragmentPostlude.stream()
|
|
||||||
.anyMatch(Objects::isNull)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ImmutableList.<SourceComponent>builder()
|
|
||||||
.addAll(fragmentPrelude)
|
|
||||||
.add(context)
|
|
||||||
.addAll(fragmentPostlude)
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
public final class Pipelines {
|
public final class Pipelines {
|
||||||
public static final Pipeline INSTANCED_ARRAYS = Pipeline.builder()
|
public static final Pipeline INSTANCED_ARRAYS = Pipeline.builder()
|
||||||
.glslVersion(GLSLVersion.V420)
|
.glslVersion(GLSLVersion.V330)
|
||||||
.vertex(Files.INSTANCED_ARRAYS_DRAW)
|
.vertex(Files.INSTANCED_ARRAYS_DRAW)
|
||||||
.fragment(Files.DRAW_FRAGMENT)
|
.fragment(Files.DRAW_FRAGMENT)
|
||||||
.assembler(InstancedArraysComponent::new)
|
.assembler(InstancedArraysComponent::new)
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class MaterialAdapterComponent implements SourceComponent {
|
||||||
block.ret(adaptedCall);
|
block.ret(adaptedCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.intCase(i, block);
|
sw.uintCase(i, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isVoid) {
|
if (!isVoid) {
|
||||||
|
|
|
@ -36,7 +36,6 @@ public class UniformComponent implements SourceComponent {
|
||||||
|
|
||||||
builder.uniformBlock()
|
builder.uniformBlock()
|
||||||
.layout("std140")
|
.layout("std140")
|
||||||
.binding(0)
|
|
||||||
.name("FLWUniforms")
|
.name("FLWUniforms")
|
||||||
.member("flywheel_uniforms", "flywheel");
|
.member("flywheel_uniforms", "flywheel");
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
|
||||||
import static org.lwjgl.opengl.GL20.glGetProgrami;
|
import static org.lwjgl.opengl.GL20.glGetProgrami;
|
||||||
import static org.lwjgl.opengl.GL20.glLinkProgram;
|
import static org.lwjgl.opengl.GL20.glLinkProgram;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||||
|
@ -21,14 +23,14 @@ public class ProgramLinker {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public GlProgram link(GlShader... shaders) {
|
public GlProgram link(List<GlShader> shaders) {
|
||||||
// this probably doesn't need caching
|
// this probably doesn't need caching
|
||||||
var linkResult = linkInternal(shaders);
|
var linkResult = linkInternal(shaders);
|
||||||
stats.linkResult(linkResult);
|
stats.linkResult(linkResult);
|
||||||
return linkResult.unwrap();
|
return linkResult.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinkResult linkInternal(GlShader... shaders) {
|
private LinkResult linkInternal(List<GlShader> shaders) {
|
||||||
int handle = glCreateProgram();
|
int handle = glCreateProgram();
|
||||||
|
|
||||||
for (GlShader shader : shaders) {
|
for (GlShader shader : shaders) {
|
||||||
|
|
|
@ -32,7 +32,6 @@ public class ShaderCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
Compilation ctx = new Compilation(glslVersion, shaderType);
|
Compilation ctx = new Compilation(glslVersion, shaderType);
|
||||||
ctx.enableExtension("GL_ARB_explicit_attrib_location");
|
|
||||||
ctx.enableExtension("GL_ARB_conservative_depth");
|
ctx.enableExtension("GL_ARB_conservative_depth");
|
||||||
|
|
||||||
expand(sourceComponents, ctx::appendComponent);
|
expand(sourceComponents, ctx::appendComponent);
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault
|
||||||
|
package com.jozufozu.flywheel.backend.compile;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
|
@ -1,8 +1,11 @@
|
||||||
package com.jozufozu.flywheel.gl.shader;
|
package com.jozufozu.flywheel.gl.shader;
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL20.glDeleteProgram;
|
import static org.lwjgl.opengl.GL31.GL_INVALID_INDEX;
|
||||||
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
import static org.lwjgl.opengl.GL31.glGetUniformBlockIndex;
|
||||||
import static org.lwjgl.opengl.GL20.glUniform1i;
|
import static org.lwjgl.opengl.GL31.glUniformBlockBinding;
|
||||||
|
import static org.lwjgl.opengl.GL32.glDeleteProgram;
|
||||||
|
import static org.lwjgl.opengl.GL32.glGetUniformLocation;
|
||||||
|
import static org.lwjgl.opengl.GL32.glUniform1i;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
@ -55,6 +58,17 @@ public class GlProgram extends GlObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUniformBlockBinding(String name, int binding) {
|
||||||
|
int index = glGetUniformBlockIndex(handle(), name);
|
||||||
|
|
||||||
|
if (index == GL_INVALID_INDEX) {
|
||||||
|
LOGGER.debug("No active uniform block '{}' exists. Could be unused.", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
glUniformBlockBinding(handle(), index, binding);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deleteInternal(int handle) {
|
protected void deleteInternal(int handle) {
|
||||||
glDeleteProgram(handle);
|
glDeleteProgram(handle);
|
||||||
|
|
|
@ -31,11 +31,15 @@ public interface GlslExpr {
|
||||||
return new FunctionCall0(functionName);
|
return new FunctionCall0(functionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GlslExpr literal(int expr) {
|
static GlslExpr intLiteral(int expr) {
|
||||||
return new IntLiteral(expr);
|
return new IntLiteral(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GlslExpr literal(boolean expr) {
|
static GlslExpr uintLiteral(int expr) {
|
||||||
|
return new UIntLiteral(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GlslExpr boolLiteral(boolean expr) {
|
||||||
return new BoolLiteral(expr);
|
return new BoolLiteral(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +139,19 @@ public interface GlslExpr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record UIntLiteral(int value) implements GlslExpr {
|
||||||
|
public UIntLiteral {
|
||||||
|
if (value < 0) {
|
||||||
|
throw new IllegalArgumentException("UIntLiteral must be positive");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String prettyPrint() {
|
||||||
|
return Integer.toString(value) + 'u';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
record BoolLiteral(boolean value) implements GlslExpr {
|
record BoolLiteral(boolean value) implements GlslExpr {
|
||||||
@Override
|
@Override
|
||||||
public String prettyPrint() {
|
public String prettyPrint() {
|
||||||
|
|
|
@ -25,7 +25,11 @@ public class GlslSwitch implements GlslStmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void intCase(int expr, GlslBlock block) {
|
public void intCase(int expr, GlslBlock block) {
|
||||||
cases.add(Pair.of(GlslExpr.literal(expr), block));
|
cases.add(Pair.of(GlslExpr.intLiteral(expr), block));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void uintCase(int expr, GlslBlock block) {
|
||||||
|
cases.add(Pair.of(GlslExpr.uintLiteral(expr), block));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defaultCase(GlslBlock block) {
|
public void defaultCase(GlslBlock block) {
|
||||||
|
@ -35,7 +39,7 @@ public class GlslSwitch implements GlslStmt {
|
||||||
@Override
|
@Override
|
||||||
public String prettyPrint() {
|
public String prettyPrint() {
|
||||||
return """
|
return """
|
||||||
switch (%s) {
|
switch (%s) {
|
||||||
%s
|
%s
|
||||||
}""".formatted(on.prettyPrint(), formatCases());
|
}""".formatted(on.prettyPrint(), formatCases());
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,19 +8,16 @@ import com.jozufozu.flywheel.util.Pair;
|
||||||
import com.jozufozu.flywheel.util.StringUtil;
|
import com.jozufozu.flywheel.util.StringUtil;
|
||||||
|
|
||||||
public class GlslUniformBlock implements GlslBuilder.Declaration {
|
public class GlslUniformBlock implements GlslBuilder.Declaration {
|
||||||
|
|
||||||
|
|
||||||
private String qualifier;
|
private String qualifier;
|
||||||
private int binding;
|
private String name;
|
||||||
private String name;
|
private final List<Pair<String, String>> members = new ArrayList<>();
|
||||||
private final List<Pair<String, String>> members = new ArrayList<>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String prettyPrint() {
|
public String prettyPrint() {
|
||||||
return """
|
return """
|
||||||
layout(%s, binding = %d) uniform %s {
|
layout(%s) uniform %s {
|
||||||
%s
|
%s
|
||||||
};""".formatted(qualifier, binding, name, StringUtil.indent(formatMembers(), 4));
|
};""".formatted(qualifier, name, StringUtil.indent(formatMembers(), 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatMembers() {
|
private String formatMembers() {
|
||||||
|
@ -34,15 +31,10 @@ public class GlslUniformBlock implements GlslBuilder.Declaration {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlslUniformBlock binding(int i) {
|
public GlslUniformBlock name(String name) {
|
||||||
binding = i;
|
this.name = name;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlslUniformBlock name(String name) {
|
|
||||||
this.name = name;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GlslUniformBlock member(String typeName, String variableName) {
|
public GlslUniformBlock member(String typeName, String variableName) {
|
||||||
members.add(Pair.of(typeName, variableName));
|
members.add(Pair.of(typeName, variableName));
|
||||||
|
|
|
@ -4,7 +4,6 @@ import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface NonNullSupplier<T> {
|
public interface NonNullSupplier<T> {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
T get();
|
T get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.jozufozu.flywheel.util;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface NotNullFunction<T, R> {
|
||||||
|
@NotNull R apply(T t);
|
||||||
|
}
|
Loading…
Reference in a new issue