mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-26 06:57:02 +01:00
Still loading
- Catch errors while loading complex source components - Allow compilers to progress when such an error occurs, but don't do any actual compilation. - Tweak error messages. - Make resource locations in shaders default to flywheel namespace - Make PipelineCompiler somehow simpler yet more verbose
This commit is contained in:
parent
b5fad9bd06
commit
98ebe9d95a
21 changed files with 365 additions and 131 deletions
|
@ -12,21 +12,18 @@ import com.jozufozu.flywheel.backend.compile.core.ProgramLinker;
|
|||
import com.jozufozu.flywheel.backend.compile.core.ShaderCompiler;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public abstract class AbstractCompiler<K> {
|
||||
protected final ShaderSources sources;
|
||||
protected final SourceLoader sourceLoader;
|
||||
protected final ShaderCompiler shaderCompiler;
|
||||
protected final ProgramLinker programLinker;
|
||||
private final ImmutableList<K> keys;
|
||||
private final CompilerStats stats = new CompilerStats();
|
||||
|
||||
public AbstractCompiler(ShaderSources sources, ImmutableList<K> keys) {
|
||||
this.sources = sources;
|
||||
this.keys = keys;
|
||||
|
||||
sourceLoader = new SourceLoader(sources, stats);
|
||||
shaderCompiler = new ShaderCompiler(stats);
|
||||
programLinker = new ProgramLinker(stats);
|
||||
}
|
||||
|
@ -34,21 +31,16 @@ public abstract class AbstractCompiler<K> {
|
|||
@Nullable
|
||||
protected abstract GlProgram compile(K key);
|
||||
|
||||
@Nullable
|
||||
protected SourceFile findOrReport(ResourceLocation rl) {
|
||||
var out = sources.find(rl);
|
||||
stats.loadResult(out);
|
||||
return out.unwrap();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Map<K, GlProgram> compileAndReportErrors() {
|
||||
stats.start();
|
||||
Map<K, GlProgram> out = new HashMap<>();
|
||||
for (var key : keys) {
|
||||
GlProgram glProgram = compile(key);
|
||||
if (glProgram != null) {
|
||||
if (out != null && glProgram != null) {
|
||||
out.put(key, glProgram);
|
||||
} else {
|
||||
out = null; // Return null when a preloading error occurs.
|
||||
}
|
||||
}
|
||||
stats.finish();
|
||||
|
|
|
@ -19,21 +19,27 @@ public class CullingCompiler extends AbstractCompiler<InstanceType<?>> {
|
|||
private final UniformComponent uniformComponent;
|
||||
private final SourceFile pipelineCompute;
|
||||
|
||||
public CullingCompiler(ShaderSources sources, ImmutableList<InstanceType<?>> keys, UniformComponent uniformComponent) {
|
||||
public static CullingCompiler create(SourceLoader sourceLoader, ImmutableList<InstanceType<?>> keys, UniformComponent uniformComponent) {
|
||||
var sourceFile = sourceLoader.find(Files.INDIRECT_CULL);
|
||||
|
||||
return new CullingCompiler(sourceLoader.sources, keys, uniformComponent, sourceFile);
|
||||
}
|
||||
|
||||
private CullingCompiler(ShaderSources sources, ImmutableList<InstanceType<?>> keys, UniformComponent uniformComponent, SourceFile pipeline) {
|
||||
super(sources, keys);
|
||||
|
||||
this.uniformComponent = uniformComponent;
|
||||
pipelineCompute = sources.find(Files.INDIRECT_CULL)
|
||||
.unwrap();
|
||||
this.pipelineCompute = pipeline;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected GlProgram compile(InstanceType<?> key) {
|
||||
var instanceAssembly = new IndirectComponent(sources, key);
|
||||
var instance = findOrReport(key.instanceShader());
|
||||
var instanceAssembly = IndirectComponent.create(sourceLoader, key);
|
||||
ResourceLocation rl = key.instanceShader();
|
||||
var instance = sourceLoader.find(rl);
|
||||
|
||||
if (instance == null) {
|
||||
if (instanceAssembly == null || instance == null || uniformComponent == null || pipelineCompute == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.jozufozu.flywheel.api.uniform.ShaderUniforms;
|
|||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.core.CompilerStats;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.glsl.generate.GlslExpr;
|
||||
|
@ -21,21 +22,25 @@ public class FlwPrograms {
|
|||
|
||||
public static void reload(ResourceManager resourceManager) {
|
||||
var sources = new ShaderSources(resourceManager);
|
||||
|
||||
var preLoadStats = new CompilerStats();
|
||||
var loadChecker = new SourceLoader(sources, preLoadStats);
|
||||
|
||||
var pipelineKeys = createPipelineKeys();
|
||||
var uniformComponent = UniformComponent.builder(Flywheel.rl("uniforms"))
|
||||
.sources(ShaderUniforms.REGISTRY.getAll()
|
||||
.stream()
|
||||
.map(ShaderUniforms::uniformShader)
|
||||
.toList())
|
||||
.build(sources);
|
||||
var uniformComponent = createUniformComponent(loadChecker);
|
||||
var vertexMaterialComponent = createVertexMaterialComponent(loadChecker);
|
||||
var fragmentMaterialComponent = createFragmentMaterialComponent(loadChecker);
|
||||
|
||||
var vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
|
||||
.materialSources(MaterialIndices.getAllVertexShaders())
|
||||
.adapt(FnSignature.ofVoid("flw_materialVertex"))
|
||||
.switchOn(GlslExpr.variable("_flw_materialVertexID"))
|
||||
.build(sources);
|
||||
InstancingPrograms.reload(loadChecker, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
IndirectPrograms.reload(loadChecker, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
|
||||
var fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
|
||||
if (preLoadStats.errored()) {
|
||||
Flywheel.LOGGER.error(preLoadStats.generateErrorLog());
|
||||
}
|
||||
}
|
||||
|
||||
private static MaterialAdapterComponent createFragmentMaterialComponent(SourceLoader loadChecker) {
|
||||
return MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
|
||||
.materialSources(MaterialIndices.getAllFragmentShaders())
|
||||
.adapt(FnSignature.ofVoid("flw_materialFragment"))
|
||||
.adapt(FnSignature.create()
|
||||
|
@ -49,10 +54,24 @@ public class FlwPrograms {
|
|||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.variable("color"))
|
||||
.switchOn(GlslExpr.variable("_flw_materialFragmentID"))
|
||||
.build(sources);
|
||||
.build(loadChecker);
|
||||
}
|
||||
|
||||
InstancingPrograms.reload(sources, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
IndirectPrograms.reload(sources, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
private static MaterialAdapterComponent createVertexMaterialComponent(SourceLoader loadChecker) {
|
||||
return MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
|
||||
.materialSources(MaterialIndices.getAllVertexShaders())
|
||||
.adapt(FnSignature.ofVoid("flw_materialVertex"))
|
||||
.switchOn(GlslExpr.variable("_flw_materialVertexID"))
|
||||
.build(loadChecker);
|
||||
}
|
||||
|
||||
private static UniformComponent createUniformComponent(SourceLoader loadChecker) {
|
||||
return UniformComponent.builder(Flywheel.rl("uniforms"))
|
||||
.sources(ShaderUniforms.REGISTRY.getAll()
|
||||
.stream()
|
||||
.map(ShaderUniforms::uniformShader)
|
||||
.toList())
|
||||
.build(loadChecker);
|
||||
}
|
||||
|
||||
private static ImmutableList<PipelineProgramKey> createPipelineKeys() {
|
||||
|
|
|
@ -11,10 +11,9 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
|
|||
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
|
||||
public class IndirectPrograms {
|
||||
private static IndirectPrograms instance;
|
||||
public static IndirectPrograms instance;
|
||||
private final Map<PipelineProgramKey, GlProgram> pipeline;
|
||||
private final Map<InstanceType<?>, GlProgram> culling;
|
||||
|
||||
|
@ -23,13 +22,10 @@ public class IndirectPrograms {
|
|||
this.culling = culling;
|
||||
}
|
||||
|
||||
public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
||||
if (instance != null) {
|
||||
instance.delete();
|
||||
instance = null;
|
||||
}
|
||||
var pipelineCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INDIRECT, vertexMaterialComponent, fragmentMaterialComponent, uniformComponent);
|
||||
var cullingCompiler = new CullingCompiler(sources, createCullingKeys(), uniformComponent);
|
||||
static void reload(SourceLoader loadChecker, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
||||
_delete();
|
||||
var pipelineCompiler = PipelineCompiler.create(loadChecker, Pipelines.INDIRECT, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
var cullingCompiler = CullingCompiler.create(loadChecker, createCullingKeys(), uniformComponent);
|
||||
|
||||
var pipelineResult = pipelineCompiler.compileAndReportErrors();
|
||||
var cullingResult = cullingCompiler.compileAndReportErrors();
|
||||
|
@ -58,6 +54,13 @@ public class IndirectPrograms {
|
|||
return instance != null;
|
||||
}
|
||||
|
||||
private static void _delete() {
|
||||
if (instance != null) {
|
||||
instance.delete();
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
public GlProgram getIndirectProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) {
|
||||
return pipeline.get(new PipelineProgramKey(vertexType, instanceType, contextShader));
|
||||
}
|
||||
|
|
|
@ -11,28 +11,24 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
|
|||
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
|
||||
public class InstancingPrograms {
|
||||
private static InstancingPrograms instance;
|
||||
static InstancingPrograms instance;
|
||||
private final Map<PipelineProgramKey, GlProgram> pipeline;
|
||||
|
||||
public InstancingPrograms(Map<PipelineProgramKey, GlProgram> pipeline) {
|
||||
this.pipeline = pipeline;
|
||||
}
|
||||
|
||||
public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
||||
if (instance != null) {
|
||||
instance.delete();
|
||||
instance = null;
|
||||
}
|
||||
var instancingCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INSTANCED_ARRAYS, vertexMaterialComponent, fragmentMaterialComponent, uniformComponent);
|
||||
static void reload(SourceLoader loadChecker, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
||||
_delete();
|
||||
var instancingCompiler = PipelineCompiler.create(loadChecker, Pipelines.INSTANCED_ARRAYS, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
|
||||
|
||||
var result = instancingCompiler.compileAndReportErrors();
|
||||
|
||||
if (result != null) {
|
||||
instance = new InstancingPrograms(result);
|
||||
}
|
||||
|
||||
instancingCompiler.delete();
|
||||
}
|
||||
|
||||
|
@ -45,6 +41,13 @@ public class InstancingPrograms {
|
|||
return instance != null;
|
||||
}
|
||||
|
||||
static void _delete() {
|
||||
if (instance != null) {
|
||||
instance.delete();
|
||||
instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
public GlProgram get(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) {
|
||||
return pipeline.get(new PipelineProgramKey(vertexType, instanceType, contextShader));
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.compile;
|
|||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.glsl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -19,7 +18,8 @@ public record Pipeline(GLSLVersion glslVersion, ResourceLocation vertexShader, R
|
|||
SourceComponent assemble(InstanceAssemblerContext context);
|
||||
}
|
||||
|
||||
public record InstanceAssemblerContext(ShaderSources sources, VertexType vertexType, InstanceType<?> instanceType) {
|
||||
public record InstanceAssemblerContext(SourceLoader sourceLoader, VertexType vertexType,
|
||||
InstanceType<?> instanceType) {
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
@ -12,27 +14,56 @@ import com.jozufozu.flywheel.gl.shader.GlShader;
|
|||
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class PipelineCompiler extends AbstractCompiler<PipelineProgramKey> {
|
||||
private final Pipeline pipeline;
|
||||
private final MaterialAdapterComponent vertexMaterialComponent;
|
||||
private final MaterialAdapterComponent fragmentMaterialComponent;
|
||||
private final UniformComponent uniformComponent;
|
||||
private final SourceFile pipelineFragment;
|
||||
private final SourceFile pipelineVertex;
|
||||
private final List<SourceComponent> vertexPrelude = new ArrayList<>();
|
||||
private final List<SourceComponent> vertexPostlude = new ArrayList<>();
|
||||
private final List<SourceComponent> fragmentPrelude = new ArrayList<>();
|
||||
private final List<SourceComponent> fragmentPostlude = new ArrayList<>();
|
||||
|
||||
public PipelineCompiler(ShaderSources sources, ImmutableList<PipelineProgramKey> keys, Pipeline pipeline, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent, UniformComponent uniformComponent) {
|
||||
public PipelineCompiler(ShaderSources sources, ImmutableList<PipelineProgramKey> keys, Pipeline pipeline) {
|
||||
super(sources, keys);
|
||||
this.pipeline = pipeline;
|
||||
this.vertexMaterialComponent = vertexMaterialComponent;
|
||||
this.fragmentMaterialComponent = fragmentMaterialComponent;
|
||||
this.uniformComponent = uniformComponent;
|
||||
}
|
||||
|
||||
pipelineFragment = this.sources.find(pipeline.fragmentShader())
|
||||
.unwrap();
|
||||
pipelineVertex = this.sources.find(pipeline.vertexShader())
|
||||
.unwrap();
|
||||
static PipelineCompiler create(SourceLoader sourceLoader, Pipeline pipeline, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
||||
var fragmentPipeline = sourceLoader.find(pipeline.fragmentShader());
|
||||
var vertexPipeline = sourceLoader.find(pipeline.vertexShader());
|
||||
|
||||
return new PipelineCompiler(sourceLoader.sources, pipelineKeys, pipeline).addPrelude(uniformComponent)
|
||||
.addFragmentPrelude(fragmentMaterialComponent)
|
||||
.addVertexPrelude(vertexMaterialComponent)
|
||||
.addFragmentPostlude(fragmentPipeline)
|
||||
.addVertexPostlude(vertexPipeline);
|
||||
}
|
||||
|
||||
public PipelineCompiler addPrelude(SourceComponent component) {
|
||||
addVertexPrelude(component);
|
||||
addFragmentPrelude(component);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PipelineCompiler addVertexPrelude(SourceComponent component) {
|
||||
vertexPrelude.add(component);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PipelineCompiler addVertexPostlude(SourceComponent component) {
|
||||
vertexPostlude.add(component);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PipelineCompiler addFragmentPrelude(SourceComponent component) {
|
||||
fragmentPrelude.add(component);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PipelineCompiler addFragmentPostlude(SourceComponent component) {
|
||||
fragmentPostlude.add(component);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -74,31 +105,54 @@ public class PipelineCompiler extends AbstractCompiler<PipelineProgramKey> {
|
|||
@Nullable
|
||||
private List<SourceComponent> getVertexComponents(PipelineProgramKey key) {
|
||||
var instanceAssembly = pipeline.assembler()
|
||||
.assemble(new Pipeline.InstanceAssemblerContext(sources, key.vertexType(), key.instanceType()));
|
||||
.assemble(new Pipeline.InstanceAssemblerContext(sourceLoader, key.vertexType(), key.instanceType()));
|
||||
|
||||
var layout = findOrReport(key.vertexType()
|
||||
var layout = sourceLoader.find(key.vertexType()
|
||||
.layoutShader());
|
||||
var instance = findOrReport(key.instanceType()
|
||||
var instance = sourceLoader.find(key.instanceType()
|
||||
.instanceShader());
|
||||
var context = findOrReport(key.contextShader()
|
||||
var context = sourceLoader.find(key.contextShader()
|
||||
.vertexShader());
|
||||
|
||||
if (instanceAssembly == null || layout == null || instance == null || context == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ImmutableList.of(uniformComponent, vertexMaterialComponent, instanceAssembly, layout, instance, context, pipelineVertex);
|
||||
// Check this here to do a full dry-run in case of a preloading error.
|
||||
if (vertexPrelude.stream()
|
||||
.anyMatch(Objects::isNull) || vertexPostlude.stream()
|
||||
.anyMatch(Objects::isNull)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ImmutableList.<SourceComponent>builder()
|
||||
.addAll(vertexPrelude)
|
||||
.add(instanceAssembly, layout, instance, context)
|
||||
.addAll(vertexPostlude)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<SourceComponent> getFragmentComponents(PipelineProgramKey key) {
|
||||
var context = findOrReport(key.contextShader()
|
||||
.fragmentShader());
|
||||
ResourceLocation rl = key.contextShader()
|
||||
.fragmentShader();
|
||||
var context = sourceLoader.find(rl);
|
||||
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ImmutableList.of(uniformComponent, fragmentMaterialComponent, context, pipelineFragment);
|
||||
// Check this here to do a full dry-run in case of a preloading error.
|
||||
if (fragmentPrelude.stream()
|
||||
.anyMatch(Objects::isNull) || fragmentPostlude.stream()
|
||||
.anyMatch(Objects::isNull)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ImmutableList.<SourceComponent>builder()
|
||||
.addAll(fragmentPrelude)
|
||||
.add(context)
|
||||
.addAll(fragmentPostlude)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public final class Pipelines {
|
|||
.glslVersion(GLSLVersion.V460)
|
||||
.vertex(Files.INDIRECT_DRAW)
|
||||
.fragment(Files.DRAW_FRAGMENT)
|
||||
.assembler(IndirectComponent::new)
|
||||
.assembler(IndirectComponent::create)
|
||||
.build();
|
||||
|
||||
public static void init() {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.backend.compile.core.CompilerStats;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class SourceLoader {
|
||||
|
||||
public final ShaderSources sources;
|
||||
private final CompilerStats stats;
|
||||
|
||||
public SourceLoader(ShaderSources sources, CompilerStats stats) {
|
||||
this.sources = sources;
|
||||
this.stats = stats;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SourceFile find(ResourceLocation location) {
|
||||
var out = sources.find(location);
|
||||
stats.loadResult(out);
|
||||
return out.unwrap();
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import com.jozufozu.flywheel.api.instance.InstanceType;
|
|||
import com.jozufozu.flywheel.api.layout.LayoutItem;
|
||||
import com.jozufozu.flywheel.backend.compile.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.compile.Pipelines;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.backend.compile.SourceLoader;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
import com.jozufozu.flywheel.glsl.generate.FnSignature;
|
||||
|
@ -29,14 +29,23 @@ public class IndirectComponent implements SourceComponent {
|
|||
private final List<LayoutItem> layoutItems;
|
||||
private final ImmutableList<SourceFile> included;
|
||||
|
||||
public IndirectComponent(Pipeline.InstanceAssemblerContext ctx) {
|
||||
this(ctx.sources(), ctx.instanceType());
|
||||
private IndirectComponent(List<LayoutItem> layoutItems, ImmutableList<SourceFile> included) {
|
||||
this.layoutItems = layoutItems;
|
||||
this.included = included;
|
||||
}
|
||||
|
||||
public IndirectComponent(ShaderSources sources, InstanceType<?> instanceType) {
|
||||
this.layoutItems = instanceType.getLayout().layoutItems;
|
||||
included = ImmutableList.of(sources.find(Pipelines.Files.UTIL_TYPES)
|
||||
.unwrap());
|
||||
public static IndirectComponent create(Pipeline.InstanceAssemblerContext ctx) {
|
||||
return create(ctx.sourceLoader(), ctx.instanceType());
|
||||
}
|
||||
|
||||
public static IndirectComponent create(SourceLoader sourceLoader, InstanceType<?> instanceType) {
|
||||
var util = sourceLoader.find(Pipelines.Files.UTIL_TYPES);
|
||||
|
||||
if (util == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new IndirectComponent(instanceType.getLayout().layoutItems, ImmutableList.of(util));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,13 +5,11 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.backend.compile.SourceLoader;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
import com.jozufozu.flywheel.glsl.generate.FnSignature;
|
||||
|
@ -127,7 +125,7 @@ public class MaterialAdapterComponent implements SourceComponent {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder adapt(FnSignature function, @Nonnull GlslExpr defaultReturn) {
|
||||
public Builder adapt(FnSignature function, GlslExpr defaultReturn) {
|
||||
adaptedFunctions.add(new AdaptedFn(function, defaultReturn));
|
||||
return this;
|
||||
}
|
||||
|
@ -137,23 +135,31 @@ public class MaterialAdapterComponent implements SourceComponent {
|
|||
return this;
|
||||
}
|
||||
|
||||
public MaterialAdapterComponent build(ShaderSources sources) {
|
||||
public MaterialAdapterComponent build(SourceLoader sources) {
|
||||
if (switchArg == null) {
|
||||
throw new NullPointerException("Switch argument must be set");
|
||||
}
|
||||
|
||||
var transformed = ImmutableList.<StringSubstitutionSourceComponent>builder();
|
||||
|
||||
boolean errored = false;
|
||||
int index = 0;
|
||||
for (var rl : materialSources) {
|
||||
SourceFile sourceFile = sources.find(rl)
|
||||
.unwrap();
|
||||
SourceFile sourceFile = sources.find(rl);
|
||||
final int finalIndex = index;
|
||||
var adapterMap = createAdapterMap(adaptedFunctions, fnName -> "_" + fnName + "_" + finalIndex);
|
||||
transformed.add(new StringSubstitutionSourceComponent(sourceFile, adapterMap));
|
||||
if (sourceFile != null) {
|
||||
var adapterMap = createAdapterMap(adaptedFunctions, fnName -> "_" + fnName + "_" + finalIndex);
|
||||
transformed.add(new StringSubstitutionSourceComponent(sourceFile, adapterMap));
|
||||
} else {
|
||||
errored = true;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
if (errored) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new MaterialAdapterComponent(name, switchArg, adaptedFunctions, transformed.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.backend.compile.SourceLoader;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
import com.jozufozu.flywheel.glsl.generate.GlslBuilder;
|
||||
|
@ -63,12 +63,21 @@ public class UniformComponent implements SourceComponent {
|
|||
return this;
|
||||
}
|
||||
|
||||
public UniformComponent build(ShaderSources sources) {
|
||||
public UniformComponent build(SourceLoader sources) {
|
||||
var out = ImmutableList.<SourceFile>builder();
|
||||
|
||||
for (var fileResolution : uniformShaders) {
|
||||
out.add(sources.find(fileResolution)
|
||||
.unwrap());
|
||||
boolean errored = false;
|
||||
for (ResourceLocation uniformShader : uniformShaders) {
|
||||
SourceFile sourceFile = sources.find(uniformShader);
|
||||
if (sourceFile != null) {
|
||||
out.add(sourceFile);
|
||||
} else {
|
||||
errored = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (errored) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new UniformComponent(name, out.build());
|
||||
|
|
|
@ -17,9 +17,9 @@ import com.jozufozu.flywheel.util.StringUtil;
|
|||
public class CompilerStats {
|
||||
private long compileStart;
|
||||
|
||||
private final Set<LoadError> loadErrors = new HashSet<>();
|
||||
private final List<FailedCompilation> shaderErrors = new ArrayList<>();
|
||||
private final List<String> programErrors = new ArrayList<>();
|
||||
private final Set<LoadError> loadErrors = new HashSet<>();
|
||||
|
||||
private boolean errored = false;
|
||||
private int shaderCount = 0;
|
||||
|
@ -41,11 +41,21 @@ public class CompilerStats {
|
|||
}
|
||||
|
||||
public String generateErrorLog() {
|
||||
return """
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
""".formatted(loadErrors(), compileErrors(), linkErrors());
|
||||
String out = "";
|
||||
|
||||
if (!loadErrors.isEmpty()) {
|
||||
out += "\nErrors loading sources:\n" + loadErrors();
|
||||
}
|
||||
|
||||
if (!shaderErrors.isEmpty()) {
|
||||
out += "\nShader compilation errors:\n" + compileErrors();
|
||||
}
|
||||
|
||||
if (!programErrors.isEmpty()) {
|
||||
out += "\nProgram link errors:\n" + linkErrors();
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private String compileErrors() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.jozufozu.flywheel.glsl;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -8,6 +9,7 @@ import com.jozufozu.flywheel.glsl.error.ErrorBuilder;
|
|||
import com.jozufozu.flywheel.glsl.span.Span;
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
|
||||
import net.minecraft.ResourceLocationException;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
sealed public interface LoadError {
|
||||
|
@ -33,7 +35,7 @@ sealed public interface LoadError {
|
|||
@Override
|
||||
public ErrorBuilder generateMessage() {
|
||||
var out = ErrorBuilder.create()
|
||||
.error("could not load shader due to errors in included files")
|
||||
.error("could not load \"" + location + "\"")
|
||||
.pointAtFile(location);
|
||||
|
||||
for (var innerError : innerErrors) {
|
||||
|
@ -48,11 +50,24 @@ sealed public interface LoadError {
|
|||
}
|
||||
|
||||
record IOError(ResourceLocation location, IOException exception) implements LoadError {
|
||||
@Override
|
||||
public ErrorBuilder generateMessage() {
|
||||
if (exception instanceof FileNotFoundException) {
|
||||
return ErrorBuilder.create()
|
||||
.error("\"" + location + "\" was not found");
|
||||
} else {
|
||||
return ErrorBuilder.create()
|
||||
.error("could not load \"" + location + "\" due to an IO error")
|
||||
.note(exception.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record MalformedInclude(ResourceLocationException exception) implements LoadError {
|
||||
@Override
|
||||
public ErrorBuilder generateMessage() {
|
||||
return ErrorBuilder.create()
|
||||
.error("could not load \"" + location + "\" due to an IO error")
|
||||
.note(exception.getMessage());
|
||||
.error(exception.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
|
||||
|
@ -38,7 +36,7 @@ public class ShaderSources {
|
|||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@NotNull
|
||||
public LoadResult find(ResourceLocation location) {
|
||||
if (findStack.contains(location)) {
|
||||
// Make a copy of the find stack with the offending location added on top to show the full path.
|
||||
|
@ -66,7 +64,7 @@ public class ShaderSources {
|
|||
return out;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@NotNull
|
||||
protected LoadResult load(ResourceLocation loc) {
|
||||
try {
|
||||
var resource = manager.getResource(ResourceUtil.prefixed(SHADER_DIR, loc));
|
||||
|
|
|
@ -18,7 +18,9 @@ import com.jozufozu.flywheel.glsl.parse.ShaderStruct;
|
|||
import com.jozufozu.flywheel.glsl.span.Span;
|
||||
import com.jozufozu.flywheel.glsl.span.StringSpan;
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
||||
import net.minecraft.ResourceLocationException;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
|
@ -79,7 +81,17 @@ public class SourceFile implements SourceComponent {
|
|||
if (!seen.add(string)) {
|
||||
continue;
|
||||
}
|
||||
var result = sourceFinder.find(new ResourceLocation(string));
|
||||
|
||||
ResourceLocation location;
|
||||
try {
|
||||
location = ResourceUtil.defaultToFlywheelNamespace(string);
|
||||
} catch (ResourceLocationException e) {
|
||||
failures.add(Pair.of(fileSpan, new LoadError.MalformedInclude(e)));
|
||||
continue;
|
||||
}
|
||||
|
||||
var result = sourceFinder.find(location);
|
||||
|
||||
if (result instanceof LoadResult.Success s) {
|
||||
included.add(s.unwrap());
|
||||
} else if (result instanceof LoadResult.Failure e) {
|
||||
|
@ -212,5 +224,4 @@ public class SourceFile implements SourceComponent {
|
|||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,10 +5,22 @@ import java.util.regex.Pattern;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class ResourceUtil {
|
||||
|
||||
// Match the complement of alphanumeric and underscore.
|
||||
private static final Pattern UNSAFE_CHARS = Pattern.compile("[^a-zA-Z0-9_]");
|
||||
|
||||
public static ResourceLocation defaultToFlywheelNamespace(String location) {
|
||||
String[] astring = new String[]{"flywheel", location};
|
||||
int i = location.indexOf(':');
|
||||
if (i >= 0) {
|
||||
astring[1] = location.substring(i + 1);
|
||||
if (i >= 1) {
|
||||
astring[0] = location.substring(0, i);
|
||||
}
|
||||
}
|
||||
|
||||
return new ResourceLocation(astring[0], astring[1]);
|
||||
}
|
||||
|
||||
public static ResourceLocation subPath(ResourceLocation root, String subPath) {
|
||||
return new ResourceLocation(root.getNamespace(), root.getPath() + subPath);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.glsl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -26,7 +26,7 @@ public class MockShaderSources extends ShaderSources {
|
|||
protected LoadResult load(ResourceLocation loc) {
|
||||
var maybeFound = sources.get(loc);
|
||||
if (maybeFound == null) {
|
||||
return new LoadResult.Failure(new LoadError.IOError(loc, new IOException("Mock source not found")));
|
||||
return new LoadResult.Failure(new LoadError.IOError(loc, new FileNotFoundException(loc.toString())));
|
||||
}
|
||||
return SourceFile.parse(this, loc, maybeFound);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import java.util.List;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.glsl.error.ErrorBuilder;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
|
@ -30,14 +29,6 @@ public class TestBase {
|
|||
return assertInstanceOf(clazz, failure.error());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ErrorBuilder assertErrorAndGetMessage(MockShaderSources sources, ResourceLocation loc) {
|
||||
var result = sources.find(loc);
|
||||
var failure = assertInstanceOf(LoadResult.Failure.class, result);
|
||||
return failure.error()
|
||||
.generateMessage();
|
||||
}
|
||||
|
||||
static <E extends LoadError> E assertSimpleNestedErrorsToDepth(Class<E> finalErrType, LoadError err, int depth) {
|
||||
var includeError = assertInstanceOf(LoadError.IncludeError.class, err);
|
||||
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package com.jozufozu.flywheel.glsl;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.jozufozu.flywheel.glsl.error.ErrorBuilder;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class TestErrorMessages extends TestBase {
|
||||
@BeforeAll
|
||||
static void disableConsoleColors() {
|
||||
|
@ -20,14 +24,49 @@ public class TestErrorMessages extends TestBase {
|
|||
#include "flywheel:b.glsl"
|
||||
""");
|
||||
|
||||
var aErr = assertErrorAndGetMessage(sources, FLW_A);
|
||||
|
||||
assertEquals("""
|
||||
error: could not load shader due to errors in included files
|
||||
assertErrorMatches("""
|
||||
error: could not load "flywheel:a.glsl"
|
||||
--> flywheel:a.glsl
|
||||
1 | #include "flywheel:b.glsl"
|
||||
| ^^^^^^^^^^^^^^^
|
||||
| error: could not load "flywheel:b.glsl" due to an IO error
|
||||
| note: Mock source not found""", aErr.build());
|
||||
| error: "flywheel:b.glsl" was not found
|
||||
""", sources, FLW_A);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNestedIncludeMsg() {
|
||||
var sources = new MockShaderSources();
|
||||
sources.add(FLW_A, """
|
||||
#include "flywheel:b.glsl"
|
||||
""");
|
||||
sources.add(FLW_B, """
|
||||
#include "flywheel:c.glsl"
|
||||
""");
|
||||
|
||||
assertErrorMatches("""
|
||||
error: could not load "flywheel:a.glsl"
|
||||
--> flywheel:a.glsl
|
||||
1 | #include "flywheel:b.glsl"
|
||||
| ^^^^^^^^^^^^^^^
|
||||
| error: could not load "flywheel:b.glsl"
|
||||
| --> flywheel:b.glsl
|
||||
| 1 | #include "flywheel:c.glsl"
|
||||
| | ^^^^^^^^^^^^^^^
|
||||
| | error: "flywheel:c.glsl" was not found
|
||||
""", sources, FLW_A);
|
||||
}
|
||||
|
||||
public static void assertErrorMatches(String expected, MockShaderSources sources, ResourceLocation loc) {
|
||||
var message = assertErrorAndGetMessage(sources, loc).build();
|
||||
|
||||
assertEquals(expected.trim(), message.trim());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ErrorBuilder assertErrorAndGetMessage(MockShaderSources sources, ResourceLocation loc) {
|
||||
var result = sources.find(loc);
|
||||
var failure = assertInstanceOf(LoadResult.Failure.class, result);
|
||||
return failure.error()
|
||||
.generateMessage();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,21 @@ public class TestShaderSourceLoading extends TestBase {
|
|||
findAndAssertError(LoadError.IOError.class, sources, FLW_A);
|
||||
}
|
||||
|
||||
/**
|
||||
* #includes should default to the flywheel namespace since minecraft shaders aren't relevant.
|
||||
*/
|
||||
@Test
|
||||
void testNoNamespace() {
|
||||
var sources = new MockShaderSources();
|
||||
sources.add(FLW_A, """
|
||||
#include "b.glsl"
|
||||
""");
|
||||
sources.add(FLW_B, "");
|
||||
|
||||
findAndAssertSuccess(sources, FLW_A);
|
||||
sources.assertLoaded(FLW_B);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMissingInclude() {
|
||||
var sources = new MockShaderSources();
|
||||
|
@ -38,6 +53,21 @@ public class TestShaderSourceLoading extends TestBase {
|
|||
assertEquals(FLW_B, ioErr.location());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMalformedInclude() {
|
||||
var sources = new MockShaderSources();
|
||||
sources.add(FLW_A, """
|
||||
#include "evil - wow"
|
||||
""");
|
||||
|
||||
var aErr = findAndAssertError(LoadError.IncludeError.class, sources, FLW_A);
|
||||
|
||||
var malformedInclude = assertSimpleNestedErrorsToDepth(LoadError.MalformedInclude.class, aErr, 1);
|
||||
var message = malformedInclude.exception()
|
||||
.getMessage();
|
||||
assertEquals("Non [a-z0-9/._-] character in path of location: flywheel:evil - wow", message);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBasicInclude() {
|
||||
var sources = new MockShaderSources();
|
||||
|
|
Loading…
Reference in a new issue