From a950993034415700aeafb32eac3d51eb955fa0ad Mon Sep 17 00:00:00 2001 From: RiftomeR Date: Sat, 24 Nov 2018 21:44:56 +0300 Subject: [PATCH 1/2] Optimized textures Visible textures from chunks are now recalculated after update. --- .../textures/ChunkSpriteStorage.java | 54 ++++++++++++++++++ .../mixins/client/MixinRenderChunk.java | 57 +++++++++++++++++-- .../mixins/client/MixinTextureMap.java | 12 ++-- 3 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/dimdev/vanillafix/textures/ChunkSpriteStorage.java diff --git a/src/main/java/org/dimdev/vanillafix/textures/ChunkSpriteStorage.java b/src/main/java/org/dimdev/vanillafix/textures/ChunkSpriteStorage.java new file mode 100644 index 0000000..91d3ea9 --- /dev/null +++ b/src/main/java/org/dimdev/vanillafix/textures/ChunkSpriteStorage.java @@ -0,0 +1,54 @@ +package org.dimdev.vanillafix.textures; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.*; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class ChunkSpriteStorage { + private static Logger log = LogManager.getLogger (); + private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock (); + private static Map chunkSprites = new TreeMap<> (Comparator.comparing (TextureAtlasSprite::toString)); + + public static void addUsage (TextureAtlasSprite sprite) { + lock.writeLock ().lock (); + try { + if (chunkSprites.containsKey (sprite)) { + chunkSprites.put (sprite, chunkSprites.get (sprite) + 1); + } else { + chunkSprites.put (sprite, 1); + } + } finally { + lock.writeLock ().unlock (); + } + } + + public static void removeUsage (TextureAtlasSprite sprite) { + lock.writeLock ().lock (); + try { + if (chunkSprites.containsKey (sprite)) { + int i = chunkSprites.get (sprite); + if (i <= 1) { + chunkSprites.remove (sprite); + } else { + chunkSprites.put (sprite, i - 1); + } + } else { + log.error ("Tried to remove sprite, that has no usage"); + } + } finally { + lock.writeLock ().unlock (); + } + } + + public static List getUsedSprites () { + lock.readLock ().lock (); + try { + return new ArrayList<> (chunkSprites.keySet ()); + } finally { + lock.readLock ().unlock (); + } + } +} diff --git a/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinRenderChunk.java b/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinRenderChunk.java index e5792f5..3d5772a 100644 --- a/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinRenderChunk.java +++ b/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinRenderChunk.java @@ -3,21 +3,70 @@ import net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator; import net.minecraft.client.renderer.chunk.CompiledChunk; import net.minecraft.client.renderer.chunk.RenderChunk; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.math.BlockPos; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.dimdev.vanillafix.textures.ChunkSpriteStorage; +import org.dimdev.vanillafix.textures.IPatchedCompiledChunk; import org.dimdev.vanillafix.textures.TemporaryStorage; +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.LocalCapture; -@Mixin(RenderChunk.class) +@Mixin (RenderChunk.class) public class MixinRenderChunk { + @Shadow + public CompiledChunk compiledChunk; + @Shadow + @Final + private BlockPos.MutableBlockPos position; + private boolean animationsAdded = false; + private static final Logger vanillaFixLog = LogManager.getLogger ("VanillaFix RenderChunk"); + /** * @reason Store the chunk currently being rebuild in TemporaryStorage.currentCompiledChunk * by thread ID (there are multiple chunk renderer threads working at once). */ - @Inject(method = "rebuildChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/chunk/CompiledChunk;()V", ordinal = 0, shift = At.Shift.BY, by = 2), locals = LocalCapture.CAPTURE_FAILHARD) - private void onRebuildChunk(float x, float y, float z, ChunkCompileTaskGenerator generator, CallbackInfo ci, CompiledChunk compiledChunk) { - TemporaryStorage.currentCompiledChunk.set(compiledChunk); + @Inject (method = "rebuildChunk", at = @At (value = "INVOKE", target = "Lnet/minecraft/client/renderer/chunk/CompiledChunk;()V", ordinal = 0, shift = At.Shift.BY, by = 2), locals = LocalCapture.CAPTURE_FAILHARD) + private void onRebuildChunk (float x, float y, float z, ChunkCompileTaskGenerator generator, CallbackInfo ci, CompiledChunk compiledChunk) { + TemporaryStorage.currentCompiledChunk.set (compiledChunk); + } + + @Inject (method = "setCompiledChunk", at = @At ("HEAD")) + private void onSetCompiledChunkPre (CompiledChunk compiledChunkIn, CallbackInfo ci) { + removeAnimationsIfNeccessary (); + } + + private void addAnimationsIfNeccessary () { + if (!animationsAdded) { + for (TextureAtlasSprite sprite : ((IPatchedCompiledChunk) compiledChunk).getVisibleTextures ()) { + ChunkSpriteStorage.addUsage (sprite); + } + animationsAdded = true; + } + } + + private void removeAnimationsIfNeccessary () { + if ((compiledChunk != null) && animationsAdded) { + for (TextureAtlasSprite sprite : ((IPatchedCompiledChunk) compiledChunk).getVisibleTextures ()) { + ChunkSpriteStorage.removeUsage (sprite); + } + animationsAdded = false; + } + } + + @Inject (method = "setCompiledChunk", at = @At ("RETURN")) + private void onSetCompiledChunkPost (CompiledChunk compiledChunkIn, CallbackInfo ci) { + addAnimationsIfNeccessary (); + } + + @Inject (method = "stopCompileTask", at = @At ("HEAD")) + private void onStopCompileTask (CallbackInfo ci) { + removeAnimationsIfNeccessary (); } } diff --git a/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java b/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java index f9a8bda..4bc47c6 100644 --- a/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java +++ b/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java @@ -6,6 +6,7 @@ import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; +import org.dimdev.vanillafix.textures.ChunkSpriteStorage; import org.dimdev.vanillafix.textures.IPatchedCompiledChunk; import org.dimdev.vanillafix.textures.IPatchedTextureAtlasSprite; import org.spongepowered.asm.mixin.Final; @@ -30,10 +31,13 @@ public abstract class MixinTextureMap extends AbstractTexture { public void updateAnimations() { // TODO: Recalculate list after chunk update instead! Minecraft.getMinecraft().profiler.startSection("determineVisibleTextures"); - for (RenderGlobal.ContainerLocalRenderInformation renderInfo : Minecraft.getMinecraft().renderGlobal.renderInfos) { - for (TextureAtlasSprite texture : ((IPatchedCompiledChunk) renderInfo.renderChunk.compiledChunk).getVisibleTextures()) { - ((IPatchedTextureAtlasSprite) texture).markNeedsAnimationUpdate(); - } +// for (RenderGlobal.ContainerLocalRenderInformation renderInfo : Minecraft.getMinecraft().renderGlobal.renderInfos) { +// for (TextureAtlasSprite texture : ((IPatchedCompiledChunk) renderInfo.renderChunk.compiledChunk).getVisibleTextures()) { +// ((IPatchedTextureAtlasSprite) texture).markNeedsAnimationUpdate(); +// } +// } + for(TextureAtlasSprite sprite : ChunkSpriteStorage.getUsedSprites ()) { + ((IPatchedTextureAtlasSprite)sprite).markNeedsAnimationUpdate (); } Minecraft.getMinecraft().profiler.endSection(); From 41e04049c81ab43d9b45c7c66a03498306c23e2b Mon Sep 17 00:00:00 2001 From: RiftomeR Date: Sun, 25 Nov 2018 12:47:24 +0300 Subject: [PATCH 2/2] Refactored code --- .../textures/ChunkSpriteStorage.java | 13 +++++-- .../mixins/client/MixinTextureMap.java | 37 ++++++++----------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/dimdev/vanillafix/textures/ChunkSpriteStorage.java b/src/main/java/org/dimdev/vanillafix/textures/ChunkSpriteStorage.java index 91d3ea9..5f8d73d 100644 --- a/src/main/java/org/dimdev/vanillafix/textures/ChunkSpriteStorage.java +++ b/src/main/java/org/dimdev/vanillafix/textures/ChunkSpriteStorage.java @@ -4,12 +4,15 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.*; +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ChunkSpriteStorage { private static Logger log = LogManager.getLogger (); - private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock (); + private static ReadWriteLock lock = new ReentrantReadWriteLock (); private static Map chunkSprites = new TreeMap<> (Comparator.comparing (TextureAtlasSprite::toString)); public static void addUsage (TextureAtlasSprite sprite) { @@ -43,10 +46,12 @@ public static void removeUsage (TextureAtlasSprite sprite) { } } - public static List getUsedSprites () { + public static void markAnimationsForUpdate () { lock.readLock ().lock (); try { - return new ArrayList<> (chunkSprites.keySet ()); + for (TextureAtlasSprite sprite : chunkSprites.keySet ()) { + ((IPatchedTextureAtlasSprite) sprite).markNeedsAnimationUpdate (); + } } finally { lock.readLock ().unlock (); } diff --git a/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java b/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java index 4bc47c6..6f9c881 100644 --- a/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java +++ b/src/main/java/org/dimdev/vanillafix/textures/mixins/client/MixinTextureMap.java @@ -2,12 +2,10 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; import org.dimdev.vanillafix.textures.ChunkSpriteStorage; -import org.dimdev.vanillafix.textures.IPatchedCompiledChunk; import org.dimdev.vanillafix.textures.IPatchedTextureAtlasSprite; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -16,9 +14,12 @@ import java.util.List; -@Mixin(TextureMap.class) +@Mixin (TextureMap.class) public abstract class MixinTextureMap extends AbstractTexture { - @SuppressWarnings("ShadowModifiers" /*(AT)*/) @Shadow @Final private List listAnimatedSprites; + @SuppressWarnings ("ShadowModifiers" /*(AT)*/) + @Shadow + @Final + private List listAnimatedSprites; /** * @reason Replaces the updateAnimations method to only tick animated textures @@ -28,26 +29,18 @@ public abstract class MixinTextureMap extends AbstractTexture { * Also breaks down the "root.tick.textures" profiler by texture name. */ @Overwrite - public void updateAnimations() { - // TODO: Recalculate list after chunk update instead! - Minecraft.getMinecraft().profiler.startSection("determineVisibleTextures"); -// for (RenderGlobal.ContainerLocalRenderInformation renderInfo : Minecraft.getMinecraft().renderGlobal.renderInfos) { -// for (TextureAtlasSprite texture : ((IPatchedCompiledChunk) renderInfo.renderChunk.compiledChunk).getVisibleTextures()) { -// ((IPatchedTextureAtlasSprite) texture).markNeedsAnimationUpdate(); -// } -// } - for(TextureAtlasSprite sprite : ChunkSpriteStorage.getUsedSprites ()) { - ((IPatchedTextureAtlasSprite)sprite).markNeedsAnimationUpdate (); - } - Minecraft.getMinecraft().profiler.endSection(); + public void updateAnimations () { + Minecraft.getMinecraft ().profiler.startSection ("determineVisibleTextures"); + ChunkSpriteStorage.markAnimationsForUpdate (); + Minecraft.getMinecraft ().profiler.endSection (); - GlStateManager.bindTexture(getGlTextureId()); + GlStateManager.bindTexture (getGlTextureId ()); for (TextureAtlasSprite texture : listAnimatedSprites) { - if (((IPatchedTextureAtlasSprite) texture).needsAnimationUpdate()) { - Minecraft.getMinecraft().profiler.startSection(texture.getIconName()); - texture.updateAnimation(); - ((IPatchedTextureAtlasSprite) texture).unmarkNeedsAnimationUpdate(); // Can't do this from updateAnimation mixin, that method can be overriden - Minecraft.getMinecraft().profiler.endSection(); + if (((IPatchedTextureAtlasSprite) texture).needsAnimationUpdate ()) { + Minecraft.getMinecraft ().profiler.startSection (texture.getIconName ()); + texture.updateAnimation (); + ((IPatchedTextureAtlasSprite) texture).unmarkNeedsAnimationUpdate (); // Can't do this from updateAnimation mixin, that method can be overriden + Minecraft.getMinecraft ().profiler.endSection (); } } }