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 it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction;
import kroppeb.stareval.function.FunctionReturn;
import kroppeb.stareval.function.Type;
import me.cortex.voxy.client.core.IrisVoxyRenderPipeline;
@@ -28,9 +29,7 @@ import org.joml.*;
import org.lwjgl.system.MemoryUtil;
import java.util.*;
import java.util.function.IntConsumer;
import java.util.function.IntSupplier;
import java.util.function.LongConsumer;
import java.util.function.*;
import java.util.stream.Collectors;
import static org.lwjgl.opengl.ARBDirectStateAccess.glBindTextureUnit;
@@ -116,40 +115,55 @@ public class IrisVoxyRenderPipelineData {
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) {}
private static StructLayout createUniformLayoutStructAndUpdater(CachedUniform[] uniforms) {
if (uniforms.length == 0) {
private static StructLayout createUniformLayoutStructAndUpdater(List<UniformWritingHolder> uniforms) {
if (uniforms.size() == 0) {
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
for (var uniform : uniforms) {
int order = getUniformOrdering(Type.convert(uniform.getType()));
int order = getUniformOrdering(uniform.type);
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
int pos = 0;
Int2ObjectLinkedOpenHashMap<CachedUniform> layout = new Int2ObjectLinkedOpenHashMap<>();
Int2ObjectLinkedOpenHashMap<UniformWritingHolder> layout = new Int2ObjectLinkedOpenHashMap<>();
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) {
//Emit all the align 2 as there is an even number of them
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();
}
//Emit align 3
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
if (!ordering[3].isEmpty()) {//Size 1
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
pos += 1;
}
@@ -157,15 +171,15 @@ public class IrisVoxyRenderPipelineData {
//Emit align 2
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
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();
}
@@ -175,7 +189,7 @@ public class IrisVoxyRenderPipelineData {
{
StringBuilder struct = new StringBuilder("{\n");
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("}");
structLayout = struct.toString();
@@ -183,11 +197,10 @@ public class IrisVoxyRenderPipelineData {
LongConsumer updater;
{
FunctionReturn cacheRetObj = new FunctionReturn();
LongConsumer[] updaters = new LongConsumer[uniforms.length];
LongConsumer[] updaters = new LongConsumer[uniforms.size()];
int i = 0;
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 -> {
@@ -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
List<UniformWritingHolder> uniforms = new ArrayList<>();
Set<String> seenUniforms = new HashSet<>();
DynamicLocationalUniformHolder uniformBuilder = new DynamicLocationalUniformHolder() {
@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;
}
@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
public LocationalUniformHolder addUniform(UniformUpdateFrequency uniformUpdateFrequency, Uniform uniform) {
return this;
@@ -303,24 +383,27 @@ public class IrisVoxyRenderPipelineData {
return null;
}
};
//CommonUniforms.addDynamicUniforms(uniformBuilder, FogMode.PER_FRAGMENT);
CommonUniforms.addDynamicUniforms(uniformBuilder, FogMode.PER_FRAGMENT);
cu.assignTo(uniformBuilder);
cu.mapholderToPass(uniformBuilder, patch);
CachedUniform[] uniforms = new CachedUniform[patch.getUniformList().length];
((CustomUniformsAccessor)cu).getLocationMap().get(patch).object2IntEntrySet().forEach(entry->uniforms[entry.getIntValue()] = entry.getKey());
int i = 0;
int j = 0;
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
FunctionReturn cachedReturn = new FunctionReturn();
((CustomUniformsAccessor)cu).getLocationMap().get(patch).object2IntEntrySet().forEach(entry-> {
if (!seenUniforms.add(entry.getKey().getName())) {
throw new IllegalArgumentException("Already added uniform: " + entry.getKey().getName());
}
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?
return Arrays.copyOf(uniforms, i);
return uniforms;
}
private record TextureWSampler(String name, IntSupplier texture, int sampler) { }