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:
Jozufozu 2023-05-18 00:03:53 -07:00
parent 6e6779093a
commit 863958fb00
20 changed files with 276 additions and 256 deletions

View file

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

View file

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

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

View file

@ -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");
}
}

View file

@ -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")

View file

@ -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");
}
} }

View file

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

View file

@ -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();
} }
} }

View file

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

View file

@ -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) {

View file

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

View file

@ -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) {

View file

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

View file

@ -0,0 +1,6 @@
@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault
package com.jozufozu.flywheel.backend.compile;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;

View file

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

View file

@ -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() {

View file

@ -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());
} }

View file

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

View file

@ -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();
} }

View file

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