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,9 +48,10 @@ 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
// than timeout, we keep the world acquired
world.acquireRef();
try {
//wait for opengl to be finished, this should hopefully ensure all memory allocations are free
glFinish();glFinish();
glFinish();
glFinish();
//Trigger the shared index buffer loading
SharedIndexBuffer.INSTANCE.id();
@@ -59,8 +60,8 @@ public class VoxyRenderSystem {
this.worldIn = world;
this.renderer = new RenderService(world, threadPool);
this.postProcessing = new PostProcessing();
int minSec = MinecraftClient.getInstance().world.getBottomSectionCoord()>>5;
int maxSec = (MinecraftClient.getInstance().world.getTopSectionCoord()-1)>>5;
int minSec = MinecraftClient.getInstance().world.getBottomSectionCoord() >> 5;
int maxSec = (MinecraftClient.getInstance().world.getTopSectionCoord() - 1) >> 5;
//Do some very cheeky stuff for MiB
if (false) {
@@ -77,6 +78,10 @@ public class VoxyRenderSystem {
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;
}
}
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() {
//only increase quality while there are very few mesh queues, this stops,
// e.g. while flying and is rendering alot of low quality chunks
@@ -160,6 +131,9 @@ public class VoxyRenderSystem {
if (IrisUtil.irisShadowActive()) {
return;
}
TimingStatistics.resetSamplers();
//Do some very cheeky stuff for MiB
if (false) {
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 = 1<<24;
//geometryCapacity = 1<<28;
//geometryCapacity = 1<<30;//1GB test
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.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);
@@ -106,6 +106,18 @@ public class RenderService<T extends AbstractSectionRenderer<J, Q>, J extends Vi
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) {
//LightMapHelper.tickLightmap();
@@ -121,6 +133,13 @@ public class RenderService<T extends AbstractSectionRenderer<J, Q>, J extends Vi
this.sectionRenderer.renderOpaque(viewport, depthBoundTexture);
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 {
//NOTE: need to do the upload and download tick here, after the section renderer renders the world, to ensure "stable"
// 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);
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();
this.traversal.doTraversal(viewport, depthBuffer);
this.traversal.doTraversal(viewport);
TimingStatistics.I.stop();
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()));
} while (this.frexStillHasWork());
TimingStatistics.H.start();

View File

@@ -179,6 +179,7 @@ public class AsyncNodeManager {
private void run() {
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();
if (this.workCounter.get() <= 0 || !this.running) {//No work
return;
@@ -753,7 +754,7 @@ public class AsyncNodeManager {
}
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) {

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.Shader;
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.HiZBuffer;
import me.cortex.voxy.client.core.rendering.Viewport;
@@ -30,7 +31,7 @@ import static org.lwjgl.opengl.GL45.*;
public class HierarchicalOcclusionTraverser {
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;
@@ -39,6 +40,7 @@ public class HierarchicalOcclusionTraverser {
private final AsyncNodeManager nodeManager;
private final NodeCleaner nodeCleaner;
private final RenderGenerationService meshGen;
private final GlBuffer requestBuffer;
@@ -73,7 +75,7 @@ public class HierarchicalOcclusionTraverser {
.defineIf("DEBUG", HIERARCHICAL_SHADER_DEBUG)
.define("MAX_ITERATIONS", MAX_ITERATIONS)
.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)
@@ -96,19 +98,18 @@ public class HierarchicalOcclusionTraverser {
.compile();
public HierarchicalOcclusionTraverser(AsyncNodeManager nodeManager, NodeCleaner nodeCleaner) {
public HierarchicalOcclusionTraverser(AsyncNodeManager nodeManager, NodeCleaner nodeCleaner, RenderGenerationService meshGen) {
this.nodeCleaner = nodeCleaner;
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);
glSamplerParameteri(this.hizSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glSamplerParameteri(this.hizSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(this.hizSampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
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_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
.ubo("SCENE_UNIFORM_BINDING", this.uniformBuffer)
@@ -175,23 +176,31 @@ public class HierarchicalOcclusionTraverser {
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;
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;
//MemoryUtil.memPutFloat(ptr, viewport.height); ptr += 4;
final float screenspaceAreaDecreasingSize = VoxyConfig.CONFIG.subDivisionSize*VoxyConfig.CONFIG.subDivisionSize;
//Screen space size for descending
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
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) {
@@ -203,10 +212,7 @@ public class HierarchicalOcclusionTraverser {
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, RENDER_QUEUE_BINDING, viewport.getRenderList().id);
}
public void doTraversal(Viewport<?> viewport, int depthBuffer) {
//Compute the mip chain
viewport.hiZBuffer.buildMipChain(depthBuffer, viewport.width, viewport.height);
public void doTraversal(Viewport<?> viewport) {
this.uploadUniform(viewport);
//UploadStream.INSTANCE.commit(); //Done inside traversal

View File

@@ -1213,7 +1213,8 @@ public class NodeManager {
if (!this.nodeData.isNodeGeometryInFlight(nodeId)) {
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 {
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
this.bindRenderingBuffers(viewport, depthBoundTexture);
glMemoryBarrier(GL_COMMAND_BARRIER_BIT|GL_SHADER_STORAGE_BARRIER_BIT);//Barrier everything is needed
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);

View File

@@ -69,12 +69,12 @@ public class HiZBuffer {
}
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) {
this.texture.free();
this.texture = null;
}
this.alloc(width, height);
this.alloc(Integer.highestOneBit(width), Integer.highestOneBit(height));
}
glBindVertexArray(RenderService.STATIC_VAO);
int boundFB = GL11.glGetInteger(GL_DRAW_FRAMEBUFFER_BINDING);
@@ -86,26 +86,22 @@ public class HiZBuffer {
glEnable(GL_DEPTH_TEST);
//System.err.println("SRC: " + GlTexture.getRawTextureType(srcDepthTex) + " DST: " + this.texture.id);
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);
glBindTextureUnit(0, srcDepthTex);
glBindSampler(0, this.sampler);
glUniform1i(0, 0);
int cw = this.width;
int ch = this.height;
glViewport(0, 0, cw, ch);
for (int i = 0; i < this.levels-1; i++) {
glTextureParameteri(this.texture.id, GL_TEXTURE_BASE_LEVEL, i);
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);
for (int i = 0; i < this.levels; i++) {
this.fb.bind(GL_DEPTH_ATTACHMENT, this.texture, i);
glViewport(0, 0, cw, ch); cw = Math.max(cw/2, 1); ch = Math.max(ch/2, 1);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glTextureBarrier();
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_MAX_LEVEL, 1000);//TODO: CHECK IF ITS -1 or -0
@@ -130,4 +126,8 @@ public class HiZBuffer {
public int getHizTextureId() {
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;
@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
public VoxyRenderSystem getVoxyRenderSystem() {
return this.renderer;

View File

@@ -14,6 +14,30 @@ public class Logger {
public static boolean SHUTUP = false;
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) {
if (SHUTUP) {
return;
@@ -24,8 +48,8 @@ public class Logger {
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);
if (VoxyCommon.IS_IN_MINECRAFT && !VoxyCommon.IS_DEDICATED_SERVER) {
var instance = MinecraftClient.getInstance();
@@ -48,8 +72,7 @@ public class Logger {
throwable = (Throwable) i;
}
}
var stackEntry = new Throwable().getStackTrace()[1];
LOGGER.warn((INSERT_CLASS?("["+stackEntry.getClassName()+"]: "):"") + Stream.of(args).map(Logger::objToString).collect(Collectors.joining(" ")), throwable);
LOGGER.warn((INSERT_CLASS?("["+callClsName()+"]: "):"") + Stream.of(args).map(Logger::objToString).collect(Collectors.joining(" ")), throwable);
}
public static void info(Object... args) {
@@ -62,8 +85,7 @@ public class Logger {
throwable = (Throwable) i;
}
}
var stackEntry = new Throwable().getStackTrace()[1];
LOGGER.info((INSERT_CLASS?("["+stackEntry.getClassName()+"]: "):"") + Stream.of(args).map(Logger::objToString).collect(Collectors.joining(" ")), throwable);
LOGGER.info((INSERT_CLASS?("["+callClsName()+"]: "):"") + Stream.of(args).map(Logger::objToString).collect(Collectors.joining(" ")), throwable);
}
private static String objToString(Object obj) {

View File

@@ -6,7 +6,7 @@ layout(binding = 0) uniform sampler2D depthTex;
void main() {
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)
depths = mix(vec4(0.0f), depths, cv);
}

View File

@@ -93,10 +93,9 @@ void bubbleSortInital(uint vis, uint id) {
bool shouldSortId(uint id) {
UnpackedNode node;
if (unpackNode(node, gl_GlobalInvocationID.x)==uvec4(-1)) {
if (unpackNode(node, id)==uvec4(-1)) {
return false;//Unallocated node
}
if (isEmptyMesh(node) || (!hasMesh(node))) {//|| (!hasChildren(node))
return false;
}
@@ -105,6 +104,9 @@ bool shouldSortId(uint id) {
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
// not this node
@@ -130,7 +132,7 @@ void main() {
// this means that insertion into the local buffer can be accelerated W.R.T global
for (uint i = 0; i < OPS_PER_THREAD; i++) {
//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
}
barrier();
@@ -158,7 +160,7 @@ void main() {
//Work size batching
for (uint i = 0; i < OPS_PER_THREAD; i++) {
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];
if ((sid&(1u<<31)) != 0) {
//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)
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))
// so can do &&
@@ -39,7 +39,6 @@ bool checkPointInView(vec4 point) {
vec3 minBB = vec3(0.0f);
vec3 maxBB = vec3(0.0f);
vec2 size = vec2(0.0f);
bool insideFrustum = false;
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)));
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)
@@ -128,32 +128,31 @@ bool outsideFrustum() {
}
bool isCulledByHiz() {
vec2 ssize = size * vec2(screenW, screenH);
float miplevel = log2(max(max(ssize.x, ssize.y),1));
ivec2 ssize = ivec2(1)<<ivec2((packedHizSize>>16)&0xFFFF,packedHizSize&0xFFFF);
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);
miplevel = clamp(miplevel, 0, 20);
if (miplevel >= 10.0f) {//Level 9 or 10// TODO: FIX THIS JANK SHIT
//return false;
float pointSample = -1.0f;
//float pointSample2 = 0.0f;
for (int x = mnbb.x; x<=mxbb.x; x++) {
for (int y = mnbb.y; y<=mxbb.y; y++) {
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;
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;
return pointSample<=minBB.z;
}

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 {
mat4 VP;
ivec3 camSecPos;
float screenW;
int packedHizSize;
vec3 camSubSecPos;
float screenH;
float minSSS;
Frustum frustum;
uint renderQueueMaxSize;
float minSSS;
uint frameId;
uint requestQueueSize;
};
#import <voxy:lod/hierarchical/queue.glsl>
@@ -49,9 +49,9 @@ layout(binding = STATISTICS_BUFFER_BINDING, std430) restrict buffer statisticsBu
void addRequest(inout UnpackedNode node) {
//printf("Put node decend request");
if (!hasRequested(node)) {
if (requestQueueIndex.x < REQUEST_QUEUE_SIZE) {
if (requestQueueIndex.x < requestQueueSize) {//Soft limit
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
requestQueue[atomRes] = getRawPos(node);
markRequested(node);