Pre-processing Pre-refactor

- Move pipeline code to backend package
- Store compiled programs in FlwPrograms instead of FlwCompiler
- Rename PipelineContext to PipelineProgramKey and remove CullingContext
- Remove PipelineContextSet and CullingContextSet
- Improve quality of dumped sources
- Rename pipeline directory to internal
- Add underscores before more internal GLSL variables
- Remove unnecessary GLSL files
This commit is contained in:
PepperCode1 2023-04-16 22:09:28 -07:00
parent 5b84046c1d
commit 7afa2486ad
42 changed files with 369 additions and 596 deletions

View file

@ -5,7 +5,7 @@ import org.slf4j.Logger;
import com.jozufozu.flywheel.backend.Backends; import com.jozufozu.flywheel.backend.Backends;
import com.jozufozu.flywheel.backend.Loader; import com.jozufozu.flywheel.backend.Loader;
import com.jozufozu.flywheel.backend.Pipelines; import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
import com.jozufozu.flywheel.backend.engine.UniformBuffer; import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.backend.engine.batching.DrawBuffer; import com.jozufozu.flywheel.backend.engine.batching.DrawBuffer;
import com.jozufozu.flywheel.config.BackendArgument; import com.jozufozu.flywheel.config.BackendArgument;

View file

@ -1,8 +1,5 @@
package com.jozufozu.flywheel.api.backend; package com.jozufozu.flywheel.api.backend;
import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.pipeline.Pipeline;
import com.jozufozu.flywheel.api.registry.IdRegistry; import com.jozufozu.flywheel.api.registry.IdRegistry;
import com.jozufozu.flywheel.impl.IdRegistryImpl; import com.jozufozu.flywheel.impl.IdRegistryImpl;
@ -31,6 +28,4 @@ public interface Backend {
* Check if this backend is supported. * Check if this backend is supported.
*/ */
boolean isSupported(); boolean isSupported();
@Nullable Pipeline pipelineShader();
} }

View file

@ -1,27 +0,0 @@
package com.jozufozu.flywheel.api.pipeline;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.gl.GLSLVersion;
import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent;
import net.minecraft.resources.ResourceLocation;
public interface Pipeline {
GLSLVersion glslVersion();
ResourceLocation vertexShader();
ResourceLocation fragmentShader();
/**
* Generate the source component necessary to convert a packed {@link InstanceType} into its shader representation.
*
* @return A source component defining functions that unpack a representation of the given instance type.
*/
SourceComponent assemble(InstanceAssemblerContext context);
record InstanceAssemblerContext(ShaderSources sources, VertexType vertexType, InstanceType<?> instanceType) {
}
}

View file

