Work on the funny

This commit is contained in:
mcrcortex
2024-04-13 09:50:59 +10:00
parent 26301bfe1b
commit 9b433781a5
19 changed files with 443 additions and 41 deletions

View File

@@ -68,6 +68,10 @@ public class VoxelCore {
//Trigger the shared index buffer loading //Trigger the shared index buffer loading
SharedIndexBuffer.INSTANCE.id(); SharedIndexBuffer.INSTANCE.id();
if (true) {
this.renderer = new Gl46MeshletsFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
System.out.println("Using Gl46MeshletFarWorldRendering");
} else {
if (VoxyConfig.CONFIG.useMeshShaders()) { if (VoxyConfig.CONFIG.useMeshShaders()) {
this.renderer = new NvMeshFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); this.renderer = new NvMeshFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
System.out.println("Using NvMeshFarWorldRenderer"); System.out.println("Using NvMeshFarWorldRenderer");
@@ -75,6 +79,7 @@ public class VoxelCore {
this.renderer = new Gl46FarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); this.renderer = new Gl46FarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections);
System.out.println("Using Gl46FarWorldRenderer"); System.out.println("Using Gl46FarWorldRenderer");
} }
}
this.viewportSelector = new ViewportSelector<>(this.renderer::createViewport); this.viewportSelector = new ViewportSelector<>(this.renderer::createViewport);
System.out.println("Renderer initialized"); System.out.println("Renderer initialized");

View File

