This commit is contained in:
mcrcortex
2024-07-30 15:08:49 +10:00
parent 433f3ace9f
commit 7703e2fb0f
6 changed files with 12 additions and 115 deletions

View File

@@ -568,9 +568,6 @@ public class ModelFactory {
}
private ModelTextureUpload putTextures(int id, ColourDepthTextureData[] textures) {
int X = (id&0xFF) * MODEL_TEXTURE_SIZE*3;
int Y = ((id>>8)&0xFF) * MODEL_TEXTURE_SIZE*2;
int texIndex = 0;
int[][] texData = new int[6*4][];
for (int subTex = 0; subTex < 6; subTex++) {

View File

@@ -116,7 +116,7 @@ public class ModelTextureBakery {
.getBlockModels()
.getModel(state);
var entityModel = state.hasBlockEntity()?BakedBlockEntityModel.bake(state):null;
BakedBlockEntityModel entityModel = state.hasBlockEntity()?BakedBlockEntityModel.bake(state):null;
int oldFB = GlStateManager.getBoundFramebuffer();
GL11C.glViewport(0, 0, this.width, this.height);
@@ -282,14 +282,17 @@ public class ModelTextureBakery {
//System.err.println("REPLACE THE UPLOADING WITH THREAD SAFE VARIENT");
BufferRenderer.draw(bb.end());
} catch (IllegalStateException e) {
System.err.println("Got empty buffer builder! for block " + state);
//System.err.println("Got empty buffer builder! for block " + state);
}
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
int[] colourData = new int[this.width*this.height];
int[] depthData = new int[this.width*this.height];
glGetTextureImage(this.colourTex.id, 0, GL_RGBA, GL_UNSIGNED_BYTE, colourData);
glGetTextureImage(this.depthTex.id, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, depthData);
//TODO: USE A PBO to make a download stream of the textures to a buffer to download then do a download stream
//glGetTextureImage(this.colourTex.id, 0, GL_RGBA, GL_UNSIGNED_BYTE, colourData);
//glGetTextureImage(this.depthTex.id, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, depthData);
return new ColourDepthTextureData(colourData, depthData, this.width, this.height);
}

View File

@@ -1,100 +0,0 @@
package me.cortex.voxy.client.core.model;
import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue;
import it.unimi.dsi.fastutil.ints.IntLinkedOpenHashSet;
import me.cortex.voxy.common.world.other.Mapper;
import net.minecraft.client.MinecraftClient;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLCapabilities;
import java.lang.invoke.VarHandle;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.Semaphore;
//Uses an off thread gl context to do the model baking on
public class OffThreadModelBakerySystem {
//NOTE: Create a static final context offthread and dont close it, just reuse the context, since context creation is expensive
private static final long GL_CTX;
private static final GLCapabilities GL_CAPS;
static {
var caps = GL.getCapabilities();
GLFW.glfwMakeContextCurrent(0L);
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, 0);
GL_CTX = GLFW.glfwCreateWindow(1, 1, "", 0, MinecraftClient.getInstance().getWindow().getHandle());
GLFW.glfwMakeContextCurrent(GL_CTX);
GL_CAPS = GL.createCapabilities();
GLFW.glfwMakeContextCurrent(MinecraftClient.getInstance().getWindow().getHandle());
GL.setCapabilities(caps);
}
private final ModelStore storage = new ModelStore(16);
public final ModelFactory factory;
private final ConcurrentLinkedDeque<NewModelBufferDelta> bufferDeltas = new ConcurrentLinkedDeque<>();
private final IntLinkedOpenHashSet blockIdQueue = new IntLinkedOpenHashSet();
private final Semaphore queueCounter = new Semaphore(0);
private final Thread bakingThread;
private volatile boolean running = true;
public OffThreadModelBakerySystem(Mapper mapper) {
this.factory = new ModelFactory(mapper);
this.bakingThread = new Thread(this::bakeryThread);
this.bakingThread.setName("Baking thread");
this.bakingThread.setPriority(3);
this.bakingThread.start();
}
private void bakeryThread() {
GLFW.glfwMakeContextCurrent(GL_CTX);
GL.setCapabilities(GL_CAPS);
//FIXME: tile entities will probably need to be baked on the main render thread
while (true) {
this.queueCounter.acquireUninterruptibly();
if (!this.running) break;
int blockId;
synchronized (this.blockIdQueue) {
blockId = this.blockIdQueue.removeFirstInt();
VarHandle.fullFence();//Ensure memory coherancy
}
this.factory.addEntry(blockId);
}
}
//Changes to the block table/atlas must be run on the main render thread
public void syncChanges() {
//TODO: FIXME!! the ordering of the uploads here and the order that _both_ model AND biome are done in the bakery thread MUST be the same!!!
}
public void shutdown() {
this.running = false;
this.queueCounter.release(999);
try {
this.bakingThread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
this.factory.free();
this.storage.free();
}
public void requestBlockBake(int blockId) {
synchronized (this.blockIdQueue) {
if (this.blockIdQueue.add(blockId)) {
VarHandle.fullFence();//Ensure memory coherancy
this.queueCounter.release(1);
}
}
}
public void addDebugData(List<String> debug) {
}
}

View File

@@ -24,7 +24,7 @@ public class OnThreadModelBakerySystem {
public void tick() {
//There should be a method to access the frame time IIRC, if the user framecap is unlimited lock it to like 60 fps for computation
int BUDGET = 5;//TODO: make this computed based on the remaining free time in a frame (and like div by 2 to reduce overhead) (with a min of 1)
int BUDGET = 20;//TODO: make this computed based on the remaining free time in a frame (and like div by 2 to reduce overhead) (with a min of 1)
for (int i = 0; i < BUDGET; i++) {
if (!this.blockIdQueue.isEmpty()) {
int blockId = -1;

View File

@@ -1,7 +1,6 @@
package me.cortex.voxy.client.core.rendering;
import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.client.core.model.OffThreadModelBakerySystem;
import me.cortex.voxy.client.core.model.OnThreadModelBakerySystem;
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
@@ -17,8 +16,8 @@ public class RenderService {
public RenderService(WorldEngine world) {
this.modelService = new OnThreadModelBakerySystem(world.getMapper());
this.renderGen = new RenderGenerationService(world, this.modelService, VoxyConfig.CONFIG.renderThreads, this::consumeRenderBuildResult, false);
for(int x = -10; x<=10;x++) {
for (int z = -10; z <= 10; z++) {
for(int x = -200; x<=200;x++) {
for (int z = -200; z <= 200; z++) {
for (int y = -3; y <= 3; y++) {
this.renderGen.enqueueTask(0, x, y, z);
}

View File

@@ -3,8 +3,6 @@ package me.cortex.voxy.client.core.rendering.building;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import me.cortex.voxy.client.core.model.IdNotYetComputedException;
import me.cortex.voxy.client.core.model.ModelFactory;
import me.cortex.voxy.client.core.model.OffThreadModelBakerySystem;
import me.cortex.voxy.client.core.model.OnThreadModelBakerySystem;
import me.cortex.voxy.common.world.WorldEngine;
import me.cortex.voxy.common.world.WorldSection;
@@ -12,7 +10,6 @@ import me.cortex.voxy.common.world.other.Mapper;
import net.minecraft.client.MinecraftClient;
import net.minecraft.text.Text;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.function.Consumer;
@@ -43,6 +40,7 @@ public class RenderGenerationService {
this.workers = new Thread[workers];
for (int i = 0; i < workers; i++) {
this.workers[i] = new Thread(this::renderWorker);
this.workers[i].setPriority(3);
this.workers[i].setDaemon(true);
this.workers[i].setName("Render generation service #" + i);
this.workers[i].start();
@@ -89,7 +87,7 @@ public class RenderGenerationService {
} catch (IdNotYetComputedException e) {
if (task.hasDoneModelRequest[0]) {
try {
Thread.sleep(100);
Thread.sleep(10);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}