Dynamic ubering

- Remove fog shader registry
- Remove Registry and RegistryImpl
- Make shader indices mutable
- Track fog uber component in a static field in PipelineCompiler
- When a new fog source is added, delete the pipeline compilation
  harness and recreate the fog uber component
- Inline SourceLoader
This commit is contained in:
Jozufozu 2024-09-28 15:29:35 -07:00
parent bce657804a
commit 11ce4ac185
21 changed files with 115 additions and 258 deletions

View File

@ -5,7 +5,6 @@ import org.jetbrains.annotations.Nullable;
import dev.engine_room.flywheel.api.backend.Backend; import dev.engine_room.flywheel.api.backend.Backend;
import dev.engine_room.flywheel.api.layout.LayoutBuilder; import dev.engine_room.flywheel.api.layout.LayoutBuilder;
import dev.engine_room.flywheel.api.registry.IdRegistry; import dev.engine_room.flywheel.api.registry.IdRegistry;
import dev.engine_room.flywheel.api.registry.Registry;
import dev.engine_room.flywheel.api.visualization.BlockEntityVisualizer; import dev.engine_room.flywheel.api.visualization.BlockEntityVisualizer;
import dev.engine_room.flywheel.api.visualization.EntityVisualizer; import dev.engine_room.flywheel.api.visualization.EntityVisualizer;
import dev.engine_room.flywheel.api.visualization.VisualizationManager; import dev.engine_room.flywheel.api.visualization.VisualizationManager;
@ -18,8 +17,6 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
public interface FlwApiLink { public interface FlwApiLink {
FlwApiLink INSTANCE = DependencyInjection.load(FlwApiLink.class, "dev.engine_room.flywheel.impl.FlwApiLinkImpl"); FlwApiLink INSTANCE = DependencyInjection.load(FlwApiLink.class, "dev.engine_room.flywheel.impl.FlwApiLinkImpl");
<T> Registry<T> createRegistry();
<T> IdRegistry<T> createIdRegistry(); <T> IdRegistry<T> createIdRegistry();
Backend getCurrentBackend(); Backend getCurrentBackend();

View File

@ -1,11 +1,7 @@
package dev.engine_room.flywheel.api.material; package dev.engine_room.flywheel.api.material;
import dev.engine_room.flywheel.api.internal.FlwApiLink;
import dev.engine_room.flywheel.api.registry.Registry;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public interface FogShader { public interface FogShader {
Registry<FogShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
ResourceLocation source(); ResourceLocation source();
} }

View File

@ -1,18 +0,0 @@
package dev.engine_room.flywheel.api.registry;
import java.util.Set;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.UnmodifiableView;
@ApiStatus.NonExtendable
public interface Registry<T> extends Iterable<T> {
void register(T object);
<S extends T> S registerAndGet(S object);
@UnmodifiableView
Set<T> getAll();
boolean isFrozen();
}

View File

@ -1,14 +1,11 @@
package dev.engine_room.flywheel.backend; package dev.engine_room.flywheel.backend;
import java.util.List; import java.util.List;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable; import org.jetbrains.annotations.Unmodifiable;
import dev.engine_room.flywheel.api.material.CutoutShader; import dev.engine_room.flywheel.api.material.CutoutShader;
import dev.engine_room.flywheel.api.material.FogShader; import dev.engine_room.flywheel.api.material.FogShader;
import dev.engine_room.flywheel.api.registry.Registry;
import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
@ -16,25 +13,17 @@ import it.unimi.dsi.fastutil.objects.ObjectList;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public final class MaterialShaderIndices { public final class MaterialShaderIndices {
@Nullable private static final Index fogSources = new Index();
private static Index fogSources; private static final Index cutoutSources = new Index();
@Nullable
private static Index cutoutSources;
private MaterialShaderIndices() { private MaterialShaderIndices() {
} }
public static Index fogSources() { public static Index fogSources() {
if (fogSources == null) {
fogSources = indexFromRegistry(FogShader.REGISTRY, FogShader::source);
}
return fogSources; return fogSources;
} }
public static Index cutoutSources() { public static Index cutoutSources() {
// if (cutoutSources == null) {
// cutoutSources = indexFromRegistry(CutoutShader.REGISTRY, CutoutShader::source);
// }
return cutoutSources; return cutoutSources;
} }
@ -43,30 +32,23 @@ public final class MaterialShaderIndices {
} }
public static int cutoutIndex(CutoutShader cutoutShader) { public static int cutoutIndex(CutoutShader cutoutShader) {
return 0;//cutoutSources().index(cutoutShader.source()); return cutoutSources().index(cutoutShader.source());
}
private static <T> Index indexFromRegistry(Registry<T> registry, Function<T, ResourceLocation> sourceFunc) {
if (!registry.isFrozen()) {
throw new IllegalStateException("Cannot create index from registry that is not frozen!");
}
var builder = new IndexBuilder();
for (T object : registry) {
builder.add(sourceFunc.apply(object));
}
return builder.build();
} }
public static class Index { public static class Index {
private final Object2IntMap<ResourceLocation> sources2Index; private final Object2IntMap<ResourceLocation> sources2Index;
private final ObjectList<ResourceLocation> sources; private final ObjectList<ResourceLocation> sources;
private Index(IndexBuilder builder) { private Index() {
this.sources2Index = new Object2IntOpenHashMap<>(builder.sources2Index); this.sources2Index = new Object2IntOpenHashMap<>();
this.sources = new ObjectArrayList<>(builder.sources); sources2Index.defaultReturnValue(-1);
this.sources = new ObjectArrayList<>();
}
public void add(ResourceLocation source) {
if (sources2Index.putIfAbsent(source, sources.size()) == -1) {
sources.add(source);
}
} }
public int index(ResourceLocation source) { public int index(ResourceLocation source) {
@ -82,27 +64,4 @@ public final class MaterialShaderIndices {
return sources; return sources;
} }
} }
private static class IndexBuilder {
private final Object2IntMap<ResourceLocation> sources2Index;
private final ObjectList<ResourceLocation> sources;
private int index = 0;
public IndexBuilder() {
sources2Index = new Object2IntOpenHashMap<>();
sources2Index.defaultReturnValue(-1);
sources = new ObjectArrayList<>();
}
public void add(ResourceLocation source) {
if (sources2Index.putIfAbsent(source, index) == -1) {
sources.add(source);
index++;
}
}
public Index build() {
return new Index(this);
}
}
} }

View File

@ -2,19 +2,13 @@ package dev.engine_room.flywheel.backend.compile;
import java.util.List; import java.util.List;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger; 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.MaterialShaderIndices;
import dev.engine_room.flywheel.backend.compile.component.UberShaderComponent;
import dev.engine_room.flywheel.backend.compile.core.CompilerStats; import dev.engine_room.flywheel.backend.compile.core.CompilerStats;
import dev.engine_room.flywheel.backend.compile.core.SourceLoader;
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 dev.engine_room.flywheel.backend.glsl.generate.FnSignature;
import dev.engine_room.flywheel.backend.glsl.generate.GlslExpr;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManager;
@ -23,6 +17,8 @@ public final class FlwPrograms {
private static final ResourceLocation COMPONENTS_HEADER_FRAG = Flywheel.rl("internal/components_header.frag"); private static final ResourceLocation COMPONENTS_HEADER_FRAG = Flywheel.rl("internal/components_header.frag");
public static ShaderSources SOURCES;
private FlwPrograms() { private FlwPrograms() {
} }
@ -32,52 +28,22 @@ public final class FlwPrograms {
IndirectPrograms.setInstance(null); IndirectPrograms.setInstance(null);
var sources = new ShaderSources(resourceManager); var sources = new ShaderSources(resourceManager);
SOURCES = sources;
var stats = new CompilerStats("ubershaders"); var stats = new CompilerStats("ubershaders");
var loader = new SourceLoader(sources, stats);
var fragmentComponentsHeader = loader.find(COMPONENTS_HEADER_FRAG); var fragmentComponentsHeader = sources.get(COMPONENTS_HEADER_FRAG);
var fogComponent = createFogComponent(loader);
// TODO: separate compilation for cutout OFF, but keep the rest uber'd? // TODO: separate compilation for cutout OFF, but keep the rest uber'd?
if (stats.errored() || fragmentComponentsHeader == null || fogComponent == null) { if (stats.errored() || fragmentComponentsHeader == null) {
// Probably means the shader sources are missing. // Probably means the shader sources are missing.
stats.emitErrorLog(); stats.emitErrorLog();
return; return;
} }
List<SourceComponent> vertexComponents = List.of(); List<SourceComponent> vertexComponents = List.of();
List<SourceComponent> fragmentComponents = List.of(fragmentComponentsHeader, fogComponent); List<SourceComponent> fragmentComponents = List.of(fragmentComponentsHeader);
InstancingPrograms.reload(sources, vertexComponents, fragmentComponents); InstancingPrograms.reload(sources, vertexComponents, fragmentComponents);
IndirectPrograms.reload(sources, vertexComponents, fragmentComponents); IndirectPrograms.reload(sources, vertexComponents, fragmentComponents);
} }
@Nullable
private static UberShaderComponent createFogComponent(SourceLoader loader) {
return UberShaderComponent.builder(Flywheel.rl("fog"))
.materialSources(MaterialShaderIndices.fogSources()
.all())
.adapt(FnSignature.create()
.returnType("vec4")
.name("flw_fogFilter")
.arg("vec4", "color")
.build(), GlslExpr.variable("color"))
.switchOn(GlslExpr.variable("_flw_uberFogIndex"))
.build(loader);
}
@Nullable
private static UberShaderComponent createCutoutComponent(SourceLoader loader) {
return UberShaderComponent.builder(Flywheel.rl("cutout"))
.materialSources(MaterialShaderIndices.cutoutSources()
.all())
.adapt(FnSignature.create()
.returnType("bool")
.name("flw_discardPredicate")
.arg("vec4", "color")
.build(), GlslExpr.boolLiteral(false))
.switchOn(GlslExpr.variable("_flw_uberCutoutIndex"))
.build(loader);
}
} }

