Implement chunk forcing during rendering for 1.15

This commit is contained in:
Jonas Herzig
2020-04-02 14:15:05 +02:00
parent 4ea13051fd
commit c119392c92
6 changed files with 230 additions and 37 deletions

View File

@@ -0,0 +1,111 @@
package com.replaymod.render.mixin;
//#if MC>=11500
//$$ import com.replaymod.render.hooks.ChunkLoadingRenderGlobal;
//$$ import net.minecraft.client.render.chunk.BlockBufferBuilderStorage;
//$$ import net.minecraft.client.render.chunk.ChunkBuilder;
//$$ import net.minecraft.util.thread.TaskExecutor;
//$$ import org.spongepowered.asm.mixin.Final;
//$$ import org.spongepowered.asm.mixin.Mixin;
//$$ import org.spongepowered.asm.mixin.Shadow;
//$$ import org.spongepowered.asm.mixin.injection.At;
//$$ import org.spongepowered.asm.mixin.injection.Inject;
//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
//$$
//$$ import java.util.Queue;
//$$ import java.util.concurrent.CompletableFuture;
//$$ import java.util.concurrent.locks.Condition;
//$$ import java.util.concurrent.locks.Lock;
//$$ import java.util.concurrent.locks.ReentrantLock;
//$$
//$$ @Mixin(ChunkBuilder.class)
//$$ public abstract class Mixin_BlockOnChunkRebuilds implements ChunkLoadingRenderGlobal.IBlockOnChunkRebuilds {
//$$ @Shadow @Final private Queue<BlockBufferBuilderStorage> threadBuffers;
//$$
//$$ @Shadow public abstract boolean upload();
//$$
//$$ @Shadow @Final private TaskExecutor<Runnable> mailbox;
//$$
//$$ @Shadow protected abstract void scheduleRunTasks();
//$$
//$$ @Shadow @Final private Queue<Runnable> uploadQueue;
//$$ private final Lock waitingForWorkLock = new ReentrantLock();
//$$ private final Condition newWork = waitingForWorkLock.newCondition();
//$$ private volatile boolean allDone;
//$$
//$$ private int totalBufferCount;
//$$
//$$ @Inject(method = "<init>", at = @At("RETURN"))
//$$ private void rememberTotalThreads(CallbackInfo ci) {
//$$ this.totalBufferCount = this.threadBuffers.size();
//$$ }
//$$
//$$ @Inject(method = "scheduleRunTasks", at = @At("RETURN"))
//$$ private void notifyMainThreadIfEverythingIsDone(CallbackInfo ci) {
//$$ if (this.threadBuffers.size() == this.totalBufferCount) {
//$$ // Looks like we're done, better notify the main thread in case the previous task didn't generate an upload
//$$ this.waitingForWorkLock.lock();
//$$ try {
//$$ this.allDone = true;
//$$ this.newWork.signalAll();
//$$ } finally {
//$$ this.waitingForWorkLock.unlock();
//$$ }
//$$ } else {
//$$ this.allDone = false;
//$$ }
//$$ }
//$$
//$$ @Inject(method = "scheduleUpload", at = @At("RETURN"))
//$$ private void notifyMainThreadOfNewUpload(CallbackInfoReturnable<CompletableFuture<Void>> ci) {
//$$ this.waitingForWorkLock.lock();
//$$ try {
//$$ this.newWork.signal();
//$$ } finally {
//$$ this.waitingForWorkLock.unlock();
//$$ }
//$$ }
//$$
//$$ private boolean waitForMainThreadWork() {
//$$ boolean allDone = this.mailbox.<Boolean>ask(reply -> () -> {
//$$ scheduleRunTasks();
//$$ reply.send(this.threadBuffers.size() == this.totalBufferCount);
//$$ }).join();
//$$
//$$ if (allDone) {
//$$ return true;
//$$ } else {
//$$ this.waitingForWorkLock.lock();
//$$ try {
//$$ while (true) {
//$$ if (this.allDone) {
//$$ return true;
//$$ } else if (!this.uploadQueue.isEmpty()) {
//$$ return false;
//$$ } else {
//$$ this.newWork.awaitUninterruptibly();
//$$ }
//$$ }
//$$ } finally {
//$$ this.waitingForWorkLock.unlock();
//$$ }
//$$ }
//$$ }
//$$
//$$ @Override
//$$ public boolean uploadEverythingBlocking() {
//$$ boolean anything = false;
//$$
//$$ boolean allChunksBuilt;
//$$ do {
//$$ allChunksBuilt = waitForMainThreadWork();
//$$ while (upload()) {
//$$ anything = true;
//$$ }
//$$ } while (!allChunksBuilt);
//$$
//$$ return anything;
//$$ }
//$$ }
//#endif