@ -32,7 +32,6 @@ public class Backends {
.fallback(() -> Backends.BATCHING) .fallback(() -> Backends.BATCHING)
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance() .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance()
.instancedArraysSupported()) .instancedArraysSupported())
.pipelineShader(Pipelines.INSTANCED_ARRAYS)
.register(Flywheel.rl("instancing")); .register(Flywheel.rl("instancing"));
/** /**
@ -44,7 +43,6 @@ public class Backends {
.fallback(() -> Backends.INSTANCING) .fallback(() -> Backends.INSTANCING)
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance() .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance()
.supportsIndirect()) .supportsIndirect())
.pipelineShader(Pipelines.INDIRECT)
.register(Flywheel.rl("indirect")); .register(Flywheel.rl("indirect"));
public static void init() { public static void init() {

View file

@ -1,8 +1,6 @@
package com.jozufozu.flywheel.backend; package com.jozufozu.flywheel.backend;
import com.jozufozu.flywheel.backend.compile.FlwCompiler; import com.jozufozu.flywheel.backend.compile.FlwPrograms;
import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.error.ErrorReporter;
import com.jozufozu.flywheel.impl.BackendManagerImpl; import com.jozufozu.flywheel.impl.BackendManagerImpl;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -25,14 +23,7 @@ public class Loader implements ResourceManagerReloadListener {
@Override @Override
public void onResourceManagerReload(ResourceManager manager) { public void onResourceManagerReload(ResourceManager manager) {
var errorReporter = new ErrorReporter(); FlwPrograms.reload(manager);
ShaderSources sources = new ShaderSources(errorReporter, manager);
if (FlwCompiler.INSTANCE != null) {
FlwCompiler.INSTANCE.delete();
}
FlwCompiler.INSTANCE = new FlwCompiler(sources);
// TODO: Move this to the impl package // TODO: Move this to the impl package
BackendManagerImpl.refresh(Minecraft.getInstance().level); BackendManagerImpl.refresh(Minecraft.getInstance().level);

View file

@ -40,7 +40,7 @@ public class Compilation {
public Compilation(GLSLVersion glslVersion, ShaderType shaderType) { public Compilation(GLSLVersion glslVersion, ShaderType shaderType) {
this.generatedSource = new StringBuilder(); this.generatedSource = new StringBuilder();
this.fullSource = new StringBuilder(CompileUtil.generateHeader(glslVersion, shaderType)); this.fullSource = new StringBuilder(CompileUtil.generateHeader(glslVersion, shaderType)).append('\n');
this.glslVersion = glslVersion; this.glslVersion = glslVersion;
this.shaderType = shaderType; this.shaderType = shaderType;
} }
@ -71,10 +71,6 @@ public class Compilation {
.append(" : enable\n"); .append(" : enable\n");
} }
public void addComponentName(ResourceLocation name) {
componentNames.add(name);
}
public void appendComponent(SourceComponent component) { public void appendComponent(SourceComponent component) {
var source = component.source(); var source = component.source();
@ -85,12 +81,12 @@ public class Compilation {
.toString())); .toString()));
} }
fullSource.append(source) fullSource.append(source);
.append('\n'); componentNames.add(component.name());
} }
private String sourceHeader(SourceFile sourceFile) { private String sourceHeader(SourceFile sourceFile) {
return "#line " + 0 + ' ' + getOrCreateFileID(sourceFile) + " // " + sourceFile.name + '\n'; return '\n' + "#line " + 0 + ' ' + getOrCreateFileID(sourceFile) + " // " + sourceFile.name + '\n';
} }
private String generatedHeader(String generatedCode, String comment) { private String generatedHeader(String generatedCode, String comment) {
@ -98,7 +94,7 @@ public class Compilation {
int lines = StringUtil.countLines(generatedCode); int lines = StringUtil.countLines(generatedCode);
// all generated code is put in file 0, // all generated code is put in file 0,
var out = "#line " + generatedLines + ' ' + 0; var out = '\n' + "#line " + generatedLines + ' ' + 0;
generatedLines += lines; generatedLines += lines;
@ -123,12 +119,13 @@ public class Compilation {
@NotNull @NotNull
private String buildShaderName() { private String buildShaderName() {
// TODO: This name is so long it fails to create the file. Use index and map indices to component sources in separate file?
var components = componentNames.stream() var components = componentNames.stream()
.map(ResourceLocation::toString) .map(ResourceLocation::toString)
.map(s -> s.replaceAll("/", "_") .map(s -> s.replaceAll("/", "_")
.replaceAll(":", "\\$")) .replaceAll(":", "\\$"))
.collect(Collectors.joining(";")); .collect(Collectors.joining(";"));
return shaderType.name + glslVersion + ';' + components; return shaderType.name + glslVersion + ';' /*+ components*/;
} }
private static void dumpSource(String source, String fileName) { private static void dumpSource(String source, String fileName) {

View file

@ -24,7 +24,7 @@ public class CompileUtil {
public static final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$"); public static final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$");
public static String generateHeader(GLSLVersion version, ShaderType type) { public static String generateHeader(GLSLVersion version, ShaderType type) {
return version.getVersionLine() + type.getDefineStatement() + '\n'; return version.getVersionLine() + type.getDefineStatement();
} }
public static int getElementCount(String type) { public static int getElementCount(String type) {

View file

@ -1,6 +0,0 @@
package com.jozufozu.flywheel.backend.compile;
import com.jozufozu.flywheel.api.instance.InstanceType;
public record CullingContext(InstanceType<?> instanceType) {
}

View file

@ -1,37 +0,0 @@
package com.jozufozu.flywheel.backend.compile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.jozufozu.flywheel.api.instance.InstanceType;
public class CullingContextSet {
static CullingContextSet create() {
var builder = new CullingContextSet();
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
builder.add(instanceType);
}
return builder;
}
private final List<CullingContext> contexts = new ArrayList<>();
private final List<CullingContext> contextView = Collections.unmodifiableList(contexts);
CullingContextSet() {
}
public List<CullingContext> all() {
return contextView;
}
public int size() {
return contexts.size();
}
private void add(InstanceType<?> instanceType) {
var ctx = new CullingContext(instanceType);
contexts.add(ctx);
}
}

View file

@ -10,14 +10,14 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.Flywheel;
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.pipeline.Pipeline;
import com.jozufozu.flywheel.api.uniform.ShaderUniforms; import com.jozufozu.flywheel.api.uniform.ShaderUniforms;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.compile.FlwPrograms.PipelineProgramKey;
import com.jozufozu.flywheel.backend.Pipelines; import com.jozufozu.flywheel.backend.compile.pipeline.Pipeline;
import com.jozufozu.flywheel.backend.engine.indirect.IndirectComponent; import com.jozufozu.flywheel.backend.engine.indirect.IndirectComponent;
import com.jozufozu.flywheel.gl.GLSLVersion; import com.jozufozu.flywheel.gl.GLSLVersion;
import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.gl.shader.GlProgram;
@ -30,36 +30,42 @@ import com.jozufozu.flywheel.glsl.generate.GlslExpr;
import com.jozufozu.flywheel.lib.material.MaterialIndices; import com.jozufozu.flywheel.lib.material.MaterialIndices;
import com.jozufozu.flywheel.util.StringUtil; import com.jozufozu.flywheel.util.StringUtil;
import net.minecraft.resources.ResourceLocation;
public class FlwCompiler { public class FlwCompiler {
private final long compileStart = System.nanoTime();
public static FlwCompiler INSTANCE;
final long compileStart = System.nanoTime();
private final ShaderSources sources; private final ShaderSources sources;
private final UniformComponent uniformComponent;
private final ImmutableList<PipelineProgramKey> pipelineKeys;
private final ImmutableList<InstanceType<?>> cullingKeys;
private final ShaderCompiler shaderCompiler;
private final List<FailedCompilation> errors = new ArrayList<>();
private final MaterialAdapterComponent vertexMaterialComponent; private final MaterialAdapterComponent vertexMaterialComponent;
private final MaterialAdapterComponent fragmentMaterialComponent; private final MaterialAdapterComponent fragmentMaterialComponent;
private final UniformComponent uniformComponent;
private final PipelineContextSet pipelineContexts; private final Map<PipelineProgramKey, GlProgram> pipelinePrograms = new HashMap<>();
private final CullingContextSet cullingContexts; private final Map<InstanceType<?>, GlProgram> cullingPrograms = new HashMap<>();
final ShaderCompiler shaderCompiler; public FlwCompiler(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, ImmutableList<InstanceType<?>> cullingKeys) {
final Map<PipelineContext, GlProgram> pipelinePrograms = new HashMap<>(); this.sources = sources;
final Map<InstanceType<?>, GlProgram> cullingPrograms = new HashMap<>();
final List<FailedCompilation> errors = new ArrayList<>();
public FlwCompiler(ShaderSources sources) { this.pipelineKeys = pipelineKeys;
this.shaderCompiler = ShaderCompiler.builder() this.cullingKeys = cullingKeys;
shaderCompiler = ShaderCompiler.builder()
.errorConsumer(errors::add) .errorConsumer(errors::add)
.build(); .build();
this.sources = sources; vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
this.vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
.materialSources(MaterialIndices.getAllVertexShaders()) .materialSources(MaterialIndices.getAllVertexShaders())
.adapt(FnSignature.ofVoid("flw_materialVertex")) .adapt(FnSignature.ofVoid("flw_materialVertex"))
.switchOn(GlslExpr.variable("flw_materialVertexID")) .switchOn(GlslExpr.variable("_flw_materialVertexID"))
.build(sources); .build(sources);
this.fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter")) fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
.materialSources(MaterialIndices.getAllFragmentShaders()) .materialSources(MaterialIndices.getAllFragmentShaders())
.adapt(FnSignature.ofVoid("flw_materialFragment")) .adapt(FnSignature.ofVoid("flw_materialFragment"))
.adapt(FnSignature.create() .adapt(FnSignature.create()
@ -72,36 +78,116 @@ public class FlwCompiler {
.name("flw_fogFilter") .name("flw_fogFilter")
.arg("vec4", "color") .arg("vec4", "color")
.build(), GlslExpr.variable("color")) .build(), GlslExpr.variable("color"))
.switchOn(GlslExpr.variable("flw_materialFragmentID")) .switchOn(GlslExpr.variable("_flw_materialFragmentID"))
.build(sources); .build(sources);
this.uniformComponent = UniformComponent.builder(Flywheel.rl("uniforms")) uniformComponent = UniformComponent.builder(Flywheel.rl("uniforms"))
.sources(ShaderUniforms.REGISTRY.getAll() .sources(ShaderUniforms.REGISTRY.getAll()
.stream() .stream()
.map(ShaderUniforms::uniformShader) .map(ShaderUniforms::uniformShader)
.toList()) .toList())
.build(sources); .build(sources);
}
this.pipelineContexts = PipelineContextSet.create(); public FlwPrograms compile() {
this.cullingContexts = CullingContextSet.create();
doCompilation(); doCompilation();
finish(); finish();
return new FlwPrograms(pipelinePrograms, cullingPrograms);
} }
private void doCompilation() { private void doCompilation() {
for (var ctx : pipelineContexts.all()) { for (var key : pipelineKeys) {
compilePipelineContext(ctx); GlProgram glProgram = compilePipelineProgram(key);
if (glProgram != null) {
pipelinePrograms.put(key, glProgram);
}
} }
for (var ctx : cullingContexts.all()) { for (var key : cullingKeys) {
compileComputeCuller(ctx); GlProgram glProgram = compileCullingProgram(key);
if (glProgram != null) {
cullingPrograms.put(key, glProgram);
} }
} }
}
private static GlProgram link(int... shaders) {
var handle = glCreateProgram();
for (var shader : shaders) {
glAttachShader(handle, shader);
}
glLinkProgram(handle);
CompileUtil.checkLinkLog(handle);
return new GlProgram(handle);
}
@Nullable
private GlProgram compilePipelineProgram(PipelineProgramKey key) {
var glslVersion = key.pipelineShader()
.glslVersion();
var vertex = shaderCompiler.compile(glslVersion, ShaderType.VERTEX, getVertexComponents(key));
var fragment = shaderCompiler.compile(glslVersion, ShaderType.FRAGMENT, getFragmentComponents(key));
if (vertex == null || fragment == null) {
return null;
}
var glProgram = link(vertex.handle(), fragment.handle());
key.contextShader()
.onProgramLink(glProgram);
return glProgram;
}
private ImmutableList<SourceComponent> getVertexComponents(PipelineProgramKey key) {
var instanceAssembly = key.pipelineShader()
.assembler()
.assemble(new Pipeline.InstanceAssemblerContext(sources, key.vertexType(), key.instanceType()));
var layout = sources.find(key.vertexType()
.layoutShader());
var instance = sources.find(key.instanceType()
.instanceShader());
var context = sources.find(key.contextShader()
.vertexShader());
var pipeline = sources.find(key.pipelineShader()
.vertexShader());
return ImmutableList.of(uniformComponent, vertexMaterialComponent, instanceAssembly, layout, instance, context, pipeline);
}
private ImmutableList<SourceComponent> getFragmentComponents(PipelineProgramKey key) {
var context = sources.find(key.contextShader()
.fragmentShader());
var pipeline = sources.find(key.pipelineShader()
.fragmentShader());
return ImmutableList.of(uniformComponent, fragmentMaterialComponent, context, pipeline);
}
@Nullable
private GlProgram compileCullingProgram(InstanceType<?> key) {
var computeComponents = getComputeComponents(key);
var result = shaderCompiler.compile(GLSLVersion.V460, ShaderType.COMPUTE, computeComponents);
if (result == null) {
return null;
}
return link(result.handle());
}
private ImmutableList<SourceComponent> getComputeComponents(InstanceType<?> instanceType) {
var instanceAssembly = new IndirectComponent(sources, instanceType);
var instance = sources.find(instanceType.instanceShader());
var pipeline = sources.find(Files.INDIRECT_CULL);
return ImmutableList.of(uniformComponent, instanceAssembly, instance, pipeline);
}
private void finish() { private void finish() {
long compileEnd = System.nanoTime(); long compileEnd = System.nanoTime();
int programCount = pipelineContexts.size() + InstanceType.REGISTRY.getAll().size(); int programCount = pipelineKeys.size() + cullingKeys.size();
int shaderCount = shaderCompiler.shaderCount(); int shaderCount = shaderCompiler.shaderCount();
int errorCount = errors.size(); int errorCount = errors.size();
var elapsed = StringUtil.formatTime(compileEnd - compileStart); var elapsed = StringUtil.formatTime(compileEnd - compileStart);
@ -112,94 +198,16 @@ public class FlwCompiler {
var details = errors.stream() var details = errors.stream()
.map(FailedCompilation::getMessage) .map(FailedCompilation::getMessage)
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));
// throw new ShaderLoadingException("Compilation failed.\n" + details); // TODO: disable backend instead of crashing if compilation fails
throw new ShaderLoadingException("Compilation failed.\n" + details);
} }
} }
public void delete() { public void delete() {
pipelinePrograms.values()
.forEach(GlProgram::delete);
cullingPrograms.values()
.forEach(GlProgram::delete);
shaderCompiler.delete(); shaderCompiler.delete();
} }
public GlProgram getPipelineProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader, Pipeline pipelineShader) { private static final class Files {
return pipelinePrograms.get(new PipelineContext(vertexType, instanceType, contextShader, pipelineShader)); public static final ResourceLocation INDIRECT_CULL = Flywheel.rl("internal/indirect_cull.glsl");
} }
public GlProgram getCullingProgram(InstanceType<?> instanceType) {
return cullingPrograms.get(instanceType);
}
private void compilePipelineContext(PipelineContext ctx) {
var glslVersion = ctx.pipelineShader()
.glslVersion();
var vertex = shaderCompiler.compile(glslVersion, ShaderType.VERTEX, getVertexComponents(ctx));
var fragment = shaderCompiler.compile(glslVersion, ShaderType.FRAGMENT, getFragmentComponents(ctx));
if (vertex == null || fragment == null) {
return;
}
var glProgram = link(vertex.handle(), fragment.handle());
ctx.contextShader()
.onProgramLink(glProgram);
pipelinePrograms.put(ctx, glProgram);
}
private void compileComputeCuller(CullingContext ctx) {
var computeComponents = getComputeComponents(ctx.instanceType());
var result = shaderCompiler.compile(GLSLVersion.V460, ShaderType.COMPUTE, computeComponents);
if (result == null) {
return;
}
cullingPrograms.put(ctx.instanceType(), link(result.handle()));
}
private GlProgram link(int... shaders) {
var handle = glCreateProgram();
for (var shader : shaders) {
glAttachShader(handle, shader);
}
glLinkProgram(handle);
CompileUtil.checkLinkLog(handle);
return new GlProgram(handle);
}
private ImmutableList<SourceComponent> getVertexComponents(PipelineContext ctx) {
var instanceAssembly = ctx.pipelineShader()
.assemble(new Pipeline.InstanceAssemblerContext(sources, ctx.vertexType(), ctx.instanceType()));
var layout = sources.find(ctx.vertexType()
.layoutShader());
var instance = sources.find(ctx.instanceType()
.instanceShader());
var context = sources.find(ctx.contextShader()
.vertexShader());
var pipeline = sources.find(ctx.pipelineShader()
.vertexShader());
return ImmutableList.of(uniformComponent, vertexMaterialComponent, instanceAssembly, layout, instance, context, pipeline);
}
private ImmutableList<SourceComponent> getFragmentComponents(PipelineContext ctx) {
var context = sources.find(ctx.contextShader()
.fragmentShader());
var pipeline = sources.find(ctx.pipelineShader()
.fragmentShader());
return ImmutableList.of(uniformComponent, fragmentMaterialComponent, context, pipeline);
}
private ImmutableList<SourceComponent> getComputeComponents(InstanceType<?> instanceType) {
var instanceAssembly = new IndirectComponent(sources, instanceType);
var instance = sources.find(instanceType.instanceShader());
var pipeline = sources.find(Pipelines.Files.INDIRECT_CULL);
return ImmutableList.of(uniformComponent, instanceAssembly, instance, pipeline);
}
} }