View File

@ -8,9 +8,8 @@ import com.google.common.collect.ImmutableList;
import dev.engine_room.flywheel.api.Flywheel; import dev.engine_room.flywheel.api.Flywheel;
import dev.engine_room.flywheel.api.instance.InstanceType; import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.api.material.CutoutShader; import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.material.LightShader; import dev.engine_room.flywheel.backend.MaterialShaderIndices;
import dev.engine_room.flywheel.api.material.MaterialShaders;
import dev.engine_room.flywheel.backend.compile.component.InstanceStructComponent; import dev.engine_room.flywheel.backend.compile.component.InstanceStructComponent;
import dev.engine_room.flywheel.backend.compile.component.SsboInstanceComponent; import dev.engine_room.flywheel.backend.compile.component.SsboInstanceComponent;
import dev.engine_room.flywheel.backend.compile.core.CompilationHarness; import dev.engine_room.flywheel.backend.compile.core.CompilationHarness;
@ -151,7 +150,19 @@ public class IndirectPrograms extends AtomicReferenceCounted {
setInstance(null); setInstance(null);
} }
public GlProgram getIndirectProgram(InstanceType<?> instanceType, ContextShader contextShader, LightShader light, CutoutShader cutout, MaterialShaders shaders) { public GlProgram getIndirectProgram(InstanceType<?> instanceType, ContextShader contextShader, Material material) {
var light = material.light();
var cutout = material.cutout();
var shaders = material.shaders();
var fog = material.fog();
var fogIndex = MaterialShaderIndices.fogSources();
if (fogIndex.index(fog.source()) == -1) {
fogIndex.add(fog.source());
pipeline.delete();
PipelineCompiler.createFogComponent();
}
return pipeline.get(new PipelineProgramKey(instanceType, contextShader, light, cutout, shaders, FrameUniforms.debugOn())); return pipeline.get(new PipelineProgramKey(instanceType, contextShader, light, cutout, shaders, FrameUniforms.debugOn()));
} }

