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

Optimized textures #135

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
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.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 ReadWriteLock lock = new ReentrantReadWriteLock ();
private static Map<TextureAtlasSprite, Integer> 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 void markAnimationsForUpdate () {
lock.readLock ().lock ();
try {
for (TextureAtlasSprite sprite : chunkSprites.keySet ()) {
((IPatchedTextureAtlasSprite) sprite).markNeedsAnimationUpdate ();
}
} finally {
lock.readLock ().unlock ();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;<init>()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;<init>()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 ();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +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.IPatchedCompiledChunk;
import org.dimdev.vanillafix.textures.ChunkSpriteStorage;
import org.dimdev.vanillafix.textures.IPatchedTextureAtlasSprite;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
Expand All @@ -15,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<TextureAtlasSprite> listAnimatedSprites;
@SuppressWarnings ("ShadowModifiers" /*(AT)*/)
@Shadow
@Final
private List<TextureAtlasSprite> listAnimatedSprites;

/**
* @reason Replaces the updateAnimations method to only tick animated textures
Expand All @@ -27,23 +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();
}
}
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 ();
}
}
}
Expand Down