Temporal coherance

This commit is contained in:
mcrcortex
2025-04-25 18:30:07 +10:00
parent 862afc498e
commit bbe7cd2099
5 changed files with 67 additions and 23 deletions

View File

@@ -11,6 +11,7 @@ import me.cortex.voxy.client.core.rendering.RenderService;
import me.cortex.voxy.client.core.rendering.SharedIndexBuffer; import me.cortex.voxy.client.core.rendering.SharedIndexBuffer;
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.common.Logger;
import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.RenderLayer;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import org.joml.Matrix4f; import org.joml.Matrix4f;
@@ -36,6 +37,7 @@ import static org.lwjgl.opengl.GL45.glCopyNamedBufferSubData;
//Uses MDIC to render the sections //Uses MDIC to render the sections
public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, BasicSectionGeometryManager> { public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, BasicSectionGeometryManager> {
private static final int TRANSLUCENT_OFFSET = 400_000;//in draw calls private static final int TRANSLUCENT_OFFSET = 400_000;//in draw calls
private static final int TEMPORAL_OFFSET = 500_000;//in draw calls
private static final int STATISTICS_BUFFER_BINDING = 7; private static final int STATISTICS_BUFFER_BINDING = 7;
private final Shader terrainShader = Shader.make() private final Shader terrainShader = Shader.make()
.defineIf("DEBUG_RENDER", false) .defineIf("DEBUG_RENDER", false)
@@ -45,6 +47,7 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
private final Shader commandGenShader = Shader.make() private final Shader commandGenShader = Shader.make()
.define("TRANSLUCENT_OFFSET", TRANSLUCENT_OFFSET) .define("TRANSLUCENT_OFFSET", TRANSLUCENT_OFFSET)
.define("TEMPORAL_OFFSET", TEMPORAL_OFFSET)
.defineIf("HAS_STATISTICS", RenderStatistics.enabled) .defineIf("HAS_STATISTICS", RenderStatistics.enabled)
.defineIf("STATISTICS_BUFFER_BINDING", RenderStatistics.enabled, STATISTICS_BUFFER_BINDING) .defineIf("STATISTICS_BUFFER_BINDING", RenderStatistics.enabled, STATISTICS_BUFFER_BINDING)
@@ -65,14 +68,17 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
//TODO: needs to be in the viewport, since it contains the compute indirect call/values //TODO: needs to be in the viewport, since it contains the compute indirect call/values
private final GlBuffer drawCountCallBuffer = new GlBuffer(1024).zero(); private final GlBuffer drawCountCallBuffer = new GlBuffer(1024).zero();
private final GlBuffer drawCallBuffer = new GlBuffer(5*4*(400_000+100_000)).zero();//400k draw calls private final GlBuffer drawCallBuffer = new GlBuffer(5*4*(400_000+100_000+100_000)).zero();//400k draw calls
private final GlBuffer positionScratchBuffer = new GlBuffer(8*400000).zero();//400k positions private final GlBuffer positionScratchBuffer = new GlBuffer(8*400000).zero();//400k positions
//Statistics //Statistics
private final GlBuffer statisticsBuffer = new GlBuffer(1024).zero(); private final GlBuffer statisticsBuffer = new GlBuffer(1024).zero();
private final int maxSectionCount;
public MDICSectionRenderer(ModelStore modelStore, int maxSectionCount, long geometryCapacity) { public MDICSectionRenderer(ModelStore modelStore, int maxSectionCount, long geometryCapacity) {
super(modelStore, new BasicSectionGeometryManager(maxSectionCount, geometryCapacity)); super(modelStore, new BasicSectionGeometryManager(maxSectionCount, geometryCapacity));
this.maxSectionCount = maxSectionCount;
} }
@@ -90,7 +96,11 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
MemoryUtil.memPutInt(ptr, sx); ptr += 4; MemoryUtil.memPutInt(ptr, sx); ptr += 4;
MemoryUtil.memPutInt(ptr, sy); ptr += 4; MemoryUtil.memPutInt(ptr, sy); ptr += 4;
MemoryUtil.memPutInt(ptr, sz); ptr += 4; MemoryUtil.memPutInt(ptr, sz); ptr += 4;
MemoryUtil.memPutInt(ptr, viewport.frameId); ptr += 4; if (viewport.frameId<0) {
Logger.error("Frame ID negative, this will cause things to break, wrapping around");
viewport.frameId &= 0x7fffffff;
}
MemoryUtil.memPutInt(ptr, viewport.frameId&0x7fffffff); ptr += 4;
innerTranslation.getToAddress(ptr); ptr += 4*3; innerTranslation.getToAddress(ptr); ptr += 4*3;
UploadStream.INSTANCE.commit(); UploadStream.INSTANCE.commit();
@@ -116,7 +126,7 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
} }
private void renderTerrain() { private void renderTerrain(long indirectOffset, long drawCountOffset, int maxDrawCount) {
//RenderLayer.getCutoutMipped().startDrawing(); //RenderLayer.getCutoutMipped().startDrawing();
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
@@ -125,7 +135,7 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
glBindVertexArray(RenderService.STATIC_VAO);//Needs to be before binding glBindVertexArray(RenderService.STATIC_VAO);//Needs to be before binding
this.bindRenderingBuffers(); this.bindRenderingBuffers();
glMultiDrawElementsIndirectCountARB(GL_TRIANGLES, GL_UNSIGNED_SHORT, 0, 4*3, Math.min((int)(this.geometryManager.getSectionCount()*4.4+128), 400_000), 0); glMultiDrawElementsIndirectCountARB(GL_TRIANGLES, GL_UNSIGNED_SHORT, indirectOffset, drawCountOffset, maxDrawCount, 0);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glBindVertexArray(0); glBindVertexArray(0);
@@ -143,7 +153,7 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
this.uploadUniformBuffer(viewport); this.uploadUniformBuffer(viewport);
this.renderTerrain(); this.renderTerrain(0, 4*3, Math.min((int)(this.geometryManager.getSectionCount()*4.4+128), 400_000));
} }
@Override @Override
@@ -244,6 +254,9 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
}); });
} }
} }
//Render temporal
this.renderTerrain(TEMPORAL_OFFSET*5*4, 4*5, Math.min(this.geometryManager.getSectionCount(), 100_000));
} }
@Override @Override
@@ -254,7 +267,7 @@ public class MDICSectionRenderer extends AbstractSectionRenderer<MDICViewport, B
@Override @Override
public MDICViewport createViewport() { public MDICViewport createViewport() {
return new MDICViewport(); return new MDICViewport(this.maxSectionCount);
} }
@Override @Override

