This commit is contained in:
mcrcortex
2025-08-17 13:23:58 +10:00
parent 70a937bcaa
commit 3d2693796d
11 changed files with 180 additions and 16 deletions

View File

@@ -14,7 +14,7 @@ public class RenderPipelineFactory {
public static AbstractRenderPipeline createPipeline(AsyncNodeManager nodeManager, NodeCleaner nodeCleaner, HierarchicalOcclusionTraverser traversal, BooleanSupplier frexSupplier) {
//Note this is where will choose/create e.g. IrisRenderPipeline or normal pipeline
AbstractRenderPipeline pipeline = null;
if (IrisUtil.IRIS_INSTALLED && System.getProperty("voxy.enableExperimentalIrisPipeline", "false").equalsIgnoreCase("true")) {
if (IrisUtil.IRIS_INSTALLED && IrisUtil.SHADER_SUPPORT) {
pipeline = createIrisPipeline(nodeManager, nodeCleaner, traversal, frexSupplier);
}
if (pipeline == null) {

View File

@@ -253,7 +253,7 @@ public class VoxyRenderSystem {
GlStateManager._glBindVertexArray(0);//Clear binding
GlStateManager._activeTexture(GlConst.GL_TEXTURE1);
for (int i = 0; i < 16; i++) {
for (int i = 0; i < 12; i++) {
GlStateManager._activeTexture(GlConst.GL_TEXTURE0+i);
GlStateManager._bindTexture(0);
glBindSampler(i, 0);

View File

@@ -1,5 +1,6 @@
package me.cortex.voxy.client.core.rendering;
import me.cortex.voxy.client.core.util.IrisUtil;
import net.fabricmc.loader.api.FabricLoader;
import org.vivecraft.client_vr.ClientDataHolderVR;
@@ -19,19 +20,28 @@ public class ViewportSelector <T extends Viewport<?>> {
this.defaultViewport = viewportCreator.get();
}
private T getOrCreate(Object holder) {
return this.extraViewports.computeIfAbsent(holder, a->this.creator.get());
}
private T getVivecraftViewport() {
var cdh = ClientDataHolderVR.getInstance();
var pass = cdh.currentPass;
if (pass == null) {
return this.defaultViewport;
}
return this.extraViewports.computeIfAbsent(pass, a->this.creator.get());
return this.getOrCreate(pass);
}
private static final Object IRIS_SHADOW_OBJECT = new Object();
public T getViewport() {
if (VIVECRAFT_INSTALLED) {
return getVivecraftViewport();
}
if (IrisUtil.irisShadowActive()) {
return this.getOrCreate(IRIS_SHADOW_OBJECT);
}
return this.defaultViewport;
}

View File

@@ -6,6 +6,7 @@ import net.irisshaders.iris.shadows.ShadowRenderer;
public class IrisUtil {
public static final boolean IRIS_INSTALLED = FabricLoader.getInstance().isModLoaded("iris");
public static final boolean SHADER_SUPPORT = System.getProperty("voxy.enableExperimentalIrisPipeline", "false").equalsIgnoreCase("true");
private static boolean irisShadowActive0() {

View File

@@ -1,20 +1,107 @@
package me.cortex.voxy.client.iris;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.Strictness;
import com.google.gson.*;
import com.google.gson.annotations.JsonAdapter;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import me.cortex.voxy.common.Logger;
import net.irisshaders.iris.shaderpack.ShaderPack;
import net.irisshaders.iris.shaderpack.include.AbsolutePackPath;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.function.Function;
import java.util.function.IntSupplier;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL33.*;
public class IrisShaderPatch {
public static final int VERSION = ((IntSupplier)()->1).getAsInt();
private static final class SSBODeserializer implements JsonDeserializer<Int2ObjectOpenHashMap<String>> {
@Override
public Int2ObjectOpenHashMap<String> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Int2ObjectOpenHashMap<String> ret = new Int2ObjectOpenHashMap<>();
if (json==null) return null;
try {
for (var entry : json.getAsJsonObject().entrySet()) {
ret.put(Integer.parseInt(entry.getKey()), entry.getValue().getAsString());
}
} catch (Exception e) {
Logger.error(e);
}
return ret;
}
}
public record BlendState(int buffer, boolean off, int sRBG, int dRGb, int sA, int dA) {
public static BlendState ALL_OFF = new BlendState(-1, true, 0,0,0,0);
}
private static final class BlendStateDeserializer implements JsonDeserializer<Int2ObjectMap<BlendState>> {
private static int parseType(String type) {
type = type.toUpperCase();
return switch (type) {
case "GL_ZERO" -> GL_ZERO;
case "GL_ONE" -> GL_ONE;
case "GL_SRC_COLOR" -> GL_SRC_COLOR;
case "GL_ONE_MINUS_SRC_COLOR" -> GL_ONE_MINUS_SRC_COLOR;
case "GL_SRC_ALPHA" -> GL_SRC_ALPHA;
case "GL_ONE_MINUS_SRC_ALPHA" -> GL_ONE_MINUS_SRC_ALPHA;
case "GL_DST_ALPHA" -> GL_DST_ALPHA;
case "GL_ONE_MINUS_DST_ALPHA" -> GL_ONE_MINUS_DST_ALPHA;
case "GL_DST_COLOR" -> GL_DST_COLOR;
case "GL_ONE_MINUS_DST_COLOR" -> GL_ONE_MINUS_DST_COLOR;
case "GL_SRC_ALPHA_SATURATE" -> GL_SRC_ALPHA_SATURATE;
case "GL_SRC1_COLOR" -> GL_SRC1_COLOR;
case "GL_ONE_MINUS_SRC1_COLOR" -> GL_ONE_MINUS_SRC1_COLOR;
case "GL_ONE_MINUS_SRC1_ALPHA" -> GL_ONE_MINUS_SRC1_ALPHA;
default -> -1;
};
}
@Override
public Int2ObjectMap<BlendState> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json==null) return null;
Int2ObjectMap<BlendState> ret = new Int2ObjectOpenHashMap<>();
try {
if (json.isJsonPrimitive()) {
if (json.getAsString().equalsIgnoreCase("off")) {
ret.put(-1, BlendState.ALL_OFF);
return ret;
}
} else if (json.isJsonObject()) {
for (var entry : json.getAsJsonObject().entrySet()) {
int buffer = Integer.parseInt(entry.getKey());
BlendState state;
var val = entry.getValue();
if (val.isJsonArray()) {
int[] v = val.getAsJsonArray().asList().stream().mapToInt(a->parseType(a.getAsString())).toArray();
state = new BlendState(buffer, false, v[0], v[1], v[2], v[3]);
} else if (val.isJsonPrimitive()) {
if (val.getAsString().equalsIgnoreCase("off")) {
state = new BlendState(buffer, true, 0,0,0,0);
} else {
state = new BlendState(buffer, true, -1,-1,-1,-1);
}
} else {
state = null;
}
ret.put(buffer, state);
}
return ret;
}
} catch (Exception e) {
Logger.error(e);
}
Logger.error("Failed to parse blend state: " + json);
return ret;
}
}
private static class PatchGson {
public int version;//TODO maybe replace with semver?
public int[] opaqueDrawBuffers;
@@ -23,19 +110,35 @@ public class IrisShaderPatch {
public String[] samplers;
public String[] opaquePatchData;
public String[] translucentPatchData;
@JsonAdapter(SSBODeserializer.class)
public Int2ObjectOpenHashMap<String> ssbos;
@JsonAdapter(BlendStateDeserializer.class)
public Int2ObjectOpenHashMap<BlendState> blending;
public boolean checkValid() {
return this.opaqueDrawBuffers != null && this.translucentDrawBuffers != null && this.uniforms != null && this.opaquePatchData != null;
}
}
private final PatchGson patchData;
private final ShaderPack pack;
private final Int2ObjectMap<String> ssbos;
private IrisShaderPatch(PatchGson patchData, ShaderPack pack) {
this.patchData = patchData;
this.pack = pack;
if (patchData.ssbos == null) {
this.ssbos = new Int2ObjectOpenHashMap<>();
} else {
this.ssbos = patchData.ssbos;
}
}
public Int2ObjectMap<String> getSSBOs() {
return this.ssbos;
}
public String getPatchOpaqueSource() {
return String.join("\n", this.patchData.opaquePatchData);
}

View File

@@ -2,12 +2,14 @@ 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 kroppeb.stareval.function.FunctionReturn;
import kroppeb.stareval.function.Type;
import me.cortex.voxy.client.core.IrisVoxyRenderPipeline;
import me.cortex.voxy.client.mixin.iris.CustomUniformsAccessor;
import me.cortex.voxy.client.mixin.iris.IrisRenderingPipelineAccessor;
import me.cortex.voxy.common.Logger;
import net.irisshaders.iris.gl.buffer.ShaderStorageBufferHolder;
import net.irisshaders.iris.gl.image.ImageHolder;
import net.irisshaders.iris.gl.sampler.GlSampler;
import net.irisshaders.iris.gl.sampler.SamplerHolder;
@@ -26,6 +28,7 @@ import org.lwjgl.system.MemoryUtil;
import java.util.*;
import java.util.function.IntSupplier;
import java.util.function.LongConsumer;
import java.util.stream.Collectors;
public class IrisVoxyRenderPipelineData {
public IrisVoxyRenderPipeline thePipeline;
@@ -57,11 +60,13 @@ public class IrisVoxyRenderPipelineData {
return this.translucentPatch;
}
public static IrisVoxyRenderPipelineData buildPipeline(IrisRenderingPipeline ipipe, IrisShaderPatch patch, CustomUniforms cu) {
public static IrisVoxyRenderPipelineData buildPipeline(IrisRenderingPipeline ipipe, IrisShaderPatch patch, CustomUniforms cu, ShaderStorageBufferHolder ssboHolder) {
var uniforms = createUniformLayoutStructAndUpdater(createUniformSet(cu, patch));
createImageSet(ipipe, patch);
createSSBOLayouts(patch.getSSBOs(), ssboHolder);
var opaqueDrawTargets = getDrawBuffers(patch.getOpqaueTargets(), ipipe.getFlippedAfterPrepare(), ((IrisRenderingPipelineAccessor)ipipe).getRenderTargets());
var translucentDrawTargets = getDrawBuffers(patch.getTranslucentTargets(), ipipe.getFlippedAfterPrepare(), ((IrisRenderingPipelineAccessor)ipipe).getRenderTargets());
@@ -272,8 +277,12 @@ public class IrisVoxyRenderPipelineData {
return uniforms;
}
private record TextureWSampler(String name, IntSupplier texture, int sampler) {
}
private static void createImageSet(IrisRenderingPipeline ipipe, IrisShaderPatch patch) {
Set<String> samplerNameSet = new HashSet<>(List.of(patch.getSamplerList()));
Set<String> samplerNameSet = new LinkedHashSet<>(List.of(patch.getSamplerList()));
Set<TextureWSampler> samplerSet = new LinkedHashSet<>();
SamplerHolder samplerBuilder = new SamplerHolder() {
@Override
public boolean hasSampler(String s) {
@@ -287,6 +296,13 @@ public class IrisVoxyRenderPipelineData {
return false;
}
private String name(String... names) {
for (var name : names) {
if (samplerNameSet.contains(name)) return name;
}
return null;
}
@Override
public boolean addDefaultSampler(TextureType type, IntSupplier texture, ValueUpdateNotifier notifier, GlSampler sampler, String... names) {
Logger.error("Unsupported default sampler");
@@ -301,14 +317,14 @@ public class IrisVoxyRenderPipelineData {
@Override
public boolean addDynamicSampler(TextureType type, IntSupplier texture, ValueUpdateNotifier notifier, GlSampler sampler, String... names) {
if (!this.hasSampler(names)) return false;
Logger.info(Arrays.toString(names));
return false;
samplerSet.add(new TextureWSampler(this.name(names), texture, sampler!=null?sampler.getId():-1));
return true;
}
@Override
public void addExternalSampler(int texture, String... names) {
if (!this.hasSampler(names)) return;
Logger.info(Arrays.toString(names));
samplerSet.add(new TextureWSampler(this.name(names), ()->texture, -1));
}
};
@@ -326,6 +342,18 @@ public class IrisVoxyRenderPipelineData {
};
ipipe.addGbufferOrShadowSamplers(samplerBuilder, imageBuilder, ipipe::getFlippedAfterPrepare, false, true, true, false);
//samplerSet contains our samplers
if (samplerSet.size() != samplerNameSet.size()) {
Logger.error("Did not find all requested samplers. Found [" + samplerSet.stream().map(a->a.name).collect(Collectors.joining()) + "] expected " + samplerNameSet);
}
//TODO: generate a layout (defines) for all the samplers with the correct types
}
private static void createSSBOLayouts(Int2ObjectMap<String> ssbos, ShaderStorageBufferHolder ssboStore) {
//ssboStore.getBufferIndex()
}
}

View File

@@ -1,9 +1,11 @@
package me.cortex.voxy.client.mixin.iris;
import me.cortex.voxy.client.core.util.IrisUtil;
import me.cortex.voxy.client.iris.IGetIrisVoxyPipelineData;
import me.cortex.voxy.client.iris.IGetVoxyPatchData;
import me.cortex.voxy.client.iris.IrisShaderPatch;
import me.cortex.voxy.client.iris.IrisVoxyRenderPipelineData;
import net.irisshaders.iris.gl.buffer.ShaderStorageBufferHolder;
import net.irisshaders.iris.pipeline.IrisRenderingPipeline;
import net.irisshaders.iris.shaderpack.programs.ProgramSet;
import net.irisshaders.iris.uniforms.custom.CustomUniforms;
@@ -18,19 +20,22 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = IrisRenderingPipeline.class, remap = false)
public class MixinIrisRenderingPipeline implements IGetVoxyPatchData, IGetIrisVoxyPipelineData {
@Shadow @Final private CustomUniforms customUniforms;
@Shadow private ShaderStorageBufferHolder shaderStorageBufferHolder;
@Unique IrisShaderPatch patchData;
@Unique
IrisVoxyRenderPipelineData pipeline;
@Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/irisshaders/iris/pipeline/transform/ShaderPrinter;resetPrintState()V", shift = At.Shift.AFTER))
private void voxy$injectPatchDataStore(ProgramSet programSet, CallbackInfo ci) {
this.patchData = ((IGetVoxyPatchData)programSet).voxy$getPatchData();
if (IrisUtil.SHADER_SUPPORT) {
this.patchData = ((IGetVoxyPatchData) programSet).voxy$getPatchData();
}
}
@Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/irisshaders/iris/pipeline/IrisRenderingPipeline;createSetupComputes([Lnet/irisshaders/iris/shaderpack/programs/ComputeSource;Lnet/irisshaders/iris/shaderpack/programs/ProgramSet;Lnet/irisshaders/iris/shaderpack/texture/TextureStage;)[Lnet/irisshaders/iris/gl/program/ComputeProgram;"))
private void voxy$injectPipeline(ProgramSet programSet, CallbackInfo ci) {
if (this.patchData != null) {
this.pipeline = IrisVoxyRenderPipelineData.buildPipeline((IrisRenderingPipeline)(Object)this, this.patchData, this.customUniforms);
this.pipeline = IrisVoxyRenderPipelineData.buildPipeline((IrisRenderingPipeline)(Object)this, this.patchData, this.customUniforms, this.shaderStorageBufferHolder);
}
}

View File

@@ -1,5 +1,7 @@
package me.cortex.voxy.client.mixin.iris;
import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.client.core.util.IrisUtil;
import me.cortex.voxy.client.iris.VoxyUniforms;
import net.irisshaders.iris.gl.uniform.UniformHolder;
import net.irisshaders.iris.shaderpack.IdMap;
@@ -15,6 +17,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class MixinMatrixUniforms {
@Inject(method = "addNonDynamicUniforms", at = @At("TAIL"))
private static void voxy$InjectMatrixUniforms(UniformHolder uniforms, IdMap idMap, PackDirectives directives, FrameUpdateNotifier updateNotifier, CallbackInfo ci) {
if (VoxyConfig.CONFIG.isRenderingEnabled() && IrisUtil.SHADER_SUPPORT) {
VoxyUniforms.addUniforms(uniforms);
}
}
}

View File

@@ -1,6 +1,7 @@
package me.cortex.voxy.client.mixin.iris;
import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.client.core.util.IrisUtil;
import me.cortex.voxy.client.iris.IGetVoxyPatchData;
import me.cortex.voxy.client.iris.IrisShaderPatch;
import net.irisshaders.iris.shaderpack.ShaderPack;
@@ -25,7 +26,7 @@ public class MixinProgramSet implements IGetVoxyPatchData {
@Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/irisshaders/iris/shaderpack/programs/ProgramSet;locateDirectives()V", shift = At.Shift.BEFORE))
private void voxy$injectPatchMaker(AbsolutePackPath directory, Function<AbsolutePackPath, String> sourceProvider, ShaderProperties shaderProperties, ShaderPack pack, CallbackInfo ci) {
if (VoxyConfig.CONFIG.isRenderingEnabled()) {
if (VoxyConfig.CONFIG.isRenderingEnabled() && IrisUtil.SHADER_SUPPORT) {
this.patchData = IrisShaderPatch.makePatch(pack, directory, sourceProvider);
}
/*

View File

@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.client.core.util.IrisUtil;
import net.irisshaders.iris.gl.shader.StandardMacros;
import net.irisshaders.iris.helpers.StringPair;
import org.spongepowered.asm.mixin.Mixin;
@@ -20,7 +21,7 @@ public abstract class MixinStandardMacros {
@WrapOperation(method = "createStandardEnvironmentDefines", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/ImmutableList;copyOf(Ljava/util/Collection;)Lcom/google/common/collect/ImmutableList;"))
private static ImmutableList<StringPair> voxy$injectVoxyDefine(Collection<StringPair> list, Operation<ImmutableList<StringPair>> original) {
if (VoxyConfig.CONFIG.isRenderingEnabled()) {
if (VoxyConfig.CONFIG.isRenderingEnabled() && IrisUtil.SHADER_SUPPORT) {
define((List<StringPair>) list, "VOXY");
}
return ImmutableList.copyOf(list);

View File

@@ -119,6 +119,17 @@ void main() {
colour = textureLod(blockModelAtlas, texPos, 0);
}
//If we are in shaders and are a helper invocation, just exit, as it enables extra performance gains for small sized
// fragments, we do this here after derivative computation
//Trying it with all shaders
//#ifdef PATCHED_SHADER
#ifndef PATCHED_SHADER_ALLOW_DERIVATIVES
if (gl_HelperInvocation) {
return;
}
#endif
//#endif
if (any(notEqual(clamp(tile, vec2(0), vec2((interData.x>>8)&0xFu, (interData.x>>12)&0xFu)), tile))) {
discard;
}