A shady API

- Remove storage qualifiers and compile guards from api sources.
- Replace api sources with empty stubs by poisoning the ShaderSources
  cache.
- Pipelines redefine the shader api and are inserted at the top of a
  compilation.
- Declare shader api methods in api sources.
- Fix crash in ErrorBuilder#pointAtLine
This commit is contained in:
Jozufozu 2023-12-01 00:23:34 -08:00
parent b947470089
commit d730ab02a9
18 changed files with 243 additions and 91 deletions

View file

@ -59,4 +59,28 @@ public class CompilationHarness<K> {
public interface KeyCompiler<K> {
@Nullable GlProgram compile(K key, SourceLoader loader, ShaderCompiler shaderCompiler, ProgramLinker programLinker);
}
public static class Builder<K> {
private final ShaderSources sources;
private ImmutableList<K> keys;
private KeyCompiler<K> compiler;
public Builder(ShaderSources sources) {
this.sources = sources;
}
public Builder<K> keys(ImmutableList<K> keys) {
this.keys = keys;
return this;
}
public Builder<K> compiler(KeyCompiler<K> compiler) {
this.compiler = compiler;
return this;
}
public CompilationHarness<K> build() {
return new CompilationHarness<>(sources, keys, compiler);
}
}
}

View file

@ -19,19 +19,34 @@ import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.gl.shader.GlShader;
import com.jozufozu.flywheel.gl.shader.ShaderType;
import com.jozufozu.flywheel.glsl.GLSLVersion;
import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent;
import net.minecraft.resources.ResourceLocation;
public class Compile {
public static <K> ShaderCompilerBuilder<K> shader(GLSLVersion glslVersion, ShaderType shaderType) {
/**
* A typed provider for shader compiler builders.
* <br>
* This could just be a static utility class, but creating an instance of Compile
* and calling the functors on it prevents you from having to specify the key type everywhere.
* <br>
* Consider {@code Compile.<PipelineKey>shader(...)} vs {@code PIPELINE.shader(...)}
*
* @param <K> The type of the key used to compile shaders.
*/
public class Compile<K> {
public ShaderCompilerBuilder<K> shader(GLSLVersion glslVersion, ShaderType shaderType) {
return new ShaderCompilerBuilder<>(glslVersion, shaderType);
}
public static <K> ProgramLinkBuilder<K> program() {
public ProgramLinkBuilder<K> program() {
return new ProgramLinkBuilder<>();
}
public CompilationHarness.Builder<K> harness(ShaderSources sources) {
return new CompilationHarness.Builder<>(sources);
}
public static class ProgramLinkBuilder<K> implements CompilationHarness.KeyCompiler<K> {
private final Map<ShaderType, ShaderCompilerBuilder<K>> compilers = new EnumMap<>(ShaderType.class);
private BiConsumer<K, GlProgram> onLink = (k, p) -> {

View file

@ -1,5 +1,7 @@
package com.jozufozu.flywheel.backend.compile;
import java.util.List;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.context.Context;
@ -22,7 +24,8 @@ public class FlwPrograms {
}
public static void reload(ResourceManager resourceManager) {
var sources = new ShaderSources(resourceManager);
var empty = List.of(Flywheel.rl("api/fragment.glsl"), Flywheel.rl("api/vertex.glsl"));
var sources = new ShaderSources(resourceManager, empty);
var preLoadStats = new CompilerStats();
var loadChecker = new SourceLoader(sources, preLoadStats);

View file

@ -22,6 +22,7 @@ import net.minecraft.resources.ResourceLocation;
public class IndirectPrograms {
public static IndirectPrograms instance;
private static final Compile<InstanceType<?>> CULL = new Compile<>();
private final Map<PipelineProgramKey, GlProgram> pipeline;
private final Map<InstanceType<?>, GlProgram> culling;
@ -74,16 +75,17 @@ public class IndirectPrograms {
}
private static CompilationHarness<InstanceType<?>> createCullingCompiler(UniformComponent uniformComponent, ShaderSources sources) {
return new CompilationHarness<>(sources, createCullingKeys(), Compile.<InstanceType<?>>program()
.link(Compile.<InstanceType<?>>shader(GLSLVersion.V460, ShaderType.COMPUTE)
.define("FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
.withComponent(uniformComponent)
.withComponent(IndirectComponent::create)
.withResource(InstanceType::instanceShader)
.withResource(Files.INDIRECT_CULL))
.then((InstanceType<?> key, GlProgram program) -> {
program.setUniformBlockBinding("FLWUniforms", 0);
}));
return CULL.harness(sources)
.keys(createCullingKeys())
.compiler(CULL.program()
.link(CULL.shader(GLSLVersion.V460, ShaderType.COMPUTE)
.define("FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
.withComponent(uniformComponent)
.withComponent(IndirectComponent::create)
.withResource(Files.INDIRECT_CULL)
.withResource(InstanceType::instanceShader))
.then((key, program) -> program.setUniformBlockBinding("FLWUniforms", 0)))
.build();
}
public GlProgram getIndirectProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) {

View file

@ -2,12 +2,12 @@ package com.jozufozu.flywheel.backend.compile;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.compile.Pipeline.InstanceAssembler;
import com.jozufozu.flywheel.glsl.GLSLVersion;
import com.jozufozu.flywheel.glsl.SourceComponent;
import net.minecraft.resources.ResourceLocation;
// TODO: move shader api redefinition to a separate file?
public record Pipeline(GLSLVersion glslVersion, ResourceLocation vertexShader, ResourceLocation fragmentShader, InstanceAssembler assembler) {
@FunctionalInterface
public interface InstanceAssembler {

View file

@ -3,36 +3,40 @@ package com.jozufozu.flywheel.backend.compile;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.gl.shader.ShaderType;
import com.jozufozu.flywheel.glsl.ShaderSources;
public class PipelineCompiler {
private static final Compile<PipelineProgramKey> PIPELINE = new Compile<>();
static CompilationHarness<PipelineProgramKey> create(ShaderSources sources, Pipeline pipeline, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
return new CompilationHarness<>(sources, pipelineKeys, Compile.<PipelineProgramKey>program()
.link(Compile.<PipelineProgramKey>shader(pipeline.glslVersion(), ShaderType.VERTEX)
.withComponent(uniformComponent)
.withComponent(vertexMaterialComponent)
.withComponent(key -> pipeline.assembler()
.assemble(new Pipeline.InstanceAssemblerContext(key.vertexType(), key.instanceType())))
.withResource(key -> key.vertexType()
.layoutShader())
.withResource(key -> key.instanceType()
.instanceShader())
.withResource(key -> key.contextShader()
.vertexShader())
.withResource(pipeline.vertexShader()))
.link(Compile.<PipelineProgramKey>shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
.enableExtension("GL_ARB_conservative_depth")
.withComponent(uniformComponent)
.withComponent(fragmentMaterialComponent)
.withResource(key -> key.contextShader()
.fragmentShader())
.withResource(pipeline.fragmentShader()))
.then((PipelineProgramKey key, GlProgram program) -> {
key.contextShader()
.onProgramLink(program);
program.setUniformBlockBinding("FLWUniforms", 0);
}));
return PIPELINE.harness(sources)
.keys(pipelineKeys)
.compiler(PIPELINE.program()
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.VERTEX)
.withComponent(uniformComponent)
.withComponent(key -> pipeline.assembler()
.assemble(new Pipeline.InstanceAssemblerContext(key.vertexType(), key.instanceType())))
.withResource(pipeline.vertexShader())
.withComponent(vertexMaterialComponent)
.withResource(key -> key.vertexType()
.layoutShader())
.withResource(key -> key.instanceType()
.instanceShader())
.withResource(key -> key.contextShader()
.vertexShader()))
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
.enableExtension("GL_ARB_conservative_depth")
.withComponent(uniformComponent)
.withResource(pipeline.fragmentShader())
.withComponent(fragmentMaterialComponent)
.withResource(key -> key.contextShader()
.fragmentShader()))
.then((key, program) -> {
key.contextShader()
.onProgramLink(program);
program.setUniformBlockBinding("FLWUniforms", 0);
}))
.build();
}
}

View file

@ -10,7 +10,7 @@ import net.minecraft.resources.ResourceLocation;
public class SourceLoader {
public final ShaderSources sources;
private final ShaderSources sources;
private final CompilerStats stats;
public SourceLoader(ShaderSources sources, CompilerStats stats) {

View file

@ -35,6 +35,18 @@ public class ShaderSources {
this.manager = manager;
}
public ShaderSources(ResourceManager manager, Map<ResourceLocation, LoadResult> preloadCache) {
this.manager = manager;
cache.putAll(preloadCache);
}
public ShaderSources(ResourceManager manager, List<ResourceLocation> preloadEmpty) {
this.manager = manager;
for (ResourceLocation rl : preloadEmpty) {
cache.put(rl, SourceFile.empty(rl));
}
}
@NotNull
public LoadResult find(ResourceLocation location) {
if (findStack.contains(location)) {

View file

@ -67,6 +67,10 @@ public class SourceFile implements SourceComponent {
this.finalSource = finalSource;
}
public static LoadResult empty(ResourceLocation name) {
return new LoadResult.Success(new SourceFile(name, new SourceLines(name, ""), ImmutableMap.of(), ImmutableMap.of(), ImmutableList.of(), ImmutableMap.of(), ImmutableList.of(), ""));
}
public static LoadResult parse(ShaderSources sourceFinder, ResourceLocation name, String stringSource) {
var source = new SourceLines(name, stringSource);

View file

@ -122,7 +122,7 @@ public class ErrorBuilder {
public ErrorBuilder pointAtLine(SourceLines lines, int spanLine, int ctxLines, int firstCol, int lastCol) {
int firstLine = Math.max(0, spanLine - ctxLines);
int lastLine = Math.min(lines.count(), spanLine + ctxLines);
int lastLine = Math.min(lines.count() - 1, spanLine + ctxLines);
for (int i = firstLine; i <= lastLine; i++) {

View file

@ -1,22 +1,16 @@
#ifdef FRAGMENT_SHADER
in vec4 flw_vertexPos;
in vec4 flw_vertexColor;
in vec2 flw_vertexTexCoord;
flat in ivec2 flw_vertexOverlay;
in vec2 flw_vertexLight;
in vec3 flw_vertexNormal;
/*const*/ vec4 flw_vertexPos;
/*const*/ vec4 flw_vertexColor;
/*const*/ vec2 flw_vertexTexCoord;
/*const*/ ivec2 flw_vertexOverlay;
/*const*/ vec2 flw_vertexLight;
/*const*/ vec3 flw_vertexNormal;
in float flw_distance;
/*const*/ float flw_distance;
in vec4 flw_var0;
in vec4 flw_var1;
in vec4 flw_var2;
in vec4 flw_var3;
flat in uint _flw_materialFragmentID;
flat in uint _flw_packedMaterialProperties;
//
/*const*/ vec4 flw_var0;
/*const*/ vec4 flw_var1;
/*const*/ vec4 flw_var2;
/*const*/ vec4 flw_var3;
/*const*/ vec4 flw_sampleColor;
@ -24,13 +18,11 @@ vec4 flw_fragColor;
ivec2 flw_fragOverlay;
vec2 flw_fragLight;
/*
* Must be implemented by materials.
*/
// To be implemented by material shaders.
vec4 flw_fogFilter(vec4 color);
/*
* Must be implemented by materials.
*/
bool flw_discardPredicate(vec4 finalColor);
#endif
void flw_materialFragment();
// To be implemented by the context shader.
void flw_initFragment();
void flw_contextFragment();

View file

@ -1,19 +1,27 @@
#ifdef VERTEX_SHADER
uint _flw_materialVertexID;
vec4 flw_vertexPos;
vec4 flw_vertexColor;
vec2 flw_vertexTexCoord;
ivec2 flw_vertexOverlay;
vec2 flw_vertexLight;
vec3 flw_vertexNormal;
out vec4 flw_vertexPos;
out vec4 flw_vertexColor;
out vec2 flw_vertexTexCoord;
flat out ivec2 flw_vertexOverlay;
out vec2 flw_vertexLight;
out vec3 flw_vertexNormal;
float flw_distance;
out float flw_distance;
vec4 flw_var0;
vec4 flw_var1;
vec4 flw_var2;
vec4 flw_var3;
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_packedMaterialProperties;
#endif
// To be implemented by the layout shader.
void flw_layoutVertex();
// To be implemented by the instance shader.
void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius);
void flw_instanceVertex(FlwInstance i);
// To be implemented by material shaders.
void flw_materialVertex();
// To be implemented by the context shader.
void flw_initVertex();
void flw_contextVertex();

View file

@ -9,11 +9,9 @@ void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout floa
center = rotateVertexByQuat(center - pivot, rotation) + pivot + pos;
}
#ifdef VERTEX_SHADER
void flw_instanceVertex(in FlwInstance i) {
flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.position, 1.0);
flw_vertexNormal = rotateVertexByQuat(flw_vertexNormal, i.rotation);
flw_vertexColor = i.color;
flw_vertexLight = i.light / 15.0;
}
#endif

View file

@ -8,11 +8,9 @@ void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout floa
radius *= scale;
}
#ifdef VERTEX_SHADER
void flw_instanceVertex(in FlwInstance i) {
flw_vertexPos = i.pose * flw_vertexPos;
flw_vertexNormal = i.normal * flw_vertexNormal;
flw_vertexColor = i.color;
flw_vertexLight = i.light / 15.0;
}
#endif

View file

@ -1,4 +1,33 @@
#include "flywheel:api/fragment.glsl"
in vec4 flw_vertexPos;
in vec4 flw_vertexColor;
in vec2 flw_vertexTexCoord;
flat in ivec2 flw_vertexOverlay;
in vec2 flw_vertexLight;
in vec3 flw_vertexNormal;
in float flw_distance;
in vec4 flw_var0;
in vec4 flw_var1;
in vec4 flw_var2;
in vec4 flw_var3;
flat in uint _flw_materialFragmentID;
flat in uint _flw_packedMaterialProperties;
vec4 flw_sampleColor;
vec4 flw_fragColor;
ivec2 flw_fragOverlay;
vec2 flw_fragLight;
vec4 flw_fogFilter(vec4 color);
bool flw_discardPredicate(vec4 finalColor);
void flw_initFragment();
void flw_materialFragment();
void flw_contextFragment();
void main() {
flw_initFragment();

View file

@ -2,6 +2,21 @@ layout(local_size_x = FLW_SUBGROUP_SIZE) in;
#include "flywheel:internal/indirect_draw_command.glsl"
// need to add stubs so the instance shader compiles.
vec4 flw_vertexPos;
vec4 flw_vertexColor;
vec2 flw_vertexTexCoord;
ivec2 flw_vertexOverlay;
vec2 flw_vertexLight;
vec3 flw_vertexNormal;
float flw_distance;
vec4 flw_var0;
vec4 flw_var1;
vec4 flw_var2;
vec4 flw_var3;
void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius);
struct Object {
uint batchID;
FlwPackedInstance instance;

View file

@ -1,6 +1,23 @@
#include "flywheel:api/vertex.glsl"
#include "flywheel:internal/indirect_draw_command.glsl"
out vec4 flw_vertexPos;
out vec4 flw_vertexColor;
out vec2 flw_vertexTexCoord;
flat out ivec2 flw_vertexOverlay;
out vec2 flw_vertexLight;
out vec3 flw_vertexNormal;
out float flw_distance;
out vec4 flw_var0;
out vec4 flw_var1;
out vec4 flw_var2;
out vec4 flw_var3;
uint _flw_materialVertexID;
flat out uint _flw_materialFragmentID;
flat out uint _flw_packedMaterialProperties;
struct Object {
uint batchID;
FlwPackedInstance instance;
@ -19,6 +36,14 @@ layout(std430, binding = 2) restrict readonly buffer DrawCommands {
MeshDrawCommand drawCommands[];
};
FlwInstance _flw_unpackInstance(FlwPackedInstance i);
void flw_layoutVertex();
void flw_initVertex();
void flw_instanceVertex(FlwInstance i);
void flw_materialVertex();
void flw_contextVertex();
void main() {
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
uint batchID = objects[instanceIndex].batchID;

View file

@ -1,7 +1,30 @@
#include "flywheel:api/vertex.glsl"
out vec4 flw_vertexPos;
out vec4 flw_vertexColor;
out vec2 flw_vertexTexCoord;
flat out ivec2 flw_vertexOverlay;
out vec2 flw_vertexLight;
out vec3 flw_vertexNormal;
out float flw_distance;
out vec4 flw_var0;
out vec4 flw_var1;
out vec4 flw_var2;
out vec4 flw_var3;
uint _flw_materialVertexID;
flat out uint _flw_materialFragmentID;
flat out uint _flw_packedMaterialProperties;
uniform uvec3 _flw_material_instancing;
void flw_layoutVertex();
void flw_initVertex();
void flw_instanceVertex(FlwInstance i);
void flw_materialVertex();
void flw_contextVertex();
void main() {
_flw_materialVertexID = _flw_material_instancing.x;
_flw_materialFragmentID = _flw_material_instancing.y;