Fix crash after compilation error during in-world resource reload

- Store *Programs inside engines to disallow replacement and use
reference counting to delete programs at the appropriate time
- Move CompilationHarness, Compile, and SourceLoader to compile.core
- Fix packed material comments
- Fix pack.mcmeta pack format
- Remove Embeddium version range
This commit is contained in:
PepperCode1 2024-01-17 10:37:39 -08:00
parent 45ba75af78
commit 80127664d2
25 changed files with 210 additions and 139 deletions

View file

@ -157,8 +157,7 @@ tasks.named('processResources', ProcessResources).configure {
forge_version : forge_version, forge_version : forge_version,
forge_version_range : forge_version_range, forge_version_range : forge_version_range,
loader_version_range : loader_version_range, loader_version_range : loader_version_range,
mod_version : mod_version, mod_version : mod_version
embeddium_version_range: embeddium_version_range
] ]
inputs.properties replaceProperties inputs.properties replaceProperties

View file

@ -10,7 +10,6 @@ forge_version=47.2.19
minecraft_version_range=[1.20.1,1.20.3) minecraft_version_range=[1.20.1,1.20.3)
forge_version_range=[47,) forge_version_range=[47,)
loader_version_range=[47,) loader_version_range=[47,)
embeddium_version_range=[0.2.10,0.3)
# build dependency versions # build dependency versions
forgegradle_version = [6.0.16,6.2) forgegradle_version = [6.0.16,6.2)

View file

@ -21,7 +21,7 @@ public class Backends {
public static final Backend INSTANCING = SimpleBackend.builder() public static final Backend INSTANCING = SimpleBackend.builder()
.engineMessage(Component.literal("Using Instancing Engine") .engineMessage(Component.literal("Using Instancing Engine")
.withStyle(ChatFormatting.GREEN)) .withStyle(ChatFormatting.GREEN))
.engineFactory(level -> new InstancingEngine(256)) .engineFactory(level -> new InstancingEngine(InstancingPrograms.get(), 256))
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.supportsInstancing() && InstancingPrograms.allLoaded()) .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.supportsInstancing() && InstancingPrograms.allLoaded())
.register(Flywheel.rl("instancing")); .register(Flywheel.rl("instancing"));
@ -31,7 +31,7 @@ public class Backends {
public static final Backend INDIRECT = SimpleBackend.builder() public static final Backend INDIRECT = SimpleBackend.builder()
.engineMessage(Component.literal("Using Indirect Engine") .engineMessage(Component.literal("Using Indirect Engine")
.withStyle(ChatFormatting.GREEN)) .withStyle(ChatFormatting.GREEN))
.engineFactory(level -> new IndirectEngine(256)) .engineFactory(level -> new IndirectEngine(IndirectPrograms.get(), 256))
.fallback(() -> Backends.INSTANCING) .fallback(() -> Backends.INSTANCING)
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.supportsIndirect() && IndirectPrograms.allLoaded()) .supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.supportsIndirect() && IndirectPrograms.allLoaded())
.register(Flywheel.rl("indirect")); .register(Flywheel.rl("indirect"));

View file

@ -0,0 +1,31 @@
package com.jozufozu.flywheel.backend.compile;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class AbstractPrograms {
private final AtomicInteger refCount = new AtomicInteger();
private volatile boolean isDeleted;
public int refCount() {
return refCount.get();
}
public void acquire() {
if (isDeleted) {
throw new IllegalStateException("Tried to acquire deleted instance of '" + getClass().getName() + "'!");
}
refCount.getAndIncrement();
}
public void release() {
int newCount = refCount.decrementAndGet();
if (newCount == 0) {
isDeleted = true;
delete();
} else if (newCount < 0) {
throw new IllegalStateException("Tried to delete instance of '" + getClass().getName() + "' more times than it was acquired!");
}
}
protected abstract void delete();
}

View file