View file

@ -0,0 +1,94 @@
package com.jozufozu.flywheel.backend.compile;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList;
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.pipeline.Pipeline;
import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.error.ErrorReporter;
import com.jozufozu.flywheel.lib.context.Contexts;
import net.minecraft.server.packs.resources.ResourceManager;
public class FlwPrograms {
private static FlwPrograms instance;
private final Map<PipelineProgramKey, GlProgram> pipelinePrograms;
private final Map<InstanceType<?>, GlProgram> cullingPrograms;
public FlwPrograms(Map<PipelineProgramKey, GlProgram> pipelinePrograms, Map<InstanceType<?>, GlProgram> cullingPrograms) {
this.pipelinePrograms = pipelinePrograms;
this.cullingPrograms = cullingPrograms;
}
public static void reload(ResourceManager resourceManager) {
if (instance != null) {
instance.delete();
}
ErrorReporter errorReporter = new ErrorReporter();
ShaderSources sources = new ShaderSources(errorReporter, resourceManager);
FlwCompiler compiler = new FlwCompiler(sources, createPipelineKeys(), createCullingKeys());
instance = compiler.compile();
compiler.delete();
}
private static ImmutableList<PipelineProgramKey> createPipelineKeys() {
ImmutableList.Builder<PipelineProgramKey> builder = ImmutableList.builder();
for (Pipeline pipelineShader : Pipelines.ALL) {
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
for (VertexType vertexType : VertexType.REGISTRY) {
builder.add(new PipelineProgramKey(vertexType, instanceType, Contexts.WORLD, pipelineShader));
}
}
}
return builder.build();
}
private static ImmutableList<InstanceType<?>> createCullingKeys() {
ImmutableList.Builder<InstanceType<?>> builder = ImmutableList.builder();
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
builder.add(instanceType);
}
return builder.build();
}
@Nullable
public static FlwPrograms get() {
return instance;
}
public GlProgram getPipelineProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader, Pipeline pipelineShader) {
return pipelinePrograms.get(new PipelineProgramKey(vertexType, instanceType, contextShader, pipelineShader));
}
public GlProgram getCullingProgram(InstanceType<?> instanceType) {
return cullingPrograms.get(instanceType);
}
private void delete() {
pipelinePrograms.values()
.forEach(GlProgram::delete);
cullingPrograms.values()
.forEach(GlProgram::delete);
}
/**
* Represents the entire context of a program's usage.
*
* @param vertexType The vertex type the program should be adapted for.
* @param instanceType The instance shader to use.
* @param contextShader The context shader to use.
* @param pipelineShader The pipeline shader to use.
*/
public record PipelineProgramKey(VertexType vertexType, InstanceType<?> instanceType, Context contextShader,
Pipeline pipelineShader) {
}
}

