More work on setting up render system
This commit is contained in:
@@ -25,7 +25,8 @@ import org.lwjgl.opengl.GL11;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
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
|
//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);
|
.setScreenSize(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight);
|
||||||
|
|
||||||
int boundFB = GL11.glGetInteger(GL_DRAW_FRAMEBUFFER_BINDING);
|
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.postProcessing.setup(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight, boundFB);
|
||||||
|
|
||||||
this.renderer.renderFarAwayOpaque(viewport);
|
this.renderer.renderFarAwayOpaque(viewport);
|
||||||
|
|||||||
@@ -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.model.ModelBakerySubsystem;
|
||||||
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
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.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.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.section.MDICSectionRenderer;
|
||||||
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
|
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
|
||||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
@@ -14,40 +16,47 @@ import net.minecraft.client.render.Camera;
|
|||||||
|
|
||||||
import java.util.List;
|
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>> {
|
public class RenderService<T extends AbstractSectionRenderer<J>, J extends Viewport<J>> {
|
||||||
|
private static AbstractSectionRenderer<?> createSectionRenderer() {
|
||||||
|
return new MDICSectionRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
private final ViewportSelector<?> viewportSelector;
|
private final ViewportSelector<?> viewportSelector;
|
||||||
private final T sectionRenderer;
|
private final AbstractSectionRenderer<J> sectionRenderer;
|
||||||
|
|
||||||
|
private final HierarchicalNodeManager nodeManager;
|
||||||
private final HierarchicalOcclusionTraverser traversal;
|
private final HierarchicalOcclusionTraverser traversal;
|
||||||
private final ModelBakerySubsystem modelService;
|
private final ModelBakerySubsystem modelService;
|
||||||
private final RenderGenerationService renderGen;
|
private final RenderGenerationService renderGen;
|
||||||
|
|
||||||
|
|
||||||
public RenderService(WorldEngine world) {
|
public RenderService(WorldEngine world) {
|
||||||
this.modelService = new ModelBakerySubsystem(world.getMapper());
|
this.modelService = new ModelBakerySubsystem(world.getMapper());
|
||||||
|
this.nodeManager = new HierarchicalNodeManager(1<<21);
|
||||||
|
|
||||||
this.sectionRenderer = (T) createSectionRenderer();
|
this.sectionRenderer = (T) createSectionRenderer();
|
||||||
this.renderGen = new RenderGenerationService(world, this.modelService, VoxyConfig.CONFIG.renderThreads, this::consumeBuiltSection, false);
|
this.viewportSelector = new ViewportSelector<>(this.sectionRenderer::createViewport);
|
||||||
this.traversal = new HierarchicalOcclusionTraverser(this.renderGen, null);
|
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)));
|
world.setDirtyCallback(section -> System.out.println("Section updated!!: " + WorldEngine.pprintPos(section.key)));
|
||||||
|
|
||||||
this.viewportSelector = new ViewportSelector<>(this.sectionRenderer::createViewport);
|
/*
|
||||||
|
for(int x = -200; x<=200;x++) {
|
||||||
|
for (int z = -200; z <= 200; z++) {
|
||||||
for(int x = -400; x<=400;x++) {
|
for (int y = -3; y <= 3; y++) {
|
||||||
for (int z = -400; z <= 400; z++) {
|
|
||||||
for (int y = -6; y <= 6; y++) {
|
|
||||||
this.renderGen.enqueueTask(0, x, y, z);
|
this.renderGen.enqueueTask(0, x, y, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private void consumeBuiltSection(BuiltSection section) {
|
//Cant do a lambda in the constructor cause "this.nodeManager" could be null??? even tho this does the exact same thing, java is stupid
|
||||||
this.traversal.consumeBuiltSection(section);
|
private void consumeBuiltSection(BuiltSection section) {this.nodeManager.processBuildResult(section);}
|
||||||
}
|
|
||||||
|
|
||||||
private static AbstractSectionRenderer<?> createSectionRenderer() {
|
|
||||||
return new MDICSectionRenderer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setup(Camera camera) {
|
public void setup(Camera camera) {
|
||||||
this.modelService.tick();
|
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
|
// the section renderer is as it might have different backends, but they all accept a buffer containing the section list
|
||||||
|
|
||||||
this.sectionRenderer.renderOpaque(viewport);
|
this.sectionRenderer.renderOpaque(viewport);
|
||||||
|
|
||||||
//NOTE: need to do the upload and download tick here, after the section renderer renders the world, to ensure "stable"
|
//NOTE: need to do the upload and download tick here, after the section renderer renders the world, to ensure "stable"
|
||||||
// sections
|
// sections
|
||||||
UploadStream.INSTANCE.tick();
|
|
||||||
DownloadStream.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);
|
this.sectionRenderer.buildDrawCallsAndRenderTemporal(viewport, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.Shader;
|
||||||
import me.cortex.voxy.client.core.gl.shader.ShaderType;
|
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.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 me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -98,6 +98,9 @@ public class PostProcessing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setup(int width, int height, int sourceFB) {
|
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.didSSAO = false;
|
||||||
this.glStateCapture.capture();
|
this.glStateCapture.capture();
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
}
|
||||||
@@ -133,6 +133,7 @@ public class DownloadStream {
|
|||||||
|
|
||||||
//Synchonize force flushes everything
|
//Synchonize force flushes everything
|
||||||
public void flushWaitClear() {
|
public void flushWaitClear() {
|
||||||
|
glFinish();
|
||||||
this.tick();
|
this.tick();
|
||||||
var fence = new GlFence();
|
var fence = new GlFence();
|
||||||
glFinish();
|
glFinish();
|
||||||
|
|||||||
@@ -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.GlFramebuffer;
|
||||||
import me.cortex.voxy.client.core.gl.GlTexture;
|
import me.cortex.voxy.client.core.gl.GlTexture;
|
||||||
Reference in New Issue
Block a user