Use onthread bakery until all the issues related to offthread baking can be resolved (related to tile entity baking)

This commit is contained in:
mcrcortex
2024-07-30 09:14:36 +10:00
parent ca899dd506
commit 87f7d71c94
8 changed files with 114 additions and 44 deletions

View File

@@ -2,10 +2,7 @@ package me.cortex.voxy.client.core;
import com.mojang.blaze3d.systems.RenderSystem;
import me.cortex.voxy.client.Voxy;
import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.client.core.model.OffThreadModelBakerySystem;
import me.cortex.voxy.client.core.rendering.*;
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
import me.cortex.voxy.client.core.rendering.post.PostProcessing;
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
import me.cortex.voxy.client.core.util.IrisUtil;

View File

@@ -101,21 +101,26 @@ public class BakedBlockEntityModel {
}
public void renderOut() {
var vc = Tessellator.getInstance();
for (var layer : this.layers) {
if (layer.isEmpty()) continue;
var bb = vc.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR);
if (layer.layer instanceof RenderLayer.MultiPhase mp) {
Identifier textureId = mp.phases.texture.getId().orElse(null);
if (textureId == null) {
System.err.println("ERROR: Empty texture id for layer: " + layer);
} else {
var texture = MinecraftClient.getInstance().getTextureManager().getTexture(textureId);
glBindTexture(GL_TEXTURE_2D, texture.getGlId());
//TODO:FIXME: CANT RUN ON RENDER THREAD
if (false) {
System.err.println("Model entity baking not yet supported offthread baking");
} else {
var vc = Tessellator.getInstance();
for (var layer : this.layers) {
if (layer.isEmpty()) continue;
var bb = vc.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR);
if (layer.layer instanceof RenderLayer.MultiPhase mp) {
Identifier textureId = mp.phases.texture.getId().orElse(null);
if (textureId == null) {
System.err.println("ERROR: Empty texture id for layer: " + layer);
} else {
var texture = MinecraftClient.getInstance().getTextureManager().getTexture(textureId);
glBindTexture(GL_TEXTURE_2D, texture.getGlId());
}
}
layer.putInto(bb);
BufferRenderer.draw(bb.end());
}
layer.putInto(bb);
BufferRenderer.draw(bb.end());
}
}

View File

@@ -143,7 +143,6 @@ public class ModelFactory {
public void addEntry(int blockId) {
if (this.idMappings[blockId] != -1) {
System.err.println("Block id already added: " + blockId);
return;
}
this.addEntry(blockId, this.mapper.getBlockStateFromBlockId(blockId));
@@ -156,7 +155,7 @@ public class ModelFactory {
// while the depth is computed from the depth buffer data
public void addEntry(int blockId, BlockState blockState) {
if (this.idMappings[blockId] != -1) {
System.err.println("Block id already added: " + blockId + " for state: " + blockState);
//System.err.println("Block id already added: " + blockId + " for state: " + blockState);
return;
}

View File

@@ -15,6 +15,7 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.GlUniform;
import net.minecraft.client.render.*;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.util.BufferAllocator;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.Identifier;
@@ -118,15 +119,14 @@ public class ModelTextureBakery {
var entityModel = state.hasBlockEntity()?BakedBlockEntityModel.bake(state):null;
int oldFB = GlStateManager.getBoundFramebuffer();
var oldProjection = new Matrix4f(RenderSystem.getProjectionMatrix());
GL11C.glViewport(0, 0, this.width, this.height);
RenderSystem.setProjectionMatrix(new Matrix4f().identity().set(new float[]{
var projection = new Matrix4f().identity().set(new float[]{
2,0,0,0,
0, 2,0,0,
0,0, -1f,0,
-1,-1,0,1,
}), VertexSorter.BY_Z);
});
@@ -176,7 +176,7 @@ public class ModelTextureBakery {
var faces = new ColourDepthTextureData[FACE_VIEWS.size()];
for (int i = 0; i < faces.length; i++) {
faces[i] = captureView(state, model, entityModel, FACE_VIEWS.get(i), randomValue, i, renderFluid, texId);
faces[i] = captureView(state, model, entityModel, FACE_VIEWS.get(i), randomValue, i, renderFluid, texId, projection);
//glBlitNamedFramebuffer(this.framebuffer.id, oldFB, 0,0,16,16,300*(i>>1),300*(i&1),300*(i>>1)+256,300*(i&1)+256, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
@@ -184,7 +184,6 @@ public class ModelTextureBakery {
glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);
RenderSystem.setProjectionMatrix(oldProjection, VertexSorter.BY_DISTANCE);
glBindFramebuffer(GL_FRAMEBUFFER, oldFB);
GL11C.glViewport(GlStateManager.Viewport.getX(), GlStateManager.Viewport.getY(), GlStateManager.Viewport.getWidth(), GlStateManager.Viewport.getHeight());
@@ -194,13 +193,11 @@ public class ModelTextureBakery {
return faces;
}
private ColourDepthTextureData captureView(BlockState state, BakedModel model, BakedBlockEntityModel blockEntityModel, MatrixStack stack, long randomValue, int face, boolean renderFluid, int textureId) {
var vc = Tessellator.getInstance();
private final BufferAllocator allocator = new BufferAllocator(786432);
private ColourDepthTextureData captureView(BlockState state, BakedModel model, BakedBlockEntityModel blockEntityModel, MatrixStack stack, long randomValue, int face, boolean renderFluid, int textureId, Matrix4f projection) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
float[] mat = new float[4*4];
new Matrix4f(RenderSystem.getProjectionMatrix()).mul(stack.peek().getPositionMatrix()).get(mat);
new Matrix4f(projection).mul(stack.peek().getPositionMatrix()).get(mat);
glUniformMatrix4fv(1, false, mat);
@@ -208,7 +205,7 @@ public class ModelTextureBakery {
blockEntityModel.renderOut();
}
var bb = vc.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR);
var bb = new BufferBuilder(this.allocator, VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR);
if (!renderFluid) {
renderQuads(bb, state, model, new MatrixStack(), randomValue);
} else {
@@ -282,6 +279,7 @@ public class ModelTextureBakery {
glBindTexture(GL_TEXTURE_2D, textureId);
try {
//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);
@@ -311,5 +309,6 @@ public class ModelTextureBakery {
this.colourTex.free();
this.depthTex.free();
this.rasterShader.free();
this.allocator.close();
}
}

View File

@@ -2,10 +2,12 @@ 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;
@@ -16,13 +18,16 @@ import java.util.concurrent.Semaphore;
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.createCapabilities();
GL_CAPS = GL.createCapabilities();
GLFW.glfwMakeContextCurrent(MinecraftClient.getInstance().getWindow().getHandle());
GL.setCapabilities(caps);
}
@@ -30,7 +35,7 @@ public class OffThreadModelBakerySystem {
private final ModelStore storage = new ModelStore(16);
public final ModelFactory factory;
private final ConcurrentLinkedDeque<NewModelBufferDelta> bufferDeltas = new ConcurrentLinkedDeque<>();
private final IntArrayFIFOQueue blockQueue = new IntArrayFIFOQueue();
private final IntLinkedOpenHashSet blockIdQueue = new IntLinkedOpenHashSet();
private final Semaphore queueCounter = new Semaphore(0);
@@ -47,14 +52,15 @@ public class OffThreadModelBakerySystem {
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.blockQueue) {
blockId = this.blockQueue.dequeueInt();
synchronized (this.blockIdQueue) {
blockId = this.blockIdQueue.removeFirstInt();
VarHandle.fullFence();//Ensure memory coherancy
}
@@ -80,10 +86,11 @@ public class OffThreadModelBakerySystem {
}
public void requestBlockBake(int blockId) {
synchronized (this.blockQueue) {
this.blockQueue.enqueue(blockId);
VarHandle.fullFence();//Ensure memory coherancy
this.queueCounter.release(1);
synchronized (this.blockIdQueue) {
if (this.blockIdQueue.add(blockId)) {
VarHandle.fullFence();//Ensure memory coherancy
this.queueCounter.release(1);
}
}
}

View File

@@ -0,0 +1,56 @@
package me.cortex.voxy.client.core.model;
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;
public class OnThreadModelBakerySystem {
private final ModelStore storage = new ModelStore(16);
public final ModelFactory factory;
private final IntLinkedOpenHashSet blockIdQueue = new IntLinkedOpenHashSet();
public OnThreadModelBakerySystem(Mapper mapper) {
this.factory = new ModelFactory(mapper);
}
public void tick() {
if (!this.blockIdQueue.isEmpty()) {
int blockId = -1;
synchronized (this.blockIdQueue) {
if (!this.blockIdQueue.isEmpty()) {
blockId = this.blockIdQueue.removeFirstInt();
VarHandle.fullFence();//Ensure memory coherancy
}
}
if (blockId != -1) {
this.factory.addEntry(blockId);
}
}
}
public void shutdown() {
this.factory.free();
this.storage.free();
}
public void requestBlockBake(int blockId) {
synchronized (this.blockIdQueue) {
if (this.blockIdQueue.add(blockId)) {
VarHandle.fullFence();//Ensure memory coherancy
}
}
}
public void addDebugData(List<String> debug) {
}
}

View File

@@ -2,6 +2,7 @@ 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;
import me.cortex.voxy.common.world.WorldEngine;
@@ -10,14 +11,19 @@ import net.minecraft.client.render.Camera;
import java.util.List;
public class RenderService {
private final OffThreadModelBakerySystem modelService;
private final OnThreadModelBakerySystem modelService;
private final RenderGenerationService renderGen;
public RenderService(WorldEngine world) {
this.modelService = new OffThreadModelBakerySystem(world.getMapper());
this.modelService = new OnThreadModelBakerySystem(world.getMapper());
this.renderGen = new RenderGenerationService(world, this.modelService, VoxyConfig.CONFIG.renderThreads, this::consumeRenderBuildResult, false);
this.renderGen.enqueueTask(0,0,0,0);
for(int x = -10; x<=10;x++) {
for (int z = -10; z <= 10; z++) {
for (int y = -3; y <= 3; y++) {
this.renderGen.enqueueTask(0, x, y, z);
}
}
}
}
private void consumeRenderBuildResult(BuiltSection section) {
@@ -26,7 +32,7 @@ public class RenderService {
}
public void setup(Camera camera) {
this.modelService.syncChanges();
this.modelService.tick();
}
public void renderFarAwayOpaque(Viewport viewport) {

View File

@@ -5,6 +5,7 @@ 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;
import me.cortex.voxy.common.world.other.Mapper;
@@ -29,12 +30,12 @@ public class RenderGenerationService {
private final Semaphore taskCounter = new Semaphore(0);
private final WorldEngine world;
private final OffThreadModelBakerySystem modelBakery;
private final OnThreadModelBakerySystem modelBakery;
private final Consumer<BuiltSection> resultConsumer;
private final BuiltSectionMeshCache meshCache = new BuiltSectionMeshCache();
private final boolean emitMeshlets;
public RenderGenerationService(WorldEngine world, OffThreadModelBakerySystem modelBakery, int workers, Consumer<BuiltSection> consumer, boolean emitMeshlets) {
public RenderGenerationService(WorldEngine world, OnThreadModelBakerySystem modelBakery, int workers, Consumer<BuiltSection> consumer, boolean emitMeshlets) {
this.emitMeshlets = emitMeshlets;
this.world = world;
this.modelBakery = modelBakery;