This commit is contained in:
mcrcortex
2024-04-17 11:22:11 +10:00
parent 6ebc4739b9
commit 52baa303dc
12 changed files with 317 additions and 89 deletions

View File

@@ -23,7 +23,7 @@ public class DistanceTracker {
private final int maxYSection; private final int maxYSection;
private final int renderDistance; private final int renderDistance;
public DistanceTracker(RenderTracker tracker, int[] lodRingScales, int renderDistance, int cacheDistance, int minY, int maxY) { public DistanceTracker(RenderTracker tracker, int[] lodRingScales, int renderDistance, int minY, int maxY) {
this.loDRings = new TransitionRing2D[lodRingScales.length]; this.loDRings = new TransitionRing2D[lodRingScales.length];
this.cacheLoadRings = new TransitionRing2D[lodRingScales.length]; this.cacheLoadRings = new TransitionRing2D[lodRingScales.length];
this.cacheUnloadRings = new TransitionRing2D[lodRingScales.length]; this.cacheUnloadRings = new TransitionRing2D[lodRingScales.length];
@@ -72,34 +72,28 @@ public class DistanceTracker {
// the issue is when to uncache these methods // the issue is when to uncache these methods
/* /*
this.cacheLoadRings[i] = new TransitionRing2D(5 + i, (scale << 1) + cacheDistance, (x, z) -> { //TODO: FIX AND FINISH!!!
this.cacheLoadRings[i] = new TransitionRing2D(5 + i, (scale << 1) + 2, (x, z) -> {
//When entering a cache ring, trigger a mesh op and inject into cache //When entering a cache ring, trigger a mesh op and inject into cache
for (int y = this.minYSection >> capRing; y <= this.maxYSection >> capRing; y++) { for (int y = this.minYSection >> capRing; y <= this.maxYSection >> capRing; y++) {
this.tracker.addCache(capRing, x, y, z); this.tracker.addCache(capRing, x, y, z);
} }
}, (x, z) -> { }, (x, z) -> {
int shift = capRing+1;
if (shift <= this.loDRings.length) {
for (int y = this.minYSection >> shift; y <= this.maxYSection >> shift; y++) {
this.tracker.removeCache(shift, x>>1, y, z>>1);
}
}
});
this.cacheUnloadRings[i] = new TransitionRing2D(5 + i, Math.max(1, (scale << 1) + cacheDistance), (x, z) -> {
int shift = capRing+1;
if (shift <= this.loDRings.length) {
for (int y = this.minYSection >> shift; y <= this.maxYSection >> shift; y++) {
this.tracker.addCache(shift, x>>1, y, z>>1);
}
}
}, (x, z) -> {
//When exiting the cache unload ring, tell the cache to dump whatever mesh it has cached and not add any mesh from that position
for (int y = this.minYSection >> capRing; y <= this.maxYSection >> capRing; y++) { for (int y = this.minYSection >> capRing; y <= this.maxYSection >> capRing; y++) {
this.tracker.removeCache(capRing, x, y, z); this.tracker.removeCache(capRing, x, y, z);
} }
}); });
*/
this.cacheUnloadRings[i] = new TransitionRing2D(5 + i, Math.max(1, (scale << 1) - 2), (x, z) -> {
for (int y = this.minYSection >> capRing; y <= this.maxYSection >> capRing; y++) {
this.tracker.removeCache(capRing, x, y, z);
}
}, (x, z) -> {
});
*/
} }
if (isTerminatingRing) { if (isTerminatingRing) {

View File

@@ -104,7 +104,7 @@ public class VoxelCore {
this.distanceTracker = new DistanceTracker(this.renderTracker, new int[]{q,q,q,q}, this.distanceTracker = new DistanceTracker(this.renderTracker, new int[]{q,q,q,q},
(VoxyConfig.CONFIG.renderDistance<0?VoxyConfig.CONFIG.renderDistance:((VoxyConfig.CONFIG.renderDistance+1)/2)), (VoxyConfig.CONFIG.renderDistance<0?VoxyConfig.CONFIG.renderDistance:((VoxyConfig.CONFIG.renderDistance+1)/2)),
3, minY, maxY); minY, maxY);
System.out.println("Distance tracker initialized"); System.out.println("Distance tracker initialized");
this.postProcessing = new PostProcessing(); this.postProcessing = new PostProcessing();
@@ -187,7 +187,11 @@ public class VoxelCore {
var projection = computeProjectionMat(); var projection = computeProjectionMat();
//var projection = RenderSystem.getProjectionMatrix();//computeProjectionMat(); //var projection = RenderSystem.getProjectionMatrix();//computeProjectionMat();
var viewport = this.viewportSelector.getViewport(); var viewport = this.viewportSelector.getViewport();
viewport.setProjection(projection).setModelView(matrices.peek().getPositionMatrix()).setCamera(cameraX, cameraY, cameraZ); viewport
.setProjection(projection)
.setModelView(matrices.peek().getPositionMatrix())
.setCamera(cameraX, cameraY, cameraZ)
.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);
this.postProcessing.setup(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight, boundFB); this.postProcessing.setup(MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight, boundFB);

View File

@@ -42,10 +42,6 @@ import static org.lwjgl.opengl.NVRepresentativeFragmentTest.GL_REPRESENTATIVE_FR
// the shader can cull the verticies of any quad that has its index over the expected quuad count // the shader can cull the verticies of any quad that has its index over the expected quuad count
// this could potentially result in a fair bit of memory savings (especially if used in normal mc terrain rendering) // this could potentially result in a fair bit of memory savings (especially if used in normal mc terrain rendering)
public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46MeshletViewport, DefaultGeometryManager> { 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() private final Shader lodShader = Shader.make()
.add(ShaderType.VERTEX, "voxy:lod/gl46mesh/quads.vert") .add(ShaderType.VERTEX, "voxy:lod/gl46mesh/quads.vert")
.add(ShaderType.FRAGMENT, "voxy:lod/gl46mesh/quads.frag") .add(ShaderType.FRAGMENT, "voxy:lod/gl46mesh/quads.frag")
@@ -56,17 +52,26 @@ public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46M
.add(ShaderType.FRAGMENT, "voxy:lod/gl46mesh/cull.frag") .add(ShaderType.FRAGMENT, "voxy:lod/gl46mesh/cull.frag")
.compile(); .compile();
private final Shader meshletGenerator = Shader.make()
.add(ShaderType.COMPUTE, "voxy:lod/gl46mesh/cmdgen.comp")
.compile();
private final Shader meshletCuller = Shader.make()
.add(ShaderType.COMPUTE, "voxy:lod/gl46mesh/meshletculler.comp")
.compile();
private final GlBuffer glDrawIndirect; private final GlBuffer glDrawIndirect;
private final GlBuffer meshletBuffer; private final GlBuffer meshletBuffer;
private final HiZBuffer hiZBuffer = new HiZBuffer(); private final HiZBuffer hiZBuffer = new HiZBuffer();
private final int hizSampler = glGenSamplers();
public Gl46MeshletsFarWorldRenderer(int geometrySize, int maxSections) { public Gl46MeshletsFarWorldRenderer(int geometrySize, int maxSections) {
super(new DefaultGeometryManager(alignUp(geometrySize*8L, 8*32), maxSections, 8*32)); super(new DefaultGeometryManager(alignUp(geometrySize*8L, 8*32), maxSections, 8*32));
this.glDrawIndirect = new GlBuffer(4*5); this.glDrawIndirect = new GlBuffer(4*(4+5));
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);//TODO: Make max meshlet count configurable, not just 1 million (even tho thats a max of 126 million quads per frame)
} }
protected void bindResources(Gl46MeshletViewport viewport, boolean bindToDrawIndirect) { protected void bindResources(Gl46MeshletViewport viewport, boolean bindToDrawIndirect, boolean bindToDispatchIndirect, boolean bindHiz) {
glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniformBuffer.id); glBindBufferBase(GL_UNIFORM_BUFFER, 0, this.uniformBuffer.id);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.geometry.geometryId()); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, this.geometry.geometryId());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, bindToDrawIndirect?0:this.glDrawIndirect.id); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, bindToDrawIndirect?0:this.glDrawIndirect.id);
@@ -77,11 +82,18 @@ public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46M
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, this.models.getColourBufferId()); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, this.models.getColourBufferId());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 8, this.lightDataBuffer.id);//Lighting LUT glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 8, this.lightDataBuffer.id);//Lighting LUT
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, bindToDrawIndirect?this.glDrawIndirect.id:0); glBindBuffer(GL_DRAW_INDIRECT_BUFFER, bindToDrawIndirect?this.glDrawIndirect.id:0);
glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, bindToDispatchIndirect?this.glDrawIndirect.id:0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedIndexBuffer.INSTANCE_BYTE.id()); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedIndexBuffer.INSTANCE_BYTE.id());
//Bind the texture atlas if (!bindHiz) {
glBindSampler(0, this.models.getSamplerId()); //Bind the texture atlas
glBindTextureUnit(0, this.models.getTextureId()); glBindSampler(0, this.models.getSamplerId());
glBindTextureUnit(0, this.models.getTextureId());
} else {
//Bind the hiz buffer
glBindSampler(0, this.hizSampler);
glBindTextureUnit(0, this.hiZBuffer.getHizTextureId());
}
} }
private void updateUniformBuffer(Gl46MeshletViewport viewport) { private void updateUniformBuffer(Gl46MeshletViewport viewport) {
@@ -101,6 +113,8 @@ public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46M
} }
innerTranslation.getToAddress(ptr); ptr += 4*3; innerTranslation.getToAddress(ptr); ptr += 4*3;
MemoryUtil.memPutInt(ptr, viewport.frameId++); ptr += 4; MemoryUtil.memPutInt(ptr, viewport.frameId++); ptr += 4;
MemoryUtil.memPutInt(ptr, viewport.width); ptr += 4;
MemoryUtil.memPutInt(ptr, viewport.height); ptr += 4;
} }
@Override @Override
@@ -124,24 +138,18 @@ public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46M
UploadStream.INSTANCE.commit(); UploadStream.INSTANCE.commit();
glBindVertexArray(AbstractFarWorldRenderer.STATIC_VAO); glBindVertexArray(AbstractFarWorldRenderer.STATIC_VAO);
nglClearNamedBufferSubData(this.glDrawIndirect.id, GL_R32UI, 4, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0); nglClearNamedBufferSubData(this.glDrawIndirect.id, GL_R32UI, 0, 4*4, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
this.meshletGenerator.bind();
this.bindResources(viewport, false);
glDispatchCompute((this.geometry.getSectionCount()+63)/64, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT);
this.lodShader.bind(); this.lodShader.bind();
this.bindResources(viewport, true); this.bindResources(viewport, true, false, false);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_BYTE, 0); glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_BYTE, 4*4);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT | GL_FRAMEBUFFER_BARRIER_BIT); glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT | GL_FRAMEBUFFER_BARRIER_BIT);
this.cullShader.bind(); this.cullShader.bind();
this.bindResources(viewport, false); this.bindResources(viewport, false, false, false);
glDepthMask(false); glDepthMask(false);
glColorMask(false, false, false, false); glColorMask(false, false, false, false);
glDrawElementsInstanced(GL_TRIANGLES, 6 * 2 * 3, GL_UNSIGNED_BYTE, (1 << 8) * 6, this.geometry.getSectionCount()); glDrawElementsInstanced(GL_TRIANGLES, 6 * 2 * 3, GL_UNSIGNED_BYTE, (1 << 8) * 6, this.geometry.getSectionCount());
@@ -150,12 +158,20 @@ public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46M
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
this.meshletGenerator.bind();
this.bindResources(viewport, false, false, false);
glDispatchCompute((this.geometry.getSectionCount()+63)/64, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT);
var i = new int[1]; var i = new int[1];
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, i); glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, i);
this.hiZBuffer.buildMipChain(i[0], MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight); this.hiZBuffer.buildMipChain(i[0], MinecraftClient.getInstance().getFramebuffer().textureWidth, MinecraftClient.getInstance().getFramebuffer().textureHeight);
this.meshletCuller.bind();
this.bindResources(viewport, false, true, true);
glDispatchComputeIndirect(0);
glBindVertexArray(0); glBindVertexArray(0);
@@ -178,14 +194,16 @@ public class Gl46MeshletsFarWorldRenderer extends AbstractFarWorldRenderer<Gl46M
@Override @Override
public void shutdown() { public void shutdown() {
super.shutdown(); super.shutdown();
this.meshletGenerator.free();
this.lodShader.free(); this.lodShader.free();
this.cullShader.free(); this.cullShader.free();
this.meshletGenerator.free();
this.meshletCuller.free();
this.glDrawIndirect.free(); this.glDrawIndirect.free();
this.meshletBuffer.free(); this.meshletBuffer.free();
this.hiZBuffer.free(); this.hiZBuffer.free();
glDeleteSamplers(this.hizSampler);
} }
public static long alignUp(long n, long alignment) { public static long alignUp(long n, long alignment) {

View File

@@ -95,4 +95,8 @@ public class HiZBuffer {
this.texture = null; this.texture = null;
glDeleteSamplers(this.sampler); glDeleteSamplers(this.sampler);
} }
public int getHizTextureId() {
return this.texture.id;
}
} }

