mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-11-14 22:43:56 +01:00
The end of issues with big endianness
- Fix unpacking of some layout elements (only for instancing) - All byte backed and short backed elements (incorrect assumption that system is little endian) - All signed byte and signed short elements (missing sign extension) - Matrices with byte backed and short backed reprs in some cases (incorrect assumption that matrix rows are 4 byte aligned) - IntegerRepr.INT scalar (invalid implicit cast) - FloatRepr.NORMALIZED_INT scalar (missing cast to signed int) - IntegerRepr.INT vector (invalid implicit cast) - FloatRepr.NORMALIZED_INT vector (missing cast to signed int) - FloatRepr.NORMALIZED_SHORT vector (incorrect divisor) - Add explicit casts from uint to float since some drivers have a bug where uint over float division is invalid - Lower GLSL requirement of instancing from 420 to 330 - Fix lib instance writers assuming little endian when writing overlay and light - Move overlay clamping to vertex input shader and clamp to 15 instead of 10 - Create abstract InstanceAssemblerComponent class - Change return type of SourceComponent.name() to String and improve implementations
This commit is contained in:
parent
bf3b8ea89b
commit
2bb9092d49
@ -67,7 +67,7 @@ public final class FlwPrograms {
|
||||
|
||||
@Nullable
|
||||
private static UberShaderComponent createVertexMaterialComponent(SourceLoader loadChecker) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("uber_material_vertex"))
|
||||
return UberShaderComponent.builder(Flywheel.rl("material_vertex"))
|
||||
.materialSources(ShaderIndices.materialVertex()
|
||||
.all())
|
||||
.adapt(FnSignature.ofVoid("flw_materialVertex"))
|
||||
@ -77,7 +77,7 @@ public final class FlwPrograms {
|
||||
|
||||
@Nullable
|
||||
private static UberShaderComponent createFragmentMaterialComponent(SourceLoader loadChecker) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("uber_material_fragment"))
|
||||
return UberShaderComponent.builder(Flywheel.rl("material_fragment"))
|
||||
.materialSources(ShaderIndices.materialFragment()
|
||||
.all())
|
||||
.adapt(FnSignature.ofVoid("flw_materialFragment"))
|
||||
@ -87,7 +87,7 @@ public final class FlwPrograms {
|
||||
|
||||
@Nullable
|
||||
private static UberShaderComponent createFogComponent(SourceLoader loadChecker) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("uber_fog"))
|
||||
return UberShaderComponent.builder(Flywheel.rl("fog"))
|
||||
.materialSources(ShaderIndices.fog()
|
||||
.all())
|
||||
.adapt(FnSignature.create()
|
||||
@ -101,7 +101,7 @@ public final class FlwPrograms {
|
||||
|
||||
@Nullable
|
||||
private static UberShaderComponent createCutoutComponent(SourceLoader loadChecker) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("uber_cutout"))
|
||||
return UberShaderComponent.builder(Flywheel.rl("cutout"))
|
||||
.materialSources(ShaderIndices.cutout()
|
||||
.all())
|
||||
.adapt(FnSignature.create()
|
||||
|
@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.backend.compile.component.IndirectComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.StructInstanceComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.core.CompilationHarness;
|
||||
import com.jozufozu.flywheel.backend.compile.core.Compile;
|
||||
import com.jozufozu.flywheel.backend.gl.GlCompat;
|
||||
@ -78,7 +78,7 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||
.nameMapper(instanceType -> "culling/" + ResourceUtil.toDebugFileNameNoExtension(instanceType.cullShader()))
|
||||
.define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
|
||||
.withResource(CULL_SHADER_HEADER)
|
||||
.withComponent(IndirectComponent::create)
|
||||
.withComponent(StructInstanceComponent::create)
|
||||
.withResource(InstanceType::cullShader)
|
||||
.withResource(CULL_SHADER_MAIN))
|
||||
.postLink((key, program) -> program.setUniformBlockBinding("_FlwFrameUniforms", 0))
|
||||
|
@ -2,8 +2,8 @@ package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.Samplers;
|
||||
import com.jozufozu.flywheel.backend.compile.component.IndirectComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.SamplerBufferComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.BufferTextureInstanceComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.StructInstanceComponent;
|
||||
import com.jozufozu.flywheel.backend.glsl.GlslVersion;
|
||||
|
||||
public final class Pipelines {
|
||||
@ -14,7 +14,7 @@ public final class Pipelines {
|
||||
.fragmentMain(Flywheel.rl("internal/instancing/main.frag"))
|
||||
.vertexApiImpl(Flywheel.rl("internal/instancing/api_impl.vert"))
|
||||
.fragmentApiImpl(Flywheel.rl("internal/instancing/api_impl.frag"))
|
||||
.assembler(SamplerBufferComponent::create)
|
||||
.assembler(BufferTextureInstanceComponent::create)
|
||||
.onLink(program -> program.setSamplerBinding("_flw_instances", Samplers.INSTANCE_BUFFER))
|
||||
.build();
|
||||
public static final Pipeline INDIRECT = Pipeline.builder()
|
||||
@ -24,7 +24,7 @@ public final class Pipelines {
|
||||
.fragmentMain(Flywheel.rl("internal/indirect/main.frag"))
|
||||
.vertexApiImpl(Flywheel.rl("internal/indirect/api_impl.vert"))
|
||||
.fragmentApiImpl(Flywheel.rl("internal/indirect/api_impl.frag"))
|
||||
.assembler(IndirectComponent::create)
|
||||
.assembler(StructInstanceComponent::create)
|
||||
.onLink($ -> {
|
||||
})
|
||||
.build();
|
||||
|
@ -0,0 +1,292 @@
|
||||
package com.jozufozu.flywheel.backend.compile.component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.layout.FloatRepr;
|
||||
import com.jozufozu.flywheel.api.layout.IntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.Layout;
|
||||
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;
|
||||
import com.jozufozu.flywheel.backend.compile.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBlock;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslStmt;
|
||||
import com.jozufozu.flywheel.lib.math.MoreMath;
|
||||
|
||||
public class BufferTextureInstanceComponent extends InstanceAssemblerComponent {
|
||||
private static final String UNPACK_ARG = "index";
|
||||
|
||||
private static final String[] SWIZZLE_SELECTORS = { "x", "y", "z", "w" };
|
||||
|
||||
// Each function receives a uint expression as the input.
|
||||
// For byte unpacking, the lowest 8 bits contain the value. For short unpacking, the lowest 16 bits contain the value.
|
||||
// In both cases, all other bits are 0.
|
||||
private static final EnumMap<IntegerRepr, Function<GlslExpr, GlslExpr>> INT_UNPACKING_FUNCS = new EnumMap<>(IntegerRepr.class);
|
||||
private static final EnumMap<UnsignedIntegerRepr, Function<GlslExpr, GlslExpr>> UINT_UNPACKING_FUNCS = new EnumMap<>(UnsignedIntegerRepr.class);
|
||||
private static final EnumMap<FloatRepr, Function<GlslExpr, GlslExpr>> FLOAT_UNPACKING_FUNCS = new EnumMap<>(FloatRepr.class);
|
||||
|
||||
static {
|
||||
INT_UNPACKING_FUNCS.put(IntegerRepr.BYTE, e -> signExtendByte(e).cast("int"));
|
||||
INT_UNPACKING_FUNCS.put(IntegerRepr.SHORT, e -> signExtendShort(e).cast("int"));
|
||||
INT_UNPACKING_FUNCS.put(IntegerRepr.INT, e -> e.cast("int"));
|
||||
|
||||
UINT_UNPACKING_FUNCS.put(UnsignedIntegerRepr.UNSIGNED_BYTE, Function.identity());
|
||||
UINT_UNPACKING_FUNCS.put(UnsignedIntegerRepr.UNSIGNED_SHORT, Function.identity());
|
||||
UINT_UNPACKING_FUNCS.put(UnsignedIntegerRepr.UNSIGNED_INT, Function.identity());
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.BYTE, e -> signExtendByte(e).cast("int").cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_BYTE, e -> signExtendByte(e).cast("int").cast("float").div(127f).clamp(-1, 1));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.UNSIGNED_BYTE, e -> e.cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_UNSIGNED_BYTE, e -> e.cast("float").div(255f));
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.SHORT, e -> signExtendShort(e).cast("int").cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_SHORT, e -> signExtendShort(e).cast("int").cast("float").div(32767f).clamp(-1, 1));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.UNSIGNED_SHORT, e -> e.cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_UNSIGNED_SHORT, e -> e.cast("float").div(65535f));
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.INT, e -> e.cast("int").cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_INT, e -> e.cast("int").cast("float").div(2147483647f).clamp(-1, 1));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.UNSIGNED_INT, e -> e.cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_UNSIGNED_INT, e -> e.cast("float").div(4294967295f));
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.FLOAT, e -> e.callFunction("uintBitsToFloat")); // FIXME: GLSL 330+
|
||||
}
|
||||
|
||||
public BufferTextureInstanceComponent(InstanceType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
public static BufferTextureInstanceComponent create(InstanceType<?> type) {
|
||||
return new BufferTextureInstanceComponent(type);
|
||||
}
|
||||
|
||||
public static BufferTextureInstanceComponent create(Pipeline.InstanceAssemblerContext ctx) {
|
||||
return create(ctx.instanceType());
|
||||
}
|
||||
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
|
||||
// Assumes bits higher than sign bit are zero
|
||||
private static GlslExpr signExtendByte(GlslExpr e) {
|
||||
return e.xor(0x80).sub(0x80);
|
||||
}
|
||||
|
||||
private static GlslExpr signExtendShort(GlslExpr e) {
|
||||
return e.xor(0x8000).sub(0x8000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return Flywheel.rl("buffer_texture_instance_assembler").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateUnpacking(GlslBuilder builder) {
|
||||
var block = new GlslBlock();
|
||||
|
||||
// TODO: don't require writing to be 16 byte aligned
|
||||
var texels = MoreMath.ceilingDiv(layout.byteSize(), 16);
|
||||
|
||||
block.add(GlslStmt.raw("int base = " + UNPACK_ARG + " * " + texels + ";"));
|
||||
|
||||
for (int i = 0; i < texels; i++) {
|
||||
// Fetch all the texels for the given instance ahead of time to simplify the unpacking generators.
|
||||
block.add(GlslStmt.raw("uvec4 u" + i + " = texelFetch(_flw_instances, base + " + i + ");"));
|
||||
}
|
||||
|
||||
var unpackArgs = new ArrayList<GlslExpr>();
|
||||
int uintOffset = 0;
|
||||
for (Layout.Element element : layout.elements()) {
|
||||
unpackArgs.add(unpackElement(element, uintOffset));
|
||||
// Element byte size is always a multiple of 4
|
||||
uintOffset += element.type().byteSize() / 4;
|
||||
}
|
||||
|
||||
block.ret(GlslExpr.call(STRUCT_NAME, unpackArgs));
|
||||
|
||||
builder._addRaw("uniform usamplerBuffer _flw_instances;");
|
||||
builder.blankLine();
|
||||
builder.function()
|
||||
.signature(FnSignature.create()
|
||||
.returnType(STRUCT_NAME)
|
||||
.name(UNPACK_FN_NAME)
|
||||
.arg("int", UNPACK_ARG)
|
||||
.build())
|
||||
.body(block);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackElement(Layout.Element element, int uintOffset) {
|
||||
var type = element.type();
|
||||
|
||||
if (type instanceof ScalarElementType scalar) {
|
||||
return unpackScalar(scalar, uintOffset);
|
||||
} else if (type instanceof VectorElementType vector) {
|
||||
return unpackVector(vector, uintOffset);
|
||||
} else if (type instanceof MatrixElementType matrix) {
|
||||
return unpackMatrix(matrix, uintOffset);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown type " + type);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(ScalarElementType type, int uintOffset) {
|
||||
var repr = type.repr();
|
||||
Function<GlslExpr, GlslExpr> unpackingFunc;
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
unpackingFunc = INT_UNPACKING_FUNCS.get(intRepr);
|
||||
} else if (repr instanceof UnsignedIntegerRepr uintRepr) {
|
||||
unpackingFunc = UINT_UNPACKING_FUNCS.get(uintRepr);
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
unpackingFunc = FLOAT_UNPACKING_FUNCS.get(floatRepr);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
if (isByteBacked(repr)) {
|
||||
return unpackByteBackedScalar(uintOffset, unpackingFunc);
|
||||
} else if (isShortBacked(repr)) {
|
||||
return unpackShortBackedScalar(uintOffset, unpackingFunc);
|
||||
} else {
|
||||
return unpackIntBackedScalar(uintOffset, unpackingFunc);
|
||||
}
|
||||
}
|
||||
|
||||
private static GlslExpr unpackVector(VectorElementType type, int uintOffset) {
|
||||
var repr = type.repr();
|
||||
int size = type.size();
|
||||
Function<GlslExpr, GlslExpr> unpackingFunc;
|
||||
String outType;
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
unpackingFunc = INT_UNPACKING_FUNCS.get(intRepr);
|
||||
outType = "ivec" + size;
|
||||
} else if (repr instanceof UnsignedIntegerRepr uintRepr) {
|
||||
unpackingFunc = UINT_UNPACKING_FUNCS.get(uintRepr);
|
||||
outType = "uvec" + size;
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
unpackingFunc = FLOAT_UNPACKING_FUNCS.get(floatRepr);
|
||||
outType = "vec" + size;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
if (isByteBacked(repr)) {
|
||||
return unpackByteBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else if (isShortBacked(repr)) {
|
||||
return unpackShortBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else {
|
||||
return unpackIntBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
}
|
||||
}
|
||||
|
||||
private static GlslExpr unpackMatrix(MatrixElementType type, int uintOffset) {
|
||||
var repr = type.repr();
|
||||
int rows = type.rows();
|
||||
int columns = type.columns();
|
||||
Function<GlslExpr, GlslExpr> unpackingFunc = FLOAT_UNPACKING_FUNCS.get(repr);
|
||||
String outType = "mat" + columns + "x" + rows;
|
||||
int size = rows * columns;
|
||||
|
||||
if (isByteBacked(repr)) {
|
||||
return unpackByteBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else if (isShortBacked(repr)) {
|
||||
return unpackShortBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else {
|
||||
return unpackIntBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isByteBacked(ValueRepr repr) {
|
||||
return repr.byteSize() == Byte.BYTES;
|
||||
}
|
||||
|
||||
private static boolean isShortBacked(ValueRepr repr) {
|
||||
return repr.byteSize() == Short.BYTES;
|
||||
}
|
||||
|
||||
private static GlslExpr unpackByteBackedScalar(int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
GlslExpr e;
|
||||
if (BIG_ENDIAN) {
|
||||
e = access(uintOffset)
|
||||
.rsh(24)
|
||||
.and(0xFF);
|
||||
} else {
|
||||
e = access(uintOffset)
|
||||
.and(0xFF);
|
||||
}
|
||||
return perElement.apply(e);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackShortBackedScalar(int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
GlslExpr e;
|
||||
if (BIG_ENDIAN) {
|
||||
e = access(uintOffset)
|
||||
.rsh(16)
|
||||
.and(0xFFFF);
|
||||
} else {
|
||||
e = access(uintOffset)
|
||||
.and(0xFFFF);
|
||||
}
|
||||
return perElement.apply(e);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntBackedScalar(int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
return perElement.apply(access(uintOffset));
|
||||
}
|
||||
|
||||
private static GlslExpr unpackByteBackedVector(String outType, int size, int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
// Vectors cannot contain more than 4 elements, but matrix unpacking treats the matrix as a long vector, which for mat4x4 would be the equivalent of a vec16.
|
||||
int bitPos = (i % 4) * 8;
|
||||
if (BIG_ENDIAN) {
|
||||
bitPos = 24 - bitPos;
|
||||
}
|
||||
int wordOffset = i / 4;
|
||||
var element = access(uintOffset + wordOffset)
|
||||
.rsh(bitPos)
|
||||
.and(0xFF);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackShortBackedVector(String outType, int size, int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int bitPos = (i % 2) * 16;
|
||||
if (BIG_ENDIAN) {
|
||||
bitPos = 16 - bitPos;
|
||||
}
|
||||
int wordOffset = i / 2;
|
||||
var element = access(uintOffset + wordOffset)
|
||||
.rsh(bitPos)
|
||||
.and(0xFFFF);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntBackedVector(String outType, int size, int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
args.add(perElement.apply(access(uintOffset + i)));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr access(int uintOffset) {
|
||||
return GlslExpr.variable("u" + (uintOffset >> 2))
|
||||
.swizzle(SWIZZLE_SELECTORS[uintOffset & 3]);
|
||||
}
|
||||
}
|
@ -1,349 +0,0 @@
|
||||
package com.jozufozu.flywheel.backend.compile.component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.layout.FloatRepr;
|
||||
import com.jozufozu.flywheel.api.layout.IntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.Layout;
|
||||
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.VectorElementType;
|
||||
import com.jozufozu.flywheel.backend.compile.LayoutInterpreter;
|
||||
import com.jozufozu.flywheel.backend.compile.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBlock;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslStruct;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class IndirectComponent implements SourceComponent {
|
||||
private static final String UNPACK_ARG = "p";
|
||||
private static final GlslExpr.Variable UNPACKING_VARIABLE = GlslExpr.variable(UNPACK_ARG);
|
||||
private static final String STRUCT_NAME = "FlwInstance";
|
||||
private static final String PACKED_STRUCT_NAME = "FlwPackedInstance";
|
||||
private static final String UNPACK_FN_NAME = "_flw_unpackInstance";
|
||||
|
||||
private final Layout layout;
|
||||
|
||||
public IndirectComponent(InstanceType<?> type) {
|
||||
this.layout = type.layout();
|
||||
}
|
||||
|
||||
public static IndirectComponent create(Pipeline.InstanceAssemblerContext ctx) {
|
||||
return create(ctx.instanceType());
|
||||
}
|
||||
|
||||
public static IndirectComponent create(InstanceType<?> instanceType) {
|
||||
return new IndirectComponent(instanceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation name() {
|
||||
return Flywheel.rl("generated_indirect");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String source() {
|
||||
return generateIndirect();
|
||||
}
|
||||
|
||||
public String generateIndirect() {
|
||||
var builder = new GlslBuilder();
|
||||
|
||||
generateInstanceStruct(builder);
|
||||
|
||||
builder.blankLine();
|
||||
|
||||
generateUnpacking(builder);
|
||||
|
||||
builder.blankLine();
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
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<GlslExpr>();
|
||||
|
||||
for (Layout.Element element : layout.elements()) {
|
||||
unpackArgs.add(unpackElement(element, packed));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public static GlslExpr unpackElement(Layout.Element element, GlslStruct packed) {
|
||||
// FIXME: I don't think we're unpacking signed byte/short values correctly
|
||||
// FIXME: we definitely don't consider endianness. this all assumes little endian which works on my machine.
|
||||
var type = element.type();
|
||||
var name = element.name();
|
||||
|
||||
if (type instanceof ScalarElementType scalar) {
|
||||
return unpackScalar(name, packed, scalar);
|
||||
} else if (type instanceof VectorElementType vector) {
|
||||
return unpackVector(name, packed, vector);
|
||||
} else if (type instanceof MatrixElementType matrix) {
|
||||
return unpackMatrix(name, packed, matrix);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown type " + type);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(String fieldName, GlslStruct packed, ScalarElementType scalar) {
|
||||
var repr = scalar.repr();
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
return unpackIntScalar(fieldName, intRepr, packed);
|
||||
} else if (repr instanceof UnsignedIntegerRepr unsignedIntegerRepr) {
|
||||
return unpackUnsignedScalar(fieldName, unsignedIntegerRepr, packed);
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
return unpackFloatScalar(fieldName, floatRepr, packed);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntScalar(String fieldName, IntegerRepr intRepr, GlslStruct packed) {
|
||||
return switch (intRepr) {
|
||||
case BYTE -> unpackScalar(fieldName, packed, "uint", e -> e.and(0xFF)
|
||||
.cast("int"));
|
||||
case SHORT -> unpackScalar(fieldName, packed, "uint", e -> e.and(0xFFFF)
|
||||
.cast("int"));
|
||||
case INT -> unpackScalar(fieldName, packed, "int");
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackUnsignedScalar(String fieldName, UnsignedIntegerRepr repr, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case UNSIGNED_BYTE -> unpackScalar(fieldName, packed, "uint", e -> e.and(0xFF));
|
||||
case UNSIGNED_SHORT -> unpackScalar(fieldName, packed, "uint", e -> e.and(0xFFFF));
|
||||
case UNSIGNED_INT -> unpackScalar(fieldName, packed, "uint");
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackFloatScalar(String fieldName, FloatRepr repr, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackScalar(fieldName, packed, "uint", e -> e.and(0xFF)
|
||||
.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_BYTE -> unpackScalar(fieldName, packed, "uint", e -> e.callFunction("unpackSnorm4x8")
|
||||
.swizzle("x"));
|
||||
case UNSIGNED_BYTE -> unpackScalar(fieldName, packed, "uint", e -> e.and(0xFF)
|
||||
.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_BYTE ->
|
||||
unpackScalar(fieldName, packed, "uint", e -> e.callFunction("unpackUnorm4x8")
|
||||
.swizzle("x"));
|
||||
case SHORT -> unpackScalar(fieldName, packed, "uint", e -> e.and(0xFFFF)
|
||||
.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_SHORT -> unpackScalar(fieldName, packed, "uint", e -> e.callFunction("unpackSnorm2x16")
|
||||
.swizzle("x"));
|
||||
case UNSIGNED_SHORT -> unpackScalar(fieldName, packed, "uint", e -> e.and(0xFFFF)
|
||||
.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_SHORT ->
|
||||
unpackScalar(fieldName, packed, "uint", e -> e.callFunction("unpackUnorm2x16")
|
||||
.swizzle("x"));
|
||||
case INT -> unpackScalar(fieldName, packed, "int", e -> e.cast("float"));
|
||||
case NORMALIZED_INT -> unpackScalar(fieldName, packed, "int", e -> e.div(2147483647f)
|
||||
.clamp(-1, 1));
|
||||
case UNSIGNED_INT -> unpackScalar(fieldName, packed, "uint", e -> e.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_INT -> unpackScalar(fieldName, packed, "uint", e -> e.div(4294967295f));
|
||||
case FLOAT -> unpackScalar(fieldName, packed, "float");
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(String fieldName, GlslStruct packed, String packedType) {
|
||||
return unpackScalar(fieldName, packed, packedType, Function.identity());
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(String fieldName, GlslStruct packed, String packedType, Function<GlslExpr, GlslExpr> perElement) {
|
||||
packed.addField(packedType, fieldName);
|
||||
return perElement.apply(UNPACKING_VARIABLE.access(fieldName));
|
||||
}
|
||||
|
||||
private static GlslExpr unpackVector(String fieldName, GlslStruct packed, VectorElementType vector) {
|
||||
var repr = vector.repr();
|
||||
|
||||
int size = vector.size();
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
return unpackIntVector(fieldName, intRepr, packed, size);
|
||||
} else if (repr instanceof UnsignedIntegerRepr unsignedIntegerRepr) {
|
||||
return unpackUnsignedVector(fieldName, unsignedIntegerRepr, packed, size);
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
return unpackFloatVector(fieldName, floatRepr, packed, size);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntVector(String fieldName, IntegerRepr repr, GlslStruct packed, int size) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackByteBacked(fieldName, packed, size, "ivec" + size, e -> e.cast("int"));
|
||||
case SHORT -> unpackShortBacked(fieldName, packed, size, "ivec" + size, e -> e.cast("int"));
|
||||
case INT -> unpack(fieldName, packed, size, "int", "ivec" + size);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackUnsignedVector(String fieldName, UnsignedIntegerRepr unsignedIntegerRepr, GlslStruct packed, int size) {
|
||||
return switch (unsignedIntegerRepr) {
|
||||
case UNSIGNED_BYTE -> unpackByteBacked(fieldName, packed, size, "uvec" + size, e -> e.cast("uint"));
|
||||
case UNSIGNED_SHORT -> unpackShortBacked(fieldName, packed, size, "uvec" + size, e -> e.cast("uint"));
|
||||
case UNSIGNED_INT -> unpack(fieldName, packed, size, "uint", "uvec" + size);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackFloatVector(String fieldName, FloatRepr floatRepr, GlslStruct packed, int size) {
|
||||
return switch (floatRepr) {
|
||||
case NORMALIZED_BYTE -> unpackByteBuiltin(fieldName, packed, size, "unpackSnorm4x8");
|
||||
case NORMALIZED_UNSIGNED_BYTE -> unpackByteBuiltin(fieldName, packed, size, "unpackUnorm4x8");
|
||||
case NORMALIZED_SHORT -> unpackShortBuiltin(fieldName, packed, size, "unpackSnorm2x16");
|
||||
case NORMALIZED_UNSIGNED_SHORT -> unpackShortBuiltin(fieldName, packed, size, "unpackUnorm2x16");
|
||||
case NORMALIZED_INT -> unpack(fieldName, packed, size, "int", "vec" + size, e -> e.div(2147483647f)
|
||||
.clamp(-1, 1));
|
||||
case NORMALIZED_UNSIGNED_INT ->
|
||||
unpack(fieldName, packed, size, "uint", "vec" + size, e -> e.div(4294967295f));
|
||||
case BYTE -> unpackByteBacked(fieldName, packed, size, "vec" + size, e -> e.cast("int")
|
||||
.cast("float"));
|
||||
case UNSIGNED_BYTE -> unpackByteBacked(fieldName, packed, size, "vec" + size, e -> e.cast("float"));
|
||||
case SHORT -> unpackShortBacked(fieldName, packed, size, "vec" + size, e -> e.cast("int")
|
||||
.cast("float"));
|
||||
case UNSIGNED_SHORT -> unpackShortBacked(fieldName, packed, size, "vec" + size, e -> e.cast("float"));
|
||||
case INT -> unpack(fieldName, packed, size, "int", "vec" + size, e -> e.cast("float"));
|
||||
case UNSIGNED_INT -> unpack(fieldName, packed, size, "float", "vec" + size, e -> e.cast("float"));
|
||||
case FLOAT -> unpack(fieldName, packed, size, "float", "vec" + size);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackByteBacked(String fieldName, GlslStruct packed, int size, String outType, Function<GlslExpr, GlslExpr> perElement) {
|
||||
packed.addField("uint", fieldName);
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int bitPos = i * 8;
|
||||
var element = UNPACKING_VARIABLE.access(fieldName)
|
||||
.and(0xFF << bitPos)
|
||||
.rsh(bitPos);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackShortBacked(String fieldName, GlslStruct packed, int size, String outType, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int unpackField = i / 2;
|
||||
int bitPos = (i % 2) * 16;
|
||||
var name = fieldName + "_" + unpackField;
|
||||
if (bitPos == 0) {
|
||||
// First time we're seeing this field, add it to the struct.
|
||||
packed.addField("uint", name);
|
||||
}
|
||||
var element = UNPACKING_VARIABLE.access(name)
|
||||
.and(0xFFFF << bitPos)
|
||||
.rsh(bitPos);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpack(String fieldName, GlslStruct packed, int size, String backingType, String outType) {
|
||||
return unpack(fieldName, packed, size, backingType, outType, Function.identity());
|
||||
}
|
||||
|
||||
private static GlslExpr unpack(String fieldName, GlslStruct packed, int size, String backingType, String outType, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
var name = fieldName + "_" + i;
|
||||
packed.addField(backingType, name);
|
||||
args.add(UNPACKING_VARIABLE.access(name)
|
||||
.transform(perElement));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackByteBuiltin(String fieldName, GlslStruct packed, int size, String func) {
|
||||
packed.addField("uint", fieldName);
|
||||
GlslExpr expr = UNPACKING_VARIABLE.access(fieldName)
|
||||
.callFunction(func);
|
||||
return switch (size) {
|
||||
case 2 -> expr.swizzle("xy");
|
||||
case 3 -> expr.swizzle("xyz");
|
||||
case 4 -> expr;
|
||||
default -> throw new IllegalArgumentException("Invalid vector size " + size);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackShortBuiltin(String fieldName, GlslStruct packed, int size, String func) {
|
||||
if (size == 2) {
|
||||
packed.addField("uint", fieldName);
|
||||
return UNPACKING_VARIABLE.access(fieldName)
|
||||
.callFunction(func);
|
||||
} else {
|
||||
var name0 = fieldName + "_" + 0;
|
||||
var name1 = fieldName + "_" + 1;
|
||||
packed.addField("uint", name0);
|
||||
packed.addField("uint", name1);
|
||||
GlslExpr xy = UNPACKING_VARIABLE.access(name0)
|
||||
.callFunction(func);
|
||||
|
||||
GlslExpr zw = UNPACKING_VARIABLE.access(name1)
|
||||
.callFunction(func);
|
||||
|
||||
if (size == 3) {
|
||||
return GlslExpr.call("vec3", List.of(xy.swizzle("xy"), zw.swizzle("x")));
|
||||
} else {
|
||||
return GlslExpr.call("vec4", List.of(xy, zw));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static GlslExpr unpackMatrix(String name, GlslStruct packed, MatrixElementType matrix) {
|
||||
var repr = matrix.repr();
|
||||
|
||||
int rows = matrix.rows();
|
||||
int columns = matrix.columns();
|
||||
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < columns; i++) {
|
||||
args.add(unpackFloatVector(name + "_" + i, repr, packed, rows));
|
||||
}
|
||||
|
||||
return GlslExpr.call("mat" + columns + "x" + rows, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.jozufozu.flywheel.backend.compile.component;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
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.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder;
|
||||
|
||||
public abstract class InstanceAssemblerComponent implements SourceComponent {
|
||||
protected static final String STRUCT_NAME = "FlwInstance";
|
||||
protected static final String UNPACK_FN_NAME = "_flw_unpackInstance";
|
||||
|
||||
protected static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
||||
|
||||
protected final Layout layout;
|
||||
|
||||
public InstanceAssemblerComponent(InstanceType<?> type) {
|
||||
layout = type.layout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String source() {
|
||||
var builder = new GlslBuilder();
|
||||
generateInstanceStruct(builder);
|
||||
builder.blankLine();
|
||||
generateUnpacking(builder);
|
||||
builder.blankLine();
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
protected 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());
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void generateUnpacking(GlslBuilder builder);
|
||||
}
|
@ -1,322 +0,0 @@
|
||||
package com.jozufozu.flywheel.backend.compile.component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.layout.FloatRepr;
|
||||
import com.jozufozu.flywheel.api.layout.IntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.Layout;
|
||||
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.VectorElementType;
|
||||
import com.jozufozu.flywheel.backend.compile.LayoutInterpreter;
|
||||
import com.jozufozu.flywheel.backend.compile.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBlock;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslStmt;
|
||||
import com.jozufozu.flywheel.lib.math.MoreMath;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class SamplerBufferComponent implements SourceComponent {
|
||||
private static final String STRUCT_NAME = "FlwInstance";
|
||||
private static final String UNPACK_FN_NAME = "_flw_unpackInstance";
|
||||
private static final String UNPACK_ARG = "index";
|
||||
|
||||
private final Layout layout;
|
||||
|
||||
public SamplerBufferComponent(InstanceType<?> type) {
|
||||
this.layout = type.layout();
|
||||
}
|
||||
|
||||
public static SamplerBufferComponent create(Pipeline.InstanceAssemblerContext ctx) {
|
||||
return create(ctx.instanceType());
|
||||
}
|
||||
|
||||
public static SamplerBufferComponent create(InstanceType<?> instanceType) {
|
||||
return new SamplerBufferComponent(instanceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation name() {
|
||||
return Flywheel.rl("generated_instancing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String source() {
|
||||
return generateIndirect();
|
||||
}
|
||||
|
||||
public String generateIndirect() {
|
||||
var builder = new GlslBuilder();
|
||||
|
||||
generateInstanceStruct(builder);
|
||||
|
||||
builder.blankLine();
|
||||
|
||||
builder._addRaw("uniform usamplerBuffer _flw_instances;");
|
||||
|
||||
builder.blankLine();
|
||||
|
||||
generateUnpacking(builder);
|
||||
|
||||
builder.blankLine();
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
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 block = new GlslBlock();
|
||||
|
||||
var texels = MoreMath.ceilingDiv(layout.byteSize(), 16);
|
||||
|
||||
block.add(GlslStmt.raw("int base = " + UNPACK_ARG + " * " + texels + ";"));
|
||||
|
||||
for (int i = 0; i < texels; i++) {
|
||||
// Fetch all the texels for the given instance ahead of time to simplify the unpacking generators.
|
||||
block.add(GlslStmt.raw("uvec4 u" + i + " = texelFetch(_flw_instances, base + " + i + ");"));
|
||||
}
|
||||
|
||||
var unpackArgs = new ArrayList<GlslExpr>();
|
||||
int uintOffset = 0;
|
||||
for (Layout.Element element : layout.elements()) {
|
||||
unpackArgs.add(unpackElement(element, uintOffset));
|
||||
uintOffset += MoreMath.ceilingDiv(element.type().byteSize(), 4);
|
||||
}
|
||||
|
||||
block.ret(GlslExpr.call(STRUCT_NAME, unpackArgs));
|
||||
|
||||
builder.function()
|
||||
.signature(FnSignature.create()
|
||||
.returnType(STRUCT_NAME)
|
||||
.name(UNPACK_FN_NAME)
|
||||
.arg("int", UNPACK_ARG)
|
||||
.build())
|
||||
.body(block);
|
||||
}
|
||||
|
||||
public static GlslExpr access(int uintOffset) {
|
||||
return GlslExpr.variable("u" + (uintOffset >> 2))
|
||||
.swizzle(String.valueOf("xyzw".charAt(uintOffset & 3)));
|
||||
}
|
||||
|
||||
// TODO: deduplicate this with IndirectComponent somehow?
|
||||
|
||||
public static GlslExpr unpackElement(Layout.Element element, int uintOffset) {
|
||||
// FIXME: I don't think we're unpacking signed byte/short values correctly
|
||||
// FIXME: we definitely don't consider endianness. this all assumes little endian which works on my machine.
|
||||
var type = element.type();
|
||||
|
||||
if (type instanceof ScalarElementType scalar) {
|
||||
return unpackScalar(uintOffset, scalar);
|
||||
} else if (type instanceof VectorElementType vector) {
|
||||
return unpackVector(uintOffset, vector);
|
||||
} else if (type instanceof MatrixElementType matrix) {
|
||||
return unpackMatrix(uintOffset, matrix);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown type " + type);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(int uintOffset, ScalarElementType scalar) {
|
||||
var repr = scalar.repr();
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
return unpackIntScalar(uintOffset, intRepr);
|
||||
} else if (repr instanceof UnsignedIntegerRepr unsignedIntegerRepr) {
|
||||
return unpackUnsignedScalar(uintOffset, unsignedIntegerRepr);
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
return unpackFloatScalar(uintOffset, floatRepr);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntScalar(int uintOffset, IntegerRepr intRepr) {
|
||||
return switch (intRepr) {
|
||||
case BYTE -> unpackScalar(uintOffset, e -> e.and(0xFF)
|
||||
.cast("int"));
|
||||
case SHORT -> unpackScalar(uintOffset, e -> e.and(0xFFFF)
|
||||
.cast("int"));
|
||||
case INT -> unpackScalar(uintOffset);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackUnsignedScalar(int uintOffset, UnsignedIntegerRepr repr) {
|
||||
return switch (repr) {
|
||||
case UNSIGNED_BYTE -> unpackScalar(uintOffset, e -> e.and(0xFF));
|
||||
case UNSIGNED_SHORT -> unpackScalar(uintOffset, e -> e.and(0xFFFF));
|
||||
case UNSIGNED_INT -> unpackScalar(uintOffset);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackFloatScalar(int uintOffset, FloatRepr repr) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackScalar(uintOffset, e -> e.and(0xFF)
|
||||
.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_BYTE -> unpackScalar(uintOffset, e -> e.callFunction("unpackSnorm4x8")
|
||||
.swizzle("x"));
|
||||
case UNSIGNED_BYTE -> unpackScalar(uintOffset, e -> e.and(0xFF)
|
||||
.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_BYTE ->
|
||||
unpackScalar(uintOffset, e -> e.callFunction("unpackUnorm4x8")
|
||||
.swizzle("x"));
|
||||
case SHORT -> unpackScalar(uintOffset, e -> e.and(0xFFFF)
|
||||
.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_SHORT -> unpackScalar(uintOffset, e -> e.callFunction("unpackSnorm2x16")
|
||||
.swizzle("x"));
|
||||
case UNSIGNED_SHORT -> unpackScalar(uintOffset, e -> e.and(0xFFFF)
|
||||
.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_SHORT ->
|
||||
unpackScalar(uintOffset, e -> e.callFunction("unpackUnorm2x16")
|
||||
.swizzle("x"));
|
||||
case INT -> unpackScalar(uintOffset, e -> e.cast("int").cast("float"));
|
||||
case NORMALIZED_INT -> unpackScalar(uintOffset, e -> e.div(2147483647f)
|
||||
.clamp(-1, 1));
|
||||
case UNSIGNED_INT -> unpackScalar(uintOffset, e -> e.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_INT -> unpackScalar(uintOffset, e -> e.div(4294967295f));
|
||||
case FLOAT -> unpackScalar(uintOffset, e -> e.callFunction("uintBitsToFloat"));
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(int uintOffset) {
|
||||
return unpackScalar(uintOffset, Function.identity());
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
return perElement.apply(access(uintOffset));
|
||||
}
|
||||
|
||||
private static GlslExpr unpackVector(int uintOffset, VectorElementType vector) {
|
||||
var repr = vector.repr();
|
||||
|
||||
int size = vector.size();
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
return unpackIntVector(uintOffset, intRepr, size);
|
||||
} else if (repr instanceof UnsignedIntegerRepr unsignedIntegerRepr) {
|
||||
return unpackUnsignedVector(uintOffset, unsignedIntegerRepr, size);
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
return unpackFloatVector(uintOffset, floatRepr, size);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntVector(int uintOffset, IntegerRepr repr, int size) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackByteBacked(uintOffset, size, "ivec" + size, e -> e.cast("int"));
|
||||
case SHORT -> unpackShortBacked(uintOffset, size, "ivec" + size, e -> e.cast("int"));
|
||||
case INT -> unpack(uintOffset, size, "ivec" + size);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackUnsignedVector(int uintOffset, UnsignedIntegerRepr unsignedIntegerRepr, int size) {
|
||||
return switch (unsignedIntegerRepr) {
|
||||
case UNSIGNED_BYTE -> unpackByteBacked(uintOffset, size, "uvec" + size, Function.identity());
|
||||
case UNSIGNED_SHORT -> unpackShortBacked(uintOffset, size, "uvec" + size, Function.identity());
|
||||
case UNSIGNED_INT -> unpack(uintOffset, size, "uvec" + size);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackFloatVector(int uintOffset, FloatRepr floatRepr, int size) {
|
||||
return switch (floatRepr) {
|
||||
case NORMALIZED_BYTE -> unpackByteBacked(uintOffset, size, "vec" + size, e -> e.div(127).clamp(-1, 1));
|
||||
case NORMALIZED_UNSIGNED_BYTE -> unpackByteBacked(uintOffset, size, "vec" + size, e -> e.div(255));
|
||||
case NORMALIZED_SHORT -> unpackShortBacked(uintOffset, size, "vec" + size, e -> e.div(32727).clamp(-1, 1));
|
||||
case NORMALIZED_UNSIGNED_SHORT -> unpackShortBacked(uintOffset, size, "vec" + size, e -> e.div(65535));
|
||||
case NORMALIZED_INT -> unpack(uintOffset, size, "vec" + size, e -> e.div(2147483647f)
|
||||
.clamp(-1, 1));
|
||||
case NORMALIZED_UNSIGNED_INT ->
|
||||
unpack(uintOffset, size, "vec" + size, e -> e.div(4294967295f));
|
||||
case BYTE -> unpackByteBacked(uintOffset, size, "vec" + size, e -> e.cast("int")
|
||||
.cast("float"));
|
||||
case UNSIGNED_BYTE -> unpackByteBacked(uintOffset, size, "vec" + size, e -> e.cast("float"));
|
||||
case SHORT -> unpackShortBacked(uintOffset, size, "vec" + size, e -> e.cast("int")
|
||||
.cast("float"));
|
||||
case UNSIGNED_SHORT -> unpackShortBacked(uintOffset, size, "vec" + size, e -> e.cast("float"));
|
||||
case INT -> unpack(uintOffset, size, "vec" + size, e -> e.cast("float"));
|
||||
case UNSIGNED_INT -> unpack(uintOffset, size, "vec" + size, e -> e.cast("int").cast("float"));
|
||||
case FLOAT -> unpack(uintOffset, size, "vec" + size, e -> e.callFunction("uintBitsToFloat"));
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackByteBacked(int uintOffset, int size, String outType, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int bitPos = i * 8;
|
||||
var element = access(uintOffset)
|
||||
.and(0xFF << bitPos)
|
||||
.rsh(bitPos);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackShortBacked(int uintOffset, int size, String outType, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int bitPos = (i % 2) * 16;
|
||||
int wordOffset = i / 2;
|
||||
var element = access(uintOffset + wordOffset)
|
||||
.and(0xFFFF << bitPos)
|
||||
.rsh(bitPos);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpack(int uintOffset, int size, String outType) {
|
||||
return unpack(uintOffset, size, outType, Function.identity());
|
||||
}
|
||||
|
||||
private static GlslExpr unpack(int uintOffset, int size, String outType, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
args.add(access(uintOffset + i)
|
||||
.transform(perElement));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackMatrix(int uintOffset, MatrixElementType matrix) {
|
||||
var repr = matrix.repr();
|
||||
|
||||
int rows = matrix.rows();
|
||||
int columns = matrix.columns();
|
||||
|
||||
int columnWordSize = MoreMath.ceilingDiv(rows * repr.byteSize(), 4);
|
||||
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < columns; i++) {
|
||||
args.add(unpackFloatVector(uintOffset + i * columnWordSize, repr, rows));
|
||||
}
|
||||
|
||||
return GlslExpr.call("mat" + columns + "x" + rows, args);
|
||||
}
|
||||
}
|
@ -3,20 +3,19 @@ package com.jozufozu.flywheel.backend.compile.component;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public final class StringSubstitutionSourceComponent implements SourceComponent {
|
||||
public final class StringSubstitutionComponent implements SourceComponent {
|
||||
private final SourceComponent source;
|
||||
private final Map<String, String> replacements;
|
||||
private final String sourceString;
|
||||
|
||||
public StringSubstitutionSourceComponent(SourceComponent source, String find, String replace) {
|
||||
public StringSubstitutionComponent(SourceComponent source, String find, String replace) {
|
||||
this(source, Map.of(find, replace));
|
||||
}
|
||||
|
||||
public StringSubstitutionSourceComponent(SourceComponent source, Map<String, String> replacements) {
|
||||
public StringSubstitutionComponent(SourceComponent source, Map<String, String> replacements) {
|
||||
this.source = source;
|
||||
this.replacements = replacements;
|
||||
this.sourceString = source.source();
|
||||
@ -42,8 +41,8 @@ public final class StringSubstitutionSourceComponent implements SourceComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation name() {
|
||||
return source.name().withSuffix("_string_substitution");
|
||||
public String name() {
|
||||
return Flywheel.rl("string_substitution").toString() + " / " + source.name();
|
||||
}
|
||||
|
||||
@Override
|
@ -0,0 +1,308 @@
|
||||
package com.jozufozu.flywheel.backend.compile.component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.layout.FloatRepr;
|
||||
import com.jozufozu.flywheel.api.layout.IntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.Layout;
|
||||
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.VectorElementType;
|
||||
import com.jozufozu.flywheel.backend.compile.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBlock;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslStruct;
|
||||
|
||||
// TODO: Use a uvec4[] instead of a FlwPackedInstance[] in the SSBO to store data and reuse unpacking code from BufferTextureInstanceComponent.
|
||||
// Unpacking should be moved from BufferTextureInstanceComponent to InstanceAssemblerComponent and this class should be renamed to SsboInstanceComponent. Further abstraction may be possible.
|
||||
// Currently, some of the unpacking code generated by this class is incorrect. It is correct in BufferTextureInstanceComponent.
|
||||
public class StructInstanceComponent extends InstanceAssemblerComponent {
|
||||
private static final String UNPACK_ARG = "p";
|
||||
private static final GlslExpr.Variable UNPACKING_VARIABLE = GlslExpr.variable(UNPACK_ARG);
|
||||
private static final String PACKED_STRUCT_NAME = "FlwPackedInstance";
|
||||
|
||||
public StructInstanceComponent(InstanceType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
public static StructInstanceComponent create(InstanceType<?> type) {
|
||||
return new StructInstanceComponent(type);
|
||||
}
|
||||
|
||||
public static StructInstanceComponent create(Pipeline.InstanceAssemblerContext ctx) {
|
||||
return create(ctx.instanceType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return Flywheel.rl("struct_instance_assembler").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateUnpacking(GlslBuilder builder) {
|
||||
var packed = builder.struct();
|
||||
packed.setName(PACKED_STRUCT_NAME);
|
||||
|
||||
var unpackArgs = new ArrayList<GlslExpr>();
|
||||
|
||||
for (Layout.Element element : layout.elements()) {
|
||||
unpackArgs.add(unpackElement(element, packed));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackElement(Layout.Element element, GlslStruct packed) {
|
||||
// FIXME: I don't think we're unpacking signed byte/short values correctly
|
||||
// FIXME: we definitely don't consider endianness. this all assumes little endian which works on my machine.
|
||||
var type = element.type();
|
||||
var name = element.name();
|
||||
|
||||
if (type instanceof ScalarElementType scalar) {
|
||||
return unpackScalar(scalar, name, packed);
|
||||
} else if (type instanceof VectorElementType vector) {
|
||||
return unpackVector(vector, name, packed);
|
||||
} else if (type instanceof MatrixElementType matrix) {
|
||||
return unpackMatrix(matrix, name, packed);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown type " + type);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(ScalarElementType type, String fieldName, GlslStruct packed) {
|
||||
var repr = type.repr();
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
return unpackIntScalar(intRepr, fieldName, packed);
|
||||
} else if (repr instanceof UnsignedIntegerRepr uintRepr) {
|
||||
return unpackUintScalar(uintRepr, fieldName, packed);
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
return unpackFloatScalar(floatRepr, fieldName, packed);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntScalar(IntegerRepr repr, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFF)
|
||||
.cast("int"));
|
||||
case SHORT -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFFFF)
|
||||
.cast("int"));
|
||||
case INT -> unpackScalar("int", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackUintScalar(UnsignedIntegerRepr repr, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case UNSIGNED_BYTE -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFF));
|
||||
case UNSIGNED_SHORT -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFFFF));
|
||||
case UNSIGNED_INT -> unpackScalar("uint", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackFloatScalar(FloatRepr repr, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFF)
|
||||
.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_BYTE -> unpackScalar("uint", fieldName, packed, e -> e.callFunction("unpackSnorm4x8")
|
||||
.swizzle("x"));
|
||||
case UNSIGNED_BYTE -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFF)
|
||||
.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_BYTE ->
|
||||
unpackScalar("uint", fieldName, packed, e -> e.callFunction("unpackUnorm4x8")
|
||||
.swizzle("x"));
|
||||
case SHORT -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFFFF)
|
||||
.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_SHORT -> unpackScalar("uint", fieldName, packed, e -> e.callFunction("unpackSnorm2x16")
|
||||
.swizzle("x"));
|
||||
case UNSIGNED_SHORT -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFFFF)
|
||||
.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_SHORT ->
|
||||
unpackScalar("uint", fieldName, packed, e -> e.callFunction("unpackUnorm2x16")
|
||||
.swizzle("x"));
|
||||
case INT -> unpackScalar("int", fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_INT -> unpackScalar("int", fieldName, packed, e -> e.div(2147483647f)
|
||||
.clamp(-1, 1));
|
||||
case UNSIGNED_INT -> unpackScalar("uint", fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_INT -> unpackScalar("uint", fieldName, packed, e -> e.div(4294967295f));
|
||||
case FLOAT -> unpackScalar("float", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(String packedType, String fieldName, GlslStruct packed) {
|
||||
return unpackScalar(packedType, fieldName, packed, Function.identity());
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(String packedType, String fieldName, GlslStruct packed, Function<GlslExpr, GlslExpr> perElement) {
|
||||
packed.addField(packedType, fieldName);
|
||||
return perElement.apply(UNPACKING_VARIABLE.access(fieldName));
|
||||
}
|
||||
|
||||
private static GlslExpr unpackVector(VectorElementType type, String fieldName, GlslStruct packed) {
|
||||
var repr = type.repr();
|
||||
int size = type.size();
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
return unpackIntVector(intRepr, size, fieldName, packed);
|
||||
} else if (repr instanceof UnsignedIntegerRepr uintRepr) {
|
||||
return unpackUintVector(uintRepr, size, fieldName, packed);
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
return unpackFloatVector(floatRepr, size, fieldName, packed);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntVector(IntegerRepr repr, int size, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackByteBackedVector("ivec" + size, size, fieldName, packed, e -> e.cast("int"));
|
||||
case SHORT -> unpackShortBackedVector("ivec" + size, size, fieldName, packed, e -> e.cast("int"));
|
||||
case INT -> unpackVector("ivec" + size, size, "int", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackUintVector(UnsignedIntegerRepr repr, int size, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case UNSIGNED_BYTE -> unpackByteBackedVector("uvec" + size, size, fieldName, packed, e -> e.cast("uint"));
|
||||
case UNSIGNED_SHORT -> unpackShortBackedVector("uvec" + size, size, fieldName, packed, e -> e.cast("uint"));
|
||||
case UNSIGNED_INT -> unpackVector("uvec" + size, size, "uint", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackFloatVector(FloatRepr repr, int size, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackByteBackedVector("vec" + size, size, fieldName, packed, e -> e.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_BYTE -> unpackByteBuiltinVector(size, fieldName, packed, "unpackSnorm4x8");
|
||||
case UNSIGNED_BYTE -> unpackByteBackedVector("vec" + size, size, fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_BYTE -> unpackByteBuiltinVector(size, fieldName, packed, "unpackUnorm4x8");
|
||||
case SHORT -> unpackShortBackedVector("vec" + size, size, fieldName, packed, e -> e.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_SHORT -> unpackShortBuiltinVector(size, fieldName, packed, "unpackSnorm2x16");
|
||||
case UNSIGNED_SHORT -> unpackShortBackedVector("vec" + size, size, fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_SHORT -> unpackShortBuiltinVector(size, fieldName, packed, "unpackUnorm2x16");
|
||||
case INT -> unpackVector("vec" + size, size, "int", fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_INT -> unpackVector("vec" + size, size, "int", fieldName, packed, e -> e.div(2147483647f)
|
||||
.clamp(-1, 1));
|
||||
case UNSIGNED_INT -> unpackVector("vec" + size, size, "float", fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_INT ->
|
||||
unpackVector("vec" + size, size, "uint", fieldName, packed, e -> e.div(4294967295f));
|
||||
case FLOAT -> unpackVector("vec" + size, size, "float", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackByteBackedVector(String outType, int size, String fieldName, GlslStruct packed, Function<GlslExpr, GlslExpr> perElement) {
|
||||
packed.addField("uint", fieldName);
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int bitPos = i * 8;
|
||||
var element = UNPACKING_VARIABLE.access(fieldName)
|
||||
.rsh(bitPos)
|
||||
.and(0xFF);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackShortBackedVector(String outType, int size, String fieldName, GlslStruct packed, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int unpackField = i / 2;
|
||||
int bitPos = (i % 2) * 16;
|
||||
var name = fieldName + "_" + unpackField;
|
||||
if (bitPos == 0) {
|
||||
// First time we're seeing this field, add it to the struct.
|
||||
packed.addField("uint", name);
|
||||
}
|
||||
var element = UNPACKING_VARIABLE.access(name)
|
||||
.rsh(bitPos)
|
||||
.and(0xFFFF);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackByteBuiltinVector(int size, String fieldName, GlslStruct packed, String func) {
|
||||
packed.addField("uint", fieldName);
|
||||
GlslExpr expr = UNPACKING_VARIABLE.access(fieldName)
|
||||
.callFunction(func);
|
||||
return switch (size) {
|
||||
case 2 -> expr.swizzle("xy");
|
||||
case 3 -> expr.swizzle("xyz");
|
||||
case 4 -> expr;
|
||||
default -> throw new IllegalArgumentException("Invalid vector size " + size);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackShortBuiltinVector(int size, String fieldName, GlslStruct packed, String func) {
|
||||
if (size == 2) {
|
||||
packed.addField("uint", fieldName);
|
||||
return UNPACKING_VARIABLE.access(fieldName)
|
||||
.callFunction(func);
|
||||
} else {
|
||||
var name0 = fieldName + "_" + 0;
|
||||
var name1 = fieldName + "_" + 1;
|
||||
packed.addField("uint", name0);
|
||||
packed.addField("uint", name1);
|
||||
GlslExpr xy = UNPACKING_VARIABLE.access(name0)
|
||||
.callFunction(func);
|
||||
|
||||
GlslExpr zw = UNPACKING_VARIABLE.access(name1)
|
||||
.callFunction(func);
|
||||
|
||||
if (size == 3) {
|
||||
return GlslExpr.call("vec3", List.of(xy.swizzle("xy"), zw.swizzle("x")));
|
||||
} else {
|
||||
return GlslExpr.call("vec4", List.of(xy, zw));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static GlslExpr unpackVector(String outType, int size, String backingType, String fieldName, GlslStruct packed) {
|
||||
return unpackVector(outType, size, backingType, fieldName, packed, Function.identity());
|
||||
}
|
||||
|
||||
private static GlslExpr unpackVector(String outType, int size, String backingType, String fieldName, GlslStruct packed, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
var name = fieldName + "_" + i;
|
||||
packed.addField(backingType, name);
|
||||
args.add(perElement.apply(UNPACKING_VARIABLE.access(name)));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackMatrix(MatrixElementType type, String name, GlslStruct packed) {
|
||||
var repr = type.repr();
|
||||
int rows = type.rows();
|
||||
int columns = type.columns();
|
||||
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < columns; i++) {
|
||||
args.add(unpackFloatVector(repr, rows, name + "_" + i, packed));
|
||||
}
|
||||
|
||||
return GlslExpr.call("mat" + columns + "x" + rows, args);
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.compile.core.SourceLoader;
|
||||
import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.backend.glsl.SourceFile;
|
||||
@ -24,9 +25,9 @@ public class UberShaderComponent implements SourceComponent {
|
||||
private final ResourceLocation name;
|
||||
private final GlslExpr switchArg;
|
||||
private final List<AdaptedFn> functionsToAdapt;
|
||||
private final List<StringSubstitutionSourceComponent> adaptedComponents;
|
||||
private final List<StringSubstitutionComponent> adaptedComponents;
|
||||
|
||||
private UberShaderComponent(ResourceLocation name, GlslExpr switchArg, List<AdaptedFn> functionsToAdapt, List<StringSubstitutionSourceComponent> adaptedComponents) {
|
||||
private UberShaderComponent(ResourceLocation name, GlslExpr switchArg, List<AdaptedFn> functionsToAdapt, List<StringSubstitutionComponent> adaptedComponents) {
|
||||
this.name = name;
|
||||
this.switchArg = switchArg;
|
||||
this.functionsToAdapt = functionsToAdapt;
|
||||
@ -38,8 +39,8 @@ public class UberShaderComponent implements SourceComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation name() {
|
||||
return name;
|
||||
public String name() {
|
||||
return Flywheel.rl("uber_shader").toString() + " / " + name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -141,7 +142,7 @@ public class UberShaderComponent implements SourceComponent {
|
||||
throw new NullPointerException("Switch argument must be set");
|
||||
}
|
||||
|
||||
var transformed = ImmutableList.<StringSubstitutionSourceComponent>builder();
|
||||
var transformed = ImmutableList.<StringSubstitutionComponent>builder();
|
||||
|
||||
boolean errored = false;
|
||||
int index = 0;
|
||||
@ -150,7 +151,7 @@ public class UberShaderComponent implements SourceComponent {
|
||||
final int finalIndex = index;
|
||||
if (sourceFile != null) {
|
||||
var adapterMap = createAdapterMap(adaptedFunctions, fnName -> "_" + fnName + "_" + finalIndex);
|
||||
transformed.add(new StringSubstitutionSourceComponent(sourceFile, adapterMap));
|
||||
transformed.add(new StringSubstitutionComponent(sourceFile, adapterMap));
|
||||
} else {
|
||||
errored = true;
|
||||
}
|
||||
@ -163,7 +164,6 @@ public class UberShaderComponent implements SourceComponent {
|
||||
|
||||
return new UberShaderComponent(name, switchArg, adaptedFunctions, transformed.build());
|
||||
}
|
||||
}
|
||||
|
||||
private static ImmutableMap<String, String> createAdapterMap(List<AdaptedFn> adaptedFunctions, UnaryOperator<String> nameAdapter) {
|
||||
ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
|
||||
@ -176,4 +176,5 @@ public class UberShaderComponent implements SourceComponent {
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ public class Compilation {
|
||||
fullSource.append("\n#line 0 ")
|
||||
.append(fileId)
|
||||
.append(" // ")
|
||||
.append(file.name)
|
||||
.append(file.name())
|
||||
.append('\n');
|
||||
} else {
|
||||
// Add extra newline to keep line numbers consistent
|
||||
|
@ -2,12 +2,10 @@ package com.jozufozu.flywheel.backend.glsl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface SourceComponent {
|
||||
Collection<? extends SourceComponent> included();
|
||||
|
||||
String source();
|
||||
|
||||
ResourceLocation name();
|
||||
String name();
|
||||
}
|
||||
|
@ -125,8 +125,8 @@ public class SourceFile implements SourceComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation name() {
|
||||
return name;
|
||||
public String name() {
|
||||
return name.toString();
|
||||
}
|
||||
|
||||
public Span getLineSpan(int lineNo) {
|
||||
|
@ -1,9 +1,11 @@
|
||||
package com.jozufozu.flywheel.backend.glsl.generate;
|
||||
|
||||
public enum BinOp {
|
||||
BITWISE_AND("&"),
|
||||
RIGHT_SHIFT(">>"),
|
||||
DIVIDE("/"),
|
||||
SUBTRACT("-"),
|
||||
RIGHT_SHIFT(">>"),
|
||||
BITWISE_AND("&"),
|
||||
BITWISE_XOR("^"),
|
||||
// TODO: add more as we need them
|
||||
;
|
||||
|
||||
|
@ -95,8 +95,12 @@ public interface GlslExpr {
|
||||
return f.apply(this);
|
||||
}
|
||||
|
||||
default GlslExpr and(int mask) {
|
||||
return new Binary(this, uintHexLiteral(mask), BinOp.BITWISE_AND);
|
||||
default GlslExpr div(float v) {
|
||||
return new Binary(this, floatLiteral(v), BinOp.DIVIDE);
|
||||
}
|
||||
|
||||
default GlslExpr sub(int v) {
|
||||
return new Binary(this, uintLiteral(v), BinOp.SUBTRACT);
|
||||
}
|
||||
|
||||
default GlslExpr rsh(int by) {
|
||||
@ -106,8 +110,12 @@ public interface GlslExpr {
|
||||
return new Binary(this, uintLiteral(by), BinOp.RIGHT_SHIFT);
|
||||
}
|
||||
|
||||
default GlslExpr div(float v) {
|
||||
return new Binary(this, floatLiteral(v), BinOp.DIVIDE);
|
||||
default GlslExpr and(int mask) {
|
||||
return new Binary(this, uintHexLiteral(mask), BinOp.BITWISE_AND);
|
||||
}
|
||||
|
||||
default GlslExpr xor(int mask) {
|
||||
return new Binary(this, uintHexLiteral(mask), BinOp.BITWISE_XOR);
|
||||
}
|
||||
|
||||
default GlslExpr clamp(float from, float to) {
|
||||
|
@ -24,8 +24,10 @@ public final class InstanceTypes {
|
||||
MemoryUtil.memPutByte(ptr + 1, instance.g);
|
||||
MemoryUtil.memPutByte(ptr + 2, instance.b);
|
||||
MemoryUtil.memPutByte(ptr + 3, instance.a);
|
||||
MemoryUtil.memPutInt(ptr + 4, instance.overlay);
|
||||
MemoryUtil.memPutInt(ptr + 8, (int) instance.blockLight | (int) instance.skyLight << 16);
|
||||
MemoryUtil.memPutShort(ptr + 4, (short) (instance.overlay & 0xFFFF));
|
||||
MemoryUtil.memPutShort(ptr + 6, (short) (instance.overlay >> 16 & 0xFFFF));
|
||||
MemoryUtil.memPutShort(ptr + 8, (short) (Byte.toUnsignedInt(instance.blockLight) << 4));
|
||||
MemoryUtil.memPutShort(ptr + 10, (short) (Byte.toUnsignedInt(instance.skyLight) << 4));
|
||||
MatrixMath.writeUnsafe(instance.model, ptr + 12);
|
||||
MatrixMath.writeUnsafe(instance.normal, ptr + 76);
|
||||
})
|
||||
@ -47,8 +49,10 @@ public final class InstanceTypes {
|
||||
MemoryUtil.memPutByte(ptr + 1, instance.g);
|
||||
MemoryUtil.memPutByte(ptr + 2, instance.b);
|
||||
MemoryUtil.memPutByte(ptr + 3, instance.a);
|
||||
MemoryUtil.memPutInt(ptr + 4, instance.overlay);
|
||||
MemoryUtil.memPutInt(ptr + 8, (int) instance.blockLight | (int) instance.skyLight << 16);
|
||||
MemoryUtil.memPutShort(ptr + 4, (short) (instance.overlay & 0xFFFF));
|
||||
MemoryUtil.memPutShort(ptr + 6, (short) (instance.overlay >> 16 & 0xFFFF));
|
||||
MemoryUtil.memPutShort(ptr + 8, (short) (Byte.toUnsignedInt(instance.blockLight) << 4));
|
||||
MemoryUtil.memPutShort(ptr + 10, (short) (Byte.toUnsignedInt(instance.skyLight) << 4));
|
||||
MemoryUtil.memPutFloat(ptr + 12, instance.posX);
|
||||
MemoryUtil.memPutFloat(ptr + 16, instance.posY);
|
||||
MemoryUtil.memPutFloat(ptr + 20, instance.posZ);
|
||||
|
@ -5,5 +5,6 @@ void flw_instanceVertex(in FlwInstance i) {
|
||||
flw_vertexNormal = rotateByQuaternion(flw_vertexNormal, i.rotation);
|
||||
flw_vertexColor *= i.color;
|
||||
flw_vertexOverlay = i.overlay;
|
||||
flw_vertexLight = i.light / 15.;
|
||||
// Some drivers have a bug where uint over float division is invalid, so use an explicit cast.
|
||||
flw_vertexLight = vec2(i.light) / 256.0;
|
||||
}
|
||||
|
@ -3,5 +3,6 @@ void flw_instanceVertex(in FlwInstance i) {
|
||||
flw_vertexNormal = i.normal * flw_vertexNormal;
|
||||
flw_vertexColor *= i.color;
|
||||
flw_vertexOverlay = i.overlay;
|
||||
flw_vertexLight = i.light / 15.;
|
||||
// Some drivers have a bug where uint over float division is invalid, so use an explicit cast.
|
||||
flw_vertexLight = vec2(i.light) / 256.0;
|
||||
}
|
||||
|
@ -33,15 +33,12 @@ void _flw_main() {
|
||||
}
|
||||
|
||||
if (flw_material.useOverlay) {
|
||||
// Need to clamp the overlay texture coords to sane coordinates because integer vertex attributes explode on
|
||||
// some drivers for some draw calls. This should only effect instances that don't write to overlay, but
|
||||
// the internal vertex format is unfortunately subject to these issues.
|
||||
vec4 overlayColor = texelFetch(flw_overlayTex, clamp(flw_fragOverlay, 0, 10), 0);
|
||||
vec4 overlayColor = texelFetch(flw_overlayTex, flw_fragOverlay, 0);
|
||||
color.rgb = mix(overlayColor.rgb, color.rgb, overlayColor.a);
|
||||
}
|
||||
|
||||
if (flw_material.useLight) {
|
||||
vec4 lightColor = texture(flw_lightTex, (flw_fragLight * 15.0 + 0.5) / 16.0);
|
||||
vec4 lightColor = texture(flw_lightTex, clamp(flw_fragLight, 0.5 / 16.0, 15.5 / 16.0));
|
||||
color *= lightColor;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,10 @@ void _flw_layoutVertex() {
|
||||
flw_vertexPos = vec4(_flw_a_pos, 1.0);
|
||||
flw_vertexColor = _flw_a_color;
|
||||
flw_vertexTexCoord = _flw_a_texCoord;
|
||||
flw_vertexOverlay = _flw_a_overlay;
|
||||
// Need to clamp the overlay texture coords to sane coordinates because integer vertex attributes explode on
|
||||
// some drivers for some draw calls. This should only effect instances that don't write to overlay, but
|
||||
// the internal vertex format is unfortunately subject to these issues.
|
||||
flw_vertexOverlay = clamp(_flw_a_overlay, 0, 15);
|
||||
flw_vertexLight = _flw_a_light / 256.0;
|
||||
flw_vertexNormal = _flw_a_normal;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user