Geometry cleaner works again
This commit is contained in:
@@ -8,6 +8,7 @@ import me.cortex.voxy.client.core.gl.Capabilities;
|
|||||||
import me.cortex.voxy.client.core.model.bakery.ModelTextureBakery;
|
import me.cortex.voxy.client.core.model.bakery.ModelTextureBakery;
|
||||||
import me.cortex.voxy.client.core.rendering.util.RawDownloadStream;
|
import me.cortex.voxy.client.core.rendering.util.RawDownloadStream;
|
||||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
|
import me.cortex.voxy.common.util.MemoryBuffer;
|
||||||
import me.cortex.voxy.common.world.other.Mapper;
|
import me.cortex.voxy.common.world.other.Mapper;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@@ -35,6 +36,7 @@ import org.lwjgl.system.MemoryUtil;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static me.cortex.voxy.client.core.model.ModelStore.MODEL_SIZE;
|
import static me.cortex.voxy.client.core.model.ModelStore.MODEL_SIZE;
|
||||||
|
import static org.lwjgl.opengl.ARBDirectStateAccess.nglTextureSubImage2D;
|
||||||
import static org.lwjgl.opengl.GL11.*;
|
import static org.lwjgl.opengl.GL11.*;
|
||||||
import static org.lwjgl.opengl.GL33.glDeleteSamplers;
|
import static org.lwjgl.opengl.GL33.glDeleteSamplers;
|
||||||
import static org.lwjgl.opengl.GL33.glGenSamplers;
|
import static org.lwjgl.opengl.GL33.glGenSamplers;
|
||||||
@@ -661,8 +663,54 @@ public class ModelFactory {
|
|||||||
return this.metadataCache[clientId];
|
return this.metadataCache[clientId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static int computeSizeWithMips(int size) {
|
||||||
|
int total = 0;
|
||||||
|
for (;size!=0;size>>=1) total += size*size;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
private static final MemoryBuffer SCRATCH_TEX = new MemoryBuffer((2L*3*computeSizeWithMips(MODEL_TEXTURE_SIZE))*4);
|
||||||
|
private static final int LAYERS = Integer.numberOfTrailingZeros(MODEL_TEXTURE_SIZE);
|
||||||
//TODO: redo to batch blit, instead of 6 seperate blits, and also fix mipping
|
//TODO: redo to batch blit, instead of 6 seperate blits, and also fix mipping
|
||||||
private void putTextures(int id, ColourDepthTextureData[] textures) {
|
private void putTextures(int id, ColourDepthTextureData[] textures) {
|
||||||
|
if (MODEL_TEXTURE_SIZE != 16) {throw new IllegalStateException("THIS METHOD MUST BE REDONE IF THIS CONST CHANGES");}
|
||||||
|
|
||||||
|
|
||||||
|
//Copy all textures into scratch
|
||||||
|
final long addr = SCRATCH_TEX.address;
|
||||||
|
final int LENGTH_B = MODEL_TEXTURE_SIZE*3;
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
int x = (i>>1)*MODEL_TEXTURE_SIZE;
|
||||||
|
int y = (i&1)*MODEL_TEXTURE_SIZE;
|
||||||
|
int j = 0;
|
||||||
|
for (int t : textures[i].colour()) {
|
||||||
|
int o = ((y+(j>>LAYERS))*LENGTH_B + ((j&(MODEL_TEXTURE_SIZE-1))+x))*4; j++;//LAYERS here is just cause faster
|
||||||
|
MemoryUtil.memPutInt(addr+o, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Mip the scratch
|
||||||
|
long dAddr = addr;
|
||||||
|
for (int i = 0; i < LAYERS-1; i++) {
|
||||||
|
long sAddr = dAddr;
|
||||||
|
dAddr += (MODEL_TEXTURE_SIZE*MODEL_TEXTURE_SIZE*3*2*4)>>(i<<1);//is.. i*2 because shrink both MODEL_TEXTURE_SIZE by >>i so is 2*i total shift
|
||||||
|
int width = (MODEL_TEXTURE_SIZE*3)>>(i+1);
|
||||||
|
int sWidth = (MODEL_TEXTURE_SIZE*3)>>i;
|
||||||
|
int height = (MODEL_TEXTURE_SIZE*2)>>(i+1);
|
||||||
|
//TODO: OPTIMZIE THIS
|
||||||
|
for (int px = 0; px < width; px++) {
|
||||||
|
for (int py = 0; py < height; py++) {
|
||||||
|
long bp = sAddr + (px*2 + py*2*sWidth)*4;
|
||||||
|
int C00 = MemoryUtil.memGetInt(bp);
|
||||||
|
int C01 = MemoryUtil.memGetInt(bp+sWidth*4);
|
||||||
|
int C10 = MemoryUtil.memGetInt(bp+4);
|
||||||
|
int C11 = MemoryUtil.memGetInt(bp+sWidth*4+4);
|
||||||
|
MemoryUtil.memPutInt(dAddr + (px+py*width) * 4L, TextureUtils.mipColours(C00, C01, C10, C11));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int X = (id&0xFF) * MODEL_TEXTURE_SIZE*3;
|
int X = (id&0xFF) * MODEL_TEXTURE_SIZE*3;
|
||||||
int Y = ((id>>8)&0xFF) * MODEL_TEXTURE_SIZE*2;
|
int Y = ((id>>8)&0xFF) * MODEL_TEXTURE_SIZE*2;
|
||||||
|
|
||||||
@@ -671,31 +719,10 @@ public class ModelFactory {
|
|||||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
|
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||||
|
|
||||||
for (int subTex = 0; subTex < 6; subTex++) {
|
long cAddr = addr;
|
||||||
int x = X + (subTex>>1)*MODEL_TEXTURE_SIZE;
|
for (int lvl = 0; lvl < LAYERS; lvl++) {
|
||||||
int y = Y + (subTex&1)*MODEL_TEXTURE_SIZE;
|
nglTextureSubImage2D(this.storage.textures.id, lvl, X >> lvl, Y >> lvl, (MODEL_TEXTURE_SIZE*3) >> lvl, (MODEL_TEXTURE_SIZE*2) >> lvl, GL_RGBA, GL_UNSIGNED_BYTE, cAddr);
|
||||||
|
cAddr += (MODEL_TEXTURE_SIZE*MODEL_TEXTURE_SIZE*3*2*4)>>(lvl<<1);
|
||||||
var current = textures[subTex].colour();
|
|
||||||
var next = new int[current.length>>1];
|
|
||||||
final int layers = Integer.numberOfTrailingZeros(MODEL_TEXTURE_SIZE);
|
|
||||||
for (int i = 0; i < layers; i++) {
|
|
||||||
glTextureSubImage2D(this.storage.textures.id, i, x>>i, y>>i, MODEL_TEXTURE_SIZE>>i, MODEL_TEXTURE_SIZE>>i, GL_RGBA, GL_UNSIGNED_BYTE, current);
|
|
||||||
|
|
||||||
int nSize = MODEL_TEXTURE_SIZE>>(i+1);
|
|
||||||
int size = MODEL_TEXTURE_SIZE>>i;
|
|
||||||
for (int pX = 0; pX < nSize; pX++) {
|
|
||||||
for (int pY = 0; pY < nSize; pY++) {
|
|
||||||
int C00 = current[(pY*2)*size+pX*2];
|
|
||||||
int C01 = current[(pY*2+1)*size+pX*2];
|
|
||||||
int C10 = current[(pY*2)*size+pX*2+1];
|
|
||||||
int C11 = current[(pY*2+1)*size+pX*2+1];
|
|
||||||
next[pY*nSize+pX] = TextureUtils.mipColours(C00, C01, C10, C11);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current = next;
|
|
||||||
next = new int[current.length>>1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
|||||||
import me.cortex.voxy.common.Logger;
|
import me.cortex.voxy.common.Logger;
|
||||||
import me.cortex.voxy.common.util.MemoryBuffer;
|
import me.cortex.voxy.common.util.MemoryBuffer;
|
||||||
import me.cortex.voxy.common.world.WorldSection;
|
import me.cortex.voxy.common.world.WorldSection;
|
||||||
import net.fabricmc.loader.impl.util.log.Log;
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
@@ -27,7 +26,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.concurrent.locks.LockSupport;
|
import java.util.concurrent.locks.LockSupport;
|
||||||
import java.util.concurrent.locks.StampedLock;
|
import java.util.concurrent.locks.StampedLock;
|
||||||
|
|
||||||
import static me.cortex.voxy.client.core.rendering.section.geometry.BasicSectionGeometryData.SECTION_METADATA_SIZE;
|
|
||||||
import static org.lwjgl.opengl.ARBUniformBufferObject.glBindBufferBase;
|
import static org.lwjgl.opengl.ARBUniformBufferObject.glBindBufferBase;
|
||||||
import static org.lwjgl.opengl.GL30C.glUniform1ui;
|
import static org.lwjgl.opengl.GL30C.glUniform1ui;
|
||||||
import static org.lwjgl.opengl.GL42C.GL_UNIFORM_BARRIER_BIT;
|
import static org.lwjgl.opengl.GL42C.GL_UNIFORM_BARRIER_BIT;
|
||||||
@@ -57,6 +55,7 @@ public class AsyncNodeManager {
|
|||||||
|
|
||||||
private final Thread thread;
|
private final Thread thread;
|
||||||
public final int maxNodeCount;
|
public final int maxNodeCount;
|
||||||
|
private final long geometryCapacity;
|
||||||
private volatile boolean running = true;
|
private volatile boolean running = true;
|
||||||
|
|
||||||
private final NodeManager manager;
|
private final NodeManager manager;
|
||||||
@@ -70,7 +69,7 @@ public class AsyncNodeManager {
|
|||||||
private volatile SyncResults resultCache2 = new SyncResults();
|
private volatile SyncResults resultCache2 = new SyncResults();
|
||||||
|
|
||||||
//Yes. this is stupid. yes. it is a large amount of runtime. Is it profiler bias, probably
|
//Yes. this is stupid. yes. it is a large amount of runtime. Is it profiler bias, probably
|
||||||
private ConcurrentLinkedDeque<MemoryBuffer> buffersToFreeQueue = new ConcurrentLinkedDeque<>();
|
private final ConcurrentLinkedDeque<MemoryBuffer> buffersToFreeQueue = new ConcurrentLinkedDeque<>();
|
||||||
|
|
||||||
|
|
||||||
//locals for during iteration
|
//locals for during iteration
|
||||||
@@ -86,8 +85,10 @@ public class AsyncNodeManager {
|
|||||||
// it MUST ONLY be accessed on the render thread
|
// it MUST ONLY be accessed on the render thread
|
||||||
// AsyncNodeManager will use an AsyncGeometryManager as the manager for the data store, and sync the results on the render thread
|
// AsyncNodeManager will use an AsyncGeometryManager as the manager for the data store, and sync the results on the render thread
|
||||||
this.geometryData = geometryData;
|
this.geometryData = geometryData;
|
||||||
|
this.geometryCapacity = ((BasicSectionGeometryData)geometryData).getGeometryCapacityBytes();
|
||||||
|
|
||||||
this.maxNodeCount = maxNodeCount;
|
this.maxNodeCount = maxNodeCount;
|
||||||
|
|
||||||
this.thread = new Thread(()->{
|
this.thread = new Thread(()->{
|
||||||
try {
|
try {
|
||||||
while (this.running) {
|
while (this.running) {
|
||||||
@@ -99,7 +100,7 @@ public class AsyncNodeManager {
|
|||||||
});
|
});
|
||||||
this.thread.setName("Async Node Manager");
|
this.thread.setName("Async Node Manager");
|
||||||
|
|
||||||
this.geometryManager = new BasicAsyncGeometryManager(((BasicSectionGeometryData)geometryData).getMaxSectionCount(), ((BasicSectionGeometryData)geometryData).getGeometryCapacity());
|
this.geometryManager = new BasicAsyncGeometryManager(((BasicSectionGeometryData)geometryData).getMaxSectionCount(), this.geometryCapacity);
|
||||||
this.manager = new NodeManager(maxNodeCount, this.geometryManager, watcher);
|
this.manager = new NodeManager(maxNodeCount, this.geometryManager, watcher);
|
||||||
//Dont do the move... is just to much effort
|
//Dont do the move... is just to much effort
|
||||||
this.manager.setClear(new NodeManager.ICleaner() {
|
this.manager.setClear(new NodeManager.ICleaner() {
|
||||||
@@ -446,6 +447,7 @@ public class AsyncNodeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
results.geometrySectionCount = this.geometryManager.getSectionCount();
|
results.geometrySectionCount = this.geometryManager.getSectionCount();
|
||||||
|
results.usedGeometry = this.geometryManager.getGeometryUsedBytes();
|
||||||
results.currentMaxNodeId = this.manager.getCurrentMaxNodeId();
|
results.currentMaxNodeId = this.manager.getCurrentMaxNodeId();
|
||||||
|
|
||||||
this.needsWaitForSync |= results.geometryUploads.size() > UPLOAD_LIMIT;//Max of 200 uploads per frame :(
|
this.needsWaitForSync |= results.geometryUploads.size() > UPLOAD_LIMIT;//Max of 200 uploads per frame :(
|
||||||
@@ -520,6 +522,7 @@ public class AsyncNodeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.currentMaxNodeId = results.currentMaxNodeId;
|
this.currentMaxNodeId = results.currentMaxNodeId;
|
||||||
|
this.usedGeometryAmount = results.usedGeometry;
|
||||||
|
|
||||||
//Insert the result set into the cache
|
//Insert the result set into the cache
|
||||||
if (!RESULT_CACHE_1_HANDLE.compareAndSet(this, null, results)) {
|
if (!RESULT_CACHE_1_HANDLE.compareAndSet(this, null, results)) {
|
||||||
@@ -541,6 +544,16 @@ public class AsyncNodeManager {
|
|||||||
return this.currentMaxNodeId;
|
return this.currentMaxNodeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long usedGeometryAmount = 0;
|
||||||
|
public long getUsedGeometryCapacity() {
|
||||||
|
return this.usedGeometryAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getGeometryCapacity() {
|
||||||
|
return this.geometryCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//==================================================================================================================
|
//==================================================================================================================
|
||||||
//Incoming events
|
//Incoming events
|
||||||
|
|
||||||
@@ -700,6 +713,7 @@ public class AsyncNodeManager {
|
|||||||
|
|
||||||
//Deltas for geometry store
|
//Deltas for geometry store
|
||||||
private int geometrySectionCount;
|
private int geometrySectionCount;
|
||||||
|
private long usedGeometry;
|
||||||
private final Int2ObjectOpenHashMap<MemoryBuffer> geometryUploads = new Int2ObjectOpenHashMap<>();
|
private final Int2ObjectOpenHashMap<MemoryBuffer> geometryUploads = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -136,7 +136,8 @@ public class NodeCleaner {
|
|||||||
//return this.nodeManager.getGeometryManager().getRemainingCapacity() < 1_000_000_000L;
|
//return this.nodeManager.getGeometryManager().getRemainingCapacity() < 1_000_000_000L;
|
||||||
|
|
||||||
//If used more than 75% of geometry buffer
|
//If used more than 75% of geometry buffer
|
||||||
return false;//return 3<((double)this.nodeManager.getGeometryManager().getUsedCapacity())/((double)this.nodeManager.getGeometryManager().getRemainingCapacity());
|
long used = this.nodeManager.getUsedGeometryCapacity();
|
||||||
|
return 1<((double)used)/((double)(this.nodeManager.getGeometryCapacity()-used));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateIds(IntOpenHashSet collection) {
|
public void updateIds(IntOpenHashSet collection) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public class BasicAsyncGeometryManager implements IGeometryManager {
|
|||||||
//Note!: the int part is an unsigned int ptr, must be scaled by GEOMETRY_ELEMENT_SIZE
|
//Note!: the int part is an unsigned int ptr, must be scaled by GEOMETRY_ELEMENT_SIZE
|
||||||
private final Int2ObjectOpenHashMap<MemoryBuffer> heapUploads = new Int2ObjectOpenHashMap<>(1024);//Uploads into the buffer at the given location
|
private final Int2ObjectOpenHashMap<MemoryBuffer> heapUploads = new Int2ObjectOpenHashMap<>(1024);//Uploads into the buffer at the given location
|
||||||
private final IntOpenHashSet heapRemoveUploads = new IntOpenHashSet(1024);//Any removals are added here, so that it can be properly synced
|
private final IntOpenHashSet heapRemoveUploads = new IntOpenHashSet(1024);//Any removals are added here, so that it can be properly synced
|
||||||
|
private long usedCapacity = 0;
|
||||||
|
|
||||||
public BasicAsyncGeometryManager(int maxSectionCount, long geometryCapacity) {
|
public BasicAsyncGeometryManager(int maxSectionCount, long geometryCapacity) {
|
||||||
this.allocationSet = new HierarchicalBitSet(maxSectionCount);
|
this.allocationSet = new HierarchicalBitSet(maxSectionCount);
|
||||||
@@ -85,7 +86,7 @@ public class BasicAsyncGeometryManager implements IGeometryManager {
|
|||||||
var oldMetadata = this.sectionMetadata.set(id, null);
|
var oldMetadata = this.sectionMetadata.set(id, null);
|
||||||
int ptr = oldMetadata.geometryPtr;
|
int ptr = oldMetadata.geometryPtr;
|
||||||
//Free from the heap
|
//Free from the heap
|
||||||
this.allocationHeap.free(Integer.toUnsignedLong(ptr));
|
this.usedCapacity -= this.allocationHeap.free(Integer.toUnsignedLong(ptr));
|
||||||
//Free the upload if it was uploading
|
//Free the upload if it was uploading
|
||||||
var buf = this.heapUploads.remove(ptr);
|
var buf = this.heapUploads.remove(ptr);
|
||||||
if (buf != null) {
|
if (buf != null) {
|
||||||
@@ -100,6 +101,7 @@ public class BasicAsyncGeometryManager implements IGeometryManager {
|
|||||||
int size = (int) (section.geometryBuffer.size/GEOMETRY_ELEMENT_SIZE);
|
int size = (int) (section.geometryBuffer.size/GEOMETRY_ELEMENT_SIZE);
|
||||||
//Address
|
//Address
|
||||||
int addr = (int)this.allocationHeap.alloc(size);
|
int addr = (int)this.allocationHeap.alloc(size);
|
||||||
|
this.usedCapacity += size;
|
||||||
//Create upload
|
//Create upload
|
||||||
if (this.heapUploads.put(addr, section.geometryBuffer) != null) {
|
if (this.heapUploads.put(addr, section.geometryBuffer) != null) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
@@ -126,6 +128,10 @@ public class BasicAsyncGeometryManager implements IGeometryManager {
|
|||||||
return this.allocationSet.getCount();
|
return this.allocationSet.getCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getGeometryUsedBytes() {
|
||||||
|
return this.usedCapacity * GEOMETRY_ELEMENT_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
public IntOpenHashSet getUpdateIds() {
|
public IntOpenHashSet getUpdateIds() {
|
||||||
return this.invalidatedIds;
|
return this.invalidatedIds;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class BasicSectionGeometryData implements IGeometryData {
|
|||||||
return this.maxSectionCount;
|
return this.maxSectionCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getGeometryCapacity() {//In bytes
|
public long getGeometryCapacityBytes() {//In bytes
|
||||||
return this.geometryBuffer.size();
|
return this.geometryBuffer.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user