View File

@@ -4,7 +4,8 @@ import org.joml.Matrix4f;
public abstract class Viewport <A extends Viewport<A>> { public abstract class Viewport <A extends Viewport<A>> {
private final AbstractFarWorldRenderer renderer; private final AbstractFarWorldRenderer renderer;
int width;
int height;
int frameId; int frameId;
Matrix4f projection; Matrix4f projection;
Matrix4f modelView; Matrix4f modelView;
@@ -39,4 +40,10 @@ public abstract class Viewport <A extends Viewport<A>> {
this.cameraZ = z; this.cameraZ = z;
return (A) this; return (A) this;
} }
public A setScreenSize(int width, int height) {
this.width = width;
this.height = height;
return (A) this;
}
} }

View File

@@ -6,6 +6,25 @@ import me.cortex.voxy.client.core.util.Mesher2D;
public class QuadEncoder { public class QuadEncoder {
public static int getX(long data) {
return (int) ((data>>21)&0b11111);
}
public static int getY(long data) {
return (int) ((data>>16)&0b11111);
}
public static int getZ(long data) {
return (int) ((data>>11)&0b11111);
}
public static int getW(long data) {
return (int) ((data>>3)&0b1111)+1;
}
public static int getH(long data) {
return (int) ((data>>7)&0b1111)+1;
}
public static int getFace(long data) {
return (int) (data&0b111);
}
//Note: the encodedMeshedData is from the Mesher2D //Note: the encodedMeshedData is from the Mesher2D
public static int encodePosition(int face, int otherAxis, int encodedMeshedData) { public static int encodePosition(int face, int otherAxis, int encodedMeshedData) {
if (false&&(Mesher2D.getW(encodedMeshedData) > 16 || Mesher2D.getH(encodedMeshedData) > 16)) { if (false&&(Mesher2D.getW(encodedMeshedData) > 16 || Mesher2D.getH(encodedMeshedData) > 16)) {

View File

@@ -118,24 +118,55 @@ public class RenderDataFactory {
//Ordering is: translucent, double sided quads, directional quads //Ordering is: translucent, double sided quads, directional quads
offsets[0] = meshlet; offsets[0] = meshlet;
int mix = 32, miy = 32, miz = 32, max = 0, may = 0, maz = 0;
for (long data : this.translucentQuadCollector) { for (long data : this.translucentQuadCollector) {
if (innerQuadCount == 0) { if (innerQuadCount == 0) {
//Write out meshlet header //Write out meshlet header
//Write out the section position //Write out the section position
writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2), key); writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2), key);
MemoryUtil.memPutLong(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + 8, 0);
} }
MemoryUtil.memPutLong(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + (2 + innerQuadCount++) * 8L, data); MemoryUtil.memPutLong(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + (2 + innerQuadCount++) * 8L, data);
int x = QuadEncoder.getX(data), y = QuadEncoder.getY(data), z = QuadEncoder.getZ(data), f = QuadEncoder.getFace(data);
mix = Math.min(x, mix); miy = Math.min(y, miy); miz = Math.min(z, miz);
if ((f>>1)==0) {
max = Math.max(x + QuadEncoder.getW(data), max);
may = Math.max(y, may);
maz = Math.max(z + QuadEncoder.getH(data), maz);
} else if ((f>>1)==1) {
max = Math.max(x + QuadEncoder.getW(data), max);
may = Math.max(y + QuadEncoder.getH(data), may);
maz = Math.max(z, maz);
} else {
max = Math.max(x, max);
may = Math.max(y + QuadEncoder.getW(data), may);
maz = Math.max(z + QuadEncoder.getH(data), maz);
}
if (innerQuadCount == QUADS_PER_MESHLET) { if (innerQuadCount == QUADS_PER_MESHLET) {
//Write out the meshlet size data
long sizeData = ((long)mix)|(((long)miy)<<8)|(((long)miz)<<16)|
(((long)max)<<24)|(((long)may)<<32)|(((long)maz)<<40);
writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + 8, sizeData);
innerQuadCount = 0; innerQuadCount = 0;
meshlet++; meshlet++;
mix = 32; miy = 32; miz = 32; max = 0; may = 0; maz = 0;
} }
} }
if (innerQuadCount != 0) { if (innerQuadCount != 0) {
//Write out the meshlet size data
long sizeData = ((long)mix)|(((long)miy)<<8)|(((long)miz)<<16)|
(((long)max)<<24)|(((long)may)<<32)|(((long)maz)<<40);
writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + 8, sizeData);
meshlet++; meshlet++;
innerQuadCount = 0; innerQuadCount = 0;
mix = 32; miy = 32; miz = 32; max = 0; may = 0; maz = 0;
} }
offsets[1] = meshlet; offsets[1] = meshlet;
@@ -145,18 +176,46 @@ public class RenderDataFactory {
//Write out the section position //Write out the section position
writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2), key); writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2), key);
MemoryUtil.memPutLong(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + 8, 0);
} }
MemoryUtil.memPutLong(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + (2 + innerQuadCount++) * 8L, data); MemoryUtil.memPutLong(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + (2 + innerQuadCount++) * 8L, data);
int x = QuadEncoder.getX(data), y = QuadEncoder.getY(data), z = QuadEncoder.getZ(data), f = QuadEncoder.getFace(data);
mix = Math.min(x, mix); miy = Math.min(y, miy); miz = Math.min(z, miz);
if ((f>>1)==0) {
max = Math.max(x + QuadEncoder.getW(data), max);
may = Math.max(y, may);
maz = Math.max(z + QuadEncoder.getH(data), maz);
} else if ((f>>1)==1) {
max = Math.max(x + QuadEncoder.getW(data), max);
may = Math.max(y + QuadEncoder.getH(data), may);
maz = Math.max(z, maz);
} else {
max = Math.max(x, max);
may = Math.max(y + QuadEncoder.getW(data), may);
maz = Math.max(z + QuadEncoder.getH(data), maz);
}
if (innerQuadCount == QUADS_PER_MESHLET) { if (innerQuadCount == QUADS_PER_MESHLET) {
//Write out the meshlet size data
long sizeData = ((long)mix)|(((long)miy)<<8)|(((long)miz)<<16)|
(((long)max)<<24)|(((long)may)<<32)|(((long)maz)<<40);
writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + 8, sizeData);
innerQuadCount = 0; innerQuadCount = 0;
meshlet++; meshlet++;
mix = 32; miy = 32; miz = 32; max = 0; may = 0; maz = 0;
} }
} }
if (innerQuadCount != 0) { if (innerQuadCount != 0) {
//Write out the meshlet size data
long sizeData = ((long)mix)|(((long)miy)<<8)|(((long)miz)<<16)|
(((long)max)<<24)|(((long)may)<<32)|(((long)maz)<<40);
writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + 8, sizeData);
meshlet++; meshlet++;
innerQuadCount = 0; innerQuadCount = 0;
mix = 32; miy = 32; miz = 32; max = 0; may = 0; maz = 0;
} }
for (int face = 0; face < 6; face++) { for (int face = 0; face < 6; face++) {
@@ -167,18 +226,46 @@ public class RenderDataFactory {
//Write out the section position //Write out the section position
writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2), key); writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2), key);
MemoryUtil.memPutLong(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + 8, 0);
} }
MemoryUtil.memPutLong(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + (2 + innerQuadCount++) * 8L, data); MemoryUtil.memPutLong(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + (2 + innerQuadCount++) * 8L, data);
int x = QuadEncoder.getX(data), y = QuadEncoder.getY(data), z = QuadEncoder.getZ(data), f = QuadEncoder.getFace(data);
mix = Math.min(x, mix); miy = Math.min(y, miy); miz = Math.min(z, miz);
if ((f>>1)==0) {
max = Math.max(x + QuadEncoder.getW(data), max);
may = Math.max(y, may);
maz = Math.max(z + QuadEncoder.getH(data), maz);
} else if ((f>>1)==1) {
max = Math.max(x + QuadEncoder.getW(data), max);
may = Math.max(y + QuadEncoder.getH(data), may);
maz = Math.max(z, maz);
} else {
max = Math.max(x, max);
may = Math.max(y + QuadEncoder.getW(data), may);
maz = Math.max(z + QuadEncoder.getH(data), maz);
}
if (innerQuadCount == QUADS_PER_MESHLET) { if (innerQuadCount == QUADS_PER_MESHLET) {
//Write out the meshlet size data
long sizeData = ((long)mix)|(((long)miy)<<8)|(((long)miz)<<16)|
(((long)max)<<24)|(((long)may)<<32)|(((long)maz)<<40);
writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + 8, sizeData);
innerQuadCount = 0; innerQuadCount = 0;
meshlet++; meshlet++;
mix = 32; miy = 32; miz = 32; max = 0; may = 0; maz = 0;
} }
} }
if (innerQuadCount != 0) { if (innerQuadCount != 0) {
//Write out the meshlet size data
long sizeData = ((long)mix)|(((long)miy)<<8)|(((long)miz)<<16)|
(((long)max)<<24)|(((long)may)<<32)|(((long)maz)<<40);
writePos(ptr + meshlet * 8L * (QUADS_PER_MESHLET+2) + 8, sizeData);
meshlet++; meshlet++;
innerQuadCount = 0; innerQuadCount = 0;
mix = 32; miy = 32; miz = 32; max = 0; may = 0; maz = 0;
} }
} }
} else { } else {

View File

@@ -10,6 +10,7 @@ layout(binding = 0, std140) uniform SceneUniform {
Frustum frustum; Frustum frustum;
vec3 cameraSubPos; vec3 cameraSubPos;
uint frameId; uint frameId;
uvec2 screensize;
}; };
struct BlockModel { struct BlockModel {
@@ -38,8 +39,17 @@ struct DrawCommand {
int baseVertex; int baseVertex;
uint baseInstance; uint baseInstance;
}; };
struct DispatchIndirect {
uint x;
uint y;
uint z;
};
#ifdef BIND_SAMPLER_AS_HIZ
layout(binding = 0) uniform sampler2D hizSampler;
#else
layout(binding = 0) uniform sampler2D blockModelAtlas; layout(binding = 0) uniform sampler2D blockModelAtlas;
#endif
#ifndef Quad #ifndef Quad
#define Quad ivec2 #define Quad ivec2
@@ -49,13 +59,12 @@ layout(binding = 1, std430) readonly restrict buffer GeometryBuffer {
}; };
layout(binding = 2, std430) restrict buffer DrawBuffer { layout(binding = 2, std430) restrict buffer DrawBuffer {
DispatchIndirect dispatchCmd;
uint fullMeshletCount;
DrawCommand drawCmd; DrawCommand drawCmd;
}; };
#ifndef MESHLET_ACCESS layout(binding = 3, std430) restrict buffer MeshletListData {
#define MESHLET_ACCESS readonly writeonly
#endif
layout(binding = 3, std430) MESHLET_ACCESS restrict buffer MeshletListData {
uint meshlets[]; uint meshlets[];
}; };