View File

@@ -1,17 +1,24 @@
//#if MC>=10800 && MC<11500
package com.replaymod.render.mixin;
//#if MC>=10800
import com.replaymod.render.hooks.ChunkLoadingRenderGlobal;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.Frustum;
import net.minecraft.client.render.chunk.ChunkBuilder;
import net.minecraft.client.render.VisibleRegion;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11400
//#if MC>=11500
//$$ import java.util.Set;
//#else
import net.minecraft.client.render.VisibleRegion;
import net.minecraft.entity.Entity;
//#endif
//#if MC>=11400 && MC<11500
import net.minecraft.client.render.Camera;
//#endif
@@ -32,8 +39,57 @@ import net.minecraft.client.render.WorldRenderer;
//#else
//$$ @Mixin(RenderGlobal.class)
//#endif
public abstract class MixinRenderGlobal {
public abstract class Mixin_ForceChunkLoading {
public ChunkLoadingRenderGlobal replayModRender_hook;
//#if MC>=11500
//$$ @Shadow private Set<ChunkBuilder.BuiltChunk> chunksToRebuild;
//$$
//$$ @Shadow private ChunkBuilder chunkBuilder;
//$$
//$$ @Shadow private boolean needsTerrainUpdate;
//$$
//$$ @Shadow public abstract void scheduleTerrainUpdate();
//$$
//$$ @Shadow protected abstract void setupTerrain(Camera camera_1, Frustum frustum_1, boolean boolean_1, int int_1, boolean boolean_2);
//$$
//$$ @Shadow private int frame;
//$$
//$$ private boolean passThrough;
//$$ @Inject(method = "setupTerrain", at = @At("HEAD"), cancellable = true)
//$$ private void forceAllChunks(Camera camera_1, Frustum frustum_1, boolean boolean_1, int int_1, boolean boolean_2, CallbackInfo ci) {
//$$ if (replayModRender_hook == null) {
//$$ return;
//$$ }
//$$ if (passThrough) {
//$$ return;
//$$ }
//$$ ci.cancel();
//$$
//$$ passThrough = true;
//$$ try {
//$$ do {
//$$ // Determine which chunks shall be visible
//$$ setupTerrain(camera_1, frustum_1, boolean_1, frame++, boolean_2);
//$$
//$$ // Schedule all chunks which need rebuilding (we schedule even important rebuilds because we wait for
//$$ // all of them anyway and this way we can take advantage of threading)
//$$ for (ChunkBuilder.BuiltChunk builtChunk : this.chunksToRebuild) {
//$$ builtChunk.scheduleRebuild(this.chunkBuilder);
//$$ builtChunk.cancelRebuild();
//$$ }
//$$ this.chunksToRebuild.clear();
//$$
//$$ // Upload all chunks
//$$ this.needsTerrainUpdate |= ((ChunkLoadingRenderGlobal.IBlockOnChunkRebuilds) this.chunkBuilder).uploadEverythingBlocking();
//$$
//$$ // Repeat until no more updates are needed
//$$ } while (this.needsTerrainUpdate);
//$$ } finally {
//$$ passThrough = false;
//$$ }
//$$ }
//#else
private boolean replayModRender_passThroughSetupTerrain;
@Shadow
@@ -132,5 +188,6 @@ public abstract class MixinRenderGlobal {
replayModRender_hook.updateRenderDispatcher(this.chunkBuilder);
}
}
//#endif
}
//#endif