View File

@ -7,9 +7,8 @@ import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import dev.engine_room.flywheel.api.instance.InstanceType; import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.api.material.CutoutShader; import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.material.LightShader; import dev.engine_room.flywheel.backend.MaterialShaderIndices;
import dev.engine_room.flywheel.api.material.MaterialShaders;
import dev.engine_room.flywheel.backend.compile.core.CompilationHarness; import dev.engine_room.flywheel.backend.compile.core.CompilationHarness;
import dev.engine_room.flywheel.backend.engine.uniform.FrameUniforms; import dev.engine_room.flywheel.backend.engine.uniform.FrameUniforms;
import dev.engine_room.flywheel.backend.gl.GlCompat; import dev.engine_room.flywheel.backend.gl.GlCompat;
@ -74,7 +73,20 @@ public class InstancingPrograms extends AtomicReferenceCounted {
setInstance(null); setInstance(null);
} }
public GlProgram get(InstanceType<?> instanceType, ContextShader contextShader, LightShader light, CutoutShader cutout, MaterialShaders materialShaders) { public GlProgram get(InstanceType<?> instanceType, ContextShader contextShader, Material material) {
var light = material.light();
var cutout = material.cutout();
var materialShaders = material.shaders();
var fog = material.fog();
var fogIndex = MaterialShaderIndices.fogSources();
if (fogIndex.index(fog.source()) == -1) {
fogIndex.add(fog.source());
pipeline.delete();
PipelineCompiler.createFogComponent();
}
return pipeline.get(new PipelineProgramKey(instanceType, contextShader, light, cutout, materialShaders, FrameUniforms.debugOn())); return pipeline.get(new PipelineProgramKey(instanceType, contextShader, light, cutout, materialShaders, FrameUniforms.debugOn()));
} }

