From 733ec602164cf9b7827c2b70902248d2c3161cae Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Thu, 4 Jan 2024 23:44:35 -0800 Subject: [PATCH] Instancing with Layouts - InstancedArraysComponent now fully uses Layouts. - Trivial to get the glsl type name of a given Element. - Also quite easy to get the attribute count without actually creating the attribute list. - IndirectComponent is WIP because unpacking is hard. - Reorganize so all the unpacking stuff is in one loop. --- .../backend/compile/LayoutInterpreter.java | 62 ++++++++++++++++ .../compile/component/IndirectComponent.java | 74 +++++++++++-------- .../component/InstancedArraysComponent.java | 44 ++++++----- .../flywheel/glsl/generate/GlslFn.java | 7 +- 4 files changed, 137 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/backend/compile/LayoutInterpreter.java diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/LayoutInterpreter.java b/src/main/java/com/jozufozu/flywheel/backend/compile/LayoutInterpreter.java new file mode 100644 index 000000000..62f255848 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/LayoutInterpreter.java @@ -0,0 +1,62 @@ +package com.jozufozu.flywheel.backend.compile; + +import com.jozufozu.flywheel.api.layout.ElementType; +import com.jozufozu.flywheel.api.layout.FloatRepr; +import com.jozufozu.flywheel.api.layout.IntegerRepr; +import com.jozufozu.flywheel.api.layout.MatrixElementType; +import com.jozufozu.flywheel.api.layout.ScalarElementType; +import com.jozufozu.flywheel.api.layout.UnsignedIntegerRepr; +import com.jozufozu.flywheel.api.layout.ValueRepr; +import com.jozufozu.flywheel.api.layout.VectorElementType; + +public class LayoutInterpreter { + public static int attributeCount(ElementType type) { + if (type instanceof ScalarElementType) { + return 1; + } else if (type instanceof VectorElementType) { + return 1; + } else if (type instanceof MatrixElementType matrix) { + return matrix.rows(); + } + + throw new IllegalArgumentException("Unknown type " + type); + } + + public static String typeName(ElementType type) { + if (type instanceof ScalarElementType scalar) { + return scalarTypeName(scalar.repr()); + } else if (type instanceof VectorElementType vector) { + return vectorTypeName(vector.repr(), vector.size()); + } else if (type instanceof MatrixElementType matrix) { + return matrixTypeName(matrix); + } + + throw new IllegalArgumentException("Unknown type " + type); + } + + public static String matrixTypeName(MatrixElementType matrix) { + return "mat" + matrix.columns() + "x" + matrix.rows(); + } + + public static String vectorTypeName(ValueRepr repr, int size) { + if (repr instanceof IntegerRepr) { + return "ivec" + size; + } else if (repr instanceof UnsignedIntegerRepr) { + return "uvec" + size; + } else if (repr instanceof FloatRepr) { + return "vec" + size; + } + throw new IllegalArgumentException("Unknown repr " + repr); + } + + public static String scalarTypeName(ValueRepr repr) { + if (repr instanceof IntegerRepr) { + return "int"; + } else if (repr instanceof UnsignedIntegerRepr) { + return "uint"; + } else if (repr instanceof FloatRepr) { + return "float"; + } + throw new IllegalArgumentException("Unknown repr " + repr); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/component/IndirectComponent.java b/src/main/java/com/jozufozu/flywheel/backend/compile/component/IndirectComponent.java index 067f75377..af02aa7d7 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/component/IndirectComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/component/IndirectComponent.java @@ -1,5 +1,6 @@ package com.jozufozu.flywheel.backend.compile.component; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -7,6 +8,7 @@ import java.util.List; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.layout.Layout; +import com.jozufozu.flywheel.backend.compile.LayoutInterpreter; import com.jozufozu.flywheel.backend.compile.Pipeline; import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.generate.FnSignature; @@ -58,44 +60,58 @@ public class IndirectComponent implements SourceComponent { public String generateIndirect() { var builder = new GlslBuilder(); - layoutItems.stream() - .map(LayoutItem::type) - .distinct() - .forEach(type -> type.declare(builder)); + generateHeader(builder); - var instance = builder.struct(); - instance.setName(STRUCT_NAME); - builder.blankLine(); - var packed = builder.struct(); - packed.setName(PACKED_STRUCT_NAME); - - for (var field : layoutItems) { - packed.addField(field.type() - .packedTypeName(), field.name()); - instance.addField(field.type() - .typeName(), field.name()); - } + generateInstanceStruct(builder); builder.blankLine(); - builder.function() - .signature(FnSignature.create() - .returnType(STRUCT_NAME) - .name(UNPACK_FN_NAME) - .arg(PACKED_STRUCT_NAME, UNPACK_ARG) - .build()) - .body(this::generateUnpackingBody); + generateUnpacking(builder); builder.blankLine(); return builder.build(); } - private void generateUnpackingBody(GlslBlock b) { - var unpackedFields = layoutItems.stream() - .map(layoutItem -> UNPACKING_VARIABLE.access(layoutItem.name()) - .transform(layoutItem.type()::unpack)) - .toList(); - b.ret(GlslExpr.call(STRUCT_NAME, unpackedFields)); + private void generateHeader(GlslBuilder builder) { + layoutItems.stream() + .map(LayoutItem::type) + .distinct() + .forEach(type -> type.declare(builder)); + } + + private void generateInstanceStruct(GlslBuilder builder) { + var instance = builder.struct(); + instance.setName(STRUCT_NAME); + for (var element : layout.elements()) { + instance.addField(LayoutInterpreter.typeName(element.type()), element.name()); + } + } + + private void generateUnpacking(GlslBuilder builder) { + var packed = builder.struct(); + packed.setName(PACKED_STRUCT_NAME); + + var unpackArgs = new ArrayList(); + for (LayoutItem field : layoutItems) { + GlslExpr unpack = UNPACKING_VARIABLE.access(field.name()) + .transform(field.type()::unpack); + unpackArgs.add(unpack); + + packed.addField(field.type() + .packedTypeName(), field.name()); + } + + var block = new GlslBlock(); + block.ret(GlslExpr.call(STRUCT_NAME, unpackArgs)); + + builder.blankLine(); + builder.function() + .signature(FnSignature.create() + .returnType(STRUCT_NAME) + .name(UNPACK_FN_NAME) + .arg(PACKED_STRUCT_NAME, UNPACK_ARG) + .build()) + .body(block); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/component/InstancedArraysComponent.java b/src/main/java/com/jozufozu/flywheel/backend/compile/component/InstancedArraysComponent.java index cd82b2024..79c91a11f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/component/InstancedArraysComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/component/InstancedArraysComponent.java @@ -2,16 +2,16 @@ package com.jozufozu.flywheel.backend.compile.component; import java.util.Collection; import java.util.Collections; -import java.util.List; import com.jozufozu.flywheel.Flywheel; +import com.jozufozu.flywheel.api.layout.Layout; +import com.jozufozu.flywheel.backend.compile.LayoutInterpreter; import com.jozufozu.flywheel.backend.compile.Pipeline; import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.generate.FnSignature; import com.jozufozu.flywheel.glsl.generate.GlslBlock; import com.jozufozu.flywheel.glsl.generate.GlslBuilder; import com.jozufozu.flywheel.glsl.generate.GlslExpr; -import com.jozufozu.flywheel.lib.layout.LayoutItem; import net.minecraft.resources.ResourceLocation; @@ -20,12 +20,12 @@ public class InstancedArraysComponent implements SourceComponent { private static final String STRUCT_NAME = "FlwInstance"; private static final String UNPACK_FN_NAME = "_flw_unpackInstance"; - private final List layoutItems; + private final Layout layout; private final int baseIndex; public InstancedArraysComponent(Pipeline.InstanceAssemblerContext ctx) { - this.layoutItems = ctx.instanceType() - .oldLayout().layoutItems; + this.layout = ctx.instanceType() + .layout(); this.baseIndex = ctx.baseAttribute(); } @@ -43,26 +43,15 @@ public class InstancedArraysComponent implements SourceComponent { public String source() { var builder = new GlslBuilder(); - int i = baseIndex; - for (var field : layoutItems) { - builder.vertexInput() - .binding(i) - .type(field.type() - .typeName()) - .name(ATTRIBUTE_PREFIX + field.name()); - - i += field.type() - .attributeCount(); - } + generateVertexInput(builder); builder.blankLine(); var structBuilder = builder.struct(); structBuilder.setName(STRUCT_NAME); - for (var field : layoutItems) { - structBuilder.addField(field.type() - .typeName(), field.name()); + for (var element : layout.elements()) { + structBuilder.addField(LayoutInterpreter.typeName(element.type()), element.name()); } builder.blankLine(); @@ -77,8 +66,23 @@ public class InstancedArraysComponent implements SourceComponent { return builder.build(); } + private void generateVertexInput(GlslBuilder builder) { + int i = baseIndex; + for (var element : layout.elements()) { + var type = element.type(); + + builder.vertexInput() + .binding(i) + .type(LayoutInterpreter.typeName(type)) + .name(ATTRIBUTE_PREFIX + element.name()); + + i += LayoutInterpreter.attributeCount(type); + } + } + private void generateUnpackingBody(GlslBlock b) { - var fields = layoutItems.stream() + var fields = layout.elements() + .stream() .map(it -> new GlslExpr.Variable(ATTRIBUTE_PREFIX + it.name())) .toList(); b.ret(GlslExpr.call(STRUCT_NAME, fields)); diff --git a/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslFn.java b/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslFn.java index 360588cbd..d36c16ce8 100644 --- a/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslFn.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslFn.java @@ -5,7 +5,7 @@ import java.util.function.Consumer; import com.jozufozu.flywheel.lib.util.StringUtil; public class GlslFn implements GlslBuilder.Declaration { - private final GlslBlock body = new GlslBlock(); + private GlslBlock body = new GlslBlock(); private FnSignature signature; public GlslFn signature(FnSignature signature) { @@ -18,6 +18,11 @@ public class GlslFn implements GlslBuilder.Declaration { return this; } + public GlslFn body(GlslBlock block) { + body = block; + return this; + } + public String prettyPrint() { return """ %s {