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 extends S> 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",