@ -11,6 +11,7 @@ import com.jozufozu.flywheel.backend.ShaderIndices;
import com.jozufozu.flywheel.backend.compile.component.UberShaderComponent; import com.jozufozu.flywheel.backend.compile.component.UberShaderComponent;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent; import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.backend.compile.core.CompilerStats; import com.jozufozu.flywheel.backend.compile.core.CompilerStats;
import com.jozufozu.flywheel.backend.compile.core.SourceLoader;
import com.jozufozu.flywheel.backend.glsl.ShaderSources; import com.jozufozu.flywheel.backend.glsl.ShaderSources;
import com.jozufozu.flywheel.backend.glsl.SourceComponent; import com.jozufozu.flywheel.backend.glsl.SourceComponent;
import com.jozufozu.flywheel.backend.glsl.generate.FnSignature; import com.jozufozu.flywheel.backend.glsl.generate.FnSignature;
@ -19,13 +20,12 @@ import com.jozufozu.flywheel.backend.glsl.generate.GlslExpr;
import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.ResourceManagerReloadListener; import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
public class FlwPrograms { public final class FlwPrograms {
private FlwPrograms() { private FlwPrograms() {
} }
public static void reload(ResourceManager resourceManager) { private static void reload(ResourceManager resourceManager) {
var sources = new ShaderSources(resourceManager); var sources = new ShaderSources(resourceManager);
var preLoadStats = new CompilerStats(); var preLoadStats = new CompilerStats();
var loadChecker = new SourceLoader(sources, preLoadStats); var loadChecker = new SourceLoader(sources, preLoadStats);

View file

@ -11,6 +11,8 @@ import com.jozufozu.flywheel.api.context.Context;
import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.backend.compile.component.IndirectComponent; import com.jozufozu.flywheel.backend.compile.component.IndirectComponent;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent; import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.backend.compile.core.CompilationHarness;
import com.jozufozu.flywheel.backend.compile.core.Compile;
import com.jozufozu.flywheel.backend.gl.GlCompat; import com.jozufozu.flywheel.backend.gl.GlCompat;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
@ -20,20 +22,23 @@ import com.jozufozu.flywheel.backend.glsl.SourceComponent;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public class IndirectPrograms { public class IndirectPrograms extends AbstractPrograms {
private static final ResourceLocation CULL_SHADER_MAIN = Flywheel.rl("internal/indirect/cull.glsl"); private static final ResourceLocation CULL_SHADER_MAIN = Flywheel.rl("internal/indirect/cull.glsl");
private static final ResourceLocation APPLY_SHADER_MAIN = Flywheel.rl("internal/indirect/apply.glsl"); private static final ResourceLocation APPLY_SHADER_MAIN = Flywheel.rl("internal/indirect/apply.glsl");
private static final ResourceLocation SCATTER_SHADER_MAIN = Flywheel.rl("internal/indirect/scatter.glsl"); private static final ResourceLocation SCATTER_SHADER_MAIN = Flywheel.rl("internal/indirect/scatter.glsl");
public static IndirectPrograms instance;
private static final Compile<InstanceType<?>> CULL = new Compile<>(); private static final Compile<InstanceType<?>> CULL = new Compile<>();
private static final Compile<ResourceLocation> UTIL = new Compile<>(); private static final Compile<ResourceLocation> UTIL = new Compile<>();
@Nullable
private static IndirectPrograms instance;
private final Map<PipelineProgramKey, GlProgram> pipeline; private final Map<PipelineProgramKey, GlProgram> pipeline;
private final Map<InstanceType<?>, GlProgram> culling; private final Map<InstanceType<?>, GlProgram> culling;
private final GlProgram apply; private final GlProgram apply;
private final GlProgram scatter; private final GlProgram scatter;
public IndirectPrograms(Map<PipelineProgramKey, GlProgram> pipeline, Map<InstanceType<?>, GlProgram> culling, GlProgram apply, GlProgram scatter) { private IndirectPrograms(Map<PipelineProgramKey, GlProgram> pipeline, Map<InstanceType<?>, GlProgram> culling, GlProgram apply, GlProgram scatter) {
this.pipeline = pipeline; this.pipeline = pipeline;
this.culling = culling; this.culling = culling;
this.apply = apply; this.apply = apply;
@ -41,7 +46,8 @@ public class IndirectPrograms {
} }
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) { static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
_delete(); IndirectPrograms newInstance = null;
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, uniformComponent, vertexComponents, fragmentComponents); var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, uniformComponent, vertexComponents, fragmentComponents);
var cullingCompiler = createCullingCompiler(uniformComponent, sources); var cullingCompiler = createCullingCompiler(uniformComponent, sources);
var applyCompiler = createUtilCompiler(sources); var applyCompiler = createUtilCompiler(sources);
@ -52,38 +58,17 @@ public class IndirectPrograms {
var utils = applyCompiler.compileAndReportErrors(List.of(APPLY_SHADER_MAIN, SCATTER_SHADER_MAIN)); var utils = applyCompiler.compileAndReportErrors(List.of(APPLY_SHADER_MAIN, SCATTER_SHADER_MAIN));
if (pipelineResult != null && cullingResult != null && utils != null) { if (pipelineResult != null && cullingResult != null && utils != null) {
instance = new IndirectPrograms(pipelineResult, cullingResult, utils.get(APPLY_SHADER_MAIN), utils.get(SCATTER_SHADER_MAIN)); newInstance = new IndirectPrograms(pipelineResult, cullingResult, utils.get(APPLY_SHADER_MAIN), utils.get(SCATTER_SHADER_MAIN));
} }
} catch (Throwable e) { } catch (Throwable t) {
Flywheel.LOGGER.error("Failed to compile indirect programs", e); Flywheel.LOGGER.error("Failed to compile indirect programs", t);
} }
pipelineCompiler.delete(); pipelineCompiler.delete();
cullingCompiler.delete(); cullingCompiler.delete();
applyCompiler.delete(); applyCompiler.delete();
}
private static ImmutableList<InstanceType<?>> createCullingKeys() { setInstance(newInstance);
ImmutableList.Builder<InstanceType<?>> builder = ImmutableList.builder();
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
builder.add(instanceType);
}
return builder.build();
}
@Nullable
public static IndirectPrograms get() {
return instance;
}
public static boolean allLoaded() {
return instance != null;
}
private static void _delete() {
if (instance != null) {
instance.delete();
instance = null;
}
} }
private static CompilationHarness<InstanceType<?>> createCullingCompiler(UniformComponent uniformComponent, ShaderSources sources) { private static CompilationHarness<InstanceType<?>> createCullingCompiler(UniformComponent uniformComponent, ShaderSources sources) {
@ -106,6 +91,33 @@ public class IndirectPrograms {
.harness(sources); .harness(sources);
} }
private static ImmutableList<InstanceType<?>> createCullingKeys() {
ImmutableList.Builder<InstanceType<?>> builder = ImmutableList.builder();
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
builder.add(instanceType);
}
return builder.build();
}
private static void setInstance(@Nullable IndirectPrograms newInstance) {
if (instance != null) {
instance.release();
}
if (newInstance != null) {
newInstance.acquire();
}
instance = newInstance;
}
@Nullable
public static IndirectPrograms get() {
return instance;
}
public static boolean allLoaded() {
return instance != null;
}
public GlProgram getIndirectProgram(InstanceType<?> instanceType, Context contextShader) { public GlProgram getIndirectProgram(InstanceType<?> instanceType, Context contextShader) {
return pipeline.get(new PipelineProgramKey(instanceType, contextShader)); return pipeline.get(new PipelineProgramKey(instanceType, contextShader));
} }
@ -122,7 +134,8 @@ public class IndirectPrograms {
return scatter; return scatter;
} }
public void delete() { @Override
protected void delete() {
pipeline.values() pipeline.values()
.forEach(GlProgram::delete); .forEach(GlProgram::delete);
culling.values() culling.values()

View file

@ -14,28 +14,44 @@ import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.backend.glsl.ShaderSources; import com.jozufozu.flywheel.backend.glsl.ShaderSources;
import com.jozufozu.flywheel.backend.glsl.SourceComponent; import com.jozufozu.flywheel.backend.glsl.SourceComponent;
public class InstancingPrograms { public class InstancingPrograms extends AbstractPrograms {
static InstancingPrograms instance; @Nullable
private static InstancingPrograms instance;
private final Map<PipelineProgramKey, GlProgram> pipeline; private final Map<PipelineProgramKey, GlProgram> pipeline;
public InstancingPrograms(Map<PipelineProgramKey, GlProgram> pipeline) { private InstancingPrograms(Map<PipelineProgramKey, GlProgram> pipeline) {
this.pipeline = pipeline; this.pipeline = pipeline;
} }
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) { static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
_delete(); InstancingPrograms newInstance = null;
var instancingCompiler = PipelineCompiler.create(sources, Pipelines.INSTANCED_ARRAYS, uniformComponent, vertexComponents, fragmentComponents);
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INSTANCED_ARRAYS, uniformComponent, vertexComponents, fragmentComponents);
try { try {
var result = instancingCompiler.compileAndReportErrors(pipelineKeys); var pipelineResult = pipelineCompiler.compileAndReportErrors(pipelineKeys);
if (result != null) { if (pipelineResult != null) {
instance = new InstancingPrograms(result); newInstance = new InstancingPrograms(pipelineResult);
} }
} catch (Throwable e) { } catch (Throwable t) {
Flywheel.LOGGER.error("Failed to compile instancing programs", e); Flywheel.LOGGER.error("Failed to compile instancing programs", t);
} }
instancingCompiler.delete();
pipelineCompiler.delete();
setInstance(newInstance);
}
private static void setInstance(@Nullable InstancingPrograms newInstance) {
if (instance != null) {
instance.release();
}
if (newInstance != null) {
newInstance.acquire();
}
instance = newInstance;
} }
@Nullable @Nullable
@ -47,18 +63,12 @@ public class InstancingPrograms {
return instance != null; return instance != null;
} }
static void _delete() {
if (instance != null) {
instance.delete();
instance = null;
}
}
public GlProgram get(InstanceType<?> instanceType, Context contextShader) { public GlProgram get(InstanceType<?> instanceType, Context contextShader) {
return pipeline.get(new PipelineProgramKey(instanceType, contextShader)); return pipeline.get(new PipelineProgramKey(instanceType, contextShader));
} }
public void delete() { @Override
protected void delete() {
pipeline.values() pipeline.values()
.forEach(GlProgram::delete); .forEach(GlProgram::delete);
} }