View file

@ -61,6 +61,8 @@ public class MaterialAdapterComponent implements SourceComponent {
.body(body -> generateAdapter(body, adaptedFunction)); .body(body -> generateAdapter(body, adaptedFunction));
} }
builder.blankLine();
return builder.build(); return builder.build();
} }

View file

@ -1,17 +0,0 @@
package com.jozufozu.flywheel.backend.compile;
import com.jozufozu.flywheel.api.context.Context;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.pipeline.Pipeline;
import com.jozufozu.flywheel.api.vertex.VertexType;
/**
* Represents the entire context of a program's usage.
*
* @param vertexType The vertexType the program should be adapted for.
* @param instanceType The instance shader to use.
* @param contextShader The context shader to use.
*/
public record PipelineContext(VertexType vertexType, InstanceType<?> instanceType, Context contextShader,
Pipeline pipelineShader) {
}

View file

@ -1,58 +0,0 @@
package com.jozufozu.flywheel.backend.compile;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import com.jozufozu.flywheel.api.backend.Backend;
import com.jozufozu.flywheel.api.context.Context;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.pipeline.Pipeline;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.lib.context.Contexts;
public class PipelineContextSet {
private final List<PipelineContext> contexts = new ArrayList<>();
private final List<PipelineContext> contextView = Collections.unmodifiableList(contexts);
PipelineContextSet() {
}
static PipelineContextSet create() {
var builder = new PipelineContextSet();
for (Pipeline pipelineShader : availablePipelineShaders()) {
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
for (VertexType vertexType : VertexType.REGISTRY) {
builder.add(vertexType, instanceType, Contexts.WORLD, pipelineShader);
}
}
}
return builder;
}
private static Collection<Pipeline> availablePipelineShaders() {
return Backend.REGISTRY.getAll()
.stream()
.filter(Backend::isSupported)
.map(Backend::pipelineShader)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
public List<PipelineContext> all() {
return contextView;
}
public int size() {
return contexts.size();
}
private void add(VertexType vertexType, InstanceType<?> instanceType, Context world, Pipeline pipelineShader) {
var ctx = new PipelineContext(vertexType, instanceType, world, pipelineShader);
contexts.add(ctx);
}
}

View file

@ -41,6 +41,8 @@ public class UniformComponent implements SourceComponent {
.name("FLWUniforms") .name("FLWUniforms")
.member("flywheel_uniforms", "flywheel"); .member("flywheel_uniforms", "flywheel");
builder.blankLine();
return builder.build(); return builder.build();
} }

View file

@ -0,0 +1,59 @@
package com.jozufozu.flywheel.backend.compile.pipeline;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.gl.GLSLVersion;
import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent;
import net.minecraft.resources.ResourceLocation;
public record Pipeline(GLSLVersion glslVersion, ResourceLocation vertexShader, ResourceLocation fragmentShader, InstanceAssembler assembler) {
@FunctionalInterface
public interface InstanceAssembler {
/**
* Generate the source component necessary to convert a packed {@link InstanceType} into its shader representation.
*
* @return A source component defining functions that unpack a representation of the given instance type.
*/
SourceComponent assemble(InstanceAssemblerContext context);
}
public record InstanceAssemblerContext(ShaderSources sources, VertexType vertexType, InstanceType<?> instanceType) {
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private GLSLVersion glslVersion;
private ResourceLocation vertex;
private ResourceLocation fragment;
private InstanceAssembler assembler;
public Builder glslVersion(GLSLVersion glslVersion) {
this.glslVersion = glslVersion;
return this;
}
public Builder vertex(ResourceLocation vertex) {
this.vertex = vertex;
return this;
}
public Builder fragment(ResourceLocation fragment) {
this.fragment = fragment;
return this;
}
public Builder assembler(InstanceAssembler assembler) {
this.assembler = assembler;
return this;
}
public Pipeline build() {
return new Pipeline(glslVersion, vertex, fragment, assembler);
}
}
}

View file

@ -1,35 +1,38 @@
package com.jozufozu.flywheel.backend; package com.jozufozu.flywheel.backend.compile.pipeline;
import java.util.List;
import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.backend.engine.indirect.IndirectComponent; import com.jozufozu.flywheel.backend.engine.indirect.IndirectComponent;
import com.jozufozu.flywheel.backend.engine.instancing.InstancedArraysComponent; import com.jozufozu.flywheel.backend.engine.instancing.InstancedArraysComponent;
import com.jozufozu.flywheel.gl.GLSLVersion; import com.jozufozu.flywheel.gl.GLSLVersion;
import com.jozufozu.flywheel.lib.pipeline.SimplePipeline;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public class Pipelines { public final class Pipelines {
public static final SimplePipeline INSTANCED_ARRAYS = SimplePipeline.builder() public static final Pipeline INSTANCED_ARRAYS = Pipeline.builder()
.glslVersion(GLSLVersion.V420) .glslVersion(GLSLVersion.V420)
.vertex(Files.INSTANCED_ARRAYS_DRAW) .vertex(Files.INSTANCED_ARRAYS_DRAW)
.fragment(Files.DRAW_FRAGMENT) .fragment(Files.DRAW_FRAGMENT)
.assemblerFactory(InstancedArraysComponent::new) .assembler(InstancedArraysComponent::new)
.build(); .build();
public static final SimplePipeline INDIRECT = SimplePipeline.builder() public static final Pipeline INDIRECT = Pipeline.builder()
.glslVersion(GLSLVersion.V460) .glslVersion(GLSLVersion.V460)
.vertex(Files.INDIRECT_DRAW) .vertex(Files.INDIRECT_DRAW)
.fragment(Files.DRAW_FRAGMENT) .fragment(Files.DRAW_FRAGMENT)
.assemblerFactory(IndirectComponent::new) .assembler(IndirectComponent::new)
.build(); .build();
public static final List<Pipeline> ALL = List.of(INSTANCED_ARRAYS, INDIRECT);
public static void init() { public static void init() {
} }
public static class Files { public static final class Files {
public static final ResourceLocation DRAW_FRAGMENT = Flywheel.rl("pipeline/draw.frag"); public static final ResourceLocation INSTANCED_ARRAYS_DRAW = Flywheel.rl("internal/instanced_arrays_draw.vert");
public static final ResourceLocation INSTANCED_ARRAYS_DRAW = Flywheel.rl("pipeline/instanced_arrays_draw.vert"); public static final ResourceLocation INDIRECT_DRAW = Flywheel.rl("internal/indirect_draw.vert");
public static final ResourceLocation INDIRECT_DRAW = Flywheel.rl("pipeline/indirect_draw.vert"); public static final ResourceLocation DRAW_FRAGMENT = Flywheel.rl("internal/draw.frag");
public static final ResourceLocation INDIRECT_CULL = Flywheel.rl("pipeline/indirect_cull.glsl");
public static final ResourceLocation UTIL_TYPES = Flywheel.rl("util/types.glsl"); public static final ResourceLocation UTIL_TYPES = Flywheel.rl("util/types.glsl");
} }
} }

