initial commit for gl-fences (#2285)

This commit is contained in:
Eclipse-Sol authored and GitHub committed 2026-10-21 20:12:01 -07:00
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() {
@@ -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();
}
@@ -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<>();
@@ -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();
+2 -2
View File
@@ -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 {
@@ -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(
@@ -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");