mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
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:
parent
5b84046c1d
commit
7afa2486ad
42 changed files with 369 additions and 596 deletions
|
@ -5,7 +5,7 @@ import org.slf4j.Logger;
|
|||
|
||||
import com.jozufozu.flywheel.backend.Backends;
|
||||
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.batching.DrawBuffer;
|
||||
import com.jozufozu.flywheel.config.BackendArgument;
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
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.impl.IdRegistryImpl;
|
||||
|
||||
|
@ -31,6 +28,4 @@ public interface Backend {
|
|||
* Check if this backend is supported.
|
||||
*/
|
||||
boolean isSupported();
|
||||
|
||||
@Nullable Pipeline pipelineShader();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
|
@ -32,7 +32,6 @@ public class Backends {
|
|||
.fallback(() -> Backends.BATCHING)
|
||||
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance()
|
||||
.instancedArraysSupported())
|
||||
.pipelineShader(Pipelines.INSTANCED_ARRAYS)
|
||||
.register(Flywheel.rl("instancing"));
|
||||
|
||||
/**
|
||||
|
@ -44,7 +43,6 @@ public class Backends {
|
|||
.fallback(() -> Backends.INSTANCING)
|
||||
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance()
|
||||
.supportsIndirect())
|
||||
.pipelineShader(Pipelines.INDIRECT)
|
||||
.register(Flywheel.rl("indirect"));
|
||||
|
||||
public static void init() {
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package com.jozufozu.flywheel.backend;
|
||||
|
||||
import com.jozufozu.flywheel.backend.compile.FlwCompiler;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.backend.compile.FlwPrograms;
|
||||
import com.jozufozu.flywheel.impl.BackendManagerImpl;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
@ -25,14 +23,7 @@ public class Loader implements ResourceManagerReloadListener {
|
|||
|
||||
@Override
|
||||
public void onResourceManagerReload(ResourceManager manager) {
|
||||
var errorReporter = new ErrorReporter();
|
||||
ShaderSources sources = new ShaderSources(errorReporter, manager);
|
||||
|
||||
if (FlwCompiler.INSTANCE != null) {
|
||||
FlwCompiler.INSTANCE.delete();
|
||||
}
|
||||
|
||||
FlwCompiler.INSTANCE = new FlwCompiler(sources);
|
||||
FlwPrograms.reload(manager);
|
||||
|
||||
// TODO: Move this to the impl package
|
||||
BackendManagerImpl.refresh(Minecraft.getInstance().level);
|
||||
|
|
|
@ -40,7 +40,7 @@ public class Compilation {
|
|||
|
||||
public Compilation(GLSLVersion glslVersion, ShaderType shaderType) {
|
||||
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.shaderType = shaderType;
|
||||
}
|
||||
|
@ -71,10 +71,6 @@ public class Compilation {
|
|||
.append(" : enable\n");
|
||||
}
|
||||
|
||||
public void addComponentName(ResourceLocation name) {
|
||||
componentNames.add(name);
|
||||
}
|
||||
|
||||
public void appendComponent(SourceComponent component) {
|
||||
var source = component.source();
|
||||
|
||||
|
@ -85,12 +81,12 @@ public class Compilation {
|
|||
.toString()));
|
||||
}
|
||||
|
||||
fullSource.append(source)
|
||||
.append('\n');
|
||||
fullSource.append(source);
|
||||
componentNames.add(component.name());
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -98,7 +94,7 @@ public class Compilation {
|
|||
int lines = StringUtil.countLines(generatedCode);
|
||||
|
||||
// all generated code is put in file 0,
|
||||
var out = "#line " + generatedLines + ' ' + 0;
|
||||
var out = '\n' + "#line " + generatedLines + ' ' + 0;
|
||||
|
||||
generatedLines += lines;
|
||||
|
||||
|
@ -123,12 +119,13 @@ public class Compilation {
|
|||
|
||||
@NotNull
|
||||
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()
|
||||
.map(ResourceLocation::toString)
|
||||
.map(s -> s.replaceAll("/", "_")
|
||||
.replaceAll(":", "\\$"))
|
||||
.collect(Collectors.joining(";"));
|
||||
return shaderType.name + glslVersion + ';' + components;
|
||||
return shaderType.name + glslVersion + ';' /*+ components*/;
|
||||
}
|
||||
|
||||
private static void dumpSource(String source, String fileName) {
|
||||
|
|
|
@ -24,7 +24,7 @@ public class CompileUtil {
|
|||
public static final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$");
|
||||
|
||||
public static String generateHeader(GLSLVersion version, ShaderType type) {
|
||||
return version.getVersionLine() + type.getDefineStatement() + '\n';
|
||||
return version.getVersionLine() + type.getDefineStatement();
|
||||
}
|
||||
|
||||
public static int getElementCount(String type) {
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
|
||||
public record CullingContext(InstanceType<?> instanceType) {
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -10,14 +10,14 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
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.uniform.ShaderUniforms;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.Pipelines;
|
||||
import com.jozufozu.flywheel.backend.compile.FlwPrograms.PipelineProgramKey;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.engine.indirect.IndirectComponent;
|
||||
import com.jozufozu.flywheel.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
|
@ -30,78 +30,164 @@ import com.jozufozu.flywheel.glsl.generate.GlslExpr;
|
|||
import com.jozufozu.flywheel.lib.material.MaterialIndices;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class FlwCompiler {
|
||||
private final long compileStart = System.nanoTime();
|
||||
|
||||
public static FlwCompiler INSTANCE;
|
||||
|
||||
final long compileStart = System.nanoTime();
|
||||
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 fragmentMaterialComponent;
|
||||
private final UniformComponent uniformComponent;
|
||||
|
||||
private final PipelineContextSet pipelineContexts;
|
||||
private final CullingContextSet cullingContexts;
|
||||
private final Map<PipelineProgramKey, GlProgram> pipelinePrograms = new HashMap<>();
|
||||
private final Map<InstanceType<?>, GlProgram> cullingPrograms = new HashMap<>();
|
||||
|
||||
final ShaderCompiler shaderCompiler;
|
||||
final Map<PipelineContext, GlProgram> pipelinePrograms = new HashMap<>();
|
||||
final Map<InstanceType<?>, GlProgram> cullingPrograms = new HashMap<>();
|
||||
final List<FailedCompilation> errors = new ArrayList<>();
|
||||
public FlwCompiler(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, ImmutableList<InstanceType<?>> cullingKeys) {
|
||||
this.sources = sources;
|
||||
|
||||
public FlwCompiler(ShaderSources sources) {
|
||||
this.shaderCompiler = ShaderCompiler.builder()
|
||||
this.pipelineKeys = pipelineKeys;
|
||||
this.cullingKeys = cullingKeys;
|
||||
|
||||
shaderCompiler = ShaderCompiler.builder()
|
||||
.errorConsumer(errors::add)
|
||||
.build();
|
||||
|
||||
this.sources = sources;
|
||||
this.vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
|
||||
vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
|
||||
.materialSources(MaterialIndices.getAllVertexShaders())
|
||||
.adapt(FnSignature.ofVoid("flw_materialVertex"))
|
||||
.switchOn(GlslExpr.variable("flw_materialVertexID"))
|
||||
.switchOn(GlslExpr.variable("_flw_materialVertexID"))
|
||||
.build(sources);
|
||||
this.fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
|
||||
fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
|
||||
.materialSources(MaterialIndices.getAllFragmentShaders())
|
||||
.adapt(FnSignature.ofVoid("flw_materialFragment"))
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("bool")
|
||||
.name("flw_discardPredicate")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.literal(false))
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("vec4")
|
||||
.name("flw_fogFilter")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.variable("color"))
|
||||
.switchOn(GlslExpr.variable("flw_materialFragmentID"))
|
||||
.build(sources);
|
||||
this.uniformComponent = UniformComponent.builder(Flywheel.rl("uniforms"))
|
||||
.name("flw_discardPredicate")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.literal(false))
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("vec4")
|
||||
.name("flw_fogFilter")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.variable("color"))
|
||||
.switchOn(GlslExpr.variable("_flw_materialFragmentID"))
|
||||
.build(sources);
|
||||
uniformComponent = UniformComponent.builder(Flywheel.rl("uniforms"))
|
||||
.sources(ShaderUniforms.REGISTRY.getAll()
|
||||
.stream()
|
||||
.map(ShaderUniforms::uniformShader)
|
||||
.toList())
|
||||
.toList())
|
||||
.build(sources);
|
||||
}
|
||||
|
||||
this.pipelineContexts = PipelineContextSet.create();
|
||||
this.cullingContexts = CullingContextSet.create();
|
||||
|
||||
public FlwPrograms compile() {
|
||||
doCompilation();
|
||||
|
||||
finish();
|
||||
|
||||
return new FlwPrograms(pipelinePrograms, cullingPrograms);
|
||||
}
|
||||
|
||||
private void doCompilation() {
|
||||
for (var ctx : pipelineContexts.all()) {
|
||||
compilePipelineContext(ctx);
|
||||
for (var key : pipelineKeys) {
|
||||
GlProgram glProgram = compilePipelineProgram(key);
|
||||
if (glProgram != null) {
|
||||
pipelinePrograms.put(key, glProgram);
|
||||
}
|
||||
}
|
||||
|
||||
for (var ctx : cullingContexts.all()) {
|
||||
compileComputeCuller(ctx);
|
||||
for (var key : cullingKeys) {
|
||||
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() {
|
||||
long compileEnd = System.nanoTime();
|
||||
int programCount = pipelineContexts.size() + InstanceType.REGISTRY.getAll().size();
|
||||
int programCount = pipelineKeys.size() + cullingKeys.size();
|
||||
int shaderCount = shaderCompiler.shaderCount();
|
||||
int errorCount = errors.size();
|
||||
var elapsed = StringUtil.formatTime(compileEnd - compileStart);
|
||||
|
@ -112,94 +198,16 @@ public class FlwCompiler {
|
|||
var details = errors.stream()
|
||||
.map(FailedCompilation::getMessage)
|
||||
.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() {
|
||||
pipelinePrograms.values()
|
||||
.forEach(GlProgram::delete);
|
||||
cullingPrograms.values()
|
||||
.forEach(GlProgram::delete);
|
||||
shaderCompiler.delete();
|
||||
}
|
||||
|
||||
public GlProgram getPipelineProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader, Pipeline pipelineShader) {
|
||||
return pipelinePrograms.get(new PipelineContext(vertexType, instanceType, contextShader, pipelineShader));
|
||||
private static final class Files {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
|
@ -61,6 +61,8 @@ public class MaterialAdapterComponent implements SourceComponent {
|
|||
.body(body -> generateAdapter(body, adaptedFunction));
|
||||
}
|
||||
|
||||
builder.blankLine();
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -41,6 +41,8 @@ public class UniformComponent implements SourceComponent {
|
|||
.name("FLWUniforms")
|
||||
.member("flywheel_uniforms", "flywheel");
|
||||
|
||||
builder.blankLine();
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.backend.engine.indirect.IndirectComponent;
|
||||
import com.jozufozu.flywheel.backend.engine.instancing.InstancedArraysComponent;
|
||||
import com.jozufozu.flywheel.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.lib.pipeline.SimplePipeline;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class Pipelines {
|
||||
public static final SimplePipeline INSTANCED_ARRAYS = SimplePipeline.builder()
|
||||
public final class Pipelines {
|
||||
public static final Pipeline INSTANCED_ARRAYS = Pipeline.builder()
|
||||
.glslVersion(GLSLVersion.V420)
|
||||
.vertex(Files.INSTANCED_ARRAYS_DRAW)
|
||||
.fragment(Files.DRAW_FRAGMENT)
|
||||
.assemblerFactory(InstancedArraysComponent::new)
|
||||
.assembler(InstancedArraysComponent::new)
|
||||
.build();
|
||||
public static final SimplePipeline INDIRECT = SimplePipeline.builder()
|
||||
public static final Pipeline INDIRECT = Pipeline.builder()
|
||||
.glslVersion(GLSLVersion.V460)
|
||||
.vertex(Files.INDIRECT_DRAW)
|
||||
.fragment(Files.DRAW_FRAGMENT)
|
||||
.assemblerFactory(IndirectComponent::new)
|
||||
.assembler(IndirectComponent::new)
|
||||
.build();
|
||||
|
||||
public static final List<Pipeline> ALL = List.of(INSTANCED_ARRAYS, INDIRECT);
|
||||
|
||||
public static void init() {
|
||||
}
|
||||
|
||||
public static class Files {
|
||||
public static final ResourceLocation DRAW_FRAGMENT = Flywheel.rl("pipeline/draw.frag");
|
||||
public static final ResourceLocation INSTANCED_ARRAYS_DRAW = Flywheel.rl("pipeline/instanced_arrays_draw.vert");
|
||||
public static final ResourceLocation INDIRECT_DRAW = Flywheel.rl("pipeline/indirect_draw.vert");
|
||||
public static final ResourceLocation INDIRECT_CULL = Flywheel.rl("pipeline/indirect_cull.glsl");
|
||||
public static final class Files {
|
||||
public static final ResourceLocation INSTANCED_ARRAYS_DRAW = Flywheel.rl("internal/instanced_arrays_draw.vert");
|
||||
public static final ResourceLocation INDIRECT_DRAW = Flywheel.rl("internal/indirect_draw.vert");
|
||||
public static final ResourceLocation DRAW_FRAGMENT = Flywheel.rl("internal/draw.frag");
|
||||
|
||||
public static final ResourceLocation UTIL_TYPES = Flywheel.rl("util/types.glsl");
|
||||
}
|
||||
}
|
|
@ -7,8 +7,8 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.layout.LayoutItem;
|
||||
import com.jozufozu.flywheel.api.pipeline.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.Pipelines;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
|
@ -57,6 +57,7 @@ public class IndirectComponent implements SourceComponent {
|
|||
var builder = new GlslBuilder();
|
||||
builder.define("FlwInstance", STRUCT_NAME);
|
||||
builder.define("FlwPackedInstance", PACKED_STRUCT_NAME);
|
||||
builder.blankLine();
|
||||
|
||||
var packed = builder.struct();
|
||||
builder.blankLine();
|
||||
|
@ -74,11 +75,13 @@ public class IndirectComponent implements SourceComponent {
|
|||
builder.function()
|
||||
.signature(FnSignature.create()
|
||||
.returnType(STRUCT_NAME)
|
||||
.name("flw_unpackInstance")
|
||||
.name("_flw_unpackInstance")
|
||||
.arg(PACKED_STRUCT_NAME, UNPACK_ARG)
|
||||
.build())
|
||||
.body(this::generateUnpackingBody);
|
||||
|
||||
builder.blankLine();
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ import com.jozufozu.flywheel.api.event.RenderStage;
|
|||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.Pipelines;
|
||||
import com.jozufozu.flywheel.backend.compile.FlwCompiler;
|
||||
import com.jozufozu.flywheel.backend.compile.FlwPrograms;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
|
||||
import com.jozufozu.flywheel.backend.engine.UniformBuffer;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.lib.context.Contexts;
|
||||
|
@ -62,8 +62,8 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||
.quads2Tris(2048).glBuffer;
|
||||
setupVertexArray();
|
||||
|
||||
compute = FlwCompiler.INSTANCE.getCullingProgram(instanceType);
|
||||
draw = FlwCompiler.INSTANCE.getPipelineProgram(vertexType, instanceType, Contexts.WORLD, Pipelines.INDIRECT);
|
||||
compute = FlwPrograms.get().getCullingProgram(instanceType);
|
||||
draw = FlwPrograms.get().getPipelineProgram(vertexType, instanceType, Contexts.WORLD, Pipelines.INDIRECT);
|
||||
}
|
||||
|
||||
private void setupVertexArray() {
|
||||
|
|
|
@ -6,7 +6,7 @@ import java.util.List;
|
|||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
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.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.glsl.generate.GlslBlock;
|
||||
|
@ -16,7 +16,7 @@ import com.jozufozu.flywheel.glsl.generate.GlslExpr;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
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 final List<LayoutItem> layoutItems;
|
||||
|
@ -45,13 +45,15 @@ public class InstancedArraysComponent implements SourceComponent {
|
|||
var builder = new GlslBuilder();
|
||||
builder.define("FlwInstance", STRUCT_NAME);
|
||||
|
||||
builder.blankLine();
|
||||
|
||||
int i = baseIndex;
|
||||
for (var field : layoutItems) {
|
||||
builder.vertexInput()
|
||||
.binding(i)
|
||||
.type(field.type()
|
||||
.typeName())
|
||||
.name(field.name() + ATTRIBUTE_SUFFIX);
|
||||
.name(ATTRIBUTE_PREFIX + field.name());
|
||||
|
||||
i += field.type()
|
||||
.attributeCount();
|
||||
|
@ -70,15 +72,17 @@ public class InstancedArraysComponent implements SourceComponent {
|
|||
|
||||
// unpacking function
|
||||
builder.function()
|
||||
.signature(FnSignature.of(STRUCT_NAME, "flw_unpackInstance"))
|
||||
.signature(FnSignature.of(STRUCT_NAME, "_flw_unpackInstance"))
|
||||
.body(this::generateUnpackingBody);
|
||||
|
||||
builder.blankLine();
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void generateUnpackingBody(GlslBlock b) {
|
||||
var fields = layoutItems.stream()
|
||||
.map(it -> new GlslExpr.Variable(it.name() + ATTRIBUTE_SUFFIX))
|
||||
.map(it -> new GlslExpr.Variable(ATTRIBUTE_PREFIX + it.name()))
|
||||
.toList();
|
||||
b.ret(GlslExpr.call(STRUCT_NAME, fields));
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ import com.jozufozu.flywheel.api.instance.Instancer;
|
|||
import com.jozufozu.flywheel.api.model.Model;
|
||||
import com.jozufozu.flywheel.api.task.Plan;
|
||||
import com.jozufozu.flywheel.api.task.TaskExecutor;
|
||||
import com.jozufozu.flywheel.backend.Pipelines;
|
||||
import com.jozufozu.flywheel.backend.compile.FlwCompiler;
|
||||
import com.jozufozu.flywheel.backend.compile.FlwPrograms;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
|
||||
import com.jozufozu.flywheel.backend.engine.AbstractEngine;
|
||||
import com.jozufozu.flywheel.backend.engine.UniformBuffer;
|
||||
import com.jozufozu.flywheel.gl.GlStateTracker;
|
||||
|
@ -106,7 +106,7 @@ public class InstancingEngine extends AbstractEngine {
|
|||
var vertexType = desc.vertexType();
|
||||
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);
|
||||
|
||||
var uniformLocation = program.getUniformLocation("_flw_materialID_instancing");
|
||||
|
|
|
@ -93,7 +93,7 @@ public interface GlslExpr {
|
|||
public String prettyPrint() {
|
||||
var args = this.args.stream()
|
||||
.map(GlslExpr::prettyPrint)
|
||||
.collect(Collectors.joining(","));
|
||||
.collect(Collectors.joining(", "));
|
||||
return name + "(" + args + ")";
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ public class GlslFn implements GlslBuilder.Declaration {
|
|||
return """
|
||||
%s {
|
||||
%s
|
||||
}
|
||||
""".formatted(signature.fullDeclaration(), StringUtil.indent(body.prettyPrint(), 4));
|
||||
}""".formatted(signature.fullDeclaration(), StringUtil.indent(body.prettyPrint(), 4));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.List;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
public class GlslStruct implements GlslBuilder.Declaration {
|
||||
|
||||
|
@ -25,11 +26,11 @@ public class GlslStruct implements GlslBuilder.Declaration {
|
|||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
return """
|
||||
struct %s {
|
||||
%s
|
||||
};
|
||||
""".formatted(name, buildFields().indent(4));
|
||||
};""".formatted(name, StringUtil.indent(buildFields(), 4));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,7 @@ public class GlslUniformBlock implements GlslBuilder.Declaration {
|
|||
return """
|
||||
layout(%s, binding = %d) uniform %s {
|
||||
%s
|
||||
};
|
||||
""".formatted(qualifier, binding, name, StringUtil.indent(formatMembers(), 4));
|
||||
};""".formatted(qualifier, binding, name, StringUtil.indent(formatMembers(), 4));
|
||||
}
|
||||
|
||||
private String formatMembers() {
|
||||
|
|
|
@ -8,7 +8,6 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.jozufozu.flywheel.glsl.span.Span;
|
||||
|
||||
public class ShaderFunction {
|
||||
|
||||
// https://regexr.com/60n3d
|
||||
public static final Pattern PATTERN = Pattern.compile("(\\w+)\\s+(\\w+)\\s*\\(([\\w,\\s]*)\\)\\s*\\{");
|
||||
|
||||
|
@ -86,11 +85,10 @@ public class ShaderFunction {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
String p = parameters.stream()
|
||||
.map(variable -> variable.type)
|
||||
.map(Span::get)
|
||||
.collect(Collectors.joining(","));
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
return type + " " + name + "(" + p + ")";
|
||||
}
|
||||
|
|
|
@ -4,12 +4,9 @@ import java.util.function.BooleanSupplier;
|
|||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.backend.Backend;
|
||||
import com.jozufozu.flywheel.api.backend.BackendManager;
|
||||
import com.jozufozu.flywheel.api.backend.Engine;
|
||||
import com.jozufozu.flywheel.api.pipeline.Pipeline;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -20,14 +17,12 @@ public class SimpleBackend implements Backend {
|
|||
private final Function<LevelAccessor, Engine> engineFactory;
|
||||
private final Supplier<Backend> fallback;
|
||||
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.engineFactory = engineFactory;
|
||||
this.fallback = fallback;
|
||||
this.isSupported = isSupported;
|
||||
this.pipelineShader = pipelineShader;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
|
@ -59,17 +54,11 @@ public class SimpleBackend implements Backend {
|
|||
return isSupported.getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Pipeline pipelineShader() {
|
||||
return pipelineShader;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Component engineMessage;
|
||||
private Function<LevelAccessor, Engine> engineFactory;
|
||||
private Supplier<Backend> fallback = BackendManager::getOffBackend;
|
||||
private BooleanSupplier isSupported;
|
||||
private Pipeline pipelineShader;
|
||||
|
||||
public Builder engineMessage(Component engineMessage) {
|
||||
this.engineMessage = engineMessage;
|
||||
|
@ -91,13 +80,8 @@ public class SimpleBackend implements Backend {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder pipelineShader(Pipeline pipelineShader) {
|
||||
this.pipelineShader = pipelineShader;
|
||||
return this;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ public class StringUtil {
|
|||
|
||||
private static final NumberFormat THREE_DECIMAL_PLACES = new DecimalFormat("#0.000");
|
||||
|
||||
// FIXME: this method should count trailing newlines
|
||||
public static int countLines(String s) {
|
||||
return (int) s.lines()
|
||||
.count();
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#ifdef COMPUTE_SHADER
|
||||
uint flw_objectID;
|
||||
uint flw_batchID;
|
||||
#endif
|
|
@ -13,7 +13,7 @@ in vec4 flw_var1;
|
|||
in vec4 flw_var2;
|
||||
in vec4 flw_var3;
|
||||
|
||||
flat in uint flw_materialFragmentID;
|
||||
flat in uint _flw_materialFragmentID;
|
||||
|
||||
//
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifdef VERTEX_SHADER
|
||||
uint flw_materialVertexID;
|
||||
uint _flw_materialVertexID;
|
||||
|
||||
out vec4 flw_vertexPos;
|
||||
out vec4 flw_vertexColor;
|
||||
|
@ -14,5 +14,5 @@ out vec4 flw_var0;
|
|||
out vec4 flw_var1;
|
||||
out vec4 flw_var2;
|
||||
out vec4 flw_var3;
|
||||
flat out uint flw_materialFragmentID;
|
||||
flat out uint _flw_materialFragmentID;
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
*/
|
|
@ -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.));
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor = vec4(1.0, 1.0, 1.0, 0.2);
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
layout(location = 0) in vec3 worldPos;
|
||||
|
||||
void main() {
|
||||
gl_Position = flywheel.viewProjection * vec4(worldPos, 1.0);
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#define FLW_SUBGROUP_SIZE 32
|
||||
layout(local_size_x = FLW_SUBGROUP_SIZE) in;
|
||||
#use "flywheel:api/cull.glsl"
|
||||
|
||||
#use "flywheel:util/types.glsl"
|
||||
#use "flywheel:pipeline/indirect_draw_command.glsl"
|
||||
#use "flywheel:internal/indirect_draw_command.glsl"
|
||||
|
||||
// populated by instancers
|
||||
layout(std430, binding = 0) restrict readonly buffer ObjectBuffer {
|
||||
|
@ -21,6 +21,9 @@ layout(std430, binding = 3) restrict buffer DrawCommands {
|
|||
MeshDrawCommand drawCommands[];
|
||||
};
|
||||
|
||||
uint flw_objectID;
|
||||
uint flw_batchID;
|
||||
|
||||
// 83 - 27 = 56 spirv instruction results
|
||||
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);
|
||||
|
@ -36,7 +39,7 @@ bool isVisible() {
|
|||
float radius;
|
||||
unpackBoundingSphere(sphere, center, radius);
|
||||
|
||||
FlwInstance object = flw_unpackInstance(objects[flw_objectID]);
|
||||
FlwInstance object = _flw_unpackInstance(objects[flw_objectID]);
|
||||
flw_transformBoundingSphere(object, center, radius);
|
||||
|
||||
return testSphere(center, radius);
|
|
@ -1,5 +1,5 @@
|
|||
#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 {
|
||||
FlwPackedInstance objects[];
|
||||
|
@ -20,10 +20,10 @@ layout(std430, binding = 3) restrict readonly buffer DrawCommands {
|
|||
void main() {
|
||||
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
|
||||
uint batchID = batchIDs[instanceIndex];
|
||||
FlwInstance i = flw_unpackInstance(objects[instanceIndex]);
|
||||
FlwInstance i = _flw_unpackInstance(objects[instanceIndex]);
|
||||
|
||||
flw_materialVertexID = drawCommands[batchID].vertexMaterialID;
|
||||
flw_materialFragmentID = drawCommands[batchID].fragmentMaterialID;
|
||||
_flw_materialVertexID = drawCommands[batchID].vertexMaterialID;
|
||||
_flw_materialFragmentID = drawCommands[batchID].fragmentMaterialID;
|
||||
|
||||
flw_layoutVertex();
|
||||
flw_instanceVertex(i);
|
|
@ -5,10 +5,10 @@ uniform uvec2 _flw_materialID_instancing;
|
|||
void main() {
|
||||
flw_layoutVertex();
|
||||
|
||||
flw_materialVertexID = _flw_materialID_instancing.x;
|
||||
flw_materialFragmentID = _flw_materialID_instancing.y;
|
||||
_flw_materialVertexID = _flw_materialID_instancing.x;
|
||||
_flw_materialFragmentID = _flw_materialID_instancing.y;
|
||||
|
||||
FlwInstance i = flw_unpackInstance();
|
||||
FlwInstance i = _flw_unpackInstance();
|
||||
flw_instanceVertex(i);
|
||||
flw_materialVertex();
|
||||
flw_contextVertex();
|
|
@ -1,12 +1,12 @@
|
|||
struct FLWPackedPlanes {
|
||||
vec4 xyX;// <nx.x, px.x, ny.x, py.x>
|
||||
vec4 xyY;// <nx.y, px.y, ny.y, py.y>
|
||||
vec4 xyZ;// <nx.z, px.z, ny.z, py.z>
|
||||
vec4 xyW;// <nx.w, px.w, ny.w, py.w>
|
||||
vec2 zX;// <nz.x, pz.x>
|
||||
vec2 zY;// <nz.y, pz.y>
|
||||
vec2 zZ;// <nz.z, pz.z>
|
||||
vec2 zW;// <nz.w, pz.w>
|
||||
vec4 xyX; // <nx.x, px.x, ny.x, py.x>
|
||||
vec4 xyY; // <nx.y, px.y, ny.y, py.y>
|
||||
vec4 xyZ; // <nx.z, px.z, ny.z, py.z>
|
||||
vec4 xyW; // <nx.w, px.w, ny.w, py.w>
|
||||
vec2 zX; // <nz.x, pz.x>
|
||||
vec2 zY; // <nz.y, pz.y>
|
||||
vec2 zZ; // <nz.z, pz.z>
|
||||
vec2 zW; // <nz.w, pz.w>
|
||||
};
|
||||
|
||||
struct flywheel_uniforms {
|
||||
|
|
Loading…
Reference in a new issue