View File

@ -6,8 +6,10 @@ import java.util.List;
import dev.engine_room.flywheel.api.Flywheel; import dev.engine_room.flywheel.api.Flywheel;
import dev.engine_room.flywheel.backend.BackendConfig; import dev.engine_room.flywheel.backend.BackendConfig;
import dev.engine_room.flywheel.backend.InternalVertex; import dev.engine_room.flywheel.backend.InternalVertex;
import dev.engine_room.flywheel.backend.MaterialShaderIndices;
import dev.engine_room.flywheel.backend.Samplers; import dev.engine_room.flywheel.backend.Samplers;
import dev.engine_room.flywheel.backend.compile.component.InstanceStructComponent; import dev.engine_room.flywheel.backend.compile.component.InstanceStructComponent;
import dev.engine_room.flywheel.backend.compile.component.UberShaderComponent;
import dev.engine_room.flywheel.backend.compile.core.CompilationHarness; import dev.engine_room.flywheel.backend.compile.core.CompilationHarness;
import dev.engine_room.flywheel.backend.compile.core.Compile; import dev.engine_room.flywheel.backend.compile.core.Compile;
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms; import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
@ -16,6 +18,8 @@ import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
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.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 dev.engine_room.flywheel.backend.glsl.generate.FnSignature;
import dev.engine_room.flywheel.backend.glsl.generate.GlslExpr;
import dev.engine_room.flywheel.lib.material.CutoutShaders; import dev.engine_room.flywheel.lib.material.CutoutShaders;
import dev.engine_room.flywheel.lib.util.ResourceUtil; import dev.engine_room.flywheel.lib.util.ResourceUtil;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@ -23,6 +27,9 @@ import net.minecraft.resources.ResourceLocation;
public final class PipelineCompiler { public final class PipelineCompiler {
private static final Compile<PipelineProgramKey> PIPELINE = new Compile<>(); private static final Compile<PipelineProgramKey> PIPELINE = new Compile<>();
private static UberShaderComponent FOG;
private static UberShaderComponent CUTOUT;
private static final ResourceLocation API_IMPL_VERT = Flywheel.rl("internal/api_impl.vert"); private static final ResourceLocation API_IMPL_VERT = Flywheel.rl("internal/api_impl.vert");
private static final ResourceLocation API_IMPL_FRAG = Flywheel.rl("internal/api_impl.frag"); private static final ResourceLocation API_IMPL_FRAG = Flywheel.rl("internal/api_impl.frag");
@ -98,6 +105,7 @@ public final class PipelineCompiler {
.withResource(key -> key.materialShaders() .withResource(key -> key.materialShaders()
.fragmentSource()) .fragmentSource())
.withComponents(fragmentComponents) .withComponents(fragmentComponents)
.withComponent(key -> FOG)
.withResource(key -> key.light() .withResource(key -> key.light()
.source()) .source())
.withResource(key -> key.cutout() .withResource(key -> key.cutout()
@ -128,4 +136,30 @@ public final class PipelineCompiler {
}) })
.harness(pipeline.compilerMarker(), sources); .harness(pipeline.compilerMarker(), sources);
} }
public static void createFogComponent() {
FOG = UberShaderComponent.builder(Flywheel.rl("fog"))
.materialSources(MaterialShaderIndices.fogSources()
.all())
.adapt(FnSignature.create()
.returnType("vec4")
.name("flw_fogFilter")
.arg("vec4", "color")
.build(), GlslExpr.variable("color"))
.switchOn(GlslExpr.variable("_flw_uberFogIndex"))
.build(FlwPrograms.SOURCES);
}
private static void createCutoutComponent() {
CUTOUT = UberShaderComponent.builder(Flywheel.rl("cutout"))
.materialSources(MaterialShaderIndices.cutoutSources()
.all())
.adapt(FnSignature.create()
.returnType("bool")
.name("flw_discardPredicate")
.arg("vec4", "color")
.build(), GlslExpr.boolLiteral(false))
.switchOn(GlslExpr.variable("_flw_uberCutoutIndex"))
.build(FlwPrograms.SOURCES);
}
} }

