diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectDrawManager.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectDrawManager.java index 494403045..7f71d72d0 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectDrawManager.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/IndirectDrawManager.java @@ -49,6 +49,7 @@ public class IndirectDrawManager extends DrawManager> { private final MatrixBuffer matrixBuffer; private final DepthPyramid depthPyramid; + private final VisibilityBuffer visibilityBuffer; private boolean needsBarrier = false; @@ -64,6 +65,7 @@ public class IndirectDrawManager extends DrawManager> { matrixBuffer = new MatrixBuffer(); depthPyramid = new DepthPyramid(programs.getDepthReduceProgram()); + visibilityBuffer = new VisibilityBuffer(); } @Override @@ -100,6 +102,8 @@ public class IndirectDrawManager extends DrawManager> { matrixBuffer.bind(); Uniforms.bindAll(); + visibilityBuffer.attach(); + if (needsBarrier) { glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); needsBarrier = false; @@ -111,6 +115,8 @@ public class IndirectDrawManager extends DrawManager> { MaterialRenderState.reset(); TextureBinder.resetLightAndOverlay(); + + visibilityBuffer.detach(); } } @@ -185,6 +191,10 @@ public class IndirectDrawManager extends DrawManager> { crumblingDrawBuffer.delete(); programs.release(); + + depthPyramid.delete(); + + visibilityBuffer.delete(); } public void renderCrumbling(List crumblingBlocks) { diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/VisibilityBuffer.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/VisibilityBuffer.java new file mode 100644 index 000000000..025d7bf1f --- /dev/null +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/indirect/VisibilityBuffer.java @@ -0,0 +1,87 @@ +package dev.engine_room.flywheel.backend.engine.indirect; + +import org.lwjgl.opengl.GL30; +import org.lwjgl.opengl.GL32; +import org.lwjgl.opengl.GL46; + +import com.mojang.blaze3d.platform.GlStateManager; + +import dev.engine_room.flywheel.backend.FlwBackend; +import dev.engine_room.flywheel.backend.gl.GlTextureUnit; +import it.unimi.dsi.fastutil.ints.IntArraySet; +import it.unimi.dsi.fastutil.ints.IntSet; +import net.minecraft.client.Minecraft; + +public class VisibilityBuffer { + private static final int ATTACHMENT = GL30.GL_COLOR_ATTACHMENT1; + + private final int textureId; + + private int lastWidth = -1; + private int lastHeight = -1; + + private final IntSet attached = new IntArraySet(); + + public VisibilityBuffer() { + textureId = GL32.glGenTextures(); + + GlStateManager._bindTexture(textureId); + GlStateManager._texParameter(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_NEAREST); + GlStateManager._texParameter(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_NEAREST); + GlStateManager._texParameter(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_WRAP_S, GL32.GL_CLAMP_TO_EDGE); + GlStateManager._texParameter(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_WRAP_T, GL32.GL_CLAMP_TO_EDGE); + } + + public void attach() { + // TODO: clear the vis buffer. maybe do this when we read it? + + var mainRenderTarget = Minecraft.getInstance() + .getMainRenderTarget(); + + setupTexture(mainRenderTarget.width, mainRenderTarget.height); + + if (attached.add(mainRenderTarget.frameBufferId)) { + GL46.glNamedFramebufferTexture(mainRenderTarget.frameBufferId, ATTACHMENT, textureId, 0); + + try { + mainRenderTarget.checkStatus(); + } catch (Exception e) { + FlwBackend.LOGGER.error("Error attaching visbuffer", e); + } + } + + // Enable writes + GL46.glNamedFramebufferDrawBuffers(mainRenderTarget.frameBufferId, new int[] { GL30.GL_COLOR_ATTACHMENT0, ATTACHMENT }); + } + + public void detach() { + var mainRenderTarget = Minecraft.getInstance() + .getMainRenderTarget(); + + // Disable writes + GL46.glNamedFramebufferDrawBuffers(mainRenderTarget.frameBufferId, new int[] { GL30.GL_COLOR_ATTACHMENT0 }); + } + + public void delete() { + GL32.glDeleteTextures(textureId); + } + + private void setupTexture(int width, int height) { + if (lastWidth == width && lastHeight == height) { + return; + } + + // Need to rebind to all fbos because an attachment becomes incomplete when it's resized + attached.clear(); + + lastWidth = width; + lastHeight = height; + + GlTextureUnit.T0.makeActive(); + GlStateManager._bindTexture(textureId); + + // TODO: DSA texture storage? + GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_R32UI, width, height, 0, GL32.GL_RED_INTEGER, GL32.GL_UNSIGNED_INT, 0); + GlStateManager._bindTexture(0); + } +} diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/common.frag b/common/src/backend/resources/assets/flywheel/flywheel/internal/common.frag index aac8334b3..6e367fd3e 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/common.frag +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/common.frag @@ -13,9 +13,7 @@ uniform sampler2D _flw_crumblingTex; in vec2 _flw_crumblingTexCoord; #endif -flat in uint _flw_instanceID; - -out vec4 _flw_outputColor; +layout(location = 0) out vec4 _flw_outputColor; float _flw_diffuseFactor() { if (flw_material.diffuse) { @@ -29,7 +27,7 @@ float _flw_diffuseFactor() { } } -void _flw_main() { +void _flw_main(uint instanceID) { flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord); flw_fragColor = flw_vertexColor * flw_sampleColor; flw_fragOverlay = flw_vertexOverlay; @@ -72,7 +70,7 @@ void _flw_main() { color = vec4(flw_vertexNormal * .5 + .5, 1.); break; case 2u: - color = _flw_id2Color(_flw_instanceID); + color = _flw_id2Color(instanceID); break; case 3u: color = vec4(vec2((flw_fragLight * 15.0 + 0.5) / 16.), 0., 1.); diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/common.vert b/common/src/backend/resources/assets/flywheel/flywheel/internal/common.vert index 214ab12d2..888114d5d 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/common.vert +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/common.vert @@ -71,9 +71,7 @@ mat4 _flw_modelMatrix; mat3 _flw_normalMatrix; #endif -flat out uint _flw_instanceID; - -void _flw_main(in FlwInstance instance, in uint stableInstanceID) { +void _flw_main(in FlwInstance instance) { _flw_layoutVertex(); flw_instanceVertex(instance); flw_materialVertex(); @@ -92,6 +90,4 @@ void _flw_main(in FlwInstance instance, in uint stableInstanceID) { flw_distance = fogDistance(flw_vertexPos.xyz, flw_cameraPos, flw_fogShape); gl_Position = flw_viewProjection * flw_vertexPos; - - _flw_instanceID = stableInstanceID; } diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.frag b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.frag index 7d528ce24..b0f246634 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.frag +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.frag @@ -4,10 +4,16 @@ flat in uvec3 _flw_packedMaterial; +flat in uint _flw_instanceID; + +layout(location = 1) out uint _flw_out_instanceID; + void main() { _flw_uberMaterialFragmentIndex = _flw_packedMaterial.x; _flw_unpackUint2x16(_flw_packedMaterial.y, _flw_uberFogIndex, _flw_uberCutoutIndex); _flw_unpackMaterialProperties(_flw_packedMaterial.z, flw_material); - _flw_main(); + _flw_main(_flw_instanceID); + + _flw_out_instanceID = _flw_instanceID; } diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.vert b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.vert index e53dff313..9cc21ce97 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.vert +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/main.vert @@ -21,8 +21,14 @@ layout(std430, binding = _FLW_MATRIX_BUFFER_BINDING) restrict buffer MatrixBuffe uniform uint _flw_baseDraw; +// We read the visibility buffer for all culling groups into a single shared buffer. +// This offset is used to know where each culling group starts. +uniform uint _flw_globalInstanceIdOffset = 0; + flat out uvec3 _flw_packedMaterial; +flat out uint _flw_instanceID; + void main() { #if __VERSION__ < 460 uint drawIndex = gl_DrawIDARB + _flw_baseDraw; @@ -49,5 +55,8 @@ void main() { #endif FlwInstance instance = _flw_unpackInstance(instanceIndex); - _flw_main(instance, instanceIndex); + _flw_main(instance); + + // Add 1 because a 0 instance id means null. + _flw_instanceID = _flw_globalInstanceIdOffset + instanceIndex + 1; } diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/read_visibility.glsl b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/read_visibility.glsl new file mode 100644 index 000000000..dad817b98 --- /dev/null +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/read_visibility.glsl @@ -0,0 +1,25 @@ +layout(local_size_x = 8, local_size_y = 8) in; + +layout(binding = 0) uniform usampler2D visBuffer; + +layout(std430) restrict buffer VisibleFlagBuffer { + uint _flw_visibleFlag[]; +}; + +void main() { + uint instanceID = texelFetch(visBuffer, ivec2(gl_GlobalInvocationID.xy), 0).r; + + // Null instance id. + if (instanceID == 0) { + return; + } + + // Adjust for null to find the actual index. + instanceID = instanceID - 1; + + uint index = instanceID >> 5; + + uint mask = 1u << (instanceID & 31u); + + atomicOr(_flw_visibleFlag[index], mask); +} diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.frag b/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.frag index cfd7dfea1..d88d748f2 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.frag +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.frag @@ -3,10 +3,12 @@ uniform uvec4 _flw_packedMaterial; +flat in uint _flw_instanceID; + void main() { _flw_uberMaterialFragmentIndex = _flw_packedMaterial.y; _flw_unpackUint2x16(_flw_packedMaterial.z, _flw_uberFogIndex, _flw_uberCutoutIndex); _flw_unpackMaterialProperties(_flw_packedMaterial.w, flw_material); - _flw_main(); + _flw_main(_flw_instanceID); } diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.vert b/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.vert index 30a863917..bb0a9be65 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.vert +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/instancing/main.vert @@ -10,6 +10,8 @@ uniform mat4 _flw_modelMatrixUniform; uniform mat3 _flw_normalMatrixUniform; #endif +flat out uint _flw_instanceID; + void main() { _flw_uberMaterialVertexIndex = _flw_packedMaterial.x; _flw_unpackMaterialProperties(_flw_packedMaterial.w, flw_material); @@ -21,5 +23,7 @@ void main() { _flw_normalMatrix = _flw_normalMatrixUniform; #endif - _flw_main(instance, uint(gl_InstanceID)); + _flw_main(instance); + + _flw_instanceID = gl_InstanceID; }