Make generic object updating async
This commit is contained in:
+19
-10
@@ -48,8 +48,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAcce
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import org.lwjgl.opengl.ARBInstancedArrays;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.GL33;
|
||||
@@ -476,6 +474,18 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
continue;
|
||||
}
|
||||
|
||||
// update instanced data if needed
|
||||
if (useInstancedRendering)
|
||||
{
|
||||
boxGroup.tryUpdateInstancedDataAsync();
|
||||
|
||||
// skip groups that haven't been uploaded yet
|
||||
if (boxGroup.instancedVbos.state != InstancedVboContainer.EState.RENDER)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// render //
|
||||
@@ -535,7 +545,6 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
// update instance data //
|
||||
|
||||
profiler.push("vertex setup");
|
||||
boxGroup.updateVertexAttributeData();
|
||||
|
||||
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
|
||||
if (shading == null)
|
||||
@@ -553,27 +562,27 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
// Bind instance data //
|
||||
profiler.popPush("binding");
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instanceColorVbo);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instancedVbos.color);
|
||||
GL32.glEnableVertexAttribArray(1);
|
||||
GL32.glVertexAttribPointer(1, 4, GL32.GL_FLOAT, false, 4 * Float.BYTES, 0);
|
||||
this.vertexAttribDivisor(1, 1);
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instanceScaleVbo);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instancedVbos.scale);
|
||||
GL32.glEnableVertexAttribArray(2);
|
||||
this.vertexAttribDivisor(2, 1);
|
||||
GL32.glVertexAttribPointer(2, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instanceChunkPosVbo);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instancedVbos.chunkPos);
|
||||
GL32.glEnableVertexAttribArray(3);
|
||||
this.vertexAttribDivisor(3, 1);
|
||||
GL32.glVertexAttribIPointer(3, 3, GL32.GL_INT, 3 * Integer.BYTES, 0);
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instanceSubChunkPosVbo);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instancedVbos.subChunkPos);
|
||||
GL32.glEnableVertexAttribArray(4);
|
||||
this.vertexAttribDivisor(4, 1);
|
||||
GL32.glVertexAttribPointer(4, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instanceMaterialVbo);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, boxGroup.instancedVbos.material);
|
||||
GL32.glEnableVertexAttribArray(5);
|
||||
this.vertexAttribDivisor(5, 1);
|
||||
GL32.glVertexAttribIPointer(5, 1, GL32.GL_BYTE, Byte.BYTES, 0);
|
||||
@@ -581,9 +590,9 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
|
||||
// Draw instanced
|
||||
profiler.popPush("render");
|
||||
if (boxGroup.uploadedBoxCount > 0)
|
||||
if (boxGroup.instancedVbos.uploadedBoxCount > 0)
|
||||
{
|
||||
GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, boxGroup.uploadedBoxCount);
|
||||
GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, boxGroup.instancedVbos.uploadedBoxCount);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
package com.seibel.distanthorizons.core.render.renderer.generic;
|
||||
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* For use by {@link RenderableBoxGroup}
|
||||
*
|
||||
* @see RenderableBoxGroup
|
||||
*/
|
||||
public class InstancedVboContainer implements AutoCloseable
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class);
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
|
||||
|
||||
public int chunkPos = 0;
|
||||
public int subChunkPos = 0;
|
||||
public int scale = 0;
|
||||
public int color = 0;
|
||||
public int material = 0;
|
||||
|
||||
public int[] chunkPosData = new int[0];
|
||||
public float[] subChunkPosData = new float[0];
|
||||
public float[] scalingData = new float[0];
|
||||
public float[] colorData = new float[0];
|
||||
public int[] materialData = new int[0];
|
||||
|
||||
public int uploadedBoxCount = 0;
|
||||
|
||||
public EState state = EState.NEW;
|
||||
|
||||
|
||||
|
||||
//===========================//
|
||||
// render building/uploading //
|
||||
//===========================//
|
||||
//region
|
||||
|
||||
/** needs to be done on the render thread */
|
||||
public void tryRunRenderThreadSetup()
|
||||
{
|
||||
if (this.chunkPos == 0)
|
||||
{
|
||||
this.chunkPos = GLMC.glGenBuffers();
|
||||
this.subChunkPos = GLMC.glGenBuffers();
|
||||
this.scale = GLMC.glGenBuffers();
|
||||
this.color = GLMC.glGenBuffers();
|
||||
this.material = GLMC.glGenBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateVertexData(List<DhApiRenderableBox> uploadBoxList)
|
||||
{
|
||||
int boxCount = uploadBoxList.size();
|
||||
|
||||
|
||||
// recreate the data arrays if their size is different
|
||||
if (this.uploadedBoxCount != boxCount)
|
||||
{
|
||||
this.uploadedBoxCount = boxCount;
|
||||
|
||||
this.chunkPosData = new int[boxCount * 3]; // 3 elements XYZ
|
||||
this.subChunkPosData = new float[boxCount * 3]; // 3 elements XYZ
|
||||
this.scalingData = new float[boxCount * 3]; // 3 elements XYZ
|
||||
|
||||
this.colorData = new float[boxCount * 4]; // 4 elements, RGBA
|
||||
this.materialData = new int[boxCount];
|
||||
}
|
||||
|
||||
|
||||
// transformation / scaling //
|
||||
for (int i = 0; i < boxCount; i++)
|
||||
{
|
||||
DhApiRenderableBox box = uploadBoxList.get(i);
|
||||
|
||||
int dataIndex = i * 3;
|
||||
|
||||
this.chunkPosData[dataIndex] = LodUtil.getChunkPosFromDouble(box.minPos.x);
|
||||
this.chunkPosData[dataIndex + 1] = LodUtil.getChunkPosFromDouble(box.minPos.y);
|
||||
this.chunkPosData[dataIndex + 2] = LodUtil.getChunkPosFromDouble(box.minPos.z);
|
||||
|
||||
this.subChunkPosData[dataIndex] = LodUtil.getSubChunkPosFromDouble(box.minPos.x);
|
||||
this.subChunkPosData[dataIndex + 1] = LodUtil.getSubChunkPosFromDouble(box.minPos.y);
|
||||
this.subChunkPosData[dataIndex + 2] = LodUtil.getSubChunkPosFromDouble(box.minPos.z);
|
||||
|
||||
this.scalingData[dataIndex] = (float) (box.maxPos.x - box.minPos.x);
|
||||
this.scalingData[dataIndex + 1] = (float) (box.maxPos.y - box.minPos.y);
|
||||
this.scalingData[dataIndex + 2] = (float) (box.maxPos.z - box.minPos.z);
|
||||
}
|
||||
|
||||
|
||||
// colors/materials //
|
||||
for (int i = 0; i < boxCount; i++)
|
||||
{
|
||||
DhApiRenderableBox box = uploadBoxList.get(i);
|
||||
Color color = box.color;
|
||||
int colorIndex = i * 4;
|
||||
this.colorData[colorIndex] = color.getRed() / 255.0f;
|
||||
this.colorData[colorIndex + 1] = color.getGreen() / 255.0f;
|
||||
this.colorData[colorIndex + 2] = color.getBlue() / 255.0f;
|
||||
this.colorData[colorIndex + 3] = color.getAlpha() / 255.0f;
|
||||
|
||||
this.materialData[i] = box.material;
|
||||
}
|
||||
|
||||
this.state = InstancedVboContainer.EState.READY_TO_UPLOAD;
|
||||
}
|
||||
|
||||
public void uploadDataToGpu()
|
||||
{
|
||||
// Upload transformation matrices
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.chunkPos);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.chunkPosData, GL32.GL_DYNAMIC_DRAW);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.subChunkPos);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.subChunkPosData, GL32.GL_DYNAMIC_DRAW);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.scale);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.scalingData, GL32.GL_DYNAMIC_DRAW);
|
||||
|
||||
// Upload colors
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.color);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.colorData, GL32.GL_DYNAMIC_DRAW);
|
||||
|
||||
// Upload materials
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.material);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.materialData, GL32.GL_DYNAMIC_DRAW);
|
||||
|
||||
this.state = EState.RENDER;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
tryDeleteBuffer(this.chunkPos);
|
||||
tryDeleteBuffer(this.subChunkPos);
|
||||
tryDeleteBuffer(this.scale);
|
||||
tryDeleteBuffer(this.color);
|
||||
tryDeleteBuffer(this.material);
|
||||
}
|
||||
private static void tryDeleteBuffer(int bufferId)
|
||||
{
|
||||
// usually unnecessary, but just in case
|
||||
if (bufferId != 0)
|
||||
{
|
||||
GLMC.glDeleteBuffers(bufferId);
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
//region
|
||||
|
||||
public enum EState
|
||||
{
|
||||
NEW,
|
||||
UPDATING_DATA,
|
||||
READY_TO_UPLOAD,
|
||||
RENDER,
|
||||
|
||||
ERROR,
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
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 com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* @see RenderableBoxGroup
|
||||
*/
|
||||
public class RenderBoxArrayCache
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
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); }
|
||||
|
||||
}
|
||||
+64
-112
@@ -5,28 +5,23 @@ import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhAp
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.ColumnRenderBufferBuilder;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
|
||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.Closeable;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.UnaryOperator;
|
||||
@@ -36,6 +31,8 @@ public class RenderableBoxGroup
|
||||
extends AbstractList<DhApiRenderableBox>
|
||||
implements IDhApiRenderableBoxGroup, Closeable
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class);
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
@@ -70,13 +67,10 @@ public class RenderableBoxGroup
|
||||
public Consumer<DhApiRenderParam> afterRenderFunc;
|
||||
|
||||
// instance data
|
||||
public int instanceColorVbo = 0;
|
||||
public int instanceMaterialVbo = 0;
|
||||
public int instanceScaleVbo = 0;
|
||||
public int instanceChunkPosVbo = 0;
|
||||
public int instanceSubChunkPosVbo = 0;
|
||||
public InstancedVboContainer instancedVbos = new InstancedVboContainer();
|
||||
/** double buffering for thread safety and to prevent locking the render thread during update */
|
||||
private InstancedVboContainer altInstancedVbos = new InstancedVboContainer();
|
||||
|
||||
public int uploadedBoxCount = -1;
|
||||
|
||||
|
||||
//=================//
|
||||
@@ -194,24 +188,52 @@ public class RenderableBoxGroup
|
||||
@Override
|
||||
public void triggerBoxChange() { this.vertexDataDirty = true; }
|
||||
|
||||
/** Does nothing if the vertex data is already up-to-date */
|
||||
public void updateVertexAttributeData()
|
||||
/**
|
||||
* Does nothing if the vertex data is already up-to-date
|
||||
* and is meaningless if using direct rendering.
|
||||
*/
|
||||
public void tryUpdateInstancedDataAsync()
|
||||
{
|
||||
// if the alt container is done, swap it in
|
||||
if (this.altInstancedVbos.state == InstancedVboContainer.EState.READY_TO_UPLOAD)
|
||||
{
|
||||
this.altInstancedVbos.uploadDataToGpu();
|
||||
|
||||
// swap VBO references for rendering
|
||||
InstancedVboContainer temp = this.instancedVbos;
|
||||
this.instancedVbos = this.altInstancedVbos;
|
||||
this.altInstancedVbos = temp;
|
||||
|
||||
this.vertexDataDirty = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if the vertex data is already up to date, do nothing
|
||||
if (!this.vertexDataDirty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.vertexDataDirty = false;
|
||||
|
||||
if (this.instanceChunkPosVbo == 0)
|
||||
PriorityTaskPicker.Executor executor = ThreadPoolUtil.getRenderLoadingExecutor();
|
||||
if (executor == null || executor.isTerminated())
|
||||
{
|
||||
this.instanceChunkPosVbo = GLMC.glGenBuffers();
|
||||
this.instanceSubChunkPosVbo = GLMC.glGenBuffers();
|
||||
this.instanceScaleVbo = GLMC.glGenBuffers();
|
||||
this.instanceColorVbo = GLMC.glGenBuffers();
|
||||
this.instanceMaterialVbo = GLMC.glGenBuffers();
|
||||
return;
|
||||
}
|
||||
|
||||
// if the alternate container is already updating, don't double-queue it
|
||||
if (this.altInstancedVbos.state == InstancedVboContainer.EState.UPDATING_DATA)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.altInstancedVbos.state = InstancedVboContainer.EState.UPDATING_DATA;
|
||||
|
||||
|
||||
|
||||
this.altInstancedVbos.tryRunRenderThreadSetup();
|
||||
|
||||
// copy over the box list so we can upload without concurrent modification issues
|
||||
this.uploadBoxList.clear();
|
||||
synchronized (this.uploadBoxList)
|
||||
@@ -219,69 +241,26 @@ public class RenderableBoxGroup
|
||||
this.uploadBoxList.addAll(this.boxList);
|
||||
}
|
||||
|
||||
|
||||
int boxCount = this.uploadBoxList.size();
|
||||
this.uploadedBoxCount = boxCount;
|
||||
|
||||
|
||||
|
||||
// transformation / scaling //
|
||||
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++)
|
||||
try
|
||||
{
|
||||
DhApiRenderableBox box = this.uploadBoxList.get(i);
|
||||
|
||||
int dataIndex = i * 3;
|
||||
|
||||
chunkPosData[dataIndex] = LodUtil.getChunkPosFromDouble(box.minPos.x);
|
||||
chunkPosData[dataIndex + 1] = LodUtil.getChunkPosFromDouble(box.minPos.y);
|
||||
chunkPosData[dataIndex + 2] = LodUtil.getChunkPosFromDouble(box.minPos.z);
|
||||
|
||||
subChunkPosData[dataIndex] = LodUtil.getSubChunkPosFromDouble(box.minPos.x);
|
||||
subChunkPosData[dataIndex + 1] = LodUtil.getSubChunkPosFromDouble(box.minPos.y);
|
||||
subChunkPosData[dataIndex + 2] = LodUtil.getSubChunkPosFromDouble(box.minPos.z);
|
||||
|
||||
scalingData[dataIndex] = (float) (box.maxPos.x - box.minPos.x);
|
||||
scalingData[dataIndex + 1] = (float) (box.maxPos.y - box.minPos.y);
|
||||
scalingData[dataIndex + 2] = (float) (box.maxPos.z - box.minPos.z);
|
||||
|
||||
executor.runTask(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
this.altInstancedVbos.updateVertexData(this.uploadBoxList);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unexpected error updating instanced VBO data for: ["+this+"], error: ["+e.getMessage()+"].", e);
|
||||
this.altInstancedVbos.state = InstancedVboContainer.EState.ERROR;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// colors/materials //
|
||||
float[] colorData = RenderBoxArrayCache.getCachedFloatArray(boxCount * 4, 3);
|
||||
int[] materialData = RenderBoxArrayCache.getCachedIntArray(boxCount, 4);
|
||||
for (int i = 0; i < boxCount; i++)
|
||||
catch (RejectedExecutionException ignore)
|
||||
{
|
||||
DhApiRenderableBox box = this.uploadBoxList.get(i);
|
||||
Color color = box.color;
|
||||
int colorIndex = i * 4;
|
||||
colorData[colorIndex] = color.getRed() / 255.0f;
|
||||
colorData[colorIndex + 1] = color.getGreen() / 255.0f;
|
||||
colorData[colorIndex + 2] = color.getBlue() / 255.0f;
|
||||
colorData[colorIndex + 3] = color.getAlpha() / 255.0f;
|
||||
|
||||
materialData[i] = box.material;
|
||||
// the executor was shut down, it should be back up shortly and able to accept new jobs
|
||||
this.altInstancedVbos.state = InstancedVboContainer.EState.NEW;
|
||||
}
|
||||
|
||||
|
||||
// Upload transformation matrices
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceChunkPosVbo);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, chunkPosData, GL32.GL_DYNAMIC_DRAW);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceSubChunkPosVbo);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, subChunkPosData, GL32.GL_DYNAMIC_DRAW);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceScaleVbo);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, scalingData, GL32.GL_DYNAMIC_DRAW);
|
||||
|
||||
// Upload colors
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceColorVbo);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, colorData, GL32.GL_DYNAMIC_DRAW);
|
||||
|
||||
// Upload materials
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceMaterialVbo);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, materialData, GL32.GL_DYNAMIC_DRAW);
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -362,42 +341,15 @@ public class RenderableBoxGroup
|
||||
//region
|
||||
|
||||
@Override
|
||||
public String toString() { return "ID:["+this.id+"], pos:["+this.originBlockPos.x+","+this.originBlockPos.y+","+this.originBlockPos.z+"], size:["+this.size()+"], active:["+this.active+"]"; }
|
||||
public String toString() { return "["+this.resourceLocationNamespace+":"+this.resourceLocationPath+"] ID:["+this.id+"], pos:["+this.originBlockPos.x+","+this.originBlockPos.y+","+this.originBlockPos.z+"], size:["+this.size()+"], active:["+this.active+"]"; }
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
GLProxy.queueRunningOnRenderThread(() ->
|
||||
{
|
||||
if (this.instanceChunkPosVbo != 0)
|
||||
{
|
||||
GLMC.glDeleteBuffers(this.instanceChunkPosVbo);
|
||||
this.instanceChunkPosVbo = 0;
|
||||
}
|
||||
|
||||
if (this.instanceSubChunkPosVbo != 0)
|
||||
{
|
||||
GLMC.glDeleteBuffers(this.instanceSubChunkPosVbo);
|
||||
this.instanceSubChunkPosVbo = 0;
|
||||
}
|
||||
|
||||
if (this.instanceScaleVbo != 0)
|
||||
{
|
||||
GLMC.glDeleteBuffers(this.instanceScaleVbo);
|
||||
this.instanceScaleVbo = 0;
|
||||
}
|
||||
|
||||
if (this.instanceColorVbo != 0)
|
||||
{
|
||||
GLMC.glDeleteBuffers(this.instanceColorVbo);
|
||||
this.instanceColorVbo = 0;
|
||||
}
|
||||
|
||||
if (this.instanceMaterialVbo != 0)
|
||||
{
|
||||
GLMC.glDeleteBuffers(this.instanceMaterialVbo);
|
||||
this.instanceMaterialVbo = 0;
|
||||
}
|
||||
this.instancedVbos.close();
|
||||
this.altInstancedVbos.close();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user