@@ -40,11 +40,11 @@ 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> { public abstract class AbstractFarWorldRenderer <T extends Viewport, J extends AbstractGeometryManager> {
public static final int STATIC_VAO = glGenVertexArrays(); public static final int STATIC_VAO = glGenVertexArrays();
protected final GlBuffer uniformBuffer; protected final GlBuffer uniformBuffer;
protected final GeometryManager geometry; protected final J geometry;
protected final ModelManager models; protected final ModelManager models;
protected final GlBuffer lightDataBuffer; protected final GlBuffer lightDataBuffer;
@@ -63,11 +63,11 @@ public abstract class AbstractFarWorldRenderer <T extends Viewport> {
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(int geometrySize, int maxSections) { public AbstractFarWorldRenderer(J geometry) {
this.maxSections = maxSections; 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 = new GeometryManager(geometrySize*8L, maxSections); this.geometry = geometry;
this.models = new ModelManager(16); this.models = new ModelManager(16);
} }

View File

@@ -0,0 +1,35 @@
package me.cortex.voxy.client.core.rendering;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
import java.util.concurrent.ConcurrentLinkedDeque;
public abstract class AbstractGeometryManager {
protected int sectionCount = 0;
protected final int maxSections;
protected final ConcurrentLinkedDeque<BuiltSection> buildResults = new ConcurrentLinkedDeque<>();
protected AbstractGeometryManager(int maxSections) {
this.maxSections = maxSections;
}
abstract IntArrayList uploadResults();
int getMaxSections() {
return this.maxSections;
}
public void enqueueResult(BuiltSection sectionGeometry) {
this.buildResults.add(sectionGeometry);
}
public abstract float getGeometryBufferUsage();
public int getSectionCount() {
return this.sectionCount;
}
public abstract void free();
}

View File

@@ -14,11 +14,8 @@ import org.lwjgl.system.MemoryUtil;
import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedDeque;
public class GeometryManager { public class DefaultGeometryManager extends AbstractGeometryManager {
private static final int SECTION_METADATA_SIZE = 32; private static final int SECTION_METADATA_SIZE = 32;
private final ConcurrentLinkedDeque<BuiltSection> buildResults = new ConcurrentLinkedDeque<>();
private int sectionCount = 0;
private final Long2IntOpenHashMap pos2id = new Long2IntOpenHashMap(); private final Long2IntOpenHashMap pos2id = new Long2IntOpenHashMap();
private final LongArrayList id2pos = new LongArrayList(); private final LongArrayList id2pos = new LongArrayList();
private final ObjectArrayList<SectionMeta> sectionMetadata = new ObjectArrayList<>(); private final ObjectArrayList<SectionMeta> sectionMetadata = new ObjectArrayList<>();
@@ -27,7 +24,8 @@ public class GeometryManager {
private final GlBuffer sectionMetaBuffer; private final GlBuffer sectionMetaBuffer;
private final BufferArena geometryBuffer; private final BufferArena geometryBuffer;
public GeometryManager(long geometryBufferSize, int maxSections) { public DefaultGeometryManager(long geometryBufferSize, int maxSections) {
super(maxSections);
this.sectionMetaBuffer = new GlBuffer(((long) maxSections) * SECTION_METADATA_SIZE); this.sectionMetaBuffer = new GlBuffer(((long) maxSections) * SECTION_METADATA_SIZE);
this.geometryBuffer = new BufferArena(geometryBufferSize, 8); this.geometryBuffer = new BufferArena(geometryBufferSize, 8);
this.pos2id.defaultReturnValue(-1); this.pos2id.defaultReturnValue(-1);
@@ -120,14 +118,6 @@ public class GeometryManager {
return this.markSectionIds; return this.markSectionIds;
} }
public void enqueueResult(BuiltSection sectionGeometry) {
this.buildResults.add(sectionGeometry);
}
public int getSectionCount() {
return this.sectionCount;
}
public void free() { public void free() {
while (!this.buildResults.isEmpty()) { while (!this.buildResults.isEmpty()) {
this.buildResults.pop().free(); this.buildResults.pop().free();
@@ -156,7 +146,7 @@ public class GeometryManager {
//TODO: pack the offsets of each axis so that implicit face culling can work //TODO: pack the offsets of each axis so that implicit face culling can work
//Note! the opaquePreDataCount and translucentPreDataCount are never writen to the meta buffer, as they are indexed in reverse relative to the base opaque and translucent geometry //Note! the opaquePreDataCount and translucentPreDataCount are never writen to the meta buffer, as they are indexed in reverse relative to the base opaque and translucent geometry
private record SectionMeta(long position, int aabb, int geometryPtr, int size, int[] offsets) { protected record SectionMeta(long position, int aabb, int geometryPtr, int size, int[] offsets) {
public void writeMetadata(long ptr) { public void writeMetadata(long ptr) {
//THIS IS DUE TO ENDIANNESS and that we are splitting a long into 2 ints //THIS IS DUE TO ENDIANNESS and that we are splitting a long into 2 ints
MemoryUtil.memPutInt(ptr, (int) (this.position>>32)); ptr += 4; MemoryUtil.memPutInt(ptr, (int) (this.position>>32)); ptr += 4;
@@ -171,7 +161,7 @@ public class GeometryManager {
} }
} }
private SectionMeta createMeta(BuiltSection geometry) { protected SectionMeta createMeta(BuiltSection geometry) {
int geometryPtr = (int) this.geometryBuffer.upload(geometry.geometryBuffer); int geometryPtr = (int) this.geometryBuffer.upload(geometry.geometryBuffer);
if (geometryPtr == -1) { if (geometryPtr == -1) {
String msg = "Buffer arena out of memory, please increase it in settings or decrease LoD quality"; String msg = "Buffer arena out of memory, please increase it in settings or decrease LoD quality";
@@ -182,10 +172,9 @@ public class GeometryManager {
return new SectionMeta(geometry.position, geometry.aabb, geometryPtr, (int) (geometry.geometryBuffer.size/8), geometry.offsets); return new SectionMeta(geometry.position, geometry.aabb, geometryPtr, (int) (geometry.geometryBuffer.size/8), geometry.offsets);
} }
private void freeMeta(SectionMeta meta) { protected void freeMeta(SectionMeta meta) {
if (meta.geometryPtr != -1) { if (meta.geometryPtr != -1) {
this.geometryBuffer.free(meta.geometryPtr); this.geometryBuffer.free(meta.geometryPtr);
} }
} }
} }

View File

@@ -1,5 +0,0 @@
package me.cortex.voxy.client.core.rendering;
public class FrustumLoDComputation {
}

View File

@@ -34,7 +34,7 @@ import static org.lwjgl.opengl.GL45.glBindTextureUnit;
import static org.lwjgl.opengl.GL45.glClearNamedBufferData; import static org.lwjgl.opengl.GL45.glClearNamedBufferData;
import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData; import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData;
public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer<Gl46Viewport> { public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer<Gl46Viewport, DefaultGeometryManager> {
private final Shader commandGen = Shader.make() private final Shader commandGen = Shader.make()
.add(ShaderType.COMPUTE, "voxy:lod/gl46/cmdgen.comp") .add(ShaderType.COMPUTE, "voxy:lod/gl46/cmdgen.comp")
.compile(); .compile();
@@ -55,7 +55,7 @@ public class Gl46FarWorldRenderer extends AbstractFarWorldRenderer<Gl46Viewport>
private final GlBuffer glCommandCountBuffer; private final GlBuffer glCommandCountBuffer;
public Gl46FarWorldRenderer(int geometryBuffer, int maxSections) { public Gl46FarWorldRenderer(int geometryBuffer, int maxSections) {
super(geometryBuffer, maxSections); super(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);

View File

@@ -0,0 +1,21 @@
package me.cortex.voxy.client.core.rendering;
import me.cortex.voxy.client.core.gl.GlBuffer;
import static org.lwjgl.opengl.GL30C.GL_R8UI;
import static org.lwjgl.opengl.GL30C.GL_RED_INTEGER;
import static org.lwjgl.opengl.GL42.GL_UNSIGNED_BYTE;
import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData;
public class Gl46MeshletViewport extends Viewport<Gl46MeshletViewport> {
GlBuffer visibilityBuffer;
public Gl46MeshletViewport(Gl46MeshletsFarWorldRenderer renderer) {
super(renderer);
this.visibilityBuffer = new GlBuffer(renderer.maxSections*4L);
nglClearNamedBufferData(this.visibilityBuffer.id, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 0);
}
protected void delete0() {
this.visibilityBuffer.free();
}
}

View File

@@ -0,0 +1,164 @@
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.util.UploadStream;
import me.cortex.voxy.client.mixin.joml.AccessFrustumIntersection;
import net.minecraft.client.render.RenderLayer;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.system.MemoryUtil;
import static org.lwjgl.opengl.ARBIndirectParameters.GL_PARAMETER_BUFFER_ARB;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL14C.glBlendFuncSeparate;
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;
import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData;
import static org.lwjgl.opengl.NVMeshShader.glDrawMeshTasksNV;
import static org.lwjgl.opengl.NVRepresentativeFragmentTest.GL_REPRESENTATIVE_FRAGMENT_TEST_NV;
public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46MeshletViewport, DefaultGeometryManager> {
private final Shader meshletGenerator = Shader.make()
.add(ShaderType.COMPUTE, "voxy:lod/gl46mesh/cmdgen.comp")
.compile();
private final Shader lodShader = Shader.make()
.add(ShaderType.VERTEX, "voxy:lod/gl46mesh/quads.vert")
.add(ShaderType.FRAGMENT, "voxy:lod/gl46mesh/quads.frag")
.compile();
private final Shader cullShader = Shader.make()
.add(ShaderType.VERTEX, "voxy:lod/gl46mesh/cull.vert")
.add(ShaderType.FRAGMENT, "voxy:lod/gl46mesh/cull.frag")
.compile();
private final GlBuffer glDrawIndirect;
private final GlBuffer meshletBuffer;
public Gl46MeshletsFarWorldRenderer(int geometrySize, int maxSections) {
super(new DefaultGeometryManager(geometrySize*8L, maxSections));
this.glDrawIndirect = new GlBuffer(4*5);
this.meshletBuffer = new GlBuffer(4*1000000);//TODO: Make max meshlet count configurable
}
protected void bindResources(Gl46MeshletViewport viewport) {
glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniformBuffer.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.geometry.geometryId());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, this.glDrawIndirect.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, this.meshletBuffer.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, this.geometry.metaId());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, viewport.visibilityBuffer.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, this.models.getBufferId());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, this.models.getColourBufferId());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 8, this.lightDataBuffer.id);//Lighting LUT
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, this.glDrawIndirect.id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedIndexBuffer.INSTANCE.id());
//Bind the texture atlas
glBindSampler(0, this.models.getSamplerId());
glBindTextureUnit(0, this.models.getTextureId());
}
private void updateUniformBuffer(Gl46MeshletViewport viewport) {
long ptr = UploadStream.INSTANCE.upload(this.uniformBuffer, 0, this.uniformBuffer.size());
var mat = new Matrix4f(viewport.projection).mul(viewport.modelView);
var innerTranslation = new Vector3f((float) (viewport.cameraX-(this.sx<<5)), (float) (viewport.cameraY-(this.sy<<5)), (float) (viewport.cameraZ-(this.sz<<5)));
mat.translate(-innerTranslation.x, -innerTranslation.y, -innerTranslation.z);
mat.getToAddress(ptr); ptr += 4*4*4;
MemoryUtil.memPutInt(ptr, this.sx); ptr += 4;
MemoryUtil.memPutInt(ptr, this.sy); ptr += 4;
MemoryUtil.memPutInt(ptr, this.sz); ptr += 4;
MemoryUtil.memPutInt(ptr, this.geometry.getSectionCount()); ptr += 4;
var planes = ((AccessFrustumIntersection)this.frustum).getPlanes();
for (var plane : planes) {
plane.getToAddress(ptr); ptr += 4*4;
}
innerTranslation.getToAddress(ptr); ptr += 4*3;
MemoryUtil.memPutInt(ptr, viewport.frameId++); ptr += 4;
}
@Override
public void renderFarAwayOpaque(Gl46MeshletViewport viewport) {
if (this.geometry.getSectionCount() == 0) {
return;
}
{//Mark all of the updated sections as being visible from last frame
for (int id : this.updatedSectionIds) {
long ptr = UploadStream.INSTANCE.upload(viewport.visibilityBuffer, id * 4L, 4);
MemoryUtil.memPutInt(ptr, viewport.frameId - 1);//(visible from last frame)
}
}
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
this.updateUniformBuffer(viewport);
UploadStream.INSTANCE.commit();
glBindVertexArray(AbstractFarWorldRenderer.STATIC_VAO);
nglClearNamedBufferSubData(this.glDrawIndirect.id, GL_R32UI, 4, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
this.meshletGenerator.bind();
this.bindResources(viewport);
glDispatchCompute((this.geometry.getSectionCount()+63)/64, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT);
this.lodShader.bind();
this.bindResources(viewport);
glDisable(GL_CULL_FACE);
glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, 0);
glEnable(GL_CULL_FACE);
glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT | GL_FRAMEBUFFER_BARRIER_BIT);
this.cullShader.bind();
this.bindResources(viewport);
glDepthMask(false);
glColorMask(false, false, false, false);
glDrawElementsInstanced(GL_TRIANGLES, 6 * 2 * 3, GL_UNSIGNED_BYTE, (1 << 16) * 6 * 2, this.geometry.getSectionCount());
glColorMask(true, true, true, true);
glDepthMask(true);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
}
@Override
public void renderFarAwayTranslucent(Gl46MeshletViewport viewport) {
}
@Override
protected Gl46MeshletViewport createViewport0() {
return new Gl46MeshletViewport(this);
}
@Override
public void shutdown() {
super.shutdown();
this.meshletGenerator.free();
this.lodShader.free();
this.cullShader.free();
this.glDrawIndirect.free();
this.meshletBuffer.free();
}
}

View File

@@ -9,7 +9,7 @@ import static org.lwjgl.opengl.GL42.GL_UNSIGNED_BYTE;
import static org.lwjgl.opengl.GL45C.glClearNamedBufferData; import static org.lwjgl.opengl.GL45C.glClearNamedBufferData;
import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData; import static org.lwjgl.opengl.GL45C.nglClearNamedBufferData;
public class Gl46Viewport extends Viewport<Gl46Viewport, Gl46FarWorldRenderer> { public class Gl46Viewport extends Viewport<Gl46Viewport> {
GlBuffer visibilityBuffer; GlBuffer visibilityBuffer;
public Gl46Viewport(Gl46FarWorldRenderer renderer) { public Gl46Viewport(Gl46FarWorldRenderer renderer) {
super(renderer); super(renderer);

View File

@@ -34,7 +34,7 @@ import static org.lwjgl.opengl.GL45.glBindTextureUnit;
import static org.lwjgl.opengl.NVMeshShader.glDrawMeshTasksNV; import static org.lwjgl.opengl.NVMeshShader.glDrawMeshTasksNV;
import static org.lwjgl.opengl.NVRepresentativeFragmentTest.GL_REPRESENTATIVE_FRAGMENT_TEST_NV; import static org.lwjgl.opengl.NVRepresentativeFragmentTest.GL_REPRESENTATIVE_FRAGMENT_TEST_NV;
public class NvMeshFarWorldRenderer extends AbstractFarWorldRenderer<NvMeshViewport> { public class NvMeshFarWorldRenderer extends AbstractFarWorldRenderer<NvMeshViewport, DefaultGeometryManager> {
private final Shader terrain = Shader.make() private final Shader terrain = Shader.make()
.add(ShaderType.TASK, "voxy:lod/nvmesh/primary.task") .add(ShaderType.TASK, "voxy:lod/nvmesh/primary.task")
.add(ShaderType.MESH, "voxy:lod/nvmesh/primary.mesh") .add(ShaderType.MESH, "voxy:lod/nvmesh/primary.mesh")
@@ -53,7 +53,7 @@ public class NvMeshFarWorldRenderer extends AbstractFarWorldRenderer<NvMeshViewp
.compile(); .compile();
public NvMeshFarWorldRenderer(int geometrySize, int maxSections) { public NvMeshFarWorldRenderer(int geometrySize, int maxSections) {
super(geometrySize, maxSections); super(new DefaultGeometryManager(geometrySize*8L, maxSections));
} }

View File

@@ -7,7 +7,7 @@ import static org.lwjgl.opengl.GL30C.GL_RED_INTEGER;
import static org.lwjgl.opengl.GL42.GL_UNSIGNED_BYTE; import static org.lwjgl.opengl.GL42.GL_UNSIGNED_BYTE;
import static org.lwjgl.opengl.GL45C.glClearNamedBufferData; import static org.lwjgl.opengl.GL45C.glClearNamedBufferData;
public class NvMeshViewport extends Viewport<NvMeshViewport, NvMeshFarWorldRenderer> { public class NvMeshViewport extends Viewport<NvMeshViewport> {
GlBuffer visibilityBuffer; GlBuffer visibilityBuffer;
public NvMeshViewport(NvMeshFarWorldRenderer renderer) { public NvMeshViewport(NvMeshFarWorldRenderer renderer) {
super(renderer); super(renderer);

View File

@@ -2,8 +2,8 @@ package me.cortex.voxy.client.core.rendering;
import org.joml.Matrix4f; import org.joml.Matrix4f;
public abstract class Viewport <A extends Viewport<A,T>, T extends AbstractFarWorldRenderer<A>> { public abstract class Viewport <A extends Viewport<A>> {
private final T renderer; private final AbstractFarWorldRenderer renderer;
int frameId; int frameId;
Matrix4f projection; Matrix4f projection;
@@ -12,7 +12,7 @@ public abstract class Viewport <A extends Viewport<A,T>, T extends AbstractFarWo
double cameraY; double cameraY;
double cameraZ; double cameraZ;
protected Viewport(T renderer) { protected Viewport(AbstractFarWorldRenderer renderer) {
this.renderer = renderer; this.renderer = renderer;
} }

View File

@@ -0,0 +1,76 @@
struct BlockModel {
uint faceData[6];
uint flagsA;
uint colourTint;
uint _pad[8];
};
struct SectionMeta {
uint posA;
uint posB;
uint AABB;
uint ptr;
uint cntA;
uint cntB;
uint cntC;
uint cntD;
};
//TODO: see if making the stride 2*4*4 bytes or something cause you get that 16 byte write
struct DrawCommand {
uint count;
uint instanceCount;
uint firstIndex;
int baseVertex;
uint baseInstance;
};
layout(binding = 0) uniform sampler2D blockModelAtlas;
#ifndef Quad
#define Quad ivec2
#endif
layout(binding = 1, std430) readonly restrict buffer QuadBuffer {
Quad quadData[];
};
layout(binding = 2, std430) restrict buffer DrawBuffer {
DrawCommand drawCmd;
};
#ifndef Quad
#define MESHLET_ACCESS readonly writeonly
#endif
layout(binding = 3, std430) MESHLET_ACCESS restrict buffer MeshletListData {
uint meshlets[];
};
layout(binding = 4, std430) readonly restrict buffer SectionBuffer {
SectionMeta sectionData[];
};
#ifndef VISIBILITY_ACCESS
#define VISIBILITY_ACCESS readonly
#endif
layout(binding = 5, std430) VISIBILITY_ACCESS restrict buffer VisibilityBuffer {
uint visibilityData[];
};
layout(binding = 6, std430) readonly restrict buffer ModelBuffer {
BlockModel modelData[];
};
layout(binding = 7, std430) readonly restrict buffer ModelColourBuffer {
uint colourData[];
};
layout(binding = 8, std430) readonly restrict buffer LightingBuffer {
uint lightData[];
};
vec4 getLighting(uint index) {
uvec4 arr = uvec4(lightData[index]);
arr = arr>>uvec4(16,8,0,24);
arr = arr & uvec4(0xFF);
return vec4(arr)*vec4(1.0f/255.0f);
}

View File

@@ -0,0 +1,60 @@
#version 450
#define MESHLET_ACCESS writeonly
#import <voxy:lod/quad_format.glsl>
#import <voxy:lod/gl46mesh/bindings.glsl>
#import <voxy:lod/section.glsl>
#define extractMeshletStart extractQuadStart
layout(local_size_x = 64) in;
#define QUADS_PER_MESHLET 126
void emitMeshlets(inout uint mli, inout uint meshletPtr, uint mskedCnt, uint cnt) {
for (;mskedCnt != 0; mskedCnt--,mli++) {
meshlets[mli] = meshletPtr + (mskedCnt-1);
}
meshletPtr += cnt;
}
void main() {
if (gl_GlobalInvocationID.x == 0) {
//Setup the remaining state of the drawElementsIndirect command
drawCmd.count = QUADS_PER_MESHLET*6;
drawCmd.firstIndex = 0;
drawCmd.baseVertex = 0;
drawCmd.baseInstance = 0;
}
if (gl_GlobalInvocationID.x >= sectionCount) {
return;
}
//Check the occlusion data from last frame
bool shouldRender = visibilityData[gl_GlobalInvocationID.x] == frameId - 1;
if (shouldRender) {
SectionMeta meta = sectionData[gl_GlobalInvocationID.x];
uint detail = extractDetail(meta);
ivec3 ipos = extractPosition(meta);
ivec3 relative = ipos-(baseSectionPos>>detail);
uint a = ((meta.cntA>>16)&0xFFFF);
uint u = (meta.cntB &0xFFFF) * uint(relative.y>-1);
uint d = ((meta.cntB>>16)&0xFFFF) * uint(relative.y<1 );
uint s = (meta.cntC &0xFFFF) * uint(relative.z>-1);
uint n = ((meta.cntC>>16)&0xFFFF) * uint(relative.z<1 );
uint w = (meta.cntD &0xFFFF) * uint(relative.x>-1);
uint e = ((meta.cntD>>16)&0xFFFF) * uint(relative.x<1 );
uint total = a + u + d + s + n + w + e;
uint mli = atomicAdd(drawCmd.instanceCount, total);//meshletListIndex
uint meshletPtr = extractMeshletStart(meta);
emitMeshlets(mli, meshletPtr, a, a);
emitMeshlets(mli, meshletPtr, u, (meta.cntB &0xFFFF));
emitMeshlets(mli, meshletPtr, d, ((meta.cntB>>16)&0xFFFF));
emitMeshlets(mli, meshletPtr, s, (meta.cntC &0xFFFF));
emitMeshlets(mli, meshletPtr, n, ((meta.cntC>>16)&0xFFFF));
emitMeshlets(mli, meshletPtr, w, (meta.cntD &0xFFFF));
emitMeshlets(mli, meshletPtr, e, ((meta.cntD>>16)&0xFFFF));
//TODO: also increment a secondary atomic buffer that can be used to do a compute pass over all meshlets (need to basicly divide the meshletCounter by the computes workGroup size)
}
}

View File

@@ -0,0 +1,3 @@
#version 450
void main() {
}

View File

@@ -0,0 +1,3 @@
#version 450
void main() {
}

View File

@@ -0,0 +1,5 @@
#version 460 core
layout(location = 0) out vec4 outColour;
void main() {
outColour = vec4(1,0,0,1);
}

View File

@@ -0,0 +1,38 @@
#version 450
#define MESHLET_ACCESS readonly
#define QUADS_PER_MESHLET 126
//There are 16 bytes of metadata at the start of the meshlet
#define MESHLET_SIZE (QUADS_PER_MESHLET+2)
#import <voxy:lod/quad_format.glsl>
#import <voxy:lod/gl46mesh/bindings.glsl>
#import <voxy:lod/section.glsl>
uvec2 meshletPosition;
Quad quad;
bool setupMeshlet() {
gl_CullDistance[0] = 1;
//TODO: replace with vertexAttribute that has a divisor of 1
uint data = meshlets[gl_InstanceID];
if (data == uint(-1)) {//Came across a culled meshlet
gl_CullDistance[0] = -1;
//Since the primative is culled, dont need to do any more work or set any values as the primative is discarded
// we dont need to care about undefined values
return true;
}
uint baseId = (data*QUADS_PER_MESHLET);
uint quadIndex = baseId + (gl_VertexID>>2) + 2;
meshletPosition = geometryPool[baseId];
quad = geometryPool[quadIndex];
if (isQuadEmpty(quad)) {
gl_CullDistance[0] = -1;
return true;
}
return false;
}
void main() {
if (setupMeshlet()) {
return;
}
}

View File

@@ -29,6 +29,10 @@ uint extractLightId(uint64_t quad) {
return Eu32(quad, 8, 55); return Eu32(quad, 8, 55);
} }
bool isQuadEmpty(uint64_t quad) {
return quad == uint64_t(0);
}
#else #else
//TODO: FIXME, ivec2 swaps around the data of the x and y cause its written in little endian //TODO: FIXME, ivec2 swaps around the data of the x and y cause its written in little endian
@@ -69,4 +73,8 @@ uint extractBiomeId(ivec2 quad) {
uint extractLightId(ivec2 quad) { uint extractLightId(ivec2 quad) {
return Eu32v(quad, 8, 55); return Eu32v(quad, 8, 55);
} }
bool isQuadEmpty(ivec2 quad) {
return all(equal(quad, ivec2(0)));
}
#endif #endif