Merge branch 'mc_1215' into mc_1216

This commit is contained in:
mcrcortex
2025-06-18 08:55:06 +10:00
13 changed files with 163 additions and 157 deletions

View File

@@ -48,35 +48,40 @@ public class VoxyRenderSystem {
//Keep the world loaded, NOTE: this is done FIRST, to keep and ensure that even if the rest of loading takes more //Keep the world loaded, NOTE: this is done FIRST, to keep and ensure that even if the rest of loading takes more
// than timeout, we keep the world acquired // than timeout, we keep the world acquired
world.acquireRef(); world.acquireRef();
try {
//wait for opengl to be finished, this should hopefully ensure all memory allocations are free
glFinish();
glFinish();
//wait for opengl to be finished, this should hopefully ensure all memory allocations are free //Trigger the shared index buffer loading
glFinish();glFinish(); SharedIndexBuffer.INSTANCE.id();
Capabilities.init();//Ensure clinit is called
//Trigger the shared index buffer loading this.worldIn = world;
SharedIndexBuffer.INSTANCE.id(); this.renderer = new RenderService(world, threadPool);
Capabilities.init();//Ensure clinit is called this.postProcessing = new PostProcessing();
int minSec = MinecraftClient.getInstance().world.getBottomSectionCoord() >> 5;
int maxSec = (MinecraftClient.getInstance().world.getTopSectionCoord() - 1) >> 5;
this.worldIn = world; //Do some very cheeky stuff for MiB
this.renderer = new RenderService(world, threadPool); if (false) {
this.postProcessing = new PostProcessing(); minSec = -8;
int minSec = MinecraftClient.getInstance().world.getBottomSectionCoord()>>5; maxSec = 7;
int maxSec = (MinecraftClient.getInstance().world.getTopSectionCoord()-1)>>5; }
//Do some very cheeky stuff for MiB this.renderDistanceTracker = new RenderDistanceTracker(20,
if (false) { minSec,
minSec = -8; maxSec,
maxSec = 7; this.renderer::addTopLevelNode,
this.renderer::removeTopLevelNode);
this.renderDistanceTracker.setRenderDistance(VoxyConfig.CONFIG.sectionRenderDistance);
this.chunkBoundRenderer = new ChunkBoundRenderer();
} catch (RuntimeException e) {
world.releaseRef();//If something goes wrong, we must release the world first
throw e;
} }
this.renderDistanceTracker = new RenderDistanceTracker(20,
minSec,
maxSec,
this.renderer::addTopLevelNode,
this.renderer::removeTopLevelNode);
this.renderDistanceTracker.setRenderDistance(VoxyConfig.CONFIG.sectionRenderDistance);
this.chunkBoundRenderer = new ChunkBoundRenderer();
} }
public void setRenderDistance(int renderDistance) { public void setRenderDistance(int renderDistance) {
@@ -84,40 +89,6 @@ public class VoxyRenderSystem {
} }
//private static final ModelTextureBakery mtb = new ModelTextureBakery(16, 16);
//private static final RawDownloadStream downstream = new RawDownloadStream(1<<20);
public void renderSetup(Frustum frustum, Camera camera) {
TimingStatistics.resetSamplers();
/*
if (false) {
int allocation = downstream.download(2 * 4 * 6 * 16 * 16, ptr -> {
ColourDepthTextureData[] textureData = new ColourDepthTextureData[6];
final int FACE_SIZE = 16 * 16;
for (int face = 0; face < 6; face++) {
long faceDataPtr = ptr + (FACE_SIZE * 4) * face * 2;
int[] colour = new int[FACE_SIZE];
int[] depth = new int[FACE_SIZE];
//Copy out colour
for (int i = 0; i < FACE_SIZE; i++) {
//De-interpolate results
colour[i] = MemoryUtil.memGetInt(faceDataPtr + (i * 4 * 2));
depth[i] = MemoryUtil.memGetInt(faceDataPtr + (i * 4 * 2) + 4);
}
textureData[face] = new ColourDepthTextureData(colour, depth, 16, 16);
}
if (textureData[0].colour()[0] == 0) {
int a = 0;
}
});
mtb.renderFacesToStream(Blocks.AIR.getDefaultState(), 123456, false, downstream.getBufferId(), allocation);
downstream.submit();
downstream.tick();
}*/
}
private void autoBalanceSubDivSize() { private void autoBalanceSubDivSize() {
//only increase quality while there are very few mesh queues, this stops, //only increase quality while there are very few mesh queues, this stops,
// e.g. while flying and is rendering alot of low quality chunks // e.g. while flying and is rendering alot of low quality chunks
@@ -160,6 +131,9 @@ public class VoxyRenderSystem {
if (IrisUtil.irisShadowActive()) { if (IrisUtil.irisShadowActive()) {
return; return;
} }
TimingStatistics.resetSamplers();
//Do some very cheeky stuff for MiB //Do some very cheeky stuff for MiB
if (false) { if (false) {
int sector = (((int)Math.floor(cameraX)>>4)+512)>>10; int sector = (((int)Math.floor(cameraX)>>4)+512)>>10;

View File

@@ -56,7 +56,7 @@ public class RenderService<T extends AbstractSectionRenderer<J, Q>, J extends Vi
geometryCapacity = Math.min(geometryCapacity, limit); geometryCapacity = Math.min(geometryCapacity, limit);
} }
//geometryCapacity = 1<<24; //geometryCapacity = 1<<28;
//geometryCapacity = 1<<30;//1GB test //geometryCapacity = 1<<30;//1GB test
return geometryCapacity; return geometryCapacity;
} }
@@ -84,7 +84,7 @@ public class RenderService<T extends AbstractSectionRenderer<J, Q>, J extends Vi
this.nodeManager = new AsyncNodeManager(1<<21, this.geometryData, this.renderGen); this.nodeManager = new AsyncNodeManager(1<<21, this.geometryData, this.renderGen);
this.nodeCleaner = new NodeCleaner(this.nodeManager); this.nodeCleaner = new NodeCleaner(this.nodeManager);
this.traversal = new HierarchicalOcclusionTraverser(this.nodeManager, this.nodeCleaner); this.traversal = new HierarchicalOcclusionTraverser(this.nodeManager, this.nodeCleaner, this.renderGen);
world.setDirtyCallback(this.nodeManager::worldEvent); world.setDirtyCallback(this.nodeManager::worldEvent);
@@ -106,6 +106,18 @@ public class RenderService<T extends AbstractSectionRenderer<J, Q>, J extends Vi
this.modelService.tick(budget); this.modelService.tick(budget);
} }
private boolean frexStillHasWork() {
if (!VoxyClient.isFrexActive()) {
return false;
}
//If frex is running we must tick everything to ensure correctness
UploadStream.INSTANCE.tick();
//Done here as is allows less gl state resetup
this.modelService.tick(100_000_000);
glFinish();
return this.nodeManager.hasWork() || this.renderGen.getTaskCount()!=0 || !this.modelService.areQueuesEmpty();
}
public void renderFarAwayOpaque(J viewport, GlTexture depthBoundTexture) { public void renderFarAwayOpaque(J viewport, GlTexture depthBoundTexture) {
//LightMapHelper.tickLightmap(); //LightMapHelper.tickLightmap();
@@ -121,6 +133,13 @@ public class RenderService<T extends AbstractSectionRenderer<J, Q>, J extends Vi
this.sectionRenderer.renderOpaque(viewport, depthBoundTexture); this.sectionRenderer.renderOpaque(viewport, depthBoundTexture);
TimingStatistics.G.stop(); TimingStatistics.G.stop();
{
int depthBuffer = glGetFramebufferAttachmentParameteri(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
//Compute the mip chain
viewport.hiZBuffer.buildMipChain(depthBuffer, viewport.width, viewport.height);
}
do { do {
//NOTE: need to do the upload and download tick here, after the section renderer renders the world, to ensure "stable" //NOTE: need to do the upload and download tick here, after the section renderer renders the world, to ensure "stable"
// sections // sections
@@ -157,23 +176,11 @@ public class RenderService<T extends AbstractSectionRenderer<J, Q>, J extends Vi
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT | GL_PIXEL_BUFFER_BARRIER_BIT); glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT | GL_PIXEL_BUFFER_BARRIER_BIT);
int depthBuffer = glGetFramebufferAttachmentParameteri(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
//if (depthBuffer == 0) {
// depthBuffer = glGetFramebufferAttachmentParameteri(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
//}
TimingStatistics.I.start(); TimingStatistics.I.start();
this.traversal.doTraversal(viewport, depthBuffer); this.traversal.doTraversal(viewport);
TimingStatistics.I.stop(); TimingStatistics.I.stop();
} while (this.frexStillHasWork());
if (VoxyClient.isFrexActive()) {//If frex is running we must tick everything to ensure correctness
UploadStream.INSTANCE.tick();
//Done here as is allows less gl state resetup
this.tickModelService(100_000_000);
glFinish();
}
} while (VoxyClient.isFrexActive() && (this.nodeManager.hasWork() || this.renderGen.getTaskCount()!=0 || !this.modelService.areQueuesEmpty()));
TimingStatistics.H.start(); TimingStatistics.H.start();

View File

@@ -179,6 +179,7 @@ public class AsyncNodeManager {
private void run() { private void run() {
if (this.workCounter.get() <= 0) { if (this.workCounter.get() <= 0) {
//TODO: here, instead of parking, we can do more work on other sub-tasks such as filtering the mesh build queue
LockSupport.park(); LockSupport.park();
if (this.workCounter.get() <= 0 || !this.running) {//No work if (this.workCounter.get() <= 0 || !this.running) {//No work
return; return;
@@ -753,7 +754,7 @@ public class AsyncNodeManager {
} }
public boolean hasWork() { public boolean hasWork() {
return this.workCounter.get()!=0 && RESULT_HANDLE.get(this) != null; return this.workCounter.get()!=0 || RESULT_HANDLE.get(this) != null;
} }
public void worldEvent(WorldSection section, int flags) { public void worldEvent(WorldSection section, int flags) {

View File

@@ -7,6 +7,7 @@ import me.cortex.voxy.client.core.gl.GlBuffer;
import me.cortex.voxy.client.core.gl.shader.AutoBindingShader; import me.cortex.voxy.client.core.gl.shader.AutoBindingShader;
import me.cortex.voxy.client.core.gl.shader.Shader; import me.cortex.voxy.client.core.gl.shader.Shader;
import me.cortex.voxy.client.core.gl.shader.ShaderType; import me.cortex.voxy.client.core.gl.shader.ShaderType;
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
import me.cortex.voxy.client.core.rendering.util.PrintfDebugUtil; import me.cortex.voxy.client.core.rendering.util.PrintfDebugUtil;
import me.cortex.voxy.client.core.rendering.util.HiZBuffer; import me.cortex.voxy.client.core.rendering.util.HiZBuffer;
import me.cortex.voxy.client.core.rendering.Viewport; import me.cortex.voxy.client.core.rendering.Viewport;
@@ -30,7 +31,7 @@ import static org.lwjgl.opengl.GL45.*;
public class HierarchicalOcclusionTraverser { public class HierarchicalOcclusionTraverser {
public static final boolean HIERARCHICAL_SHADER_DEBUG = System.getProperty("voxy.hierarchicalShaderDebug", "false").equals("true"); public static final boolean HIERARCHICAL_SHADER_DEBUG = System.getProperty("voxy.hierarchicalShaderDebug", "false").equals("true");
public static final int REQUEST_QUEUE_SIZE = 50; public static final int MAX_REQUEST_QUEUE_SIZE = 50;
public static final int MAX_QUEUE_SIZE = 200_000; public static final int MAX_QUEUE_SIZE = 200_000;
@@ -39,6 +40,7 @@ public class HierarchicalOcclusionTraverser {
private final AsyncNodeManager nodeManager; private final AsyncNodeManager nodeManager;
private final NodeCleaner nodeCleaner; private final NodeCleaner nodeCleaner;
private final RenderGenerationService meshGen;
private final GlBuffer requestBuffer; private final GlBuffer requestBuffer;
@@ -73,7 +75,7 @@ public class HierarchicalOcclusionTraverser {
.defineIf("DEBUG", HIERARCHICAL_SHADER_DEBUG) .defineIf("DEBUG", HIERARCHICAL_SHADER_DEBUG)
.define("MAX_ITERATIONS", MAX_ITERATIONS) .define("MAX_ITERATIONS", MAX_ITERATIONS)
.define("LOCAL_SIZE_BITS", LOCAL_WORK_SIZE_BITS) .define("LOCAL_SIZE_BITS", LOCAL_WORK_SIZE_BITS)
.define("REQUEST_QUEUE_SIZE", REQUEST_QUEUE_SIZE) .define("MAX_REQUEST_QUEUE_SIZE", MAX_REQUEST_QUEUE_SIZE)
.define("HIZ_BINDING", 0) .define("HIZ_BINDING", 0)
@@ -96,19 +98,18 @@ public class HierarchicalOcclusionTraverser {
.compile(); .compile();
public HierarchicalOcclusionTraverser(AsyncNodeManager nodeManager, NodeCleaner nodeCleaner) { public HierarchicalOcclusionTraverser(AsyncNodeManager nodeManager, NodeCleaner nodeCleaner, RenderGenerationService meshGen) {
this.nodeCleaner = nodeCleaner; this.nodeCleaner = nodeCleaner;
this.nodeManager = nodeManager; this.nodeManager = nodeManager;
this.requestBuffer = new GlBuffer(REQUEST_QUEUE_SIZE*8L+8).zero(); this.meshGen = meshGen;
this.requestBuffer = new GlBuffer(MAX_REQUEST_QUEUE_SIZE*8L+8).zero();
this.nodeBuffer = new GlBuffer(nodeManager.maxNodeCount*16L).fill(-1); this.nodeBuffer = new GlBuffer(nodeManager.maxNodeCount*16L).fill(-1);
glSamplerParameteri(this.hizSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glSamplerParameteri(this.hizSampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glSamplerParameteri(this.hizSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(this.hizSampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glSamplerParameteri(this.hizSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glSamplerParameteri(this.hizSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glSamplerParameteri(this.hizSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glSamplerParameteri(this.hizSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(this.hizSampler, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glSamplerParameteri(this.hizSampler, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
this.traversal this.traversal
.ubo("SCENE_UNIFORM_BINDING", this.uniformBuffer) .ubo("SCENE_UNIFORM_BINDING", this.uniformBuffer)
@@ -175,23 +176,31 @@ public class HierarchicalOcclusionTraverser {
viewport.section.getToAddress(ptr); ptr += 4*3; viewport.section.getToAddress(ptr); ptr += 4*3;
MemoryUtil.memPutFloat(ptr, viewport.width); ptr += 4; //MemoryUtil.memPutFloat(ptr, viewport.width); ptr += 4;
MemoryUtil.memPutInt(ptr, viewport.hiZBuffer.getPackedLevels()); ptr += 4;
viewport.innerTranslation.getToAddress(ptr); ptr += 4*3; viewport.innerTranslation.getToAddress(ptr); ptr += 4*3;
MemoryUtil.memPutFloat(ptr, viewport.height); ptr += 4; //MemoryUtil.memPutFloat(ptr, viewport.height); ptr += 4;
setFrustum(viewport, ptr); ptr += 4*4*6;
MemoryUtil.memPutInt(ptr, (int) (viewport.getRenderList().size()/4-1)); ptr += 4;
final float screenspaceAreaDecreasingSize = VoxyConfig.CONFIG.subDivisionSize*VoxyConfig.CONFIG.subDivisionSize; final float screenspaceAreaDecreasingSize = VoxyConfig.CONFIG.subDivisionSize*VoxyConfig.CONFIG.subDivisionSize;
//Screen space size for descending //Screen space size for descending
MemoryUtil.memPutFloat(ptr, (float) (screenspaceAreaDecreasingSize) /(viewport.width*viewport.height)); ptr += 4; MemoryUtil.memPutFloat(ptr, (float) (screenspaceAreaDecreasingSize) /(viewport.width*viewport.height)); ptr += 4;
setFrustum(viewport, ptr); ptr += 4*4*6;
MemoryUtil.memPutInt(ptr, (int) (viewport.getRenderList().size()/4-1)); ptr += 4;
//VisibilityId //VisibilityId
MemoryUtil.memPutInt(ptr, this.nodeCleaner.visibilityId); ptr += 4; MemoryUtil.memPutInt(ptr, this.nodeCleaner.visibilityId); ptr += 4;
{
final double TARGET_COUNT = 4000;//TODO: make this configurable, or at least dynamically computed based on throughput rate of mesh gen
double iFillness = Math.max(0, (TARGET_COUNT - this.meshGen.getTaskCount()) / TARGET_COUNT);
iFillness = Math.pow(iFillness, 2);
final int requestSize = (int) Math.ceil(iFillness * MAX_REQUEST_QUEUE_SIZE);
MemoryUtil.memPutInt(ptr, Math.max(0, Math.min(MAX_REQUEST_QUEUE_SIZE, requestSize)));ptr += 4;
}
} }
private void bindings(Viewport<?> viewport) { private void bindings(Viewport<?> viewport) {
@@ -203,10 +212,7 @@ public class HierarchicalOcclusionTraverser {
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, RENDER_QUEUE_BINDING, viewport.getRenderList().id); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, RENDER_QUEUE_BINDING, viewport.getRenderList().id);
} }
public void doTraversal(Viewport<?> viewport, int depthBuffer) { public void doTraversal(Viewport<?> viewport) {
//Compute the mip chain
viewport.hiZBuffer.buildMipChain(depthBuffer, viewport.width, viewport.height);
this.uploadUniform(viewport); this.uploadUniform(viewport);
//UploadStream.INSTANCE.commit(); //Done inside traversal //UploadStream.INSTANCE.commit(); //Done inside traversal

View File

@@ -1213,7 +1213,8 @@ public class NodeManager {
if (!this.nodeData.isNodeGeometryInFlight(nodeId)) { if (!this.nodeData.isNodeGeometryInFlight(nodeId)) {
if (!this.watcher.watch(pos, WorldEngine.UPDATE_TYPE_BLOCK_BIT)) { if (!this.watcher.watch(pos, WorldEngine.UPDATE_TYPE_BLOCK_BIT)) {
Logger.info("Node: " + nodeId + " at pos: " + WorldEngine.pprintPos(pos) + " got update request, but geometry was already being watched"); //Logger.info("Node: " + nodeId + " at pos: " + WorldEngine.pprintPos(pos) + " got update request, but geometry was already being watched");
this.invalidateNode(nodeId);//Who knows why but just invalidate the data just to keep in sync
} else { } else {
this.nodeData.markNodeGeometryInFlight(nodeId); this.nodeData.markNodeGeometryInFlight(nodeId);
} }

View File

@@ -172,6 +172,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(viewport, depthBoundTexture); this.bindRenderingBuffers(viewport, depthBoundTexture);
glMemoryBarrier(GL_COMMAND_BARRIER_BIT|GL_SHADER_STORAGE_BARRIER_BIT);//Barrier everything is needed
glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
glMultiDrawElementsIndirectCountARB(GL_TRIANGLES, GL_UNSIGNED_SHORT, TRANSLUCENT_OFFSET*5*4, 4*4, Math.min(this.geometryManager.getSectionCount(), 100_000), 0); glMultiDrawElementsIndirectCountARB(GL_TRIANGLES, GL_UNSIGNED_SHORT, TRANSLUCENT_OFFSET*5*4, 4*4, Math.min(this.geometryManager.getSectionCount(), 100_000), 0);

View File

@@ -69,12 +69,12 @@ public class HiZBuffer {
} }
public void buildMipChain(int srcDepthTex, int width, int height) { public void buildMipChain(int srcDepthTex, int width, int height) {
if (this.width != width || this.height != height) { if (this.width != Integer.highestOneBit(width) || this.height != Integer.highestOneBit(height)) {
if (this.texture != null) { if (this.texture != null) {
this.texture.free(); this.texture.free();
this.texture = null; this.texture = null;
} }
this.alloc(width, height); this.alloc(Integer.highestOneBit(width), Integer.highestOneBit(height));
} }
glBindVertexArray(RenderService.STATIC_VAO); glBindVertexArray(RenderService.STATIC_VAO);
int boundFB = GL11.glGetInteger(GL_DRAW_FRAMEBUFFER_BINDING); int boundFB = GL11.glGetInteger(GL_DRAW_FRAMEBUFFER_BINDING);
@@ -86,26 +86,22 @@ public class HiZBuffer {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
//System.err.println("SRC: " + GlTexture.getRawTextureType(srcDepthTex) + " DST: " + this.texture.id); glBindTextureUnit(0, srcDepthTex);
glCopyImageSubData(srcDepthTex, GL_TEXTURE_2D, 0,0,0,0,
this.texture.id, GL_TEXTURE_2D, 0,0,0,0,
width, height, 1);
glBindTextureUnit(0, this.texture.id);
glBindSampler(0, this.sampler); glBindSampler(0, this.sampler);
glUniform1i(0, 0); glUniform1i(0, 0);
int cw = this.width; int cw = this.width;
int ch = this.height; int ch = this.height;
glViewport(0, 0, cw, ch); for (int i = 0; i < this.levels; i++) {
for (int i = 0; i < this.levels-1; i++) { this.fb.bind(GL_DEPTH_ATTACHMENT, this.texture, i);
glTextureParameteri(this.texture.id, GL_TEXTURE_BASE_LEVEL, i); glViewport(0, 0, cw, ch); cw = Math.max(cw/2, 1); ch = Math.max(ch/2, 1);
glTextureParameteri(this.texture.id, GL_TEXTURE_MAX_LEVEL, i);
this.fb.bind(GL_DEPTH_ATTACHMENT, this.texture, i+1);
cw = Math.max(cw/2, 1); ch = Math.max(ch/2, 1); glViewport(0, 0, cw, ch);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glTextureBarrier(); glTextureBarrier();
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT|GL_TEXTURE_FETCH_BARRIER_BIT); glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT|GL_TEXTURE_FETCH_BARRIER_BIT);
glTextureParameteri(this.texture.id, GL_TEXTURE_BASE_LEVEL, i);
glTextureParameteri(this.texture.id, GL_TEXTURE_MAX_LEVEL, i);
if (i==0) {
glBindTextureUnit(0, this.texture.id);
}
} }
glTextureParameteri(this.texture.id, GL_TEXTURE_BASE_LEVEL, 0); glTextureParameteri(this.texture.id, GL_TEXTURE_BASE_LEVEL, 0);
glTextureParameteri(this.texture.id, GL_TEXTURE_MAX_LEVEL, 1000);//TODO: CHECK IF ITS -1 or -0 glTextureParameteri(this.texture.id, GL_TEXTURE_MAX_LEVEL, 1000);//TODO: CHECK IF ITS -1 or -0
@@ -130,4 +126,8 @@ public class HiZBuffer {
public int getHizTextureId() { public int getHizTextureId() {
return this.texture.id; return this.texture.id;
} }
public int getPackedLevels() {
return ((Integer.numberOfTrailingZeros(this.width))<<16)|(Integer.numberOfTrailingZeros(this.height));//+1
}
} }

View File

@@ -26,13 +26,6 @@ public abstract class MixinWorldRenderer implements IGetVoxyRenderSystem {
@Shadow private @Nullable ClientWorld world; @Shadow private @Nullable ClientWorld world;
@Unique private VoxyRenderSystem renderer; @Unique private VoxyRenderSystem renderer;
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;setupTerrain(Lnet/minecraft/client/render/Camera;Lnet/minecraft/client/render/Frustum;ZZ)V", shift = At.Shift.AFTER))
private void injectSetup(ObjectAllocator allocator, RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, Matrix4f positionMatrix, Matrix4f projectionMatrix, CallbackInfo ci) {
if (this.renderer != null) {
this.renderer.renderSetup(this.frustum, camera);
}
}
@Override @Override
public VoxyRenderSystem getVoxyRenderSystem() { public VoxyRenderSystem getVoxyRenderSystem() {
return this.renderer; return this.renderer;

View File

@@ -14,6 +14,30 @@ public class Logger {
public static boolean SHUTUP = false; public static boolean SHUTUP = false;
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger("Voxy"); private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger("Voxy");
private static String callClsName() {
String className = "";
if (INSERT_CLASS) {
var stackEntry = new Throwable().getStackTrace()[2];
className = stackEntry.getClassName();
var builder = new StringBuilder();
var parts = className.split("\\.");
for (int i = 0; i < parts.length; i++) {
var part = parts[i];
if (i < parts.length-1) {//-2
builder.append(part.charAt(0)).append(part.charAt(part.length()-1));
} else {
builder.append(part);
}
if (i!=parts.length-1) {
builder.append(".");
}
}
className = builder.toString();
}
return className;
}
public static void error(Object... args) { public static void error(Object... args) {
if (SHUTUP) { if (SHUTUP) {
return; return;
@@ -24,8 +48,8 @@ public class Logger {
throwable = (Throwable) i; throwable = (Throwable) i;
} }
} }
var stackEntry = new Throwable().getStackTrace()[1];
String error = (INSERT_CLASS?("["+stackEntry.getClassName()+"]: "):"") + Stream.of(args).map(Logger::objToString).collect(Collectors.joining(" ")); String error = (INSERT_CLASS?("["+callClsName()+"]: "):"") + Stream.of(args).map(Logger::objToString).collect(Collectors.joining(" "));
LOGGER.error(error, throwable); LOGGER.error(error, throwable);
if (VoxyCommon.IS_IN_MINECRAFT && !VoxyCommon.IS_DEDICATED_SERVER) { if (VoxyCommon.IS_IN_MINECRAFT && !VoxyCommon.IS_DEDICATED_SERVER) {
var instance = MinecraftClient.getInstance(); var instance = MinecraftClient.getInstance();
@@ -48,8 +72,7 @@ public class Logger {
throwable = (Throwable) i; throwable = (Throwable) i;
} }
} }
var stackEntry = new Throwable().getStackTrace()[1]; LOGGER.warn((INSERT_CLASS?("["+callClsName()+"]: "):"") + Stream.of(args).map(Logger::objToString).collect(Collectors.joining(" ")), throwable);
LOGGER.warn((INSERT_CLASS?("["+stackEntry.getClassName()+"]: "):"") + Stream.of(args).map(Logger::objToString).collect(Collectors.joining(" ")), throwable);
} }
public static void info(Object... args) { public static void info(Object... args) {
@@ -62,8 +85,7 @@ public class Logger {
throwable = (Throwable) i; throwable = (Throwable) i;
} }
} }
var stackEntry = new Throwable().getStackTrace()[1]; LOGGER.info((INSERT_CLASS?("["+callClsName()+"]: "):"") + Stream.of(args).map(Logger::objToString).collect(Collectors.joining(" ")), throwable);
LOGGER.info((INSERT_CLASS?("["+stackEntry.getClassName()+"]: "):"") + Stream.of(args).map(Logger::objToString).collect(Collectors.joining(" ")), throwable);
} }
private static String objToString(Object obj) { private static String objToString(Object obj) {

View File

@@ -6,7 +6,7 @@ layout(binding = 0) uniform sampler2D depthTex;
void main() { void main() {
vec4 depths = textureGather(depthTex, uv, 0); // Get depth values from all surrounding texels. vec4 depths = textureGather(depthTex, uv, 0); // Get depth values from all surrounding texels.
bvec4 cv = lessThanEqual(vec4(0.999999f), depths); bvec4 cv = lessThanEqual(vec4(0.999999999f), depths);
if (any(cv)) {//Patch holes (its very dodgy but should work :tm:, should clamp it to the first 3 levels) if (any(cv)) {//Patch holes (its very dodgy but should work :tm:, should clamp it to the first 3 levels)
depths = mix(vec4(0.0f), depths, cv); depths = mix(vec4(0.0f), depths, cv);
} }

View File

@@ -93,10 +93,9 @@ void bubbleSortInital(uint vis, uint id) {
bool shouldSortId(uint id) { bool shouldSortId(uint id) {
UnpackedNode node; UnpackedNode node;
if (unpackNode(node, gl_GlobalInvocationID.x)==uvec4(-1)) { if (unpackNode(node, id)==uvec4(-1)) {
return false;//Unallocated node return false;//Unallocated node
} }
if (isEmptyMesh(node) || (!hasMesh(node))) {//|| (!hasChildren(node)) if (isEmptyMesh(node) || (!hasMesh(node))) {//|| (!hasChildren(node))
return false; return false;
} }
@@ -105,6 +104,9 @@ bool shouldSortId(uint id) {
return false;//Cannot remove geometry from top level node return false;//Cannot remove geometry from top level node
} }
if (hasRequested(node)) {//If a node has a request its not valid to remove
return false;
}
/*THIS IS COMPLETLY WRONG, we need to check if all the children of the parent of the child are leaf nodes /*THIS IS COMPLETLY WRONG, we need to check if all the children of the parent of the child are leaf nodes
// not this node // not this node
@@ -130,7 +132,7 @@ void main() {
// this means that insertion into the local buffer can be accelerated W.R.T global // this means that insertion into the local buffer can be accelerated W.R.T global
for (uint i = 0; i < OPS_PER_THREAD; i++) { for (uint i = 0; i < OPS_PER_THREAD; i++) {
//Copy in with warp size batch fetch //Copy in with warp size batch fetch
uint id = gl_LocalInvocationID.x + (i*WORK_SIZE); uint id = (gl_LocalInvocationID.x*OPS_PER_THREAD) + i;
initalSort[id] = minVisIds[id]|(1u<<31);//Flag the id as being external initalSort[id] = minVisIds[id]|(1u<<31);//Flag the id as being external
} }
barrier(); barrier();
@@ -158,7 +160,7 @@ void main() {
//Work size batching //Work size batching
for (uint i = 0; i < OPS_PER_THREAD; i++) { for (uint i = 0; i < OPS_PER_THREAD; i++) {
barrier();//Probably unneeded, was just to keep warp coheriancy barrier();//Probably unneeded, was just to keep warp coheriancy
uint id = gl_LocalInvocationID.x+(i*WORK_SIZE); uint id = (gl_LocalInvocationID.x*OPS_PER_THREAD)+i;
uint sid = initalSort[id]; uint sid = initalSort[id];
if ((sid&(1u<<31)) != 0) { if ((sid&(1u<<31)) != 0) {
//The flag being external was set, meaning we should NOT insert this element //The flag being external was set, meaning we should NOT insert this element

View File

@@ -12,7 +12,7 @@
// substantually for performance (for both persistent threads and incremental) // substantually for performance (for both persistent threads and incremental)
layout(binding = HIZ_BINDING) uniform sampler2DShadow hizDepthSampler; layout(binding = HIZ_BINDING) uniform sampler2D hizDepthSampler;
//TODO: maybe do spher bounds aswell? cause they have different accuracies but are both over estimates (liberals (non conservative xD)) //TODO: maybe do spher bounds aswell? cause they have different accuracies but are both over estimates (liberals (non conservative xD))
// so can do && // so can do &&
@@ -39,7 +39,6 @@ bool checkPointInView(vec4 point) {
vec3 minBB = vec3(0.0f); vec3 minBB = vec3(0.0f);
vec3 maxBB = vec3(0.0f); vec3 maxBB = vec3(0.0f);
vec2 size = vec2(0.0f);
bool insideFrustum = false; bool insideFrustum = false;
float screenSize = 0.0f; float screenSize = 0.0f;
@@ -117,7 +116,8 @@ void setupScreenspace(in UnpackedNode node) {
minBB = min(min(min(p000, p100), min(p001, p101)), min(min(p010, p110), min(p011, p111))); minBB = min(min(min(p000, p100), min(p001, p101)), min(min(p010, p110), min(p011, p111)));
maxBB = max(max(max(p000, p100), max(p001, p101)), max(max(p010, p110), max(p011, p111))); maxBB = max(max(max(p000, p100), max(p001, p101)), max(max(p010, p110), max(p011, p111)));
size = clamp(maxBB.xy - minBB.xy, vec2(0), vec2(1)); minBB = clamp(minBB, vec3(0), vec3(1));
maxBB = clamp(maxBB, vec3(0), vec3(1));
} }
//Checks if the node is implicitly culled (outside frustum) //Checks if the node is implicitly culled (outside frustum)
@@ -128,32 +128,31 @@ bool outsideFrustum() {
} }
bool isCulledByHiz() { bool isCulledByHiz() {
vec2 ssize = size * vec2(screenW, screenH); ivec2 ssize = ivec2(1)<<ivec2((packedHizSize>>16)&0xFFFF,packedHizSize&0xFFFF);
float miplevel = log2(max(max(ssize.x, ssize.y),1)); vec2 size = (maxBB.xy-minBB.xy)*ssize;
float miplevel = log2(max(max(size.x, size.y),1));
//TODO: make a path for if the miplevel would result in the textureSampler sampling a size of 1 miplevel = floor(miplevel)-1;
miplevel = clamp(miplevel, 0, textureQueryLevels(hizDepthSampler)-1);
int ml = int(miplevel);
ssize = max(ivec2(1), ssize>>ml);
ivec2 mxbb = ivec2(maxBB.xy*ssize);
ivec2 mnbb = ivec2(minBB.xy*ssize);
miplevel = ceil(miplevel); float pointSample = -1.0f;
miplevel = clamp(miplevel, 0, 20); //float pointSample2 = 0.0f;
for (int x = mnbb.x; x<=mxbb.x; x++) {
if (miplevel >= 10.0f) {//Level 9 or 10// TODO: FIX THIS JANK SHIT for (int y = mnbb.y; y<=mxbb.y; y++) {
//return false; float sp = texelFetch(hizDepthSampler, ivec2(x, y), ml).r;
//pointSample2 = max(sp, pointSample2);
//sp = mix(sp, pointSample, 0.9999999f<=sp);
pointSample = max(sp, pointSample);
}
} }
//pointSample = mix(pointSample, pointSample2, pointSample<=0.000001f);
vec2 midpoint = (maxBB.xy + minBB.xy)*0.5f; return pointSample<=minBB.z;
float testAgainst = minBB.z;
//the *2.0f-1.0f converts from the 0->1 range to -1->1 range that depth is in (not having this causes tighter bounds, but causes culling issues in caves)
testAgainst = testAgainst*2.0f-1.0f;
bool culled = textureLod(hizDepthSampler, clamp(vec3(midpoint, testAgainst), vec3(0), vec3(1)), miplevel) < 0.0001f;
//printf("HiZ sample point: (%f,%f)@%f against %f", midpoint.x, midpoint.y, miplevel, minBB.z);
//if ((culled) && node22.lodLevel == 0) {
// printf("HiZ sample point: (%f,%f)@%f against %f, value %f", midpoint.x, midpoint.y, miplevel, minBB.z, textureLod(hizDepthSampler, vec3(0.5f,0.5f, 0.000000001f), 9.0f));
//}
return culled;
} }

View File

@@ -10,13 +10,13 @@ layout(local_size_x=LOCAL_SIZE) in;//, local_size_y=1
layout(binding = SCENE_UNIFORM_BINDING, std140) uniform SceneUniform { layout(binding = SCENE_UNIFORM_BINDING, std140) uniform SceneUniform {
mat4 VP; mat4 VP;
ivec3 camSecPos; ivec3 camSecPos;
float screenW; int packedHizSize;
vec3 camSubSecPos; vec3 camSubSecPos;
float screenH; float minSSS;
Frustum frustum; Frustum frustum;
uint renderQueueMaxSize; uint renderQueueMaxSize;
float minSSS;
uint frameId; uint frameId;
uint requestQueueSize;
}; };
#import <voxy:lod/hierarchical/queue.glsl> #import <voxy:lod/hierarchical/queue.glsl>
@@ -49,9 +49,9 @@ layout(binding = STATISTICS_BUFFER_BINDING, std430) restrict buffer statisticsBu
void addRequest(inout UnpackedNode node) { void addRequest(inout UnpackedNode node) {
//printf("Put node decend request"); //printf("Put node decend request");
if (!hasRequested(node)) { if (!hasRequested(node)) {
if (requestQueueIndex.x < REQUEST_QUEUE_SIZE) { if (requestQueueIndex.x < requestQueueSize) {//Soft limit
uint atomRes = atomicAdd(requestQueueIndex.x, 1); uint atomRes = atomicAdd(requestQueueIndex.x, 1);
if (atomRes < REQUEST_QUEUE_SIZE) { if (atomRes < MAX_REQUEST_QUEUE_SIZE) {//Hard limit
//Mark node as having a request submitted to prevent duplicate submissions //Mark node as having a request submitted to prevent duplicate submissions
requestQueue[atomRes] = getRawPos(node); requestQueue[atomRes] = getRawPos(node);
markRequested(node); markRequested(node);