Shader lighting, fixes for loosing tasks in MultiThreadPrioritySemaphore, limit render generation rebuilds based on model queue and failure rate, fix native memory leak in ModelFactory (related to raw download stream)

This commit is contained in:
mcrcortex
2025-10-31 20:02:38 +10:00
parent 86882d5ac9
commit 5baf4ce2db
10 changed files with 70 additions and 37 deletions

View File

@@ -70,6 +70,7 @@ public class VoxyCommands {
} }
VoxyCommon.shutdownInstance(); VoxyCommon.shutdownInstance();
System.gc();
VoxyCommon.createInstance(); VoxyCommon.createInstance();
if (wr!=null) { if (wr!=null) {
((IGetVoxyRenderSystem)wr).createRenderer(); ((IGetVoxyRenderSystem)wr).createRenderer();

View File

@@ -77,6 +77,7 @@ public class VoxyRenderSystem {
//Keep the world loaded, NOTE: this is done FIRST, to keep and ensure that even if the rest of loading takes more //Keep the world loaded, NOTE: this is done FIRST, to keep and ensure that even if the rest of loading takes more
// than timeout, we keep the world acquired // than timeout, we keep the world acquired
world.acquireRef(); world.acquireRef();
System.gc();
//Fking HATE EVERYTHING AAAAAAAAAAAAAAAA //Fking HATE EVERYTHING AAAAAAAAAAAAAAAA
int[] oldBufferBindings = new int[10]; int[] oldBufferBindings = new int[10];

View File

@@ -33,7 +33,7 @@ public class ModelBakerySubsystem {
while (this.isRunning) { while (this.isRunning) {
this.factory.processAllThings(); this.factory.processAllThings();
try { try {
Thread.sleep(50); Thread.sleep(10);
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -913,14 +913,14 @@ public class ModelFactory {
} }
public void free() { public void free() {
this.bakery.free();
this.downstream.free();
while (!this.rawBakeResults.isEmpty()) { while (!this.rawBakeResults.isEmpty()) {
this.rawBakeResults.poll().rawData.free(); this.rawBakeResults.poll().rawData.free();
} }
while (!this.uploadResults.isEmpty()) { while (!this.uploadResults.isEmpty()) {
this.uploadResults.poll().free(); this.uploadResults.poll().free();
} }
this.downstream.free();
this.bakery.free();
} }
public int getBakedCount() { public int getBakedCount() {

View File

@@ -79,7 +79,7 @@ public class RenderGenerationService {
return new Pair<>(() -> { return new Pair<>(() -> {
this.processJob(factory, seenMissed); this.processJob(factory, seenMissed);
}, factory::free); }, factory::free);
}, 10, "Section mesh generation service"); }, 10, "Section mesh generation service", ()->modelBakery.getProcessingCount()<400||RenderGenerationService.MESH_FAILED_COUNTER.get()<500);
} }
public void setResultConsumer(Consumer<BuiltSection> consumer) { public void setResultConsumer(Consumer<BuiltSection> consumer) {
@@ -354,14 +354,12 @@ public class RenderGenerationService {
} }
private long lastChangedTime = 0; private long lastChangedTime = 0;
private int failedCounter = 0;
public void addDebugData(List<String> debug) { public void addDebugData(List<String> debug) {
if (System.currentTimeMillis()-this.lastChangedTime > 1000) { if (System.currentTimeMillis()-this.lastChangedTime > 100) {
this.failedCounter = 0; MESH_FAILED_COUNTER.set(0);
this.lastChangedTime = System.currentTimeMillis(); this.lastChangedTime = System.currentTimeMillis();
} }
this.failedCounter += MESH_FAILED_COUNTER.getAndSet(0); debug.add("RSSQ/TFC: " + this.taskQueueCount.get() + "/" + MESH_FAILED_COUNTER.get());//render section service queue, Task Fail Counter
debug.add("RSSQ/TFC: " + this.taskQueueCount.get() + "/" + this.failedCounter);//render section service queue, Task Fail Counter
} }

View File

@@ -80,6 +80,17 @@ public class RawDownloadStream {
} }
public void free() { public void free() {
glFinish();
this.tick();
GlFence fence = new GlFence();
while (!fence.signaled()) {
glFinish();
}
fence.free();
this.tick();
if (this.frames.size() != 0) {
throw new IllegalStateException();
}
this.frames.forEach(a->a.fence.free()); this.frames.forEach(a->a.fence.free());
this.downloadBuffer.free(); this.downloadBuffer.free();
} }

View File

@@ -4,6 +4,8 @@ import me.cortex.voxy.common.util.TrackedObject;
import java.util.*; import java.util.*;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.function.IntSupplier;
//Basiclly acts as a priority based mutlti semaphore //Basiclly acts as a priority based mutlti semaphore
// allows the pooling of multiple threadpools together while prioritizing the work the original was ment for // allows the pooling of multiple threadpools together while prioritizing the work the original was ment for
@@ -51,7 +53,9 @@ public class MultiThreadPrioritySemaphore {
if (this.localSemaphore.tryAcquire()) {//We prioritize locals first if (this.localSemaphore.tryAcquire()) {//We prioritize locals first
return; return;
} }
this.man.tryRun(this); if (this.man.tryRun(this)) {//Returns true if it captured a local job
break;
}
} else { } else {
this.localSemaphore.acquireUninterruptibly(); this.localSemaphore.acquireUninterruptibly();
if (!this.blockSemaphore.tryAcquire()) { if (!this.blockSemaphore.tryAcquire()) {
@@ -87,11 +91,11 @@ public class MultiThreadPrioritySemaphore {
} }
private final Semaphore pooledSemaphore = new Semaphore(0); private final Semaphore pooledSemaphore = new Semaphore(0);
private final Runnable executor; private final IntSupplier executor;
private volatile Block[] blocks = new Block[0]; private volatile Block[] blocks = new Block[0];
public MultiThreadPrioritySemaphore(Runnable executor) { public MultiThreadPrioritySemaphore(IntSupplier executor) {
this.executor = executor; this.executor = executor;
} }
@@ -136,7 +140,22 @@ public class MultiThreadPrioritySemaphore {
} }
}*/ }*/
//Run the pooled job //Run the pooled job
this.executor.run(); while (true) {
int status = this.executor.getAsInt();
if (status == 0) return false;//We finished pure and true
if (status == 1) return false;// we didnt run a job because there either wasnt any or no services exist
if (2 <= status) {//2 and 3 mean failed to find a service that can currently run, but should try again after a delay
try {
if (block.localSemaphore.tryAcquire(10, TimeUnit.MILLISECONDS)) {//Await 10 millis for a local job to come in
//We do this confusing thing
block.blockSemaphore.tryAcquire();//Try acquire the block that we just got
this.pooledRelease(1);//We need to release back into the pool
return true; return true;
} }
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
} }

View File

@@ -58,48 +58,49 @@ public class ServiceManager {
return newService; return newService;
} }
public boolean runAJob() {//Executes a single job on the current thread public int tryRunAJob() {//Executes a single job on the current thread
while (true) { if (this.services.length == 0 || this.totalJobs.get() == 0) return 1;
if (this.services.length == 0 || this.totalJobs.get() == 0) return false; return this.runAJob0();
if (this.runAJob0()) return true;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
} }
private boolean runAJob0() {//Executes a single job on the current thread private int runAJob0() {//Executes a single job on the current thread
if (this.services.length == 0) return false; if (this.services.length == 0) return 1;
var ctx = this.accelerationContext.get(); var ctx = this.accelerationContext.get();
outer: outer:
while (true) { while (true) {
long skipMsk = 0;
var services = this.services;//Capture the current services array var services = this.services;//Capture the current services array
if (services.length == 0) return false; if (services.length == 0) return 1;
if (this.totalJobs.get()==0) return false; if (this.totalJobs.get()==0) return 1;
long totalWeight = 0; long totalWeight = 0;
int shiftFactor = (ctx.shiftFactor++)&Integer.MAX_VALUE;//We cycle and shift the starting service when choosing to prevent bias int shiftFactor = (ctx.shiftFactor++)&Integer.MAX_VALUE;//We cycle and shift the starting service when choosing to prevent bias
int c = shiftFactor; int c = shiftFactor;
Service selectedService = null; Service selectedService = null;
for (var service:services) { for (int i = 0; i < services.length; i++) {
var service = services[i];
if (!service.isLive()) { if (!service.isLive()) {
Thread.yield(); Thread.yield();
continue outer;//We need to refetch the array and start over continue outer;//We need to refetch the array and start over
} }
boolean sc = c--<=0; boolean sc = c--<=0;
if (service.limiter!=null && !service.limiter.getAsBoolean()) continue; if (service.limiter!=null && !service.limiter.getAsBoolean()) {
skipMsk |= 1L<<i;
continue;
}
long jc = service.numJobs(); long jc = service.numJobs();
if (sc&&jc!=0&&selectedService==null) selectedService=service; if (sc&&jc!=0&&selectedService==null) selectedService=service;
totalWeight += jc * service.weight; totalWeight += jc * service.weight;
} }
if (totalWeight == 0) return false; if (totalWeight == 0) return skipMsk!=0?3:2;
long sample = ctx.rand(totalWeight);//Random number long sample = ctx.rand(totalWeight);//Random number
for (int i = 0; i < services.length; i++) { for (int i = 0; i < services.length; i++) {
var service = services[(i+shiftFactor)%services.length]; var service = services[(i+shiftFactor)%services.length];
if (service.limiter!=null && !service.limiter.getAsBoolean()) continue; if (service.limiter!=null && (((skipMsk&(1L<<i))!=0)|| !service.limiter.getAsBoolean())) {
skipMsk |= 1L<<i;
continue;
}
sample -= service.numJobs() * service.weight; sample -= service.numJobs() * service.weight;
if (sample<=0) { if (sample<=0) {
selectedService = service; selectedService = service;
@@ -108,7 +109,7 @@ public class ServiceManager {
} }
if (selectedService == null) { if (selectedService == null) {
return false; return skipMsk!=0?3:2;
} }
if (!selectedService.isLive()) { if (!selectedService.isLive()) {
@@ -124,7 +125,7 @@ public class ServiceManager {
} }
break; break;
} }
return true; return 0;
} }
public void shutdown() { public void shutdown() {

View File

@@ -18,7 +18,7 @@ public class UnifiedServiceThreadPool {
public UnifiedServiceThreadPool() { public UnifiedServiceThreadPool() {
this.dedicatedPool = new ThreadGroup("Voxy Dedicated Service"); this.dedicatedPool = new ThreadGroup("Voxy Dedicated Service");
this.serviceManager = new ServiceManager(this::release); this.serviceManager = new ServiceManager(this::release);
this.groupSemaphore = new MultiThreadPrioritySemaphore(this.serviceManager::runAJob); this.groupSemaphore = new MultiThreadPrioritySemaphore(this.serviceManager::tryRunAJob);
this.selfBlock = this.groupSemaphore.createBlock(); this.selfBlock = this.groupSemaphore.createBlock();
} }

View File

@@ -54,7 +54,7 @@ uint getFace() {
#ifdef PATCHED_SHADER #ifdef PATCHED_SHADER
vec2 getLightmap() { vec2 getLightmap() {
//return clamp(vec2(interData.y&0xFu, (interData.y>>4)&0xFu)/16, vec2(4.0f/255), vec2(252.0f/255)); //return clamp(vec2(interData.y&0xFu, (interData.y>>4)&0xFu)/16, vec2(4.0f/255), vec2(252.0f/255));
return vec2(interData.y&0xFu, (interData.y>>4)&0xFu)/15; return clamp((vec2((interData.y>>4)&0xFu, interData.y&0xFu))/16, vec2(8.0f/256), vec2(248.0f/256));
} }
#endif #endif
@@ -190,7 +190,9 @@ void main() {
tint = uint2vec4RGBA(interData.z).yzwx; tint = uint2vec4RGBA(interData.z).yzwx;
} }
voxy_emitFragment(VoxyFragmentParameters(colour, tile, texPos, getFace(), modelId, getLightmap().yx, tint, model.customId)); uint face = getFace();
face ^= uint((face&1u)!=uint(gl_FrontFacing!=((face>>1)!=0u)));
voxy_emitFragment(VoxyFragmentParameters(colour, tile, texPos, face, modelId, getLightmap(), tint, model.customId));
#endif #endif
} }