Skip to content

Commit

Permalink
Directly visible
Browse files Browse the repository at this point in the history
- Don't actually need a framebuffer attachment for visibility
- Instead, process everything in pass 2 and write out the visibility
  bitset directly
- Persist visibility bits between frames for use in pass 1
- No need for indirect dispatch!
- Also saves some ssbo bindings
- Do frustum culling in both passes
  • Loading branch information
Jozufozu committed Oct 18, 2024
1 parent afdab92 commit b90c43b
Show file tree
Hide file tree
Showing 13 changed files with 109 additions and 513 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ private static CompilationHarness<InstanceType<?>> createCullingCompiler(ShaderS
.nameMapper(instanceType -> name + "/" + ResourceUtil.toDebugFileNameNoExtension(instanceType.cullShader()))
.requireExtensions(COMPUTE_EXTENSIONS)
.define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
.enableExtension("GL_KHR_shader_subgroup_basic")
.enableExtension("GL_KHR_shader_subgroup_ballot")
.withResource(CULL_SHADER_API_IMPL)
.withComponent(InstanceStructComponent::new)
.withResource(InstanceType::cullShader)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package dev.engine_room.flywheel.backend.engine.indirect;

public final class BufferBindings {
public static final int PASS_TWO_DISPATCH = 0;
public static final int PASS_TWO_INSTANCE_INDEX = 1;
public static final int PAGE_FRAME_DESCRIPTOR = 2;
public static final int INSTANCE = 3;
public static final int DRAW_INSTANCE_INDEX = 4;
public static final int MODEL = 5;
public static final int DRAW = 6;
public static final int LAST_FRAME_VISIBILITY = 0;
public static final int PAGE_FRAME_DESCRIPTOR = 1;
public static final int INSTANCE = 2;
public static final int DRAW_INSTANCE_INDEX = 3;
public static final int MODEL = 4;
public static final int DRAW = 5;

public static final int LIGHT_LUT = 7;
public static final int LIGHT_SECTION = 8;
public static final int MATRICES = 9;
public static final int LAST_FRAME_VISIBILITY = 10;
public static final int LIGHT_LUT = 6;
public static final int LIGHT_SECTION = 7;
public static final int MATRICES = 8;

private BufferBindings() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
import org.lwjgl.system.Pointer;

import dev.engine_room.flywheel.backend.gl.buffer.GlBufferType;
import dev.engine_room.flywheel.lib.math.MoreMath;
import dev.engine_room.flywheel.lib.memory.MemoryBlock;

public class IndirectBuffers {
// Number of vbos created.
public static final int BUFFER_COUNT = 7;
public static final int BUFFER_COUNT = 6;

public static final long INT_SIZE = Integer.BYTES;
public static final long PTR_SIZE = Pointer.POINTER_SIZE;
Expand All @@ -30,17 +31,15 @@ public class IndirectBuffers {
private static final long BUFFERS_SIZE_BYTES = SIZE_OFFSET + BUFFER_COUNT * PTR_SIZE;

// Offsets to the vbos
private static final long PASS_TWO_DISPATCH_HANDLE_OFFSET = HANDLE_OFFSET + BufferBindings.PASS_TWO_DISPATCH * INT_SIZE;
private static final long PASS_TWO_INSTANCE_INDEX_HANDLE_OFFSET = HANDLE_OFFSET + BufferBindings.PASS_TWO_INSTANCE_INDEX * INT_SIZE;
private static final long LAST_FRAME_VISIBILITY_HANDLE_OFFSET = HANDLE_OFFSET + BufferBindings.LAST_FRAME_VISIBILITY * INT_SIZE;
private static final long PAGE_FRAME_DESCRIPTOR_HANDLE_OFFSET = HANDLE_OFFSET + BufferBindings.PAGE_FRAME_DESCRIPTOR * INT_SIZE;
private static final long INSTANCE_HANDLE_OFFSET = HANDLE_OFFSET + BufferBindings.INSTANCE * INT_SIZE;
private static final long DRAW_INSTANCE_INDEX_HANDLE_OFFSET = HANDLE_OFFSET + BufferBindings.DRAW_INSTANCE_INDEX * INT_SIZE;
private static final long MODEL_HANDLE_OFFSET = HANDLE_OFFSET + BufferBindings.MODEL * INT_SIZE;
private static final long DRAW_HANDLE_OFFSET = HANDLE_OFFSET + BufferBindings.DRAW * INT_SIZE;

// Offsets to the sizes
private static final long PASS_TWO_DISPATCH_SIZE_OFFSET = SIZE_OFFSET + BufferBindings.PASS_TWO_DISPATCH * PTR_SIZE;
private static final long PASS_TWO_INSTANCE_INDEX_SIZE_OFFSET = SIZE_OFFSET + BufferBindings.PASS_TWO_INSTANCE_INDEX * PTR_SIZE;
private static final long LAST_FRAME_VISIBILITY_SIZE_OFFSET = SIZE_OFFSET + BufferBindings.LAST_FRAME_VISIBILITY * PTR_SIZE;
private static final long PAGE_FRAME_DESCRIPTOR_SIZE_OFFSET = SIZE_OFFSET + BufferBindings.PAGE_FRAME_DESCRIPTOR * PTR_SIZE;
private static final long INSTANCE_SIZE_OFFSET = SIZE_OFFSET + BufferBindings.INSTANCE * PTR_SIZE;
private static final long DRAW_INSTANCE_INDEX_SIZE_OFFSET = SIZE_OFFSET + BufferBindings.DRAW_INSTANCE_INDEX * PTR_SIZE;
Expand All @@ -66,8 +65,7 @@ public class IndirectBuffers {
*/
private final MemoryBlock multiBindBlock;

public final ResizableStorageBuffer passTwoDispatch;
public final ResizableStorageArray passTwoInstanceIndex;
public final ResizableStorageArray lastFrameVisibility;
public final ObjectStorage objectStorage;
public final ResizableStorageArray drawInstanceIndex;
public final ResizableStorageArray model;
Expand All @@ -76,34 +74,29 @@ public class IndirectBuffers {
IndirectBuffers(long instanceStride) {
this.multiBindBlock = MemoryBlock.calloc(BUFFERS_SIZE_BYTES, 1);

passTwoDispatch = new ResizableStorageBuffer();
passTwoInstanceIndex = new ResizableStorageArray(INT_SIZE, INSTANCE_GROWTH_FACTOR);
lastFrameVisibility = new ResizableStorageArray(INT_SIZE, INSTANCE_GROWTH_FACTOR);
objectStorage = new ObjectStorage(instanceStride);
drawInstanceIndex = new ResizableStorageArray(INT_SIZE, INSTANCE_GROWTH_FACTOR);
model = new ResizableStorageArray(MODEL_STRIDE, MODEL_GROWTH_FACTOR);
draw = new ResizableStorageArray(DRAW_COMMAND_STRIDE, DRAW_GROWTH_FACTOR);

passTwoDispatch.ensureCapacity(INT_SIZE * 4);
}

void updateCounts(int instanceCount, int modelCount, int drawCount) {
drawInstanceIndex.ensureCapacity(instanceCount);
passTwoInstanceIndex.ensureCapacity(instanceCount);
lastFrameVisibility.ensureCapacity(MoreMath.ceilingDiv(instanceCount, 32));
model.ensureCapacity(modelCount);
draw.ensureCapacity(drawCount);

final long ptr = multiBindBlock.ptr();

MemoryUtil.memPutInt(ptr + PASS_TWO_DISPATCH_HANDLE_OFFSET, passTwoDispatch.handle());
MemoryUtil.memPutInt(ptr + PASS_TWO_INSTANCE_INDEX_HANDLE_OFFSET, passTwoInstanceIndex.handle());
MemoryUtil.memPutInt(ptr + LAST_FRAME_VISIBILITY_HANDLE_OFFSET, lastFrameVisibility.handle());
MemoryUtil.memPutInt(ptr + PAGE_FRAME_DESCRIPTOR_HANDLE_OFFSET, objectStorage.frameDescriptorBuffer.handle());
MemoryUtil.memPutInt(ptr + INSTANCE_HANDLE_OFFSET, objectStorage.objectBuffer.handle());
MemoryUtil.memPutInt(ptr + DRAW_INSTANCE_INDEX_HANDLE_OFFSET, drawInstanceIndex.handle());
MemoryUtil.memPutInt(ptr + MODEL_HANDLE_OFFSET, model.handle());
MemoryUtil.memPutInt(ptr + DRAW_HANDLE_OFFSET, draw.handle());

MemoryUtil.memPutAddress(ptr + PASS_TWO_DISPATCH_SIZE_OFFSET, passTwoDispatch.capacity());
MemoryUtil.memPutAddress(ptr + PASS_TWO_INSTANCE_INDEX_SIZE_OFFSET, INT_SIZE * instanceCount);
MemoryUtil.memPutAddress(ptr + LAST_FRAME_VISIBILITY_SIZE_OFFSET, INT_SIZE * MoreMath.ceilingDiv(instanceCount, 32));
MemoryUtil.memPutAddress(ptr + PAGE_FRAME_DESCRIPTOR_SIZE_OFFSET, objectStorage.frameDescriptorBuffer.capacity());
MemoryUtil.memPutAddress(ptr + INSTANCE_SIZE_OFFSET, objectStorage.objectBuffer.capacity());
MemoryUtil.memPutAddress(ptr + DRAW_INSTANCE_INDEX_SIZE_OFFSET, INT_SIZE * instanceCount);
Expand All @@ -112,24 +105,23 @@ void updateCounts(int instanceCount, int modelCount, int drawCount) {
}

public void bindForCullPassOne() {
multiBind(0, 6);
multiBind(0, 5);
}

public void bindForCullPassTwo() {
multiBind(0, 6);
GlBufferType.DISPATCH_INDIRECT_BUFFER.bind(passTwoDispatch.handle());
multiBind(0, 5);
}

public void bindForApply() {
multiBind(5, 2);
multiBind(4, 2);
}

public void bindForModelReset() {
multiBind(5, 1);
multiBind(4, 1);
}

public void bindForDraw() {
multiBind(3, 4);
multiBind(2, 4);
GlBufferType.DRAW_INDIRECT_BUFFER.bind(draw.handle());
}

Expand All @@ -155,7 +147,6 @@ public void delete() {
drawInstanceIndex.delete();
model.delete();
draw.delete();
passTwoDispatch.delete();
passTwoInstanceIndex.delete();
lastFrameVisibility.delete();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,13 @@
import static org.lwjgl.opengl.GL42.GL_COMMAND_BARRIER_BIT;
import static org.lwjgl.opengl.GL42.glMemoryBarrier;
import static org.lwjgl.opengl.GL43.glDispatchCompute;
import static org.lwjgl.opengl.GL43.glDispatchComputeIndirect;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

import org.lwjgl.opengl.GL46;

import dev.engine_room.flywheel.api.instance.Instance;
import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.api.material.Material;
Expand All @@ -29,7 +26,6 @@
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
import dev.engine_room.flywheel.backend.gl.GlCompat;
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
import dev.engine_room.flywheel.lib.material.LightShaders;
import dev.engine_room.flywheel.lib.math.MoreMath;

public class IndirectCullingGroup<I extends Instance> {
Expand All @@ -54,12 +50,6 @@ public class IndirectCullingGroup<I extends Instance> {
private boolean needsDrawSort;
public int instanceCountThisFrame;

private int pagesLastFrame = 0;
private int pagesThisFrame = 0;

private int visibilityWriteOffsetPages = 0;
private int visibilityReadOffsetPages = 0;

IndirectCullingGroup(InstanceType<I> instanceType, IndirectPrograms programs) {
this.instanceType = instanceType;
instanceStride = MoreMath.align4(instanceType.layout()
Expand Down Expand Up @@ -95,17 +85,6 @@ public void flushInstancers() {
}
}

public int flipVisibilityOffsets(int visibilityWriteOffsetPages) {
this.visibilityReadOffsetPages = this.visibilityWriteOffsetPages;
this.visibilityWriteOffsetPages = visibilityWriteOffsetPages;

pagesLastFrame = pagesThisFrame;

pagesThisFrame = buffers.objectStorage.capacity();

return pagesThisFrame;
}

public void upload(StagingBuffer stagingBuffer) {
if (nothingToDo()) {
return;
Expand All @@ -127,8 +106,6 @@ public void upload(StagingBuffer stagingBuffer) {
}

uploadDraws(stagingBuffer);

GL46.nglClearNamedBufferData(buffers.passTwoDispatch.handle(), GL46.GL_R32UI, GL46.GL_RED, GL46.GL_UNSIGNED_INT, 0);
}

public void dispatchCull() {
Expand All @@ -139,8 +116,6 @@ public void dispatchCull() {
Uniforms.bindAll();
earlyCull.bind();

earlyCull.setUInt("_flw_visibilityReadOffsetPages", visibilityReadOffsetPages);

buffers.bindForCullPassOne();
glDispatchCompute(buffers.objectStorage.capacity(), 1, 1);
}
Expand All @@ -154,7 +129,7 @@ public void dispatchCullPassTwo() {
lateCull.bind();

buffers.bindForCullPassTwo();
glDispatchComputeIndirect(0);
glDispatchCompute(buffers.objectStorage.capacity(), 1, 1);
}

public void dispatchApply() {
Expand Down Expand Up @@ -257,8 +232,6 @@ public void submit(VisualType visualType) {
// Don't need to do this unless the program changes.
drawProgram.bind();
baseDrawUniformLoc = drawProgram.getUniformLocation("_flw_baseDraw");

drawProgram.setUInt("_flw_visibilityWriteOffsetInstances", visibilityWriteOffsetPages << ObjectStorage.LOG_2_PAGE_SIZE);
}

glUniform1ui(baseDrawUniformLoc, multiDraw.start);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,6 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
private final MatrixBuffer matrixBuffer;

private final DepthPyramid depthPyramid;
private final VisibilityBuffer visibilityBuffer;

private int totalPagesLastFrame = 0;

private boolean needsBarrier = false;

public IndirectDrawManager(IndirectPrograms programs) {
this.programs = programs;
Expand All @@ -73,7 +68,6 @@ public IndirectDrawManager(IndirectPrograms programs) {
matrixBuffer = new MatrixBuffer();

depthPyramid = new DepthPyramid(programs);
visibilityBuffer = new VisibilityBuffer(programs);
}

@Override
Expand Down Expand Up @@ -112,8 +106,6 @@ public void render(VisualType visualType) {

glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT);

visibilityBuffer.bind();

for (var group1 : cullingGroups.values()) {
group1.dispatchCull();
}
Expand All @@ -124,8 +116,6 @@ public void render(VisualType visualType) {

glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);

visibilityBuffer.attach();

submitDraws();

depthPyramid.generate();
Expand Down Expand Up @@ -156,8 +146,6 @@ public void render(VisualType visualType) {

MaterialRenderState.reset();
TextureBinder.resetLightAndOverlay();

visibilityBuffer.detach();
}

private void dispatchApply() {
Expand Down Expand Up @@ -185,20 +173,12 @@ public void flush(LightStorage lightStorage, EnvironmentStorage environmentStora
group.flushInstancers();
}

visibilityBuffer.read(totalPagesLastFrame);
visibilityBuffer.clear();

cullingGroups.values()
.removeIf(IndirectCullingGroup::checkEmptyAndDelete);

instancers.values()
.removeIf(instancer -> instancer.instanceCount() == 0);

int totalPagesThisFrame = 0;
for (var group : cullingGroups.values()) {
totalPagesThisFrame += group.flipVisibilityOffsets(totalPagesThisFrame);
}

meshPool.flush();

stagingBuffer.reclaim();
Expand All @@ -215,10 +195,6 @@ public void flush(LightStorage lightStorage, EnvironmentStorage environmentStora

// We could probably save some driver calls here when there are
// actually zero instances, but that feels like a very rare case

needsBarrier = true;

totalPagesLastFrame = totalPagesThisFrame;
}

@Override
Expand All @@ -238,8 +214,6 @@ public void delete() {
programs.release();

depthPyramid.delete();

visibilityBuffer.delete();
}

public void renderCrumbling(List<Engine.CrumblingBlock> crumblingBlocks) {
Expand Down
Loading

0 comments on commit b90c43b

Please sign in to comment.