View File

@@ -4,8 +4,12 @@ import me.cortex.voxy.client.core.gl.GlBuffer;
import me.cortex.voxy.client.core.rendering.Viewport; import me.cortex.voxy.client.core.rendering.Viewport;
public class MDICViewport extends Viewport<MDICViewport> { public class MDICViewport extends Viewport<MDICViewport> {
public final GlBuffer visibilityBuffer = new GlBuffer(100_000*4);
public final GlBuffer indirectLookupBuffer = new GlBuffer(100_000*4+4); public final GlBuffer indirectLookupBuffer = new GlBuffer(100_000*4+4);
public final GlBuffer visibilityBuffer;
public MDICViewport(int maxSectionCount) {
this.visibilityBuffer = new GlBuffer(maxSectionCount*4L);
}
@Override @Override
protected void delete0() { protected void delete0() {

View File

@@ -59,20 +59,16 @@ void main() {
vec3 cornerPos = vec3(((ipos<<detail)-baseSectionPos)<<5)-cameraSubPos; vec3 cornerPos = vec3(((ipos<<detail)-baseSectionPos)<<5)-cameraSubPos;
//Note! its not with respect to the sectionId uint dat = visibilityData[sectionId];
//
//Check the occlusion data from this frame occlusion
bool shouldRender = visibilityData[gl_GlobalInvocationID.x] == frameId;
//Clear the occlusion data (not strictly? needed? i think???) //if the section was visible this frame
//visibilityData[gl_GlobalInvocationID.x] = 0; bool shouldRender = (dat&0x7fffffffu) == frameId;
bool renderTemporally = (dat&0x80000000u)==0;// means, if it was not visible last frame
//TODO: need to make it check that only if it was also in the frustum last frame does it apply the visibilityData check!
// this fixes temporal coherance
if (shouldRender) { if (shouldRender) {
#ifdef HAS_STATISTICS #ifdef HAS_STATISTICS
atomicAdd(visibleSectionCounts[detail], 1); atomicAdd(visibleSectionCounts[detail], 1);
#endif #endif
@@ -95,8 +91,15 @@ void main() {
msk |= uint(((meta.cntA>>16)&0xFFFF)!=0)<<6; msk |= uint(((meta.cntA>>16)&0xFFFF)!=0)<<6;
uint cmdPtr = atomicAdd(opaqueDrawCount, bitCount(msk)); uint cmdCnt = bitCount(msk);
uint cmdPtr = atomicAdd(opaqueDrawCount, cmdCnt);
uint tCmdPtr = 0;
if (renderTemporally) {
tCmdPtr = atomicAdd(temporalOpaqueDrawCount, cmdCnt) + TEMPORAL_OFFSET;
}
//TODO: make totalQuads also have temporal amount
#ifdef HAS_STATISTICS #ifdef HAS_STATISTICS
uint totalQuads = 0; uint totalQuads = 0;
#endif #endif
@@ -117,6 +120,9 @@ void main() {
count = (meta.cntA>>16)&0xFFFF; count = (meta.cntA>>16)&0xFFFF;
if (count != 0) { if (count != 0) {
writeCmd(cmdPtr++, drawId, ptr, count); writeCmd(cmdPtr++, drawId, ptr, count);
if (renderTemporally) {
writeCmd(tCmdPtr++, drawId, ptr, count);
}
#ifdef HAS_STATISTICS #ifdef HAS_STATISTICS
totalQuads += count; totalQuads += count;
#endif #endif
@@ -127,6 +133,9 @@ void main() {
count = (meta.cntB)&0xFFFF; count = (meta.cntB)&0xFFFF;
if (((msk&(1u<<0))!=0)) { if (((msk&(1u<<0))!=0)) {
writeCmd(cmdPtr++, drawId, ptr, count); writeCmd(cmdPtr++, drawId, ptr, count);
if (renderTemporally) {
writeCmd(tCmdPtr++, drawId, ptr, count);
}
#ifdef HAS_STATISTICS #ifdef HAS_STATISTICS
totalQuads += count; totalQuads += count;
#endif #endif
@@ -137,6 +146,9 @@ void main() {
count = (meta.cntB>>16)&0xFFFF; count = (meta.cntB>>16)&0xFFFF;
if ((msk&(1u<<1))!=0) { if ((msk&(1u<<1))!=0) {
writeCmd(cmdPtr++, drawId, ptr, count); writeCmd(cmdPtr++, drawId, ptr, count);
if (renderTemporally) {
writeCmd(tCmdPtr++, drawId, ptr, count);
}
#ifdef HAS_STATISTICS #ifdef HAS_STATISTICS
totalQuads += count; totalQuads += count;
#endif #endif
@@ -147,6 +159,9 @@ void main() {
count = (meta.cntC)&0xFFFF; count = (meta.cntC)&0xFFFF;
if ((msk&(1u<<2))!=0) { if ((msk&(1u<<2))!=0) {
writeCmd(cmdPtr++, drawId, ptr, count); writeCmd(cmdPtr++, drawId, ptr, count);
if (renderTemporally) {
writeCmd(tCmdPtr++, drawId, ptr, count);
}
#ifdef HAS_STATISTICS #ifdef HAS_STATISTICS
totalQuads += count; totalQuads += count;
#endif #endif
@@ -157,6 +172,9 @@ void main() {
count = (meta.cntC>>16)&0xFFFF; count = (meta.cntC>>16)&0xFFFF;
if ((msk&(1u<<3))!=0) { if ((msk&(1u<<3))!=0) {
writeCmd(cmdPtr++, drawId, ptr, count); writeCmd(cmdPtr++, drawId, ptr, count);
if (renderTemporally) {
writeCmd(tCmdPtr++, drawId, ptr, count);
}
#ifdef HAS_STATISTICS #ifdef HAS_STATISTICS
totalQuads += count; totalQuads += count;
#endif #endif
@@ -167,6 +185,9 @@ void main() {
count = (meta.cntD)&0xFFFF; count = (meta.cntD)&0xFFFF;
if ((msk&(1u<<4))!=0) { if ((msk&(1u<<4))!=0) {
writeCmd(cmdPtr++, drawId, ptr, count); writeCmd(cmdPtr++, drawId, ptr, count);
if (renderTemporally) {
writeCmd(tCmdPtr++, drawId, ptr, count);
}
#ifdef HAS_STATISTICS #ifdef HAS_STATISTICS
totalQuads += count; totalQuads += count;
#endif #endif
@@ -177,6 +198,9 @@ void main() {
count = (meta.cntD>>16)&0xFFFF; count = (meta.cntD>>16)&0xFFFF;
if ((msk&(1u<<5))!=0) { if ((msk&(1u<<5))!=0) {
writeCmd(cmdPtr++, drawId, ptr, count); writeCmd(cmdPtr++, drawId, ptr, count);
if (renderTemporally) {
writeCmd(tCmdPtr++, drawId, ptr, count);
}
#ifdef HAS_STATISTICS #ifdef HAS_STATISTICS
totalQuads += count; totalQuads += count;
#endif #endif

View File

@@ -7,9 +7,9 @@ layout(early_fragment_tests) in;
flat in uint id; flat in uint id;
flat in uint value; flat in uint value;
out vec4 colour; //out vec4 colour;
void main() { void main() {
visibilityData[id] = value; visibilityData[id] = value;
colour = vec4(float(id&7u)/7, float((id>>3)&7u)/7, float((id>>6)&7u)/7, 1); //colour = vec4(float(id&7u)/7, float((id>>3)&7u)/7, float((id>>6)&7u)/7, 1);
} }

View File

@@ -1,6 +1,6 @@
#version 460 core #version 460 core
#extension GL_ARB_gpu_shader_int64 : enable #extension GL_ARB_gpu_shader_int64 : enable
#define VISIBILITY_ACCESS writeonly #define VISIBILITY_ACCESS readonly
#define SECTION_METADATA_BUFFER_BINDING 1 #define SECTION_METADATA_BUFFER_BINDING 1
#define VISIBILITY_BUFFER_BINDING 2 #define VISIBILITY_BUFFER_BINDING 2
@@ -29,7 +29,10 @@ void main() {
gl_Position = MVP * vec4(vec3(pos),1); gl_Position = MVP * vec4(vec3(pos),1);
//Write to this id //Write to the section id, to track temporal over time (litterally just need a single bit, 1 fking bit, but no)
id = gl_InstanceID;//Note!! we write to the instance id _not_ the section id id = sid;
value = frameId;
uint previous = visibilityData[sid]&0x7fffffffu;
bool wasVisibleLastFrame = previous==(frameId-1);
value = (frameId&0x7fffffffu)|(uint(wasVisibleLastFrame)<<31);//Encode if it was visible last frame
} }