From 9d657aed4057ac927f84f53df2165a97b1295f4e Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Fri, 5 Aug 2022 10:51:07 -0700 Subject: [PATCH] Things on the screen - Specialize MeshPool for the indirect engine - Temporarily force the engine to be indirect - Fix compilation issues with test shaders - VertexAttribute supports DSA - Fix Miniball issues in dev-env - VertexList implements PointSet for use with Miniball - Meshes store their bounding spheres - Add hook/system property to load renderdoc on client launch - StructTypes provide separate StorageBufferWriter for indirect --- build.gradle | 32 ++- .../api/struct/StorageBufferWriter.java | 10 + .../flywheel/api/struct/StructType.java | 2 + .../flywheel/api/vertex/VertexList.java | 24 +- .../jozufozu/flywheel/backend/Backend.java | 3 +- .../flywheel/backend/gl/GLSLVersion.java | 4 + .../backend/gl/array/VertexAttribute.java | 13 + .../backend/gl/array/VertexAttributeF.java | 6 + .../backend/gl/array/VertexAttributeI.java | 6 + .../backend/instancing/AbstractInstancer.java | 9 + .../instancing/batching/CPUInstancer.java | 8 - ...mpiler.java => ComputeCullerCompiler.java} | 26 +- .../instancing/indirect/DSABuffer.java | 10 - .../indirect/IndirectDrawCompiler.java | 65 +++++ .../instancing/indirect/IndirectEngine.java | 3 - .../indirect/IndirectInstancer.java | 6 +- .../instancing/indirect/IndirectList.java | 235 +++++++++++++----- .../instancing/indirect/IndirectMeshPool.java | 118 +++++++++ .../instancing/indirect/InstancedModel.java | 8 +- .../instancing/instancing/MeshPool.java | 4 +- .../jozufozu/flywheel/core/Components.java | 3 + .../flywheel/core/hardcoded/ModelPart.java | 12 + .../flywheel/core/layout/BufferLayout.java | 2 +- .../jozufozu/flywheel/core/model/Mesh.java | 3 + .../flywheel/core/model/ModelUtil.java | 10 + .../flywheel/core/model/SimpleMesh.java | 10 + .../flywheel/core/source/SourceFile.java | 12 +- .../core/structs/model/TransformedType.java | 6 + .../oriented/OrientedStorageWriter.java | 45 ++++ .../core/structs/oriented/OrientedType.java | 6 + .../flywheel/mixin/ClientMainMixin.java | 27 ++ .../flywheel/compute/cull_instances.glsl | 18 +- .../flywheel/compute/draw_instances.frag | 9 + .../flywheel/compute/draw_instances.vert | 11 +- .../flywheel/flywheel/compute/objects.glsl | 8 +- src/main/resources/flywheel.mixins.json | 1 + 36 files changed, 644 insertions(+), 131 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/api/struct/StorageBufferWriter.java rename src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/{ComputeCompiler.java => ComputeCullerCompiler.java} (52%) delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/DSABuffer.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawCompiler.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedStorageWriter.java create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/ClientMainMixin.java create mode 100644 src/main/resources/assets/flywheel/flywheel/compute/draw_instances.frag diff --git a/build.gradle b/build.gradle index 5f87840a4..11b24de04 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,8 @@ apply plugin: 'eclipse' apply plugin: 'maven-publish' apply plugin: 'org.spongepowered.mixin' +jarJar.enable() + boolean dev = System.getenv('RELEASE') == null || System.getenv('RELEASE').equalsIgnoreCase('false'); ext.buildNumber = System.getenv('BUILD_NUMBER') @@ -31,8 +33,6 @@ version = mod_version + (dev && buildNumber != null ? "-${buildNumber}" : '') java.toolchain.languageVersion = JavaLanguageVersion.of(17) -jarJar.enable() - println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) minecraft { mappings channel: 'parchment', version: "${parchment_version}-${minecraft_version}" @@ -47,6 +47,7 @@ minecraft { property 'mixin.env.remapRefMap', 'true' property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" property 'flw.dumpShaderSource', 'true' + property 'flw.loadRenderDoc', 'true' arg '-mixin.config=flywheel.mixins.json' @@ -108,15 +109,31 @@ repositories { includeGroup "maven.modrinth" } } + mavenCentral() } +// Fix for loading non-mod libraries in dev-env, used for miniball. +// https://gist.github.com/SizableShrimp/66b22f1b24c255e1491c8d98d3f11f83 +// v--------------------------------------------------------------------v +configurations { + library + implementation.extendsFrom library +} + +minecraft.runs.all { + lazyToken('minecraft_classpath') { + configurations.library.copyRecursive().resolve().collect { it.absolutePath }.join(File.pathSeparator) + } +} +// ^--------------------------------------------------------------------^ + dependencies { minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" - implementation "com.dreizak:miniball:1.0.3" - jarJar(group: 'com.dreizak', name: 'miniball', version: '[1.0,2.0)') { - jarJar.pin(it, "[1.0,2.0)") + jarJar(group: 'com.dreizak', name: 'miniball', version: "1.0.3") { + jarJar.ranged(it, "[1.0,2.0)") } + library "com.dreizak:miniball:1.0.3" // switch to implementation for debugging compileOnly fg.deobf("maven.modrinth:starlight-forge:1.0.2+1.18.2") @@ -139,6 +156,7 @@ mixin { // Workaround for SpongePowered/MixinGradle#38 afterEvaluate { tasks.configureReobfTaskForReobfJar.mustRunAfter(tasks.compileJava) + tasks.configureReobfTaskForReobfJarJar.mustRunAfter(tasks.compileJava) } tasks.withType(JavaCompile).configureEach { @@ -151,6 +169,10 @@ javadoc { options.addStringOption('Xdoclint:none', '-quiet') } +compileJava { + options.compilerArgs = ['-Xdiags:verbose'] +} + jar { manifest { attributes([ diff --git a/src/main/java/com/jozufozu/flywheel/api/struct/StorageBufferWriter.java b/src/main/java/com/jozufozu/flywheel/api/struct/StorageBufferWriter.java new file mode 100644 index 000000000..de7c9dfc1 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/struct/StorageBufferWriter.java @@ -0,0 +1,10 @@ +package com.jozufozu.flywheel.api.struct; + +import com.jozufozu.flywheel.api.instancer.InstancedPart; + +public interface StorageBufferWriter { + + void write(final long ptr, final T instance, final int batchID); + + int getAlignment(); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java index 7841f92de..3463c7cc5 100644 --- a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java +++ b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java @@ -36,6 +36,8 @@ public interface StructType { VertexTransformer getVertexTransformer(); + StorageBufferWriter getStorageBufferWriter(); + public interface VertexTransformer { void transform(MutableVertexList vertexList, S struct, ClientLevel level); } diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java index 519ef671f..cf9d84789 100644 --- a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java @@ -1,5 +1,7 @@ package com.jozufozu.flywheel.api.vertex; +import com.dreizak.miniball.model.PointSet; + /** * A read only view of a vertex buffer. * @@ -9,7 +11,7 @@ package com.jozufozu.flywheel.api.vertex; *

* TODO: more flexible elements? */ -public interface VertexList { +public interface VertexList extends PointSet { float x(int index); float y(int index); @@ -47,4 +49,24 @@ public interface VertexList { default boolean isEmpty() { return getVertexCount() == 0; } + + @Override + default int size() { + return getVertexCount(); + } + + @Override + default int dimension() { + return 3; + } + + @Override + default double coord(int i, int j) { + return switch (j) { + case 0 -> x(i); + case 1 -> y(i); + case 2 -> z(i); + default -> throw new IllegalArgumentException("Invalid dimension: " + j); + }; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index b48077615..20c6f1b62 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -54,7 +54,8 @@ public class Backend { } public static void refresh() { - TYPE = chooseEngine(); + // TODO: Revert when done testing + TYPE = BackendType.INDIRECT; // chooseEngine(); } public static boolean isOn() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GLSLVersion.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GLSLVersion.java index eb128ad69..52ac01c2a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/GLSLVersion.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GLSLVersion.java @@ -26,4 +26,8 @@ public enum GLSLVersion { public String toString() { return Integer.toString(version); } + + public String getVersionLine() { + return "#version " + version + '\n'; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttribute.java b/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttribute.java index 18c458643..d18a568d6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttribute.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttribute.java @@ -3,5 +3,18 @@ package com.jozufozu.flywheel.backend.gl.array; public interface VertexAttribute { int getByteWidth(); + /** + * Apply this vertex attribute to the bound vertex array. + * @param offset The byte offset to the first element of the attribute. + * @param i The attribute index. + * @param stride The byte stride between consecutive elements of the attribute. + */ void pointer(long offset, int i, int stride); + + /** + * Use DSA to apply this vertex attribute to the given vertex array. + * @param vaobj The vertex array object to modify. + * @param i The attribute index. + */ + void format(int vaobj, int i); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttributeF.java b/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttributeF.java index 001e73d06..65cb51b7c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttributeF.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttributeF.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.backend.gl.array; import org.lwjgl.opengl.GL32; +import org.lwjgl.opengl.GL45; import com.jozufozu.flywheel.backend.gl.GlNumericType; @@ -22,4 +23,9 @@ public record VertexAttributeF(GlNumericType type, int size, boolean normalized) public void pointer(long offset, int i, int stride) { GL32.glVertexAttribPointer(i, size(), type().getGlEnum(), normalized(), stride, offset); } + + @Override + public void format(int vaobj, int i) { + GL45.glVertexArrayAttribFormat(vaobj, i, size(), type().getGlEnum(), normalized(), 0); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttributeI.java b/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttributeI.java index d0f0bc903..64934cd3a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttributeI.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/array/VertexAttributeI.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.backend.gl.array; import org.lwjgl.opengl.GL32; +import org.lwjgl.opengl.GL45; import com.jozufozu.flywheel.backend.gl.GlNumericType; @@ -21,4 +22,9 @@ public record VertexAttributeI(GlNumericType type, int size) implements VertexAt public void pointer(long offset, int i, int stride) { GL32.glVertexAttribIPointer(i, size(), type().getGlEnum(), stride, offset); } + + @Override + public void format(int vaobj, int i) { + GL45.glVertexArrayAttribIFormat(vaobj, i, size(), type().getGlEnum(), 0); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java index 77cad5920..4b5d4c0a0 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing; import java.util.ArrayList; import java.util.BitSet; +import java.util.List; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.Instancer; @@ -60,6 +61,14 @@ public abstract class AbstractInstancer implements Inst return data.size(); } + public List getRange(int start, int end) { + return data.subList(start, end); + } + + public List getAll() { + return data; + } + protected void removeDeletedInstances() { // Figure out which elements are to be removed. final int oldSize = this.data.size(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java index 97fc5737f..61cc12016 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java @@ -19,14 +19,6 @@ public class CPUInstancer extends AbstractInstancer } } - public List getRange(int start, int end) { - return data.subList(start, end); - } - - public List getAll() { - return data; - } - @Override public void notifyDirty() { // noop diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java similarity index 52% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCompiler.java rename to src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java index 00f02c6d3..a104faf26 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java @@ -1,34 +1,42 @@ package com.jozufozu.flywheel.backend.instancing.indirect; import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlShader; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.core.compile.Memoizer; import com.jozufozu.flywheel.core.compile.ProgramAssembler; +import com.jozufozu.flywheel.core.compile.ShaderCompilationException; import com.jozufozu.flywheel.core.source.CompilationContext; import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.event.ReloadRenderersEvent; -public class ComputeCompiler extends Memoizer { +public class ComputeCullerCompiler extends Memoizer { - public static final ComputeCompiler INSTANCE = new ComputeCompiler(); + public static final ComputeCullerCompiler INSTANCE = new ComputeCullerCompiler(); - private ComputeCompiler() { + private ComputeCullerCompiler() { } @Override protected GlProgram _create(FileResolution file) { + CompilationContext context = new CompilationContext(); + + var header = GLSLVersion.V460.getVersionLine(); String source = file.getFile() - .generateFinalSource(new CompilationContext()); + .generateFinalSource(context); - var shader = new GlShader(source, ShaderType.COMPUTE, ImmutableList.of(file.getFileLoc())); + try { + var shader = new GlShader(header + source, ShaderType.COMPUTE, ImmutableList.of(file.getFileLoc())); - return new ProgramAssembler(file.getFileLoc()) - .attachShader(shader) - .link() - .build(GlProgram::new); + return new ProgramAssembler(file.getFileLoc()).attachShader(shader) + .link() + .build(GlProgram::new); + } catch (ShaderCompilationException e) { + throw e.withErrorLog(context); + } } @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/DSABuffer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/DSABuffer.java deleted file mode 100644 index 43b1710e3..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/DSABuffer.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.indirect; - -public class DSABuffer { - int id; - int byteSize; - - public DSABuffer(int id) { - this.id = id; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawCompiler.java new file mode 100644 index 000000000..80fc7bbc5 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectDrawCompiler.java @@ -0,0 +1,65 @@ +package com.jozufozu.flywheel.backend.instancing.indirect; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.backend.gl.GLSLVersion; +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; +import com.jozufozu.flywheel.backend.gl.shader.GlShader; +import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.core.WorldProgram; +import com.jozufozu.flywheel.core.compile.CompileUtil; +import com.jozufozu.flywheel.core.compile.Memoizer; +import com.jozufozu.flywheel.core.compile.ProgramAssembler; +import com.jozufozu.flywheel.core.compile.ShaderCompilationException; +import com.jozufozu.flywheel.core.source.CompilationContext; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.ShaderLoadingException; +import com.jozufozu.flywheel.core.source.SourceFile; +import com.jozufozu.flywheel.event.ReloadRenderersEvent; + +public class IndirectDrawCompiler extends Memoizer { + public static final IndirectDrawCompiler INSTANCE = new IndirectDrawCompiler(); + + private IndirectDrawCompiler() { + } + + @Override + protected GlProgram _create(IndirectDrawCompiler.Program program) { + + GlShader vertexShader = compile(program.vertex.getFile(), ShaderType.VERTEX); + GlShader fragmentShader = compile(program.fragment.getFile(), ShaderType.FRAGMENT); + + return new ProgramAssembler(program.vertex.getFileLoc()) + .attachShader(vertexShader) + .attachShader(fragmentShader) + .link() + .build(WorldProgram::new); + } + + @NotNull + private static GlShader compile(SourceFile file, ShaderType type) { + var context = new CompilationContext(); + try { + var header = CompileUtil.generateHeader(GLSLVersion.V460, type); + var source = file.generateFinalSource(context); + + return new GlShader(header + source, type, ImmutableList.of(file.name)); + } catch (ShaderCompilationException e) { + throw e.withErrorLog(context); + } + } + + @Override + protected void _destroy(GlProgram value) { + value.delete(); + } + + public static void invalidateAll(ReloadRenderersEvent ignored) { + INSTANCE.invalidate(); + } + + public record Program(FileResolution vertex, FileResolution fragment) { + + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java index 3294ff928..c60324ef6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java @@ -149,9 +149,6 @@ public class IndirectEngine implements Engine { model.init(renderLists); } uninitializedModels.clear(); - - MeshPool.getInstance() - .flush(); } private void shiftListeners(int cX, int cY, int cZ) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectInstancer.java index ff6ee8e51..bcc09acf2 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectInstancer.java @@ -11,7 +11,7 @@ public class IndirectInstancer extends AbstractInstance public final BufferLayout instanceFormat; public final StructType structType; public final InstancedModel parent; - int maxInstanceCount = 0; + int instanceCount = 0; boolean anyToUpdate; @@ -28,7 +28,7 @@ public class IndirectInstancer extends AbstractInstance } public boolean isEmpty() { - return !anyToUpdate && !anyToRemove && maxInstanceCount == 0; + return !anyToUpdate && !anyToRemove && instanceCount == 0; } void update() { @@ -36,7 +36,7 @@ public class IndirectInstancer extends AbstractInstance removeDeletedInstances(); } - maxInstanceCount = data.size(); + instanceCount = data.size(); anyToRemove = false; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectList.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectList.java index b68aec224..cff54901c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectList.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectList.java @@ -1,121 +1,244 @@ package com.jozufozu.flywheel.backend.instancing.indirect; -import java.nio.ByteBuffer; +import static org.lwjgl.opengl.GL46.*; + +import java.text.Format; import java.util.ArrayList; import java.util.List; -import java.util.Objects; -import org.lwjgl.opengl.GL46; import org.lwjgl.opengl.GL46C; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.api.instancer.InstancedPart; +import com.jozufozu.flywheel.api.struct.StorageBufferWriter; import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.backend.gl.GlNumericType; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.backend.instancing.instancing.MeshPool; import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.QuadConverter; import com.jozufozu.flywheel.core.model.Mesh; +import com.jozufozu.flywheel.core.uniform.UniformBuffer; +import com.jozufozu.flywheel.core.vertex.Formats; public class IndirectList { + private static final int DRAW_COMMAND_STRIDE = 20; + + final StorageBufferWriter storageBufferWriter; final GlProgram compute; final GlProgram draw; + private final StructType type; + private final long maxObjectCount; + private final long objectStride; + private final int maxBatchCount; + private final long objectClientStorage; + private final int elementBuffer; /** * Stores raw instance data per-object. */ - DSABuffer objectBuffer; + int objectBuffer; + int targetBuffer; /** * Stores bounding spheres */ - DSABuffer boundingSphereBuffer; + int boundingSphereBuffer; /** * Stores drawIndirect structs. */ - DSABuffer drawBuffer; - DSABuffer targetBuffer; + int drawBuffer; - final int[] buffers = new int[4]; + final IndirectMeshPool meshPool; + + int vertexArray; + + final int[] shaderStorageBuffers = new int[4]; final List> batches = new ArrayList<>(); IndirectList(StructType structType) { - GL46.glCreateBuffers(buffers); - objectBuffer = new DSABuffer(buffers[0]); - targetBuffer = new DSABuffer(buffers[1]); - boundingSphereBuffer = new DSABuffer(buffers[2]); - drawBuffer = new DSABuffer(buffers[3]); + type = structType; + storageBufferWriter = type.getStorageBufferWriter(); - compute = ComputeCompiler.INSTANCE.get(Components.Files.CULL_INSTANCES); - draw = null; + if (storageBufferWriter == null) { + throw new NullPointerException(); + } + + glCreateBuffers(shaderStorageBuffers); + objectBuffer = shaderStorageBuffers[0]; + targetBuffer = shaderStorageBuffers[1]; + boundingSphereBuffer = shaderStorageBuffers[2]; + drawBuffer = shaderStorageBuffers[3]; + meshPool = new IndirectMeshPool(Formats.BLOCK, 1024); + + // FIXME: Resizable buffers + maxObjectCount = 1024L * 100L; + maxBatchCount = 64; + + // +4 for the batch id + objectStride = storageBufferWriter.getAlignment(); + glNamedBufferStorage(objectBuffer, objectStride * maxObjectCount, GL_DYNAMIC_STORAGE_BIT); + glNamedBufferStorage(targetBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT); + glNamedBufferStorage(boundingSphereBuffer, 16 * maxBatchCount, GL_DYNAMIC_STORAGE_BIT); + glNamedBufferStorage(drawBuffer, DRAW_COMMAND_STRIDE * maxBatchCount, GL_DYNAMIC_STORAGE_BIT); + + objectClientStorage = MemoryUtil.nmemAlloc(objectStride * maxObjectCount); + + vertexArray = glCreateVertexArrays(); + + elementBuffer = QuadConverter.getInstance() + .quads2Tris(2048).buffer.handle(); + setupVertexArray(); + + compute = ComputeCullerCompiler.INSTANCE.get(Components.Files.CULL_INSTANCES); + draw = IndirectDrawCompiler.INSTANCE.get(new IndirectDrawCompiler.Program(Components.Files.DRAW_INDIRECT_VERTEX, Components.Files.DRAW_INDIRECT_FRAGMENT)); + } + + private void setupVertexArray() { + glVertexArrayElementBuffer(vertexArray, elementBuffer); + + var meshLayout = Formats.BLOCK.getLayout(); + var meshAttribs = meshLayout.getAttributeCount(); + + var attributes = meshLayout.getAttributes(); + + long offset = 0; + for (int i = 0; i < meshAttribs; i++) { + var attribute = attributes.get(i); + glEnableVertexArrayAttrib(vertexArray, i); + glVertexArrayVertexBuffer(vertexArray, i, meshPool.vbo, offset, meshLayout.getStride()); + attribute.format(vertexArray, i); + offset += attribute + .getByteWidth(); + } + + glEnableVertexArrayAttrib(vertexArray, meshAttribs); + glVertexArrayVertexBuffer(vertexArray, meshAttribs, targetBuffer, 0, 4); + glVertexArrayAttribIFormat(vertexArray, meshAttribs, 1, GlNumericType.UINT.getGlEnum(), 0); } public void add(Mesh mesh, IndirectInstancer instancer) { - var pool = MeshPool.getInstance(); - var buffered = pool.alloc(mesh); - - batches.add(new Batch<>(instancer, buffered)); + batches.add(new Batch<>(instancer, meshPool.alloc(mesh))); } - public void prepare() { + void submit() { + int instanceCountThisFrame = calculateTotalInstanceCount(); + if (instanceCountThisFrame == 0) { + return; + } + + meshPool.uploadAll(); + uploadInstanceData(); + uploadBoundingSpheres(); + uploadIndirectCommands(); + + UniformBuffer.getInstance().sync(); + + dispatchCompute(instanceCountThisFrame); + issueMemoryBarrier(); + dispatchDraw(); + } + + private void dispatchDraw() { + draw.bind(); + Materials.BELL.setup(); + glVertexArrayElementBuffer(vertexArray, elementBuffer); + glBindVertexArray(vertexArray); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, drawBuffer); + glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, 0, batches.size(), 0); + Materials.BELL.clear(); + } + + private static void issueMemoryBarrier() { + glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); + } + + private void uploadBoundingSpheres() { try (var stack = MemoryStack.stackPush()) { - var size = batches.size() * 20; + final int size = batches.size() * 16; + final long basePtr = stack.nmalloc(size); + + long ptr = basePtr; + for (Batch batch : batches) { + var boundingSphere = batch.mesh.mesh.getBoundingSphere(); + boundingSphere.getToAddress(ptr); + ptr += 16; + } + + GL46C.nglNamedBufferSubData(boundingSphereBuffer, 0, size, basePtr); + } + } + + private void dispatchCompute(int instanceCount) { + compute.bind(); + glBindBuffersBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffers); + + var groupCount = (instanceCount + 31) >> 5; // ceil(totalInstanceCount / 32) + glDispatchCompute(groupCount, 1, 1); + } + + private void uploadInstanceData() { + long ptr = objectClientStorage; + int baseInstance = 0; + int batchID = 0; + for (var batch : batches) { + batch.baseInstance = baseInstance; + var instancer = batch.instancer; + for (T t : instancer.getAll()) { + storageBufferWriter.write(ptr, t, batchID); + ptr += objectStride; + } + baseInstance += batch.instancer.instanceCount; + batchID++; + } + + GL46C.nglNamedBufferSubData(objectBuffer, 0, ptr - objectClientStorage, objectClientStorage); + + } + + private void uploadIndirectCommands() { + try (var stack = MemoryStack.stackPush()) { + var size = batches.size() * DRAW_COMMAND_STRIDE; long basePtr = stack.nmalloc(size); long writePtr = basePtr; for (Batch batch : batches) { batch.writeIndirectCommand(writePtr); - writePtr += 20; + writePtr += DRAW_COMMAND_STRIDE; } - GL46C.nglNamedBufferData(drawBuffer.id, size, basePtr, GL46.GL_STREAM_DRAW); + GL46C.nglNamedBufferSubData(drawBuffer, 0, size, basePtr); } } - public void submit() { - - compute.bind(); - GL46.glBindBuffersBase(GL46.GL_SHADER_STORAGE_BUFFER, 0, buffers); - - var groupCount = (getTotalInstanceCount() + 31) >> 5; // ceil(totalInstanceCount / 32) - GL46.glDispatchCompute(groupCount, 1, 1); - - draw.bind(); - GL46.glMemoryBarrier(GL46.GL_SHADER_STORAGE_BARRIER_BIT); - GL46.glBindBuffer(GL46.GL_DRAW_INDIRECT_BUFFER, drawBuffer.id); - - GL46.glMultiDrawElementsIndirect(GL46.GL_TRIANGLES, GL46.GL_UNSIGNED_INT, 0, batches.size(), 0); - } - - private int getTotalInstanceCount() { - return 0; + private int calculateTotalInstanceCount() { + int total = 0; + for (Batch batch : batches) { + batch.instancer.update(); + total += batch.instancer.instanceCount; + } + return total; } private static final class Batch { final IndirectInstancer instancer; - final MeshPool.BufferedMesh mesh; + final IndirectMeshPool.BufferedMesh mesh; + int baseInstance; - private Batch(IndirectInstancer instancer, MeshPool.BufferedMesh mesh) { + private Batch(IndirectInstancer instancer, IndirectMeshPool.BufferedMesh mesh) { this.instancer = instancer; this.mesh = mesh; } public void writeIndirectCommand(long ptr) { - // typedef struct { - // GLuint count; - // GLuint instanceCount; - // GLuint firstIndex; - // GLuint baseVertex; - // GLuint baseInstance; - //} DrawElementsIndirectCommand; - - MemoryUtil.memPutInt(ptr, mesh.getVertexCount()); - MemoryUtil.memPutInt(ptr + 4, 0); - MemoryUtil.memPutInt(ptr + 8, 0); - MemoryUtil.memPutInt(ptr + 12, mesh.getBaseVertex()); - MemoryUtil.memPutInt(ptr + 16, 0); + MemoryUtil.memPutInt(ptr, mesh.getVertexCount()); // count + MemoryUtil.memPutInt(ptr + 4, 0); // instanceCount - to be incremented by the compute shader + MemoryUtil.memPutInt(ptr + 8, 0); // firstIndex - all models share the same index buffer + MemoryUtil.memPutInt(ptr + 12, mesh.getBaseVertex()); // baseVertex + MemoryUtil.memPutInt(ptr + 16, baseInstance); // baseInstance } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java new file mode 100644 index 000000000..ade54f176 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java @@ -0,0 +1,118 @@ +package com.jozufozu.flywheel.backend.instancing.indirect; + +import static org.lwjgl.opengl.GL46.*; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.jetbrains.annotations.Nullable; +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.instancing.instancing.ElementBuffer; +import com.jozufozu.flywheel.core.model.Mesh; + +public class IndirectMeshPool { + + private final Map meshes = new HashMap<>(); + private final List meshList = new ArrayList<>(); + + final VertexType vertexType; + + final int vbo; + private final ByteBuffer clientStorage; + + private boolean dirty; + + /** + * Create a new mesh pool. + */ + public IndirectMeshPool(VertexType type, int vertexCapacity) { + vertexType = type; + vbo = glCreateBuffers(); + var byteCapacity = type.byteOffset(vertexCapacity); + glNamedBufferStorage(vbo, byteCapacity, GL_DYNAMIC_STORAGE_BIT); + clientStorage = MemoryUtil.memAlloc(byteCapacity); + } + + /** + * Allocate a model in the arena. + * + * @param mesh The model to allocate. + * @return A handle to the allocated model. + */ + public BufferedMesh alloc(Mesh mesh) { + return meshes.computeIfAbsent(mesh, m -> { + BufferedMesh bufferedModel = new BufferedMesh(m); + meshList.add(bufferedModel); + + dirty = true; + return bufferedModel; + }); + } + + @Nullable + public BufferedMesh get(Mesh mesh) { + return meshes.get(mesh); + } + + void uploadAll() { + if (!dirty) { + return; + } + dirty = false; + + int byteIndex = 0; + int baseVertex = 0; + for (BufferedMesh model : meshList) { + model.byteIndex = byteIndex; + model.baseVertex = baseVertex; + + model.buffer(clientStorage); + + byteIndex += model.getByteSize(); + baseVertex += model.mesh.getVertexCount(); + } + + glNamedBufferSubData(vbo, 0, clientStorage); + } + + public void delete() { + glDeleteBuffers(vbo); + meshes.clear(); + meshList.clear(); + } + + public class BufferedMesh { + + public final Mesh mesh; + private long byteIndex; + private int baseVertex; + + public BufferedMesh(Mesh mesh) { + this.mesh = mesh; + } + + private void buffer(ByteBuffer buffer) { + var writer = IndirectMeshPool.this.vertexType.createWriter(buffer); + writer.seek(this.byteIndex); + writer.writeVertexList(this.mesh.getReader()); + } + + public int getByteSize() { + return IndirectMeshPool.this.vertexType.getLayout().getStride() * this.mesh.getVertexCount(); + } + + public int getBaseVertex() { + return baseVertex; + } + + public int getVertexCount() { + return this.mesh.getVertexCount(); + } + } + +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/InstancedModel.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/InstancedModel.java index 5c5f032bb..e3faeb739 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/InstancedModel.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/InstancedModel.java @@ -1,13 +1,7 @@ package com.jozufozu.flywheel.backend.instancing.indirect; -import java.util.List; -import java.util.Map; - -import com.jozufozu.flywheel.api.RenderStage; import com.jozufozu.flywheel.api.instancer.InstancedPart; -import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.core.model.Mesh; import com.jozufozu.flywheel.core.model.Model; public class InstancedModel { @@ -42,7 +36,7 @@ public class InstancedModel { } public int getVertexCount() { - return model.getVertexCount() * instancer.maxInstanceCount; + return model.getVertexCount() * instancer.instanceCount; } public void delete() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/MeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/MeshPool.java index 053af8645..0438ac71d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/MeshPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/MeshPool.java @@ -27,7 +27,7 @@ public class MeshPool { private static MeshPool allocator; - public static MeshPool getInstance() { + static MeshPool getInstance() { if (allocator == null) { allocator = new MeshPool(); } @@ -188,7 +188,7 @@ public class MeshPool { public class BufferedMesh { private final ElementBuffer ebo; - private final Mesh mesh; + public final Mesh mesh; private final VertexType type; private long byteIndex; private int baseVertex; diff --git a/src/main/java/com/jozufozu/flywheel/core/Components.java b/src/main/java/com/jozufozu/flywheel/core/Components.java index 581dd62be..f89df8d97 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Components.java +++ b/src/main/java/com/jozufozu/flywheel/core/Components.java @@ -49,6 +49,8 @@ public class Components { public static final FileResolution CRUMBLING_VERTEX = contextVertex(ResourceUtil.subPath(Names.CRUMBLING, ".vert")); public static final FileResolution CRUMBLING_FRAGMENT = contextFragment(ResourceUtil.subPath(Names.CRUMBLING, ".frag")); public static final FileResolution CULL_INSTANCES = compute(Flywheel.rl("compute/cull_instances.glsl")); + public static final FileResolution DRAW_INDIRECT_VERTEX = FileResolution.get(ResourceUtil.subPath(Names.DRAW_INDIRECT, ".vert")); + public static final FileResolution DRAW_INDIRECT_FRAGMENT = FileResolution.get(ResourceUtil.subPath(Names.DRAW_INDIRECT, ".frag")); private static FileResolution compute(ResourceLocation rl) { return FileResolution.get(rl); @@ -115,5 +117,6 @@ public class Components { public static final ResourceLocation SHADED = Flywheel.rl("material/shaded"); public static final ResourceLocation WORLD = Flywheel.rl("context/world"); public static final ResourceLocation CRUMBLING = Flywheel.rl("context/crumbling"); + public static final ResourceLocation DRAW_INDIRECT = Flywheel.rl("compute/draw_instances"); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java b/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java index b639d64e0..91620e819 100644 --- a/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java +++ b/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java @@ -2,19 +2,24 @@ package com.jozufozu.flywheel.core.hardcoded; import java.util.List; +import org.jetbrains.annotations.NotNull; import org.lwjgl.system.MemoryStack; import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.core.model.Mesh; +import com.jozufozu.flywheel.core.model.ModelUtil; import com.jozufozu.flywheel.core.vertex.Formats; import com.jozufozu.flywheel.core.vertex.PosTexNormalVertex; import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe; +import com.jozufozu.flywheel.util.joml.Vector4f; +import com.jozufozu.flywheel.util.joml.Vector4fc; public class ModelPart implements Mesh { private final int vertices; private final String name; private final VertexList reader; + private final @NotNull Vector4f boundingSphere; public ModelPart(List cuboids, String name) { this.name = name; @@ -35,6 +40,8 @@ public class ModelPart implements Mesh { reader = writer.intoReader(this.vertices); } + + boundingSphere = ModelUtil.computeBoundingSphere(reader); } public static PartBuilder builder(String name, int sizeU, int sizeV) { @@ -60,4 +67,9 @@ public class ModelPart implements Mesh { public PosTexNormalVertex getVertexType() { return Formats.POS_TEX_NORMAL; } + + @Override + public Vector4fc getBoundingSphere() { + return boundingSphere; + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java b/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java index 74f958d6a..8f28d9f2d 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java @@ -35,7 +35,7 @@ public class BufferLayout { this.stride = calculateStride(this.attributes) + padding; } - public Collection getAttributes() { + public List getAttributes() { return attributes; } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java b/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java index c382211c7..dcc7ffa8f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java @@ -7,6 +7,7 @@ import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexWriter; import com.jozufozu.flywheel.backend.instancing.instancing.ElementBuffer; import com.jozufozu.flywheel.core.QuadConverter; +import com.jozufozu.flywheel.util.joml.Vector4fc; /** * A mesh that can be rendered by flywheel. @@ -39,6 +40,8 @@ public interface Mesh { VertexList getReader(); + Vector4fc getBoundingSphere(); + /** * @return The number of vertices the model has. */ diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java b/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java index ff76a0220..fe3041287 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java @@ -3,6 +3,7 @@ package com.jozufozu.flywheel.core.model; import java.lang.reflect.Field; import java.nio.ByteBuffer; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import com.dreizak.miniball.highdim.Miniball; @@ -11,6 +12,7 @@ import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.vertex.Formats; +import com.jozufozu.flywheel.util.joml.Vector4f; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.datafixers.util.Pair; @@ -74,4 +76,12 @@ public class ModelUtil { } return null; } + + @NotNull + public static Vector4f computeBoundingSphere(VertexList reader) { + var miniball = new Miniball(reader); + double[] center = miniball.center(); + double radius = miniball.radius(); + return new Vector4f((float) center[0], (float) center[1], (float) center[2], (float) radius); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java b/src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java index 55f76ef44..e5808067f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java @@ -2,16 +2,21 @@ package com.jozufozu.flywheel.core.model; import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.util.joml.Vector4f; +import com.jozufozu.flywheel.util.joml.Vector4fc; public class SimpleMesh implements Mesh { private final VertexList reader; private final VertexType vertexType; private final String name; + private final Vector4f boundingSphere; public SimpleMesh(VertexList reader, VertexType vertexType, String name) { this.reader = reader; this.vertexType = vertexType; this.name = name; + + boundingSphere = ModelUtil.computeBoundingSphere(reader); } @Override @@ -29,6 +34,11 @@ public class SimpleMesh implements Mesh { return reader; } + @Override + public Vector4fc getBoundingSphere() { + return boundingSphere; + } + @Override public String toString() { return "SimpleMesh{" + "name='" + name + "',vertexType='" + vertexType + "}"; diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java index 4e63ef409..2f799677b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java @@ -184,24 +184,24 @@ public class SourceFile { return "#use " + '"' + name + '"'; } - public String generateFinalSource(CompilationContext env) { - return generateFinalSource(env, Collections.emptyList()); + public String generateFinalSource(CompilationContext context) { + return generateFinalSource(context, Collections.emptyList()); } - public String generateFinalSource(CompilationContext env, List> replacements) { + public String generateFinalSource(CompilationContext context, List> replacements) { var out = new StringBuilder(); for (Import include : flattenedImports) { SourceFile file = include.getFile(); - if (file == null || env.contains(file)) { + if (file == null || context.contains(file)) { continue; } - out.append(file.generateLineHeader(env)) + out.append(file.generateLineHeader(context)) .append(file.replaceAndElide(replacements)); } - out.append(this.generateLineHeader(env)) + out.append(this.generateLineHeader(context)) .append(this.replaceAndElide(replacements)); return out.toString(); diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java index 30d750672..c754bc1ab 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.core.structs.model; import java.nio.ByteBuffer; +import com.jozufozu.flywheel.api.struct.StorageBufferWriter; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.core.Components; @@ -33,6 +34,11 @@ public class TransformedType implements StructType { return new TransformedWriterUnsafe(this, backing); } + @Override + public StorageBufferWriter getStorageBufferWriter() { + return null; // TODO + } + @Override public FileResolution getInstanceShader() { return Components.Files.TRANSFORMED; diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedStorageWriter.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedStorageWriter.java new file mode 100644 index 000000000..43c8a0f82 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedStorageWriter.java @@ -0,0 +1,45 @@ +package com.jozufozu.flywheel.core.structs.oriented; + + +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.api.struct.StorageBufferWriter; + +public class OrientedStorageWriter implements StorageBufferWriter { + + public static final OrientedStorageWriter INSTANCE = new OrientedStorageWriter(); + + private OrientedStorageWriter() { + } + + @Override + public void write(final long ptr, OrientedPart d, final int batchID) { + MemoryUtil.memPutFloat(ptr, d.qX); + MemoryUtil.memPutFloat(ptr + 4, d.qY); + MemoryUtil.memPutFloat(ptr + 8, d.qZ); + MemoryUtil.memPutFloat(ptr + 12, d.qW); + + MemoryUtil.memPutFloat(ptr + 16, d.posX); + MemoryUtil.memPutFloat(ptr + 20, d.posY); + MemoryUtil.memPutFloat(ptr + 24, d.posZ); + + MemoryUtil.memPutFloat(ptr + 28, d.pivotX); + MemoryUtil.memPutFloat(ptr + 32, d.pivotY); + MemoryUtil.memPutFloat(ptr + 36, d.pivotZ); + + MemoryUtil.memPutShort(ptr + 40, d.blockLight); + MemoryUtil.memPutShort(ptr + 42, d.skyLight); + + MemoryUtil.memPutByte(ptr + 44, d.r); + MemoryUtil.memPutByte(ptr + 45, d.g); + MemoryUtil.memPutByte(ptr + 46, d.b); + MemoryUtil.memPutByte(ptr + 47, d.a); + + MemoryUtil.memPutInt(ptr + 48, batchID); + } + + @Override + public int getAlignment() { + return 52; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java index 93a0226ef..be6fbfa28 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.core.structs.oriented; import java.nio.ByteBuffer; +import com.jozufozu.flywheel.api.struct.StorageBufferWriter; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.core.Components; @@ -36,6 +37,11 @@ public class OrientedType implements StructType { return new OrientedWriterUnsafe(this, backing); } + @Override + public OrientedStorageWriter getStorageBufferWriter() { + return OrientedStorageWriter.INSTANCE; + } + @Override public FileResolution getInstanceShader() { return Components.Files.ORIENTED; diff --git a/src/main/java/com/jozufozu/flywheel/mixin/ClientMainMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/ClientMainMixin.java new file mode 100644 index 000000000..49f7d0abe --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/ClientMainMixin.java @@ -0,0 +1,27 @@ +package com.jozufozu.flywheel.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.main.Main; + +@Mixin(Main.class) +public class ClientMainMixin { + @Inject(method = "main", at = @At("HEAD")) + private static void injectRenderDoc(CallbackInfo ci) { + // Only try to load RenderDoc if a system property is set. + if (System.getProperty("flw.loadRenderDoc") == null) { + return; + } + + try { + System.loadLibrary("renderdoc"); + } catch (Throwable ignored) { + // Oh well, we tried. + // On Windows, RenderDoc installs to "C:\Program Files\RenderDoc\" + System.err.println("Is RenderDoc in your PATH?"); + } + } +} diff --git a/src/main/resources/assets/flywheel/flywheel/compute/cull_instances.glsl b/src/main/resources/assets/flywheel/flywheel/compute/cull_instances.glsl index ade7d8eb4..ef4577120 100644 --- a/src/main/resources/assets/flywheel/flywheel/compute/cull_instances.glsl +++ b/src/main/resources/assets/flywheel/flywheel/compute/cull_instances.glsl @@ -1,10 +1,9 @@ -#version 450 #define FLW_SUBGROUP_SIZE 32 layout(local_size_x = FLW_SUBGROUP_SIZE) in; #use "flywheel:compute/objects.glsl" #use "flywheel:util/quaternion.glsl" -layout(std130, binding = 3) uniform FrameData { +layout(std140, binding = 3) uniform FrameData { vec4 a1; // vec4(nx.x, px.x, ny.x, py.x) vec4 a2; // vec4(nx.y, px.y, ny.y, py.y) vec4 a3; // vec4(nx.z, px.z, ny.z, py.z) @@ -13,23 +12,22 @@ layout(std130, binding = 3) uniform FrameData { vec2 b2; // vec2(nz.y, pz.y) vec2 b3; // vec2(nz.z, pz.z) vec2 b4; // vec2(nz.w, pz.w) - uint drawCount; } frustum; // populated by instancers -layout(binding = 0) readonly buffer ObjectBuffer { +layout(std430, binding = 0) readonly buffer ObjectBuffer { Instance objects[]; }; -layout(binding = 1) writeonly buffer TargetBuffer { +layout(std430, binding = 1) writeonly buffer TargetBuffer { uint objectIDs[]; }; -layout(binding = 2) readonly buffer BoundingSpheres { +layout(std430, binding = 2) readonly buffer BoundingSpheres { vec4 boundingSpheres[]; }; -layout(binding = 3) buffer DrawCommands { +layout(std430, binding = 3) buffer DrawCommands { MeshDrawCommand drawCommands[]; }; @@ -44,16 +42,16 @@ bool isVisible(uint objectID, uint batchID) { vec4 sphere = boundingSpheres[batchID]; vec3 pivot = objects[objectID].pivot; - vec3 center = rotateQuat(sphere.xyz - pivot, objects[objectID].orientation) + pivot + objects[objectID].position; + vec3 center = rotateVertexByQuat(sphere.xyz - pivot, objects[objectID].rotation) + pivot + objects[objectID].pos; float radius = sphere.r; - return testSphere(center, radius); + return true; //testSphere(center, radius); } void main() { uint objectID = gl_GlobalInvocationID.x; - if (objectID >= frustum.drawCount) { + if (objectID >= objects.length()) { return; } diff --git a/src/main/resources/assets/flywheel/flywheel/compute/draw_instances.frag b/src/main/resources/assets/flywheel/flywheel/compute/draw_instances.frag new file mode 100644 index 000000000..6591bea51 --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/compute/draw_instances.frag @@ -0,0 +1,9 @@ +#use "flywheel:api/fragment.glsl" +#use "flywheel:context/world.frag" +#use "flywheel:material/default.frag" + +void main() { + flw_initFragment(); + flw_materialFragment(); + flw_contextFragment(); +} diff --git a/src/main/resources/assets/flywheel/flywheel/compute/draw_instances.vert b/src/main/resources/assets/flywheel/flywheel/compute/draw_instances.vert index ab72b635d..030d82200 100644 --- a/src/main/resources/assets/flywheel/flywheel/compute/draw_instances.vert +++ b/src/main/resources/assets/flywheel/flywheel/compute/draw_instances.vert @@ -1,22 +1,23 @@ #use "flywheel:api/vertex.glsl" #use "flywheel:compute/objects.glsl" -#use "flywheel:pos_tex_normal.glsl" +#use "flywheel:layout/block.vert" #use "flywheel:context/world.vert" +#use "flywheel:util/quaternion.glsl" // populated by instancers -layout(binding = 0) readonly buffer ObjectBuffer { +layout(std430, binding = 0) readonly buffer ObjectBuffer { Instance objects[]; }; -layout(binding = 1) readonly buffer TargetBuffer { +layout(std430, binding = 1) readonly buffer TargetBuffer { uint objectIDs[]; }; void flw_instanceVertex(Instance i) { flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.pos, 1.0); flw_vertexNormal = rotateVertexByQuat(flw_vertexNormal, i.rotation); - flw_vertexColor = i.color; - flw_vertexLight = i.light / 15.0; + flw_vertexColor = unpackUnorm4x8(i.color); + flw_vertexLight = unpackUnorm2x16(i.light) / 15.0; } void main() { diff --git a/src/main/resources/assets/flywheel/flywheel/compute/objects.glsl b/src/main/resources/assets/flywheel/flywheel/compute/objects.glsl index c8179345a..635ae39db 100644 --- a/src/main/resources/assets/flywheel/flywheel/compute/objects.glsl +++ b/src/main/resources/assets/flywheel/flywheel/compute/objects.glsl @@ -1,14 +1,14 @@ struct Instance { - ivec2 light; - vec4 color; + vec4 rotation; vec3 pos; vec3 pivot; - vec4 rotation; + uint light; + uint color; uint batchID; }; -struct MeshDrawCommands { +struct MeshDrawCommand { uint indexCount; uint instanceCount; uint firstIndex; diff --git a/src/main/resources/flywheel.mixins.json b/src/main/resources/flywheel.mixins.json index fab33485c..5c36a9163 100644 --- a/src/main/resources/flywheel.mixins.json +++ b/src/main/resources/flywheel.mixins.json @@ -11,6 +11,7 @@ "BufferUploaderMixin", "ChunkRebuildHooksMixin", "ClientLevelMixin", + "ClientMainMixin", "EntityTypeMixin", "FixFabulousDepthMixin", "FogUpdateMixin",