If you say so

- Only do OIT for materials marked ORDER_INDEPENDENT
- Clean up some of the indirect frame logic, early out if there's
  nothing to do
This commit is contained in:
Jozufozu 2025-02-23 15:07:46 -08:00
parent c1ae6256e5
commit 026eb90566
3 changed files with 59 additions and 58 deletions

View file

@ -146,7 +146,7 @@ public final class MaterialRenderState {
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
}
case TRANSLUCENT, ORDER_INDEPENDENT -> {
case TRANSLUCENT -> {
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
}

View file

@ -38,7 +38,7 @@ public class IndirectCullingGroup<I extends Instance> {
private final List<IndirectInstancer<I>> instancers = new ArrayList<>();
private final List<IndirectDraw> indirectDraws = new ArrayList<>();
private final List<MultiDraw> multiDraws = new ArrayList<>();
private final List<MultiDraw> transparentDraws = new ArrayList<>();
private final List<MultiDraw> oitDraws = new ArrayList<>();
private final IndirectPrograms programs;
private final GlProgram cullProgram;
@ -57,7 +57,7 @@ public class IndirectCullingGroup<I extends Instance> {
cullProgram = programs.getCullingProgram(instanceType);
}
public void flushInstancers() {
public boolean flushInstancers() {
instanceCountThisFrame = 0;
int modelIndex = 0;
for (var iterator = instancers.iterator(); iterator.hasNext(); ) {
@ -79,13 +79,17 @@ public class IndirectCullingGroup<I extends Instance> {
if (indirectDraws.removeIf(IndirectDraw::deleted)) {
needsDrawSort = true;
}
var out = indirectDraws.isEmpty();
if (out) {
delete();
}
return out;
}
public void upload(StagingBuffer stagingBuffer) {
if (nothingToDo()) {
return;
}
buffers.updateCounts(instanceCountThisFrame, instancers.size(), indirectDraws.size());
// Upload only instances that have changed.
@ -107,10 +111,6 @@ public class IndirectCullingGroup<I extends Instance> {
}
public void dispatchCull() {
if (nothingToDo()) {
return;
}
Uniforms.bindAll();
cullProgram.bind();
@ -119,21 +119,17 @@ public class IndirectCullingGroup<I extends Instance> {
}
public void dispatchApply() {
if (nothingToDo()) {
return;
}
buffers.bindForApply();
glDispatchCompute(GlCompat.getComputeGroupCount(indirectDraws.size()), 1, 1);
}
private boolean nothingToDo() {
return indirectDraws.isEmpty() || instanceCountThisFrame == 0;
public boolean hasOitDraws() {
return !oitDraws.isEmpty();
}
private void sortDraws() {
multiDraws.clear();
transparentDraws.clear();
oitDraws.clear();
// sort by visual type, then material
indirectDraws.sort(DRAW_COMPARATOR);
@ -143,7 +139,7 @@ public class IndirectCullingGroup<I extends Instance> {
// if the next draw call has a different VisualType or Material, start a new MultiDraw
if (i == indirectDraws.size() - 1 || incompatibleDraws(draw1, indirectDraws.get(i + 1))) {
var dst = draw1.material()
.transparency() == Transparency.TRANSLUCENT ? transparentDraws : multiDraws;
.transparency() == Transparency.ORDER_INDEPENDENT ? oitDraws : multiDraws;
dst.add(new MultiDraw(draw1.material(), draw1.isEmbedded(), start, i + 1));
start = i + 1;
}
@ -178,7 +174,7 @@ public class IndirectCullingGroup<I extends Instance> {
}
public void submitSolid() {
if (nothingToDo()) {
if (multiDraws.isEmpty()) {
return;
}
@ -204,7 +200,7 @@ public class IndirectCullingGroup<I extends Instance> {
}
public void submitTransparent(PipelineCompiler.OitMode oit) {
if (nothingToDo()) {
if (oitDraws.isEmpty()) {
return;
}
@ -214,7 +210,7 @@ public class IndirectCullingGroup<I extends Instance> {
GlProgram lastProgram = null;
for (var multiDraw : transparentDraws) {
for (var multiDraw : oitDraws) {
var drawProgram = programs.getIndirectProgram(instanceType, multiDraw.embedded ? ContextShader.EMBEDDED : ContextShader.DEFAULT, multiDraw.material, oit);
if (drawProgram != lastProgram) {
lastProgram = drawProgram;
@ -290,16 +286,6 @@ public class IndirectCullingGroup<I extends Instance> {
buffers.delete();
}
public boolean checkEmptyAndDelete() {
var out = indirectDraws.isEmpty();
if (out) {
delete();
}
return out;
}
private record MultiDraw(Material material, boolean embedded, int start, int end) {
private void submit(GlProgram drawProgram) {
GlCompat.safeMultiDrawElementsIndirect(drawProgram, GL_TRIANGLES, GL_UNSIGNED_INT, this.start, this.end, IndirectBuffers.DRAW_COMMAND_STRIDE);

View file

@ -85,13 +85,11 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
public void render(LightStorage lightStorage, EnvironmentStorage environmentStorage) {
super.render(lightStorage, environmentStorage);
for (var group : cullingGroups.values()) {
group.flushInstancers();
}
// Flush instance counts, page mappings, and prune empty groups.
cullingGroups.values()
.removeIf(IndirectCullingGroup::checkEmptyAndDelete);
.removeIf(IndirectCullingGroup::flushInstancers);
// Instancers may have been emptied in the above call, now remove them here.
instancers.values()
.removeIf(instancer -> instancer.instanceCount() == 0);
@ -99,6 +97,12 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
stagingBuffer.reclaim();
// Genuinely nothing to do, we can just early out.
// Still process the mesh pool and reclaim fenced staging regions though.
if (cullingGroups.isEmpty()) {
return;
}
lightBuffers.flush(stagingBuffer, lightStorage);
matrixBuffer.flush(stagingBuffer, environmentStorage);
@ -146,33 +150,44 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
group.submitSolid();
}
oitFramebuffer.prepare();
oitFramebuffer.depthRange();
// Let's avoid invoking the oit chain if we don't have anything to do
boolean useOit = false;
for (var group : cullingGroups.values()) {
group.submitTransparent(PipelineCompiler.OitMode.DEPTH_RANGE);
if (group.hasOitDraws()) {
useOit = true;
break;
}
}
oitFramebuffer.renderTransmittance();
if (useOit) {
oitFramebuffer.prepare();
for (var group : cullingGroups.values()) {
group.submitTransparent(PipelineCompiler.OitMode.GENERATE_COEFFICIENTS);
oitFramebuffer.depthRange();
for (var group : cullingGroups.values()) {
group.submitTransparent(PipelineCompiler.OitMode.DEPTH_RANGE);
}
oitFramebuffer.renderTransmittance();
for (var group : cullingGroups.values()) {
group.submitTransparent(PipelineCompiler.OitMode.GENERATE_COEFFICIENTS);
}
oitFramebuffer.renderDepthFromTransmittance();
// Need to bind this again because we just drew a full screen quad for OIT.
vertexArray.bindForDraw();
oitFramebuffer.shade();
for (var group : cullingGroups.values()) {
group.submitTransparent(PipelineCompiler.OitMode.EVALUATE);
}
oitFramebuffer.composite();
}
oitFramebuffer.renderDepthFromTransmittance();
// Need to bind this again because we just drew a full screen quad for OIT.
vertexArray.bindForDraw();
oitFramebuffer.shade();
for (var group : cullingGroups.values()) {
group.submitTransparent(PipelineCompiler.OitMode.EVALUATE);
}
oitFramebuffer.composite();
MaterialRenderState.reset();
TextureBinder.resetLightAndOverlay();
}