mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
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
This commit is contained in:
parent
6234df6440
commit
9d657aed40
36 changed files with 644 additions and 131 deletions
32
build.gradle
32
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([
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
|
||||
public interface StorageBufferWriter<T extends InstancedPart> {
|
||||
|
||||
void write(final long ptr, final T instance, final int batchID);
|
||||
|
||||
int getAlignment();
|
||||
}
|
|
@ -36,6 +36,8 @@ public interface StructType<S extends InstancedPart> {
|
|||
|
||||
VertexTransformer<? extends S> getVertexTransformer();
|
||||
|
||||
StorageBufferWriter<S> getStorageBufferWriter();
|
||||
|
||||
public interface VertexTransformer<S extends InstancedPart> {
|
||||
void transform(MutableVertexList vertexList, S struct, ClientLevel level);
|
||||
}
|
||||
|
|
|
@ -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;
|
|||
* </p>
|
||||
* 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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -26,4 +26,8 @@ public enum GLSLVersion {
|
|||
public String toString() {
|
||||
return Integer.toString(version);
|
||||
}
|
||||
|
||||
public String getVersionLine() {
|
||||
return "#version " + version + '\n';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<D extends InstancedPart> implements Inst
|
|||
return data.size();
|
||||
}
|
||||
|
||||
public List<D> getRange(int start, int end) {
|
||||
return data.subList(start, end);
|
||||
}
|
||||
|
||||
public List<D> getAll() {
|
||||
return data;
|
||||
}
|
||||
|
||||
protected void removeDeletedInstances() {
|
||||
// Figure out which elements are to be removed.
|
||||
final int oldSize = this.data.size();
|
||||
|
|
|
@ -19,14 +19,6 @@ public class CPUInstancer<D extends InstancedPart> extends AbstractInstancer<D>
|
|||
}
|
||||
}
|
||||
|
||||
public List<D> getRange(int start, int end) {
|
||||
return data.subList(start, end);
|
||||
}
|
||||
|
||||
public List<D> getAll() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDirty() {
|
||||
// noop
|
||||
|
|
|
@ -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<FileResolution, GlProgram> {
|
||||
public class ComputeCullerCompiler extends Memoizer<FileResolution, GlProgram> {
|
||||
|
||||
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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<IndirectDrawCompiler.Program, GlProgram> {
|
||||
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) {
|
||||
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -11,7 +11,7 @@ public class IndirectInstancer<D extends InstancedPart> extends AbstractInstance
|
|||
public final BufferLayout instanceFormat;
|
||||
public final StructType<D> structType;
|
||||
public final InstancedModel<D> parent;
|
||||
int maxInstanceCount = 0;
|
||||
int instanceCount = 0;
|
||||
|
||||
boolean anyToUpdate;
|
||||
|
||||
|
@ -28,7 +28,7 @@ public class IndirectInstancer<D extends InstancedPart> extends AbstractInstance
|
|||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return !anyToUpdate && !anyToRemove && maxInstanceCount == 0;
|
||||
return !anyToUpdate && !anyToRemove && instanceCount == 0;
|
||||
}
|
||||
|
||||
void update() {
|
||||
|
@ -36,7 +36,7 @@ public class IndirectInstancer<D extends InstancedPart> extends AbstractInstance
|
|||
removeDeletedInstances();
|
||||
}
|
||||
|
||||
maxInstanceCount = data.size();
|
||||
instanceCount = data.size();
|
||||
|
||||
anyToRemove = false;
|
||||
}
|
||||
|
|
|
@ -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<T extends InstancedPart> {
|
||||
|
||||
private static final int DRAW_COMMAND_STRIDE = 20;
|
||||
|
||||
final StorageBufferWriter<T> storageBufferWriter;
|
||||
final GlProgram compute;
|
||||
final GlProgram draw;
|
||||
private final StructType<T> 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<Batch<T>> batches = new ArrayList<>();
|
||||
|
||||
IndirectList(StructType<T> 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<T> 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<T> 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<T> 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<T> batch : batches) {
|
||||
batch.instancer.update();
|
||||
total += batch.instancer.instanceCount;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
private static final class Batch<T extends InstancedPart> {
|
||||
final IndirectInstancer<T> instancer;
|
||||
final MeshPool.BufferedMesh mesh;
|
||||
final IndirectMeshPool.BufferedMesh mesh;
|
||||
int baseInstance;
|
||||
|
||||
private Batch(IndirectInstancer<T> instancer, MeshPool.BufferedMesh mesh) {
|
||||
private Batch(IndirectInstancer<T> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Mesh, BufferedMesh> meshes = new HashMap<>();
|
||||
private final List<BufferedMesh> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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<D extends InstancedPart> {
|
||||
|
@ -42,7 +36,7 @@ public class InstancedModel<D extends InstancedPart> {
|
|||
}
|
||||
|
||||
public int getVertexCount() {
|
||||
return model.getVertexCount() * instancer.maxInstanceCount;
|
||||
return model.getVertexCount() * instancer.instanceCount;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<PartBuilder.CuboidBuilder> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class BufferLayout {
|
|||
this.stride = calculateStride(this.attributes) + padding;
|
||||
}
|
||||
|
||||
public Collection<VertexAttribute> getAttributes() {
|
||||
public List<VertexAttribute> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 + "}";
|
||||
|
|
|
@ -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<Pair<Span, String>> replacements) {
|
||||
public String generateFinalSource(CompilationContext context, List<Pair<Span, String>> 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();
|
||||
|
|
|
@ -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<TransformedPart> {
|
|||
return new TransformedWriterUnsafe(this, backing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageBufferWriter<TransformedPart> getStorageBufferWriter() {
|
||||
return null; // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution getInstanceShader() {
|
||||
return Components.Files.TRANSFORMED;
|
||||
|
|
|
@ -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<OrientedPart> {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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<OrientedPart> {
|
|||
return new OrientedWriterUnsafe(this, backing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrientedStorageWriter getStorageBufferWriter() {
|
||||
return OrientedStorageWriter.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution getInstanceShader() {
|
||||
return Components.Files.ORIENTED;
|
||||
|
|
|
@ -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?");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"BufferUploaderMixin",
|
||||
"ChunkRebuildHooksMixin",
|
||||
"ClientLevelMixin",
|
||||
"ClientMainMixin",
|
||||
"EntityTypeMixin",
|
||||
"FixFabulousDepthMixin",
|
||||
"FogUpdateMixin",
|
||||
|
|
Loading…
Reference in a new issue