View File

@@ -5,9 +5,9 @@
#import <voxy:lod/quad_format.glsl> #import <voxy:lod/quad_format.glsl>
#import <voxy:lod/gl46mesh/bindings.glsl> #import <voxy:lod/gl46mesh/bindings.glsl>
#import <voxy:lod/section.glsl> #import <voxy:lod/section.glsl>
#define extractMeshletStart extractQuadStart #import <voxy:lod/gl46mesh/meshlet.glsl>
layout(local_size_x = 64) in; layout(local_size_x = 64) in;
#define QUADS_PER_MESHLET 30
void emitMeshlets(inout uint mli, inout uint meshletPtr, uint mskedCnt, uint cnt) { void emitMeshlets(inout uint mli, inout uint meshletPtr, uint mskedCnt, uint cnt) {
for (;mskedCnt != 0; mskedCnt--,mli++) { for (;mskedCnt != 0; mskedCnt--,mli++) {
@@ -17,19 +17,19 @@ void emitMeshlets(inout uint mli, inout uint meshletPtr, uint mskedCnt, uint cnt
} }
void main() { void main() {
//Clear here as it stops the need to dispatch a glClearData instruction
if (gl_GlobalInvocationID.x == 0) { if (gl_GlobalInvocationID.x == 0) {
//Setup the remaining state of the drawElementsIndirect command drawCmd.instanceCount = 0;
drawCmd.count = QUADS_PER_MESHLET*6; dispatchCmd.y = 1;
drawCmd.firstIndex = 0; dispatchCmd.z = 1;
drawCmd.baseVertex = 0;
drawCmd.baseInstance = 0;
} }
if (gl_GlobalInvocationID.x >= sectionCount) { if (gl_GlobalInvocationID.x >= sectionCount) {
return; return;
} }
//Check the occlusion data from last frame //Check the occlusion data from last frame
bool shouldRender = visibilityData[gl_GlobalInvocationID.x] == frameId - 1; bool shouldRender = visibilityData[gl_GlobalInvocationID.x] == frameId;
if (shouldRender) { if (shouldRender) {
SectionMeta meta = sectionData[gl_GlobalInvocationID.x]; SectionMeta meta = sectionData[gl_GlobalInvocationID.x];
uint detail = extractDetail(meta); uint detail = extractDetail(meta);
@@ -46,7 +46,12 @@ void main() {
uint e = ((meta.cntD>>16)&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 total = a + u + d + s + n + w + e;
uint mli = atomicAdd(drawCmd.instanceCount, total);//meshletListIndex uint mli = atomicAdd(fullMeshletCount, total);//meshletListIndex
//Need to increment the glDispatchComputeIndirect with respect to the workgroup
uint addWorkAmount = ((mli+total)>>7)-(mli>>7);//the >>7 is cause the workgroup size is 128
addWorkAmount += uint(mli==0); //If we where the first to add to the meshlet counter then we need to add an extra dispatch
// to account for trailing data
atomicAdd(dispatchCmd.x, addWorkAmount);
uint meshletPtr = extractMeshletStart(meta) + (meta.cntA&0xFFFF); uint meshletPtr = extractMeshletStart(meta) + (meta.cntA&0xFFFF);

View File

@@ -0,0 +1,46 @@
#define QUADS_PER_MESHLET 30
#define extractMeshletStart extractQuadStart
#define PosHeader Quad
#define AABBHeader Quad
//There are 16 bytes of metadata at the start of the meshlet
#define MESHLET_SIZE (QUADS_PER_MESHLET+2)
#ifdef GL_ARB_gpu_shader_int64
ivec3 extractPosition(PosHeader pos64) {
//((long)lvl<<60)|((long)(y&0xFF)<<52)|((long)(z&((1<<24)-1))<<28)|((long)(x&((1<<24)-1))<<4);
//return ivec3((pos64<<4)&uint64_t(0xFFFFFFFF),(pos64>>28)&uint64_t(0xFFFFFFFF),(pos64>>24)&uint64_t(0xFFFFFFFF))>>ivec3(8,24,8);
return (ivec3(int(pos64>>4)&((1<<24)-1), int(pos64>>52)&0xFF, int(pos64>>28)&((1<<24)-1))<<ivec3(8,24,8))>>ivec3(8,24,8);
}
uint extractDetail(PosHeader pos64) {
return uint(pos64>>60);
}
uvec3 extractMin(AABBHeader aabb) {
return uvec3(uint(aabb&0xFF),uint((aabb>>8)&0xFF),uint((aabb>>16)&0xFF));
}
uvec3 extractMax(AABBHeader aabb) {
return uvec3(uint((aabb>>24)&0xFF),uint((aabb>>32)&0xFF),uint((aabb>>40)&0xFF));
}
#else
ivec3 extractPosition(PosHeader pos) {
int y = ((int(pos.x)<<4)>>24);
int x = (int(pos.y)<<4)>>8;
int z = int((pos.x&((1<<20)-1))<<4);
z |= int(pos.y>>28)&0xF;
z <<= 8;
z >>= 8;
return ivec3(x,y,z);
}
uint extractDetail(PosHeader pos) {
return uint(pos.x)>>28;
}
uvec3 extractMin(AABBHeader aabb) {
return uvec3(aabb.x&0xFF,(aabb.x>>8)&0xFF,(aabb.x>>16)&0xFF);
}
uvec3 extractMax(AABBHeader aabb) {
return uvec3((aabb.x>>24)&0xFF,aabb.y&0xFF,(aabb.y>>8)&0xFF);
}
#endif

View File

@@ -0,0 +1,65 @@
#version 450
#extension GL_ARB_gpu_shader_int64 : enable
#define MESHLET_ACCESS
#define BIND_SAMPLER_AS_HIZ
#import <voxy:lod/quad_format.glsl>
#import <voxy:lod/gl46mesh/bindings.glsl>
#import <voxy:lod/section.glsl>
#import <voxy:lod/gl46mesh/meshlet.glsl>
layout(local_size_x=128) in;
vec3 proj(vec3 pos) {
vec4 t = MVP * vec4(vec3(pos),1);
return t.xyz/t.w;
}
bool testHiZ(PosHeader secPos, AABBHeader aabb) {
ivec3 section = extractPosition(secPos);
uint detail = extractDetail(secPos);
ivec3 pos = (((section<<detail)-baseSectionPos)<<5);
uvec3 cmin = extractMin(aabb)*(1<<detail);
uvec3 cmax = extractMax(aabb)*(1<<detail);
vec3 minBB = proj(pos);
vec3 maxBB = minBB;
for (int i = 1; i < 8; i++) {
vec3 point = proj(pos+mix(cmin, cmax, bvec3((i&1)!=0,(i&2)!=0,(i&4)!=0)));
minBB = min(minBB, point);
maxBB = max(maxBB, point);
}
minBB = minBB*0.5+0.5;
maxBB = maxBB*0.5+0.5;
vec2 size = (maxBB.xy - minBB.xy) * vec2(screensize);
float miplevel = ceil(log2(max(size.x, size.y)/2));//NOTE: the /2 is cause the mipmaps dont include bottom level depth
float a = textureLod(hizSampler,minBB.xy,miplevel).r;
float b = textureLod(hizSampler,vec2(minBB.x,maxBB.y),miplevel).r;
float c = textureLod(hizSampler,maxBB.xy,miplevel).r;
float d = textureLod(hizSampler,vec2(maxBB.x,minBB.y),miplevel).r;
float depth = max(max(a,b),max(c,d));
return minBB.z <= depth;
}
void main() {
if (gl_GlobalInvocationID.x >= fullMeshletCount) {
return;
}
if (gl_GlobalInvocationID.x == 0) {
//Setup the state of the drawElementsIndirect command, instanceCount is cleared externally
drawCmd.count = QUADS_PER_MESHLET*6;
drawCmd.firstIndex = 0;
drawCmd.baseVertex = 0;
drawCmd.baseInstance = fullMeshletCount;//Start at the begining of the newly emitted meshlet array
}
uint meshletId = meshlets[gl_GlobalInvocationID.x];
PosHeader pos = geometryPool[meshletId*MESHLET_SIZE];
AABBHeader aabb = geometryPool[meshletId*MESHLET_SIZE+1];
if (true||testHiZ(pos, aabb)) {//If didnt cull, insert it back into the stream
meshlets[atomicAdd(drawCmd.instanceCount, 1)+fullMeshletCount] = meshletId;
}
}

View File

@@ -1,40 +1,10 @@
#version 450 #version 450
#extension GL_ARB_gpu_shader_int64 : enable #extension GL_ARB_gpu_shader_int64 : enable
#define QUADS_PER_MESHLET 30
#define MESHLET_ACCESS readonly
//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/quad_format.glsl>
#import <voxy:lod/gl46mesh/bindings.glsl> #import <voxy:lod/gl46mesh/bindings.glsl>
#import <voxy:lod/block_model.glsl> #import <voxy:lod/block_model.glsl>
#define PosHeader Quad #import <voxy:lod/gl46mesh/meshlet.glsl>
#ifdef GL_ARB_gpu_shader_int64
ivec3 extractPosition(PosHeader pos64) {
//((long)lvl<<60)|((long)(y&0xFF)<<52)|((long)(z&((1<<24)-1))<<28)|((long)(x&((1<<24)-1))<<4);
//return ivec3((pos64<<4)&uint64_t(0xFFFFFFFF),(pos64>>28)&uint64_t(0xFFFFFFFF),(pos64>>24)&uint64_t(0xFFFFFFFF))>>ivec3(8,24,8);
return (ivec3(int(pos64>>4)&((1<<24)-1), int(pos64>>52)&0xFF, int(pos64>>28)&((1<<24)-1))<<ivec3(8,24,8))>>ivec3(8,24,8);
}
uint extractDetail(PosHeader pos64) {
return uint(pos64>>60);
}
#else
ivec3 extractPosition(PosHeader pos) {
int y = ((int(pos.x)<<4)>>24);
int x = (int(pos.y)<<4)>>8;
int z = int((pos.x&((1<<20)-1))<<4);
z |= int(pos.y>>28)&0xF;
z <<= 8;
z >>= 8;
return ivec3(x,y,z);
}
uint extractDetail(PosHeader pos) {
return uint(pos.x)>>28;
}
#endif
layout(location = 6) out flat uint meshlet; layout(location = 6) out flat uint meshlet;
PosHeader meshletPosition; PosHeader meshletPosition;