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;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.api.registry.Registry;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.impl.RegistryImpl;
|
||||
|
@ -9,7 +11,7 @@ import net.minecraft.resources.ResourceLocation;
|
|||
public interface Context {
|
||||
static Registry<Context> REGISTRY = RegistryImpl.create();
|
||||
|
||||
void onProgramLink(GlProgram program);
|
||||
void onProgramLink(@NotNull GlProgram program);
|
||||
|
||||
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.glsl.ShaderSources;
|
||||
|
||||
public abstract class AbstractCompiler<K> {
|
||||
protected final SourceLoader sourceLoader;
|
||||
protected final ShaderCompiler shaderCompiler;
|
||||
protected final ProgramLinker programLinker;
|
||||
public class CompilationHarness<K> {
|
||||
private final KeyCompiler<K> compiler;
|
||||
private final SourceLoader sourceLoader;
|
||||
private final ShaderCompiler shaderCompiler;
|
||||
private final ProgramLinker programLinker;
|
||||
private final ImmutableList<K> keys;
|
||||
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.compiler = compiler;
|
||||
sourceLoader = new SourceLoader(sources, stats);
|
||||
shaderCompiler = new ShaderCompiler(stats);
|
||||
programLinker = new ProgramLinker(stats);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract GlProgram compile(K key);
|
||||
|
||||
@Nullable
|
||||
public Map<K, GlProgram> compileAndReportErrors() {
|
||||
stats.start();
|
||||
Map<K, GlProgram> out = new HashMap<>();
|
||||
for (var key : keys) {
|
||||
GlProgram glProgram = compile(key);
|
||||
GlProgram glProgram = compiler.compile(key, sourceLoader, shaderCompiler, programLinker);
|
||||
if (out != null && glProgram != null) {
|
||||
out.put(key, glProgram);
|
||||
} else {
|
||||
|
@ -56,4 +55,8 @@ public abstract class AbstractCompiler<K> {
|
|||
public void 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 fragmentMaterialComponent = createFragmentMaterialComponent(loadChecker);
|
||||
|
||||
InstancingPrograms.reload(loadChecker, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
IndirectPrograms.reload(loadChecker, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
InstancingPrograms.reload(sources, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
IndirectPrograms.reload(sources, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
|
||||
if (preLoadStats.errored()) {
|
||||
Flywheel.LOGGER.error(preLoadStats.generateErrorLog());
|
||||
|
@ -47,7 +47,7 @@ public class FlwPrograms {
|
|||
.returnType("bool")
|
||||
.name("flw_discardPredicate")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.literal(false))
|
||||
.build(), GlslExpr.boolLiteral(false))
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("vec4")
|
||||
.name("flw_fogFilter")
|
||||
|
|
|
@ -9,9 +9,15 @@ import com.jozufozu.flywheel.Flywheel;
|
|||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
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.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 net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class IndirectPrograms {
|
||||
public static IndirectPrograms instance;
|
||||
|
@ -23,10 +29,10 @@ public class IndirectPrograms {
|
|||
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();
|
||||
var pipelineCompiler = PipelineCompiler.create(loadChecker, Pipelines.INDIRECT, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
var cullingCompiler = CullingCompiler.create(loadChecker, createCullingKeys(), uniformComponent);
|
||||
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
var cullingCompiler = createCullingCompiler(uniformComponent, sources);
|
||||
|
||||
try {
|
||||
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) {
|
||||
return pipeline.get(new PipelineProgramKey(vertexType, instanceType, contextShader));
|
||||
}
|
||||
|
@ -80,4 +98,8 @@ public class IndirectPrograms {
|
|||
culling.values()
|
||||
.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.UniformComponent;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
|
||||
public class InstancingPrograms {
|
||||
static InstancingPrograms instance;
|
||||
|
@ -21,9 +22,9 @@ public class InstancingPrograms {
|
|||
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();
|
||||
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 {
|
||||
var result = instancingCompiler.compileAndReportErrors();
|
||||
|
|
|
@ -1,158 +1,37 @@
|
|||
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.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
||||
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.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class PipelineCompiler extends AbstractCompiler<PipelineProgramKey> {
|
||||
private final Pipeline pipeline;
|
||||
private final List<SourceComponent> vertexPrelude = new ArrayList<>();
|
||||
private final List<SourceComponent> vertexPostlude = new ArrayList<>();
|
||||
private final List<SourceComponent> fragmentPrelude = new ArrayList<>();
|
||||
private final List<SourceComponent> fragmentPostlude = new ArrayList<>();
|
||||
|
||||
public PipelineCompiler(ShaderSources sources, ImmutableList<PipelineProgramKey> keys, Pipeline pipeline) {
|
||||
super(sources, keys);
|
||||
this.pipeline = pipeline;
|
||||
}
|
||||
|
||||
static PipelineCompiler create(SourceLoader sourceLoader, Pipeline pipeline, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
||||
var fragmentPipeline = sourceLoader.find(pipeline.fragmentShader());
|
||||
var vertexPipeline = sourceLoader.find(pipeline.vertexShader());
|
||||
|
||||
return new PipelineCompiler(sourceLoader.sources, pipelineKeys, pipeline).addPrelude(uniformComponent)
|
||||
.addFragmentPrelude(fragmentMaterialComponent)
|
||||
.addVertexPrelude(vertexMaterialComponent)
|
||||
.addFragmentPostlude(fragmentPipeline)
|
||||
.addVertexPostlude(vertexPipeline);
|
||||
}
|
||||
|
||||
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();
|
||||
public class PipelineCompiler {
|
||||
static CompilationHarness<PipelineProgramKey> create(ShaderSources sources, Pipeline pipeline, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
||||
return new CompilationHarness<>(sources, pipelineKeys, Compile.<PipelineProgramKey>program()
|
||||
.link(Compile.<PipelineProgramKey>shader(pipeline.glslVersion(), ShaderType.VERTEX)
|
||||
.withComponent(uniformComponent)
|
||||
.withComponent(vertexMaterialComponent)
|
||||
.withComponent(key -> pipeline.assembler()
|
||||
.assemble(new Pipeline.InstanceAssemblerContext(key.vertexType(), key.instanceType())))
|
||||
.withResource(key -> key.vertexType()
|
||||
.layoutShader())
|
||||
.withResource(key -> key.instanceType()
|
||||
.instanceShader())
|
||||
.withResource(key -> key.contextShader()
|
||||
.vertexShader())
|
||||
.withResource(pipeline.vertexShader()))
|
||||
.link(Compile.<PipelineProgramKey>shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
|
||||
.withComponent(uniformComponent)
|
||||
.withComponent(fragmentMaterialComponent)
|
||||
.withResource(key -> key.contextShader()
|
||||
.fragmentShader())
|
||||
.withResource(pipeline.fragmentShader()))
|
||||
.then((PipelineProgramKey key, GlProgram program) -> {
|
||||
key.contextShader()
|
||||
.onProgramLink(program);
|
||||
program.setUniformBlockBinding("FLWUniforms", 0);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import net.minecraft.resources.ResourceLocation;
|
|||
|
||||
public final class Pipelines {
|
||||
public static final Pipeline INSTANCED_ARRAYS = Pipeline.builder()
|
||||
.glslVersion(GLSLVersion.V420)
|
||||
.glslVersion(GLSLVersion.V330)
|
||||
.vertex(Files.INSTANCED_ARRAYS_DRAW)
|
||||
.fragment(Files.DRAW_FRAGMENT)
|
||||
.assembler(InstancedArraysComponent::new)
|
||||
|
|
|
@ -87,7 +87,7 @@ public class MaterialAdapterComponent implements SourceComponent {
|
|||
block.ret(adaptedCall);
|
||||
}
|
||||
|
||||
sw.intCase(i, block);
|
||||
sw.uintCase(i, block);
|
||||
}
|
||||
|
||||
if (!isVoid) {
|
||||
|
|
|
@ -36,7 +36,6 @@ public class UniformComponent implements SourceComponent {
|
|||
|
||||
builder.uniformBlock()
|
||||
.layout("std140")
|
||||
.binding(0)
|
||||
.name("FLWUniforms")
|
||||
.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.glLinkProgram;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
|
@ -21,14 +23,14 @@ public class ProgramLinker {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public GlProgram link(GlShader... shaders) {
|
||||
public GlProgram link(List<GlShader> shaders) {
|
||||
// this probably doesn't need caching
|
||||
var linkResult = linkInternal(shaders);
|
||||
stats.linkResult(linkResult);
|
||||
return linkResult.unwrap();
|
||||
}
|
||||
|
||||
private LinkResult linkInternal(GlShader... shaders) {
|
||||
private LinkResult linkInternal(List<GlShader> shaders) {
|
||||
int handle = glCreateProgram();
|
||||
|
||||
for (GlShader shader : shaders) {
|
||||
|
|
|
@ -32,7 +32,6 @@ public class ShaderCompiler {
|
|||
}
|
||||
|
||||
Compilation ctx = new Compilation(glslVersion, shaderType);
|
||||
ctx.enableExtension("GL_ARB_explicit_attrib_location");
|
||||
ctx.enableExtension("GL_ARB_conservative_depth");
|
||||
|
||||
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;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.glDeleteProgram;
|
||||
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||
import static org.lwjgl.opengl.GL20.glUniform1i;
|
||||
import static org.lwjgl.opengl.GL31.GL_INVALID_INDEX;
|
||||
import static org.lwjgl.opengl.GL31.glGetUniformBlockIndex;
|
||||
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;
|
||||
|
||||
|
@ -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
|
||||
protected void deleteInternal(int handle) {
|
||||
glDeleteProgram(handle);
|
||||
|
|
|
@ -31,11 +31,15 @@ public interface GlslExpr {
|
|||
return new FunctionCall0(functionName);
|
||||
}
|
||||
|
||||
static GlslExpr literal(int expr) {
|
||||
static GlslExpr intLiteral(int 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);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
|
|
|
@ -25,7 +25,11 @@ public class GlslSwitch implements GlslStmt {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -35,7 +39,7 @@ public class GlslSwitch implements GlslStmt {
|
|||
@Override
|
||||
public String prettyPrint() {
|
||||
return """
|
||||
switch (%s) {
|
||||
switch (%s) {
|
||||
%s
|
||||
}""".formatted(on.prettyPrint(), formatCases());
|
||||
}
|
||||
|
|
|
@ -8,19 +8,16 @@ import com.jozufozu.flywheel.util.Pair;
|
|||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
public class GlslUniformBlock implements GlslBuilder.Declaration {
|
||||
|
||||
|
||||
private String qualifier;
|
||||
private int binding;
|
||||
private String name;
|
||||
private final List<Pair<String, String>> members = new ArrayList<>();
|
||||
private String name;
|
||||
private final List<Pair<String, String>> members = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
return """
|
||||
layout(%s, binding = %d) uniform %s {
|
||||
%s
|
||||
};""".formatted(qualifier, binding, name, StringUtil.indent(formatMembers(), 4));
|
||||
return """
|
||||
layout(%s) uniform %s {
|
||||
%s
|
||||
};""".formatted(qualifier, name, StringUtil.indent(formatMembers(), 4));
|
||||
}
|
||||
|
||||
private String formatMembers() {
|
||||
|
@ -34,15 +31,10 @@ public class GlslUniformBlock implements GlslBuilder.Declaration {
|
|||
return this;
|
||||
}
|
||||
|
||||
public GlslUniformBlock binding(int i) {
|
||||
binding = i;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GlslUniformBlock name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
public GlslUniformBlock name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GlslUniformBlock member(String typeName, String variableName) {
|
||||
members.add(Pair.of(typeName, variableName));
|
||||
|
|
|
@ -4,7 +4,6 @@ import org.jetbrains.annotations.NotNull;
|
|||
|
||||
@FunctionalInterface
|
||||
public interface NonNullSupplier<T> {
|
||||
|
||||
@NotNull
|
||||
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