Restructure A
This commit is contained in:
@@ -3,9 +3,9 @@ package me.cortex.voxy.client.core;
|
|||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import me.cortex.voxy.client.Voxy;
|
import me.cortex.voxy.client.Voxy;
|
||||||
import me.cortex.voxy.client.config.VoxyConfig;
|
import me.cortex.voxy.client.config.VoxyConfig;
|
||||||
|
import me.cortex.voxy.client.core.model.ModelManager;
|
||||||
import me.cortex.voxy.client.core.rendering.*;
|
import me.cortex.voxy.client.core.rendering.*;
|
||||||
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.Test;
|
|
||||||
import me.cortex.voxy.client.core.rendering.post.PostProcessing;
|
import me.cortex.voxy.client.core.rendering.post.PostProcessing;
|
||||||
import me.cortex.voxy.client.core.util.IrisUtil;
|
import me.cortex.voxy.client.core.util.IrisUtil;
|
||||||
import me.cortex.voxy.client.saver.ContextSelectionSystem;
|
import me.cortex.voxy.client.saver.ContextSelectionSystem;
|
||||||
@@ -46,18 +46,19 @@ import static org.lwjgl.opengl.GL30C.GL_DRAW_FRAMEBUFFER_BINDING;
|
|||||||
//Ingest -> world engine -> raw render data -> render data
|
//Ingest -> world engine -> raw render data -> render data
|
||||||
public class VoxelCore {
|
public class VoxelCore {
|
||||||
private final WorldEngine world;
|
private final WorldEngine world;
|
||||||
private final DistanceTracker distanceTracker;
|
|
||||||
private final RenderGenerationService renderGen;
|
private final RenderGenerationService renderGen;
|
||||||
|
private final ModelManager modelManager;
|
||||||
|
|
||||||
|
private final DistanceTracker distanceTracker;
|
||||||
private final RenderTracker renderTracker;
|
private final RenderTracker renderTracker;
|
||||||
|
|
||||||
private final AbstractFarWorldRenderer renderer;
|
private final IRenderInterface renderer;
|
||||||
private final ViewportSelector viewportSelector;
|
private final ViewportSelector viewportSelector;
|
||||||
private final PostProcessing postProcessing;
|
private final PostProcessing postProcessing;
|
||||||
|
|
||||||
//private final Thread shutdownThread = new Thread(this::shutdown);
|
//private final Thread shutdownThread = new Thread(this::shutdown);
|
||||||
|
|
||||||
private WorldImporter importer;
|
private WorldImporter importer;
|
||||||
private Test test;
|
|
||||||
public VoxelCore(ContextSelectionSystem.Selection worldSelection) {
|
public VoxelCore(ContextSelectionSystem.Selection worldSelection) {
|
||||||
this.world = worldSelection.createEngine();
|
this.world = worldSelection.createEngine();
|
||||||
var cfg = worldSelection.getConfig();
|
var cfg = worldSelection.getConfig();
|
||||||
@@ -66,12 +67,13 @@ public class VoxelCore {
|
|||||||
//Trigger the shared index buffer loading
|
//Trigger the shared index buffer loading
|
||||||
SharedIndexBuffer.INSTANCE.id();
|
SharedIndexBuffer.INSTANCE.id();
|
||||||
Capabilities.init();//Ensure clinit is called
|
Capabilities.init();//Ensure clinit is called
|
||||||
|
this.modelManager = new ModelManager(16);
|
||||||
this.renderer = this.createRenderBackend();
|
this.renderer = this.createRenderBackend();
|
||||||
this.viewportSelector = new ViewportSelector<>(this.renderer::createViewport);
|
this.viewportSelector = new ViewportSelector<>(this.renderer::createViewport);
|
||||||
System.out.println("Renderer initialized");
|
System.out.println("Renderer initialized");
|
||||||
|
|
||||||
this.renderTracker = new RenderTracker(this.world, this.renderer);
|
this.renderTracker = new RenderTracker(this.world, (AbstractFarWorldRenderer) this.renderer);
|
||||||
this.renderGen = new RenderGenerationService(this.world, this.renderer.getModelManager(), VoxyConfig.CONFIG.renderThreads, this.renderTracker::processBuildResult, this.renderer.usesMeshlets());
|
this.renderGen = new RenderGenerationService(this.world, this.modelManager, VoxyConfig.CONFIG.renderThreads, this.renderTracker::processBuildResult, this.renderer.generateMeshlets());
|
||||||
this.world.setDirtyCallback(this.renderTracker::sectionUpdated);
|
this.world.setDirtyCallback(this.renderTracker::sectionUpdated);
|
||||||
this.renderTracker.setRenderGen(this.renderGen);
|
this.renderTracker.setRenderGen(this.renderGen);
|
||||||
System.out.println("Render tracker and generator initialized");
|
System.out.println("Render tracker and generator initialized");
|
||||||
@@ -115,20 +117,19 @@ public class VoxelCore {
|
|||||||
//this.renderer.getModelManager().updateEntry(0, Blocks.GRASS_BLOCK.getDefaultState());
|
//this.renderer.getModelManager().updateEntry(0, Blocks.GRASS_BLOCK.getDefaultState());
|
||||||
|
|
||||||
System.out.println("Voxy core initialized");
|
System.out.println("Voxy core initialized");
|
||||||
this.test = new Test();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractFarWorldRenderer<?,?> createRenderBackend() {
|
private AbstractFarWorldRenderer<?,?> createRenderBackend() {
|
||||||
if (false) {
|
if (false) {
|
||||||
System.out.println("Using Gl46MeshletFarWorldRendering");
|
System.out.println("Using Gl46MeshletFarWorldRendering");
|
||||||
return new Gl46MeshletsFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
|
return new Gl46MeshletsFarWorldRenderer(this.modelManager, VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
|
||||||
} else {
|
} else {
|
||||||
if (VoxyConfig.CONFIG.useMeshShaders()) {
|
if (VoxyConfig.CONFIG.useMeshShaders()) {
|
||||||
System.out.println("Using NvMeshFarWorldRenderer");
|
System.out.println("Using NvMeshFarWorldRenderer");
|
||||||
return new NvMeshFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
|
return new NvMeshFarWorldRenderer(this.modelManager, VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
|
||||||
} else {
|
} else {
|
||||||
System.out.println("Using Gl46FarWorldRenderer");
|
System.out.println("Using Gl46FarWorldRenderer");
|
||||||
return new Gl46FarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
|
return new Gl46FarWorldRenderer(this.modelManager, VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,8 +200,6 @@ public class VoxelCore {
|
|||||||
|
|
||||||
this.renderer.renderFarAwayOpaque(viewport);
|
this.renderer.renderFarAwayOpaque(viewport);
|
||||||
|
|
||||||
this.test.doIt(viewport);
|
|
||||||
|
|
||||||
//Compute the SSAO of the rendered terrain
|
//Compute the SSAO of the rendered terrain
|
||||||
this.postProcessing.computeSSAO(projection, matrices);
|
this.postProcessing.computeSSAO(projection, matrices);
|
||||||
|
|
||||||
@@ -246,7 +245,7 @@ public class VoxelCore {
|
|||||||
System.out.println("Render gen shut down");
|
System.out.println("Render gen shut down");
|
||||||
try {this.world.shutdown();} catch (Exception e) {System.err.println(e);}
|
try {this.world.shutdown();} catch (Exception e) {System.err.println(e);}
|
||||||
System.out.println("World engine shut down");
|
System.out.println("World engine shut down");
|
||||||
try {this.renderer.shutdown(); this.viewportSelector.free();} catch (Exception e) {System.err.println(e);}
|
try {this.renderer.shutdown(); this.viewportSelector.free(); this.modelManager.free();} catch (Exception e) {System.err.println(e);}
|
||||||
System.out.println("Renderer shut down");
|
System.out.println("Renderer shut down");
|
||||||
if (this.postProcessing!=null){try {this.postProcessing.shutdown();} catch (Exception e) {System.err.println(e);}}
|
if (this.postProcessing!=null){try {this.postProcessing.shutdown();} catch (Exception e) {System.err.println(e);}}
|
||||||
System.out.println("Voxel core shut down");
|
System.out.println("Voxel core shut down");
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package me.cortex.voxy.client.core.gl;
|
|||||||
|
|
||||||
import me.cortex.voxy.common.util.TrackedObject;
|
import me.cortex.voxy.common.util.TrackedObject;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
|
||||||
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
|
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
|
||||||
import static org.lwjgl.opengl.GL44C.glBufferStorage;
|
import static org.lwjgl.opengl.GL44C.glBufferStorage;
|
||||||
import static org.lwjgl.opengl.GL45C.glCreateBuffers;
|
import static org.lwjgl.opengl.GL45C.*;
|
||||||
import static org.lwjgl.opengl.GL45C.glNamedBufferStorage;
|
|
||||||
|
|
||||||
public class GlBuffer extends TrackedObject {
|
public class GlBuffer extends TrackedObject {
|
||||||
public final int id;
|
public final int id;
|
||||||
@@ -30,4 +30,9 @@ public class GlBuffer extends TrackedObject {
|
|||||||
public long size() {
|
public long size() {
|
||||||
return this.size;
|
return this.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GlBuffer zero() {
|
||||||
|
nglClearNamedBufferData(this.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 0);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import static org.lwjgl.opengl.GL30.*;
|
|||||||
|
|
||||||
|
|
||||||
//Todo: tinker with having the compute shader where each thread is a position to render? maybe idk
|
//Todo: tinker with having the compute shader where each thread is a position to render? maybe idk
|
||||||
public abstract class AbstractFarWorldRenderer <T extends Viewport, J extends AbstractGeometryManager> {
|
public abstract class AbstractFarWorldRenderer <T extends Viewport, J extends AbstractGeometryManager> implements IRenderInterface<T> {
|
||||||
public static final int STATIC_VAO = glGenVertexArrays();
|
public static final int STATIC_VAO = glGenVertexArrays();
|
||||||
|
|
||||||
protected final GlBuffer uniformBuffer;
|
protected final GlBuffer uniformBuffer;
|
||||||
@@ -52,18 +52,18 @@ public abstract class AbstractFarWorldRenderer <T extends Viewport, J extends Ab
|
|||||||
|
|
||||||
protected FrustumIntersection frustum;
|
protected FrustumIntersection frustum;
|
||||||
|
|
||||||
private final List<T> viewports = new ArrayList<>();
|
//private final List<T> viewports = new ArrayList<>();
|
||||||
|
|
||||||
protected IntArrayList updatedSectionIds;
|
protected IntArrayList updatedSectionIds;
|
||||||
|
|
||||||
private final ConcurrentLinkedDeque<Mapper.StateEntry> blockStateUpdates = new ConcurrentLinkedDeque<>();
|
private final ConcurrentLinkedDeque<Mapper.StateEntry> blockStateUpdates = new ConcurrentLinkedDeque<>();
|
||||||
private final ConcurrentLinkedDeque<Mapper.BiomeEntry> biomeUpdates = new ConcurrentLinkedDeque<>();
|
private final ConcurrentLinkedDeque<Mapper.BiomeEntry> biomeUpdates = new ConcurrentLinkedDeque<>();
|
||||||
public AbstractFarWorldRenderer(J geometry) {
|
public AbstractFarWorldRenderer(ModelManager models, J geometry) {
|
||||||
this.maxSections = geometry.getMaxSections();
|
this.maxSections = geometry.getMaxSections();
|
||||||
this.uniformBuffer = new GlBuffer(1024);
|
this.uniformBuffer = new GlBuffer(1024);
|
||||||
this.lightDataBuffer = new GlBuffer(256*4);//256 of uint
|
this.lightDataBuffer = new GlBuffer(256*4);//256 of uint
|
||||||
this.geometry = geometry;
|
this.geometry = geometry;
|
||||||
this.models = new ModelManager(16);
|
this.models = models;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setupRender(Frustum frustum, Camera camera) {
|
public void setupRender(Frustum frustum, Camera camera) {
|
||||||
@@ -148,29 +148,20 @@ public abstract class AbstractFarWorldRenderer <T extends Viewport, J extends Ab
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
this.models.free();
|
|
||||||
this.geometry.free();
|
this.geometry.free();
|
||||||
this.uniformBuffer.free();
|
this.uniformBuffer.free();
|
||||||
this.lightDataBuffer.free();
|
this.lightDataBuffer.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModelManager getModelManager() {
|
|
||||||
return this.models;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final T createViewport() {
|
public final T createViewport() {
|
||||||
var viewport = createViewport0();
|
var viewport = createViewport0();
|
||||||
this.viewports.add(viewport);
|
//this.viewports.add(viewport);
|
||||||
return viewport;
|
return viewport;
|
||||||
}
|
}
|
||||||
|
|
||||||
final void removeViewport(T viewport) {
|
|
||||||
this.viewports.remove(viewport);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract T createViewport0();
|
protected abstract T createViewport0();
|
||||||
|
|
||||||
public boolean usesMeshlets() {
|
public boolean generateMeshlets() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package me.cortex.voxy.client.core.rendering;
|
|||||||
import me.cortex.voxy.client.core.gl.GlBuffer;
|
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||||
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.model.ModelManager;
|
||||||
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;
|
||||||
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
|
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
|
||||||
@@ -54,8 +55,8 @@ public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer<Gl46Viewport,
|
|||||||
private final GlBuffer glCommandBuffer;
|
private final GlBuffer glCommandBuffer;
|
||||||
private final GlBuffer glCommandCountBuffer;
|
private final GlBuffer glCommandCountBuffer;
|
||||||
|
|
||||||
public Gl46FarWorldRenderer(int geometryBuffer, int maxSections) {
|
public Gl46FarWorldRenderer(ModelManager modelManager, int geometryBuffer, int maxSections) {
|
||||||
super(new DefaultGeometryManager(geometryBuffer*8L, maxSections));
|
super(modelManager, new DefaultGeometryManager(geometryBuffer*8L, maxSections));
|
||||||
this.glCommandBuffer = new GlBuffer(maxSections*5L*4 * 6);
|
this.glCommandBuffer = new GlBuffer(maxSections*5L*4 * 6);
|
||||||
this.glCommandCountBuffer = new GlBuffer(4*2);
|
this.glCommandCountBuffer = new GlBuffer(4*2);
|
||||||
nglClearNamedBufferData(this.glCommandBuffer.id, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
|
nglClearNamedBufferData(this.glCommandBuffer.id, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package me.cortex.voxy.client.core.rendering;
|
||||||
|
|
||||||
|
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||||
|
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.building.RenderDataFactory;
|
||||||
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
|
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
|
||||||
|
import me.cortex.voxy.common.world.other.Mapper;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.render.Camera;
|
||||||
|
import net.minecraft.client.render.Frustum;
|
||||||
|
import net.minecraft.client.render.RenderLayer;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.ARBDirectStateAccess.glTextureParameteri;
|
||||||
|
import static org.lwjgl.opengl.GL11.*;
|
||||||
|
import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER;
|
||||||
|
import static org.lwjgl.opengl.GL15.glBindBuffer;
|
||||||
|
import static org.lwjgl.opengl.GL30.glBindBufferBase;
|
||||||
|
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
||||||
|
import static org.lwjgl.opengl.GL30C.GL_RED_INTEGER;
|
||||||
|
import static org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER;
|
||||||
|
import static org.lwjgl.opengl.GL31.glDrawElementsInstanced;
|
||||||
|
import static org.lwjgl.opengl.GL33.glBindSampler;
|
||||||
|
import static org.lwjgl.opengl.GL40.glDrawElementsIndirect;
|
||||||
|
import static org.lwjgl.opengl.GL40C.GL_DRAW_INDIRECT_BUFFER;
|
||||||
|
import static org.lwjgl.opengl.GL42.GL_FRAMEBUFFER_BARRIER_BIT;
|
||||||
|
import static org.lwjgl.opengl.GL42.glMemoryBarrier;
|
||||||
|
import static org.lwjgl.opengl.GL43.*;
|
||||||
|
import static org.lwjgl.opengl.GL45.glBindTextureUnit;
|
||||||
|
import static org.lwjgl.opengl.GL45.nglClearNamedBufferSubData;
|
||||||
|
|
||||||
|
public class Gl46HierarchicalRenderer implements IRenderInterface {
|
||||||
|
@Override
|
||||||
|
public Viewport createViewport() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupRender(Frustum frustum, Camera camera) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderFarAwayOpaque(Viewport viewport) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderFarAwayTranslucent(Viewport viewport) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addBlockState(Mapper.StateEntry stateEntry) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addBiome(Mapper.BiomeEntry biomeEntry) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean generateMeshlets() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addDebugData(List debug) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package me.cortex.voxy.client.core.rendering;
|
||||||
|
|
||||||
|
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||||
|
|
||||||
|
public class Gl46HierarchicalViewport extends Viewport<Gl46HierarchicalViewport> {
|
||||||
|
public Gl46HierarchicalViewport(Gl46HierarchicalRenderer renderer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void delete0() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,9 +10,7 @@ import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData;
|
|||||||
public class Gl46MeshletViewport extends Viewport<Gl46MeshletViewport> {
|
public class Gl46MeshletViewport extends Viewport<Gl46MeshletViewport> {
|
||||||
GlBuffer visibilityBuffer;
|
GlBuffer visibilityBuffer;
|
||||||
public Gl46MeshletViewport(Gl46MeshletsFarWorldRenderer renderer) {
|
public Gl46MeshletViewport(Gl46MeshletsFarWorldRenderer renderer) {
|
||||||
super(renderer);
|
this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L).zero();
|
||||||
this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L);
|
|
||||||
nglClearNamedBufferData(this.visibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void delete0() {
|
protected void delete0() {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import me.cortex.voxy.client.core.gl.GlBuffer;
|
|||||||
import me.cortex.voxy.client.core.gl.shader.PrintfInjector;
|
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.model.ModelManager;
|
||||||
import me.cortex.voxy.client.core.rendering.building.RenderDataFactory;
|
import me.cortex.voxy.client.core.rendering.building.RenderDataFactory;
|
||||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
|
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
|
||||||
@@ -73,10 +74,10 @@ public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46M
|
|||||||
private final HiZBuffer hiZBuffer = new HiZBuffer();
|
private final HiZBuffer hiZBuffer = new HiZBuffer();
|
||||||
private final int hizSampler = glGenSamplers();
|
private final int hizSampler = glGenSamplers();
|
||||||
|
|
||||||
public Gl46MeshletsFarWorldRenderer(int geometrySize, int maxSections) {
|
public Gl46MeshletsFarWorldRenderer(ModelManager modelManager, int geometrySize, int maxSections) {
|
||||||
super(new DefaultGeometryManager(alignUp(geometrySize*8L, 8* (RenderDataFactory.QUADS_PER_MESHLET+2)), maxSections, 8*(RenderDataFactory.QUADS_PER_MESHLET+2)));
|
super(modelManager, new DefaultGeometryManager(alignUp(geometrySize*8L, 8* (RenderDataFactory.QUADS_PER_MESHLET+2)), maxSections, 8*(RenderDataFactory.QUADS_PER_MESHLET+2)));
|
||||||
this.glDrawIndirect = new GlBuffer(4*(4+5));
|
this.glDrawIndirect = new GlBuffer(4*(4+5)).zero();
|
||||||
this.meshletBuffer = new GlBuffer(4*1000000);//TODO: Make max meshlet count configurable, not just 1 million (even tho thats a max of 126 million quads per frame)
|
this.meshletBuffer = new GlBuffer(4*1000000).zero();//TODO: Make max meshlet count configurable, not just 1 million (even tho thats a max of 126 million quads per frame)
|
||||||
|
|
||||||
glSamplerParameteri(this.hizSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);//This is so that using the shadow sampler works correctly
|
glSamplerParameteri(this.hizSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);//This is so that using the shadow sampler works correctly
|
||||||
glTextureParameteri(this.hizSampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTextureParameteri(this.hizSampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
@@ -85,8 +86,10 @@ public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46M
|
|||||||
glTextureParameteri(this.hizSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTextureParameteri(this.hizSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTextureParameteri(this.hizSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTextureParameteri(this.hizSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
/*
|
||||||
nglClearNamedBufferData(this.meshletBuffer.id, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
|
nglClearNamedBufferData(this.meshletBuffer.id, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
|
||||||
nglClearNamedBufferData(this.glDrawIndirect.id, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
|
nglClearNamedBufferData(this.glDrawIndirect.id, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void bindResources(Gl46MeshletViewport viewport, boolean bindToDrawIndirect, boolean bindToDispatchIndirect, boolean bindHiz) {
|
protected void bindResources(Gl46MeshletViewport viewport, boolean bindToDrawIndirect, boolean bindToDispatchIndirect, boolean bindHiz) {
|
||||||
@@ -231,7 +234,7 @@ public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46M
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean usesMeshlets() {
|
public boolean generateMeshlets() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData;
|
|||||||
public class Gl46Viewport extends Viewport<Gl46Viewport> {
|
public class Gl46Viewport extends Viewport<Gl46Viewport> {
|
||||||
GlBuffer visibilityBuffer;
|
GlBuffer visibilityBuffer;
|
||||||
public Gl46Viewport(Gl46FarWorldRenderer renderer) {
|
public Gl46Viewport(Gl46FarWorldRenderer renderer) {
|
||||||
super(renderer);
|
this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L).zero();
|
||||||
this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L);
|
|
||||||
nglClearNamedBufferData(this.visibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void delete0() {
|
protected void delete0() {
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
package me.cortex.voxy.client.core.rendering;
|
|
||||||
|
|
||||||
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.hierarchical.NodeManager2;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL30.glBindBufferBase;
|
|
||||||
import static org.lwjgl.opengl.GL33.glBindSampler;
|
|
||||||
import static org.lwjgl.opengl.GL33.glGenSamplers;
|
|
||||||
import static org.lwjgl.opengl.GL42C.*;
|
|
||||||
import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BUFFER;
|
|
||||||
import static org.lwjgl.opengl.GL43C.GL_SHADER_STORAGE_BARRIER_BIT;
|
|
||||||
import static org.lwjgl.opengl.GL44.GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT;
|
|
||||||
import static org.lwjgl.opengl.GL45.glBindTextureUnit;
|
|
||||||
|
|
||||||
public class HierarchicalOcclusionRenderer {
|
|
||||||
private PrintfInjector printf = new PrintfInjector(100000, 10, System.out::println);
|
|
||||||
|
|
||||||
private final NodeManager2 nodeManager = new NodeManager2(null, null);
|
|
||||||
private final HiZBuffer hiz = new HiZBuffer();
|
|
||||||
private final int hizSampler = glGenSamplers();
|
|
||||||
|
|
||||||
private Shader hierarchicalTraversal = Shader.make(this.printf)
|
|
||||||
.add(ShaderType.COMPUTE, "voxy:lod/hierarchical/traversal.comp")
|
|
||||||
.compile();
|
|
||||||
|
|
||||||
public HierarchicalOcclusionRenderer() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bind() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void render(int depthBuffer, int width, int height) {
|
|
||||||
this.nodeManager.upload();
|
|
||||||
|
|
||||||
//Make hiz
|
|
||||||
this.hiz.buildMipChain(depthBuffer, width, height);
|
|
||||||
glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT);
|
|
||||||
this.hierarchicalTraversal.bind();
|
|
||||||
|
|
||||||
{
|
|
||||||
//Bind stuff here
|
|
||||||
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.nodeManager.nodeBuffer.id);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.nodeManager.requestQueue.id);
|
|
||||||
|
|
||||||
//Bind the hiz buffer
|
|
||||||
glBindSampler(0, this.hizSampler);
|
|
||||||
glBindTextureUnit(0, this.hiz.getHizTextureId());
|
|
||||||
}
|
|
||||||
this.printf.bind();
|
|
||||||
{
|
|
||||||
//Dispatch hierarchies
|
|
||||||
}
|
|
||||||
|
|
||||||
this.nodeManager.download();
|
|
||||||
this.printf.download();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void free() {
|
|
||||||
this.printf.free();
|
|
||||||
this.hiz.free();
|
|
||||||
this.nodeManager.free();
|
|
||||||
glDeleteSamplers(this.hizSampler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package me.cortex.voxy.client.core.rendering;
|
||||||
|
|
||||||
|
|
||||||
|
import me.cortex.voxy.client.core.rendering.hierarchical.HierarchicalOcclusionRenderer;
|
||||||
|
import me.cortex.voxy.common.world.other.Mapper;
|
||||||
|
import net.minecraft.client.render.Camera;
|
||||||
|
import net.minecraft.client.render.Frustum;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL30.*;
|
||||||
|
|
||||||
|
public interface IRenderInterface <T extends Viewport> {
|
||||||
|
|
||||||
|
T createViewport();
|
||||||
|
|
||||||
|
void setupRender(Frustum frustum, Camera camera);
|
||||||
|
|
||||||
|
void renderFarAwayOpaque(T viewport);
|
||||||
|
|
||||||
|
void renderFarAwayTranslucent(T viewport);
|
||||||
|
|
||||||
|
void addDebugData(List<String> debug);
|
||||||
|
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
|
void addBlockState(Mapper.StateEntry stateEntry);
|
||||||
|
|
||||||
|
void addBiome(Mapper.BiomeEntry biomeEntry);
|
||||||
|
|
||||||
|
boolean generateMeshlets();
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package me.cortex.voxy.client.core.rendering;
|
|||||||
|
|
||||||
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.model.ModelManager;
|
||||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
|
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
|
||||||
import net.minecraft.client.render.Camera;
|
import net.minecraft.client.render.Camera;
|
||||||
@@ -52,8 +53,8 @@ public class NvMeshFarWorldRenderer extends AbstractFarWorldRenderer<NvMeshViewp
|
|||||||
.add(ShaderType.FRAGMENT, "voxy:lod/nvmesh/cull.frag")
|
.add(ShaderType.FRAGMENT, "voxy:lod/nvmesh/cull.frag")
|
||||||
.compile();
|
.compile();
|
||||||
|
|
||||||
public NvMeshFarWorldRenderer(int geometrySize, int maxSections) {
|
public NvMeshFarWorldRenderer(ModelManager modelManager, int geometrySize, int maxSections) {
|
||||||
super(new DefaultGeometryManager(geometrySize*8L, maxSections));
|
super(modelManager, new DefaultGeometryManager(geometrySize*8L, maxSections));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ import static org.lwjgl.opengl.GL45C.glClearNamedBufferData;
|
|||||||
public class NvMeshViewport extends Viewport<NvMeshViewport> {
|
public class NvMeshViewport extends Viewport<NvMeshViewport> {
|
||||||
GlBuffer visibilityBuffer;
|
GlBuffer visibilityBuffer;
|
||||||
public NvMeshViewport(NvMeshFarWorldRenderer renderer) {
|
public NvMeshViewport(NvMeshFarWorldRenderer renderer) {
|
||||||
super(renderer);
|
this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L).zero();
|
||||||
this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L);
|
|
||||||
glClearNamedBufferData(this.visibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, new int[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void delete0() {
|
protected void delete0() {
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
package me.cortex.voxy.client.core.rendering;
|
|
||||||
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL30.*;
|
|
||||||
import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME;
|
|
||||||
|
|
||||||
public class Test {
|
|
||||||
private final HierarchicalOcclusionRenderer hor = new HierarchicalOcclusionRenderer();
|
|
||||||
|
|
||||||
public void doIt(Viewport viewport) {
|
|
||||||
var i = new int[1];
|
|
||||||
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, i);
|
|
||||||
this.hor.render(i[0], viewport.width, viewport.height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ package me.cortex.voxy.client.core.rendering;
|
|||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
public abstract class Viewport <A extends Viewport<A>> {
|
public abstract class Viewport <A extends Viewport<A>> {
|
||||||
private final AbstractFarWorldRenderer renderer;
|
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
int frameId;
|
int frameId;
|
||||||
@@ -13,13 +12,11 @@ public abstract class Viewport <A extends Viewport<A>> {
|
|||||||
double cameraY;
|
double cameraY;
|
||||||
double cameraZ;
|
double cameraZ;
|
||||||
|
|
||||||
protected Viewport(AbstractFarWorldRenderer renderer) {
|
protected Viewport() {
|
||||||
this.renderer = renderer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void delete() {
|
public final void delete() {
|
||||||
this.delete0();
|
this.delete0();
|
||||||
this.renderer.removeViewport((A) this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void delete0();
|
protected abstract void delete0();
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package me.cortex.voxy.client.core.rendering.hierarchical;
|
||||||
|
|
||||||
|
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||||
|
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.HiZBuffer;
|
||||||
|
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
||||||
|
import me.cortex.voxy.client.core.rendering.hierarchical.INodeInteractor;
|
||||||
|
import me.cortex.voxy.client.core.rendering.hierarchical.MeshManager;
|
||||||
|
import me.cortex.voxy.client.core.rendering.hierarchical.NodeManager;
|
||||||
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL30.glBindBufferBase;
|
||||||
|
import static org.lwjgl.opengl.GL33.glBindSampler;
|
||||||
|
import static org.lwjgl.opengl.GL33.glGenSamplers;
|
||||||
|
import static org.lwjgl.opengl.GL42C.*;
|
||||||
|
import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BUFFER;
|
||||||
|
import static org.lwjgl.opengl.GL43.glDispatchCompute;
|
||||||
|
import static org.lwjgl.opengl.GL45.glBindTextureUnit;
|
||||||
|
|
||||||
|
public class HierarchicalOcclusionRenderer {
|
||||||
|
private PrintfInjector printf = new PrintfInjector(100000, 10, System.out::println);
|
||||||
|
|
||||||
|
private final MeshManager meshManager = new MeshManager();
|
||||||
|
private final NodeManager nodeManager = new NodeManager(new INodeInteractor() {
|
||||||
|
@Override
|
||||||
|
public void watchUpdates(long pos) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unwatchUpdates(long pos) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestMesh(long pos) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMeshUpdateCallback(Consumer<BuiltSection> mesh) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}, this.meshManager);
|
||||||
|
|
||||||
|
private final HiZBuffer hiz = new HiZBuffer();
|
||||||
|
|
||||||
|
private final int hizSampler = glGenSamplers();
|
||||||
|
|
||||||
|
private final Shader hierarchicalTraversal = Shader.make(this.printf)
|
||||||
|
.add(ShaderType.COMPUTE, "voxy:lod/hierarchical/traversal.comp")
|
||||||
|
.compile();
|
||||||
|
|
||||||
|
private final GlBuffer nodeQueue;
|
||||||
|
private final GlBuffer renderQueue;
|
||||||
|
private final GlBuffer uniformBuffer;
|
||||||
|
|
||||||
|
public HierarchicalOcclusionRenderer() {
|
||||||
|
this.nodeQueue = new GlBuffer(1000000*4+4).zero();
|
||||||
|
this.renderQueue = new GlBuffer(1000000*4+4).zero();
|
||||||
|
this.uniformBuffer = new GlBuffer(1024).zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void uploadUniform() {
|
||||||
|
long ptr = UploadStream.INSTANCE.upload(this.uniformBuffer, 0, 1024);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doHierarchicalTraversal(int depthBuffer, int width, int height) {
|
||||||
|
this.uploadUniform();
|
||||||
|
this.nodeManager.upload();
|
||||||
|
//Make hiz
|
||||||
|
this.hiz.buildMipChain(depthBuffer, width, height);
|
||||||
|
glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT);
|
||||||
|
this.hierarchicalTraversal.bind();
|
||||||
|
|
||||||
|
{
|
||||||
|
glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniformBuffer.id);
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.nodeManager.nodeBuffer.id);
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.nodeQueue.id);
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, this.nodeManager.requestQueue.id);
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, this.renderQueue.id);
|
||||||
|
|
||||||
|
//Bind the hiz buffer
|
||||||
|
glBindSampler(0, this.hizSampler);
|
||||||
|
glBindTextureUnit(0, this.hiz.getHizTextureId());
|
||||||
|
}
|
||||||
|
this.printf.bind();
|
||||||
|
{
|
||||||
|
//Dispatch hierarchies
|
||||||
|
glDispatchCompute(1,1,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.nodeManager.download();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void render(int depthBuffer, int width, int height) {
|
||||||
|
this.doHierarchicalTraversal(depthBuffer, width, height);
|
||||||
|
|
||||||
|
|
||||||
|
this.printf.download();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void free() {
|
||||||
|
this.nodeQueue.free();
|
||||||
|
this.renderQueue.free();
|
||||||
|
this.printf.free();
|
||||||
|
this.hiz.free();
|
||||||
|
this.nodeManager.free();
|
||||||
|
this.meshManager.free();
|
||||||
|
glDeleteSamplers(this.hizSampler);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,4 +30,8 @@ public class MeshManager {
|
|||||||
public void removeMesh(int mesh) {
|
public void removeMesh(int mesh) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void free() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import me.cortex.voxy.client.core.gl.GlBuffer;
|
|||||||
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.util.DownloadStream;
|
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
|
||||||
import me.cortex.voxy.client.core.rendering.util.MarkedObjectList;
|
import me.cortex.voxy.client.core.rendering.util.MarkedObjectList;
|
||||||
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
import me.cortex.voxy.common.util.HierarchicalBitSet;
|
import me.cortex.voxy.common.util.HierarchicalBitSet;
|
||||||
import me.cortex.voxy.common.world.WorldEngine;
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
@@ -25,7 +26,7 @@ import static org.lwjgl.opengl.GL45.nglClearNamedBufferSubData;
|
|||||||
|
|
||||||
//TODO: Make it an sparse voxel octree, that is if all of the children bar 1 are empty/air, remove the self node and replace it with the non empty child
|
//TODO: Make it an sparse voxel octree, that is if all of the children bar 1 are empty/air, remove the self node and replace it with the non empty child
|
||||||
|
|
||||||
public class NodeManager2 {
|
public class NodeManager {
|
||||||
//A request for making a new child nodes
|
//A request for making a new child nodes
|
||||||
private static final class LeafRequest {
|
private static final class LeafRequest {
|
||||||
//LoD position identifier
|
//LoD position identifier
|
||||||
@@ -98,9 +99,12 @@ public class NodeManager2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final int REQUEST_QUEUE_SIZE = 1024;
|
|
||||||
public static final int MAX_NODE_COUNT = 1<<22;
|
public static final int MAX_NODE_COUNT = 1<<22;
|
||||||
public static final int NODE_MSK = MAX_NODE_COUNT-1;
|
public static final int MAX_MESH_ID = 1<<24;
|
||||||
|
|
||||||
|
public static final int REQUEST_QUEUE_SIZE = 1024;
|
||||||
|
public static final int MESH_MSK = MAX_MESH_ID-1;
|
||||||
|
public static final int NODE_MSK = (1<<24)-1;//NOTE!! IS DIFFERENT FROM MAX_NODE_COUNT as the MAX_NODE_COUNT is for the buffers, the ACTUAL MAX is NODE_MSK+1
|
||||||
|
|
||||||
//Local data layout
|
//Local data layout
|
||||||
// first long is position (todo! might not be needed)
|
// first long is position (todo! might not be needed)
|
||||||
@@ -115,13 +119,20 @@ public class NodeManager2 {
|
|||||||
public final GlBuffer nodeBuffer;
|
public final GlBuffer nodeBuffer;
|
||||||
public final GlBuffer requestQueue;
|
public final GlBuffer requestQueue;
|
||||||
|
|
||||||
public NodeManager2(INodeInteractor interactor, MeshManager meshManager) {
|
public NodeManager(INodeInteractor interactor, MeshManager meshManager) {
|
||||||
this.interactor = interactor;
|
this.interactor = interactor;
|
||||||
this.pos2meshId.defaultReturnValue(NO_NODE);
|
this.pos2meshId.defaultReturnValue(NO_NODE);
|
||||||
this.interactor.setMeshUpdateCallback(this::meshUpdate);
|
this.interactor.setMeshUpdateCallback(this::meshUpdate);
|
||||||
this.meshManager = meshManager;
|
this.meshManager = meshManager;
|
||||||
this.nodeBuffer = new GlBuffer(MAX_NODE_COUNT*16);
|
this.nodeBuffer = new GlBuffer(MAX_NODE_COUNT*16);
|
||||||
this.requestQueue = new GlBuffer(REQUEST_QUEUE_SIZE*4+4);
|
this.requestQueue = new GlBuffer(REQUEST_QUEUE_SIZE*4+4);
|
||||||
|
Arrays.fill(this.localNodeData, 0);
|
||||||
|
|
||||||
|
|
||||||
|
this.setNodePosition(0, WorldEngine.getWorldSectionId(0, 0,5,0));
|
||||||
|
this.setChildPtr(0, NODE_MSK, 0);
|
||||||
|
this.setMeshId(0, MESH_MSK);
|
||||||
|
this.pushNode(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void insertTopLevelNode(long position) {
|
public void insertTopLevelNode(long position) {
|
||||||
@@ -137,21 +148,63 @@ public class NodeManager2 {
|
|||||||
|
|
||||||
//Returns the mesh offset/id for the given node or -1 if it doesnt exist
|
//Returns the mesh offset/id for the given node or -1 if it doesnt exist
|
||||||
private int getNodeMesh(int node) {
|
private int getNodeMesh(int node) {
|
||||||
return -1;
|
return (int) (this.localNodeData[node*3+1]&((1<<24)-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getNodeChildPtr(int node) {
|
||||||
|
return (int) ((this.localNodeData[node*3+1]>>>32)&NODE_MSK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getNodeChildCnt(int node) {
|
||||||
|
return (int) ((this.localNodeData[node*3+1]>>>61)&7)+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getNodePos(int node) {
|
private long getNodePos(int node) {
|
||||||
return -1;
|
return this.localNodeData[node*3];
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLeafNode(int node) {
|
private boolean isLeafNode(int node) {
|
||||||
return true;
|
//TODO: maybe make this flag based instead of checking the child ptr?
|
||||||
|
return this.getNodeChildPtr(node) != NODE_MSK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Its ment to return if the node is just an empty mesh or if all the children are also empty
|
||||||
|
private boolean isEmptyNode(int node) {
|
||||||
|
return this.getNodeMesh(node)==(MESH_MSK-1);//Special case/reserved
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setNodePosition(int node, long position) {
|
||||||
|
this.localNodeData[node*3] = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setMeshId(int node, int mesh) {
|
private void setMeshId(int node, int mesh) {
|
||||||
|
if (mesh > MESH_MSK) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
long val = this.localNodeData[node*3+1];
|
||||||
|
val &= ~MESH_MSK;
|
||||||
|
val |= mesh;
|
||||||
|
this.localNodeData[node*3+1] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setChildPtr(int node, int childPtr, int count) {
|
||||||
|
if (childPtr > NODE_MSK || (childPtr!=NODE_MSK&&count < 1)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
long val = this.localNodeData[node*3+1];
|
||||||
|
//Put the count
|
||||||
|
val &= ~(0x7L<<61);
|
||||||
|
val |= Integer.toUnsignedLong(Math.max(count-1,0))<<61;
|
||||||
|
//Put the child ptr
|
||||||
|
val &= ~(Integer.toUnsignedLong(NODE_MSK)<<32);
|
||||||
|
val |= Integer.toUnsignedLong(childPtr) << 32;
|
||||||
|
this.localNodeData[node*3+1] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static long makeChildPos(long basePos, int addin) {
|
private static long makeChildPos(long basePos, int addin) {
|
||||||
int lvl = WorldEngine.getLevel(basePos);
|
int lvl = WorldEngine.getLevel(basePos);
|
||||||
if (lvl == 0) {
|
if (lvl == 0) {
|
||||||
@@ -256,6 +309,9 @@ public class NodeManager2 {
|
|||||||
// that is, there is a request that is satisfied bar 1 section, that section is supplied as non emptpty but then becomes empty in the same tick
|
// that is, there is a request that is satisfied bar 1 section, that section is supplied as non emptpty but then becomes empty in the same tick
|
||||||
private void meshUpdate(BuiltSection mesh) {
|
private void meshUpdate(BuiltSection mesh) {
|
||||||
int id = this.pos2meshId.get(mesh.position);
|
int id = this.pos2meshId.get(mesh.position);
|
||||||
|
//TODO: FIXME!! if we get a node that has an update and is watched but no id for it, it could be an update state from
|
||||||
|
// an empty node to non empty node, this means we need to invalidate all the childrens positions and move them!
|
||||||
|
// then also update the parent pointer
|
||||||
if (id == NO_NODE) {
|
if (id == NO_NODE) {
|
||||||
//The built mesh section is no longer needed, discard it
|
//The built mesh section is no longer needed, discard it
|
||||||
// TODO: could probably?? cache the mesh in ram that way if its requested? it can be immediatly fetched while a newer mesh is built??
|
// TODO: could probably?? cache the mesh in ram that way if its requested? it can be immediatly fetched while a newer mesh is built??
|
||||||
@@ -359,16 +415,31 @@ public class NodeManager2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void writeNode(long dst, int id) {
|
private void writeNode(long dst, int id) {
|
||||||
|
long pos = this.localNodeData[id*3];
|
||||||
|
MemoryUtil.memPutInt(dst, (int) (pos>>32)); dst += 4;
|
||||||
|
MemoryUtil.memPutInt(dst, (int) pos); dst += 4;
|
||||||
|
|
||||||
|
int flags = 0;
|
||||||
|
flags |= this.isEmptyNode(id)?2:0;
|
||||||
|
flags |= Math.max(0, this.getNodeChildCnt(id)-1)<<2;
|
||||||
|
|
||||||
|
int a = this.getNodeMesh(id)|(flags&0xFF);
|
||||||
|
int b = this.getNodeChildPtr(id)|((flags>>8)&0xFF);
|
||||||
|
|
||||||
|
MemoryUtil.memPutInt(dst, a); dst += 4;
|
||||||
|
MemoryUtil.memPutInt(dst, b); dst += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void upload() {
|
public void upload() {
|
||||||
for (int i = 0; i < this.nodeUpdates.size(); i++) {
|
for (int i = 0; i < this.nodeUpdates.size(); i++) {
|
||||||
int node = this.nodeUpdates.getInt(i);
|
int node = this.nodeUpdates.getInt(i);
|
||||||
//TODO: UPLOAD NODE
|
long ptr = UploadStream.INSTANCE.upload(this.nodeBuffer, node*16L, 16);
|
||||||
|
this.writeNode(ptr, node);
|
||||||
|
}
|
||||||
|
if (!this.nodeUpdates.isEmpty()) {
|
||||||
|
UploadStream.INSTANCE.commit();//Cause we actually uploaded something (do it after cause it allows batch comitting thing)
|
||||||
|
this.nodeUpdates.clear();
|
||||||
}
|
}
|
||||||
this.nodeUpdates.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void download() {
|
public void download() {
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
#define SCENE_UNIFORM_INDEX 0
|
#define SCENE_UNIFORM_INDEX 0
|
||||||
#define NODE_DATA_INDEX 1
|
#define NODE_DATA_INDEX 1
|
||||||
#define REQUEST_QUEUE_INDEX 2
|
#define NODE_QUEUE_INDEX 2
|
||||||
#define RENDER_QUEUE_INDEX 3
|
#define REQUEST_QUEUE_INDEX 3
|
||||||
#define TRANSFORM_ARRAY_INDEX 4
|
#define RENDER_QUEUE_INDEX 4
|
||||||
|
#define TRANSFORM_ARRAY_INDEX 5
|
||||||
|
|
||||||
//Samplers
|
//Samplers
|
||||||
#define HIZ_BINDING_INDEX 0
|
#define HIZ_BINDING_INDEX 0
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ struct UnpackedNode {
|
|||||||
uint childPtr;
|
uint childPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NULL_NODE ((1<<25)-1)
|
#define NULL_NODE ((1<<24)-1)
|
||||||
#define NULL_MESH ((1<<24)-1)
|
#define NULL_MESH ((1<<24)-1)
|
||||||
|
|
||||||
void unpackNode(inout UnpackedNode node, uint nodeId) {
|
void unpackNode(out UnpackedNode node, uint nodeId) {
|
||||||
node.nodeId = nodeId;
|
|
||||||
uvec4 compactedNode = nodes[nodeId];
|
uvec4 compactedNode = nodes[nodeId];
|
||||||
|
node.nodeId = nodeId;
|
||||||
node.lodLevel = compactedNode.x >> 28;
|
node.lodLevel = compactedNode.x >> 28;
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -40,13 +40,12 @@ void unpackNode(inout UnpackedNode node, uint nodeId) {
|
|||||||
z |= int(compactedNode.y>>28);
|
z |= int(compactedNode.y>>28);
|
||||||
z <<= 8;
|
z <<= 8;
|
||||||
z >>= 8;
|
z >>= 8;
|
||||||
|
|
||||||
node.pos = ivec3(x, y, z);
|
node.pos = ivec3(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
node.meshPtr = compactedNode.z&0xFFFFFFu;
|
node.meshPtr = compactedNode.z&0xFFFFFFu;
|
||||||
node.childPtr = compactedNode.w&0x1FFFFFFu;
|
node.childPtr = compactedNode.w&0xFFFFFFu;
|
||||||
node.flags = (compactedNode.z>>24) | ((compactedNode.w>>23)<<8);
|
node.flags = ((compactedNode.z>>24)&0xFFu) | (((compactedNode.w>>24)&0xFFu)<<8);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasMesh(in UnpackedNode node) {
|
bool hasMesh(in UnpackedNode node) {
|
||||||
@@ -89,5 +88,5 @@ void markRequested(inout UnpackedNode node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void debugDumpNode(in UnpackedNode node) {
|
void debugDumpNode(in UnpackedNode node) {
|
||||||
printf("Node %d, %d@[%d,%d,%d], flags: %d, mesh: %d, ChildPtr: %d", node.nodeId, node.lodLevel, node.pos.x, node.pos.z, node.pos.z, node.flags, node.meshPtr, node.childPtr);
|
printf("Node %d, %d@[%d,%d,%d], flags: %d, mesh: %d, ChildPtr: %d", node.nodeId, node.lodLevel, node.pos.x, node.pos.y, node.pos.z, node.flags, node.meshPtr, node.childPtr);
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,11 @@ layout(binding = SCENE_UNIFORM_INDEX, std140) uniform SceneUniform {
|
|||||||
uint renderQueueMaxSize;
|
uint renderQueueMaxSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
layout(binding = NODE_QUEUE_INDEX, std430) restrict buffer NodeQueue {
|
||||||
|
uint nodeQueueSize;
|
||||||
|
uint[] nodeQueue;
|
||||||
|
};
|
||||||
|
|
||||||
layout(binding = REQUEST_QUEUE_INDEX, std430) restrict buffer RequestQueue {
|
layout(binding = REQUEST_QUEUE_INDEX, std430) restrict buffer RequestQueue {
|
||||||
uint requestQueueIndex;
|
uint requestQueueIndex;
|
||||||
uint[] requestQueue;
|
uint[] requestQueue;
|
||||||
@@ -35,6 +40,7 @@ layout(binding = RENDER_QUEUE_INDEX, std430) restrict buffer RenderQueue {
|
|||||||
uint[] renderQueue;
|
uint[] renderQueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
layout(binding = 2, std430) restrict buffer QueueData {
|
layout(binding = 2, std430) restrict buffer QueueData {
|
||||||
uint tail;
|
uint tail;
|
||||||
@@ -83,11 +89,11 @@ void addRequest(inout UnpackedNode node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void enqueueChildren(in UnpackedNode node) {
|
void enqueueChildren(in UnpackedNode node) {
|
||||||
printf("children");
|
//printf("children");
|
||||||
}
|
}
|
||||||
|
|
||||||
void enqueueSelfForRender(in UnpackedNode node) {
|
void enqueueSelfForRender(in UnpackedNode node) {
|
||||||
printf("render");
|
//printf("render");
|
||||||
if (renderQueueIndex < renderQueueMaxSize) {
|
if (renderQueueIndex < renderQueueMaxSize) {
|
||||||
renderQueue[atomicAdd(renderQueueIndex, 1)] = getMesh(node);
|
renderQueue[atomicAdd(renderQueueIndex, 1)] = getMesh(node);
|
||||||
}
|
}
|
||||||
@@ -98,17 +104,17 @@ void main() {
|
|||||||
UnpackedNode node;
|
UnpackedNode node;
|
||||||
|
|
||||||
//Setup/unpack the node
|
//Setup/unpack the node
|
||||||
unpackNode(node, gl_GlobalInvocationID.x);
|
unpackNode(node, nodeQueue[gl_GlobalInvocationID.x]);
|
||||||
|
|
||||||
//TODO: check the node is OK first??? maybe?
|
//TODO: check the node is OK first??? maybe?
|
||||||
|
|
||||||
//Compute screenspace
|
//Compute screenspace
|
||||||
setupScreenspace(node);
|
setupScreenspace(node);
|
||||||
|
|
||||||
debugDumpNode(node);
|
//debugDumpNode(node);
|
||||||
|
|
||||||
if (isCulledByHiz()) {
|
if (isCulledByHiz()) {
|
||||||
printf("HizCulled");
|
//printf("HizCulled");
|
||||||
//We are done here, dont do any more, the issue is the shader barriers maybe
|
//We are done here, dont do any more, the issue is the shader barriers maybe
|
||||||
// its culled, maybe just mark it as culled?
|
// its culled, maybe just mark it as culled?
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user