mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-10-25 20:22:22 +00:00
initial commit for gl-fences (#2285)
This commit is contained in:
1 parent
69124e3f2f
commit
73d61d385c
16 files changed
+115
-72
No files matched your search
@@ -411,6 +411,7 @@ public class Uniforms {
|
||||
if (ring != null) {
|
||||
ring.endFrame();
|
||||
}
|
||||
invalidateBinding();
|
||||
lastFrameBlockWrites = blockWrites;
|
||||
lastFrameBlockSkips = blockSkips;
|
||||
lastFrameStagedMatrices = stagedMatrices;
|
||||
|
||||
@@ -25,6 +25,7 @@ final class GlStreamingRing {
|
||||
|
||||
private static final long SYNC_WAIT_SLICE_NANOS = 10_000_000L;
|
||||
private static final long SYNC_WAIT_TOTAL_NANOS = 5_000_000_000L;
|
||||
private static long totalFencesIssued;
|
||||
|
||||
private final FenceQueue fences = new FenceQueue();
|
||||
private int writePos;
|
||||
@@ -68,6 +69,9 @@ final class GlStreamingRing {
|
||||
/** Byte offset of a reserved range, or -1 when it can never be served. */
|
||||
long reserve(int bytes, int alignment) {
|
||||
if (bytes > capacity) return -1;
|
||||
if (pendingBytes >= capacity / 4) {
|
||||
fence();
|
||||
}
|
||||
if (remaining < capacity / 2) {
|
||||
reclaim();
|
||||
}
|
||||
@@ -82,9 +86,6 @@ final class GlStreamingRing {
|
||||
writePos = offset + bytes;
|
||||
remaining -= waste + bytes;
|
||||
pendingBytes += waste + bytes;
|
||||
if (pendingBytes >= capacity / 4) {
|
||||
fence();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -104,6 +105,7 @@ final class GlStreamingRing {
|
||||
fences.enqueue(GLStateManager.glFenceSync(GL32.GL_SYNC_GPU_COMMANDS_COMPLETE, 0), pendingBytes);
|
||||
pendingBytes = 0;
|
||||
fencesIssued++;
|
||||
totalFencesIssued++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +156,7 @@ final class GlStreamingRing {
|
||||
int remaining() { return remaining; }
|
||||
int wraps() { return wraps; }
|
||||
int fencesIssued() { return fencesIssued; }
|
||||
static long totalFencesIssued() { return totalFencesIssued; }
|
||||
int forcedReclaims() { return forcedReclaims; }
|
||||
|
||||
void destroy() {
|
||||
|
||||
+3
-1
@@ -45,12 +45,14 @@ public final class PersistentStreamingBuffer {
|
||||
public int getBufferId() { return ring.bufferId(); }
|
||||
public int getCapacity() { return ring.capacity(); }
|
||||
public int getRemaining() { return ring.remaining(); }
|
||||
public int getFencesIssued() { return ring.fencesIssued(); }
|
||||
public int getForcedReclaims() { return ring.forcedReclaims(); }
|
||||
public int getWraps() { return ring.wraps(); }
|
||||
public static long getFencesIssuedByAllRings() { return GlStreamingRing.totalFencesIssued(); }
|
||||
|
||||
ByteBuffer getMappedBuffer() { return ring.mapped(); }
|
||||
|
||||
public void postDraw() {
|
||||
public void endFrame() {
|
||||
ring.endFrame();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -330,7 +330,7 @@ public class TessellatorStreamingDrawer {
|
||||
|
||||
public static void endFrame() {
|
||||
if (persistentBuffer != null) {
|
||||
persistentBuffer.postDraw();
|
||||
persistentBuffer.endFrame();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,24 @@ class FfpUniformBlockDedupTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void unchangedContentStillWritesAfterFrameEnd() {
|
||||
resetState();
|
||||
final Uniforms uniforms = new Uniforms();
|
||||
try {
|
||||
uniforms.upload(GLStateManager.ctx());
|
||||
final int firstOffset = boundRangeStart();
|
||||
uniforms.endFrame();
|
||||
|
||||
uniforms.upload(GLStateManager.ctx());
|
||||
assertEquals(1, uniforms.blockWrites, "the frame-end fence owns the old range, so the next frame must not reuse it");
|
||||
assertNotEquals(firstOffset, boundRangeStart());
|
||||
} finally {
|
||||
uniforms.destroy();
|
||||
resetState();
|
||||
}
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
List<DynamicTest> everyStagingCategoryForcesAWrite() {
|
||||
final List<DynamicTest> tests = new ArrayList<>();
|
||||
|
||||
+25
-7
@@ -122,7 +122,7 @@ class StreamingBufferTest {
|
||||
data1.flip();
|
||||
int v1 = buf.upload(data1, stride);
|
||||
assertTrue(v1 >= 0);
|
||||
buf.postDraw();
|
||||
buf.endFrame();
|
||||
memFree(data1);
|
||||
|
||||
// Wait for GPU to finish so fence is signaled
|
||||
@@ -142,7 +142,7 @@ class StreamingBufferTest {
|
||||
assertEquals((byte) ((i + 100) & 0xFF), mapped.get(offset2 + i), "Mismatch at byte " + i);
|
||||
}
|
||||
|
||||
buf.postDraw();
|
||||
buf.endFrame();
|
||||
memFree(data2);
|
||||
} finally {
|
||||
buf.destroy();
|
||||
@@ -162,14 +162,14 @@ class StreamingBufferTest {
|
||||
|
||||
buf.upload(data, 32);
|
||||
assertEquals(4096 - 1024, buf.getRemaining(), "upload consumes its bytes");
|
||||
buf.postDraw();
|
||||
buf.endFrame();
|
||||
|
||||
data.position(0).limit(512);
|
||||
buf.upload(data, 32);
|
||||
buf.postDraw();
|
||||
buf.endFrame();
|
||||
|
||||
GL11.glFinish();
|
||||
buf.postDraw();
|
||||
buf.endFrame();
|
||||
assertEquals(4096, buf.getRemaining(), "all fenced regions reclaimed after completion");
|
||||
memFree(data);
|
||||
} finally {
|
||||
@@ -204,7 +204,25 @@ class StreamingBufferTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void persistent_exhaustionReclaimsPendingWithoutPostDraw() {
|
||||
void persistent_thresholdFenceExcludesNewestReservation() {
|
||||
Assumptions.assumeTrue(RenderSystem.supportsBufferStorage(), "GL4.4+ required");
|
||||
|
||||
final GlStreamingRing ring = GlStreamingRing.create(GL15.GL_ARRAY_BUFFER, 1024);
|
||||
assertNotNull(ring);
|
||||
try {
|
||||
assertEquals(0, ring.reserve(256, 16));
|
||||
assertEquals(0, ring.fencesIssued(), "the caller has not drawn the reserved bytes yet");
|
||||
assertEquals(256, ring.reserve(16, 16));
|
||||
assertEquals(1, ring.fencesIssued(), "the next reservation fences earlier draws");
|
||||
ring.endFrame();
|
||||
assertEquals(2, ring.fencesIssued(), "the newest reservation still needs a fence after its draw");
|
||||
} finally {
|
||||
ring.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void persistent_exhaustionReclaimsPendingWithoutEndFrame() {
|
||||
Assumptions.assumeTrue(RenderSystem.supportsBufferStorage(), "GL4.4+ required");
|
||||
|
||||
PersistentStreamingBuffer buf = PersistentStreamingBuffer.createOrNull(1024);
|
||||
@@ -218,7 +236,7 @@ class StreamingBufferTest {
|
||||
data.position(0).limit(512);
|
||||
assertTrue(buf.upload(data, 32) >= 0);
|
||||
data.position(0).limit(512);
|
||||
assertTrue(buf.upload(data, 32) >= 0, "ring must self-fence and reclaim without postDraw");
|
||||
assertTrue(buf.upload(data, 32) >= 0, "ring must self-fence and reclaim without endFrame");
|
||||
memFree(data);
|
||||
} finally {
|
||||
buf.destroy();
|
||||
|
||||
@@ -8,7 +8,7 @@ import sys
|
||||
CSVEXPORT = os.environ.get("TRACY_CSVEXPORT", os.path.expanduser("~/dev/mc/tracy/csvexport/build/tracy-csvexport"))
|
||||
|
||||
PLOTS = [
|
||||
"gl.drawCalls", "gl.listPlaybacks", "gl.streamDraws", "entitiesRendered", "blockEntitiesRendered", "tesr.modelParts", "tesr.retainedDraws", "tesr.cacheMisses", "tesr.instancedDraws", "tesr.instancedInstances", "tesr.cubeInstances",
|
||||
"gl.drawCalls", "gl.listPlaybacks", "gl.streamDraws", "gl.allRingFences", "entitiesRendered", "blockEntitiesRendered", "tesr.modelParts", "tesr.retainedDraws", "tesr.cacheMisses", "tesr.instancedDraws", "tesr.instancedInstances", "tesr.cubeInstances",
|
||||
"tesr.streamedInstances", "tesr.texMatrixRuns", "tesr.liveFallbacks", "tesr.bail.foreignProgram",
|
||||
"tesr.bail.material", "tesr.bail.texture", "entity.shadowQuads", "entity.shadowDraws", "items.instanced", "items.fallback", "items.glintInstanced",
|
||||
"items.bail.ineligible", "items.bail.material", "items.bail.isbrh", "items.bail.blockState", "items.bail.notAllowed", "items.bail.template", "items.bail.queue",
|
||||
@@ -16,7 +16,7 @@ PLOTS = [
|
||||
"sdl.acquireWaitUs",
|
||||
"weather.strength", "weather.quads", "weather.drawCalls", "weather.micros",
|
||||
]
|
||||
ZONES = ["entityModelParts", "tesrBatch", "tesrInstanced", "entityLayerLoop", "tesrOpaque", "particlePass", "cl:weather"]
|
||||
ZONES = ["entityModelParts", "tesrBatch", "entityLayerLoop", "entityDeferred", "tesrOpaque", "particlePass", "cl:weather", "streamingEndFrame"]
|
||||
CLOCK = "gl.drawCalls"
|
||||
|
||||
|
||||
|
||||
@@ -323,7 +323,7 @@ public class BatchingFontRenderer {
|
||||
|
||||
public static void endFrame() {
|
||||
if (streamRing != null) {
|
||||
streamRing.postDraw();
|
||||
streamRing.endFrame();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.TracyBackend;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.PersistentStreamingBuffer;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.TessellatorStreamingDrawer;
|
||||
import com.gtnewhorizons.angelica.rendering.AngelicaRenderQueue;
|
||||
import com.gtnewhorizons.angelica.rendering.FramePacer;
|
||||
@@ -45,6 +46,7 @@ public final class TracyFramePlots {
|
||||
private static final PlotDelta P_GL_ORPHAN_FALLBACKS = new PlotDelta("gl.orphanFallbacks");
|
||||
private static final PlotDelta P_GL_STREAM_CONTIGUOUS = new PlotDelta("gl.streamContiguous");
|
||||
private static final PlotDelta P_GL_RING_WRAPS = new PlotDelta("gl.ringWraps");
|
||||
private static final PlotDelta P_GL_ALL_RING_FENCES = new PlotDelta("gl.allRingFences");
|
||||
private static final long P_GL_SECTION_META_BYTES = Tracy.plotHandle("gl.sectionMetaBytes", TracyBackend.PLOT_FORMAT_MEMORY);
|
||||
|
||||
private static final long P_SHADOW_RELAY_FRAMES = Tracy.plotHandle("shadow.relayFrames");
|
||||
@@ -200,6 +202,7 @@ public final class TracyFramePlots {
|
||||
P_GL_ORPHAN_FALLBACKS.plot(TessellatorStreamingDrawer.orphanFallbacks);
|
||||
P_GL_STREAM_CONTIGUOUS.plot(TessellatorStreamingDrawer.streamContiguous);
|
||||
P_GL_RING_WRAPS.plot(TessellatorStreamingDrawer.ringWraps());
|
||||
P_GL_ALL_RING_FENCES.plot(PersistentStreamingBuffer.getFencesIssuedByAllRings());
|
||||
Tracy.plotInt(P_GL_SECTION_META_BYTES, TerrainDrawStats.takeSectionMetaBytes());
|
||||
Tracy.plotInt(P_SHADOW_RELAY_FRAMES, ShadowRenderer.SHADOW_TERRAIN_RELAID ? 1 : 0);
|
||||
Tracy.plotInt(P_TERRAIN_DRAW_COMMANDS, TerrainDrawStats.takeCommandsSubmitted());
|
||||
|
||||
@@ -60,7 +60,6 @@ public final class ParticleInstancer {
|
||||
private static DeferredWorldRenderingPipeline unavailableFor;
|
||||
private static DeferredWorldRenderingPipeline deferred;
|
||||
private static Tessellator run;
|
||||
private static boolean ringUsedThisLayer;
|
||||
|
||||
private static float rotX;
|
||||
private static float rotXZ;
|
||||
@@ -180,7 +179,6 @@ public final class ParticleInstancer {
|
||||
}
|
||||
layerActive = false;
|
||||
Throwable failure = null;
|
||||
ringUsedThisLayer = false;
|
||||
try {
|
||||
if (groupCount > 0) {
|
||||
restoreDepth = GLStateManager.pushState(StateSet.BATCH);
|
||||
@@ -212,13 +210,6 @@ public final class ParticleInstancer {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ringUsedThisLayer) {
|
||||
try {
|
||||
ring().postDraw();
|
||||
} catch (Throwable t) {
|
||||
failure = RenderFailures.suppress(failure, t);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < groupCount; i++) {
|
||||
final ByteBuffer list = GROUP_POOL.get(i).list;
|
||||
if (list != null) list.clear();
|
||||
@@ -227,7 +218,6 @@ public final class ParticleInstancer {
|
||||
deferred = null;
|
||||
run = null;
|
||||
layerStarted = false;
|
||||
ringUsedThisLayer = false;
|
||||
}
|
||||
RenderFailures.rethrowWrapped(failure);
|
||||
}
|
||||
@@ -253,7 +243,6 @@ public final class ParticleInstancer {
|
||||
run = null;
|
||||
unavailableFor = null;
|
||||
groupCount = 0;
|
||||
ringUsedThisLayer = false;
|
||||
for (int i = 0; i < GROUP_POOL.size(); i++) {
|
||||
GROUP_POOL.get(i).list = null;
|
||||
}
|
||||
@@ -297,7 +286,6 @@ public final class ParticleInstancer {
|
||||
}
|
||||
}
|
||||
|
||||
ringUsedThisLayer = true;
|
||||
final long base = ring().upload(list, STRIDE);
|
||||
list.clear();
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ public final class InstanceRing {
|
||||
private PersistentStreamingBuffer persistentRing;
|
||||
private OrphanStreamingBuffer orphanRing;
|
||||
private boolean initialized;
|
||||
private boolean usedThisFrame;
|
||||
private boolean lastUploadKept;
|
||||
private int bufferId;
|
||||
|
||||
@@ -19,7 +18,6 @@ public final class InstanceRing {
|
||||
initialized = true;
|
||||
persistentRing = PersistentStreamingBuffer.createOrNull(PersistentStreamingBuffer.DEFAULT_CAPACITY);
|
||||
}
|
||||
usedThisFrame = true;
|
||||
if (persistentRing != null) {
|
||||
final int index = persistentRing.upload(data, stride);
|
||||
if (index >= 0) {
|
||||
@@ -36,18 +34,19 @@ public final class InstanceRing {
|
||||
}
|
||||
|
||||
public int keptUploadsEpoch() {
|
||||
return lastUploadKept && persistentRing != null ? persistentRing.getWraps() : -1;
|
||||
if (!lastUploadKept || persistentRing == null) return -1;
|
||||
// Once a fence covers an upload, the ring may reuse that range while a later redraw still reads it.
|
||||
return persistentRing.getFencesIssued() & Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public int bufferId() {
|
||||
return bufferId;
|
||||
}
|
||||
|
||||
public void postDraw() {
|
||||
if (usedThisFrame && persistentRing != null) {
|
||||
persistentRing.postDraw();
|
||||
public void endFrame() {
|
||||
if (persistentRing != null) {
|
||||
persistentRing.endFrame();
|
||||
}
|
||||
usedThisFrame = false;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
@@ -60,7 +59,6 @@ public final class InstanceRing {
|
||||
orphanRing = null;
|
||||
}
|
||||
initialized = false;
|
||||
usedThisFrame = false;
|
||||
lastUploadKept = false;
|
||||
bufferId = 0;
|
||||
}
|
||||
|
||||
@@ -311,10 +311,6 @@ final class InstancedTemplateRenderer {
|
||||
return extVbo;
|
||||
}
|
||||
|
||||
void endFrame() {
|
||||
ring.postDraw();
|
||||
}
|
||||
|
||||
void retire(TemplateBuffer template) {
|
||||
retired.add(template);
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ public final class ModelPartBatcher {
|
||||
private static final long SWEEP_INTERVAL_MS = 5_000L;
|
||||
|
||||
private static final Tracy.ZoneId Z_ENTITY_LAYER_LOOP = Tracy.zoneId("entityLayerLoop", Tracy.COLOR_CLIENT);
|
||||
private static final Tracy.ZoneId Z_ENTITY_DEFERRED = Tracy.zoneId("entityDeferred", Tracy.COLOR_CLIENT);
|
||||
|
||||
private final AngelicaBufferSource bufferSource = new AngelicaBufferSource();
|
||||
private final AngelicaBufferSource entitySource = new AngelicaBufferSource();
|
||||
@@ -309,9 +310,6 @@ public final class ModelPartBatcher {
|
||||
if (wrapEntities) GbufferPrograms.endEntities();
|
||||
}
|
||||
}
|
||||
if (instancedThisCycle && !hold) {
|
||||
TesrBatchRenderer.INSTANCE.instancedRenderer.endFrame();
|
||||
}
|
||||
if (!TesrBatchRenderer.INSTANCE.hasPendingGeometry()) {
|
||||
BatchingFontRenderer.flushDeferredText();
|
||||
}
|
||||
@@ -337,6 +335,7 @@ public final class ModelPartBatcher {
|
||||
if (!entityTranslucentsHeld) return;
|
||||
entityTranslucentsHeld = false;
|
||||
BatchStateGuard.suspend();
|
||||
if (Tracy.ENABLED) Tracy.beginZone(Z_ENTITY_DEFERRED);
|
||||
try {
|
||||
final EntityRenderer entityRenderer = Minecraft.getMinecraft().entityRenderer;
|
||||
final int deferredDepth = GLStateManager.pushState(StateSet.BATCH);
|
||||
@@ -352,9 +351,6 @@ public final class ModelPartBatcher {
|
||||
if (wrap) GbufferPrograms.beginEntities();
|
||||
try {
|
||||
entitySource.endBatch(entityGroups);
|
||||
if (instancedThisCycle) {
|
||||
TesrBatchRenderer.INSTANCE.instancedRenderer.endFrame();
|
||||
}
|
||||
recycleAtlas();
|
||||
AngelicaBufferSource.rebindPass();
|
||||
} finally {
|
||||
|
||||
@@ -59,7 +59,6 @@ public final class TesrBatchRenderer {
|
||||
|
||||
private static final Tracy.ZoneId Z_TESR_OPAQUE = Tracy.zoneId("tesrOpaque", Tracy.COLOR_CLIENT);
|
||||
private static final Tracy.ZoneId Z_TESR_BATCH = Tracy.zoneId("tesrBatch", Tracy.COLOR_CLIENT);
|
||||
private static final Tracy.ZoneId Z_TESR_INSTANCED = Tracy.zoneId("tesrInstanced", Tracy.COLOR_CLIENT);
|
||||
private static final Tracy.ZoneId Z_TESR_TEXT = Tracy.zoneId("tesrText", Tracy.COLOR_CLIENT);
|
||||
private static final Tracy.ZoneId Z_TESR_DEFERRED = Tracy.zoneId("tesrDeferred", Tracy.COLOR_CLIENT);
|
||||
|
||||
@@ -388,7 +387,6 @@ public final class TesrBatchRenderer {
|
||||
deferredFlushPending = false;
|
||||
pendingDeferredHook = null;
|
||||
bufferSource.endBatch(hook);
|
||||
instancedRenderer.endFrame();
|
||||
BatchingFontRenderer.flushDeferredText();
|
||||
}
|
||||
|
||||
@@ -413,12 +411,6 @@ public final class TesrBatchRenderer {
|
||||
} finally {
|
||||
if (Tracy.ENABLED) Tracy.endZone();
|
||||
}
|
||||
if (Tracy.ENABLED) Tracy.beginZone(Z_TESR_INSTANCED);
|
||||
try {
|
||||
instancedRenderer.endFrame();
|
||||
} finally {
|
||||
if (Tracy.ENABLED) Tracy.endZone();
|
||||
}
|
||||
if (Tracy.ENABLED) Tracy.beginZone(Z_TESR_TEXT);
|
||||
try {
|
||||
BatchingFontRenderer.flushDeferredText();
|
||||
@@ -462,7 +454,6 @@ public final class TesrBatchRenderer {
|
||||
}
|
||||
try {
|
||||
bufferSource.endBatch(hook);
|
||||
instancedRenderer.endFrame();
|
||||
AngelicaBufferSource.rebindPass();
|
||||
BatchingFontRenderer.flushDeferredText();
|
||||
} finally {
|
||||
|
||||
+13
-3
@@ -3,11 +3,13 @@ package com.gtnewhorizons.angelica.mixins.early.angelica;
|
||||
import com.gtnewhorizons.angelica.AngelicaMod;
|
||||
import com.gtnewhorizons.angelica.client.font.BatchingFontRenderer;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.TessellatorStreamingDrawer;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.IGameSettingsExt;
|
||||
import com.gtnewhorizons.angelica.proxy.ClientProxy;
|
||||
import com.gtnewhorizons.angelica.rendering.FpsReducer;
|
||||
import com.gtnewhorizons.angelica.rendering.FramePacer;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TesrBatchRenderer;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -44,6 +46,8 @@ public abstract class MixinMinecraft {
|
||||
@Unique
|
||||
private static boolean angelica$hadWorld;
|
||||
|
||||
@Unique private static final Tracy.ZoneId angelica$Z_STREAMING_END_FRAME = Tracy.zoneId("streamingEndFrame", Tracy.COLOR_CLIENT);
|
||||
|
||||
@Inject(
|
||||
method = "runGameLoop",
|
||||
at = @At(value = "INVOKE", target = "Lcpw/mods/fml/common/FMLCommonHandler;onRenderTickEnd(F)V", shift = At.Shift.AFTER, remap = false)
|
||||
@@ -111,9 +115,15 @@ public abstract class MixinMinecraft {
|
||||
|
||||
@Inject(method = "runGameLoop", at = @At("RETURN"))
|
||||
private void angelica$streamingBufferEndFrame(CallbackInfo ci) {
|
||||
TessellatorStreamingDrawer.endFrame();
|
||||
BatchingFontRenderer.endFrame();
|
||||
ShaderManager.endFrame();
|
||||
if (Tracy.ENABLED) Tracy.beginZone(angelica$Z_STREAMING_END_FRAME);
|
||||
try {
|
||||
TessellatorStreamingDrawer.endFrame();
|
||||
BatchingFontRenderer.endFrame();
|
||||
TesrBatchRenderer.INSTANCE.instanceRing().endFrame();
|
||||
ShaderManager.endFrame();
|
||||
} finally {
|
||||
if (Tracy.ENABLED) Tracy.endZone();
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyExpressionValue(
|
||||
|
||||
+34
-15
@@ -8,6 +8,7 @@ import com.gtnewhorizons.angelica.api.tesr.TesrShader;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.RenderLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.GLCoreTest;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.StateSet;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.CubeParams;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.CubeParityFixture;
|
||||
@@ -16,6 +17,7 @@ import com.gtnewhorizons.angelica.glsm.ffp.Instancing;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.BatchStateGuard;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.PersistentStreamingBuffer;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import com.gtnewhorizons.angelica.rendering.GlintClock;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.RetainedTesrGroups.Group;
|
||||
@@ -33,6 +35,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Matrix4fc;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -196,7 +199,6 @@ class RetainedTesrGroupsGLTest {
|
||||
final InstanceColumns cols = new InstanceColumns();
|
||||
cols.add(template, mv, 0, colorABGR, 0, 0L);
|
||||
renderer.drawTemplates(cols, run(1, 1), System.currentTimeMillis());
|
||||
renderer.endFrame();
|
||||
}
|
||||
|
||||
private void queueThreeEntities(CountingPipeline pipeline) {
|
||||
@@ -219,7 +221,7 @@ class RetainedTesrGroupsGLTest {
|
||||
groups.queue(SCOPE, template, layer, material, mv.set(base).mul(model), 0, -1, 0, 0L, 5, null);
|
||||
}
|
||||
groups.drawLayer(layer);
|
||||
instanced.endFrame();
|
||||
ring.endFrame();
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
|
||||
}
|
||||
|
||||
@@ -316,7 +318,7 @@ class RetainedTesrGroupsGLTest {
|
||||
groups.queue(SCOPE, templates[i], layer, BAKED_ADDITIVE, new Matrix4f().translation(frame * 0.01f, i * 0.05f, 0f), 0, -1, 0, 0L, 5, null);
|
||||
}
|
||||
groups.drawLayer(layer);
|
||||
instanced.endFrame();
|
||||
ring.endFrame();
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
|
||||
}
|
||||
assertEquals(count <= RetainedTesrGroups.PROMOTE_MAX_TEMPLATES ? 1 : 0, groups.streamPromotions);
|
||||
@@ -364,7 +366,7 @@ class RetainedTesrGroupsGLTest {
|
||||
if (pair.get(0).streamPath) sawPromoted = true;
|
||||
else if (sawPromoted) sawDemotedAgain = true;
|
||||
groups.drawLayer(layer);
|
||||
instanced.endFrame();
|
||||
ring.endFrame();
|
||||
}
|
||||
assertTrue(sawPromoted, "the animating overlay must pull its static depth writer onto the instanced path");
|
||||
assertTrue(sawDemotedAgain, "once the overlay settles the pair must return to baked together");
|
||||
@@ -706,6 +708,34 @@ class RetainedTesrGroupsGLTest {
|
||||
return new int[][] { basePixels, glintPixels };
|
||||
}
|
||||
|
||||
@Test
|
||||
void glintReuseStopsWhenAnUploadIsFenced() {
|
||||
Assumptions.assumeTrue(RenderSystem.supportsBufferStorage(), "Persistent mapping required");
|
||||
final PersistentStreamingBuffer persistent = PersistentStreamingBuffer.createOrNull(1024);
|
||||
assertNotNull(persistent);
|
||||
Reflect.set(ring, "persistentRing", persistent);
|
||||
Reflect.set(ring, "initialized", true);
|
||||
final ByteBuffer data = BufferUtils.createByteBuffer(256);
|
||||
data.limit(16);
|
||||
assertEquals(0, ring.upload(data, 16));
|
||||
final int baseEpoch = instanced.ringEpoch();
|
||||
final int baseBuffer = instanced.ringBuffer();
|
||||
assertTrue(instanced.canRedraw(baseEpoch, baseBuffer));
|
||||
|
||||
data.limit(240);
|
||||
assertEquals(16, ring.upload(data, 16));
|
||||
assertTrue(instanced.canRedraw(baseEpoch, baseBuffer), "later uploads can share an unfenced range");
|
||||
|
||||
final int fences = persistent.getFencesIssued();
|
||||
data.limit(16);
|
||||
assertEquals(256, ring.upload(data, 16));
|
||||
assertEquals(fences + 1, persistent.getFencesIssued());
|
||||
assertEquals(0, persistent.getWraps(), "the ring has not overwritten the earlier upload");
|
||||
assertEquals(baseBuffer, instanced.ringBuffer());
|
||||
assertFalse(instanced.canRedraw(baseEpoch, baseBuffer), "a new draw must not outlive its range's earlier fence");
|
||||
assertTrue(instanced.canRedraw(instanced.ringEpoch(), baseBuffer), "the newest upload is still unfenced");
|
||||
}
|
||||
|
||||
private void glintState() {
|
||||
GLStateManager.glViewport(0, 0, SIZE, SIZE);
|
||||
layer = RenderLayer.tesr(GLINT_TEXTURE, TesrMaterial.CURRENT_STATE, PassOverride.NONE, 0f, 0f, ShaderGlint.NO_TINT, DrawState.DISABLED, false, true);
|
||||
@@ -789,7 +819,6 @@ class RetainedTesrGroupsGLTest {
|
||||
cols.add(glintTemplate, templateE1, 0, 0xFFFFFFFF, 0, 0L);
|
||||
cols.add(glintTemplate, templateE2, 0, 0xFFFFFFFF, 0, 0L);
|
||||
instanced.drawTemplates(cols, run(2, 2), System.currentTimeMillis());
|
||||
instanced.endFrame();
|
||||
return FfpFixture.readRegion(SIZE);
|
||||
}
|
||||
|
||||
@@ -800,7 +829,6 @@ class RetainedTesrGroupsGLTest {
|
||||
cols.addCubes(null, glintCubes, CUBE_SCALE, cubeE1, 0, 0xFFFFFFFF, 0, 0L, null);
|
||||
cols.addCubes(null, glintCubes, CUBE_SCALE, cubeE2, 0, 0xFFFFFFFF, 0, 0L, null);
|
||||
instanced.drawCubes(cols, run(2, 2 * glintCubes.length));
|
||||
instanced.endFrame();
|
||||
return FfpFixture.readRegion(SIZE);
|
||||
}
|
||||
|
||||
@@ -808,7 +836,6 @@ class RetainedTesrGroupsGLTest {
|
||||
final InstanceColumns cols = new InstanceColumns();
|
||||
cols.addCubes(null, glintCubes, CUBE_SCALE, mv, 0, 0xFFFFFFFF, 0, 0L, null);
|
||||
instanced.drawCubes(cols, run(1, glintCubes.length));
|
||||
instanced.endFrame();
|
||||
}
|
||||
|
||||
private int[] templateReference(boolean swapFirstEmitter) {
|
||||
@@ -837,7 +864,6 @@ class RetainedTesrGroupsGLTest {
|
||||
groups.queue(SCOPE, glintTemplate, layer, EntityMaterials.GLINT, templateE2, 0, -1, 0, 0L, 2, glintMatrixA);
|
||||
groups.queue(SCOPE, glintTemplate, layer, EntityMaterials.GLINT, templateE2, 0, -1, 0, 0L, 2, glintMatrixB);
|
||||
groups.drawLayer(layer);
|
||||
instanced.endFrame();
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "the merged candidate draw must not raise a GL error");
|
||||
return FfpFixture.readRegion(SIZE);
|
||||
}
|
||||
@@ -868,7 +894,6 @@ class RetainedTesrGroupsGLTest {
|
||||
groups.queue(SCOPE, null, glintCubes, CUBE_SCALE, layer, EntityMaterials.GLINT, cubeE2, 0, -1, 0, 0L, 2, glintMatrixA, null);
|
||||
groups.queue(SCOPE, null, glintCubes, CUBE_SCALE, layer, EntityMaterials.GLINT, cubeE2, 0, -1, 0, 0L, 2, glintMatrixB, null);
|
||||
groups.drawLayer(layer);
|
||||
instanced.endFrame();
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "the merged candidate draw must not raise a GL error");
|
||||
return FfpFixture.readRegion(SIZE);
|
||||
}
|
||||
@@ -926,7 +951,6 @@ class RetainedTesrGroupsGLTest {
|
||||
if (!cubes) assertFalse(capture.replay(groups), "a captured pass is replayed only once");
|
||||
}
|
||||
groups.drawLayer(layer);
|
||||
instanced.endFrame();
|
||||
CubeParityFixture.assertPixelParity(reference, FfpFixture.readRegion(SIZE), SIZE, BACKGROUND, RetainedTesrGroupsGLTest::describe);
|
||||
}
|
||||
|
||||
@@ -965,7 +989,6 @@ class RetainedTesrGroupsGLTest {
|
||||
glint.end();
|
||||
assertTrue(glint.replay(groups, glintMatrixB), "the second layer can be queued without rerunning legacy texture setup");
|
||||
groups.drawLayer(Reflect.get(batcher, "lastLayer"));
|
||||
instanced.endFrame();
|
||||
final int[] actual = FfpFixture.readRegion(SIZE);
|
||||
int error = 0;
|
||||
for (int p = 0; p < actual.length; p++) for (int shift = 0; shift < 24; shift += 8) {
|
||||
@@ -1011,7 +1034,6 @@ class RetainedTesrGroupsGLTest {
|
||||
GLStateManager.glCullFace(GL11.GL_BACK);
|
||||
|
||||
source.endBatch(groups);
|
||||
instanced.endFrame();
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "the batched draw must not raise a GL error");
|
||||
|
||||
CubeParityFixture.assertPixelParity(reference, FfpFixture.readRegion(SIZE), SIZE, BACKGROUND, RetainedTesrGroupsGLTest::describe);
|
||||
@@ -1058,7 +1080,6 @@ class RetainedTesrGroupsGLTest {
|
||||
groups.queue(SCOPE, quad, opposingLayer, RetainedTesrTestSupport.STREAM, new Matrix4f(), 0, COLOR_ABGR, 0, 0L, 1, null);
|
||||
|
||||
source.endBatch(groups);
|
||||
instanced.endFrame();
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "the flush must not raise a GL error");
|
||||
|
||||
assertEquals(cullEnabledBefore, GLStateManager.getCullState().isEnabled(), "cache cull enable must be restored");
|
||||
@@ -1104,7 +1125,6 @@ class RetainedTesrGroupsGLTest {
|
||||
shaderLayer.startDrawing();
|
||||
groups.drawLayer(shaderLayer);
|
||||
shaderLayer.endDrawing();
|
||||
instanced.endFrame();
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "shader draw must not raise a GL error");
|
||||
final int[][] pixels = new int[SHADER_PROBES.length][];
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
@@ -1188,7 +1208,6 @@ class RetainedTesrGroupsGLTest {
|
||||
assertEquals(GL11.GL_EQUAL, GL11.glGetInteger(GL11.GL_DEPTH_FUNC));
|
||||
groups.drawLayer(overlayLayer);
|
||||
overlayLayer.endDrawing();
|
||||
instanced.endFrame();
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "depth-equal pair must not raise a GL error");
|
||||
assertEquals(instancing ? 2 : 0, groups.instancedDraws - instancedBefore, path + ": base and overlay must share the path");
|
||||
|
||||
|
||||
Reference in new issue
Block a user