mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-09 11:45:01 +01:00
Errors galore
- Make everything in the compiler chain's results not null - Throw errors immediately when encountered - Log error messages when falling back - Do not eagerly grab utility programs in IndirectDrawManager so we can actually catch errors and fall back - Remove CompilerStats
This commit is contained in:
parent
11ce4ac185
commit
ef05f7d3fd
16 changed files with 103 additions and 216 deletions
|
@ -6,7 +6,6 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.Flywheel;
|
import dev.engine_room.flywheel.api.Flywheel;
|
||||||
import dev.engine_room.flywheel.backend.compile.core.CompilerStats;
|
|
||||||
import dev.engine_room.flywheel.backend.glsl.ShaderSources;
|
import dev.engine_room.flywheel.backend.glsl.ShaderSources;
|
||||||
import dev.engine_room.flywheel.backend.glsl.SourceComponent;
|
import dev.engine_room.flywheel.backend.glsl.SourceComponent;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
@ -29,17 +28,9 @@ public final class FlwPrograms {
|
||||||
|
|
||||||
var sources = new ShaderSources(resourceManager);
|
var sources = new ShaderSources(resourceManager);
|
||||||
SOURCES = sources;
|
SOURCES = sources;
|
||||||
var stats = new CompilerStats("ubershaders");
|
|
||||||
|
|
||||||
var fragmentComponentsHeader = sources.get(COMPONENTS_HEADER_FRAG);
|
var fragmentComponentsHeader = sources.get(COMPONENTS_HEADER_FRAG);
|
||||||
|
|
||||||
// TODO: separate compilation for cutout OFF, but keep the rest uber'd?
|
|
||||||
if (stats.errored() || fragmentComponentsHeader == null) {
|
|
||||||
// Probably means the shader sources are missing.
|
|
||||||
stats.emitErrorLog();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<SourceComponent> vertexComponents = List.of();
|
List<SourceComponent> vertexComponents = List.of();
|
||||||
List<SourceComponent> fragmentComponents = List.of(fragmentComponentsHeader);
|
List<SourceComponent> fragmentComponents = List.of(fragmentComponentsHeader);
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,6 @@ public class InstancingPrograms extends AtomicReferenceCounted {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INSTANCING, vertexComponents, fragmentComponents, EXTENSIONS);
|
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INSTANCING, vertexComponents, fragmentComponents, EXTENSIONS);
|
||||||
InstancingPrograms newInstance = new InstancingPrograms(pipelineCompiler);
|
InstancingPrograms newInstance = new InstancingPrograms(pipelineCompiler);
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,6 @@ package dev.engine_room.flywheel.backend.compile.core;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.backend.gl.GlObject;
|
import dev.engine_room.flywheel.backend.gl.GlObject;
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||||
import dev.engine_room.flywheel.backend.glsl.ShaderSources;
|
import dev.engine_room.flywheel.backend.glsl.ShaderSources;
|
||||||
|
@ -14,16 +12,14 @@ public class CompilationHarness<K> {
|
||||||
private final KeyCompiler<K> compiler;
|
private final KeyCompiler<K> compiler;
|
||||||
private final ShaderCache shaderCache;
|
private final ShaderCache shaderCache;
|
||||||
private final ProgramLinker programLinker;
|
private final ProgramLinker programLinker;
|
||||||
private final CompilerStats stats;
|
|
||||||
|
|
||||||
private final Map<K, GlProgram> programs = new HashMap<>();
|
private final Map<K, GlProgram> programs = new HashMap<>();
|
||||||
|
|
||||||
public CompilationHarness(String marker, ShaderSources sources, KeyCompiler<K> compiler) {
|
public CompilationHarness(String marker, ShaderSources sources, KeyCompiler<K> compiler) {
|
||||||
this.sources = sources;
|
this.sources = sources;
|
||||||
this.compiler = compiler;
|
this.compiler = compiler;
|
||||||
stats = new CompilerStats(marker);
|
shaderCache = new ShaderCache();
|
||||||
shaderCache = new ShaderCache(stats);
|
programLinker = new ProgramLinker();
|
||||||
programLinker = new ProgramLinker(stats);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlProgram get(K key) {
|
public GlProgram get(K key) {
|
||||||
|
@ -31,14 +27,7 @@ public class CompilationHarness<K> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private GlProgram compile(K key) {
|
private GlProgram compile(K key) {
|
||||||
var out = compiler.compile(key, sources, shaderCache, programLinker);
|
return compiler.compile(key, sources, shaderCache, programLinker);
|
||||||
|
|
||||||
if (out == null) {
|
|
||||||
// TODO: populate exception with error details
|
|
||||||
throw new ShaderException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete() {
|
public void delete() {
|
||||||
|
@ -51,6 +40,6 @@ public class CompilationHarness<K> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface KeyCompiler<K> {
|
public interface KeyCompiler<K> {
|
||||||
@Nullable GlProgram compile(K key, ShaderSources loader, ShaderCache shaderCache, ProgramLinker programLinker);
|
GlProgram compile(K key, ShaderSources loader, ShaderCache shaderCache, ProgramLinker programLinker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,6 @@ import java.util.function.BiFunction;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.backend.compile.FlwPrograms;
|
import dev.engine_room.flywheel.backend.compile.FlwPrograms;
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
||||||
|
@ -44,7 +42,7 @@ public class Compile<K> {
|
||||||
public static class ShaderCompiler<K> {
|
public static class ShaderCompiler<K> {
|
||||||
private final GlslVersion glslVersion;
|
private final GlslVersion glslVersion;
|
||||||
private final ShaderType shaderType;
|
private final ShaderType shaderType;
|
||||||
private final List<BiFunction<K, ShaderSources, @Nullable SourceComponent>> fetchers = new ArrayList<>();
|
private final List<BiFunction<K, ShaderSources, SourceComponent>> fetchers = new ArrayList<>();
|
||||||
private BiConsumer<K, Compilation> compilationCallbacks = ($, $$) -> {
|
private BiConsumer<K, Compilation> compilationCallbacks = ($, $$) -> {
|
||||||
};
|
};
|
||||||
private Function<K, String> nameMapper = Object::toString;
|
private Function<K, String> nameMapper = Object::toString;
|
||||||
|
@ -59,21 +57,21 @@ public class Compile<K> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderCompiler<K> with(BiFunction<K, ShaderSources, @Nullable SourceComponent> fetch) {
|
public ShaderCompiler<K> with(BiFunction<K, ShaderSources, SourceComponent> fetch) {
|
||||||
fetchers.add(fetch);
|
fetchers.add(fetch);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderCompiler<K> withComponents(Collection<@Nullable SourceComponent> components) {
|
public ShaderCompiler<K> withComponents(Collection<SourceComponent> components) {
|
||||||
components.forEach(this::withComponent);
|
components.forEach(this::withComponent);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderCompiler<K> withComponent(@Nullable SourceComponent component) {
|
public ShaderCompiler<K> withComponent(SourceComponent component) {
|
||||||
return withComponent($ -> component);
|
return withComponent($ -> component);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderCompiler<K> withComponent(Function<K, @Nullable SourceComponent> sourceFetcher) {
|
public ShaderCompiler<K> withComponent(Function<K, SourceComponent> sourceFetcher) {
|
||||||
return with((key, $) -> sourceFetcher.apply(key));
|
return with((key, $) -> sourceFetcher.apply(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,22 +120,12 @@ public class Compile<K> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private GlShader compile(K key, ShaderCache compiler, ShaderSources loader) {
|
private GlShader compile(K key, ShaderCache compiler, ShaderSources loader) {
|
||||||
long start = System.nanoTime();
|
long start = System.nanoTime();
|
||||||
|
|
||||||
var components = new ArrayList<SourceComponent>();
|
var components = new ArrayList<SourceComponent>();
|
||||||
boolean ok = true;
|
|
||||||
for (var fetcher : fetchers) {
|
for (var fetcher : fetchers) {
|
||||||
SourceComponent apply = fetcher.apply(key, loader);
|
components.add(fetcher.apply(key, loader));
|
||||||
if (apply == null) {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
components.add(apply);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Consumer<Compilation> cb = ctx -> compilationCallbacks.accept(key, ctx);
|
Consumer<Compilation> cb = ctx -> compilationCallbacks.accept(key, ctx);
|
||||||
|
@ -182,7 +170,6 @@ public class Compile<K> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
|
||||||
public GlProgram compile(K key, ShaderSources loader, ShaderCache shaderCache, ProgramLinker programLinker) {
|
public GlProgram compile(K key, ShaderSources loader, ShaderCache shaderCache, ProgramLinker programLinker) {
|
||||||
if (compilers.isEmpty()) {
|
if (compilers.isEmpty()) {
|
||||||
throw new IllegalStateException("No shader compilers were added!");
|
throw new IllegalStateException("No shader compilers were added!");
|
||||||
|
@ -192,24 +179,13 @@ public class Compile<K> {
|
||||||
|
|
||||||
List<GlShader> shaders = new ArrayList<>();
|
List<GlShader> shaders = new ArrayList<>();
|
||||||
|
|
||||||
boolean ok = true;
|
|
||||||
for (ShaderCompiler<K> compiler : compilers.values()) {
|
for (ShaderCompiler<K> compiler : compilers.values()) {
|
||||||
var shader = compiler.compile(key, shaderCache, loader);
|
shaders.add(compiler.compile(key, shaderCache, loader));
|
||||||
if (shader == null) {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
shaders.add(shader);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var out = programLinker.link(shaders, p -> preLink.accept(key, p));
|
var out = programLinker.link(shaders, p -> preLink.accept(key, p));
|
||||||
|
|
||||||
if (out != null) {
|
|
||||||
postLink.accept(key, out);
|
postLink.accept(key, out);
|
||||||
}
|
|
||||||
|
|
||||||
long end = System.nanoTime();
|
long end = System.nanoTime();
|
||||||
|
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
package dev.engine_room.flywheel.backend.compile.core;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.slf4j.Marker;
|
|
||||||
import org.slf4j.MarkerFactory;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.backend.compile.FlwPrograms;
|
|
||||||
import dev.engine_room.flywheel.backend.glsl.LoadError;
|
|
||||||
import dev.engine_room.flywheel.backend.glsl.LoadResult;
|
|
||||||
import dev.engine_room.flywheel.backend.glsl.error.ErrorBuilder;
|
|
||||||
import dev.engine_room.flywheel.lib.util.StringUtil;
|
|
||||||
|
|
||||||
public class CompilerStats {
|
|
||||||
private final Marker marker;
|
|
||||||
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 boolean errored = false;
|
|
||||||
private int shaderCount = 0;
|
|
||||||
private int programCount = 0;
|
|
||||||
|
|
||||||
public CompilerStats(String marker) {
|
|
||||||
this.marker = MarkerFactory.getMarker(marker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
compileStart = System.nanoTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void finish() {
|
|
||||||
long compileEnd = System.nanoTime();
|
|
||||||
var elapsed = StringUtil.formatTime(compileEnd - compileStart);
|
|
||||||
|
|
||||||
FlwPrograms.LOGGER.info(marker, "Compiled %d programs (with %d link errors) and %d shaders (with %d compile errors) in %s".formatted(programCount, programErrors.size(), shaderCount, shaderErrors.size(), elapsed));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean errored() {
|
|
||||||
return errored;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void emitErrorLog() {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
FlwPrograms.LOGGER.error(marker, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String compileErrors() {
|
|
||||||
return shaderErrors.stream()
|
|
||||||
.map(FailedCompilation::generateMessage)
|
|
||||||
.collect(Collectors.joining("\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String linkErrors() {
|
|
||||||
return String.join("\n", programErrors);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String loadErrors() {
|
|
||||||
return loadErrors.stream()
|
|
||||||
.map(LoadError::generateMessage)
|
|
||||||
.map(ErrorBuilder::build)
|
|
||||||
.collect(Collectors.joining("\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shaderResult(ShaderResult result) {
|
|
||||||
if (result instanceof ShaderResult.Failure f) {
|
|
||||||
shaderErrors.add(f.failure());
|
|
||||||
errored = true;
|
|
||||||
}
|
|
||||||
shaderCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void linkResult(LinkResult linkResult) {
|
|
||||||
if (linkResult instanceof LinkResult.Failure f) {
|
|
||||||
programErrors.add(f.failure());
|
|
||||||
errored = true;
|
|
||||||
}
|
|
||||||
programCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadResult(LoadResult loadResult) {
|
|
||||||
if (loadResult instanceof LoadResult.Failure f) {
|
|
||||||
loadErrors.add(f.error());
|
|
||||||
errored = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +1,11 @@
|
||||||
package dev.engine_room.flywheel.backend.compile.core;
|
package dev.engine_room.flywheel.backend.compile.core;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||||
|
|
||||||
public sealed interface LinkResult {
|
public sealed interface LinkResult {
|
||||||
@Nullable
|
GlProgram unwrap();
|
||||||
default GlProgram unwrap() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
record Success(GlProgram program, String log) implements LinkResult {
|
record Success(GlProgram program, String log) implements LinkResult {
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,6 +16,10 @@ public sealed interface LinkResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
record Failure(String failure) implements LinkResult {
|
record Failure(String failure) implements LinkResult {
|
||||||
|
@Override
|
||||||
|
public GlProgram unwrap() {
|
||||||
|
throw new ShaderException.Link(failure);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static LinkResult success(GlProgram program, String log) {
|
static LinkResult success(GlProgram program, String log) {
|
||||||
|
|
|
@ -11,24 +11,17 @@ import static org.lwjgl.opengl.GL20.glLinkProgram;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
||||||
|
|
||||||
public class ProgramLinker {
|
public class ProgramLinker {
|
||||||
private final CompilerStats stats;
|
|
||||||
|
|
||||||
public ProgramLinker(CompilerStats stats) {
|
public ProgramLinker() {
|
||||||
this.stats = stats;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public GlProgram link(List<GlShader> shaders, Consumer<GlProgram> preLink) {
|
public GlProgram link(List<GlShader> shaders, Consumer<GlProgram> preLink) {
|
||||||
// this probably doesn't need caching
|
// this probably doesn't need caching
|
||||||
var linkResult = linkInternal(shaders, preLink);
|
return linkInternal(shaders, preLink).unwrap();
|
||||||
stats.linkResult(linkResult);
|
|
||||||
return linkResult.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinkResult linkInternal(List<GlShader> shaders, Consumer<GlProgram> preLink) {
|
private LinkResult linkInternal(List<GlShader> shaders, Consumer<GlProgram> preLink) {
|
||||||
|
|
|
@ -4,12 +4,9 @@ import java.util.HashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.ShaderType;
|
import dev.engine_room.flywheel.backend.gl.shader.ShaderType;
|
||||||
import dev.engine_room.flywheel.backend.glsl.GlslVersion;
|
import dev.engine_room.flywheel.backend.glsl.GlslVersion;
|
||||||
|
@ -17,13 +14,10 @@ import dev.engine_room.flywheel.backend.glsl.SourceComponent;
|
||||||
|
|
||||||
public class ShaderCache {
|
public class ShaderCache {
|
||||||
private final Map<ShaderKey, ShaderResult> inner = new HashMap<>();
|
private final Map<ShaderKey, ShaderResult> inner = new HashMap<>();
|
||||||
private final CompilerStats stats;
|
|
||||||
|
|
||||||
public ShaderCache(CompilerStats stats) {
|
public ShaderCache() {
|
||||||
this.stats = stats;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public GlShader compile(GlslVersion glslVersion, ShaderType shaderType, String name, Consumer<Compilation> callback, List<SourceComponent> sourceComponents) {
|
public GlShader compile(GlslVersion glslVersion, ShaderType shaderType, String name, Consumer<Compilation> callback, List<SourceComponent> sourceComponents) {
|
||||||
var key = new ShaderKey(glslVersion, shaderType, name);
|
var key = new ShaderKey(glslVersion, shaderType, name);
|
||||||
var cached = inner.get(key);
|
var cached = inner.get(key);
|
||||||
|
@ -41,15 +35,14 @@ public class ShaderCache {
|
||||||
|
|
||||||
ShaderResult out = ctx.compile(shaderType, name);
|
ShaderResult out = ctx.compile(shaderType, name);
|
||||||
inner.put(key, out);
|
inner.put(key, out);
|
||||||
stats.shaderResult(out);
|
|
||||||
return out.unwrap();
|
return out.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete() {
|
public void delete() {
|
||||||
inner.values()
|
inner.values()
|
||||||
.stream()
|
.stream()
|
||||||
|
.filter(r -> r instanceof ShaderResult.Success)
|
||||||
.map(ShaderResult::unwrap)
|
.map(ShaderResult::unwrap)
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.forEach(GlShader::delete);
|
.forEach(GlShader::delete);
|
||||||
inner.clear();
|
inner.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,57 @@
|
||||||
package dev.engine_room.flywheel.backend.compile.core;
|
package dev.engine_room.flywheel.backend.compile.core;
|
||||||
|
|
||||||
public class ShaderException extends RuntimeException {
|
public class ShaderException extends RuntimeException {
|
||||||
|
public ShaderException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Link extends ShaderException {
|
||||||
|
public Link(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Link(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Link(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Compile extends ShaderException {
|
||||||
|
public Compile(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Compile(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Compile(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Load extends ShaderException {
|
||||||
|
public Load(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Load(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Load(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,22 @@
|
||||||
package dev.engine_room.flywheel.backend.compile.core;
|
package dev.engine_room.flywheel.backend.compile.core;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
||||||
|
|
||||||
public sealed interface ShaderResult {
|
public sealed interface ShaderResult {
|
||||||
@Nullable
|
GlShader unwrap();
|
||||||
default GlShader unwrap() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
record Success(GlShader shader, String infoLog) implements ShaderResult {
|
record Success(GlShader shader, String infoLog) implements ShaderResult {
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
|
||||||
public GlShader unwrap() {
|
public GlShader unwrap() {
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record Failure(FailedCompilation failure) implements ShaderResult {
|
record Failure(FailedCompilation failure) implements ShaderResult {
|
||||||
|
@Override
|
||||||
|
public GlShader unwrap() {
|
||||||
|
throw new ShaderException.Compile(failure.generateMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ShaderResult success(GlShader program, String infoLog) {
|
static ShaderResult success(GlShader program, String infoLog) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import dev.engine_room.flywheel.api.task.Plan;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualEmbedding;
|
import dev.engine_room.flywheel.api.visualization.VisualEmbedding;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualType;
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||||
|
import dev.engine_room.flywheel.backend.FlwBackend;
|
||||||
import dev.engine_room.flywheel.backend.compile.core.ShaderException;
|
import dev.engine_room.flywheel.backend.compile.core.ShaderException;
|
||||||
import dev.engine_room.flywheel.backend.engine.embed.EmbeddedEnvironment;
|
import dev.engine_room.flywheel.backend.engine.embed.EmbeddedEnvironment;
|
||||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||||
|
@ -93,6 +94,7 @@ public class EngineImpl implements Engine {
|
||||||
environmentStorage.flush();
|
environmentStorage.flush();
|
||||||
drawManager.flush(lightStorage, environmentStorage);
|
drawManager.flush(lightStorage, environmentStorage);
|
||||||
} catch (ShaderException e) {
|
} catch (ShaderException e) {
|
||||||
|
FlwBackend.LOGGER.error("Falling back", e);
|
||||||
triggerFallback();
|
triggerFallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,6 +104,7 @@ public class EngineImpl implements Engine {
|
||||||
try (var state = GlStateTracker.getRestoreState()) {
|
try (var state = GlStateTracker.getRestoreState()) {
|
||||||
drawManager.render(visualType);
|
drawManager.render(visualType);
|
||||||
} catch (ShaderException e) {
|
} catch (ShaderException e) {
|
||||||
|
FlwBackend.LOGGER.error("Falling back", e);
|
||||||
triggerFallback();
|
triggerFallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,6 +114,7 @@ public class EngineImpl implements Engine {
|
||||||
try (var state = GlStateTracker.getRestoreState()) {
|
try (var state = GlStateTracker.getRestoreState()) {
|
||||||
drawManager.renderCrumbling(crumblingBlocks);
|
drawManager.renderCrumbling(crumblingBlocks);
|
||||||
} catch (ShaderException e) {
|
} catch (ShaderException e) {
|
||||||
|
FlwBackend.LOGGER.error("Falling back", e);
|
||||||
triggerFallback();
|
triggerFallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,23 +5,21 @@ import org.lwjgl.opengl.GL46;
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.GlStateManager;
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
|
||||||
|
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
||||||
import dev.engine_room.flywheel.backend.gl.GlTextureUnit;
|
import dev.engine_room.flywheel.backend.gl.GlTextureUnit;
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
|
||||||
import dev.engine_room.flywheel.lib.math.MoreMath;
|
import dev.engine_room.flywheel.lib.math.MoreMath;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
public class DepthPyramid {
|
public class DepthPyramid {
|
||||||
private final GlProgram downsampleFirstProgram;
|
private final IndirectPrograms programs;
|
||||||
private final GlProgram downsampleSecondProgram;
|
|
||||||
|
|
||||||
public int pyramidTextureId = -1;
|
public int pyramidTextureId = -1;
|
||||||
|
|
||||||
private int lastWidth = -1;
|
private int lastWidth = -1;
|
||||||
private int lastHeight = -1;
|
private int lastHeight = -1;
|
||||||
|
|
||||||
public DepthPyramid(GlProgram downsampleFirstProgram, GlProgram downsampleSecondProgram) {
|
public DepthPyramid(IndirectPrograms programs) {
|
||||||
this.downsampleFirstProgram = downsampleFirstProgram;
|
this.programs = programs;
|
||||||
this.downsampleSecondProgram = downsampleSecondProgram;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generate() {
|
public void generate() {
|
||||||
|
@ -42,6 +40,7 @@ public class DepthPyramid {
|
||||||
GlTextureUnit.T0.makeActive();
|
GlTextureUnit.T0.makeActive();
|
||||||
GlStateManager._bindTexture(depthBufferId);
|
GlStateManager._bindTexture(depthBufferId);
|
||||||
|
|
||||||
|
var downsampleFirstProgram = programs.getDownsampleFirstProgram();
|
||||||
downsampleFirstProgram.bind();
|
downsampleFirstProgram.bind();
|
||||||
downsampleFirstProgram.setUInt("max_mip_level", mipLevels);
|
downsampleFirstProgram.setUInt("max_mip_level", mipLevels);
|
||||||
|
|
||||||
|
@ -59,6 +58,7 @@ public class DepthPyramid {
|
||||||
|
|
||||||
GL46.glMemoryBarrier(GL46.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
|
GL46.glMemoryBarrier(GL46.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
|
||||||
|
|
||||||
|
var downsampleSecondProgram = programs.getDownsampleSecondProgram();
|
||||||
downsampleSecondProgram.bind();
|
downsampleSecondProgram.bind();
|
||||||
downsampleSecondProgram.setUInt("max_mip_level", mipLevels);
|
downsampleSecondProgram.setUInt("max_mip_level", mipLevels);
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
||||||
this.programs = programs;
|
this.programs = programs;
|
||||||
programs.acquire();
|
programs.acquire();
|
||||||
|
|
||||||
|
// WARN: We should avoid eagerly grabbing GlPrograms here as catching compile
|
||||||
|
// errors and falling back during construction is a bit more complicated.
|
||||||
stagingBuffer = new StagingBuffer(this.programs);
|
stagingBuffer = new StagingBuffer(this.programs);
|
||||||
meshPool = new MeshPool();
|
meshPool = new MeshPool();
|
||||||
vertexArray = GlVertexArray.create();
|
vertexArray = GlVertexArray.create();
|
||||||
|
@ -63,7 +65,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
||||||
lightBuffers = new LightBuffers();
|
lightBuffers = new LightBuffers();
|
||||||
matrixBuffer = new MatrixBuffer();
|
matrixBuffer = new MatrixBuffer();
|
||||||
|
|
||||||
depthPyramid = new DepthPyramid(programs.getDownsampleFirstProgram(), programs.getDownsampleSecondProgram());
|
depthPyramid = new DepthPyramid(programs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -10,7 +10,6 @@ import org.lwjgl.system.MemoryUtil;
|
||||||
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
||||||
import dev.engine_room.flywheel.backend.gl.GlFence;
|
import dev.engine_room.flywheel.backend.gl.GlFence;
|
||||||
import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer;
|
import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer;
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
|
||||||
import dev.engine_room.flywheel.lib.memory.FlwMemoryTracker;
|
import dev.engine_room.flywheel.lib.memory.FlwMemoryTracker;
|
||||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||||
import it.unimi.dsi.fastutil.PriorityQueue;
|
import it.unimi.dsi.fastutil.PriorityQueue;
|
||||||
|
@ -26,6 +25,7 @@ public class StagingBuffer {
|
||||||
private final int vbo;
|
private final int vbo;
|
||||||
private final long map;
|
private final long map;
|
||||||
private final long capacity;
|
private final long capacity;
|
||||||
|
private final IndirectPrograms programs;
|
||||||
|
|
||||||
private final OverflowStagingBuffer overflow = new OverflowStagingBuffer();
|
private final OverflowStagingBuffer overflow = new OverflowStagingBuffer();
|
||||||
private final TransferList transfers = new TransferList();
|
private final TransferList transfers = new TransferList();
|
||||||
|
@ -33,8 +33,6 @@ public class StagingBuffer {
|
||||||
private final GlBuffer scatterBuffer = new GlBuffer();
|
private final GlBuffer scatterBuffer = new GlBuffer();
|
||||||
private final ScatterList scatterList = new ScatterList();
|
private final ScatterList scatterList = new ScatterList();
|
||||||
|
|
||||||
private final GlProgram scatterProgram;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The position in the buffer at the time of the last flush.
|
* The position in the buffer at the time of the last flush.
|
||||||
*/
|
*/
|
||||||
|
@ -70,6 +68,7 @@ public class StagingBuffer {
|
||||||
|
|
||||||
public StagingBuffer(long capacity, IndirectPrograms programs) {
|
public StagingBuffer(long capacity, IndirectPrograms programs) {
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
|
this.programs = programs;
|
||||||
vbo = GL45C.glCreateBuffers();
|
vbo = GL45C.glCreateBuffers();
|
||||||
|
|
||||||
GL45C.glNamedBufferStorage(vbo, capacity, STORAGE_FLAGS);
|
GL45C.glNamedBufferStorage(vbo, capacity, STORAGE_FLAGS);
|
||||||
|
@ -78,8 +77,6 @@ public class StagingBuffer {
|
||||||
totalAvailable = capacity;
|
totalAvailable = capacity;
|
||||||
|
|
||||||
FlwMemoryTracker._allocCpuMemory(capacity);
|
FlwMemoryTracker._allocCpuMemory(capacity);
|
||||||
|
|
||||||
scatterProgram = programs.getScatterProgram();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -251,7 +248,8 @@ public class StagingBuffer {
|
||||||
* <a href=https://on-demand.gputechconf.com/gtc/2016/presentation/s6138-christoph-kubisch-pierre-boudier-gpu-driven-rendering.pdf>this presentation</a>
|
* <a href=https://on-demand.gputechconf.com/gtc/2016/presentation/s6138-christoph-kubisch-pierre-boudier-gpu-driven-rendering.pdf>this presentation</a>
|
||||||
*/
|
*/
|
||||||
private void dispatchComputeCopies() {
|
private void dispatchComputeCopies() {
|
||||||
scatterProgram.bind();
|
programs.getScatterProgram()
|
||||||
|
.bind();
|
||||||
|
|
||||||
// These bindings don't change between dstVbos.
|
// These bindings don't change between dstVbos.
|
||||||
GL45.glBindBufferBase(GL45C.GL_SHADER_STORAGE_BUFFER, 0, scatterBuffer.handle());
|
GL45.glBindBufferBase(GL45C.GL_SHADER_STORAGE_BUFFER, 0, scatterBuffer.handle());
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
package dev.engine_room.flywheel.backend.glsl;
|
package dev.engine_room.flywheel.backend.glsl;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import dev.engine_room.flywheel.backend.compile.core.ShaderException;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public sealed interface LoadResult {
|
public sealed interface LoadResult {
|
||||||
@Nullable
|
SourceFile unwrap();
|
||||||
default SourceFile unwrap() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
record Success(SourceFile source) implements LoadResult {
|
record Success(SourceFile source) implements LoadResult {
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
|
||||||
public SourceFile unwrap() {
|
public SourceFile unwrap() {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record Failure(LoadError error) implements LoadResult {
|
record Failure(LoadError error) implements LoadResult {
|
||||||
|
@Override
|
||||||
|
public SourceFile unwrap() {
|
||||||
|
throw new ShaderException.Load(error.generateMessage()
|
||||||
|
.build());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.annotations.VisibleForTesting;
|
import org.jetbrains.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.backend.compile.FlwPrograms;
|
import dev.engine_room.flywheel.backend.compile.FlwPrograms;
|
||||||
|
@ -50,7 +49,6 @@ public class ShaderSources {
|
||||||
return cache.computeIfAbsent(location, loc -> new LoadResult.Failure(new LoadError.ResourceError(loc)));
|
return cache.computeIfAbsent(location, loc -> new LoadResult.Failure(new LoadError.ResourceError(loc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public SourceFile get(ResourceLocation location) {
|
public SourceFile get(ResourceLocation location) {
|
||||||
return find(location).unwrap();
|
return find(location).unwrap();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue