mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-27 07:26:48 +01:00
Ubern't
- De-uberify the light shader - Remove lightSources index - Include LightShader in PipelineProgramKey and parameterize the pipeline fragment shader by it - Profiling suggests that specializing the shaders uses significantly less GPU time, and we may want to do this for actual user-authored material shaders (and cutout?) as well - Sort LightShader highest in the material comparator - Implement a materialEquals method so IndirectCullingGroup can bucket draws on more that just material reference equality - Do not store any particular draw program in IndirectCullingGroup
This commit is contained in:
parent
2d37c3894d
commit
b7d2b2ac7c
15 changed files with 73 additions and 72 deletions
|
@ -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 <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!");
|
||||
|
|
|
@ -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<SourceComponent> vertexComponents = List.of(vertexComponentsHeader, vertexMaterialComponent);
|
||||
List<SourceComponent> fragmentComponents = List.of(fragmentComponentsHeader, fragmentMaterialComponent, fogComponent, cutoutComponent, lightComponent);
|
||||
List<SourceComponent> 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<PipelineProgramKey> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -16,7 +16,9 @@ import net.minecraft.client.Minecraft;
|
|||
import net.minecraft.client.renderer.texture.AbstractTexture;
|
||||
|
||||
public final class MaterialRenderState {
|
||||
public static final Comparator<Material> COMPARATOR = Comparator.comparing(Material::texture)
|
||||
public static final Comparator<Material> 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<I extends Instance> {
|
||||
|
@ -49,7 +50,6 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||
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<I extends Instance> {
|
|||
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<I extends Instance> {
|
|||
|
||||
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<I extends Instance> {
|
|||
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<I extends Instance> {
|
|||
}
|
||||
|
||||
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<I extends Instance> {
|
|||
|
||||
drawBarrier();
|
||||
|
||||
var flwBaseDraw = drawProgram.getUniformLocation("_flw_baseDraw");
|
||||
var flwBaseDraw = program.getUniformLocation("_flw_baseDraw");
|
||||
glUniform1ui(flwBaseDraw, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<InstancedInstancer<?>> {
|
|||
|
||||
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()) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
uint _flw_uberMaterialFragmentIndex;
|
||||
uint _flw_uberFogIndex;
|
||||
uint _flw_uberCutoutIndex;
|
||||
uint _flw_uberLightIndex;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue