Cache arrays used by RenderableBoxGroup

This commit is contained in:
James Seibel
2024-10-25 07:40:25 -05:00
parent 240a29803c
commit 0e3d978a1f
2 changed files with 97 additions and 6 deletions
@@ -0,0 +1,91 @@
package com.seibel.distanthorizons.core.render.renderer.generic;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalNotification;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import org.apache.logging.log4j.Logger;
import java.util.concurrent.ConcurrentMap;
/**
* @see RenderableBoxGroup
*/
public class RenderBoxArrayCache
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public static final int ARRAY_LENGTH_WIDTH = 24;
public static final int ARRAY_ID_WIDTH = 8;
public static final int ARRAY_LENGTH_OFFSET = 0;
public static final int ARRAY_ID_OFFSET = ARRAY_LENGTH_OFFSET + ARRAY_LENGTH_WIDTH;
public static final int ARRAY_LENGTH_MASK = (int) Math.pow(2, ARRAY_LENGTH_WIDTH) - 1;
public static final int ARRAY_ID_MASK = (int) Math.pow(2, ARRAY_ID_WIDTH) - 1;
private static final ConcurrentMap<Integer, float[]> FLOAT_ARRAY_BY_KEY = CacheBuilder.newBuilder()
// This number needs to be high enough so that
// the number of generic object groups won't cause array thrashing.
// For now 512 should be way more than needed, unless
// someone adds a boatload of random generic objects.
.maximumSize(512)
.removalListener((RemovalNotification<Integer, float[]> notification) -> { /* TODO log a warning if arrays start getting removed, that means we may need to re-think how the caching here works */ })
.build().asMap();
private static final ConcurrentMap<Integer, int[]> INT_ARRAY_BY_KEY = CacheBuilder.newBuilder()
.maximumSize(512)
.removalListener((RemovalNotification<Integer, int[]> notification) -> {})
.build().asMap();
//============//
// get arrays //
//============//
/**
* The ID parameter is to prevent returning the same array
* multiple times when the same length is requested.
*/
public static float[] getCachedFloatArray(int length, int id)
{
int key = encodeKey(length, id);
return FLOAT_ARRAY_BY_KEY.computeIfAbsent(key, (newKey) ->
{
int newLength = getLengthFromKey(newKey);
return new float[newLength];
});
}
public static int[] getCachedIntArray(int length, int id)
{
int key = encodeKey(length, id);
return INT_ARRAY_BY_KEY.computeIfAbsent(key, (newKey) ->
{
int newLength = getLengthFromKey(newKey);
return new int[newLength];
});
}
//==============//
// key encoding //
//==============//
private static int encodeKey(int arrayLength, int id)
{
if (id > Byte.MAX_VALUE)
{
throw new IndexOutOfBoundsException("The array's ID can only be 8 bytes long.");
}
int data = 0;
data |= (arrayLength & ARRAY_LENGTH_MASK);
data |= (id & ARRAY_ID_MASK) << ARRAY_ID_OFFSET;
return data;
}
private static int getLengthFromKey(int key) { return (key & ARRAY_LENGTH_MASK); }
private static int getIdFromKey(int key) { return ((key >> ARRAY_ID_OFFSET) & ARRAY_ID_MASK); }
}
@@ -24,7 +24,7 @@ public class RenderableBoxGroup
extends AbstractList<DhApiRenderableBox>
implements IDhApiRenderableBoxGroup, Closeable
{
public final static AtomicInteger NEXT_ID_ATOMIC_INT = new AtomicInteger(0);
public static final AtomicInteger NEXT_ID_ATOMIC_INT = new AtomicInteger(0);
@@ -247,9 +247,9 @@ public class RenderableBoxGroup
// transformation / scaling //
int[] chunkPosData = new int[boxCount * 3];
float[] subChunkPosData = new float[boxCount * 3];
float[] scalingData = new float[boxCount * 3];
int[] chunkPosData = RenderBoxArrayCache.getCachedIntArray(boxCount * 3, 0);
float[] subChunkPosData = RenderBoxArrayCache.getCachedFloatArray(boxCount * 3, 1);
float[] scalingData = RenderBoxArrayCache.getCachedFloatArray(boxCount * 3, 2);
for (int i = 0; i < boxCount; i++)
{
DhApiRenderableBox box = this.get(i);
@@ -272,8 +272,8 @@ public class RenderableBoxGroup
// colors/materials //
float[] colorData = new float[boxCount * 4];
int[] materialData = new int[boxCount];
float[] colorData = RenderBoxArrayCache.getCachedFloatArray(boxCount * 4, 3);
int[] materialData = RenderBoxArrayCache.getCachedIntArray(boxCount, 4);
for (int i = 0; i < boxCount; i++)
{
DhApiRenderableBox box = this.get(i);