Skip to content

Commit

Permalink
The depths of the rabbit hole
Browse files Browse the repository at this point in the history
- 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?)
  • Loading branch information
Jozufozu committed Sep 14, 2024
1 parent 01a7936 commit 6c1fbf6
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public void generate() {
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);

Expand All @@ -53,15 +53,15 @@ public void generate() {
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);
Expand All @@ -85,20 +85,28 @@ private void createPyramidMips(int mipLevels, int width, int height) {
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

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;
Expand All @@ -17,7 +18,7 @@
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();
Expand Down Expand Up @@ -182,12 +183,20 @@ private static long writeCameraIn(long ptr, Camera camera) {
}

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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ 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;

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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct _FlwCullData {
float P11;
float pyramidWidth;
float pyramidHeight;
int pyramidLevels;
uint useMin;
};

Expand Down

0 comments on commit 6c1fbf6

Please sign in to comment.