From 074ee34dd4106885f4b6dedfeb54c3060a449200 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Thu, 5 Sep 2024 12:38:05 -0500 Subject: [PATCH] The depths of the rabbit hole - Fix mip levels being half the size they should be - Use the next lowest po2 from the main render target size for mip 0 - Map from dst texel to src texel rather than naively multiply by 2 - Clamp the estimated mip level in the cull shader - Use texel fetches in the cull shader (not sure if necessary?) --- .../backend/engine/indirect/DepthPyramid.java | 28 ++++++++++++------- .../backend/engine/uniform/FrameUniforms.java | 17 ++++++++--- .../flywheel/internal/indirect/cull.glsl | 16 +++++++---- .../internal/indirect/depth_reduce.glsl | 6 ++-- .../flywheel/internal/uniforms/frame.glsl | 1 + 5 files changed, 47 insertions(+), 21 deletions(-) diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/DepthPyramid.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/DepthPyramid.java index 30e9524c7..cb17f5276 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/DepthPyramid.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/DepthPyramid.java @@ -35,8 +35,8 @@ public class DepthPyramid { var mainRenderTarget = Minecraft.getInstance() .getMainRenderTarget(); - int width = mainRenderTarget.width; - int height = mainRenderTarget.height; + int width = mip0Size(mainRenderTarget.width); + int height = mip0Size(mainRenderTarget.height); int mipLevels = getImageMipLevels(width, height); @@ -53,15 +53,15 @@ public class DepthPyramid { depthReduceProgram.bind(); for (int i = 0; i < mipLevels; i++) { - int mipWidth = Math.max(1, width >> i); - int mipHeight = Math.max(1, height >> i); + int mipWidth = mipSize(width, i); + int mipHeight = mipSize(height, i); int srcTexture = (i == 0) ? depthBufferId : pyramidTextureId; GL46.glBindTexture(GL32.GL_TEXTURE_2D, srcTexture); GL46.glBindImageTexture(0, pyramidTextureId, i, false, 0, GL32.GL_WRITE_ONLY, GL32.GL_R32F); - depthReduceProgram.setUVec2("imageSize", mipWidth, mipHeight); + depthReduceProgram.setVec2("imageSize", mipWidth, mipHeight); depthReduceProgram.setInt("lod", Math.max(0, i - 1)); GL46.glDispatchCompute(MoreMath.ceilingDiv(mipWidth, 8), MoreMath.ceilingDiv(mipHeight, 8), 1); @@ -85,20 +85,28 @@ public class DepthPyramid { GL32.glBindTexture(GL32.GL_TEXTURE_2D, pyramidTextureId); for (int i = 0; i < mipLevels; i++) { - int mipWidth = Math.max(1, width >> (i + 1)); - int mipHeight = Math.max(1, height >> (i + 1)); + int mipWidth = mipSize(width, i); + int mipHeight = mipSize(height, i); GL32.glTexImage2D(GL32.GL_TEXTURE_2D, i, GL32.GL_R32F, mipWidth, mipHeight, 0, GL32.GL_RED, GL32.GL_FLOAT, 0); } } - private static int getImageMipLevels(int width, int height) { + public static int mipSize(int mip0Size, int level) { + return Math.max(1, mip0Size >> level); + } + + public static int mip0Size(int screenSize) { + return Integer.highestOneBit(screenSize); + } + + public static int getImageMipLevels(int width, int height) { int result = 1; while (width > 2 && height > 2) { result++; - width /= 2; - height /= 2; + width >>= 1; + height >>= 1; } return result; diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/FrameUniforms.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/FrameUniforms.java index b19370099..3f7b8e871 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/FrameUniforms.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/FrameUniforms.java @@ -8,6 +8,7 @@ import org.lwjgl.system.MemoryUtil; import dev.engine_room.flywheel.api.RenderContext; import dev.engine_room.flywheel.api.visualization.VisualizationManager; +import dev.engine_room.flywheel.backend.engine.indirect.DepthPyramid; import dev.engine_room.flywheel.backend.mixin.LevelRendererAccessor; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; @@ -17,7 +18,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; public final class FrameUniforms extends UniformWriter { - private static final int SIZE = 96 + 64 * 9 + 16 * 5 + 8 * 2 + 8 + 4 * 16; + private static final int SIZE = 96 + 64 * 9 + 16 * 5 + 8 * 2 + 8 + 4 * 17; static final UniformBuffer BUFFER = new UniformBuffer(Uniforms.FRAME_INDEX, SIZE); private static final Matrix4f VIEW = new Matrix4f(); @@ -182,12 +183,20 @@ public final class FrameUniforms extends UniformWriter { } private static long writeCullData(long ptr) { + var mc = Minecraft.getInstance(); + var mainRenderTarget = mc.getMainRenderTarget(); + + int pyramidWidth = DepthPyramid.mip0Size(mainRenderTarget.width); + int pyramidHeight = DepthPyramid.mip0Size(mainRenderTarget.height); + int pyramidDepth = DepthPyramid.getImageMipLevels(pyramidWidth, pyramidHeight); + ptr = writeFloat(ptr, 0.05F); // zNear - ptr = writeFloat(ptr, Minecraft.getInstance().gameRenderer.getDepthFar()); // zFar + ptr = writeFloat(ptr, mc.gameRenderer.getDepthFar()); // zFar ptr = writeFloat(ptr, PROJECTION.m00()); // P00 ptr = writeFloat(ptr, PROJECTION.m11()); // P11 - ptr = writeFloat(ptr, Minecraft.getInstance().getMainRenderTarget().width >> 1); // pyramidWidth - ptr = writeFloat(ptr, Minecraft.getInstance().getMainRenderTarget().height >> 1); // pyramidHeight + ptr = writeFloat(ptr, pyramidWidth); // pyramidWidth + ptr = writeFloat(ptr, pyramidHeight); // pyramidHeight + ptr = writeInt(ptr, pyramidDepth - 1); // pyramidLevels ptr = writeInt(ptr, 0); // useMin return ptr; diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl index 6d8be7aaf..1b6436a42 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl @@ -91,12 +91,18 @@ bool _flw_isVisible(uint instanceIndex, uint modelIndex) { float width = (aabb.z - aabb.x) * _flw_cullData.pyramidWidth; float height = (aabb.w - aabb.y) * _flw_cullData.pyramidHeight; - float level = floor(log2(max(width, height))); + int level = clamp(0, int(ceil(log2(max(width, height)))), _flw_cullData.pyramidLevels); - float depth01 = textureLod(_flw_depthPyramid, aabb.xw, level).r; - float depth11 = textureLod(_flw_depthPyramid, aabb.zw, level).r; - float depth10 = textureLod(_flw_depthPyramid, aabb.zy, level).r; - float depth00 = textureLod(_flw_depthPyramid, aabb.xy, level).r; + ivec2 levelSize = textureSize(_flw_depthPyramid, level); + + ivec4 levelSizePair = ivec4(levelSize, levelSize); + + ivec4 bounds = ivec4(aabb * vec4(levelSizePair)); + + float depth01 = texelFetch(_flw_depthPyramid, bounds.xw, level).r; + float depth11 = texelFetch(_flw_depthPyramid, bounds.zw, level).r; + float depth10 = texelFetch(_flw_depthPyramid, bounds.zy, level).r; + float depth00 = texelFetch(_flw_depthPyramid, bounds.xy, level).r; float depth; if (_flw_cullData.useMin == 0) { diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/depth_reduce.glsl b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/depth_reduce.glsl index 42bcd7f4e..49bbbf947 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/depth_reduce.glsl +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/depth_reduce.glsl @@ -3,7 +3,7 @@ layout(local_size_x = 8, local_size_y = 8) in; layout(binding = 0, r32f) uniform writeonly image2D outImage; layout(binding = 1) uniform sampler2D inImage; -uniform uvec2 imageSize; +uniform vec2 imageSize; uniform int lod; uniform int useMin = 0; @@ -11,7 +11,9 @@ uniform int useMin = 0; void main() { uvec2 pos = gl_GlobalInvocationID.xy; - ivec2 samplePos = ivec2(pos) * 2; + // Map the output texel to an input texel. Properly do the division because generating mip0 maps from the actual + // full resolution depth buffer and the aspect ratio may be different from our Po2 pyramid. + ivec2 samplePos = ivec2(floor(vec2(pos) * vec2(textureSize(inImage, lod)) / imageSize)); float depth01 = texelFetchOffset(inImage, samplePos, lod, ivec2(0, 1)).r; float depth11 = texelFetchOffset(inImage, samplePos, lod, ivec2(1, 1)).r; diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/uniforms/frame.glsl b/common/src/backend/resources/assets/flywheel/flywheel/internal/uniforms/frame.glsl index 4ce722400..05b3110dc 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/uniforms/frame.glsl +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/uniforms/frame.glsl @@ -16,6 +16,7 @@ struct _FlwCullData { float P11; float pyramidWidth; float pyramidHeight; + int pyramidLevels; uint useMin; };