fix dynamic unifomrs not being exposed

This commit is contained in:
mcrcortex
2025-11-01 01:17:18 +10:00
parent 5baf4ce2db
commit 9aebf20aad

View File

@@ -3,6 +3,7 @@ package me.cortex.voxy.client.iris;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction;
import kroppeb.stareval.function.FunctionReturn; import kroppeb.stareval.function.FunctionReturn;
import kroppeb.stareval.function.Type; import kroppeb.stareval.function.Type;
import me.cortex.voxy.client.core.IrisVoxyRenderPipeline; import me.cortex.voxy.client.core.IrisVoxyRenderPipeline;
@@ -28,9 +29,7 @@ import org.joml.*;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import java.util.*; import java.util.*;
import java.util.function.IntConsumer; import java.util.function.*;
import java.util.function.IntSupplier;
import java.util.function.LongConsumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.lwjgl.opengl.ARBDirectStateAccess.glBindTextureUnit; import static org.lwjgl.opengl.ARBDirectStateAccess.glBindTextureUnit;
@@ -116,40 +115,55 @@ public class IrisVoxyRenderPipelineData {
return targetTextures; return targetTextures;
} }
private static String convertToGlslType(UniformType type) {
return switch (type) {
case INT -> "int";
case FLOAT -> "float";
case MAT3 -> "mat3";
case MAT4 -> "mat4";
case VEC2 -> "vec2";
case VEC2I -> "ivec2";
case VEC3 -> "vec3";
case VEC3I -> "ivec3";
case VEC4 -> "vec4";
case VEC4I -> "ivec4";
};
}
public record StructLayout(int size, String layout, LongConsumer updater) {} public record StructLayout(int size, String layout, LongConsumer updater) {}
private static StructLayout createUniformLayoutStructAndUpdater(CachedUniform[] uniforms) { private static StructLayout createUniformLayoutStructAndUpdater(List<UniformWritingHolder> uniforms) {
if (uniforms.length == 0) { if (uniforms.size() == 0) {
return null; return null;
} }
List<CachedUniform>[] ordering = new List[]{new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()}; List<UniformWritingHolder>[] ordering = new List[]{new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()};
//Creates an optimial struct layout for the uniforms //Creates an optimial struct layout for the uniforms
for (var uniform : uniforms) { for (var uniform : uniforms) {
int order = getUniformOrdering(Type.convert(uniform.getType())); int order = getUniformOrdering(uniform.type);
ordering[order].add(uniform); ordering[order].add(uniform);
} }
//Emit the ordering, note this is not optimial, but good enough, e.g. if have even number of align 2, emit that after align 4 //Emit the ordering, note this is not optimial, but good enough, e.g. if have even number of align 2, emit that after align 4
int pos = 0; int pos = 0;
Int2ObjectLinkedOpenHashMap<CachedUniform> layout = new Int2ObjectLinkedOpenHashMap<>(); Int2ObjectLinkedOpenHashMap<UniformWritingHolder> layout = new Int2ObjectLinkedOpenHashMap<>();
for (var uniform : ordering[0]) {//Emit exact align 4 for (var uniform : ordering[0]) {//Emit exact align 4
layout.put(pos, uniform); pos += getSizeAndAlignment(Type.convert(uniform.getType()))>>5; layout.put(pos, uniform); pos += getSizeAndAlignment(uniform.type)>>5;
} }
if (!ordering[1].isEmpty() && (ordering[1].size()&1)==0) { if (!ordering[1].isEmpty() && (ordering[1].size()&1)==0) {
//Emit all the align 2 as there is an even number of them //Emit all the align 2 as there is an even number of them
for (var uniform : ordering[1]) { for (var uniform : ordering[1]) {
layout.put(pos, uniform); pos += getSizeAndAlignment(Type.convert(uniform.getType()))>>5; layout.put(pos, uniform); pos += getSizeAndAlignment(uniform.type)>>5;
} }
ordering[1].clear(); ordering[1].clear();
} }
//Emit align 3 //Emit align 3
for (var uniform : ordering[2]) {//Emit size odd, alignment must be 4 for (var uniform : ordering[2]) {//Emit size odd, alignment must be 4
layout.put(pos, uniform); pos += getSizeAndAlignment(Type.convert(uniform.getType()))>>5; layout.put(pos, uniform); pos += getSizeAndAlignment(uniform.type)>>5;
//We must get a size 1 to pad to align 4 //We must get a size 1 to pad to align 4
if (!ordering[3].isEmpty()) {//Size 1 if (!ordering[3].isEmpty()) {//Size 1
uniform = ordering[3].removeFirst(); uniform = ordering[3].removeFirst();
layout.put(pos, uniform); pos += getSizeAndAlignment(Type.convert(uniform.getType()))>>5; layout.put(pos, uniform); pos += getSizeAndAlignment(uniform.type)>>5;
} else {//Padding must be injected } else {//Padding must be injected
pos += 1; pos += 1;
} }
@@ -157,15 +171,15 @@ public class IrisVoxyRenderPipelineData {
//Emit align 2 //Emit align 2
for (var uniform : ordering[1]) { for (var uniform : ordering[1]) {
layout.put(pos, uniform); pos += getSizeAndAlignment(Type.convert(uniform.getType()))>>5; layout.put(pos, uniform); pos += getSizeAndAlignment(uniform.type)>>5;
} }
//Emit align 1 //Emit align 1
for (var uniform : ordering[3]) { for (var uniform : ordering[3]) {
layout.put(pos, uniform); pos += getSizeAndAlignment(Type.convert(uniform.getType()))>>5; layout.put(pos, uniform); pos += getSizeAndAlignment(uniform.type)>>5;
} }
if (layout.size()!=uniforms.length) { if (layout.size()!=uniforms.size()) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@@ -175,7 +189,7 @@ public class IrisVoxyRenderPipelineData {
{ {
StringBuilder struct = new StringBuilder("{\n"); StringBuilder struct = new StringBuilder("{\n");
for (var pair : layout.int2ObjectEntrySet()) { for (var pair : layout.int2ObjectEntrySet()) {
struct.append("\t").append(pair.getValue().getType().toString()).append(" ").append(pair.getValue().getName()).append(";\n"); struct.append("\t").append(convertToGlslType(pair.getValue().type)).append(" ").append(pair.getValue().name).append(";\n");
} }
struct.append("}"); struct.append("}");
structLayout = struct.toString(); structLayout = struct.toString();
@@ -183,11 +197,10 @@ public class IrisVoxyRenderPipelineData {
LongConsumer updater; LongConsumer updater;
{ {
FunctionReturn cacheRetObj = new FunctionReturn(); LongConsumer[] updaters = new LongConsumer[uniforms.size()];
LongConsumer[] updaters = new LongConsumer[uniforms.length];
int i = 0; int i = 0;
for (var pair : layout.int2ObjectEntrySet()) { for (var pair : layout.int2ObjectEntrySet()) {
updaters[i++] = createWriter(pair.getIntKey()*4L, cacheRetObj, pair.getValue()); updaters[i++] = pair.getValue().writingFactory.get(pair.getIntKey()*4L);
} }
updater = ptr -> { updater = ptr -> {
@@ -273,14 +286,81 @@ public class IrisVoxyRenderPipelineData {
}; };
} }
private static CachedUniform[] createUniformSet(CustomUniforms cu, IrisShaderPatch patch) { private record UniformWritingHolder(String name, UniformType type, Long2ObjectFunction<LongConsumer> writingFactory) {
}
private static List<UniformWritingHolder> createUniformSet(CustomUniforms cu, IrisShaderPatch patch) {
//This is a fking awful hack... but it works thinks //This is a fking awful hack... but it works thinks
List<UniformWritingHolder> uniforms = new ArrayList<>();
Set<String> seenUniforms = new HashSet<>();
DynamicLocationalUniformHolder uniformBuilder = new DynamicLocationalUniformHolder() { DynamicLocationalUniformHolder uniformBuilder = new DynamicLocationalUniformHolder() {
@Override @Override
public DynamicLocationalUniformHolder addDynamicUniform(Uniform uniform, ValueUpdateNotifier valueUpdateNotifier) { public DynamicLocationalUniformHolder uniform1i(UniformUpdateFrequency updateFrequency, String name, IntSupplier value) {
return this.uniform1i(name, value, null);
}
@Override
public DynamicLocationalUniformHolder uniform1i(String name, IntSupplier value, ValueUpdateNotifier notifier) {
this.injectDynamicUniformType(name, UniformType.INT, offset->{
return ptr->{
MemoryUtil.memPutInt(ptr+offset, value.getAsInt());
};
});
return this; return this;
} }
@Override
public DynamicLocationalUniformHolder uniform1f(UniformUpdateFrequency updateFrequency, String name, FloatSupplier value) {
return this.uniform1f(name, value, null);
}
@Override
public DynamicLocationalUniformHolder uniform1f(String name, FloatSupplier value, ValueUpdateNotifier notifier) {
this.injectDynamicUniformType(name, UniformType.FLOAT, offset->{
return ptr->{
MemoryUtil.memPutFloat(ptr+offset, value.getAsFloat());
};
});
return this;
}
@Override
public DynamicLocationalUniformHolder uniform3f(UniformUpdateFrequency updateFrequency, String name, Supplier<Vector3f> value) {
return this.uniform3f(name, value, null);
}
@Override
public DynamicLocationalUniformHolder uniform3f(String name, Supplier<Vector3f> value, ValueUpdateNotifier notifier) {
this.injectDynamicUniformType(name, UniformType.VEC3, offset->{
return ptr->{
value.get().getToAddress(ptr+offset);
};
});
return this;
}
private void injectDynamicUniformType(String name, UniformType type, Long2ObjectFunction<LongConsumer> supplier) {
var names = patch.getUniformList();
for (int i = 0; i < names.length; i++) {
if (names[i].equals(name)) {
if (!seenUniforms.add(name)) {
throw new IllegalArgumentException("Already added uniform: " + name);
}
uniforms.add(new UniformWritingHolder(name, type, supplier));
break;
}
}
}
@Override
public DynamicLocationalUniformHolder addDynamicUniform(Uniform uniform, ValueUpdateNotifier valueUpdateNotifier) {
throw new IllegalStateException("Type not implemented for uniform: " + uniform);
//return this;
}
@Override @Override
public LocationalUniformHolder addUniform(UniformUpdateFrequency uniformUpdateFrequency, Uniform uniform) { public LocationalUniformHolder addUniform(UniformUpdateFrequency uniformUpdateFrequency, Uniform uniform) {
return this; return this;
@@ -303,24 +383,27 @@ public class IrisVoxyRenderPipelineData {
return null; return null;
} }
}; };
//CommonUniforms.addDynamicUniforms(uniformBuilder, FogMode.PER_FRAGMENT); CommonUniforms.addDynamicUniforms(uniformBuilder, FogMode.PER_FRAGMENT);
cu.assignTo(uniformBuilder); cu.assignTo(uniformBuilder);
cu.mapholderToPass(uniformBuilder, patch); cu.mapholderToPass(uniformBuilder, patch);
CachedUniform[] uniforms = new CachedUniform[patch.getUniformList().length]; FunctionReturn cachedReturn = new FunctionReturn();
((CustomUniformsAccessor)cu).getLocationMap().get(patch).object2IntEntrySet().forEach(entry->uniforms[entry.getIntValue()] = entry.getKey()); ((CustomUniformsAccessor)cu).getLocationMap().get(patch).object2IntEntrySet().forEach(entry-> {
int i = 0; if (!seenUniforms.add(entry.getKey().getName())) {
int j = 0; throw new IllegalArgumentException("Already added uniform: " + entry.getKey().getName());
for (var uniform : uniforms) {
if (uniform == null) {
Logger.error("Unknown uniform at location "+j + " skipping, uniform name: " + patch.getUniformList()[j]);
} else {
uniforms[i++] = uniform;//This shuffles the uniforms down till its compacted
} }
j++; uniforms.add(new UniformWritingHolder(entry.getKey().getName(), Type.convert(entry.getKey().getType()),offset->createWriter(offset, cachedReturn, entry.getKey())));
});
if (uniforms.size() != patch.getUniformList().length) {
Set<String> uniformsUnseen = new HashSet<>(List.of(patch.getUniformList()));
for (var uniform : uniforms) {
uniformsUnseen.remove(uniform.name);
}
Logger.error("The following uniforms could not be found: [" + uniformsUnseen.stream().sorted(String::compareToIgnoreCase).collect(Collectors.joining(","))+"]");
} }
//In _theory_ this should work? //In _theory_ this should work?
return Arrays.copyOf(uniforms, i); return uniforms;
} }
private record TextureWSampler(String name, IntSupplier texture, int sampler) { } private record TextureWSampler(String name, IntSupplier texture, int sampler) { }