mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-10-26 14:24:30 +00:00
Fix NEI items vanishing with ModularUI2 screens open on SDL-GPU (#2153)
This commit is contained in:
1 parent
c9d46e70e0
commit
e17b45c842
13 files changed
+146
-109
No files matched your search
@@ -649,8 +649,6 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
GLStateManager.replayStateToBackend();
|
||||
}
|
||||
ResourceManager.setSingleThreadedReads(GLStateManager.isSplashComplete());
|
||||
st.clearedTexturesThisFrame.clear();
|
||||
st.clearedStencilTexturesThisFrame.clear();
|
||||
st.pendingColorTextures.clear();
|
||||
st.pendingDepthTextures.clear();
|
||||
st.pendingStencilTextures.clear();
|
||||
@@ -3622,7 +3620,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
final int flipMode = (srcIsFbo0 != dstIsFbo0) ? SDL_FLIP_VERTICAL : SDL_FLIP_NONE;
|
||||
|
||||
if (blitColor) {
|
||||
resolveBlitClears(cs, colorSrcTex, colorDstTex, colorDstGlId, dstX0, dstY, dstW, dstH);
|
||||
resolveBlitClears(cs, colorSrcTex, colorDstTex, colorDstGlId, dstX0, dstY, dstW, dstH, true);
|
||||
final ResourceManager.TextureMeta srcMeta = resourceManager.getTextureMeta(colorSrcGlId);
|
||||
final ResourceManager.TextureMeta dstMeta = resourceManager.getTextureMeta(colorDstGlId);
|
||||
if (flipMode == SDL_FLIP_NONE && TextureOps.canCopyInsteadOfBlit(srcMeta, dstMeta, srcW, srcH, dstW, dstH)) {
|
||||
@@ -3632,14 +3630,15 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
}
|
||||
}
|
||||
if (blitDepth) {
|
||||
resolveBlitClears(cs, depthSrcTex, depthDstTex, dstFbo.depthGlId, dstX0, dstY, dstW, dstH);
|
||||
final boolean allAspects = !PixelOps.isDepthStencilFormat(dstFbo.depthFormat) || (mask & (GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT)) == (GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT);
|
||||
resolveBlitClears(cs, depthSrcTex, depthDstTex, dstFbo.depthGlId, dstX0, dstY, dstW, dstH, allAspects);
|
||||
textureOps.copyTexture(depthSrcTex, srcX0, srcY, depthDstTex, 0, dstX0, dstY, srcW, srcH);
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveBlitClears(ContextState cs, long srcTex, long dstTex, int dstGlId, int dstX, int dstY, int dstW, int dstH) {
|
||||
private void resolveBlitClears(ContextState cs, long srcTex, long dstTex, int dstGlId, int dstX, int dstY, int dstW, int dstH, boolean allAspects) {
|
||||
fboClearTracker.materializePendingClearForTexture(cs, srcTex);
|
||||
fboClearTracker.resolveDestinationForWrite(cs, dstTex, resourceManager.getTextureMeta(dstGlId), 0, dstX, dstY, 0, dstW, dstH);
|
||||
fboClearTracker.resolveDestinationForWrite(cs, dstTex, resourceManager.getTextureMeta(dstGlId), 0, dstX, dstY, 0, dstW, dstH, allAspects);
|
||||
}
|
||||
@Override public int createBuffers() { return resourceManager.genBuffer(); }
|
||||
@Override public void namedBufferData(int buffer, long size, int usage) {
|
||||
@@ -3995,7 +3994,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
if (srcTex == 0 || dstTex == 0) return;
|
||||
final ContextState copySt = s();
|
||||
fboClearTracker.materializePendingClearForTexture(copySt, srcTex);
|
||||
fboClearTracker.resolveDestinationForWrite(copySt, dstTex, resourceManager.getTextureMeta(dstName), dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight);
|
||||
fboClearTracker.resolveDestinationForWrite(copySt, dstTex, resourceManager.getTextureMeta(dstName), dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, true);
|
||||
final long cp = frameManager.ensureCopyPass();
|
||||
if (cp == 0) return;
|
||||
try (var stack = MemoryStack.stackPush()) {
|
||||
|
||||
@@ -332,9 +332,6 @@ public final class ContextState {
|
||||
public int defaultFboId;
|
||||
public GLContextState mirroredContext;
|
||||
|
||||
public final LongOpenHashSet clearedTexturesThisFrame = new LongOpenHashSet();
|
||||
public final LongOpenHashSet clearedStencilTexturesThisFrame = new LongOpenHashSet();
|
||||
|
||||
public final LongOpenHashSet pendingColorTextures = new LongOpenHashSet();
|
||||
public final Long2ObjectOpenHashMap<float[]> pendingColorValues = new Long2ObjectOpenHashMap<>();
|
||||
public final LongOpenHashSet pendingDepthTextures = new LongOpenHashSet();
|
||||
|
||||
@@ -200,11 +200,6 @@ public final class AttachmentClear {
|
||||
st.lastAppliedStencilRef = Integer.MIN_VALUE;
|
||||
st.lastAppliedVboBindCb = 0;
|
||||
|
||||
if (t.depthTexture != 0) {
|
||||
if (depth) st.clearedTexturesThisFrame.add(t.depthTexture);
|
||||
if (stencil) st.clearedStencilTexturesThisFrame.add(t.depthTexture);
|
||||
}
|
||||
|
||||
frameManager.noteInPassClear();
|
||||
return true;
|
||||
}
|
||||
|
||||
+5
-13
@@ -160,16 +160,11 @@ public final class PipelineApplier {
|
||||
final boolean proposedStencilClear;
|
||||
final boolean depthHasStencil = fbo.depthTexture != 0 && PixelOps.isDepthStencilFormat(fbo.depthFormat);
|
||||
if (fbo.depthTexture != 0) {
|
||||
final boolean defined = resourceManager.isTextureContentDefined(fbo.depthTexture);
|
||||
final boolean pendingClear = st.pendingDepthTextures.contains(fbo.depthTexture);
|
||||
final boolean firstUse = !pendingClear && !st.clearedTexturesThisFrame.contains(fbo.depthTexture);
|
||||
proposedDepthClear = pendingClear || firstUse;
|
||||
proposedDepthClear = pendingClear || !defined;
|
||||
final boolean pendingStencil = depthHasStencil && st.pendingStencilTextures.contains(fbo.depthTexture);
|
||||
if (depthHasStencil) {
|
||||
final boolean firstStencilUse = !pendingStencil && !st.clearedStencilTexturesThisFrame.contains(fbo.depthTexture);
|
||||
proposedStencilClear = pendingStencil || firstStencilUse;
|
||||
} else {
|
||||
proposedStencilClear = false;
|
||||
}
|
||||
proposedStencilClear = depthHasStencil && (pendingStencil || !defined);
|
||||
layoutHash = Hashing.fmix64(layoutHash, fbo.depthTexture);
|
||||
if (proposedDepthClear) {
|
||||
layoutHash = foldClearDepth(layoutHash, pendingClear ? st.pendingDepthValues.get(fbo.depthTexture) : st.depthClearValue);
|
||||
@@ -274,11 +269,8 @@ public final class PipelineApplier {
|
||||
}
|
||||
if (fbo.depthTexture == 0) return;
|
||||
st.pendingDepthTextures.remove(fbo.depthTexture);
|
||||
if (depthClear) st.clearedTexturesThisFrame.add(fbo.depthTexture);
|
||||
if (depthHasStencil) {
|
||||
st.pendingStencilTextures.remove(fbo.depthTexture);
|
||||
if (stencilClear) st.clearedStencilTexturesThisFrame.add(fbo.depthTexture);
|
||||
}
|
||||
if (depthHasStencil) st.pendingStencilTextures.remove(fbo.depthTexture);
|
||||
if (depthClear || stencilClear) rm.markTextureContentDefined(fbo.depthTexture);
|
||||
}
|
||||
|
||||
static long foldClearColor(long h, float r, float g, float b, float a) {
|
||||
|
||||
+18
-25
@@ -38,7 +38,6 @@ public final class FBOClearTracker {
|
||||
if (st.pendingColorTextures.add(tex)) {
|
||||
st.pendingMutationGen++;
|
||||
}
|
||||
st.clearedTexturesThisFrame.remove(tex);
|
||||
}
|
||||
|
||||
public static void recordPendingDepthClear(ContextState st, long tex, float value) {
|
||||
@@ -46,7 +45,6 @@ public final class FBOClearTracker {
|
||||
if (st.pendingDepthTextures.add(tex)) {
|
||||
st.pendingMutationGen++;
|
||||
}
|
||||
st.clearedTexturesThisFrame.remove(tex);
|
||||
}
|
||||
|
||||
public static void recordPendingStencilClear(ContextState st, long tex, int value) {
|
||||
@@ -54,7 +52,6 @@ public final class FBOClearTracker {
|
||||
if (st.pendingStencilTextures.add(tex)) {
|
||||
st.pendingMutationGen++;
|
||||
}
|
||||
st.clearedStencilTexturesThisFrame.remove(tex);
|
||||
}
|
||||
|
||||
public static boolean fboHasPendingClear(ContextState st, FboState fbo) {
|
||||
@@ -179,7 +176,6 @@ public final class FBOClearTracker {
|
||||
MemoryAccess.putFloat(ccAddr + SDL_FColor.G, color[1]);
|
||||
MemoryAccess.putFloat(ccAddr + SDL_FColor.B, color[2]);
|
||||
MemoryAccess.putFloat(ccAddr + SDL_FColor.A, color[3]);
|
||||
st.clearedTexturesThisFrame.add(handle);
|
||||
resourceManager.markTextureContentDefined(handle);
|
||||
consumed[idx] = true;
|
||||
}
|
||||
@@ -217,35 +213,35 @@ public final class FBOClearTracker {
|
||||
frameManager.beginRenderPass(null, dt);
|
||||
frameManager.endRenderPassIfActive(FrameManager.PASS_END_CLEAR);
|
||||
}
|
||||
if (clearDepth) {
|
||||
st.pendingDepthValues.remove(handle);
|
||||
st.clearedTexturesThisFrame.add(handle);
|
||||
}
|
||||
if (clearStencil) {
|
||||
st.pendingStencilValues.remove(handle);
|
||||
st.clearedStencilTexturesThisFrame.add(handle);
|
||||
}
|
||||
if (clearDepth) st.pendingDepthValues.remove(handle);
|
||||
if (clearStencil) st.pendingStencilValues.remove(handle);
|
||||
if (clearDepth && clearStencil) resourceManager.markTextureContentDefined(handle);
|
||||
}
|
||||
|
||||
public boolean discardPendingClearIfFullyCovered(ContextState st, long handle, int dstX, int dstY, int dstLevel, int width, int height, ResourceManager.TextureMeta meta) {
|
||||
public boolean discardPendingClearIfFullyCovered(ContextState st, long handle, int dstX, int dstY, int dstLevel, int width, int height, ResourceManager.TextureMeta meta, boolean allAspects) {
|
||||
if (handle == 0 || meta == null) return false;
|
||||
if (dstLevel != 0 || dstX != 0 || dstY != 0) return false;
|
||||
if (width != meta.width() || height != meta.height() || meta.depth() > 1) return false;
|
||||
final boolean depth = st.pendingDepthTextures.remove(handle);
|
||||
final boolean color = !depth && st.pendingColorTextures.remove(handle);
|
||||
if (!depth && !color) return false;
|
||||
if (depth) st.pendingDepthValues.remove(handle);
|
||||
else st.pendingColorValues.remove(handle);
|
||||
st.clearedTexturesThisFrame.add(handle);
|
||||
resourceManager.markTextureContentDefined(handle);
|
||||
if (st.pendingDepthTextures.contains(handle) || st.pendingStencilTextures.contains(handle)) {
|
||||
if (!allAspects) return false;
|
||||
st.pendingDepthTextures.remove(handle);
|
||||
st.pendingDepthValues.remove(handle);
|
||||
st.pendingStencilTextures.remove(handle);
|
||||
st.pendingStencilValues.remove(handle);
|
||||
} else if (st.pendingColorTextures.remove(handle)) {
|
||||
st.pendingColorValues.remove(handle);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
st.pendingMutationGen++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void resolveDestinationForWrite(ContextState st, long destTex, ResourceManager.TextureMeta destMeta, int level, int dx, int dy, int dz, int w, int h) {
|
||||
if (dz != 0 || !discardPendingClearIfFullyCovered(st, destTex, dx, dy, level, w, h, destMeta)) {
|
||||
public void resolveDestinationForWrite(ContextState st, long destTex, ResourceManager.TextureMeta destMeta, int level, int dx, int dy, int dz, int w, int h, boolean allAspects) {
|
||||
if (dz != 0 || !discardPendingClearIfFullyCovered(st, destTex, dx, dy, level, w, h, destMeta, allAspects)) {
|
||||
materializePendingClearForTexture(st, destTex);
|
||||
}
|
||||
resourceManager.markTextureContentDefined(destTex);
|
||||
}
|
||||
|
||||
public void materializePendingClearForTexture(ContextState st, long handle) {
|
||||
@@ -276,7 +272,6 @@ public final class FBOClearTracker {
|
||||
frameManager.noteMaterializedClearPass();
|
||||
frameManager.beginRenderPass(targets, null);
|
||||
frameManager.endRenderPassIfActive(FrameManager.PASS_END_CLEAR);
|
||||
st.clearedTexturesThisFrame.add(handle);
|
||||
resourceManager.markTextureContentDefined(handle);
|
||||
}
|
||||
st.pendingMutationGen++;
|
||||
@@ -305,8 +300,6 @@ public final class FBOClearTracker {
|
||||
st.pendingDepthValues.remove(handle);
|
||||
st.pendingStencilTextures.remove(handle);
|
||||
st.pendingStencilValues.remove(handle);
|
||||
st.clearedTexturesThisFrame.remove(handle);
|
||||
st.clearedStencilTexturesThisFrame.remove(handle);
|
||||
}
|
||||
|
||||
public boolean fbosHaveSameAttachments(ContextState st, int a, int b) {
|
||||
|
||||
@@ -364,6 +364,7 @@ public final class ResourceManager {
|
||||
|
||||
public void markTextureContentDefined(long handle) {
|
||||
if (handle == 0) return;
|
||||
if (isTextureContentDefined(handle)) return;
|
||||
wLock.lock();
|
||||
try { definedContentTextures.add(handle); } finally { wLock.unlock(); }
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ public final class TextureOps {
|
||||
final int h = CopyRectClip.height(clip);
|
||||
|
||||
fboClearTracker.materializePendingClearForTexture(st, srcTex);
|
||||
fboClearTracker.resolveDestinationForWrite(st, destTex, destMeta, level, dx, dy, 0, w, h);
|
||||
fboClearTracker.resolveDestinationForWrite(st, destTex, destMeta, level, dx, dy, 0, w, h, true);
|
||||
|
||||
if (isDepthDest || (srcMeta != null && destMeta != null && srcMeta.sdlFormat() == destMeta.sdlFormat())) {
|
||||
copyTexture(srcTex, sx, sy, destTex, level, dx, dy, w, h);
|
||||
@@ -180,7 +180,7 @@ public final class TextureOps {
|
||||
if (st.pendingSwapchainClear || st.pendingSwapchainDepthClear || st.pendingSwapchainStencilClear) {
|
||||
frameManager.ensureFbo0RenderPass(frameManager.frame(), st);
|
||||
}
|
||||
fboClearTracker.resolveDestinationForWrite(st, destTex, destMeta, level, dx, dy, 0, w, h);
|
||||
fboClearTracker.resolveDestinationForWrite(st, destTex, destMeta, level, dx, dy, 0, w, h, true);
|
||||
|
||||
blitTexture(srcTex, sx, srcFullH - sy - h, w, h, destTex, level, dx, dy, w, h, GL11.GL_NEAREST, SDL_FLIP_VERTICAL);
|
||||
}
|
||||
|
||||
+30
@@ -5,6 +5,7 @@ import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendManager;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.frame.FrameManager;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.resource.ResourceManager;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
@@ -29,6 +30,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
class GlsmSdlAttachmentClearTest {
|
||||
|
||||
private static final int SIZE = GlsmSdlHeadlessRig.SIZE;
|
||||
private static final int RED = 0xFFFF0000;
|
||||
private static final int BLACK = 0xFF000000;
|
||||
|
||||
@BeforeAll
|
||||
static void boot() {
|
||||
@@ -570,4 +573,31 @@ class GlsmSdlAttachmentClearTest {
|
||||
GLStateManager.glDeleteTextures(tex);
|
||||
GlsmSdlHeadlessRig.bindTarget();
|
||||
}
|
||||
|
||||
@Test
|
||||
void stencilWrittenLastFramePersists() {
|
||||
GlsmSdlHeadlessRig.bindTarget();
|
||||
GlsmSdlHeadlessRig.writeStencilOneInBottomHalf();
|
||||
|
||||
GlsmSdlHeadlessRig.endFrame();
|
||||
GlsmSdlHeadlessRig.beginFrameAndReset();
|
||||
GlsmSdlHeadlessRig.drawRedWhereStencilIsOne();
|
||||
|
||||
final int[] pixels = GlsmSdlHeadlessRig.readTarget();
|
||||
GlsmSdlHeadlessRig.assertPixel(pixels, SIZE, SIZE / 2, 4, RED, "stencil written last frame");
|
||||
GlsmSdlHeadlessRig.assertPixel(pixels, SIZE, SIZE / 2, SIZE - 5, BLACK, "outside last frame's stencil");
|
||||
}
|
||||
|
||||
@Test
|
||||
void aSingleAspectClearLeavesTheTextureUndefined() {
|
||||
final int fbo = GlsmSdlHeadlessRig.createDepthStencilFbo();
|
||||
GLStateManager.glDepthMask(true);
|
||||
GLStateManager.glClear(GL11.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
final ResourceManager resourceManager = Reflect.get(BackendManager.RENDER_BACKEND, "resourceManager");
|
||||
final long depthTexture = resourceManager.getFbo(fbo).depthTexture;
|
||||
GlsmSdlHeadlessRig.endFrame();
|
||||
|
||||
assertFalse(resourceManager.isTextureContentDefined(depthTexture), "the stencil aspect was never written, so the first pass must still clear it");
|
||||
}
|
||||
}
|
||||
+22
-20
@@ -155,32 +155,13 @@ class GlsmSdlCopyBlitTest {
|
||||
assertRow(pixels, SIZE - 1, SENTINEL, "last out-of-range row");
|
||||
}
|
||||
|
||||
private static int createSecondaryFbo() {
|
||||
final int color = GLStateManager.glGenTextures();
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, color);
|
||||
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GLStateManager.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, SIZE, SIZE, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null);
|
||||
|
||||
final int depth = GLStateManager.glGenRenderbuffers();
|
||||
GLStateManager.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depth);
|
||||
GLStateManager.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH24_STENCIL8, SIZE, SIZE);
|
||||
|
||||
final int fbo = GLStateManager.glGenFramebuffers();
|
||||
GLStateManager.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fbo);
|
||||
GLStateManager.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, color, 0);
|
||||
GLStateManager.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, depth);
|
||||
return fbo;
|
||||
}
|
||||
|
||||
@Test
|
||||
void blitFramebufferWithColorAndDepthBitsMovesColor() {
|
||||
GlsmSdlHeadlessRig.bindTarget();
|
||||
GlsmSdlHeadlessRig.clearTo(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
GlsmSdlHeadlessRig.solidQuad(0.0f, 1.0f, 0.0f);
|
||||
|
||||
final int destination = createSecondaryFbo();
|
||||
final int destination = GlsmSdlHeadlessRig.createDepthStencilFbo();
|
||||
GLStateManager.glViewport(0, 0, SIZE, SIZE);
|
||||
GLStateManager.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
GLStateManager.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||
@@ -243,4 +224,25 @@ class GlsmSdlCopyBlitTest {
|
||||
GlsmSdlHeadlessRig.assertPixel(pixels, SIZE, SIZE / 2, SIZE / 2 - 4, GREEN, "blitted fbo0 below the split");
|
||||
GlsmSdlHeadlessRig.assertPixel(pixels, SIZE, SIZE / 2, SIZE / 2 + 4, RED, "blitted fbo0 above the split");
|
||||
}
|
||||
|
||||
@Test
|
||||
void blitFramebufferStencilSurvivesTheDestinationsFirstDraw() {
|
||||
GlsmSdlHeadlessRig.bindTarget();
|
||||
GlsmSdlHeadlessRig.writeStencilOneInBottomHalf();
|
||||
|
||||
final int destination = GlsmSdlHeadlessRig.createDepthStencilFbo();
|
||||
GLStateManager.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
GLStateManager.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
GlsmSdlHeadlessRig.bindTarget();
|
||||
GLStateManager.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, destination);
|
||||
GLStateManager.glBlitFramebuffer(0, 0, SIZE, SIZE, 0, 0, SIZE, SIZE, GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT, GL11.GL_NEAREST);
|
||||
|
||||
GLStateManager.glBindFramebuffer(GL30.GL_FRAMEBUFFER, destination);
|
||||
GlsmSdlHeadlessRig.drawRedWhereStencilIsOne();
|
||||
|
||||
final int[] pixels = GlsmSdlHeadlessRig.readTarget();
|
||||
GlsmSdlHeadlessRig.assertPixel(pixels, SIZE, SIZE / 2, 4, RED, "stencil carried by the blit");
|
||||
GlsmSdlHeadlessRig.assertPixel(pixels, SIZE, SIZE / 2, SIZE - 5, BLUE, "outside the blitted stencil");
|
||||
}
|
||||
}
|
||||
@@ -116,6 +116,44 @@ public final class GlsmSdlHeadlessRig {
|
||||
GLStateManager.glViewport(0, 0, SIZE, SIZE);
|
||||
}
|
||||
|
||||
public static int createDepthStencilFbo() {
|
||||
final int color = GLStateManager.glGenTextures();
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, color);
|
||||
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GLStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GLStateManager.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, SIZE, SIZE, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null);
|
||||
|
||||
final int depth = GLStateManager.glGenRenderbuffers();
|
||||
GLStateManager.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depth);
|
||||
GLStateManager.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH24_STENCIL8, SIZE, SIZE);
|
||||
|
||||
final int fbo = GLStateManager.glGenFramebuffers();
|
||||
GLStateManager.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fbo);
|
||||
GLStateManager.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, color, 0);
|
||||
GLStateManager.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, depth);
|
||||
return fbo;
|
||||
}
|
||||
|
||||
public static void writeStencilOneInBottomHalf() {
|
||||
GLStateManager.glClearStencil(0);
|
||||
GLStateManager.glStencilMask(0xFF);
|
||||
GLStateManager.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT);
|
||||
GLStateManager.glEnable(GL11.GL_STENCIL_TEST);
|
||||
GLStateManager.glStencilFunc(GL11.GL_ALWAYS, 1, 0xFF);
|
||||
GLStateManager.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
|
||||
halfQuad(-1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
|
||||
GLStateManager.glDisable(GL11.GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
public static void drawRedWhereStencilIsOne() {
|
||||
GLStateManager.glEnable(GL11.GL_STENCIL_TEST);
|
||||
GLStateManager.glStencilFunc(GL11.GL_EQUAL, 1, 0xFF);
|
||||
GLStateManager.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
|
||||
solidQuad(1.0f, 0.0f, 0.0f);
|
||||
GLStateManager.glDisable(GL11.GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
public static void clearTo(float r, float g, float b, float a) {
|
||||
GLStateManager.glClearColor(r, g, b, a);
|
||||
GLStateManager.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
+6
-6
@@ -74,16 +74,16 @@ class ClearConsumptionTest {
|
||||
|
||||
@Test
|
||||
void depthAndStencilAreConsumedIndependently() {
|
||||
final ResourceManager rm = rm();
|
||||
final ContextState st = new ContextState();
|
||||
FBOClearTracker.recordPendingDepthClear(st, DEPTH, 1f);
|
||||
FBOClearTracker.recordPendingStencilClear(st, DEPTH, 0);
|
||||
|
||||
consumeClears(rm(), st, fbo(SDL_GPU_TEXTUREFORMAT_D24_UNORM_S8_UINT), DUMMY, 0, true, true, true);
|
||||
consumeClears(rm, st, fbo(SDL_GPU_TEXTUREFORMAT_D24_UNORM_S8_UINT), DUMMY, 0, true, true, true);
|
||||
|
||||
assertFalse(st.pendingDepthTextures.contains(DEPTH));
|
||||
assertFalse(st.pendingStencilTextures.contains(DEPTH));
|
||||
assertTrue(st.clearedTexturesThisFrame.contains(DEPTH));
|
||||
assertTrue(st.clearedStencilTexturesThisFrame.contains(DEPTH));
|
||||
assertTrue(rm.isTextureContentDefined(DEPTH), "the clear pass defines the depth-stencil contents");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -96,17 +96,17 @@ class ClearConsumptionTest {
|
||||
|
||||
assertFalse(st.pendingDepthTextures.contains(DEPTH));
|
||||
assertTrue(st.pendingStencilTextures.contains(DEPTH), "the format has no stencil aspect to clear");
|
||||
assertFalse(st.clearedStencilTexturesThisFrame.contains(DEPTH));
|
||||
}
|
||||
|
||||
@Test
|
||||
void anUnclearedDepthTargetIsStillConsumed() {
|
||||
final ResourceManager rm = rm();
|
||||
final ContextState st = new ContextState();
|
||||
FBOClearTracker.recordPendingDepthClear(st, DEPTH, 1f);
|
||||
|
||||
consumeClears(rm(), st, fbo(SDL_GPU_TEXTUREFORMAT_D24_UNORM), DUMMY, 0, false, false, false);
|
||||
consumeClears(rm, st, fbo(SDL_GPU_TEXTUREFORMAT_D24_UNORM), DUMMY, 0, false, false, false);
|
||||
|
||||
assertFalse(st.pendingDepthTextures.contains(DEPTH));
|
||||
assertFalse(st.clearedTexturesThisFrame.contains(DEPTH), "no clear was baked, so nothing was cleared");
|
||||
assertFalse(rm.isTextureContentDefined(DEPTH), "no clear was baked, so nothing was defined");
|
||||
}
|
||||
}
|
||||
+18
-17
@@ -29,32 +29,34 @@ class FullCoverageClearDiscardTest {
|
||||
final ContextState st = new ContextState();
|
||||
FBOClearTracker.recordPendingColorClear(st, HANDLE, 1f, 0f, 0f, 1f);
|
||||
|
||||
assertTrue(tracker().discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, meta()));
|
||||
assertTrue(tracker().discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, meta(), true));
|
||||
assertFalse(st.pendingColorTextures.contains(HANDLE), "pending clear must be dropped, not left queued");
|
||||
assertFalse(st.pendingColorValues.containsKey(HANDLE));
|
||||
assertTrue(st.clearedTexturesThisFrame.contains(HANDLE), "the overwrite counts as the clear");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fullTargetColorBlitDefinesTheContents() {
|
||||
void copyWithNoPendingClearDefinesTheDestination() {
|
||||
final ContextState st = new ContextState();
|
||||
FBOClearTracker.recordPendingColorClear(st, HANDLE, 1f, 0f, 0f, 1f);
|
||||
|
||||
final SdlTestRig rig = SdlTestRig.create();
|
||||
final FBOClearTracker tracker = new FBOClearTracker(rig.frameManager, rig.resourceManager, null);
|
||||
assertTrue(tracker.discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, meta()));
|
||||
tracker.resolveDestinationForWrite(st, HANDLE, meta(), 0, 0, 0, 0, W, H, true);
|
||||
|
||||
assertTrue(rig.resourceManager.isTextureContentDefined(HANDLE), "the overwrite defines the contents, so a later frame must not clear it back");
|
||||
assertTrue(rig.resourceManager.isTextureContentDefined(HANDLE), "a copy is a write, so the next pass must load it, not clear it");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fullTargetDepthBlitDropsThePendingClear() {
|
||||
void depthStencilClearsDropOnlyForAnAllAspectOverwrite() {
|
||||
final ContextState st = new ContextState();
|
||||
FBOClearTracker.recordPendingDepthClear(st, HANDLE, 1f);
|
||||
FBOClearTracker.recordPendingStencilClear(st, HANDLE, 0);
|
||||
final FBOClearTracker tracker = tracker();
|
||||
|
||||
assertTrue(tracker().discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, meta()));
|
||||
assertFalse(st.pendingDepthTextures.contains(HANDLE));
|
||||
assertTrue(st.clearedTexturesThisFrame.contains(HANDLE));
|
||||
assertFalse(tracker.discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, meta(), false));
|
||||
assertTrue(st.pendingDepthTextures.contains(HANDLE) && st.pendingStencilTextures.contains(HANDLE), "a single-aspect overwrite must materialize, not drop, the other aspect's clear");
|
||||
|
||||
assertTrue(tracker.discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, meta(), true));
|
||||
assertFalse(st.pendingDepthTextures.contains(HANDLE) || st.pendingStencilTextures.contains(HANDLE));
|
||||
assertFalse(st.pendingDepthValues.containsKey(HANDLE) || st.pendingStencilValues.containsKey(HANDLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -69,7 +71,7 @@ class FullCoverageClearDiscardTest {
|
||||
for (int[] c : partial) {
|
||||
final ContextState st = new ContextState();
|
||||
FBOClearTracker.recordPendingColorClear(st, HANDLE, 1f, 0f, 0f, 1f);
|
||||
assertFalse(tracker().discardPendingClearIfFullyCovered(st, HANDLE, c[0], c[1], c[2], c[3], c[4], meta()),
|
||||
assertFalse(tracker().discardPendingClearIfFullyCovered(st, HANDLE, c[0], c[1], c[2], c[3], c[4], meta(), true),
|
||||
"x=" + c[0] + " y=" + c[1] + " level=" + c[2] + " w=" + c[3] + " h=" + c[4]);
|
||||
assertTrue(st.pendingColorTextures.contains(HANDLE), "the clear must survive a partial overwrite");
|
||||
}
|
||||
@@ -80,7 +82,7 @@ class FullCoverageClearDiscardTest {
|
||||
final ContextState st = new ContextState();
|
||||
FBOClearTracker.recordPendingColorClear(st, HANDLE, 1f, 0f, 0f, 1f);
|
||||
final ResourceManager.TextureMeta volume = new ResourceManager.TextureMeta(0, 0, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, W, H, 4, 1, 0);
|
||||
assertFalse(tracker().discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, volume),
|
||||
assertFalse(tracker().discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, volume, true),
|
||||
"one slice of a volume is not full coverage");
|
||||
assertTrue(st.pendingColorTextures.contains(HANDLE));
|
||||
}
|
||||
@@ -88,15 +90,14 @@ class FullCoverageClearDiscardTest {
|
||||
@Test
|
||||
void noPendingClearIsNotAnOverwriteClaim() {
|
||||
final ContextState st = new ContextState();
|
||||
assertFalse(tracker().discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, meta()));
|
||||
assertFalse(st.clearedTexturesThisFrame.contains(HANDLE));
|
||||
assertFalse(tracker().discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, meta(), true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingMetaFallsBackToMaterializing() {
|
||||
final ContextState st = new ContextState();
|
||||
FBOClearTracker.recordPendingColorClear(st, HANDLE, 1f, 0f, 0f, 1f);
|
||||
assertFalse(tracker().discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, null));
|
||||
assertFalse(tracker().discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, null, true));
|
||||
assertTrue(st.pendingColorTextures.contains(HANDLE));
|
||||
}
|
||||
|
||||
@@ -107,7 +108,7 @@ class FullCoverageClearDiscardTest {
|
||||
FBOClearTracker.snapshotFlushGenerations(st);
|
||||
final int before = st.pendingMutationGen;
|
||||
|
||||
assertTrue(tracker().discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, meta()));
|
||||
assertTrue(tracker().discardPendingClearIfFullyCovered(st, HANDLE, 0, 0, 0, W, H, meta(), true));
|
||||
assertEquals(before + 1, st.pendingMutationGen);
|
||||
}
|
||||
}
|
||||
-11
@@ -56,15 +56,6 @@ class StencilClearTrackingTest {
|
||||
assertTrue(FBOClearTracker.fboHasPendingClear(st, fbo), "the pass must be rebuilt to apply the stencil clear");
|
||||
}
|
||||
|
||||
@Test
|
||||
void recordingAStencilClearRetractsTheClearedThisFrameMark() {
|
||||
final ContextState st = new ContextState();
|
||||
st.clearedStencilTexturesThisFrame.add(DEPTH);
|
||||
|
||||
FBOClearTracker.recordPendingStencilClear(st, DEPTH, 0);
|
||||
assertFalse(st.clearedStencilTexturesThisFrame.contains(DEPTH), "a second clear in one frame must not be swallowed");
|
||||
}
|
||||
|
||||
@Test
|
||||
void recordingBumpsMutationGen() {
|
||||
final ContextState st = new ContextState();
|
||||
@@ -79,7 +70,6 @@ class StencilClearTrackingTest {
|
||||
void scrubDropsStencilStateWithTheTexture() {
|
||||
final ContextState st = new ContextState();
|
||||
FBOClearTracker.recordPendingStencilClear(st, DEPTH, 7);
|
||||
st.clearedStencilTexturesThisFrame.add(DEPTH);
|
||||
|
||||
final SdlTestRig rig = SdlTestRig.create();
|
||||
final int glId = rig.resourceManager.genTexture();
|
||||
@@ -88,7 +78,6 @@ class StencilClearTrackingTest {
|
||||
|
||||
assertFalse(st.pendingStencilTextures.contains(DEPTH));
|
||||
assertFalse(st.pendingStencilValues.containsKey(DEPTH));
|
||||
assertFalse(st.clearedStencilTexturesThisFrame.contains(DEPTH));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in new issue
Block a user