View File

@ -11,7 +11,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import dev.engine_room.flywheel.api.Flywheel; import dev.engine_room.flywheel.api.Flywheel;
import dev.engine_room.flywheel.backend.compile.core.SourceLoader; 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 dev.engine_room.flywheel.backend.glsl.SourceFile; import dev.engine_room.flywheel.backend.glsl.SourceFile;
import dev.engine_room.flywheel.backend.glsl.generate.FnSignature; import dev.engine_room.flywheel.backend.glsl.generate.FnSignature;
@ -137,7 +137,7 @@ public class UberShaderComponent implements SourceComponent {
} }
@Nullable @Nullable
public UberShaderComponent build(SourceLoader sources) { public UberShaderComponent build(ShaderSources sources) {
if (switchArg == null) { if (switchArg == null) {
throw new NullPointerException("Switch argument must be set"); throw new NullPointerException("Switch argument must be set");
} }
@ -147,7 +147,7 @@ public class UberShaderComponent implements SourceComponent {
boolean errored = false; boolean errored = false;
int index = 0; int index = 0;
for (var rl : materialSources) { for (var rl : materialSources) {
SourceFile sourceFile = sources.find(rl); SourceFile sourceFile = sources.get(rl);
if (sourceFile != null) { if (sourceFile != null) {
final int finalIndex = index; final int finalIndex = index;
var adapterMap = createAdapterMap(adaptedFunctions, fnName -> "_" + fnName + "_" + finalIndex); var adapterMap = createAdapterMap(adaptedFunctions, fnName -> "_" + fnName + "_" + finalIndex);

View File

@ -5,12 +5,13 @@ import java.util.Map;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
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;
public class CompilationHarness<K> { public class CompilationHarness<K> {
private final ShaderSources sources;
private final KeyCompiler<K> compiler; private final KeyCompiler<K> compiler;
private final SourceLoader sourceLoader;
private final ShaderCache shaderCache; private final ShaderCache shaderCache;
private final ProgramLinker programLinker; private final ProgramLinker programLinker;
private final CompilerStats stats; private final CompilerStats stats;
@ -18,9 +19,9 @@ public class CompilationHarness<K> {
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.compiler = compiler; this.compiler = compiler;
stats = new CompilerStats(marker); stats = new CompilerStats(marker);
sourceLoader = new SourceLoader(sources, stats);
shaderCache = new ShaderCache(stats); shaderCache = new ShaderCache(stats);
programLinker = new ProgramLinker(stats); programLinker = new ProgramLinker(stats);
} }
@ -30,7 +31,7 @@ public class CompilationHarness<K> {
} }
private GlProgram compile(K key) { private GlProgram compile(K key) {
var out = compiler.compile(key, sourceLoader, shaderCache, programLinker); var out = compiler.compile(key, sources, shaderCache, programLinker);
if (out == null) { if (out == null) {
// TODO: populate exception with error details // TODO: populate exception with error details
@ -43,12 +44,13 @@ public class CompilationHarness<K> {
public void delete() { public void delete() {
shaderCache.delete(); shaderCache.delete();
for (var program : programs.values()) { programs.values()
program.delete(); .forEach(GlObject::delete);
}
programs.clear();
} }
public interface KeyCompiler<K> { public interface KeyCompiler<K> {
@Nullable GlProgram compile(K key, SourceLoader loader, ShaderCache shaderCache, ProgramLinker programLinker); @Nullable GlProgram compile(K key, ShaderSources loader, ShaderCache shaderCache, ProgramLinker programLinker);
} }
} }

View File

@ -44,7 +44,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, SourceLoader, @Nullable SourceComponent>> fetchers = new ArrayList<>(); private final List<BiFunction<K, ShaderSources, @Nullable 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,7 +59,7 @@ public class Compile<K> {
return this; return this;
} }
public ShaderCompiler<K> with(BiFunction<K, SourceLoader, @Nullable SourceComponent> fetch) { public ShaderCompiler<K> with(BiFunction<K, ShaderSources, @Nullable SourceComponent> fetch) {
fetchers.add(fetch); fetchers.add(fetch);
return this; return this;
} }
@ -78,7 +78,7 @@ public class Compile<K> {
} }
public ShaderCompiler<K> withResource(Function<K, ResourceLocation> sourceFetcher) { public ShaderCompiler<K> withResource(Function<K, ResourceLocation> sourceFetcher) {
return with((key, loader) -> loader.find(sourceFetcher.apply(key))); return with((key, loader) -> loader.get(sourceFetcher.apply(key)));
} }
public ShaderCompiler<K> withResource(ResourceLocation resourceLocation) { public ShaderCompiler<K> withResource(ResourceLocation resourceLocation) {
@ -123,7 +123,7 @@ public class Compile<K> {
} }
@Nullable @Nullable
private GlShader compile(K key, ShaderCache compiler, SourceLoader 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>();
@ -183,7 +183,7 @@ public class Compile<K> {
@Override @Override
@Nullable @Nullable
public GlProgram compile(K key, SourceLoader 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!");
} }

View File

@ -51,6 +51,7 @@ public class ShaderCache {
.map(ShaderResult::unwrap) .map(ShaderResult::unwrap)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.forEach(GlShader::delete); .forEach(GlShader::delete);
inner.clear();
} }
private static void expand(List<SourceComponent> rootSources, Consumer<SourceComponent> out) { private static void expand(List<SourceComponent> rootSources, Consumer<SourceComponent> out) {

View File

@ -1,24 +0,0 @@
package dev.engine_room.flywheel.backend.compile.core;
import org.jetbrains.annotations.Nullable;
import dev.engine_room.flywheel.backend.glsl.ShaderSources;
import dev.engine_room.flywheel.backend.glsl.SourceFile;
import net.minecraft.resources.ResourceLocation;
public class SourceLoader {
private 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();
}
}

View File

@ -202,7 +202,7 @@ public class IndirectCullingGroup<I extends Instance> {
int baseDrawUniformLoc = -1; int baseDrawUniformLoc = -1;
for (var multiDraw : multiDraws.get(visualType)) { for (var multiDraw : multiDraws.get(visualType)) {
var drawProgram = programs.getIndirectProgram(instanceType, multiDraw.embedded ? ContextShader.EMBEDDED : ContextShader.DEFAULT, multiDraw.material.light(), multiDraw.material.cutout(), multiDraw.material.shaders()); var drawProgram = programs.getIndirectProgram(instanceType, multiDraw.embedded ? ContextShader.EMBEDDED : ContextShader.DEFAULT, multiDraw.material);
if (drawProgram != lastProgram) { if (drawProgram != lastProgram) {
lastProgram = drawProgram; lastProgram = drawProgram;
@ -220,7 +220,7 @@ public class IndirectCullingGroup<I extends Instance> {
} }
public void bindWithContextShader(ContextShader override, Material material) { public void bindWithContextShader(ContextShader override, Material material) {
var program = programs.getIndirectProgram(instanceType, override, material.light(), material.cutout(), material.shaders()); var program = programs.getIndirectProgram(instanceType, override, material);
program.bind(); program.bind();

View File

@ -174,7 +174,7 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
for (InstancedDraw draw : instancer.draws()) { for (InstancedDraw draw : instancer.draws()) {
CommonCrumbling.applyCrumblingProperties(crumblingMaterial, draw.material()); CommonCrumbling.applyCrumblingProperties(crumblingMaterial, draw.material());
var program = programs.get(shader.instanceType(), ContextShader.CRUMBLING, crumblingMaterial.light(), crumblingMaterial.cutout(), crumblingMaterial.shaders()); var program = programs.get(shader.instanceType(), ContextShader.CRUMBLING, crumblingMaterial);
program.bind(); program.bind();
program.setInt("_flw_baseInstance", index); program.setInt("_flw_baseInstance", index);
uploadMaterialUniform(program, crumblingMaterial); uploadMaterialUniform(program, crumblingMaterial);

View File

@ -57,7 +57,7 @@ public class InstancedRenderStage {
for (var drawCall : drawCalls.draws) { for (var drawCall : drawCalls.draws) {
var material = drawCall.material(); var material = drawCall.material();
var program = programs.get(shader.instanceType(), environment.contextShader(), material.light(), material.cutout(), material.shaders()); var program = programs.get(shader.instanceType(), environment.contextShader(), material);
program.bind(); program.bind();
environment.setupDraw(program); environment.setupDraw(program);

View File

@ -9,6 +9,7 @@ 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;
@ -49,6 +50,11 @@ 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) {
return find(location).unwrap();
}
private static boolean isShader(ResourceLocation loc) { private static boolean isShader(ResourceLocation loc) {
var path = loc.getPath(); var path = loc.getPath();
return path.endsWith(".glsl") || path.endsWith(".vert") || path.endsWith(".frag") || path.endsWith(".comp"); return path.endsWith(".glsl") || path.endsWith(".vert") || path.endsWith(".frag") || path.endsWith(".comp");

View File

@ -1,19 +1,13 @@
package dev.engine_room.flywheel.lib.material; package dev.engine_room.flywheel.lib.material;
import org.jetbrains.annotations.ApiStatus;
import dev.engine_room.flywheel.api.Flywheel; import dev.engine_room.flywheel.api.Flywheel;
import dev.engine_room.flywheel.api.material.FogShader; import dev.engine_room.flywheel.api.material.FogShader;
public final class FogShaders { public final class FogShaders {
public static final FogShader NONE = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/none.glsl"))); public static final FogShader NONE = new SimpleFogShader(Flywheel.rl("fog/none.glsl"));
public static final FogShader LINEAR = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/linear.glsl"))); public static final FogShader LINEAR = new SimpleFogShader(Flywheel.rl("fog/linear.glsl"));
public static final FogShader LINEAR_FADE = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/linear_fade.glsl"))); public static final FogShader LINEAR_FADE = new SimpleFogShader(Flywheel.rl("fog/linear_fade.glsl"));
private FogShaders() { private FogShaders() {
} }
@ApiStatus.Internal
public static void init() {
}
} }

View File

@ -6,13 +6,11 @@ import dev.engine_room.flywheel.api.backend.Backend;
import dev.engine_room.flywheel.api.internal.FlwApiLink; import dev.engine_room.flywheel.api.internal.FlwApiLink;
import dev.engine_room.flywheel.api.layout.LayoutBuilder; import dev.engine_room.flywheel.api.layout.LayoutBuilder;
import dev.engine_room.flywheel.api.registry.IdRegistry; import dev.engine_room.flywheel.api.registry.IdRegistry;
import dev.engine_room.flywheel.api.registry.Registry;
import dev.engine_room.flywheel.api.visualization.BlockEntityVisualizer; import dev.engine_room.flywheel.api.visualization.BlockEntityVisualizer;
import dev.engine_room.flywheel.api.visualization.EntityVisualizer; import dev.engine_room.flywheel.api.visualization.EntityVisualizer;
import dev.engine_room.flywheel.api.visualization.VisualizationManager; import dev.engine_room.flywheel.api.visualization.VisualizationManager;
import dev.engine_room.flywheel.impl.layout.LayoutBuilderImpl; import dev.engine_room.flywheel.impl.layout.LayoutBuilderImpl;
import dev.engine_room.flywheel.impl.registry.IdRegistryImpl; import dev.engine_room.flywheel.impl.registry.IdRegistryImpl;
import dev.engine_room.flywheel.impl.registry.RegistryImpl;
import dev.engine_room.flywheel.impl.visualization.VisualizationManagerImpl; import dev.engine_room.flywheel.impl.visualization.VisualizationManagerImpl;
import dev.engine_room.flywheel.impl.visualization.VisualizerRegistryImpl; import dev.engine_room.flywheel.impl.visualization.VisualizerRegistryImpl;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
@ -22,11 +20,6 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
public class FlwApiLinkImpl implements FlwApiLink { public class FlwApiLinkImpl implements FlwApiLink {
@Override
public <T> Registry<T> createRegistry() {
return new RegistryImpl<>();
}
@Override @Override
public <T> IdRegistry<T> createIdRegistry() { public <T> IdRegistry<T> createIdRegistry() {
return new IdRegistryImpl<>(); return new IdRegistryImpl<>();

View File

@ -6,8 +6,6 @@ import org.slf4j.LoggerFactory;
import dev.engine_room.flywheel.api.Flywheel; import dev.engine_room.flywheel.api.Flywheel;
import dev.engine_room.flywheel.backend.FlwBackend; import dev.engine_room.flywheel.backend.FlwBackend;
import dev.engine_room.flywheel.impl.registry.IdRegistryImpl; import dev.engine_room.flywheel.impl.registry.IdRegistryImpl;
import dev.engine_room.flywheel.impl.registry.RegistryImpl;
import dev.engine_room.flywheel.lib.material.FogShaders;
import dev.engine_room.flywheel.lib.util.ShadersModHandler; import dev.engine_room.flywheel.lib.util.ShadersModHandler;
import dev.engine_room.flywheel.vanilla.VanillaVisuals; import dev.engine_room.flywheel.vanilla.VanillaVisuals;
@ -24,7 +22,6 @@ public final class FlwImpl {
// lib // lib
ShadersModHandler.init(); ShadersModHandler.init();
FogShaders.init();
// backend // backend
FlwBackend.init(FlwConfig.INSTANCE.backendConfig()); FlwBackend.init(FlwConfig.INSTANCE.backendConfig());
@ -34,7 +31,6 @@ public final class FlwImpl {
} }
public static void freezeRegistries() { public static void freezeRegistries() {
RegistryImpl.freezeAll();
IdRegistryImpl.freezeAll(); IdRegistryImpl.freezeAll();
} }
} }

View File

@ -1,68 +0,0 @@
package dev.engine_room.flywheel.impl.registry;
import java.util.Iterator;
import java.util.Set;
import org.jetbrains.annotations.UnmodifiableView;
import dev.engine_room.flywheel.api.registry.Registry;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectList;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import it.unimi.dsi.fastutil.objects.ObjectSets;
public class RegistryImpl<T> implements Registry<T> {
private static final ObjectList<RegistryImpl<?>> ALL = new ObjectArrayList<>();
private final ObjectSet<T> set = ObjectSets.synchronize(new ObjectOpenHashSet<>());
private final ObjectSet<T> setView = ObjectSets.unmodifiable(set);
private boolean frozen;
public RegistryImpl() {
ALL.add(this);
}
@Override
public void register(T object) {
if (frozen) {
throw new IllegalStateException("Cannot register to frozen registry!");
}
boolean added = set.add(object);
if (!added) {
throw new IllegalArgumentException("Cannot override registration!");
}
}
@Override
public <S extends T> S registerAndGet(S object) {
register(object);
return object;
}
@Override
@UnmodifiableView
public Set<T> getAll() {
return setView;
}
@Override
public boolean isFrozen() {
return frozen;
}
@Override
public Iterator<T> iterator() {
return getAll().iterator();
}
private void freeze() {
frozen = true;
}
public static void freezeAll() {
for (RegistryImpl<?> registry : ALL) {
registry.freeze();
}
}
}