Oopershaders

- Do not crash when an ubershader'd component is missing
- Reset instancing/indirect programs immediately on reload to invalidate
  them in case ubershader loading fails
This commit is contained in:
Jozufozu 2024-02-16 13:58:04 -08:00
parent f912be4834
commit 464deff42e
4 changed files with 34 additions and 12 deletions

View file

@ -2,6 +2,7 @@ package com.jozufozu.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;
@ -22,26 +23,37 @@ import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.ResourceManagerReloadListener; import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
public final class FlwPrograms { public final class FlwPrograms {
public static final Logger LOGGER = LoggerFactory.getLogger(Flywheel.ID + "/compile"); public static final Logger LOGGER = LoggerFactory.getLogger(Flywheel.ID + "/shaders");
private FlwPrograms() { private FlwPrograms() {
} }
private static void reload(ResourceManager resourceManager) { private static void reload(ResourceManager resourceManager) {
// Reset the programs in case the ubershader load fails.
InstancingPrograms.setInstance(null);
IndirectPrograms.setInstance(null);
var sources = new ShaderSources(resourceManager); var sources = new ShaderSources(resourceManager);
var preLoadStats = new CompilerStats("Preload"); var stats = new CompilerStats("ubershaders");
var loadChecker = new SourceLoader(sources, preLoadStats); var loadChecker = new SourceLoader(sources, stats);
var vertexMaterialComponent = createVertexMaterialComponent(loadChecker);
var fragmentMaterialComponent = createFragmentMaterialComponent(loadChecker);
var fogComponent = createFogComponent(loadChecker);
var cutoutComponent = createCutoutComponent(loadChecker);
if (stats.errored() || vertexMaterialComponent == null || fragmentMaterialComponent == null || fogComponent == null || cutoutComponent == null) {
// Probably means the shader sources are missing.
stats.emitErrorLog();
return;
}
List<SourceComponent> vertexComponents = List.of(vertexMaterialComponent);
List<SourceComponent> fragmentComponents = List.of(fragmentMaterialComponent, fogComponent, cutoutComponent);
var pipelineKeys = createPipelineKeys(); var pipelineKeys = createPipelineKeys();
List<SourceComponent> vertexComponents = List.of(createVertexMaterialComponent(loadChecker));
List<SourceComponent> fragmentComponents = List.of(createFragmentMaterialComponent(loadChecker), createFogComponent(loadChecker), createCutoutComponent(loadChecker));
InstancingPrograms.reload(sources, pipelineKeys, vertexComponents, fragmentComponents); InstancingPrograms.reload(sources, pipelineKeys, vertexComponents, fragmentComponents);
IndirectPrograms.reload(sources, pipelineKeys, vertexComponents, fragmentComponents); IndirectPrograms.reload(sources, pipelineKeys, vertexComponents, fragmentComponents);
if (preLoadStats.errored()) {
preLoadStats.emitErrorLog();
}
} }
private static ImmutableList<PipelineProgramKey> createPipelineKeys() { private static ImmutableList<PipelineProgramKey> createPipelineKeys() {
@ -54,6 +66,7 @@ public final class FlwPrograms {
return builder.build(); return builder.build();
} }
@Nullable
private static UberShaderComponent createVertexMaterialComponent(SourceLoader loadChecker) { private static UberShaderComponent createVertexMaterialComponent(SourceLoader loadChecker) {
return UberShaderComponent.builder(Flywheel.rl("uber_material_vertex")) return UberShaderComponent.builder(Flywheel.rl("uber_material_vertex"))
.materialSources(ShaderIndices.materialVertex() .materialSources(ShaderIndices.materialVertex()
@ -63,6 +76,7 @@ public final class FlwPrograms {
.build(loadChecker); .build(loadChecker);
} }
@Nullable
private static UberShaderComponent createFragmentMaterialComponent(SourceLoader loadChecker) { private static UberShaderComponent createFragmentMaterialComponent(SourceLoader loadChecker) {
return UberShaderComponent.builder(Flywheel.rl("uber_material_fragment")) return UberShaderComponent.builder(Flywheel.rl("uber_material_fragment"))
.materialSources(ShaderIndices.materialFragment() .materialSources(ShaderIndices.materialFragment()
@ -72,6 +86,7 @@ public final class FlwPrograms {
.build(loadChecker); .build(loadChecker);
} }
@Nullable
private static UberShaderComponent createFogComponent(SourceLoader loadChecker) { private static UberShaderComponent createFogComponent(SourceLoader loadChecker) {
return UberShaderComponent.builder(Flywheel.rl("uber_fog")) return UberShaderComponent.builder(Flywheel.rl("uber_fog"))
.materialSources(ShaderIndices.fog() .materialSources(ShaderIndices.fog()
@ -85,6 +100,7 @@ public final class FlwPrograms {
.build(loadChecker); .build(loadChecker);
} }
@Nullable
private static UberShaderComponent createCutoutComponent(SourceLoader loadChecker) { private static UberShaderComponent createCutoutComponent(SourceLoader loadChecker) {
return UberShaderComponent.builder(Flywheel.rl("uber_cutout")) return UberShaderComponent.builder(Flywheel.rl("uber_cutout"))
.materialSources(ShaderIndices.cutout() .materialSources(ShaderIndices.cutout()

View file

@ -3,6 +3,7 @@ package com.jozufozu.flywheel.backend.compile;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -102,7 +103,8 @@ public class IndirectPrograms extends AbstractPrograms {
return builder.build(); return builder.build();
} }
private static void setInstance(@Nullable IndirectPrograms newInstance) { @ApiStatus.Internal
public static void setInstance(@Nullable IndirectPrograms newInstance) {
if (instance != null) { if (instance != null) {
instance.release(); instance.release();
} }

View file

@ -3,6 +3,7 @@ package com.jozufozu.flywheel.backend.compile;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -42,7 +43,8 @@ public class InstancingPrograms extends AbstractPrograms {
setInstance(newInstance); setInstance(newInstance);
} }
private static void setInstance(@Nullable InstancingPrograms newInstance) { @ApiStatus.Internal
public static void setInstance(@Nullable InstancingPrograms newInstance) {
if (instance != null) { if (instance != null) {
instance.release(); instance.release();
} }

View file

@ -108,6 +108,7 @@ public class UberShaderComponent implements SourceComponent {
private final ResourceLocation name; private final ResourceLocation name;
private final List<ResourceLocation> materialSources = new ArrayList<>(); private final List<ResourceLocation> materialSources = new ArrayList<>();
private final List<AdaptedFn> adaptedFunctions = new ArrayList<>(); private final List<AdaptedFn> adaptedFunctions = new ArrayList<>();
@Nullable
private GlslExpr switchArg; private GlslExpr switchArg;
public Builder(ResourceLocation name) { public Builder(ResourceLocation name) {
@ -134,6 +135,7 @@ public class UberShaderComponent implements SourceComponent {
return this; return this;
} }
@Nullable
public UberShaderComponent build(SourceLoader sources) { public UberShaderComponent build(SourceLoader sources) {
if (switchArg == null) { if (switchArg == null) {
throw new NullPointerException("Switch argument must be set"); throw new NullPointerException("Switch argument must be set");