Fix tests & SDL-GPU framebuffers losing attachments on resize or texture delete (#2282)

This commit is contained in:
Jason Mitchell authored and GitHub committed 2026-10-21 15:12:32 -07:00
1 parent e98c927a93
commit ed260a34c4
5 files changed
+55 -62

No files matched your search

@@ -4660,9 +4660,7 @@ public class SDLGPURenderBackend extends RenderBackend {
@Override
public void renderbufferStorage(int target, int internalformat, int width, int height) {
if (boundRenderbufferId == 0) return;
resourceManager.deleteTexture(boundRenderbufferId);
resourceManager.createTexture(boundRenderbufferId, GL11.GL_TEXTURE_2D, internalformat, width, height, 1, 1);
texStorageImpl(s(), boundRenderbufferId, GL11.GL_TEXTURE_2D, internalformat, width, height, 1, 1);
}
private boolean warnedMSAARenderbuffer = false;
@@ -331,19 +331,9 @@ public final class ResourceManager {
fboAttachedGlIds.remove(glId);
for (FboState fbo : fboStates.values()) {
for (int i = 0; i < ContextState.MAX_COLOR_ATTACHMENTS; i++) {
if (fbo.colorGlIds[i] == glId) {
fbo.colorTextures[i] = 0;
fbo.colorGlIds[i] = 0;
fbo.colorFormats[i] = 0;
fbo.targetsDirty = true;
}
}
if (fbo.depthGlId == glId) {
fbo.depthTexture = 0;
fbo.depthGlId = 0;
fbo.depthFormat = 0;
fbo.targetsDirty = true;
if (fbo.colorGlIds[i] == glId) fbo.detachColor(i);
}
if (fbo.depthGlId == glId) fbo.detachDepth();
}
texSamplerStates.remove(glId);
} finally {
@@ -514,6 +504,7 @@ public final class ResourceManager {
if (fbo.colorGlIds[i] == glId) {
fbo.colorTextures[i] = newHandle;
fbo.targetsDirty = true;
fbo.cachedFormatsDirty = true;
if (meta != null) {
fbo.colorFormats[i] = meta.sdlFormat();
if (i == 0) {
@@ -455,6 +455,27 @@ class GlsmSdlAttachmentClearTest {
GlsmSdlHeadlessRig.bindTarget();
}
@Test
void clearReachesARenderbufferRespecifiedWhileAttached() {
final int rb = GLStateManager.glGenRenderbuffers();
GLStateManager.glBindRenderbuffer(GL30.GL_RENDERBUFFER, rb);
GLStateManager.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL11.GL_RGBA8, SIZE / 4, SIZE / 4);
final int fbo = GLStateManager.glGenFramebuffers();
GLStateManager.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fbo);
GLStateManager.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL30.GL_RENDERBUFFER, rb);
GLStateManager.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL11.GL_RGBA8, SIZE, SIZE);
GLStateManager.glViewport(0, 0, SIZE, SIZE);
GLStateManager.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
GLStateManager.glClear(GL11.GL_COLOR_BUFFER_BIT);
GlsmSdlHeadlessRig.assertUniform(GlsmSdlHeadlessRig.readTarget(), RED, "respecified renderbuffer must stay attached");
GLStateManager.glDeleteFramebuffers(fbo);
GLStateManager.glDeleteRenderbuffers(rb);
GlsmSdlHeadlessRig.bindTarget();
}
private static int createColorTexture() {
return createColorTexture(GL11.GL_RGBA8, GL11.GL_RGBA);
}
@@ -84,53 +84,6 @@ class ResourceManagerConcurrencyTest {
}
}
@Test
void textureDeleteAndFboCleanupAreAtomic() throws Exception {
final ResourceManager rm = SdlTestRig.resourceManager();
final int textureId = 42;
final int fboId = rm.genFboId();
final FboState fbo = rm.createFbo(fboId);
fbo.colorGlIds[0] = textureId;
fbo.colorTextures[0] = 0xDEADBEEFL;
fbo.colorFormats[0] = 1;
final AtomicBoolean done = new AtomicBoolean(false);
final AtomicBoolean violation = new AtomicBoolean(false);
final CountDownLatch readerStarted = new CountDownLatch(1);
final Thread reader = new Thread(() -> {
readerStarted.countDown();
int iters = 0;
while (!done.get() && iters < 5_000_000) {
final FboState f = rm.getFbo(fboId);
if (f != null) {
final boolean idSet = f.colorGlIds[0] == textureId;
final boolean handleSet = f.colorTextures[0] != 0 || f.colorFormats[0] != 0;
if (idSet != handleSet) {
violation.set(true);
return;
}
}
iters++;
}
}, "reader");
reader.start();
readerStarted.await();
Thread.sleep(10);
rm.deleteTexture(textureId);
Thread.sleep(20);
done.set(true);
reader.join(2000);
assertFalse(violation.get(), "Reader observed half-cleaned FBO state");
final FboState f = rm.getFbo(fboId);
assertEquals(0, f.colorGlIds[0]);
assertEquals(0L, f.colorTextures[0]);
assertEquals(0, f.colorFormats[0]);
}
@Test
void concurrentCreateLookupDelete_noRaces() throws Exception {
final ResourceManager rm = SdlTestRig.resourceManager();
@@ -1,11 +1,14 @@
package com.gtnewhorizons.angelica.sdlgpu.resource;
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.lwjgl.opengl.GL11;
import java.util.function.Consumer;
import java.util.stream.Stream;
@@ -166,4 +169,31 @@ class SDLGPUFboTargetCacheTest {
assertFalse(fbo.targetsDirty);
assertFalse(fbo.cachedFormatsDirty);
}
@Test
void textureDeleteAndRespecUpdateAttachedFbos() {
final ResourceManager rm = SdlTestRig.resourceManager();
final FboState fbo = rm.createFbo(rm.genFboId());
fbo.colorGlIds[0] = 42; fbo.colorTextures[0] = 0xAAAAL; fbo.colorFormats[0] = 1;
fbo.colorGlIds[1] = 43; fbo.colorTextures[1] = 0xBBBBL; fbo.colorFormats[1] = 1; fbo.colorLevels[1] = 1;
fbo.depthGlId = 43; fbo.depthTexture = 0xBBBBL; fbo.depthLevel = 1;
fbo.colorAttachmentCount = 2;
fbo.cachedFormatsDirty = false;
Reflect.invoke(rm, "restoreTextureHandle", new Class<?>[] { int.class, long.class, ResourceManager.TextureMeta.class }, 42, 0xCCCCL, new ResourceManager.TextureMeta(GL11.GL_TEXTURE_2D, GL11.GL_RGBA8, 2, 16, 16, 1, 1, 0));
rm.refreshTextureReferences(42);
assertEquals(0xCCCCL, fbo.colorTextures[0]);
assertEquals(2, fbo.colorFormats[0]);
assertTrue(fbo.cachedFormatsDirty, "a respecified color attachment must rebuild the pipeline color formats");
fbo.cachedFormatsDirty = false;
rm.deleteTexture(43);
assertEquals(0, fbo.colorGlIds[1]);
assertEquals(0, fbo.colorLevels[1]);
assertEquals(1, fbo.colorAttachmentCount);
assertTrue(fbo.cachedFormatsDirty, "a deleted color attachment must rebuild the pipeline color formats");
assertEquals(0, fbo.depthGlId);
assertEquals(0, fbo.depthLevel);
assertEquals(42, fbo.colorGlIds[0]);
}
}