Post-post-pre-refactor-refactor actual refactor

- Mark backends as unavailable if their shader compilation failed
- Update command output to notify when a fallback occurs
This commit is contained in:
Jozufozu 2023-04-18 21:28:28 -07:00
parent 4c8e174712
commit 296aa7ca08
9 changed files with 71 additions and 23 deletions

View file

@ -2,6 +2,8 @@ package com.jozufozu.flywheel.backend;
import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.backend.Backend; import com.jozufozu.flywheel.api.backend.Backend;
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
import com.jozufozu.flywheel.backend.engine.batching.BatchingEngine; import com.jozufozu.flywheel.backend.engine.batching.BatchingEngine;
import com.jozufozu.flywheel.backend.engine.indirect.IndirectEngine; import com.jozufozu.flywheel.backend.engine.indirect.IndirectEngine;
import com.jozufozu.flywheel.backend.engine.instancing.InstancingEngine; import com.jozufozu.flywheel.backend.engine.instancing.InstancingEngine;
@ -31,7 +33,7 @@ public class Backends {
.engineFactory(level -> new InstancingEngine(256, Contexts.WORLD)) .engineFactory(level -> new InstancingEngine(256, Contexts.WORLD))
.fallback(() -> Backends.BATCHING) .fallback(() -> Backends.BATCHING)
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance() .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance()
.instancedArraysSupported()) .instancedArraysSupported() && InstancingPrograms.allLoaded())
.register(Flywheel.rl("instancing")); .register(Flywheel.rl("instancing"));
/** /**
@ -42,7 +44,7 @@ public class Backends {
.engineFactory(level -> new IndirectEngine(256)) .engineFactory(level -> new IndirectEngine(256))
.fallback(() -> Backends.INSTANCING) .fallback(() -> Backends.INSTANCING)
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance() .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance()
.supportsIndirect()) .supportsIndirect() && IndirectPrograms.allLoaded())
.register(Flywheel.rl("indirect")); .register(Flywheel.rl("indirect"));
public static void init() { public static void init() {

View file

@ -6,6 +6,7 @@ import java.util.Map;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.glsl.ShaderSources; import com.jozufozu.flywheel.glsl.ShaderSources;
@ -28,7 +29,8 @@ public abstract class AbstractCompiler<K> {
@Nullable @Nullable
protected abstract GlProgram compile(K key); protected abstract GlProgram compile(K key);
public Map<K, GlProgram> compile() { @Nullable
public Map<K, GlProgram> compileAndReportErrors() {
stats.start(); stats.start();
Map<K, GlProgram> out = new HashMap<>(); Map<K, GlProgram> out = new HashMap<>();
for (var key : keys) { for (var key : keys) {
@ -38,6 +40,12 @@ public abstract class AbstractCompiler<K> {
} }
} }
stats.finish(); stats.finish();
if (stats.errored()) {
Flywheel.LOGGER.error(stats.generateErrorLog());
return null;
}
return out; return out;
} }

View file

@ -25,15 +25,13 @@ public class CompilerStats {
var elapsed = StringUtil.formatTime(compileEnd - compileStart); var elapsed = StringUtil.formatTime(compileEnd - compileStart);
Flywheel.LOGGER.info("Compiled " + shaderCount + " shaders (with " + shaderErrors.size() + " compile errors) " + "and " + programCount + " programs (with " + programErrors.size() + " link errors) in " + elapsed); Flywheel.LOGGER.info("Compiled " + shaderCount + " shaders (with " + shaderErrors.size() + " compile errors) " + "and " + programCount + " programs (with " + programErrors.size() + " link errors) in " + elapsed);
} }
// TODO: use this to turn off backends
public boolean errored() { public boolean errored() {
return errored; return errored;
} }
private String generateLog() { public String generateErrorLog() {
return String.join("\n", programErrors) + '\n' + shaderErrors.stream() return String.join("\n", programErrors) + '\n' + shaderErrors.stream()
.map(FailedCompilation::getMessage) .map(FailedCompilation::getMessage)
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));

View file

@ -25,11 +25,18 @@ public class IndirectPrograms {
public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent) { public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent) {
if (instance != null) { if (instance != null) {
instance.delete(); instance.delete();
instance = null;
} }
var indirectCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INDIRECT, uniformComponent); var pipelineCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INDIRECT, uniformComponent);
var cullingCompiler = new CullingCompiler(sources, createCullingKeys(), uniformComponent); var cullingCompiler = new CullingCompiler(sources, createCullingKeys(), uniformComponent);
instance = new IndirectPrograms(indirectCompiler.compile(), cullingCompiler.compile());
indirectCompiler.delete(); var pipelineResult = pipelineCompiler.compileAndReportErrors();
var cullingResult = cullingCompiler.compileAndReportErrors();
if (pipelineResult != null && cullingResult != null) {
instance = new IndirectPrograms(pipelineResult, cullingResult);
}
pipelineCompiler.delete();
cullingCompiler.delete(); cullingCompiler.delete();
} }
@ -46,6 +53,10 @@ public class IndirectPrograms {
return instance; return instance;
} }
public static boolean allLoaded() {
return instance != null;
}
public GlProgram getIndirectProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) { public GlProgram getIndirectProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) {
return pipeline.get(new PipelineProgramKey(vertexType, instanceType, contextShader)); return pipeline.get(new PipelineProgramKey(vertexType, instanceType, contextShader));
} }

View file

@ -23,9 +23,15 @@ public class InstancingPrograms {
public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent) { public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent) {
if (instance != null) { if (instance != null) {
instance.delete(); instance.delete();
instance = null;
} }
var instancingCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INSTANCED_ARRAYS, uniformComponent); var instancingCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INSTANCED_ARRAYS, uniformComponent);
instance = new InstancingPrograms(instancingCompiler.compile()); var result = instancingCompiler.compileAndReportErrors();
if (result != null) {
instance = new InstancingPrograms(result);
}
instancingCompiler.delete(); instancingCompiler.delete();
} }
@ -34,6 +40,10 @@ public class InstancingPrograms {
return instance; return instance;
} }
public static boolean allLoaded() {
return instance != null;
}
public GlProgram get(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) { public GlProgram get(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) {
return pipeline.get(new PipelineProgramKey(vertexType, instanceType, contextShader)); return pipeline.get(new PipelineProgramKey(vertexType, instanceType, contextShader));
} }

View file

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.backend.compile; package com.jozufozu.flywheel.backend.compile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.gl.shader.GlProgram;
@ -8,13 +9,15 @@ public sealed interface LinkResult {
@Nullable @Nullable
default GlProgram unwrap() { default GlProgram unwrap() {
if (this instanceof Success s) {
return s.program();
}
return null; return null;
} }
record Success(GlProgram program, String log) implements LinkResult { record Success(GlProgram program, String log) implements LinkResult {
@Override
@NotNull
public GlProgram unwrap() {
return program;
}
} }
record Failure(String failure) implements LinkResult { record Failure(String failure) implements LinkResult {

View file

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.backend.compile; package com.jozufozu.flywheel.backend.compile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.gl.shader.GlShader; import com.jozufozu.flywheel.gl.shader.GlShader;
@ -7,13 +8,15 @@ import com.jozufozu.flywheel.gl.shader.GlShader;
public sealed interface ShaderResult { public sealed interface ShaderResult {
@Nullable @Nullable
default GlShader unwrap() { default GlShader unwrap() {
if (this instanceof Success s) {
return s.shader();
}
return null; return null;
} }
record Success(GlShader shader, String infoLog) implements ShaderResult { record Success(GlShader shader, String infoLog) implements ShaderResult {
@Override
@NotNull
public GlShader unwrap() {
return shader;
}
} }
record Failure(FailedCompilation failure) implements ShaderResult { record Failure(FailedCompilation failure) implements ShaderResult {

View file

@ -3,6 +3,7 @@ package com.jozufozu.flywheel.config;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import com.jozufozu.flywheel.api.backend.Backend; import com.jozufozu.flywheel.api.backend.Backend;
import com.jozufozu.flywheel.api.backend.BackendManager;
import com.jozufozu.flywheel.lib.uniform.FlwShaderUniforms; import com.jozufozu.flywheel.lib.uniform.FlwShaderUniforms;
import com.mojang.brigadier.Command; import com.mojang.brigadier.Command;
import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType;
@ -60,13 +61,25 @@ public class FlwCommands {
.executes(context -> { .executes(context -> {
LocalPlayer player = Minecraft.getInstance().player; LocalPlayer player = Minecraft.getInstance().player;
if (player != null) { if (player != null) {
Backend backend = context.getArgument("id", Backend.class); Backend requestedBackend = context.getArgument("id", Backend.class);
value.set(Backend.REGISTRY.getIdOrThrow(backend).toString()); var requestedId = Backend.REGISTRY.getIdOrThrow(requestedBackend)
.toString();
Component message = backend.engineMessage(); value.set(requestedId);
player.displayClientMessage(message, false);
// Reload renderers so we can report the backend that we fell back to.
Minecraft.getInstance().levelRenderer.allChanged(); Minecraft.getInstance().levelRenderer.allChanged();
var actualBackend = BackendManager.getBackend();
if (actualBackend == null) {
player.displayClientMessage(new TextComponent("Error switching backends, flywheel disabled"), false);
} else if (actualBackend != requestedBackend) {
player.displayClientMessage(new TextComponent("'" + requestedId + "' not available").withStyle(ChatFormatting.RED), false);
var component = actualBackend.engineMessage();
player.displayClientMessage(component, false);
} else {
Component message = requestedBackend.engineMessage();
player.displayClientMessage(message, false);
}
} }
return Command.SINGLE_SUCCESS; return Command.SINGLE_SUCCESS;
}))); })));

View file

@ -80,10 +80,10 @@ public class ShaderSources {
if (findStack.contains(location)) { if (findStack.contains(location)) {
generateRecursiveImportException(location); generateRecursiveImportException(location);
} }
findStack.add(location); findStack.addLast(location);
} }
private void popFindStack() { private void popFindStack() {
findStack.pop(); findStack.removeLast();
} }
} }