diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/MaterialShaderIndices.java b/common/src/backend/java/dev/engine_room/flywheel/backend/MaterialShaderIndices.java index a67daaadb..8592a9e65 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/MaterialShaderIndices.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/MaterialShaderIndices.java @@ -8,7 +8,6 @@ import org.jetbrains.annotations.Unmodifiable; import dev.engine_room.flywheel.api.material.CutoutShader; import dev.engine_room.flywheel.api.material.FogShader; -import dev.engine_room.flywheel.api.material.LightShader; import dev.engine_room.flywheel.api.material.MaterialShaders; import dev.engine_room.flywheel.api.registry.Registry; import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -26,8 +25,6 @@ public final class MaterialShaderIndices { private static Index fogSources; @Nullable private static Index cutoutSources; - @Nullable - private static Index lightSources; private MaterialShaderIndices() { } @@ -60,13 +57,6 @@ public final class MaterialShaderIndices { return cutoutSources; } - public static Index lightSources() { - if (lightSources == null) { - lightSources = indexFromRegistry(LightShader.REGISTRY, LightShader::source); - } - return lightSources; - } - public static int vertexIndex(MaterialShaders shaders) { return vertexSources().index(shaders.vertexSource()); } @@ -83,10 +73,6 @@ public final class MaterialShaderIndices { return cutoutSources().index(cutoutShader.source()); } - public static int lightIndex(LightShader lightShader) { - return lightSources().index(lightShader.source()); - } - private static Index indexFromRegistry(Registry registry, Function sourceFunc) { if (!registry.isFrozen()) { throw new IllegalStateException("Cannot create index from registry that is not frozen!"); diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/FlwPrograms.java b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/FlwPrograms.java index 6681d4676..4bb7a5066 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/FlwPrograms.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/FlwPrograms.java @@ -10,6 +10,7 @@ import com.google.common.collect.ImmutableList; import dev.engine_room.flywheel.api.Flywheel; import dev.engine_room.flywheel.api.instance.InstanceType; +import dev.engine_room.flywheel.api.material.LightShader; 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; @@ -46,16 +47,15 @@ public final class FlwPrograms { var fragmentMaterialComponent = createFragmentMaterialComponent(loader); var fogComponent = createFogComponent(loader); var cutoutComponent = createCutoutComponent(loader); - var lightComponent = createLightComponent(loader); - if (stats.errored() || vertexComponentsHeader == null || fragmentComponentsHeader == null || vertexMaterialComponent == null || fragmentMaterialComponent == null || fogComponent == null || cutoutComponent == null || lightComponent == null) { + if (stats.errored() || vertexComponentsHeader == null || fragmentComponentsHeader == null || vertexMaterialComponent == null || fragmentMaterialComponent == null || fogComponent == null || cutoutComponent == null) { // Probably means the shader sources are missing. stats.emitErrorLog(); return; } List vertexComponents = List.of(vertexComponentsHeader, vertexMaterialComponent); - List fragmentComponents = List.of(fragmentComponentsHeader, fragmentMaterialComponent, fogComponent, cutoutComponent, lightComponent); + List fragmentComponents = List.of(fragmentComponentsHeader, fragmentMaterialComponent, fogComponent, cutoutComponent); var pipelineKeys = createPipelineKeys(); InstancingPrograms.reload(sources, pipelineKeys, vertexComponents, fragmentComponents); @@ -66,7 +66,9 @@ public final class FlwPrograms { ImmutableList.Builder builder = ImmutableList.builder(); for (ContextShader contextShader : ContextShader.values()) { for (InstanceType instanceType : InstanceType.REGISTRY) { - builder.add(new PipelineProgramKey(instanceType, contextShader)); + for (LightShader light : LightShader.REGISTRY.getAll()) { + builder.add(new PipelineProgramKey(instanceType, contextShader, light)); + } } } return builder.build(); @@ -119,18 +121,4 @@ public final class FlwPrograms { .switchOn(GlslExpr.variable("_flw_uberCutoutIndex")) .build(loader); } - - // TODO: Do not uber this component. Shader compile times are very high now - @Nullable - private static UberShaderComponent createLightComponent(SourceLoader loader) { - return UberShaderComponent.builder(Flywheel.rl("light")) - .materialSources(MaterialShaderIndices.lightSources() - .all()) - .adapt(FnSignature.create() - .returnType("void") - .name("flw_shaderLight") - .build()) - .switchOn(GlslExpr.variable("_flw_uberLightIndex")) - .build(loader); - } } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/IndirectPrograms.java b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/IndirectPrograms.java index a2c7ed16c..3b705754a 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/IndirectPrograms.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/IndirectPrograms.java @@ -9,6 +9,7 @@ import com.google.common.collect.ImmutableList; import dev.engine_room.flywheel.api.Flywheel; import dev.engine_room.flywheel.api.instance.InstanceType; +import dev.engine_room.flywheel.api.material.LightShader; 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.core.CompilationHarness; @@ -167,8 +168,8 @@ public class IndirectPrograms extends AtomicReferenceCounted { return instance != null; } - public GlProgram getIndirectProgram(InstanceType instanceType, ContextShader contextShader) { - return pipeline.get(new PipelineProgramKey(instanceType, contextShader)); + public GlProgram getIndirectProgram(InstanceType instanceType, ContextShader contextShader, LightShader light) { + return pipeline.get(new PipelineProgramKey(instanceType, contextShader, light)); } public GlProgram getCullingProgram(InstanceType instanceType) { diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/InstancingPrograms.java b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/InstancingPrograms.java index f91483469..6b9fcfad9 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/InstancingPrograms.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/InstancingPrograms.java @@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable; import com.google.common.collect.ImmutableList; import dev.engine_room.flywheel.api.instance.InstanceType; +import dev.engine_room.flywheel.api.material.LightShader; import dev.engine_room.flywheel.backend.gl.GlCompat; import dev.engine_room.flywheel.backend.gl.shader.GlProgram; import dev.engine_room.flywheel.backend.glsl.GlslVersion; @@ -78,8 +79,8 @@ public class InstancingPrograms extends AtomicReferenceCounted { return instance != null; } - public GlProgram get(InstanceType instanceType, ContextShader contextShader) { - return pipeline.get(new PipelineProgramKey(instanceType, contextShader)); + public GlProgram get(InstanceType instanceType, ContextShader contextShader, LightShader light) { + return pipeline.get(new PipelineProgramKey(instanceType, contextShader, light)); } @Override diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/PipelineCompiler.java b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/PipelineCompiler.java index bc303f8f9..405ca7ffe 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/PipelineCompiler.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/PipelineCompiler.java @@ -56,7 +56,8 @@ public final class PipelineCompiler { .nameMapper(key -> { var context = key.contextShader() .nameLowerCase(); - return "pipeline/" + pipeline.compilerMarker() + "/" + context; + return "pipeline/" + pipeline.compilerMarker() + "/" + ResourceUtil.toDebugFileNameNoExtension(key.light() + .source()) + "_" + context; }) .requireExtensions(extensions) .enableExtension("GL_ARB_conservative_depth") @@ -65,6 +66,8 @@ public final class PipelineCompiler { .onCompile((key, comp) -> lightSmoothness.onCompile(comp)) .withResource(API_IMPL_FRAG) .withComponents(fragmentComponents) + .withResource(key -> key.light() + .source()) .withResource(pipeline.fragmentMain())) .preLink((key, program) -> { program.bindAttribLocation("_flw_aPos", 0); diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/PipelineProgramKey.java b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/PipelineProgramKey.java index 691e026b5..3fe6a1033 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/compile/PipelineProgramKey.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/compile/PipelineProgramKey.java @@ -1,12 +1,14 @@ package dev.engine_room.flywheel.backend.compile; import dev.engine_room.flywheel.api.instance.InstanceType; +import dev.engine_room.flywheel.api.material.LightShader; /** * Represents the entire context of a program's usage. * * @param instanceType The instance shader to use. * @param contextShader The context shader to use. + * @param light The light shader to use. */ -public record PipelineProgramKey(InstanceType instanceType, ContextShader contextShader) { +public record PipelineProgramKey(InstanceType instanceType, ContextShader contextShader, LightShader light) { } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/MaterialEncoder.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/MaterialEncoder.java index 36e7c6ba7..fc45d402e 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/MaterialEncoder.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/MaterialEncoder.java @@ -55,8 +55,7 @@ public final class MaterialEncoder { public static int packUberShader(Material material) { var fog = MaterialShaderIndices.fogIndex(material.fog()); var cutout = MaterialShaderIndices.cutoutIndex(material.cutout()); - var light = MaterialShaderIndices.lightIndex(material.light()); - return (light & 0x3FF) | (cutout & 0x3FF) << 10 | (fog & 0x3FF) << 20; + return (cutout & 0xFFFF) | (fog & 0xFFFF) << 16; } // Packed format: diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/MaterialRenderState.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/MaterialRenderState.java index de0637ddb..0ddf8e1e7 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/MaterialRenderState.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/MaterialRenderState.java @@ -16,7 +16,9 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.AbstractTexture; public final class MaterialRenderState { - public static final Comparator COMPARATOR = Comparator.comparing(Material::texture) + public static final Comparator COMPARATOR = Comparator.comparing((Material m) -> m.light() + .source()) + .thenComparing(Material::texture) .thenComparing(Material::blur) .thenComparing(Material::mipmap) .thenComparing(Material::backfaceCulling) @@ -177,4 +179,18 @@ public final class MaterialRenderState { RenderSystem.depthMask(true); RenderSystem.colorMask(true, true, true, true); } + + public static boolean materialEquals(Material lhs, Material rhs) { + if (lhs == rhs) { + return true; + } + + // Not here because ubershader: useLight, useOverlay, diffuse, shaders, fog shader, and cutout shader + // Everything in the comparator should be here. + return lhs.blur() == rhs.blur() && lhs.mipmap() == rhs.mipmap() && lhs.backfaceCulling() == rhs.backfaceCulling() && lhs.polygonOffset() == rhs.polygonOffset() && lhs.light() + .source() + .equals(rhs.light() + .source()) && lhs.texture() + .equals(rhs.texture()) && lhs.depthTest() == rhs.depthTest() && lhs.transparency() == rhs.transparency() && lhs.writeMask() == rhs.writeMask(); + } } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectCullingGroup.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectCullingGroup.java index 5dbcbe3c8..213b9016c 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectCullingGroup.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectCullingGroup.java @@ -28,6 +28,7 @@ import dev.engine_room.flywheel.backend.engine.embed.Environment; import dev.engine_room.flywheel.backend.engine.uniform.Uniforms; import dev.engine_room.flywheel.backend.gl.GlCompat; import dev.engine_room.flywheel.backend.gl.shader.GlProgram; +import dev.engine_room.flywheel.lib.material.LightShaders; import dev.engine_room.flywheel.lib.math.MoreMath; public class IndirectCullingGroup { @@ -49,7 +50,6 @@ public class IndirectCullingGroup { private final IndirectPrograms programs; private final GlProgram cullProgram; private final GlProgram applyProgram; - private final GlProgram drawProgram; private boolean needsDrawBarrier; private boolean needsDrawSort; @@ -65,7 +65,6 @@ public class IndirectCullingGroup { this.programs = programs; cullProgram = programs.getCullingProgram(instanceType); applyProgram = programs.getApplyProgram(); - drawProgram = programs.getIndirectProgram(instanceType, environment.contextShader()); } public void flushInstancers() { @@ -158,20 +157,23 @@ public class IndirectCullingGroup { for (int start = 0, i = 0; i < indirectDraws.size(); i++) { var draw1 = indirectDraws.get(i); - var material1 = draw1.material(); - var visualType1 = draw1.visualType(); // if the next draw call has a different VisualType or Material, start a new MultiDraw - if (i == indirectDraws.size() - 1 || visualType1 != indirectDraws.get(i + 1) - .visualType() || !material1.equals(indirectDraws.get(i + 1) - .material())) { - multiDraws.computeIfAbsent(visualType1, s -> new ArrayList<>()) - .add(new MultiDraw(material1, start, i + 1)); + if (i == indirectDraws.size() - 1 || incompatibleDraws(draw1, indirectDraws.get(i + 1))) { + multiDraws.computeIfAbsent(draw1.visualType(), s -> new ArrayList<>()) + .add(new MultiDraw(draw1.material(), start, i + 1)); start = i + 1; } } } + private boolean incompatibleDraws(IndirectDraw draw1, IndirectDraw draw2) { + if (draw1.visualType() != draw2.visualType()) { + return true; + } + return !MaterialRenderState.materialEquals(draw1.material(), draw2.material()); + } + public boolean hasVisualType(VisualType visualType) { return multiDraws.containsKey(visualType); } @@ -199,17 +201,25 @@ public class IndirectCullingGroup { return; } - drawProgram.bind(); buffers.bindForDraw(); - environment.setupDraw(drawProgram); - drawBarrier(); - var flwBaseDraw = drawProgram.getUniformLocation("_flw_baseDraw"); + GlProgram lastProgram = null; + int baseDrawUniformLoc = -1; for (var multiDraw : multiDraws.get(visualType)) { - glUniform1ui(flwBaseDraw, multiDraw.start); + var drawProgram = programs.getIndirectProgram(instanceType, environment.contextShader(), multiDraw.material.light()); + if (drawProgram != lastProgram) { + lastProgram = drawProgram; + + // Don't need to do this unless the program changes. + drawProgram.bind(); + environment.setupDraw(drawProgram); + baseDrawUniformLoc = drawProgram.getUniformLocation("_flw_baseDraw"); + } + + glUniform1ui(baseDrawUniformLoc, multiDraw.start); MaterialRenderState.setup(multiDraw.material); @@ -218,7 +228,7 @@ public class IndirectCullingGroup { } public void bindWithContextShader(ContextShader override) { - var program = programs.getIndirectProgram(instanceType, override); + var program = programs.getIndirectProgram(instanceType, override, LightShaders.SMOOTH_WHEN_EMBEDDED); program.bind(); @@ -226,7 +236,7 @@ public class IndirectCullingGroup { drawBarrier(); - var flwBaseDraw = drawProgram.getUniformLocation("_flw_baseDraw"); + var flwBaseDraw = program.getUniformLocation("_flw_baseDraw"); glUniform1ui(flwBaseDraw, 0); } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedDrawManager.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedDrawManager.java index dfdc57808..93d68e11d 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedDrawManager.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedDrawManager.java @@ -28,6 +28,7 @@ import dev.engine_room.flywheel.backend.gl.GlStateTracker; import dev.engine_room.flywheel.backend.gl.TextureBuffer; import dev.engine_room.flywheel.backend.gl.array.GlVertexArray; import dev.engine_room.flywheel.backend.gl.shader.GlProgram; +import dev.engine_room.flywheel.lib.material.LightShaders; import dev.engine_room.flywheel.lib.material.SimpleMaterial; import net.minecraft.client.resources.model.ModelBakery; @@ -170,7 +171,7 @@ public class InstancedDrawManager extends DrawManager> { GroupKey shader = groupEntry.getKey(); - var program = programs.get(shader.instanceType(), ContextShader.CRUMBLING); + var program = programs.get(shader.instanceType(), ContextShader.CRUMBLING, LightShaders.SMOOTH_WHEN_EMBEDDED); program.bind(); for (var progressEntry : byProgress.int2ObjectEntrySet()) { diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedRenderStage.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedRenderStage.java index 5e62e9718..73b1fdddf 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedRenderStage.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/instancing/InstancedRenderStage.java @@ -54,12 +54,13 @@ public class InstancedRenderStage { var environment = shader.environment(); - var program = programs.get(shader.instanceType(), environment.contextShader()); - program.bind(); - - environment.setupDraw(program); - for (var drawCall : drawCalls.draws) { + var program = programs.get(shader.instanceType(), environment.contextShader(), drawCall.material() + .light()); + program.bind(); + + environment.setupDraw(program); + var material = drawCall.material(); uploadMaterialUniform(program, material); diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/components_header.frag b/common/src/backend/resources/assets/flywheel/flywheel/internal/components_header.frag index 5c0550d60..ef45f6d68 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/components_header.frag +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/components_header.frag @@ -1,4 +1,3 @@ uint _flw_uberMaterialFragmentIndex; uint _flw_uberFogIndex; uint _flw_uberCutoutIndex; -uint _flw_uberLightIndex; diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.frag b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.frag index a67cb47a2..7d528ce24 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.frag +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.frag @@ -6,7 +6,7 @@ flat in uvec3 _flw_packedMaterial; void main() { _flw_uberMaterialFragmentIndex = _flw_packedMaterial.x; - _flw_unpackUint3x10(_flw_packedMaterial.y, _flw_uberFogIndex, _flw_uberCutoutIndex, _flw_uberLightIndex); + _flw_unpackUint2x16(_flw_packedMaterial.y, _flw_uberFogIndex, _flw_uberCutoutIndex); _flw_unpackMaterialProperties(_flw_packedMaterial.z, flw_material); _flw_main(); diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.frag b/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.frag index 6ada1a130..cfd7dfea1 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.frag +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.frag @@ -5,7 +5,7 @@ uniform uvec4 _flw_packedMaterial; void main() { _flw_uberMaterialFragmentIndex = _flw_packedMaterial.y; - _flw_unpackUint3x10(_flw_packedMaterial.z, _flw_uberFogIndex, _flw_uberCutoutIndex, _flw_uberLightIndex); + _flw_unpackUint2x16(_flw_packedMaterial.z, _flw_uberFogIndex, _flw_uberCutoutIndex); _flw_unpackMaterialProperties(_flw_packedMaterial.w, flw_material); _flw_main(); diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/packed_material.glsl b/common/src/backend/resources/assets/flywheel/flywheel/internal/packed_material.glsl index 892795e66..b56828c1f 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/packed_material.glsl +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/packed_material.glsl @@ -53,9 +53,3 @@ void _flw_unpackUint2x16(uint s, out uint hi, out uint lo) { hi = (s >> 16) & 0xFFFFu; lo = s & 0xFFFFu; } - -void _flw_unpackUint3x10(uint s, out uint hi, out uint mi, out uint lo) { - hi = (s >> 20) & 0x3FFu; - mi = (s >> 10) & 0x3FFu; - lo = s & 0x3FFu; -}