More work on setting up render system

This commit is contained in:
mcrcortex
2024-08-02 23:38:30 +10:00
parent 0362399ba7
commit 154f016a96
10 changed files with 170 additions and 48 deletions

View File

@@ -25,7 +25,8 @@ import org.lwjgl.opengl.GL11;
import java.io.File;
import java.util.*;
import static org.lwjgl.opengl.GL30C.GL_DRAW_FRAMEBUFFER_BINDING;
import static org.lwjgl.opengl.ARBDirectStateAccess.glGetNamedFramebufferAttachmentParameteri;
import static org.lwjgl.opengl.GL30C.*;
//Core class that ingests new data from sources and updates the required systems
@@ -121,6 +122,11 @@ public class VoxelCore {
.setScreenSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight);
int boundFB = GL11.glGetInteger(GL_DRAW_FRAMEBUFFER_BINDING);
if (boundFB == 0) {
throw new IllegalStateException("Cannot use the default framebuffer as cannot source from it");
}
//TODO: use the raw depth buffer texture instead
//int boundDepthBuffer = glGetNamedFramebufferAttachmentParameteri(boundFB, GL_DEPTH_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
this.postProcessing.setup(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight, boundFB);
this.renderer.renderFarAwayOpaque(viewport);

View File

@@ -4,8 +4,10 @@ import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.client.core.model.ModelBakerySubsystem;
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
import me.cortex.voxy.client.core.rendering.hierarchical.HierarchicalOcclusionTraverser;
import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalNodeManager;
import me.cortex.voxy.client.core.rendering.hierachical2.HierarchicalOcclusionTraverser;
import me.cortex.voxy.client.core.rendering.section.AbstractSectionRenderer;
import me.cortex.voxy.client.core.rendering.section.IUsesMeshlets;
import me.cortex.voxy.client.core.rendering.section.MDICSectionRenderer;
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
import me.cortex.voxy.client.core.rendering.util.UploadStream;
@@ -14,40 +16,47 @@ import net.minecraft.client.render.Camera;
import java.util.List;
import static org.lwjgl.opengl.ARBDirectStateAccess.glGetNamedFramebufferAttachmentParameteri;
import static org.lwjgl.opengl.GL42.*;
public class RenderService<T extends AbstractSectionRenderer<J>, J extends Viewport<J>> {
private static AbstractSectionRenderer<?> createSectionRenderer() {
return new MDICSectionRenderer();
}
private final ViewportSelector<?> viewportSelector;
private final T sectionRenderer;
private final AbstractSectionRenderer<J> sectionRenderer;
private final HierarchicalNodeManager nodeManager;
private final HierarchicalOcclusionTraverser traversal;
private final ModelBakerySubsystem modelService;
private final RenderGenerationService renderGen;
public RenderService(WorldEngine world) {
this.modelService = new ModelBakerySubsystem(world.getMapper());
this.nodeManager = new HierarchicalNodeManager(1<<21);
this.sectionRenderer = (T) createSectionRenderer();
this.renderGen = new RenderGenerationService(world, this.modelService, VoxyConfig.CONFIG.renderThreads, this::consumeBuiltSection, false);
this.traversal = new HierarchicalOcclusionTraverser(this.renderGen, null);
this.viewportSelector = new ViewportSelector<>(this.sectionRenderer::createViewport);
this.renderGen = new RenderGenerationService(world, this.modelService, VoxyConfig.CONFIG.renderThreads, this::consumeBuiltSection, this.sectionRenderer instanceof IUsesMeshlets);
this.traversal = new HierarchicalOcclusionTraverser(this.nodeManager, 512);
world.setDirtyCallback(section -> System.out.println("Section updated!!: " + WorldEngine.pprintPos(section.key)));
this.viewportSelector = new ViewportSelector<>(this.sectionRenderer::createViewport);
for(int x = -400; x<=400;x++) {
for (int z = -400; z <= 400; z++) {
for (int y = -6; y <= 6; y++) {
/*
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);
}
}
}
}*/
}
private void consumeBuiltSection(BuiltSection section) {
this.traversal.consumeBuiltSection(section);
}
private static AbstractSectionRenderer<?> createSectionRenderer() {
return new MDICSectionRenderer();
}
//Cant do a lambda in the constructor cause "this.nodeManager" could be null??? even tho this does the exact same thing, java is stupid
private void consumeBuiltSection(BuiltSection section) {this.nodeManager.processBuildResult(section);}
public void setup(Camera camera) {
this.modelService.tick();
@@ -62,12 +71,16 @@ public class RenderService<T extends AbstractSectionRenderer<J>, J extends Viewp
// the section renderer is as it might have different backends, but they all accept a buffer containing the section list
this.sectionRenderer.renderOpaque(viewport);
//NOTE: need to do the upload and download tick here, after the section renderer renders the world, to ensure "stable"
// sections
UploadStream.INSTANCE.tick();
DownloadStream.INSTANCE.tick();
UploadStream.INSTANCE.tick();
this.traversal.doTraversal(viewport);
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT|GL_PIXEL_BUFFER_BARRIER_BIT);
int depthBuffer = glGetFramebufferAttachmentParameteri(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
this.traversal.doTraversal(viewport, depthBuffer);
this.sectionRenderer.buildDrawCallsAndRenderTemporal(viewport, null);
}

View File

@@ -0,0 +1,36 @@
package me.cortex.voxy.client.core.rendering.hierachical2;
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
import me.jellysquid.mods.sodium.client.util.MathUtil;
import org.lwjgl.system.MemoryUtil;
//Contains no logic to interface with the gpu, nor does it contain any gpu buffers
public class HierarchicalNodeManager {
public static final int NODE_MSK = ((1<<24)-1);
public final int maxNodeCount;
private final long[] localNodeData;
public HierarchicalNodeManager(int maxNodeCount) {
if (!MathUtil.isPowerOfTwo(maxNodeCount)) {
throw new IllegalArgumentException("Max node count must be a power of 2");
}
if (maxNodeCount>(1<<24)) {
throw new IllegalArgumentException("Max node count cannot exceed 2^24");
}
this.maxNodeCount = maxNodeCount;
this.localNodeData = new long[maxNodeCount*4];
}
public void processRequestQueue(int count, long ptr) {
for (int i = 0; i < count; i++) {
int op = MemoryUtil.memGetInt(ptr+(i*4L));
int node = op&NODE_MSK;
}
}
public void processBuildResult(BuiltSection section) {
}
}

View File

@@ -0,0 +1,83 @@
package me.cortex.voxy.client.core.rendering.hierachical2;
import me.cortex.voxy.client.core.gl.GlBuffer;
import me.cortex.voxy.client.core.rendering.util.HiZBuffer;
import me.cortex.voxy.client.core.rendering.Viewport;
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
import me.cortex.voxy.client.core.rendering.util.UploadStream;
import org.lwjgl.system.MemoryUtil;
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
import static org.lwjgl.opengl.GL30.GL_R32UI;
import static org.lwjgl.opengl.GL30C.GL_RED_INTEGER;
import static org.lwjgl.opengl.GL42.glMemoryBarrier;
import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BARRIER_BIT;
import static org.lwjgl.opengl.GL43.glDispatchComputeIndirect;
import static org.lwjgl.opengl.GL45.nglClearNamedBufferSubData;
public class HierarchicalOcclusionTraverser {
private final HierarchicalNodeManager nodeManager;
private final int maxRequestCount;
private final GlBuffer requestBuffer;
private final GlBuffer nodeBuffer;
private final HiZBuffer hiZBuffer = new HiZBuffer();
public HierarchicalOcclusionTraverser(HierarchicalNodeManager nodeManager, int requestBufferCount) {
this.nodeManager = nodeManager;
this.requestBuffer = new GlBuffer(requestBufferCount*4L+1024).zero();//The 1024 is to assist with race condition issues
this.nodeBuffer = new GlBuffer(nodeManager.maxNodeCount*16L).zero();
this.maxRequestCount = requestBufferCount;
}
private void uploadUniform(Viewport<?> viewport) {
}
public void doTraversal(Viewport<?> viewport, int depthBuffer) {
//Compute the mip chain
this.hiZBuffer.buildMipChain(depthBuffer, viewport.width, viewport.height);
this.uploadUniform(viewport);
UploadStream.INSTANCE.commit();
//Use a chain of glDispatchComputeIndirect (5 times) with alternating read/write buffers
// TODO: swap to persistent gpu thread instead
this.downloadResetRequestQueue();
}
private void downloadResetRequestQueue() {
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
DownloadStream.INSTANCE.download(this.requestBuffer, this::forwardDownloadResult);
DownloadStream.INSTANCE.commit();
nglClearNamedBufferSubData(this.requestBuffer.id, GL_R32UI, 0, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
}
private void forwardDownloadResult(long ptr, long size) {
int count = MemoryUtil.memGetInt(ptr);
if (count < 0 || count > 50000) {
throw new IllegalStateException("Count unexpected extreme value: " + count);
}
if (count > (this.requestBuffer.size()>>2)-1) {
throw new IllegalStateException("Count over max buffer size, desync expected, aborting");
}
if (count > this.maxRequestCount) {
System.err.println("Count larger than 'maxRequestCount', overflow captured. Overflowed by " + (count-this.maxRequestCount));
}
if (count != 0) {
this.nodeManager.processRequestQueue(count, ptr + 4);
}
}
public void free() {
this.requestBuffer.free();
this.hiZBuffer.free();
this.nodeBuffer.free();
}
}

View File

@@ -5,7 +5,7 @@ import me.cortex.voxy.client.core.gl.shader.PrintfInjector;
import me.cortex.voxy.client.core.gl.shader.Shader;
import me.cortex.voxy.client.core.gl.shader.ShaderType;
import me.cortex.voxy.client.core.rendering.geometry.OLD.Gl46HierarchicalViewport;
import me.cortex.voxy.client.core.rendering.HiZBuffer;
import me.cortex.voxy.client.core.rendering.util.HiZBuffer;
import me.cortex.voxy.client.core.rendering.util.UploadStream;
import net.minecraft.util.math.MathHelper;
import org.joml.Matrix4f;

View File

@@ -1,25 +0,0 @@
package me.cortex.voxy.client.core.rendering.hierarchical;
import me.cortex.voxy.client.core.rendering.Viewport;
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
import me.cortex.voxy.client.core.rendering.section.AbstractSectionGeometryManager;
public class HierarchicalOcclusionTraverser {
public HierarchicalOcclusionTraverser(RenderGenerationService renderGenerationService, AbstractSectionGeometryManager sectionGeometryManager) {
}
public void doTraversal(Viewport<?> viewport) {
}
public void free() {
}
public void consumeBuiltSection(BuiltSection section) {
section.free();
}
}

View File

@@ -98,6 +98,9 @@ public class PostProcessing {
}
public void setup(int width, int height, int sourceFB) {
//TODO: use the raw depth texture instead
//TODO: when blitting, also set the depth value of where the mask is created to 0 (I.E. closest to the camera)
// cause of hiz computing, it makes alot of sections visible
this.didSSAO = false;
this.glStateCapture.capture();

View File

@@ -0,0 +1,5 @@
package me.cortex.voxy.client.core.rendering.section;
//A dummy empty interface to mark that the class uses meshlets
public interface IUsesMeshlets {
}

View File

@@ -133,6 +133,7 @@ public class DownloadStream {
//Synchonize force flushes everything
public void flushWaitClear() {
glFinish();
this.tick();
var fence = new GlFence();
glFinish();

View File

@@ -1,4 +1,4 @@
package me.cortex.voxy.client.core.rendering;
package me.cortex.voxy.client.core.rendering.util;
import me.cortex.voxy.client.core.gl.GlFramebuffer;
import me.cortex.voxy.client.core.gl.GlTexture;