Cut redundant GLSM state tracking (#2189)

This commit is contained in:
Jason Mitchell authored and GitHub committed 2026-10-02 20:11:37 -07:00
1 parent 80e5b544c0
commit 12fa08ab46
11 files changed
+281 -82

No files matched your search

@@ -107,6 +107,14 @@ public class GLContextState {
public int maxBoundImageUnit = 0;
public final StateSet[] attribSets = new StateSet[GLStateManager.MAX_ATTRIB_STACK_DEPTH];
public int attribDepth = 0;
public boolean savesState(int id) {
for (int i = attribDepth - 1; i >= 0; i--) {
if (attribSets[i].contains(id)) return true;
}
return false;
}
public int batchStateGeneration;
public final int[] savedBatchStateGen = new int[GLStateManager.MAX_ATTRIB_STACK_DEPTH];
public CowStateStack<?>[] stackById;
@@ -170,8 +170,7 @@ public class GLStateManager {
beforeUncapturedStateChange();
}
private static void beforeMatrixChange() {
final GLContextState c = ctx();
private static void beforeMatrixChange(GLContextState c) {
if (c.matrixMode.getMode() == GL11.GL_PROJECTION
|| (c.matrixMode.getMode() == GL11.GL_TEXTURE && c.activeTextureUnit.getValue() != 0)) {
beforeUncapturedStateChange();
@@ -188,12 +187,17 @@ public class GLStateManager {
private static volatile GLContextState primaryContext;
private static final ThreadLocal<GLContextState> tlWorkerContext = new ThreadLocal<>();
private static GLContextState mainCtx;
private static volatile boolean workerContextsActive;
private static int workerContextCount;
private static final IdentityHashMap<Object, GLContextState> drawableContexts = new IdentityHashMap<>();
private static GLContextState[] drawableContextStates = new GLContextState[0];
public static GLContextState ctx() {
if (Thread.currentThread() == MainThread) {
final GLContextState c = mainCtx;
return c != null ? c : (mainCtx = primaryContext());
}
if (!workerContextsActive) return primaryContext();
final GLContextState st = tlWorkerContext.get();
return st != null ? st : primaryContext();
@@ -235,6 +239,7 @@ public class GLStateManager {
workerContextsActive = workerContextCount != 0;
}
if (target == null) tlWorkerContext.remove(); else tlWorkerContext.set(target);
if (Thread.currentThread() == MainThread) mainCtx = target;
return true;
}
@@ -1415,10 +1420,10 @@ public class GLStateManager {
return;
}
}
mod(glCtx.blendState);
final boolean caching = isCachingEnabled();
final boolean bypass = !caching;
if (bypass || red != glCtx.blendState.getBlendColorR() || green != glCtx.blendState.getBlendColorG() || blue != glCtx.blendState.getBlendColorB() || alpha != glCtx.blendState.getBlendColorA()) {
mod(glCtx.blendState);
beforeUncapturedStateChange();
glCtx.blendState.setBlendColorR(red);
glCtx.blendState.setBlendColorG(green);
@@ -1608,16 +1613,17 @@ public class GLStateManager {
return;
}
}
mod(glCtx.blendState);
final boolean snapshotted = snapshotVanillaBlendFunc();
final DeferredBlendHandler bh = GLSMHooks.blendHandler;
if (bh != null && bh.isBlendLocked()) {
mod(glCtx.blendState);
bh.deferBlendFunc(srcFactor, dstFactor, srcFactor, dstFactor);
postVanillaBlendChangeIfMoved(snapshotted);
return;
}
final boolean caching = isCachingEnabled();
if (GLSMConfig.hudCacheOverride) {
mod(glCtx.blendState);
glCtx.blendState.setAll(srcFactor, dstFactor, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
glCtx.blendState.clearFuncUnknownState();
RENDER_BACKEND.blendFuncSeparate(srcFactor, dstFactor, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
@@ -1638,6 +1644,7 @@ public class GLStateManager {
|| glCtx.blendState.getSrcAlpha() != srcFactor
|| glCtx.blendState.getDstAlpha() != dstFactor
|| glCtx.blendState.isFuncUnknown()) {
mod(glCtx.blendState);
glCtx.blendState.setAll(srcFactor, dstFactor, srcFactor, dstFactor);
glCtx.blendState.clearFuncUnknownState();
RENDER_BACKEND.blendFunc(srcFactor, dstFactor);
@@ -1657,10 +1664,10 @@ public class GLStateManager {
if (DisplayListManager.isRecording()) {
throw DisplayListManager.unsupportedInList("glBlendEquation");
}
mod(glCtx.blendState);
final boolean caching = isCachingEnabled();
final boolean bypass = !caching;
if (bypass || glCtx.blendState.getEquationRgb() != mode || glCtx.blendState.getEquationAlpha() != mode) {
mod(glCtx.blendState);
beforeUncapturedStateChange();
glCtx.blendState.setEquationRgb(mode);
glCtx.blendState.setEquationAlpha(mode);
@@ -1673,10 +1680,10 @@ public class GLStateManager {
if (DisplayListManager.isRecording()) {
throw DisplayListManager.unsupportedInList("glBlendEquationSeparate");
}
mod(glCtx.blendState);
final boolean caching = isCachingEnabled();
final boolean bypass = !caching;
if (bypass || glCtx.blendState.getEquationRgb() != modeRGB || glCtx.blendState.getEquationAlpha() != modeAlpha) {
mod(glCtx.blendState);
beforeUncapturedStateChange();
glCtx.blendState.setEquationRgb(modeRGB);
glCtx.blendState.setEquationAlpha(modeAlpha);
@@ -1693,10 +1700,10 @@ public class GLStateManager {
return;
}
}
mod(glCtx.blendState);
final boolean snapshotted = snapshotVanillaBlendFunc();
final DeferredBlendHandler bh = GLSMHooks.blendHandler;
if (bh != null && bh.isBlendLocked()) {
mod(glCtx.blendState);
bh.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha);
postVanillaBlendChangeIfMoved(snapshotted);
return;
@@ -1708,6 +1715,7 @@ public class GLStateManager {
final boolean caching = isCachingEnabled();
final boolean bypass = !caching;
if (bypass || glCtx.blendState.getSrcRgb() != srcRgb || glCtx.blendState.getDstRgb() != dstRgb || glCtx.blendState.getSrcAlpha() != srcAlpha || glCtx.blendState.getDstAlpha() != dstAlpha || glCtx.blendState.isFuncUnknown()) {
mod(glCtx.blendState);
glCtx.blendState.setAll(srcRgb, dstRgb, srcAlpha, dstAlpha);
glCtx.blendState.clearFuncUnknownState();
RENDER_BACKEND.blendFuncSeparate(srcRgb, dstRgb, srcAlpha, dstAlpha);
@@ -1791,9 +1799,9 @@ public class GLStateManager {
return;
}
}
mod(glCtx.depthState);
final boolean caching = isCachingEnabled();
if (!caching || func != glCtx.depthState.getFunc()) {
mod(glCtx.depthState);
glCtx.depthState.setFunc(func);
RENDER_BACKEND.depthFunc(func);
}
@@ -1808,14 +1816,15 @@ public class GLStateManager {
return;
}
}
mod(glCtx.depthState);
final DeferredDepthColorHandler dch = GLSMHooks.depthColorHandler;
if (dch != null && dch.isDepthColorLocked()) {
mod(glCtx.depthState);
dch.deferDepthEnable(mask);
return;
}
final boolean caching = isCachingEnabled();
if (!caching || mask != glCtx.depthState.isEnabled()) {
mod(glCtx.depthState);
glCtx.depthState.setEnabled(mask);
RENDER_BACKEND.depthMask(mask);
}
@@ -2000,15 +2009,16 @@ public class GLStateManager {
return;
}
}
mod(glCtx.colorMask);
final DeferredDepthColorHandler dch = GLSMHooks.depthColorHandler;
if (dch != null && dch.isDepthColorLocked()) {
mod(glCtx.colorMask);
dch.deferColorMask(red, green, blue, alpha);
return;
}
final boolean caching = isCachingEnabled();
final boolean bypass = !caching;
if (bypass || red != glCtx.colorMask.red || green != glCtx.colorMask.green || blue != glCtx.colorMask.blue || alpha != glCtx.colorMask.alpha) {
mod(glCtx.colorMask);
glCtx.colorMask.setAll(red, green, blue, alpha);
RENDER_BACKEND.colorMask(red, green, blue, alpha);
}
@@ -2120,9 +2130,9 @@ public class GLStateManager {
return;
}
}
mod(glCtx.alphaState);
final DeferredAlphaHandler ah = GLSMHooks.alphaHandler;
if (ah != null && ah.isAlphaTestLocked()) {
mod(glCtx.alphaState);
if (ah.deferAlphaFunc(function, reference) && GLSMHooks.ALPHA_STATE_CHANGE.hasListeners()) {
GLSMHooks.ALPHA_STATE_CHANGE.post(GLSMHooks.alphaStateChangeEvent);
}
@@ -2130,6 +2140,7 @@ public class GLStateManager {
}
if (isCachingEnabled()
&& (function != glCtx.alphaState.getFunction() || Float.compare(reference, glCtx.alphaState.getReference()) != 0)) {
mod(glCtx.alphaState);
glCtx.alphaState.setFunction(function);
glCtx.alphaState.setReference(reference);
glCtx.fragmentGeneration++;
@@ -4083,8 +4094,11 @@ public class GLStateManager {
if (glCtx.attribDepth > 0 && glCtx.savedBatchStateGen[glCtx.attribDepth - 1] != glCtx.batchStateGeneration) {
beforeUncapturedStateChange();
}
final StateSet set = glCtx.attribSets[glCtx.attribDepth - 1];
final boolean inspectAlpha = GLSMHooks.ALPHA_STATE_CHANGE.hasListeners() && (set.contains(glCtx.alphaState.stackId()) || set.contains(glCtx.alphaTest.stackId()));
final int poppedDepth = glCtx.attribDepth;
final StateSet set = glCtx.attribSets[poppedDepth - 1];
final boolean inspectAlpha = GLSMHooks.ALPHA_STATE_CHANGE.hasListeners()
&& ((glCtx.alphaState.cowDepths().claimedAt(poppedDepth) && set.contains(glCtx.alphaState.stackId()))
|| (glCtx.alphaTest.cowDepths().claimedAt(poppedDepth) && set.contains(glCtx.alphaTest.stackId())));
final AlphaState effectiveAlpha = inspectAlpha ? glCtx.alphaState.readEffective(glCtx.restoredAlphaScratch) : null;
final boolean effectiveEnabled = inspectAlpha && glCtx.alphaTest.isEffectivelyEnabled();
final int effectiveFunction = inspectAlpha ? effectiveAlpha.getFunction() : 0;
@@ -4098,8 +4112,9 @@ public class GLStateManager {
glCtx.attribDepth--;
final int restore = set.restore;
final boolean blendSnapshotted = set.blendSnapshot && snapshotVanillaBlendFunc();
final int poppedDepth = glCtx.attribDepth + 1;
final boolean blendSnapshotted = set.blendSnapshot
&& (glCtx.blendState.cowDepths().claimedAt(poppedDepth) || glCtx.blendMode.cowDepths().claimedAt(poppedDepth))
&& snapshotVanillaBlendFunc();
int changed = 0;
long unitsChanged = 0L;
@@ -4474,7 +4489,8 @@ public class GLStateManager {
}
public static void glLoadMatrix(FloatBuffer m) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
final RecordMode mode = DisplayListManager.getRecordMode();
if (mode != RecordMode.NONE) {
final Matrix4f matrix = new Matrix4f().set(m);
@@ -4485,14 +4501,14 @@ public class GLStateManager {
}
}
if (isCachingEnabled()) {
getMatrixStack().set(m);
bumpMatrixGeneration();
matrixStack(glCtx).set(m);
bumpMatrixGeneration(glCtx);
}
}
public static void glLoadMatrix(DoubleBuffer m) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
final RecordMode mode = DisplayListManager.getRecordMode();
if (mode != RecordMode.NONE) {
// Convert double buffer to float buffer for recording
@@ -4507,8 +4523,8 @@ public class GLStateManager {
}
if (isCachingEnabled()) {
glCtx.conversionMatrix4d.set(m);
getMatrixStack().set(glCtx.conversionMatrix4d);
bumpMatrixGeneration();
matrixStack(glCtx).set(glCtx.conversionMatrix4d);
bumpMatrixGeneration(glCtx);
}
}
@@ -4539,7 +4555,10 @@ public class GLStateManager {
}
public static Matrix4fStack getMatrixStack() {
final GLContextState glCtx = ctx();
return matrixStack(ctx());
}
private static Matrix4fStack matrixStack(GLContextState glCtx) {
switch (glCtx.matrixMode.getMode()) {
case GL11.GL_MODELVIEW -> {
return glCtx.modelViewMatrix;
@@ -4548,19 +4567,18 @@ public class GLStateManager {
return glCtx.projectionMatrix;
}
case GL11.GL_TEXTURE -> {
return glCtx.textures.getTextureUnitMatrix(getActiveTextureUnit());
return glCtx.textures.getTextureUnitMatrix(glCtx.activeTextureUnit.getValue());
}
default -> throw new IllegalStateException("Unknown matrix mode: " + glCtx.matrixMode.getMode());
}
}
/** Bump the generation counter for the currently active matrix mode. */
private static void bumpMatrixGeneration() {
bumpMatrixGeneration(true);
private static void bumpMatrixGeneration(GLContextState glCtx) {
bumpMatrixGeneration(glCtx, true);
}
private static void bumpMatrixGeneration(boolean linearChanged) {
final GLContextState glCtx = ctx();
private static void bumpMatrixGeneration(GLContextState glCtx, boolean linearChanged) {
switch (glCtx.matrixMode.getMode()) {
case GL11.GL_MODELVIEW -> {
glCtx.mvGeneration++;
@@ -4572,7 +4590,8 @@ public class GLStateManager {
}
public static void glLoadIdentity() {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
final RecordMode mode = DisplayListManager.getRecordMode();
if (mode != RecordMode.NONE) {
DisplayListManager.recordLoadIdentity();
@@ -4581,62 +4600,66 @@ public class GLStateManager {
}
}
if (isCachingEnabled()) {
getMatrixStack().identity();
bumpMatrixGeneration();
matrixStack(glCtx).identity();
bumpMatrixGeneration(glCtx);
}
}
public static void glTranslatef(float x, float y, float z) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
if (DisplayListManager.isRecording()) {
DisplayListManager.applyMatrixTranslation(x, y, z);
return;
}
if (isCachingEnabled()) {
getMatrixStack().translate(x, y, z);
bumpMatrixGeneration(false);
matrixStack(glCtx).translate(x, y, z);
bumpMatrixGeneration(glCtx, false);
}
}
public static void glTranslated(double x, double y, double z) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
if (DisplayListManager.isRecording()) {
DisplayListManager.applyMatrixTranslation((float) x, (float) y, (float) z);
return;
}
if (isCachingEnabled()) {
getMatrixStack().translate((float) x, (float) y, (float) z);
bumpMatrixGeneration(false);
matrixStack(glCtx).translate((float) x, (float) y, (float) z);
bumpMatrixGeneration(glCtx, false);
}
}
public static void glScalef(float x, float y, float z) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
if (DisplayListManager.isRecording()) {
DisplayListManager.applyMatrixScale(x, y, z);
return;
}
if (isCachingEnabled()) {
getMatrixStack().scale(x, y, z);
bumpMatrixGeneration();
matrixStack(glCtx).scale(x, y, z);
bumpMatrixGeneration(glCtx);
}
}
public static void glScaled(double x, double y, double z) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
if (DisplayListManager.isRecording()) {
DisplayListManager.applyMatrixScale((float) x, (float) y, (float) z);
return;
}
if (isCachingEnabled()) {
getMatrixStack().scale((float) x, (float) y, (float) z);
bumpMatrixGeneration();
matrixStack(glCtx).scale((float) x, (float) y, (float) z);
bumpMatrixGeneration(glCtx);
}
}
public static void glMultMatrix(FloatBuffer floatBuffer) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
glCtx.multMatrix.set(floatBuffer);
final int currentMode = glCtx.matrixMode.getMode();
@@ -4645,22 +4668,23 @@ public class GLStateManager {
return;
}
if (isCachingEnabled()) {
getMatrixStack().mul(glCtx.multMatrix);
bumpMatrixGeneration();
matrixStack(glCtx).mul(glCtx.multMatrix);
bumpMatrixGeneration(glCtx);
}
}
public static void applyMultMatrix(Matrix4f multMatrix) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
if (isCachingEnabled()) {
getMatrixStack().mul(multMatrix);
bumpMatrixGeneration();
matrixStack(glCtx).mul(multMatrix);
bumpMatrixGeneration(glCtx);
}
}
public static void glMultMatrix(DoubleBuffer matrix) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
glCtx.conversionMatrix4d.set(matrix);
glCtx.conversionMatrix4f.set(glCtx.conversionMatrix4d);
@@ -4669,13 +4693,14 @@ public class GLStateManager {
return;
}
if (isCachingEnabled()) {
getMatrixStack().mul(glCtx.conversionMatrix4f);
bumpMatrixGeneration();
matrixStack(glCtx).mul(glCtx.conversionMatrix4f);
bumpMatrixGeneration(glCtx);
}
}
public static void glRotatef(float angle, float x, float y, float z) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
final float lenSq = x * x + y * y + z * z;
if (lenSq == 0.0f) return;
@@ -4692,13 +4717,14 @@ public class GLStateManager {
return;
}
if (isCachingEnabled()) {
getMatrixStack().rotate(angle, x, y, z);
bumpMatrixGeneration();
matrixStack(glCtx).rotate(angle, x, y, z);
bumpMatrixGeneration(glCtx);
}
}
public static void glRotated(double angle, double x, double y, double z) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
final double lenSq = x * x + y * y + z * z;
if (lenSq == 0.0) return;
@@ -4715,32 +4741,34 @@ public class GLStateManager {
return;
}
if (isCachingEnabled()) {
getMatrixStack().rotate((float) angle, (float) x, (float) y, (float) z);
bumpMatrixGeneration();
matrixStack(glCtx).rotate((float) angle, (float) x, (float) y, (float) z);
bumpMatrixGeneration(glCtx);
}
}
public static void glOrtho(double left, double right, double bottom, double top, double zNear, double zFar) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
if (DisplayListManager.isRecording()) {
DisplayListManager.updateRelativeTransformOrtho(left, right, bottom, top, zNear, zFar);
return;
}
if (isCachingEnabled()) {
getMatrixStack().ortho((float) left, (float) right, (float) bottom, (float) top, (float) zNear, (float) zFar);
bumpMatrixGeneration();
matrixStack(glCtx).ortho((float) left, (float) right, (float) bottom, (float) top, (float) zNear, (float) zFar);
bumpMatrixGeneration(glCtx);
}
}
public static void glFrustum(double left, double right, double bottom, double top, double zNear, double zFar) {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
if (DisplayListManager.isRecording()) {
DisplayListManager.updateRelativeTransformFrustum(left, right, bottom, top, zNear, zFar);
return;
}
if (isCachingEnabled()) {
getMatrixStack().frustum((float) left, (float) right, (float) bottom, (float) top, (float) zNear, (float) zFar);
bumpMatrixGeneration();
matrixStack(glCtx).frustum((float) left, (float) right, (float) bottom, (float) top, (float) zNear, (float) zFar);
bumpMatrixGeneration(glCtx);
}
}
@@ -4755,7 +4783,7 @@ public class GLStateManager {
// Only track stack on main thread (splash thread has separate GL context)
if (isCachingEnabled()) {
try {
getMatrixStack().pushMatrix();
matrixStack(ctx()).pushMatrix();
} catch (IllegalStateException ignored) {
if (initConfig != null && initConfig.isLwjglDebug()) LOGGER.warn("Matrix stack overflow ", new Throwable());
}
@@ -4763,7 +4791,8 @@ public class GLStateManager {
}
public static void glPopMatrix() {
beforeMatrixChange();
final GLContextState glCtx = ctx();
beforeMatrixChange(glCtx);
final RecordMode mode = DisplayListManager.getRecordMode();
if (mode != RecordMode.NONE) {
DisplayListManager.recordPopMatrix(); // Handles flush + relativeTransform stack + lastRecordedTransform sync
@@ -4774,8 +4803,8 @@ public class GLStateManager {
// Only track stack on main thread (splash thread has separate GL context)
if (isCachingEnabled()) {
try {
getMatrixStack().popMatrix();
bumpMatrixGeneration();
matrixStack(glCtx).popMatrix();
bumpMatrixGeneration(glCtx);
} catch (IllegalStateException ignored) {
if (initConfig != null && initConfig.isLwjglDebug()) LOGGER.warn("Matrix stack underflow ", new Throwable());
}
@@ -35,12 +35,14 @@ public final class CowDepths {
}
public int claim(int depth) {
if (depth <= 0) return -1;
if (pointer > 0 && slotDepth[pointer - 1] == depth) return -1;
slotDepth[pointer] = depth;
return pointer++;
}
public boolean claimedAt(int depth) {
return pointer > 0 && slotDepth[pointer - 1] == depth;
}
public int claimUnconditional() {
slotDepth[pointer] = -1;
return pointer++;
@@ -51,11 +51,10 @@ public interface CowStateStack<T> extends IStateStack<T> {
final CowDepths d = cowDepths();
final GLContextState o = d.owner;
if (o == null) return;
final int s = d.claim(o.attribDepth);
if (s >= 0) {
captureSlot(s);
GLStateManager.registerModifiedState(o, d.id);
}
final int depth = o.attribDepth;
if (depth == 0 || d.claimedAt(depth) || !o.savesState(d.id)) return;
captureSlot(d.claim(depth));
GLStateManager.registerModifiedState(o, d.id);
}
@Override
@@ -26,8 +26,8 @@ public final class TextureUnitBooleanStateStack extends BooleanStateStack {
public void setEnabled(boolean enabled) {
if (!GLStateManager.isCachingEnabled() || enabled != this.enabled) {
GLStateManager.beforeUncapturedTextureUnitChange(glCap, unitIndex);
beforeModify();
}
beforeModify();
setEnabledWithUnitSwitch(enabled);
}
@@ -78,6 +78,22 @@ public class GLSM_PerThread_UnitTest {
assertEquals(n + 1, distinct.size(), "every thread must own a distinct holder");
}
@Test
void ctxFollowsTheBindingOnTheMainThread() {
assertSame(GLStateManager.getMainThread(), Thread.currentThread(), "test must run on the GLSM main thread");
final GLContextState primary = GLStateManager.ctx();
assertSame(primary, GLStateManager.ctx());
final GLContextState worker = GLStateManager.enterWorkerContext();
try {
assertNotSame(primary, worker);
assertSame(worker, GLStateManager.ctx());
assertSame(worker, GLStateManager.ctx());
} finally {
GLStateManager.exitWorkerContext();
}
assertSame(primary, GLStateManager.ctx());
}
@Test
void matrixStackAndMvGenerationArePerThread() throws Throwable {
final int n = 6;
@@ -358,6 +358,127 @@ public class GLSM_StateSet_GLTest {
}
}
@Test
void nonMemberMutationsInsideBracketSaveAndDiscardNothing() {
try {
GLStateManager.enableAlphaTest();
GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.5f);
GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
final int d = GLStateManager.pushState(StateSet.CUTOUT);
final long discardsBefore = GLStateManager.attribDiscards;
try {
final long savedBefore = GLStateManager.attribSlotsSaved;
GLStateManager.tryBlendFuncSeparate(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_DST_COLOR, GL11.GL_ZERO);
GLStateManager.glDepthFunc(GL11.GL_ALWAYS);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE2);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
assertEquals(savedBefore, GLStateManager.attribSlotsSaved, "non-member mutations must not save slots");
} finally {
GLStateManager.popStateTo(d);
}
assertEquals(discardsBefore, GLStateManager.attribDiscards, "non-member mutations must not leave slots to discard");
assertEquals(GL11.GL_DST_COLOR, GLStateManager.getBlendState().getSrcRgb(), "cache blend src rgb - not a CUTOUT member, must stay toggled");
} finally {
GLStateManager.disableAlphaTest();
GLStateManager.glAlphaFunc(GL11.GL_ALWAYS, 0.0f);
GLStateManager.tryBlendFuncSeparate(GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ZERO);
GLStateManager.glDepthFunc(GL11.GL_LESS);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
}
}
@Test
void unchangedSettersSaveNothing() {
try {
GLStateManager.enableAlphaTest();
GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.5f);
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
GLStateManager.glDepthMask(true);
GLStateManager.glColorMask(true, true, true, true);
GLStateManager.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
GLStateManager.glBlendColor(0.1f, 0.2f, 0.3f, 0.4f);
GLStateManager.glBlendEquation(GL14.GL_FUNC_ADD);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
GLStateManager.enableTexture();
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
final int d = GLStateManager.pushState(StateSet.forMask(GL11.GL_ALL_ATTRIB_BITS));
try {
final long savedBefore = GLStateManager.attribSlotsSaved;
GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.5f);
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
GLStateManager.glDepthMask(true);
GLStateManager.glColorMask(true, true, true, true);
GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
GLStateManager.glBlendColor(0.1f, 0.2f, 0.3f, 0.4f);
GLStateManager.glBlendEquation(GL14.GL_FUNC_ADD);
GLStateManager.glBlendEquationSeparate(GL14.GL_FUNC_ADD, GL14.GL_FUNC_ADD);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
GLStateManager.enableTexture();
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
assertEquals(1, GLStateManager.attribSlotsSaved - savedBefore, "only the active unit change may save a slot");
} finally {
GLStateManager.popStateTo(d);
}
GLStateManager.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
final int d2 = GLStateManager.pushState(StateSet.forMask(GL11.GL_ALL_ATTRIB_BITS));
try {
final long savedBefore = GLStateManager.attribSlotsSaved;
GLStateManager.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
assertEquals(0, GLStateManager.attribSlotsSaved - savedBefore, "unchanged glBlendFunc must not save a slot");
} finally {
GLStateManager.popStateTo(d2);
}
} finally {
GLStateManager.disableAlphaTest();
GLStateManager.glAlphaFunc(GL11.GL_ALWAYS, 0.0f);
GLStateManager.disableBlend();
GLStateManager.tryBlendFuncSeparate(GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ZERO);
GLStateManager.glDepthFunc(GL11.GL_LESS);
GLStateManager.glDepthMask(true);
GLStateManager.glColorMask(true, true, true, true);
GLStateManager.glBlendColor(0.0f, 0.0f, 0.0f, 0.0f);
GLStateManager.glBlendEquation(GL14.GL_FUNC_ADD);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
GLStateManager.disableTexture();
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
}
}
@Test
void bracketDoesNotInheritMembersOfAnEarlierBracketAtItsDepth() {
try {
for (boolean nested : new boolean[] {false, true}) {
GLStateManager.tryBlendFuncSeparate(GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ZERO);
GLStateManager.glDepthFunc(GL11.GL_LESS);
final int outer = nested ? GLStateManager.pushState(StateSet.CULL) : GLStateManager.getAttribDepth();
try {
GLStateManager.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GLStateManager.glPopAttrib();
final int d = GLStateManager.pushState(StateSet.CUTOUT);
try {
final long savedBefore = GLStateManager.attribSlotsSaved;
GLStateManager.tryBlendFuncSeparate(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_DST_COLOR, GL11.GL_ZERO);
GLStateManager.glDepthFunc(GL11.GL_ALWAYS);
assertEquals(savedBefore, GLStateManager.attribSlotsSaved, "nested=" + nested);
} finally {
GLStateManager.popStateTo(d);
}
} finally {
GLStateManager.popStateTo(outer);
}
}
} finally {
GLStateManager.tryBlendFuncSeparate(GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ZERO);
GLStateManager.glDepthFunc(GL11.GL_LESS);
}
}
@Test
void cullFaceModeRestoredThroughCullBracket() {
try {
@@ -176,11 +176,6 @@ public class AngelicaConfig {
@Config.RequiresMcRestart
public static boolean shaderParityFlip;
@Config.Comment("Skip the end-of-frame glFlush before the buffer swap [Experimental]")
@Config.DefaultBoolean(false)
@Config.RequiresMcRestart
public static boolean skipEndOfFrameFlush;
@Config.Comment("Cache the vanilla skull mesh per skull type/player skin and batch skull draws")
@Config.DefaultBoolean(true)
@Config.RequiresMcRestart
@@ -206,9 +206,8 @@ public enum Mixins implements IMixins {
)
),
ANGELICA_SKIP_END_FRAME_FLUSH(new MixinBuilder("Skip the end-of-frame glFlush before the buffer swap")
ANGELICA_SKIP_END_FRAME_FLUSH(new MixinBuilder("Skip vanilla's end-of-frame glFlush; the buffer swap flushes")
.setPhase(Phase.EARLY)
.setApplyIf(() -> AngelicaConfig.skipEndOfFrameFlush)
.addClientMixins(
"angelica.MixinMinecraft_SkipEndFrameFlush"
)
@@ -4,6 +4,7 @@ import lombok.Getter;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.coderbot.iris.Iris;
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
import com.gtnewhorizons.angelica.glsm.DisplayListManager;
import com.gtnewhorizons.angelica.glsm.GLStateManager;
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
import com.gtnewhorizons.angelica.iris.IrisDisplayListState;
@@ -150,6 +151,10 @@ public class GbufferPrograms {
GLStateManager.enableAlphaTest();
GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.1F);
if (DisplayListManager.getRecordMode() == DisplayListManager.RecordMode.NONE) {
GLStateManager.getTextures().getTextureUnitStates(1).enable();
return;
}
final int previousUnit = GLStateManager.getActiveTextureUnitForServerState();
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
GLStateManager.enableTexture();
@@ -133,6 +133,31 @@ class IrisDisplayListStateTest {
}
}
@Test
void cutoutDefaultsOutsideListEnableLightmapWithoutSwitchingUnit() {
GLStateManager.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
try {
GLStateManager.enableAlphaTest();
GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.1f);
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
GLStateManager.disableTexture();
GLStateManager.glActiveTexture(GL13.GL_TEXTURE3);
final int d = GLStateManager.pushState(StateSet.CUTOUT);
try {
final long savedBefore = GLStateManager.attribSlotsSaved;
GbufferPrograms.setCutoutDefaults();
assertEquals(1, GLStateManager.attribSlotsSaved - savedBefore);
assertTrue(GLStateManager.getTextures().getTextureUnitStates(1).isEnabled());
assertEquals(3, GLStateManager.getActiveTextureUnit());
} finally {
GLStateManager.popStateTo(d);
}
assertFalse(GLStateManager.getTextures().getTextureUnitStates(1).isEnabled());
} finally {
GLStateManager.glPopAttrib();
}
}
@Test
void nestedBlendScopesRestorePlaybackValuesEvenIfCompileTimePopWasANoop() {
GLStateManager.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);