diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java b/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java index 1956bd86c..f53557db2 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java @@ -18,6 +18,7 @@ import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.backend.glsl.GlslVersion; import com.jozufozu.flywheel.backend.glsl.ShaderSources; import com.jozufozu.flywheel.backend.glsl.SourceComponent; +import com.jozufozu.flywheel.lib.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; @@ -74,6 +75,7 @@ public class IndirectPrograms extends AbstractPrograms { private static CompilationHarness> createCullingCompiler(ShaderSources sources) { return CULL.program() .link(CULL.shader(GlslVersion.V460, ShaderType.COMPUTE) + .nameMapper(instanceType -> "culling/" + ResourceUtil.toDebugFileNameNoExtension(instanceType.cullShader())) .define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE) .withResource(CULL_SHADER_HEADER) .withComponent(IndirectComponent::create) @@ -86,6 +88,7 @@ public class IndirectPrograms extends AbstractPrograms { private static CompilationHarness createUtilCompiler(ShaderSources sources) { return UTIL.program() .link(UTIL.shader(GlslVersion.V460, ShaderType.COMPUTE) + .nameMapper(resourceLocation -> "utilities/" + ResourceUtil.toDebugFileNameNoExtension(resourceLocation)) .define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE) .withResource(s -> s)) .harness("utilities", sources); diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineCompiler.java index 1e7f15fc0..2d3a7f71f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineCompiler.java @@ -8,6 +8,7 @@ import com.jozufozu.flywheel.backend.compile.core.Compile; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.backend.glsl.ShaderSources; import com.jozufozu.flywheel.backend.glsl.SourceComponent; +import com.jozufozu.flywheel.lib.util.ResourceUtil; public class PipelineCompiler { private static final Compile PIPELINE = new Compile<>(); @@ -15,6 +16,14 @@ public class PipelineCompiler { static CompilationHarness create(ShaderSources sources, Pipeline pipeline, List vertexComponents, List fragmentComponents) { return PIPELINE.program() .link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.VERTEX) + .nameMapper(key -> { + var instance = ResourceUtil.toDebugFileNameNoExtension(key.instanceType() + .vertexShader()); + + var context = ResourceUtil.toDebugFileNameNoExtension(key.contextShader() + .vertexShader()); + return "pipeline/" + pipeline.compilerMarker() + "/" + instance + "_" + context; + }) .withResource(pipeline.vertexApiImpl()) .withResource(InternalVertex.LAYOUT_SHADER) .withComponent(key -> pipeline.assembler() @@ -26,6 +35,14 @@ public class PipelineCompiler { .vertexShader()) .withResource(pipeline.vertexMain())) .link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.FRAGMENT) + .nameMapper(key -> { + var instance = ResourceUtil.toDebugFileNameNoExtension(key.instanceType() + .vertexShader()); + + var context = ResourceUtil.toDebugFileNameNoExtension(key.contextShader() + .fragmentShader()); + return "pipeline/" + pipeline.compilerMarker() + "/" + instance + "_" + context; + }) .enableExtension("GL_ARB_conservative_depth") .withResource(pipeline.fragmentApiImpl()) .withComponents(fragmentComponents) diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compilation.java b/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compilation.java index 6c490d1a9..756396e60 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compilation.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compilation.java @@ -29,30 +29,20 @@ public class Compilation { public static final boolean DUMP_SHADER_SOURCE = System.getProperty("flw.dumpShaderSource") != null; private final List files = new ArrayList<>(); - private final StringBuilder generatedSource; - private final StringBuilder fullSource; - private final GlslVersion glslVersion; - private final ShaderType shaderType; + private final StringBuilder generatedSource = new StringBuilder(); + private final StringBuilder fullSource = new StringBuilder(); private int generatedLines = 0; - public Compilation(GlslVersion glslVersion, ShaderType shaderType) { - this.glslVersion = glslVersion; - this.shaderType = shaderType; - - generatedSource = new StringBuilder(); - fullSource = new StringBuilder(glslVersion.getVersionLine()).append(shaderType.getDefineStatement()).append('\n'); - } - @NotNull - public ShaderResult compile() { + public ShaderResult compile(ShaderType shaderType, String name) { int handle = GL20.glCreateShader(shaderType.glEnum); var source = fullSource.toString(); GlCompat.safeShaderSource(handle, source); GL20.glCompileShader(handle); - var shaderName = shaderType.name + glslVersion + '_' + Integer.toUnsignedString(source.hashCode()); - dumpSource(source, shaderType.getFileName(shaderName)); + var shaderName = name + "." + shaderType.extension; + dumpSource(source, shaderName); var infoLog = GL20.glGetShaderInfoLog(handle); @@ -64,6 +54,12 @@ public class Compilation { return ShaderResult.failure(new FailedCompilation(shaderName, files, generatedSource.toString(), source, infoLog)); } + public void version(GlslVersion version) { + fullSource.append("#version ") + .append(version.version) + .append('\n'); + } + public void enableExtension(String ext) { fullSource.append("#extension ") .append(ext) @@ -78,6 +74,12 @@ public class Compilation { .append('\n'); } + public void define(String key) { + fullSource.append("#define ") + .append(key) + .append('\n'); + } + public void appendComponent(SourceComponent component) { var source = component.source(); @@ -117,9 +119,10 @@ public class Compilation { return; } - File dir = new File(Minecraft.getInstance().gameDirectory, "flywheel_sources"); - dir.mkdirs(); - File file = new File(dir, fileName); + File file = new File(new File(Minecraft.getInstance().gameDirectory, "flywheel_sources"), fileName); + // mkdirs of the parent so we don't create a directory named by the leaf file we want to write + file.getParentFile() + .mkdirs(); try (FileWriter writer = new FileWriter(file)) { writer.write(source); } catch (Exception e) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/core/CompilationHarness.java b/src/main/java/com/jozufozu/flywheel/backend/compile/core/CompilationHarness.java index 611ba08ee..af52e3678 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/core/CompilationHarness.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/core/CompilationHarness.java @@ -12,7 +12,7 @@ import com.jozufozu.flywheel.backend.glsl.ShaderSources; public class CompilationHarness { private final KeyCompiler compiler; private final SourceLoader sourceLoader; - private final ShaderCompiler shaderCompiler; + private final ShaderCache shaderCache; private final ProgramLinker programLinker; private final CompilerStats stats; @@ -20,7 +20,7 @@ public class CompilationHarness { this.compiler = compiler; stats = new CompilerStats(marker); sourceLoader = new SourceLoader(sources, stats); - shaderCompiler = new ShaderCompiler(stats); + shaderCache = new ShaderCache(stats); programLinker = new ProgramLinker(stats); } @@ -29,7 +29,7 @@ public class CompilationHarness { stats.start(); Map out = new HashMap<>(); for (var key : keys) { - GlProgram glProgram = compiler.compile(key, sourceLoader, shaderCompiler, programLinker); + GlProgram glProgram = compiler.compile(key, sourceLoader, shaderCache, programLinker); if (out != null && glProgram != null) { out.put(key, glProgram); } else { @@ -47,10 +47,10 @@ public class CompilationHarness { } public void delete() { - shaderCompiler.delete(); + shaderCache.delete(); } public interface KeyCompiler { - @Nullable GlProgram compile(K key, SourceLoader loader, ShaderCompiler shaderCompiler, ProgramLinker programLinker); + @Nullable GlProgram compile(K key, SourceLoader loader, ShaderCache shaderCache, ProgramLinker programLinker); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compile.java b/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compile.java index 02286ceb1..6c68e5031 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compile.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compile.java @@ -33,16 +33,16 @@ import net.minecraft.resources.ResourceLocation; * @param The type of the key used to compile shaders. */ public class Compile { - public ShaderCompilerBuilder shader(GlslVersion glslVersion, ShaderType shaderType) { - return new ShaderCompilerBuilder<>(glslVersion, shaderType); + public ShaderCompiler shader(GlslVersion glslVersion, ShaderType shaderType) { + return new ShaderCompiler<>(glslVersion, shaderType); } - public ProgramLinkBuilder program() { - return new ProgramLinkBuilder<>(); + public ProgramStitcher program() { + return new ProgramStitcher<>(); } - public static class ProgramLinkBuilder implements CompilationHarness.KeyCompiler { - private final Map> compilers = new EnumMap<>(ShaderType.class); + public static class ProgramStitcher implements CompilationHarness.KeyCompiler { + private final Map> compilers = new EnumMap<>(ShaderType.class); private BiConsumer onLink = (k, p) -> { }; @@ -50,7 +50,7 @@ public class Compile { return new CompilationHarness<>(marker, sources, this); } - public ProgramLinkBuilder link(ShaderCompilerBuilder compilerBuilder) { + public ProgramStitcher link(ShaderCompiler compilerBuilder) { if (compilers.containsKey(compilerBuilder.shaderType)) { throw new IllegalArgumentException("Duplicate shader type: " + compilerBuilder.shaderType); } @@ -58,14 +58,14 @@ public class Compile { return this; } - public ProgramLinkBuilder then(BiConsumer onLink) { + public ProgramStitcher then(BiConsumer onLink) { this.onLink = onLink; return this; } @Override @Nullable - public GlProgram compile(K key, SourceLoader loader, ShaderCompiler shaderCompiler, ProgramLinker programLinker) { + public GlProgram compile(K key, SourceLoader loader, ShaderCache shaderCache, ProgramLinker programLinker) { if (compilers.isEmpty()) { throw new IllegalStateException("No shader compilers were added!"); } @@ -73,8 +73,8 @@ public class Compile { List shaders = new ArrayList<>(); boolean ok = true; - for (ShaderCompilerBuilder compiler : compilers.values()) { - var shader = compiler.compile(key, shaderCompiler, loader); + for (ShaderCompiler compiler : compilers.values()) { + var shader = compiler.compile(key, shaderCache, loader); if (shader == null) { ok = false; } @@ -95,59 +95,65 @@ public class Compile { } } - public static class ShaderCompilerBuilder { + public static class ShaderCompiler { private final GlslVersion glslVersion; private final ShaderType shaderType; + private final List> fetchers = new ArrayList<>(); private Consumer compilationCallbacks = $ -> { }; - private final List> fetchers = new ArrayList<>(); + private Function nameMapper = Object::toString; - public ShaderCompilerBuilder(GlslVersion glslVersion, ShaderType shaderType) { + public ShaderCompiler(GlslVersion glslVersion, ShaderType shaderType) { this.glslVersion = glslVersion; this.shaderType = shaderType; } - public ShaderCompilerBuilder with(BiFunction fetch) { + public ShaderCompiler nameMapper(Function nameMapper) { + this.nameMapper = nameMapper; + return this; + } + + public ShaderCompiler with(BiFunction fetch) { fetchers.add(fetch); return this; } - public ShaderCompilerBuilder withComponents(Collection components) { + public ShaderCompiler withComponents(Collection components) { components.forEach(this::withComponent); return this; } - public ShaderCompilerBuilder withComponent(SourceComponent component) { + public ShaderCompiler withComponent(SourceComponent component) { return withComponent($ -> component); } - public ShaderCompilerBuilder withComponent(Function sourceFetcher) { + public ShaderCompiler withComponent(Function sourceFetcher) { return with((key, $) -> sourceFetcher.apply(key)); } - public ShaderCompilerBuilder withResource(Function sourceFetcher) { + public ShaderCompiler withResource(Function sourceFetcher) { return with((key, loader) -> loader.find(sourceFetcher.apply(key))); } - public ShaderCompilerBuilder withResource(ResourceLocation resourceLocation) { + public ShaderCompiler withResource(ResourceLocation resourceLocation) { return withResource($ -> resourceLocation); } - public ShaderCompilerBuilder onCompile(Consumer cb) { + public ShaderCompiler onCompile(Consumer cb) { compilationCallbacks = compilationCallbacks.andThen(cb); return this; } - public ShaderCompilerBuilder define(String def, int value) { + public ShaderCompiler define(String def, int value) { return onCompile(ctx -> ctx.define(def, String.valueOf(value))); } - public ShaderCompilerBuilder enableExtension(String extension) { + public ShaderCompiler enableExtension(String extension) { return onCompile(ctx -> ctx.enableExtension(extension)); } @Nullable - private GlShader compile(K key, ShaderCompiler compiler, SourceLoader loader) { + private GlShader compile(K key, ShaderCache compiler, SourceLoader loader) { var components = new ArrayList(); boolean ok = true; for (var fetcher : fetchers) { @@ -162,7 +168,7 @@ public class Compile { return null; } - return compiler.compile(glslVersion, shaderType, compilationCallbacks, components); + return compiler.compile(glslVersion, shaderType, nameMapper.apply(key), compilationCallbacks, components); } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/core/ShaderCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/compile/core/ShaderCache.java similarity index 79% rename from src/main/java/com/jozufozu/flywheel/backend/compile/core/ShaderCompiler.java rename to src/main/java/com/jozufozu/flywheel/backend/compile/core/ShaderCache.java index d476afc9f..3611efe00 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/core/ShaderCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/core/ShaderCache.java @@ -15,36 +15,38 @@ import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.backend.glsl.GlslVersion; import com.jozufozu.flywheel.backend.glsl.SourceComponent; -public class ShaderCompiler { - private final Map shaderCache = new HashMap<>(); +public class ShaderCache { + private final Map inner = new HashMap<>(); private final CompilerStats stats; - public ShaderCompiler(CompilerStats stats) { + public ShaderCache(CompilerStats stats) { this.stats = stats; } @Nullable - public GlShader compile(GlslVersion glslVersion, ShaderType shaderType, Consumer callback, List sourceComponents) { + public GlShader compile(GlslVersion glslVersion, ShaderType shaderType, String name, Consumer callback, List sourceComponents) { var key = new ShaderKey(glslVersion, shaderType, sourceComponents); - var cached = shaderCache.get(key); + var cached = inner.get(key); if (cached != null) { return cached.unwrap(); } - Compilation ctx = new Compilation(glslVersion, shaderType); + Compilation ctx = new Compilation(); + ctx.version(glslVersion); + ctx.define(shaderType.define); callback.accept(ctx); expand(sourceComponents, ctx::appendComponent); - ShaderResult out = ctx.compile(); - shaderCache.put(key, out); + ShaderResult out = ctx.compile(shaderType, name); + inner.put(key, out); stats.shaderResult(out); return out.unwrap(); } public void delete() { - shaderCache.values() + inner.values() .stream() .map(ShaderResult::unwrap) .filter(Objects::nonNull) diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/ShaderType.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/ShaderType.java index f5b106232..85c410b1d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/ShaderType.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/ShaderType.java @@ -20,12 +20,4 @@ public enum ShaderType { this.extension = extension; this.glEnum = glEnum; } - - public String getDefineStatement() { - return "#define " + define + "\n"; - } - - public String getFileName(String baseName) { - return baseName + "." + extension; - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/glsl/GlslVersion.java b/src/main/java/com/jozufozu/flywheel/backend/glsl/GlslVersion.java index 28022f76f..aae047dcb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/glsl/GlslVersion.java +++ b/src/main/java/com/jozufozu/flywheel/backend/glsl/GlslVersion.java @@ -27,7 +27,4 @@ public enum GlslVersion { return Integer.toString(version); } - public String getVersionLine() { - return "#version " + version + '\n'; - } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/util/ResourceUtil.java b/src/main/java/com/jozufozu/flywheel/lib/util/ResourceUtil.java index 7712b19f6..265587e4c 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/util/ResourceUtil.java +++ b/src/main/java/com/jozufozu/flywheel/lib/util/ResourceUtil.java @@ -1,5 +1,7 @@ package com.jozufozu.flywheel.lib.util; +import org.jetbrains.annotations.NotNull; + import com.jozufozu.flywheel.Flywheel; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -52,4 +54,12 @@ public final class ResourceUtil { throw ERROR_INVALID.createWithContext(reader); } } + + @NotNull + public static String toDebugFileNameNoExtension(ResourceLocation resourceLocation) { + var stringLoc = resourceLocation.toString(); + return stringLoc.substring(0, stringLoc.lastIndexOf('.')) + .replace('/', '_') + .replace(':', '_'); + } }