View file

@ -7,8 +7,8 @@ import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.layout.LayoutItem; import com.jozufozu.flywheel.api.layout.LayoutItem;
import com.jozufozu.flywheel.api.pipeline.Pipeline; import com.jozufozu.flywheel.backend.compile.pipeline.Pipeline;
import com.jozufozu.flywheel.backend.Pipelines; import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
import com.jozufozu.flywheel.glsl.ShaderSources; import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceComponent;
import com.jozufozu.flywheel.glsl.SourceFile; import com.jozufozu.flywheel.glsl.SourceFile;
@ -57,6 +57,7 @@ public class IndirectComponent implements SourceComponent {
var builder = new GlslBuilder(); var builder = new GlslBuilder();
builder.define("FlwInstance", STRUCT_NAME); builder.define("FlwInstance", STRUCT_NAME);
builder.define("FlwPackedInstance", PACKED_STRUCT_NAME); builder.define("FlwPackedInstance", PACKED_STRUCT_NAME);
builder.blankLine();
var packed = builder.struct(); var packed = builder.struct();
builder.blankLine(); builder.blankLine();
@ -74,11 +75,13 @@ public class IndirectComponent implements SourceComponent {
builder.function() builder.function()
.signature(FnSignature.create() .signature(FnSignature.create()
.returnType(STRUCT_NAME) .returnType(STRUCT_NAME)
.name("flw_unpackInstance") .name("_flw_unpackInstance")
.arg(PACKED_STRUCT_NAME, UNPACK_ARG) .arg(PACKED_STRUCT_NAME, UNPACK_ARG)
.build()) .build())
.body(this::generateUnpackingBody); .body(this::generateUnpackingBody);
builder.blankLine();
return builder.build(); return builder.build();
} }

View file

