Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration with Asynchronous Render List Generation in Sodium #2539

Draft
wants to merge 9 commits into
base: 1.21.4
Choose a base branch
from
51 changes: 0 additions & 51 deletions .github/workflows/build-release.yml

This file was deleted.

32 changes: 0 additions & 32 deletions .github/workflows/build.yml

This file was deleted.

5 changes: 4 additions & 1 deletion common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ dependencies {

modCompileOnly("net.fabricmc.fabric-api:fabric-renderer-api-v1:3.2.9+1172e897d7")

modImplementation("maven.modrinth", "sodium", "mc1.21.4-0.6.2-fabric")
// modImplementation("maven.modrinth", "sodium", "mc1.21-0.6.0-beta.2-fabric")
modImplementation("net.caffeinemc", "fabric", "0.6.6-snapshot+mc1.21.4-local") {
isChanging = true
}
modCompileOnly("org.antlr:antlr4-runtime:4.13.1")
modCompileOnly("io.github.douira:glsl-transformer:2.0.1")
modCompileOnly("org.anarres:jcpp:1.4.14")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public MixinAdvancedShadowCullingFrustum(Matrix4f matrix4f, Matrix4f matrix4f2)
}

@Shadow(remap = false)
protected int isVisible(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
protected boolean isVisibleBool(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
throw new IllegalStateException();
}

Expand All @@ -33,6 +33,6 @@ public void update(int worldMinBlockY, int worldMaxBlockY, DhApiMat4f worldViewP

@Override
public boolean intersects(int lodBlockPosMinX, int lodBlockPosMinZ, int lodBlockWidth, int lodDetailLevel) {
return this.isVisible(lodBlockPosMinX, this.worldMinYDH, lodBlockPosMinZ, lodBlockPosMinX + lodBlockWidth, this.worldMaxYDH, lodBlockPosMinZ + lodBlockWidth) != 0;
return this.isVisibleBool(lodBlockPosMinX, this.worldMinYDH, lodBlockPosMinZ, lodBlockPosMinX + lodBlockWidth, this.worldMaxYDH, lodBlockPosMinZ + lodBlockWidth);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package net.irisshaders.iris.compat.sodium.mixin;

import net.caffeinemc.mods.sodium.client.render.chunk.lists.ChunkRenderList;
import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegion;
import net.irisshaders.iris.compat.sodium.mixinterface.ShadowRenderRegion;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;

@Mixin(RenderRegion.class)
public class MixinRenderRegion implements ShadowRenderRegion {
@Final
@Shadow
@Mutable
private ChunkRenderList renderList;

@Unique
ChunkRenderList regularRenderList;

@Unique
ChunkRenderList shadowRenderList;

@Unique
@Override
public void swapToShadowRenderList() {
this.regularRenderList = this.renderList;
this.renderList = this.shadowRenderList;
this.ensureRenderList();
}

@Unique
@Override
public void swapToRegularRenderList() {
this.shadowRenderList = this.renderList;
this.renderList = this.regularRenderList;
this.ensureRenderList();
}

@Unique
private void ensureRenderList() {
if (this.renderList == null) {
this.renderList = new ChunkRenderList((RenderRegion) (Object) this);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,105 +1,137 @@
package net.irisshaders.iris.compat.sodium.mixin;

import net.caffeinemc.mods.sodium.client.gl.device.CommandList;
import net.caffeinemc.mods.sodium.client.render.chunk.ChunkUpdateType;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSection;
import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager;
import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionInfo;
import net.caffeinemc.mods.sodium.client.render.chunk.lists.SortedRenderLists;
import net.caffeinemc.mods.sodium.client.render.chunk.lists.VisibleChunkCollectorAsync;
import net.caffeinemc.mods.sodium.client.render.chunk.region.RenderRegionManager;
import net.caffeinemc.mods.sodium.client.render.chunk.tree.RemovableMultiForest;
import net.caffeinemc.mods.sodium.client.render.viewport.Viewport;
import net.irisshaders.iris.compat.sodium.mixinterface.ShadowRenderRegion;
import net.irisshaders.iris.shadows.ShadowRenderingState;
import net.minecraft.client.Camera;
import net.minecraft.client.multiplayer.ClientLevel;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.ArrayDeque;
import java.util.EnumMap;
import java.util.Map;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(RenderSectionManager.class)
public class MixinRenderSectionManagerShadow {
public abstract class MixinRenderSectionManagerShadow {
@Shadow(remap = false)
private @NotNull SortedRenderLists renderLists;

@Shadow(remap = false)
private @NotNull Map<ChunkUpdateType, ArrayDeque<RenderSection>> taskLists;
private boolean needsRenderListUpdate;

@Shadow
private int lastUpdatedFrame;
@Final
private RenderRegionManager regions;
@Shadow
private int frame;

@Unique
private @NotNull SortedRenderLists shadowRenderLists = SortedRenderLists.empty();

@Unique
private boolean shadowNeedsRenderListUpdate = true;

@Unique
private @NotNull Map<ChunkUpdateType, ArrayDeque<RenderSection>> shadowTaskLists = new EnumMap<>(ChunkUpdateType.class);
private int lastUpdatedFrameShadow;

@Inject(method = "<init>", at = @At("TAIL"))
private void create(ClientLevel level, int renderDistance, CommandList commandList, CallbackInfo ci) {
for (int var6 = 0; var6 < ChunkUpdateType.values().length; ++var6) {
ChunkUpdateType type = ChunkUpdateType.values()[var6];
shadowTaskLists.put(type, new ArrayDeque<>());
private boolean renderListStateIsShadow = false;

@WrapOperation(method = "notifyChangedCamera", at = @At(value = "FIELD", target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager;cameraChanged:Z"))
private void notifyChangedCamera(RenderSectionManager instance, boolean value, Operation<Void> original) {
if (!ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
original.call(instance, value);
return;
}

this.shadowNeedsRenderListUpdate = true;
}

@Redirect(remap = false, method = "createTerrainRenderList", at = @At(value = "FIELD", target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager;renderLists:Lnet/caffeinemc/mods/sodium/client/render/chunk/lists/SortedRenderLists;"))
private void useShadowRenderList(RenderSectionManager instance, SortedRenderLists value) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
shadowRenderLists = value;
} else {
renderLists = value;
}
@Inject(method = "updateRenderLists", at = @At(target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/occlusion/AsyncCameraTimingControl;getShouldRenderSync(Lnet/minecraft/client/Camera;)Z", value = "INVOKE"))
private void updateRenderLists(Camera camera, Viewport viewport, boolean spectator, boolean updateImmediately, CallbackInfo ci) {
this.shadowNeedsRenderListUpdate |= this.needsRenderListUpdate;
}

@Redirect(remap = false, method = "createTerrainRenderList", at = @At(value = "FIELD", target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager;taskLists:Ljava/util/Map;"))
private void useShadowTaskrList(RenderSectionManager instance, @NotNull Map<ChunkUpdateType, ArrayDeque<RenderSection>> value) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
shadowTaskLists = value;
} else {
taskLists = value;
@Shadow(remap = false)
public abstract int getVisibleChunkCount();

@Shadow(remap = false)
public abstract int getTotalSections();

@Shadow
@Final
private RemovableMultiForest renderableSectionTree;

@Shadow
protected abstract float getSearchDistance();

@Inject(method = "updateRenderLists", at = @At("HEAD"), cancellable = true)
private void updateShadowRenderLists(Camera camera, Viewport viewport, boolean spectator, boolean updateImmediately, CallbackInfo ci) {
if (!ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
if (this.renderListStateIsShadow) {
for (var region : this.regions.getLoadedRegions()) {
((ShadowRenderRegion) region).swapToRegularRenderList();
}
this.renderListStateIsShadow = false;
}
return;
}
}

@Inject(method = "update", at = @At(value = "INVOKE", target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager;createTerrainRenderList(Lnet/minecraft/client/Camera;Lnet/caffeinemc/mods/sodium/client/render/viewport/Viewport;IZ)V", shift = At.Shift.AFTER), cancellable = true)
private void cancelIfShadow(Camera camera, Viewport viewport, boolean spectator, CallbackInfo ci) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) ci.cancel();
}
if (this.shadowNeedsRenderListUpdate) {
if (!this.renderListStateIsShadow) {
for (var region : this.regions.getLoadedRegions()) {
((ShadowRenderRegion) region).swapToShadowRenderList();
}
this.renderListStateIsShadow = true;
}

@Redirect(method = {
"getRenderLists",
"getVisibleChunkCount",
"renderLayer"
}, at = @At(value = "FIELD", target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager;renderLists:Lnet/caffeinemc/mods/sodium/client/render/chunk/lists/SortedRenderLists;"), remap = false)
private SortedRenderLists useShadowRenderList2(RenderSectionManager instance) {
return ShadowRenderingState.areShadowsCurrentlyBeingRendered() ? shadowRenderLists : renderLists;
}
var visibleCollector = new VisibleChunkCollectorAsync(this.regions, -this.frame);
this.renderableSectionTree.prepareForTraversal();
this.renderableSectionTree.traverse(visibleCollector, viewport, this.getSearchDistance());
this.shadowRenderLists = visibleCollector.createRenderLists(viewport);
}

@Inject(method = "updateChunks", at = @At("HEAD"), cancellable = true, remap = false)
private void doNotUpdateDuringShadow(boolean updateImmediately, CallbackInfo ci) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) ci.cancel();
this.shadowNeedsRenderListUpdate = false;
ci.cancel();
}

@Inject(method = "uploadChunks", at = @At("HEAD"), cancellable = true, remap = false)
private void doNotUploadDuringShadow(CallbackInfo ci) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) ci.cancel();
@Inject(method = "updateSectionInfo", at = @At("HEAD"))
private void updateSectionInfo(RenderSection render, BuiltSectionInfo info, CallbackInfoReturnable<Boolean> cir) {
this.shadowNeedsRenderListUpdate = true;
}

@Redirect(method = {
"resetRenderLists",
"submitSectionTasks(Lnet/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector;Lnet/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector;Lnet/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector;)V"
}, at = @At(value = "FIELD", target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager;taskLists:Ljava/util/Map;"), remap = false)
private @NotNull Map<ChunkUpdateType, ArrayDeque<RenderSection>> useShadowTaskList3(RenderSectionManager instance) {
return ShadowRenderingState.areShadowsCurrentlyBeingRendered() ? shadowTaskLists : taskLists;
@Inject(method = "onSectionRemoved", at = @At("HEAD"))
private void onSectionRemoved(int x, int y, int z, CallbackInfo ci) {
this.shadowNeedsRenderListUpdate = true;
}

@Redirect(method = {
"resetRenderLists"
"getRenderLists",
"getVisibleChunkCount",
"renderLayer"
}, at = @At(value = "FIELD", target = "Lnet/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager;renderLists:Lnet/caffeinemc/mods/sodium/client/render/chunk/lists/SortedRenderLists;"), remap = false)
private void useShadowRenderList3(RenderSectionManager instance, SortedRenderLists value) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) shadowRenderLists = value;
else renderLists = value;
private SortedRenderLists useShadowRenderList(RenderSectionManager instance) {
return ShadowRenderingState.areShadowsCurrentlyBeingRendered() ? this.shadowRenderLists : this.renderLists;
}

@Inject(method = "getChunksDebugString", at = @At("HEAD"), cancellable = true)
private void getShadowChunksDebugString(CallbackInfoReturnable<String> cir) {
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
var renderLists = this.renderLists;
this.renderLists = this.shadowRenderLists;
cir.setReturnValue(String.format("C: %d/%d", this.getVisibleChunkCount(), this.getTotalSections()));
this.renderLists = renderLists;
cir.cancel();
}
}
}
Loading