View file

@ -9,7 +9,10 @@ import com.jozufozu.flywheel.api.layout.UnsignedIntegerRepr;
import com.jozufozu.flywheel.api.layout.ValueRepr; import com.jozufozu.flywheel.api.layout.ValueRepr;
import com.jozufozu.flywheel.api.layout.VectorElementType; import com.jozufozu.flywheel.api.layout.VectorElementType;
public class LayoutInterpreter { public final class LayoutInterpreter {
private LayoutInterpreter() {
}
public static int attributeCount(ElementType type) { public static int attributeCount(ElementType type) {
if (type instanceof ScalarElementType) { if (type instanceof ScalarElementType) {
return 1; return 1;
@ -34,8 +37,15 @@ public class LayoutInterpreter {
throw new IllegalArgumentException("Unknown type " + type); throw new IllegalArgumentException("Unknown type " + type);
} }
public static String matrixTypeName(MatrixElementType matrix) { public static String scalarTypeName(ValueRepr repr) {
return "mat" + matrix.columns() + "x" + matrix.rows(); if (repr instanceof IntegerRepr) {
return "int";
} else if (repr instanceof UnsignedIntegerRepr) {
return "uint";
} else if (repr instanceof FloatRepr) {
return "float";
}
throw new IllegalArgumentException("Unknown repr " + repr);
} }
public static String vectorTypeName(ValueRepr repr, int size) { public static String vectorTypeName(ValueRepr repr, int size) {
@ -49,14 +59,7 @@ public class LayoutInterpreter {
throw new IllegalArgumentException("Unknown repr " + repr); throw new IllegalArgumentException("Unknown repr " + repr);
} }
public static String scalarTypeName(ValueRepr repr) { public static String matrixTypeName(MatrixElementType matrix) {
if (repr instanceof IntegerRepr) { return "mat" + matrix.columns() + "x" + matrix.rows();
return "int";
} else if (repr instanceof UnsignedIntegerRepr) {
return "uint";
} else if (repr instanceof FloatRepr) {
return "float";
}
throw new IllegalArgumentException("Unknown repr " + repr);
} }
} }

View file

@ -4,6 +4,8 @@ import java.util.List;
import com.jozufozu.flywheel.backend.InternalVertex; import com.jozufozu.flywheel.backend.InternalVertex;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent; import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.backend.compile.core.CompilationHarness;
import com.jozufozu.flywheel.backend.compile.core.Compile;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import com.jozufozu.flywheel.backend.glsl.ShaderSources; import com.jozufozu.flywheel.backend.glsl.ShaderSources;
import com.jozufozu.flywheel.backend.glsl.SourceComponent; import com.jozufozu.flywheel.backend.glsl.SourceComponent;

View file

@ -9,7 +9,7 @@ import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.jozufozu.flywheel.backend.compile.SourceLoader; import com.jozufozu.flywheel.backend.compile.core.SourceLoader;
import com.jozufozu.flywheel.backend.glsl.SourceComponent; import com.jozufozu.flywheel.backend.glsl.SourceComponent;
import com.jozufozu.flywheel.backend.glsl.SourceFile; import com.jozufozu.flywheel.backend.glsl.SourceFile;
import com.jozufozu.flywheel.backend.glsl.generate.FnSignature; import com.jozufozu.flywheel.backend.glsl.generate.FnSignature;

View file

@ -5,7 +5,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.backend.compile.SourceLoader; import com.jozufozu.flywheel.backend.compile.core.SourceLoader;
import com.jozufozu.flywheel.backend.glsl.SourceComponent; import com.jozufozu.flywheel.backend.glsl.SourceComponent;
import com.jozufozu.flywheel.backend.glsl.SourceFile; import com.jozufozu.flywheel.backend.glsl.SourceFile;
import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder; import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder;

View file

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.backend.compile; package com.jozufozu.flywheel.backend.compile.core;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@ -7,9 +7,6 @@ import java.util.Map;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.backend.compile.core.CompilerStats;
import com.jozufozu.flywheel.backend.compile.core.ProgramLinker;
import com.jozufozu.flywheel.backend.compile.core.ShaderCompiler;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.backend.glsl.ShaderSources; import com.jozufozu.flywheel.backend.glsl.ShaderSources;

View file

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.backend.compile; package com.jozufozu.flywheel.backend.compile.core;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -13,9 +13,6 @@ import java.util.function.Function;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.backend.compile.core.Compilation;
import com.jozufozu.flywheel.backend.compile.core.ProgramLinker;
import com.jozufozu.flywheel.backend.compile.core.ShaderCompiler;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.backend.gl.shader.GlShader; import com.jozufozu.flywheel.backend.gl.shader.GlShader;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.backend.gl.shader.ShaderType;

View file

@ -1,15 +1,13 @@
package com.jozufozu.flywheel.backend.compile; package com.jozufozu.flywheel.backend.compile.core;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.backend.compile.core.CompilerStats;
import com.jozufozu.flywheel.backend.glsl.ShaderSources; import com.jozufozu.flywheel.backend.glsl.ShaderSources;
import com.jozufozu.flywheel.backend.glsl.SourceFile; import com.jozufozu.flywheel.backend.glsl.SourceFile;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public class SourceLoader { public class SourceLoader {
private final ShaderSources sources; private final ShaderSources sources;
private final CompilerStats stats; private final CompilerStats stats;

View file

@ -20,7 +20,8 @@ public class CommonCrumbling {
.transparency(Transparency.CRUMBLING) .transparency(Transparency.CRUMBLING)
.writeMask(WriteMask.COLOR) .writeMask(WriteMask.COLOR)
.useOverlay(false) .useOverlay(false)
.useLight(false); .useLight(false)
.diffuse(false);
} }
public static int getDiffuseTexture(Material material) { public static int getDiffuseTexture(Material material) {

View file

@ -8,7 +8,7 @@ import com.jozufozu.flywheel.backend.ShaderIndices;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
// Materials are unpacked in "flywheel:flywheel/internal/material.glsl" // Materials are unpacked in "flywheel:flywheel/internal/packed_material.glsl"
public final class MaterialEncoder { public final class MaterialEncoder {
// The number of bits each property takes up // The number of bits each property takes up
private static final int BLUR_LENGTH = 1; private static final int BLUR_LENGTH = 1;
@ -65,7 +65,7 @@ public final class MaterialEncoder {
} }
// Packed format: // Packed format:
// diffuse[1] | useOverlay[1] | useLight[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1] // diffuse[1] | useLight[1] | useOverlay[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
public static int packProperties(Material material) { public static int packProperties(Material material) {
int bits = 0; int bits = 0;

View file

@ -36,34 +36,34 @@ public class IndirectCullingGroup<I extends Instance> {
private static final int DRAW_BARRIER_BITS = GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT; private static final int DRAW_BARRIER_BITS = GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT;
private final GlProgram cullProgram; private final InstanceType<I> instanceType;
private final GlProgram applyProgram;
private final GlProgram drawProgram;
private final long objectStride; private final long objectStride;
private final IndirectBuffers buffers; private final IndirectBuffers buffers;
private final IndirectMeshPool meshPool; private final IndirectMeshPool meshPool;
private final List<IndirectModel> indirectModels = new ArrayList<>(); private final List<IndirectModel> indirectModels = new ArrayList<>();
private final List<IndirectDraw> indirectDraws = new ArrayList<>(); private final List<IndirectDraw> indirectDraws = new ArrayList<>();
private final Map<RenderStage, List<MultiDraw>> multiDraws = new EnumMap<>(RenderStage.class); private final Map<RenderStage, List<MultiDraw>> multiDraws = new EnumMap<>(RenderStage.class);
private final InstanceType<I> instanceType;
private final IndirectPrograms programs;
private final GlProgram cullProgram;
private final GlProgram applyProgram;
private final GlProgram drawProgram;
private boolean needsDrawBarrier; private boolean needsDrawBarrier;
private boolean hasNewDraws; private boolean hasNewDraws;
private int instanceCountThisFrame; private int instanceCountThisFrame;
IndirectCullingGroup(InstanceType<I> instanceType) { IndirectCullingGroup(InstanceType<I> instanceType, IndirectPrograms programs) {
this.instanceType = instanceType; this.instanceType = instanceType;
var programs = IndirectPrograms.get(); objectStride = instanceType.layout()
.byteSize() + IndirectBuffers.INT_SIZE;
buffers = new IndirectBuffers(objectStride);
meshPool = new IndirectMeshPool();
this.programs = programs;
cullProgram = programs.getCullingProgram(instanceType); cullProgram = programs.getCullingProgram(instanceType);
applyProgram = programs.getApplyProgram(); applyProgram = programs.getApplyProgram();
drawProgram = programs.getIndirectProgram(instanceType, Contexts.DEFAULT); drawProgram = programs.getIndirectProgram(instanceType, Contexts.DEFAULT);
objectStride = instanceType.layout()
.byteSize() + IndirectBuffers.INT_SIZE;
buffers = new IndirectBuffers(objectStride);
meshPool = new IndirectMeshPool();
} }
public void flush(StagingBuffer stagingBuffer) { public void flush(StagingBuffer stagingBuffer) {
@ -200,8 +200,7 @@ public class IndirectCullingGroup<I extends Instance> {
} }
public void bindForCrumbling() { public void bindForCrumbling() {
var program = IndirectPrograms.get() var program = programs.getIndirectProgram(instanceType, Contexts.CRUMBLING);
.getIndirectProgram(instanceType, Contexts.CRUMBLING);
program.bind(); program.bind();

View file

@ -18,6 +18,7 @@ import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
import com.jozufozu.flywheel.backend.engine.CommonCrumbling; import com.jozufozu.flywheel.backend.engine.CommonCrumbling;
import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl; import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
import com.jozufozu.flywheel.backend.engine.InstancerKey; import com.jozufozu.flywheel.backend.engine.InstancerKey;
@ -34,10 +35,16 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.ModelBakery;
public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>> { public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>> {
private final StagingBuffer stagingBuffer = new StagingBuffer(); private final IndirectPrograms programs;
private final StagingBuffer stagingBuffer;
private final Map<InstanceType<?>, IndirectCullingGroup<?>> cullingGroups = new HashMap<>(); private final Map<InstanceType<?>, IndirectCullingGroup<?>> cullingGroups = new HashMap<>();
private final GlBuffer crumblingDrawBuffer = new GlBuffer(); private final GlBuffer crumblingDrawBuffer = new GlBuffer();
public IndirectDrawManager(IndirectPrograms programs) {
this.programs = programs;
stagingBuffer = new StagingBuffer(this.programs);
}
@Override @Override
protected <I extends Instance> IndirectInstancer<?> create(InstanceType<I> type) { protected <I extends Instance> IndirectInstancer<?> create(InstanceType<I> type) {
return new IndirectInstancer<>(type); return new IndirectInstancer<>(type);
@ -52,7 +59,7 @@ public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>>
return; return;
} }
var group = (IndirectCullingGroup<I>) cullingGroups.computeIfAbsent(key.type(), IndirectCullingGroup::new); var group = (IndirectCullingGroup<I>) cullingGroups.computeIfAbsent(key.type(), t -> new IndirectCullingGroup<>(t, programs));
group.add((IndirectInstancer<I>) instancer, model, stage); group.add((IndirectInstancer<I>) instancer, model, stage);
} }

View file

@ -6,6 +6,7 @@ import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.task.Plan; import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
import com.jozufozu.flywheel.backend.engine.AbstractEngine; import com.jozufozu.flywheel.backend.engine.AbstractEngine;
import com.jozufozu.flywheel.backend.engine.AbstractInstancer; import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
import com.jozufozu.flywheel.backend.engine.InstancerStorage; import com.jozufozu.flywheel.backend.engine.InstancerStorage;
@ -19,13 +20,18 @@ import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
public class IndirectEngine extends AbstractEngine { public class IndirectEngine extends AbstractEngine {
private final IndirectDrawManager drawManager = new IndirectDrawManager(); private final IndirectPrograms programs;
private final IndirectDrawManager drawManager;
private final Flag flushFlag = new NamedFlag("flushed"); private final Flag flushFlag = new NamedFlag("flushed");
public IndirectEngine(int maxOriginDistance) { public IndirectEngine(IndirectPrograms programs, int maxOriginDistance) {
super(maxOriginDistance); super(maxOriginDistance);
programs.acquire();
this.programs = programs;
drawManager = new IndirectDrawManager(this.programs);
} }
@Override @Override
@ -52,9 +58,10 @@ public class IndirectEngine extends AbstractEngine {
} }
try (var restoreState = GlStateTracker.getRestoreState()) { try (var restoreState = GlStateTracker.getRestoreState()) {
GameRenderer gameRenderer = Minecraft.getInstance().gameRenderer;
int prevActiveTexture = GlStateManager._getActiveTexture(); int prevActiveTexture = GlStateManager._getActiveTexture();
Minecraft.getInstance().gameRenderer.overlayTexture().setupOverlayColor(); gameRenderer.overlayTexture().setupOverlayColor();
Minecraft.getInstance().gameRenderer.lightTexture().turnOnLightLayer(); gameRenderer.lightTexture().turnOnLightLayer();
GlTextureUnit.T1.makeActive(); GlTextureUnit.T1.makeActive();
RenderSystem.bindTexture(RenderSystem.getShaderTexture(1)); RenderSystem.bindTexture(RenderSystem.getShaderTexture(1));
@ -65,8 +72,8 @@ public class IndirectEngine extends AbstractEngine {
MaterialRenderState.reset(); MaterialRenderState.reset();
Minecraft.getInstance().gameRenderer.overlayTexture().teardownOverlayColor(); gameRenderer.overlayTexture().teardownOverlayColor();
Minecraft.getInstance().gameRenderer.lightTexture().turnOffLightLayer(); gameRenderer.lightTexture().turnOffLightLayer();
GlStateManager._activeTexture(prevActiveTexture); GlStateManager._activeTexture(prevActiveTexture);
} }
} }
@ -90,5 +97,6 @@ public class IndirectEngine extends AbstractEngine {
@Override @Override
public void delete() { public void delete() {
drawManager.delete(); drawManager.delete();
programs.release();
} }
} }

View file

@ -12,6 +12,7 @@ import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
import com.jozufozu.flywheel.backend.gl.GlCompat; import com.jozufozu.flywheel.backend.gl.GlCompat;
import com.jozufozu.flywheel.backend.gl.GlFence; import com.jozufozu.flywheel.backend.gl.GlFence;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker; import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.memory.MemoryBlock;
@ -29,6 +30,14 @@ public class StagingBuffer {
private final long map; private final long map;
private final long capacity; private final long capacity;
private final OverflowStagingBuffer overflow = new OverflowStagingBuffer();
private final TransferList transfers = new TransferList();
private final PriorityQueue<FencedRegion> fencedRegions = new ObjectArrayFIFOQueue<>();
private final GlBuffer scatterBuffer = new GlBuffer();
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.
*/ */
@ -58,17 +67,14 @@ public class StagingBuffer {
@Nullable @Nullable
private MemoryBlock scratch; private MemoryBlock scratch;
private final OverflowStagingBuffer overflow = new OverflowStagingBuffer(); public StagingBuffer(IndirectPrograms programs) {
private final TransferList transfers = new TransferList(); this(DEFAULT_CAPACITY, programs);
private final PriorityQueue<FencedRegion> fencedRegions = new ObjectArrayFIFOQueue<>();
private final GlBuffer scatterBuffer = new GlBuffer();
private final ScatterList scatterList = new ScatterList();
public StagingBuffer() {
this(DEFAULT_CAPACITY);
} }
public StagingBuffer(long capacity) { public StagingBuffer(long capacity, IndirectPrograms programs) {
scatterProgram = IndirectPrograms.get()
.getScatterProgram();
this.capacity = capacity; this.capacity = capacity;
vbo = GL45C.glCreateBuffers(); vbo = GL45C.glCreateBuffers();
@ -247,9 +253,7 @@ 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() {
IndirectPrograms.get() scatterProgram.bind();
.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());

View file

@ -23,7 +23,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.ModelBakery;
public class InstancedCrumbling { public class InstancedCrumbling {
public static void render(List<Engine.CrumblingBlock> crumblingBlocks) { public static void render(List<Engine.CrumblingBlock> crumblingBlocks, InstancingPrograms programs) {
// Sort draw calls into buckets, so we don't have to do as many shader binds. // Sort draw calls into buckets, so we don't have to do as many shader binds.
var byShaderState = doCrumblingSort(crumblingBlocks); var byShaderState = doCrumblingSort(crumblingBlocks);
@ -48,8 +48,7 @@ public class InstancedCrumbling {
CommonCrumbling.applyCrumblingProperties(crumblingMaterial, baseMaterial); CommonCrumbling.applyCrumblingProperties(crumblingMaterial, baseMaterial);
var program = InstancingPrograms.get() var program = programs.get(shader.instanceType(), Contexts.CRUMBLING);
.get(shader.instanceType(), Contexts.CRUMBLING);
program.bind(); program.bind();
UniformBuffer.get().sync(); UniformBuffer.get().sync();
@ -108,7 +107,7 @@ public class InstancedCrumbling {
} }
} }
} }
return out; return out;
} }
} }

View file

@ -28,14 +28,17 @@ import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
public class InstancingEngine extends AbstractEngine { public class InstancingEngine extends AbstractEngine {
private final InstancingPrograms programs;
private final InstancedDrawManager drawManager = new InstancedDrawManager(); private final InstancedDrawManager drawManager = new InstancedDrawManager();
private final Flag flushFlag = new NamedFlag("flushed"); private final Flag flushFlag = new NamedFlag("flushed");
public InstancingEngine(int maxOriginDistance) { public InstancingEngine(InstancingPrograms programs, int maxOriginDistance) {
super(maxOriginDistance); super(maxOriginDistance);
programs.acquire();
this.programs = programs;
} }
@Override @Override
@ -64,9 +67,10 @@ public class InstancingEngine extends AbstractEngine {
} }
try (var state = GlStateTracker.getRestoreState()) { try (var state = GlStateTracker.getRestoreState()) {
GameRenderer gameRenderer = Minecraft.getInstance().gameRenderer;
int prevActiveTexture = GlStateManager._getActiveTexture(); int prevActiveTexture = GlStateManager._getActiveTexture();
Minecraft.getInstance().gameRenderer.overlayTexture().setupOverlayColor(); gameRenderer.overlayTexture().setupOverlayColor();
Minecraft.getInstance().gameRenderer.lightTexture().turnOnLightLayer(); gameRenderer.lightTexture().turnOnLightLayer();
GlTextureUnit.T1.makeActive(); GlTextureUnit.T1.makeActive();
RenderSystem.bindTexture(RenderSystem.getShaderTexture(1)); RenderSystem.bindTexture(RenderSystem.getShaderTexture(1));
@ -75,8 +79,8 @@ public class InstancingEngine extends AbstractEngine {
render(drawSet); render(drawSet);
Minecraft.getInstance().gameRenderer.overlayTexture().teardownOverlayColor(); gameRenderer.overlayTexture().teardownOverlayColor();
Minecraft.getInstance().gameRenderer.lightTexture().turnOffLightLayer(); gameRenderer.lightTexture().turnOffLightLayer();
GlStateManager._activeTexture(prevActiveTexture); GlStateManager._activeTexture(prevActiveTexture);
} }
} }
@ -86,7 +90,7 @@ public class InstancingEngine extends AbstractEngine {
// Need to wait for flush before we can inspect instancer state. // Need to wait for flush before we can inspect instancer state.
executor.syncUntil(flushFlag::isRaised); executor.syncUntil(flushFlag::isRaised);
InstancedCrumbling.render(crumblingBlocks); InstancedCrumbling.render(crumblingBlocks, programs);
} }
@Override @Override
@ -97,6 +101,7 @@ public class InstancingEngine extends AbstractEngine {
@Override @Override
public void delete() { public void delete() {
drawManager.delete(); drawManager.delete();
programs.release();
} }
private void render(InstancedDrawManager.DrawSet drawSet) { private void render(InstancedDrawManager.DrawSet drawSet) {
@ -110,8 +115,7 @@ public class InstancingEngine extends AbstractEngine {
continue; continue;
} }
var program = InstancingPrograms.get() var program = programs.get(shader.instanceType(), Contexts.DEFAULT);
.get(shader.instanceType(), Contexts.DEFAULT);
program.bind(); program.bind();
UniformBuffer.get().sync(); UniformBuffer.get().sync();

View file

@ -31,9 +31,9 @@ side = "CLIENT"
[[dependencies.flywheel]] [[dependencies.flywheel]]
modId = "rubidium" modId = "rubidium"
# This replicates a "breaks" dependency.
# There's a mixin crash with Rubidium <0.7.0.
mandatory = false mandatory = false
# This should be a "breaks" dependency.
# There's a mixin crash with Rubidum < 0.7.0
versionRange = "[0.7.0,)" versionRange = "[0.7.0,)"
ordering = "NONE" ordering = "NONE"
side = "CLIENT" side = "CLIENT"

View file

@ -35,7 +35,7 @@ const uint _FLW_USE_LIGHT_MASK = ((1u << _FLW_USE_LIGHT_LENGTH) - 1u) << _FLW_US
const uint _FLW_DIFFUSE_MASK = ((1u << _FLW_DIFFUSE_LENGTH) - 1u) << _FLW_DIFFUSE_OFFSET; const uint _FLW_DIFFUSE_MASK = ((1u << _FLW_DIFFUSE_LENGTH) - 1u) << _FLW_DIFFUSE_OFFSET;
// Packed format: // Packed format:
// diffuse[1] | useOverlay[1] | useLight[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1] // diffuse[1] | useLight[1] | useOverlay[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
void _flw_unpackMaterialProperties(uint p, out FlwMaterial m) { void _flw_unpackMaterialProperties(uint p, out FlwMaterial m) {
m.blur = (p & _FLW_BLUR_MASK) != 0u; m.blur = (p & _FLW_BLUR_MASK) != 0u;
m.mipmap = (p & _FLW_MIPMAP_MASK) != 0u; m.mipmap = (p & _FLW_MIPMAP_MASK) != 0u;

View file

@ -1,6 +1,6 @@
{ {
"pack": { "pack": {
"description": "Flywheel resources", "description": "Flywheel resources",
"pack_format": 18 "pack_format": 15
} }
} }