@ -15,8 +15,8 @@ import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.Instance;
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.Pipelines; import com.jozufozu.flywheel.backend.compile.FlwPrograms;
import com.jozufozu.flywheel.backend.compile.FlwCompiler; import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
import com.jozufozu.flywheel.backend.engine.UniformBuffer; import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.lib.context.Contexts; import com.jozufozu.flywheel.lib.context.Contexts;
@ -62,8 +62,8 @@ public class IndirectCullingGroup<I extends Instance> {
.quads2Tris(2048).glBuffer; .quads2Tris(2048).glBuffer;
setupVertexArray(); setupVertexArray();
compute = FlwCompiler.INSTANCE.getCullingProgram(instanceType); compute = FlwPrograms.get().getCullingProgram(instanceType);
draw = FlwCompiler.INSTANCE.getPipelineProgram(vertexType, instanceType, Contexts.WORLD, Pipelines.INDIRECT); draw = FlwPrograms.get().getPipelineProgram(vertexType, instanceType, Contexts.WORLD, Pipelines.INDIRECT);
} }
private void setupVertexArray() { private void setupVertexArray() {

View file

@ -6,7 +6,7 @@ import java.util.List;
import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.layout.LayoutItem; import com.jozufozu.flywheel.api.layout.LayoutItem;
import com.jozufozu.flywheel.api.pipeline.Pipeline; import com.jozufozu.flywheel.backend.compile.pipeline.Pipeline;
import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceComponent;
import com.jozufozu.flywheel.glsl.generate.FnSignature; import com.jozufozu.flywheel.glsl.generate.FnSignature;
import com.jozufozu.flywheel.glsl.generate.GlslBlock; import com.jozufozu.flywheel.glsl.generate.GlslBlock;
@ -16,7 +16,7 @@ import com.jozufozu.flywheel.glsl.generate.GlslExpr;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public class InstancedArraysComponent implements SourceComponent { public class InstancedArraysComponent implements SourceComponent {
private static final String ATTRIBUTE_SUFFIX = "_vertex_in"; private static final String ATTRIBUTE_PREFIX = "_flw_i_";
private static final String STRUCT_NAME = "Instance"; private static final String STRUCT_NAME = "Instance";
private final List<LayoutItem> layoutItems; private final List<LayoutItem> layoutItems;
@ -45,13 +45,15 @@ public class InstancedArraysComponent implements SourceComponent {
var builder = new GlslBuilder(); var builder = new GlslBuilder();
builder.define("FlwInstance", STRUCT_NAME); builder.define("FlwInstance", STRUCT_NAME);
builder.blankLine();
int i = baseIndex; int i = baseIndex;
for (var field : layoutItems) { for (var field : layoutItems) {
builder.vertexInput() builder.vertexInput()
.binding(i) .binding(i)
.type(field.type() .type(field.type()
.typeName()) .typeName())
.name(field.name() + ATTRIBUTE_SUFFIX); .name(ATTRIBUTE_PREFIX + field.name());
i += field.type() i += field.type()
.attributeCount(); .attributeCount();
@ -70,15 +72,17 @@ public class InstancedArraysComponent implements SourceComponent {
// unpacking function // unpacking function
builder.function() builder.function()
.signature(FnSignature.of(STRUCT_NAME, "flw_unpackInstance")) .signature(FnSignature.of(STRUCT_NAME, "_flw_unpackInstance"))
.body(this::generateUnpackingBody); .body(this::generateUnpackingBody);
builder.blankLine();
return builder.build(); return builder.build();
} }
private void generateUnpackingBody(GlslBlock b) { private void generateUnpackingBody(GlslBlock b) {
var fields = layoutItems.stream() var fields = layoutItems.stream()
.map(it -> new GlslExpr.Variable(it.name() + ATTRIBUTE_SUFFIX)) .map(it -> new GlslExpr.Variable(ATTRIBUTE_PREFIX + it.name()))
.toList(); .toList();
b.ret(GlslExpr.call(STRUCT_NAME, fields)); b.ret(GlslExpr.call(STRUCT_NAME, fields));
} }

View file

@ -13,8 +13,8 @@ import com.jozufozu.flywheel.api.instance.Instancer;
import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.task.Plan; import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.backend.Pipelines; import com.jozufozu.flywheel.backend.compile.FlwPrograms;
import com.jozufozu.flywheel.backend.compile.FlwCompiler; import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
import com.jozufozu.flywheel.backend.engine.AbstractEngine; import com.jozufozu.flywheel.backend.engine.AbstractEngine;
import com.jozufozu.flywheel.backend.engine.UniformBuffer; import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.gl.GlStateTracker; import com.jozufozu.flywheel.gl.GlStateTracker;
@ -106,7 +106,7 @@ public class InstancingEngine extends AbstractEngine {
var vertexType = desc.vertexType(); var vertexType = desc.vertexType();
var instanceType = desc.instanceType(); var instanceType = desc.instanceType();
var program = FlwCompiler.INSTANCE.getPipelineProgram(vertexType, instanceType, context, Pipelines.INSTANCED_ARRAYS); var program = FlwPrograms.get().getPipelineProgram(vertexType, instanceType, context, Pipelines.INSTANCED_ARRAYS);
UniformBuffer.syncAndBind(program); UniformBuffer.syncAndBind(program);
var uniformLocation = program.getUniformLocation("_flw_materialID_instancing"); var uniformLocation = program.getUniformLocation("_flw_materialID_instancing");

View file

@ -93,7 +93,7 @@ public interface GlslExpr {
public String prettyPrint() { public String prettyPrint() {
var args = this.args.stream() var args = this.args.stream()
.map(GlslExpr::prettyPrint) .map(GlslExpr::prettyPrint)
.collect(Collectors.joining(",")); .collect(Collectors.joining(", "));
return name + "(" + args + ")"; return name + "(" + args + ")";
} }

View file

@ -22,7 +22,6 @@ public class GlslFn implements GlslBuilder.Declaration {
return """ return """
%s { %s {
%s %s
} }""".formatted(signature.fullDeclaration(), StringUtil.indent(body.prettyPrint(), 4));
""".formatted(signature.fullDeclaration(), StringUtil.indent(body.prettyPrint(), 4));
} }
} }

View file

@ -5,6 +5,7 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.jozufozu.flywheel.util.Pair; import com.jozufozu.flywheel.util.Pair;
import com.jozufozu.flywheel.util.StringUtil;
public class GlslStruct implements GlslBuilder.Declaration { public class GlslStruct implements GlslBuilder.Declaration {
@ -25,11 +26,11 @@ public class GlslStruct implements GlslBuilder.Declaration {
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));
} }
@Override
public String prettyPrint() { public String prettyPrint() {
return """ return """
struct %s { struct %s {
%s %s
}; };""".formatted(name, StringUtil.indent(buildFields(), 4));
""".formatted(name, buildFields().indent(4));
} }
} }

View file

@ -20,8 +20,7 @@ public class GlslUniformBlock implements GlslBuilder.Declaration {
return """ return """
layout(%s, binding = %d) uniform %s { layout(%s, binding = %d) uniform %s {
%s %s
}; };""".formatted(qualifier, binding, name, StringUtil.indent(formatMembers(), 4));
""".formatted(qualifier, binding, name, StringUtil.indent(formatMembers(), 4));
} }
private String formatMembers() { private String formatMembers() {

View file

@ -8,7 +8,6 @@ import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.glsl.span.Span; import com.jozufozu.flywheel.glsl.span.Span;
public class ShaderFunction { public class ShaderFunction {
// https://regexr.com/60n3d // https://regexr.com/60n3d
public static final Pattern PATTERN = Pattern.compile("(\\w+)\\s+(\\w+)\\s*\\(([\\w,\\s]*)\\)\\s*\\{"); public static final Pattern PATTERN = Pattern.compile("(\\w+)\\s+(\\w+)\\s*\\(([\\w,\\s]*)\\)\\s*\\{");
@ -86,11 +85,10 @@ public class ShaderFunction {
@Override @Override
public String toString() { public String toString() {
String p = parameters.stream() String p = parameters.stream()
.map(variable -> variable.type) .map(variable -> variable.type)
.map(Span::get) .map(Span::get)
.collect(Collectors.joining(",")); .collect(Collectors.joining(", "));
return type + " " + name + "(" + p + ")"; return type + " " + name + "(" + p + ")";
} }

View file

@ -4,12 +4,9 @@ import java.util.function.BooleanSupplier;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.backend.Backend; import com.jozufozu.flywheel.api.backend.Backend;
import com.jozufozu.flywheel.api.backend.BackendManager; import com.jozufozu.flywheel.api.backend.BackendManager;
import com.jozufozu.flywheel.api.backend.Engine; import com.jozufozu.flywheel.api.backend.Engine;
import com.jozufozu.flywheel.api.pipeline.Pipeline;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@ -20,14 +17,12 @@ public class SimpleBackend implements Backend {
private final Function<LevelAccessor, Engine> engineFactory; private final Function<LevelAccessor, Engine> engineFactory;
private final Supplier<Backend> fallback; private final Supplier<Backend> fallback;
private final BooleanSupplier isSupported; private final BooleanSupplier isSupported;
private final Pipeline pipelineShader;
public SimpleBackend(Component engineMessage, Function<LevelAccessor, Engine> engineFactory, Supplier<Backend> fallback, BooleanSupplier isSupported, @Nullable Pipeline pipelineShader) { public SimpleBackend(Component engineMessage, Function<LevelAccessor, Engine> engineFactory, Supplier<Backend> fallback, BooleanSupplier isSupported) {
this.engineMessage = engineMessage; this.engineMessage = engineMessage;
this.engineFactory = engineFactory; this.engineFactory = engineFactory;
this.fallback = fallback; this.fallback = fallback;
this.isSupported = isSupported; this.isSupported = isSupported;
this.pipelineShader = pipelineShader;
} }
public static Builder builder() { public static Builder builder() {
@ -59,17 +54,11 @@ public class SimpleBackend implements Backend {
return isSupported.getAsBoolean(); return isSupported.getAsBoolean();
} }
@Override
public @Nullable Pipeline pipelineShader() {
return pipelineShader;
}
public static class Builder { public static class Builder {
private Component engineMessage; private Component engineMessage;
private Function<LevelAccessor, Engine> engineFactory; private Function<LevelAccessor, Engine> engineFactory;
private Supplier<Backend> fallback = BackendManager::getOffBackend; private Supplier<Backend> fallback = BackendManager::getOffBackend;
private BooleanSupplier isSupported; private BooleanSupplier isSupported;
private Pipeline pipelineShader;
public Builder engineMessage(Component engineMessage) { public Builder engineMessage(Component engineMessage) {
this.engineMessage = engineMessage; this.engineMessage = engineMessage;
@ -91,13 +80,8 @@ public class SimpleBackend implements Backend {
return this; return this;
} }
public Builder pipelineShader(Pipeline pipelineShader) {
this.pipelineShader = pipelineShader;
return this;
}
public Backend register(ResourceLocation id) { public Backend register(ResourceLocation id) {
return Backend.REGISTRY.registerAndGet(id, new SimpleBackend(engineMessage, engineFactory, fallback, isSupported, pipelineShader)); return Backend.REGISTRY.registerAndGet(id, new SimpleBackend(engineMessage, engineFactory, fallback, isSupported));
} }
} }
} }

View file

@ -1,87 +0,0 @@
package com.jozufozu.flywheel.lib.pipeline;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.pipeline.Pipeline;
import com.jozufozu.flywheel.gl.GLSLVersion;
import com.jozufozu.flywheel.glsl.SourceComponent;
import net.minecraft.resources.ResourceLocation;
public final class SimplePipeline implements Pipeline {
private final GLSLVersion glslVersion;
private final ResourceLocation vertex;
private final ResourceLocation fragment;
private final InstanceAssemblerFactory factory;
public SimplePipeline(GLSLVersion glslVersion, ResourceLocation vertex, ResourceLocation fragment, InstanceAssemblerFactory factory) {
this.glslVersion = glslVersion;
this.vertex = vertex;
this.fragment = fragment;
this.factory = factory;
}
/**
* Generate the source component necessary to convert a packed {@link InstanceType} into its shader representation.
*
* @return A source component defining functions that unpack a representation of the given instance type.
*/
@Override
public SourceComponent assemble(InstanceAssemblerContext context) {
return factory.apply(context);
}
@Override
public GLSLVersion glslVersion() {
return glslVersion;
}
@Override
public ResourceLocation vertexShader() {
return vertex;
}
@Override
public ResourceLocation fragmentShader() {
return fragment;
}
@FunctionalInterface
public interface InstanceAssemblerFactory {
SourceComponent apply(InstanceAssemblerContext context);
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private GLSLVersion glslVersion;
private ResourceLocation vertex;
private ResourceLocation fragment;
private InstanceAssemblerFactory factory;
public Builder glslVersion(GLSLVersion glslVersion) {
this.glslVersion = glslVersion;
return this;
}
public Builder vertex(ResourceLocation vertex) {
this.vertex = vertex;
return this;
}
public Builder fragment(ResourceLocation fragment) {
this.fragment = fragment;
return this;
}
public Builder assemblerFactory(InstanceAssemblerFactory factory) {
this.factory = factory;
return this;
}
public SimplePipeline build() {
return new SimplePipeline(glslVersion, vertex, fragment, factory);
}
}
}

View file

@ -24,6 +24,7 @@ public class StringUtil {
private static final NumberFormat THREE_DECIMAL_PLACES = new DecimalFormat("#0.000"); private static final NumberFormat THREE_DECIMAL_PLACES = new DecimalFormat("#0.000");
// FIXME: this method should count trailing newlines
public static int countLines(String s) { public static int countLines(String s) {
return (int) s.lines() return (int) s.lines()
.count(); .count();

View file

@ -1,4 +0,0 @@
#ifdef COMPUTE_SHADER
uint flw_objectID;
uint flw_batchID;
#endif

View file

@ -13,7 +13,7 @@ in vec4 flw_var1;
in vec4 flw_var2; in vec4 flw_var2;
in vec4 flw_var3; in vec4 flw_var3;
flat in uint flw_materialFragmentID; flat in uint _flw_materialFragmentID;
// //

View file

@ -1,5 +1,5 @@
#ifdef VERTEX_SHADER #ifdef VERTEX_SHADER
uint flw_materialVertexID; uint _flw_materialVertexID;
out vec4 flw_vertexPos; out vec4 flw_vertexPos;
out vec4 flw_vertexColor; out vec4 flw_vertexColor;
@ -14,5 +14,5 @@ out vec4 flw_var0;
out vec4 flw_var1; out vec4 flw_var1;
out vec4 flw_var2; out vec4 flw_var2;
out vec4 flw_var3; out vec4 flw_var3;
flat out uint flw_materialFragmentID; flat out uint _flw_materialFragmentID;
#endif #endif

View file

@ -1,50 +0,0 @@
/*
This is what generated ubershaders should look like
uint flw_materialVertexID = 0;
uint flw_materialFragmentID = 0;
void flw_materialVertex() {
switch (flw_materialVertexID) {
case 0: flw_materialVertex_flywheel_cutout_vert(); break;
default: break;
}
}
void flw_materialFragment() {
switch (flw_materialFragmentID) {
case 0: flw_materialFragment_flywheel_cutout_frag(); break;
default: break;
}
}
bool flw_discardPredicate(vec4 finalColor) {
switch (flw_materialFragmentID) {
case 0: return flw_discardPredicate_flywheel_cutout_frag(finalColor);
default: return false;
}
}
vec4 flw_fogFilter(vec4 color) {
switch (flw_materialFragmentID) {
case 0: return flw_fogFilter_flywheel_cutout_frag(color);
default: return color;
}
}
void flw_materialVertex_flywheel_cutout_vert() {
}
void flw_materialFragment_flywheel_cutout_frag() {
}
bool flw_discardPredicate_flywheel_cutout_frag(vec4 finalColor) {
return finalColor.a < 0.1;
}
vec4 flw_fogFilter_flywheel_cutout_frag(vec4 color) {
return linear_fog(color, flw_distance, flw_fogRange.x, flw_fogRange.y, flw_fogColor);
}
*/

View file

@ -1,72 +0,0 @@
#version 450
#define FLW_SUBGROUP_SIZE 32
layout(local_size_x = FLW_SUBGROUP_SIZE) in;
// in uvec3 gl_NumWorkGroups;
// in uvec3 gl_WorkGroupID;
// in uvec3 gl_LocalInvocationID;
// in uvec3 gl_GlobalInvocationID;
// in uint gl_LocalInvocationIndex;
layout(std430, binding = 0) buffer Frustum1 {
vec4 a1; // vec4(nx.x, px.x, ny.x, py.x)
vec4 a2; // vec4(nx.y, px.y, ny.y, py.y)
vec4 a3; // vec4(nx.z, px.z, ny.z, py.z)
vec4 a4; // vec4(nx.w, px.w, ny.w, py.w)
vec2 b1; // vec2(nz.x, pz.x)
vec2 b2; // vec2(nz.y, pz.y)
vec2 b3; // vec2(nz.z, pz.z)
vec2 b4; // vec2(nz.w, pz.w)
} frustum1;
layout(binding = 1) buffer Frustum2 {
vec4 nx;
vec4 px;
vec4 ny;
vec4 py;
vec4 nz;
vec4 pz;
} frustum2;
layout(binding = 2) buffer Result {
bool res1;
bool res2;
bool res3;
} result;
// 83 - 27 = 56 spirv instruction results
bool testSphere1(vec4 sphere) {
return
all(lessThanEqual(fma(frustum1.a1, sphere.xxxx, fma(frustum1.a2, sphere.yyyy, fma(frustum1.a3, sphere.zzzz, frustum1.a4))), -sphere.wwww)) &&
all(lessThanEqual(fma(frustum1.b1, sphere.xx, fma(frustum1.b2, sphere.yy, fma(frustum1.b3, sphere.zz, frustum1.b4))), -sphere.ww));
}
// 236 - 92 = 144 spirv instruction results
bool testSphere2(vec4 sphere) {
return
fma(frustum2.nx.x, sphere.x, fma(frustum2.nx.y, sphere.y, fma(frustum2.nx.z, sphere.z, frustum2.nx.w))) >= -sphere.w &&
fma(frustum2.px.x, sphere.x, fma(frustum2.px.y, sphere.y, fma(frustum2.px.z, sphere.z, frustum2.px.w))) >= -sphere.w &&
fma(frustum2.ny.x, sphere.x, fma(frustum2.ny.y, sphere.y, fma(frustum2.ny.z, sphere.z, frustum2.ny.w))) >= -sphere.w &&
fma(frustum2.py.x, sphere.x, fma(frustum2.py.y, sphere.y, fma(frustum2.py.z, sphere.z, frustum2.py.w))) >= -sphere.w &&
fma(frustum2.nz.x, sphere.x, fma(frustum2.nz.y, sphere.y, fma(frustum2.nz.z, sphere.z, frustum2.nz.w))) >= -sphere.w &&
fma(frustum2.pz.x, sphere.x, fma(frustum2.pz.y, sphere.y, fma(frustum2.pz.z, sphere.z, frustum2.pz.w))) >= -sphere.w;
}
// 322 - 240 = 82 spirv instruction results
bool testSphere3(vec4 sphere) {
return
(dot(frustum2.nx.xyz, sphere.xyz) + frustum2.nx.w) >= -sphere.w &&
(dot(frustum2.px.xyz, sphere.xyz) + frustum2.px.w) >= -sphere.w &&
(dot(frustum2.ny.xyz, sphere.xyz) + frustum2.ny.w) >= -sphere.w &&
(dot(frustum2.py.xyz, sphere.xyz) + frustum2.py.w) >= -sphere.w &&
(dot(frustum2.nz.xyz, sphere.xyz) + frustum2.nz.w) >= -sphere.w &&
(dot(frustum2.pz.xyz, sphere.xyz) + frustum2.pz.w) >= -sphere.w;
}
void main() {
result.res1 = testSphere1(vec4(0., 1., 0., 1.));
result.res2 = testSphere2(vec4(0., 1., 0., 1.));
result.res3 = testSphere3(vec4(0., 1., 0., 1.));
}

View file

@ -1,5 +0,0 @@
out vec4 fragColor;
void main() {
fragColor = vec4(1.0, 1.0, 1.0, 0.2);
}

View file

@ -1,5 +0,0 @@
layout(location = 0) in vec3 worldPos;
void main() {
gl_Position = flywheel.viewProjection * vec4(worldPos, 1.0);
}

View file

@ -1,8 +1,8 @@
#define FLW_SUBGROUP_SIZE 32 #define FLW_SUBGROUP_SIZE 32
layout(local_size_x = FLW_SUBGROUP_SIZE) in; layout(local_size_x = FLW_SUBGROUP_SIZE) in;
#use "flywheel:api/cull.glsl"
#use "flywheel:util/types.glsl" #use "flywheel:util/types.glsl"
#use "flywheel:pipeline/indirect_draw_command.glsl" #use "flywheel:internal/indirect_draw_command.glsl"
// populated by instancers // populated by instancers
layout(std430, binding = 0) restrict readonly buffer ObjectBuffer { layout(std430, binding = 0) restrict readonly buffer ObjectBuffer {
@ -21,6 +21,9 @@ layout(std430, binding = 3) restrict buffer DrawCommands {
MeshDrawCommand drawCommands[]; MeshDrawCommand drawCommands[];
}; };
uint flw_objectID;
uint flw_batchID;
// 83 - 27 = 56 spirv instruction results // 83 - 27 = 56 spirv instruction results
bool testSphere(vec3 center, float radius) { bool testSphere(vec3 center, float radius) {
bvec4 xyInside = greaterThanEqual(fma(flywheel.planes.xyX, center.xxxx, fma(flywheel.planes.xyY, center.yyyy, fma(flywheel.planes.xyZ, center.zzzz, flywheel.planes.xyW))), -radius.xxxx); bvec4 xyInside = greaterThanEqual(fma(flywheel.planes.xyX, center.xxxx, fma(flywheel.planes.xyY, center.yyyy, fma(flywheel.planes.xyZ, center.zzzz, flywheel.planes.xyW))), -radius.xxxx);
@ -36,7 +39,7 @@ bool isVisible() {
float radius; float radius;
unpackBoundingSphere(sphere, center, radius); unpackBoundingSphere(sphere, center, radius);
FlwInstance object = flw_unpackInstance(objects[flw_objectID]); FlwInstance object = _flw_unpackInstance(objects[flw_objectID]);
flw_transformBoundingSphere(object, center, radius); flw_transformBoundingSphere(object, center, radius);
return testSphere(center, radius); return testSphere(center, radius);

View file

@ -1,5 +1,5 @@
#use "flywheel:api/vertex.glsl" #use "flywheel:api/vertex.glsl"
#use "flywheel:pipeline/indirect_draw_command.glsl" #use "flywheel:internal/indirect_draw_command.glsl"
layout(std430, binding = 0) restrict readonly buffer ObjectBuffer { layout(std430, binding = 0) restrict readonly buffer ObjectBuffer {
FlwPackedInstance objects[]; FlwPackedInstance objects[];
@ -20,10 +20,10 @@ layout(std430, binding = 3) restrict readonly buffer DrawCommands {
void main() { void main() {
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID]; uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
uint batchID = batchIDs[instanceIndex]; uint batchID = batchIDs[instanceIndex];
FlwInstance i = flw_unpackInstance(objects[instanceIndex]); FlwInstance i = _flw_unpackInstance(objects[instanceIndex]);
flw_materialVertexID = drawCommands[batchID].vertexMaterialID; _flw_materialVertexID = drawCommands[batchID].vertexMaterialID;
flw_materialFragmentID = drawCommands[batchID].fragmentMaterialID; _flw_materialFragmentID = drawCommands[batchID].fragmentMaterialID;
flw_layoutVertex(); flw_layoutVertex();
flw_instanceVertex(i); flw_instanceVertex(i);

View file

@ -5,10 +5,10 @@ uniform uvec2 _flw_materialID_instancing;
void main() { void main() {
flw_layoutVertex(); flw_layoutVertex();
flw_materialVertexID = _flw_materialID_instancing.x; _flw_materialVertexID = _flw_materialID_instancing.x;
flw_materialFragmentID = _flw_materialID_instancing.y; _flw_materialFragmentID = _flw_materialID_instancing.y;
FlwInstance i = flw_unpackInstance(); FlwInstance i = _flw_unpackInstance();
flw_instanceVertex(i); flw_instanceVertex(i);
flw_materialVertex(); flw_materialVertex();
flw_contextVertex(); flw_contextVertex();

View file

@ -1,12 +1,12 @@
struct FLWPackedPlanes { struct FLWPackedPlanes {
vec4 xyX;// <nx.x, px.x, ny.x, py.x> vec4 xyX; // <nx.x, px.x, ny.x, py.x>
vec4 xyY;// <nx.y, px.y, ny.y, py.y> vec4 xyY; // <nx.y, px.y, ny.y, py.y>
vec4 xyZ;// <nx.z, px.z, ny.z, py.z> vec4 xyZ; // <nx.z, px.z, ny.z, py.z>
vec4 xyW;// <nx.w, px.w, ny.w, py.w> vec4 xyW; // <nx.w, px.w, ny.w, py.w>
vec2 zX;// <nz.x, pz.x> vec2 zX; // <nz.x, pz.x>
vec2 zY;// <nz.y, pz.y> vec2 zY; // <nz.y, pz.y>
vec2 zZ;// <nz.z, pz.z> vec2 zZ; // <nz.z, pz.z>
vec2 zW;// <nz.w, pz.w> vec2 zW; // <nz.w, pz.w>
}; };
struct flywheel_uniforms { struct flywheel_uniforms {