Added build task removal
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package me.cortex.voxy.client.core.rendering.building;
|
package me.cortex.voxy.client.core.rendering.building;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||||
import me.cortex.voxy.client.core.model.IdNotYetComputedException;
|
import me.cortex.voxy.client.core.model.IdNotYetComputedException;
|
||||||
import me.cortex.voxy.client.core.model.ModelBakerySubsystem;
|
import me.cortex.voxy.client.core.model.ModelBakerySubsystem;
|
||||||
@@ -16,8 +17,13 @@ import java.util.function.Supplier;
|
|||||||
|
|
||||||
//TODO: Add a render cache
|
//TODO: Add a render cache
|
||||||
public class RenderGenerationService {
|
public class RenderGenerationService {
|
||||||
public interface TaskChecker {boolean check(int lvl, int x, int y, int z);}
|
private static final class BuildTask {
|
||||||
private record BuildTask(long position, Supplier<WorldSection> sectionSupplier, boolean[] hasDoneModelRequest) {}
|
final long position;
|
||||||
|
boolean hasDoneModelRequest;
|
||||||
|
private BuildTask(long position) {
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final Long2ObjectLinkedOpenHashMap<BuildTask> taskQueue = new Long2ObjectLinkedOpenHashMap<>();
|
private final Long2ObjectLinkedOpenHashMap<BuildTask> taskQueue = new Long2ObjectLinkedOpenHashMap<>();
|
||||||
|
|
||||||
@@ -61,6 +67,10 @@ public class RenderGenerationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WorldSection acquireSection(long pos) {
|
||||||
|
return this.world.acquireIfExists(pos);
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: add a generated render data cache
|
//TODO: add a generated render data cache
|
||||||
private void processJob(RenderDataFactory factory) {
|
private void processJob(RenderDataFactory factory) {
|
||||||
BuildTask task;
|
BuildTask task;
|
||||||
@@ -72,7 +82,7 @@ public class RenderGenerationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//long time = BuiltSection.getTime();
|
//long time = BuiltSection.getTime();
|
||||||
var section = task.sectionSupplier.get();
|
var section = this.acquireSection(task.position);
|
||||||
if (section == null) {
|
if (section == null) {
|
||||||
this.resultConsumer.accept(BuiltSection.empty(task.position));
|
this.resultConsumer.accept(BuiltSection.empty(task.position));
|
||||||
return;
|
return;
|
||||||
@@ -85,7 +95,7 @@ public class RenderGenerationService {
|
|||||||
if (!this.modelBakery.factory.hasModelForBlockId(e.id)) {
|
if (!this.modelBakery.factory.hasModelForBlockId(e.id)) {
|
||||||
this.modelBakery.requestBlockBake(e.id);
|
this.modelBakery.requestBlockBake(e.id);
|
||||||
}
|
}
|
||||||
if (task.hasDoneModelRequest[0]) {
|
if (task.hasDoneModelRequest) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
@@ -95,11 +105,18 @@ public class RenderGenerationService {
|
|||||||
//The reason for the extra id parameter is that we explicitly add/check against the exception id due to e.g. requesting accross a chunk boarder wont be captured in the request
|
//The reason for the extra id parameter is that we explicitly add/check against the exception id due to e.g. requesting accross a chunk boarder wont be captured in the request
|
||||||
this.computeAndRequestRequiredModels(section, e.id);
|
this.computeAndRequestRequiredModels(section, e.id);
|
||||||
}
|
}
|
||||||
//We need to reinsert the build task into the queue
|
|
||||||
//System.err.println("Render task failed to complete due to un-computed client id");
|
{
|
||||||
synchronized (this.taskQueue) {
|
//We need to reinsert the build task into the queue
|
||||||
var queuedTask = this.taskQueue.computeIfAbsent(section.key, (a)->task);
|
BuildTask queuedTask;
|
||||||
queuedTask.hasDoneModelRequest[0] = true;//Mark (or remark) the section as having chunks requested
|
synchronized (this.taskQueue) {
|
||||||
|
queuedTask = this.taskQueue.putIfAbsent(section.key, task);
|
||||||
|
}
|
||||||
|
if (queuedTask == null) {
|
||||||
|
queuedTask = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
queuedTask.hasDoneModelRequest = true;//Mark (or remark) the section as having chunks requested
|
||||||
|
|
||||||
if (queuedTask == task) {//use the == not .equal to see if we need to release a permit
|
if (queuedTask == task) {//use the == not .equal to see if we need to release a permit
|
||||||
this.threads.execute();//Since we put in queue, release permit
|
this.threads.execute();//Since we put in queue, release permit
|
||||||
@@ -113,37 +130,34 @@ public class RenderGenerationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enqueueTask(int lvl, int x, int y, int z) {
|
|
||||||
this.enqueueTask(lvl, x, y, z, (l,x1,y1,z1)->true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enqueueTask(long position) {
|
public void enqueueTask(long pos) {
|
||||||
this.enqueueTask(position, (l,x1,y1,z1)->true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enqueueTask(int lvl, int x, int y, int z, TaskChecker checker) {
|
|
||||||
this.enqueueTask(WorldEngine.getWorldSectionId(lvl, x, y, z), checker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enqueueTask(long ikey, TaskChecker checker) {
|
|
||||||
synchronized (this.taskQueue) {
|
synchronized (this.taskQueue) {
|
||||||
this.taskQueue.computeIfAbsent(ikey, key->{
|
this.taskQueue.computeIfAbsent(pos, key->{
|
||||||
this.threads.execute();
|
this.threads.execute();
|
||||||
return new BuildTask(ikey, ()->{
|
return new BuildTask(key);
|
||||||
if (checker.check(WorldEngine.getLevel(ikey), WorldEngine.getX(ikey), WorldEngine.getY(ikey), WorldEngine.getZ(ikey))) {
|
|
||||||
return this.world.acquireIfExists(WorldEngine.getLevel(ikey), WorldEngine.getX(ikey), WorldEngine.getY(ikey), WorldEngine.getZ(ikey));
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}, new boolean[1]);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTaskCount() {
|
public void removeTask(long pos) {
|
||||||
return this.threads.getJobCount();
|
BuildTask task;
|
||||||
|
synchronized (this.taskQueue) {
|
||||||
|
task = this.taskQueue.remove(pos);
|
||||||
|
}
|
||||||
|
if (task != null) {
|
||||||
|
if (!this.threads.steal()) {
|
||||||
|
throw new IllegalStateException("Failed to steal a task!!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public void enqueueTask(int lvl, int x, int y, int z) {
|
||||||
|
this.enqueueTask(WorldEngine.getWorldSectionId(lvl, x, y, z));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
this.threads.shutdown();
|
this.threads.shutdown();
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,9 @@ public class ServiceSlice extends TrackedObject {
|
|||||||
if (this.activeCount.decrementAndGet() < 0) {
|
if (this.activeCount.decrementAndGet() < 0) {
|
||||||
throw new IllegalStateException("Alive count negative!");
|
throw new IllegalStateException("Alive count negative!");
|
||||||
}
|
}
|
||||||
this.jobCount2.decrementAndGet();
|
if (this.jobCount2.decrementAndGet() < 0) {
|
||||||
|
throw new IllegalStateException("Job count negative!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -133,4 +135,16 @@ public class ServiceSlice extends TrackedObject {
|
|||||||
Thread.yield();
|
Thread.yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Steal a job, if there is no job available return false
|
||||||
|
public boolean steal() {
|
||||||
|
if (!this.jobCount.tryAcquire()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.jobCount2.decrementAndGet() < 0) {
|
||||||
|
throw new IllegalStateException("Job count negative!!!");
|
||||||
|
}
|
||||||
|
this.threadPool.steal(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,11 @@ public class ServiceThreadPool {
|
|||||||
this.jobCounter.release(1);
|
this.jobCounter.release(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void steal(ServiceSlice service) {
|
||||||
|
this.totalJobWeight.addAndGet(-service.weightPerJob);
|
||||||
|
this.jobCounter.acquireUninterruptibly(1);
|
||||||
|
}
|
||||||
|
|
||||||
private void worker(int threadId) {
|
private void worker(int threadId) {
|
||||||
long seed = 1234342;
|
long seed = 1234342;
|
||||||
int revolvingSelector = 0;
|
int revolvingSelector = 0;
|
||||||
|
|||||||
@@ -30,7 +30,10 @@ public class ActiveSectionTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public WorldSection acquire(int lvl, int x, int y, int z, boolean nullOnEmpty) {
|
public WorldSection acquire(int lvl, int x, int y, int z, boolean nullOnEmpty) {
|
||||||
long key = WorldEngine.getWorldSectionId(lvl, x, y, z);
|
return this.acquire(WorldEngine.getWorldSectionId(lvl, x, y, z), nullOnEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorldSection acquire(long key, boolean nullOnEmpty) {
|
||||||
var cache = this.loadedSectionCache[this.getCacheArrayIndex(key)];
|
var cache = this.loadedSectionCache[this.getCacheArrayIndex(key)];
|
||||||
VolatileHolder<WorldSection> holder = null;
|
VolatileHolder<WorldSection> holder = null;
|
||||||
boolean isLoader = false;
|
boolean isLoader = false;
|
||||||
@@ -50,7 +53,12 @@ public class ActiveSectionTracker {
|
|||||||
|
|
||||||
//If this thread was the one to create the reference then its the thread to load the section
|
//If this thread was the one to create the reference then its the thread to load the section
|
||||||
if (isLoader) {
|
if (isLoader) {
|
||||||
var section = new WorldSection(lvl, x, y, z, this);
|
var section = new WorldSection(WorldEngine.getLevel(key),
|
||||||
|
WorldEngine.getX(key),
|
||||||
|
WorldEngine.getY(key),
|
||||||
|
WorldEngine.getZ(key),
|
||||||
|
this);
|
||||||
|
|
||||||
int status = -1;//this.dataCache.load(section);
|
int status = -1;//this.dataCache.load(section);
|
||||||
if (status == -1) {//Cache miss
|
if (status == -1) {//Cache miss
|
||||||
status = this.loader.load(section);
|
status = this.loader.load(section);
|
||||||
@@ -85,7 +93,7 @@ public class ActiveSectionTracker {
|
|||||||
return section;
|
return section;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.acquire(lvl, x, y, z, nullOnEmpty);
|
return this.acquire(key, nullOnEmpty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public class WorldEngine {
|
|||||||
public static final int UPDATE_TYPE_BLOCK_BIT = 1;
|
public static final int UPDATE_TYPE_BLOCK_BIT = 1;
|
||||||
public static final int UPDATE_TYPE_CHILD_EXISTENCE_BIT = 2;
|
public static final int UPDATE_TYPE_CHILD_EXISTENCE_BIT = 2;
|
||||||
public static final int UPDATE_FLAGS = UPDATE_TYPE_BLOCK_BIT | UPDATE_TYPE_CHILD_EXISTENCE_BIT;
|
public static final int UPDATE_FLAGS = UPDATE_TYPE_BLOCK_BIT | UPDATE_TYPE_CHILD_EXISTENCE_BIT;
|
||||||
|
|
||||||
public interface ISectionChangeCallback {void accept(WorldSection section, int updateFlags);}
|
public interface ISectionChangeCallback {void accept(WorldSection section, int updateFlags);}
|
||||||
|
|
||||||
|
|
||||||
@@ -77,6 +78,14 @@ public class WorldEngine {
|
|||||||
return this.sectionTracker.acquire(lvl, x, y, z, false);
|
return this.sectionTracker.acquire(lvl, x, y, z, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WorldSection acquire(long pos) {
|
||||||
|
return this.sectionTracker.acquire(pos, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorldSection acquireIfExists(long pos) {
|
||||||
|
return this.sectionTracker.acquire(pos, true);
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: Fixme/optimize, cause as the lvl gets higher, the size of x,y,z gets smaller so i can dynamically compact the format
|
//TODO: Fixme/optimize, cause as the lvl gets higher, the size of x,y,z gets smaller so i can dynamically compact the format
|
||||||
// depending on the lvl, which should optimize colisions and whatnot
|
// depending on the lvl, which should optimize colisions and whatnot
|
||||||
public static long getWorldSectionId(int lvl, int x, int y, int z) {
|
public static long getWorldSectionId(int lvl, int x, int y, int z) {
|
||||||
|
|||||||
Reference in New Issue
Block a user