mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-10-26 14:24:30 +00:00
Fix crash replaying display lists compiled during the splash screen (#2250)
This commit is contained in:
1 parent
69428c12f6
commit
23aa04361d
10 files changed
+210
-53
No files matched your search
@@ -1025,7 +1025,7 @@ public class DisplayListManager {
|
||||
}
|
||||
|
||||
final DisplayListCommand[] complexObjects = commandBuffer.getComplexObjects();
|
||||
compiled = new CompiledDisplayList(commandBuffer.finish(), complexObjects, compiledBuffers, indexedBatches);
|
||||
compiled = new CompiledDisplayList(commandBuffer.finish(), complexObjects, compiledBuffers, indexedBatches, GLStateManager.ctx());
|
||||
currentRecorder = null;
|
||||
} catch (Exception e) {
|
||||
GLStateManager.LOGGER.error("Encountered a fatal issue while trying to compile a display list.");
|
||||
|
||||
+2
-1
@@ -525,8 +525,9 @@ public final class CommandBufferExecutor {
|
||||
ptr += 4;
|
||||
}
|
||||
case GLCommand.BIND_VAO -> {
|
||||
GLStateManager.glBindVertexArray(memGetInt(ptr));
|
||||
final int vao = memGetInt(ptr);
|
||||
ptr += 4;
|
||||
if (compiledDisplayList.replaysVertexArrayBind(vao)) GLStateManager.glBindVertexArray(vao);
|
||||
}
|
||||
|
||||
// === Complex object reference ===
|
||||
|
||||
+10
-2
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.glsm.recording;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.DisplayListManager;
|
||||
import com.gtnewhorizons.angelica.glsm.GLContextState;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.commands.DisplayListCommand;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.commands.IndexedDrawBatch;
|
||||
@@ -30,12 +31,13 @@ public final class CompiledDisplayList {
|
||||
* Empty display list singleton. Per OpenGL spec, an empty list is still valid.
|
||||
* This instance does nothing when rendered and is never deleted (shared singleton).
|
||||
*/
|
||||
public static final CompiledDisplayList EMPTY = new CompiledDisplayList(null, null, null, Collections.emptyList());
|
||||
public static final CompiledDisplayList EMPTY = new CompiledDisplayList(null, null, null, Collections.emptyList(), null);
|
||||
|
||||
private final ByteBuffer commandBuffer; // Off-heap command storage, must be freed
|
||||
private final DisplayListCommand[] complexObjects; // Complex commands (TexImage2D, etc.)
|
||||
private final DisplayListVBO ownedVbos; // GPU resources referenced by index
|
||||
private final List<IndexedDrawBatch> indexedBatches; // Shared VAO/VBO/EBO triples per layout group
|
||||
private GLContextState compileCtx;
|
||||
private Int2IntMap replayPrograms;
|
||||
private long programLifetimeGeneration = -1;
|
||||
|
||||
@@ -55,11 +57,16 @@ public final class CompiledDisplayList {
|
||||
return valid ? program : 0;
|
||||
}
|
||||
|
||||
public CompiledDisplayList(ByteBuffer commandBuffer, DisplayListCommand[] complexObjects, DisplayListVBO ownedVbos, List<IndexedDrawBatch> indexedBatches) {
|
||||
public CompiledDisplayList(ByteBuffer commandBuffer, DisplayListCommand[] complexObjects, DisplayListVBO ownedVbos, List<IndexedDrawBatch> indexedBatches, GLContextState compileCtx) {
|
||||
this.commandBuffer = commandBuffer;
|
||||
this.complexObjects = complexObjects;
|
||||
this.ownedVbos = ownedVbos;
|
||||
this.indexedBatches = indexedBatches;
|
||||
this.compileCtx = compileCtx;
|
||||
}
|
||||
|
||||
boolean replaysVertexArrayBind(int vao) {
|
||||
return vao == 0 || compileCtx == GLStateManager.ctx();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,6 +108,7 @@ public final class CompiledDisplayList {
|
||||
if (commandBuffer != null) {
|
||||
memFree(commandBuffer);
|
||||
}
|
||||
compileCtx = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-7
@@ -3,21 +3,20 @@ package com.gtnewhorizons.angelica.glsm.recording.commands;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
|
||||
public final class BatchedIndexedDrawCmd implements DisplayListCommand {
|
||||
private int sharedVAO;
|
||||
private IndexedDrawBatch batch;
|
||||
private int drawMode;
|
||||
private int indexCount;
|
||||
private int indexType;
|
||||
private long indexByteOffset;
|
||||
|
||||
public void fill(int sharedVAO, int drawMode, int indexCount, int indexType, long indexByteOffset) {
|
||||
this.sharedVAO = sharedVAO;
|
||||
public void fill(IndexedDrawBatch batch, int drawMode, int indexCount, int indexType, long indexByteOffset) {
|
||||
this.batch = batch;
|
||||
this.drawMode = drawMode;
|
||||
this.indexCount = indexCount;
|
||||
this.indexType = indexType;
|
||||
this.indexByteOffset = indexByteOffset;
|
||||
}
|
||||
|
||||
public int getSharedVAO() { return sharedVAO; }
|
||||
public int getDrawMode() { return drawMode; }
|
||||
public int getIndexCount() { return indexCount; }
|
||||
public int getIndexType() { return indexType; }
|
||||
@@ -25,13 +24,13 @@ public final class BatchedIndexedDrawCmd implements DisplayListCommand {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
if (sharedVAO == 0) return;
|
||||
GLStateManager.glBindVertexArray(sharedVAO);
|
||||
if (batch == null) return;
|
||||
batch.bind();
|
||||
GLStateManager.glDrawElements(drawMode, indexCount, indexType, indexByteOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BatchedIndexedDrawCmd(vao=" + sharedVAO + ", mode=" + drawMode + ", count=" + indexCount + ", type=" + indexType + ", offset=" + indexByteOffset + ")";
|
||||
return "BatchedIndexedDrawCmd(batch=" + batch + ", mode=" + drawMode + ", count=" + indexCount + ", type=" + indexType + ", offset=" + indexByteOffset + ")";
|
||||
}
|
||||
}
|
||||
+33
-7
@@ -1,34 +1,60 @@
|
||||
package com.gtnewhorizons.angelica.glsm.recording.commands;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLContextState;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
|
||||
public final class IndexedDrawBatch {
|
||||
private int sharedVAO;
|
||||
private final AttribLayoutKey layout;
|
||||
private int sharedVBO;
|
||||
private int sharedEBO;
|
||||
private int vao;
|
||||
private GLContextState vaoCtx;
|
||||
private boolean deleted;
|
||||
|
||||
public IndexedDrawBatch(int sharedVAO, int sharedVBO, int sharedEBO) {
|
||||
this.sharedVAO = sharedVAO;
|
||||
public IndexedDrawBatch(AttribLayoutKey layout, int sharedVBO, int sharedEBO) {
|
||||
this.layout = layout;
|
||||
this.sharedVBO = sharedVBO;
|
||||
this.sharedEBO = sharedEBO;
|
||||
}
|
||||
|
||||
public int getSharedVAO() { return sharedVAO; }
|
||||
public int getSharedVBO() { return sharedVBO; }
|
||||
public int getSharedEBO() { return sharedEBO; }
|
||||
|
||||
public void bind() {
|
||||
final GLContextState glCtx = GLStateManager.ctx();
|
||||
if (vaoCtx == glCtx) {
|
||||
GLStateManager.glBindVertexArray(vao);
|
||||
return;
|
||||
}
|
||||
final int prevVBO = GLStateManager.getBoundVBO();
|
||||
final int v = GLStateManager.glGenVertexArrays();
|
||||
GLStateManager.glBindVertexArray(v);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, sharedVBO);
|
||||
final int stride = layout.stride();
|
||||
for (int i = 0; i < layout.locations.length; i++) {
|
||||
final int loc = layout.locations[i];
|
||||
GLStateManager.glVertexAttribPointer(loc, layout.sizes[i], layout.types[i], layout.normalized[i], stride, layout.offset(i));
|
||||
GLStateManager.glEnableVertexAttribArray(loc);
|
||||
}
|
||||
GLStateManager.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, sharedEBO);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, prevVBO);
|
||||
vao = v;
|
||||
vaoCtx = glCtx;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
if (deleted) return;
|
||||
deleted = true;
|
||||
if (sharedVAO != 0) GLStateManager.glDeleteVertexArrays(sharedVAO);
|
||||
if (vaoCtx == GLStateManager.ctx()) GLStateManager.glDeleteVertexArrays(vao);
|
||||
if (sharedVBO != 0) GLStateManager.glDeleteBuffers(sharedVBO);
|
||||
if (sharedEBO != 0) GLStateManager.glDeleteBuffers(sharedEBO);
|
||||
sharedVAO = sharedVBO = sharedEBO = 0;
|
||||
vao = sharedVBO = sharedEBO = 0;
|
||||
vaoCtx = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IndexedDrawBatch(vao=" + sharedVAO + ", vbo=" + sharedVBO + ", ebo=" + sharedEBO + ")";
|
||||
return "IndexedDrawBatch(vao=" + vao + ", vbo=" + sharedVBO + ", ebo=" + sharedEBO + ")";
|
||||
}
|
||||
}
|
||||
+2
-19
@@ -35,7 +35,6 @@ public final class IndexedDrawBatchBuilder {
|
||||
final List<IndexedDrawBatch> out = new ArrayList<>();
|
||||
if (captures.isEmpty()) return out;
|
||||
|
||||
final int prevVAO = GLStateManager.getBoundVAO();
|
||||
final int prevVBO = GLStateManager.getBoundVBO();
|
||||
final int prevEBO = GLStateManager.getBoundEBO();
|
||||
|
||||
@@ -58,7 +57,6 @@ public final class IndexedDrawBatchBuilder {
|
||||
if (!success) {
|
||||
for (GroupResult r : results) r.batch.delete();
|
||||
}
|
||||
GLStateManager.glBindVertexArray(prevVAO);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, prevEBO);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, prevVBO);
|
||||
}
|
||||
@@ -69,9 +67,8 @@ public final class IndexedDrawBatchBuilder {
|
||||
private record GroupResult(IndexedDrawBatch batch, List<IndexedDrawCapture> captures,
|
||||
int[] drawModes, int[] indexCounts, long[] indexOffsets) {
|
||||
void commit() {
|
||||
final int sharedVAO = batch.getSharedVAO();
|
||||
for (int i = 0; i < captures.size(); i++) {
|
||||
captures.get(i).placeholder.fill(sharedVAO, drawModes[i], indexCounts[i], GL11.GL_UNSIGNED_INT, indexOffsets[i]);
|
||||
captures.get(i).placeholder.fill(batch, drawModes[i], indexCounts[i], GL11.GL_UNSIGNED_INT, indexOffsets[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,7 +84,6 @@ public final class IndexedDrawBatchBuilder {
|
||||
throw new IllegalStateException("batch exceeds 2GiB — split needed");
|
||||
}
|
||||
|
||||
int sharedVAO = 0;
|
||||
int sharedVBO = 0;
|
||||
int sharedEBO = 0;
|
||||
ByteBuffer eboData = null;
|
||||
@@ -99,12 +95,10 @@ public final class IndexedDrawBatchBuilder {
|
||||
final long[] indexOffsets = new long[n];
|
||||
|
||||
try {
|
||||
sharedVAO = GLStateManager.glGenVertexArrays();
|
||||
sharedVBO = GLStateManager.glGenBuffers();
|
||||
sharedEBO = GLStateManager.glGenBuffers();
|
||||
eboData = MemoryUtilities.memAlloc((int) totalIndexBytes);
|
||||
|
||||
GLStateManager.glBindVertexArray(sharedVAO);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, sharedVBO);
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, totalVertexBytes, GL15.GL_STATIC_DRAW);
|
||||
|
||||
@@ -146,23 +140,12 @@ public final class IndexedDrawBatchBuilder {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, sharedEBO);
|
||||
GLStateManager.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, eboData, GL15.GL_STATIC_DRAW);
|
||||
|
||||
final AttribLayoutKey layout = group.get(0).layoutKey;
|
||||
final int stride = layout.stride();
|
||||
for (int i = 0; i < layout.locations.length; i++) {
|
||||
final int loc = layout.locations[i];
|
||||
final int size = layout.sizes[i];
|
||||
final int type = layout.types[i];
|
||||
GLStateManager.glVertexAttribPointer(loc, size, type, layout.normalized[i], stride, layout.offset(i));
|
||||
GLStateManager.glEnableVertexAttribArray(loc);
|
||||
}
|
||||
|
||||
success = true;
|
||||
return new GroupResult(new IndexedDrawBatch(sharedVAO, sharedVBO, sharedEBO),
|
||||
return new GroupResult(new IndexedDrawBatch(group.get(0).layoutKey, sharedVBO, sharedEBO),
|
||||
group, drawModes, indexCounts, indexOffsets);
|
||||
} finally {
|
||||
if (eboData != null) MemoryUtilities.memFree(eboData);
|
||||
if (!success) {
|
||||
if (sharedVAO != 0) GLStateManager.glDeleteVertexArrays(sharedVAO);
|
||||
if (sharedVBO != 0) GLStateManager.glDeleteBuffers(sharedVBO);
|
||||
if (sharedEBO != 0) GLStateManager.glDeleteBuffers(sharedEBO);
|
||||
}
|
||||
|
||||
+118
@@ -3,6 +3,8 @@ package com.gtnewhorizons.angelica.glsm;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpFixture;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.VAOManager;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.commands.IndexedDrawBatch;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.TestThreads;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -14,6 +16,7 @@ import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.SharedDrawable;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@@ -29,14 +32,22 @@ import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
@GLCoreTest
|
||||
public class GLSM_SharedDrawableContext_GLTest {
|
||||
|
||||
private SharedDrawable sharedDrawable;
|
||||
private int listVbo;
|
||||
private int listEbo;
|
||||
private int indexedList;
|
||||
private int sharedContextVao;
|
||||
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
if (indexedList != 0) GLStateManager.glDeleteLists(indexedList, 1);
|
||||
if (listVbo != 0) GLStateManager.glDeleteBuffers(listVbo);
|
||||
if (listEbo != 0) GLStateManager.glDeleteBuffers(listEbo);
|
||||
if (sharedDrawable != null) {
|
||||
DrawableContexts.destroy(sharedDrawable);
|
||||
sharedDrawable = null;
|
||||
@@ -222,6 +233,113 @@ public class GLSM_SharedDrawableContext_GLTest {
|
||||
});
|
||||
}
|
||||
|
||||
private int compileIndexedListOnSharedDrawable() throws Exception {
|
||||
sharedDrawable = new SharedDrawable(Display.getDrawable());
|
||||
DrawableContexts.run(sharedDrawable, "SharedDrawableContext-IndexedList-Thread", () -> {
|
||||
final FloatBuffer vertices = BufferUtils.createFloatBuffer(9);
|
||||
vertices.put(new float[] { -0.5f, -0.5f, 0f, 0.5f, -0.5f, 0f, 0f, 0.5f, 0f });
|
||||
vertices.flip();
|
||||
final ByteBuffer indices = BufferUtils.createByteBuffer(6);
|
||||
indices.putShort((short) 0).putShort((short) 1).putShort((short) 2);
|
||||
indices.flip();
|
||||
|
||||
listVbo = GLStateManager.glGenBuffers();
|
||||
listEbo = GLStateManager.glGenBuffers();
|
||||
GLStateManager.glBindVertexArray(GLStateManager.glGenVertexArrays());
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, listVbo);
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, vertices, GL15.GL_STATIC_DRAW);
|
||||
GLStateManager.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 12, 0L);
|
||||
GLStateManager.glEnableVertexAttribArray(0);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, listEbo);
|
||||
GLStateManager.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indices, GL15.GL_STATIC_DRAW);
|
||||
|
||||
indexedList = GLStateManager.glGenLists(1);
|
||||
GLStateManager.glNewList(indexedList, GL11.GL_COMPILE);
|
||||
GLStateManager.glDrawElements(GL11.GL_TRIANGLES, 3, GL11.GL_UNSIGNED_SHORT, 0L);
|
||||
GLStateManager.glEndList();
|
||||
|
||||
final IndexedDrawBatch batch = indexedBatch();
|
||||
batch.bind();
|
||||
sharedContextVao = Reflect.<Integer>get(batch, "vao");
|
||||
});
|
||||
return indexedList;
|
||||
}
|
||||
|
||||
private IndexedDrawBatch indexedBatch() {
|
||||
return DisplayListManager.getDisplayList(indexedList).getIndexedBatches().get(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedListCompiledOnSharedDrawableReplaysOnDisplay() throws Exception {
|
||||
final int list = compileIndexedListOnSharedDrawable();
|
||||
final ShaderManager sm = ShaderManager.getInstance();
|
||||
final boolean wasEnabled = ShaderManager.isEnabled();
|
||||
ShaderManager.enable();
|
||||
sm.activate();
|
||||
try {
|
||||
GLStateManager.glCallList(list);
|
||||
|
||||
indexedBatch().bind();
|
||||
assertEquals(indexedBatch().getSharedEBO(), GL11.glGetInteger(GL15.GL_ELEMENT_ARRAY_BUFFER_BINDING));
|
||||
} finally {
|
||||
sm.deactivate();
|
||||
if (!wasEnabled) ShaderManager.disable();
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void deletingListLeavesDisplayVaoWithTheSharedContextName() throws Exception {
|
||||
final int list = compileIndexedListOnSharedDrawable();
|
||||
final IntBuffer made = BufferUtils.createIntBuffer(4096);
|
||||
while (!GL30.glIsVertexArray(sharedContextVao) && made.hasRemaining()) {
|
||||
final int v = GLStateManager.glGenVertexArrays();
|
||||
made.put(v);
|
||||
if (v == sharedContextVao) GLStateManager.glBindVertexArray(v);
|
||||
}
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
assumeTrue(GL30.glIsVertexArray(sharedContextVao));
|
||||
|
||||
GLStateManager.glDeleteLists(list, 1);
|
||||
indexedList = 0;
|
||||
|
||||
assertTrue(GL30.glIsVertexArray(sharedContextVao));
|
||||
made.flip();
|
||||
while (made.hasRemaining()) GLStateManager.glDeleteVertexArrays(made.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
void recordedVaoBindReplaysOnlyOnItsCompileContext() throws Exception {
|
||||
final int bound = GLStateManager.glGenVertexArrays();
|
||||
final int local = GLStateManager.glGenVertexArrays();
|
||||
final int localList = GLStateManager.glGenLists(1);
|
||||
final int foreignList = GLStateManager.glGenLists(1);
|
||||
GLStateManager.glNewList(localList, GL11.GL_COMPILE);
|
||||
GLStateManager.glBindVertexArray(local);
|
||||
GLStateManager.glEndList();
|
||||
|
||||
sharedDrawable = new SharedDrawable(Display.getDrawable());
|
||||
DrawableContexts.run(sharedDrawable, "SharedDrawableContext-VaoBind-Thread", () -> {
|
||||
int foreign;
|
||||
do foreign = GLStateManager.glGenVertexArrays(); while (foreign == bound);
|
||||
GLStateManager.glNewList(foreignList, GL11.GL_COMPILE);
|
||||
GLStateManager.glBindVertexArray(foreign);
|
||||
GLStateManager.glEndList();
|
||||
});
|
||||
|
||||
GLStateManager.glBindVertexArray(bound);
|
||||
GLStateManager.glCallList(foreignList);
|
||||
assertEquals(bound, GLStateManager.getBoundVAO());
|
||||
GLStateManager.glCallList(localList);
|
||||
assertEquals(local, GLStateManager.getBoundVAO());
|
||||
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
GLStateManager.glDeleteVertexArrays(bound);
|
||||
GLStateManager.glDeleteVertexArrays(local);
|
||||
GLStateManager.glDeleteLists(localList, 1);
|
||||
GLStateManager.glDeleteLists(foreignList, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deferredTextureDeletesWaitForSplashAndScrubDrawableContexts() throws Exception {
|
||||
sharedDrawable = new SharedDrawable(Display.getDrawable());
|
||||
|
||||
+14
-11
@@ -27,9 +27,10 @@ import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
@@ -234,8 +235,9 @@ class IndexedDrawBatchBuilderTest extends DisplayListTestFixture {
|
||||
final int vao = setupPosColorVao(vbo);
|
||||
final int list = recordSingleIndexedDraw(vao, ebo, GL11.GL_TRIANGLES, 3, GL11.GL_UNSIGNED_SHORT);
|
||||
|
||||
replay(list);
|
||||
final IndexedDrawBatch batch = firstBatch(list);
|
||||
final int sharedVAO = batch.getSharedVAO();
|
||||
final int sharedVAO = vaoOf(batch);
|
||||
final int sharedVBO = batch.getSharedVBO();
|
||||
final int sharedEBO = batch.getSharedEBO();
|
||||
assertTrue(GL15.glIsBuffer(sharedVBO), "shared VBO live");
|
||||
@@ -257,8 +259,9 @@ class IndexedDrawBatchBuilderTest extends DisplayListTestFixture {
|
||||
final int vao = setupPosColorVao(vbo);
|
||||
final int list = recordSingleIndexedDraw(vao, ebo, GL11.GL_TRIANGLES, 3, GL11.GL_UNSIGNED_SHORT);
|
||||
|
||||
replay(list);
|
||||
final IndexedDrawBatch first = firstBatch(list);
|
||||
final int oldVAO = first.getSharedVAO();
|
||||
final int oldVAO = vaoOf(first);
|
||||
final int oldVBO = first.getSharedVBO();
|
||||
final int oldEBO = first.getSharedEBO();
|
||||
|
||||
@@ -341,8 +344,8 @@ class IndexedDrawBatchBuilderTest extends DisplayListTestFixture {
|
||||
final List<IndexedDrawBatch> batches = batchesOf(list);
|
||||
assertEquals(1, batches.size(), "same layout → one shared batch");
|
||||
|
||||
assertEquals(cmds.get(0).getSharedVAO(), cmds.get(1).getSharedVAO(), "shared VAO across draws in the same batch");
|
||||
assertEquals(batches.getFirst().getSharedVAO(), cmds.get(0).getSharedVAO());
|
||||
assertSame(batchOf(cmds.get(0)), batchOf(cmds.get(1)), "shared batch across draws in the same layout");
|
||||
assertSame(batches.getFirst(), batchOf(cmds.get(0)));
|
||||
|
||||
assertEquals(0L, cmds.get(0).getIndexByteOffset());
|
||||
assertEquals(3 * 4L, cmds.get(1).getIndexByteOffset(), "second draw offset = first.indexCount * sizeof(UINT)");
|
||||
@@ -396,7 +399,7 @@ class IndexedDrawBatchBuilderTest extends DisplayListTestFixture {
|
||||
final List<BatchedIndexedDrawCmd> cmds = allBatchedCmds(list);
|
||||
assertEquals(2, cmds.size());
|
||||
assertEquals(2, batchesOf(list).size(), "incompatible layouts → two batches");
|
||||
assertNotEquals(cmds.get(0).getSharedVAO(), cmds.get(1).getSharedVAO(), "VAOs from separate batches must be distinct");
|
||||
assertNotSame(batchOf(cmds.get(0)), batchOf(cmds.get(1)), "separate layouts must get distinct batches");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -435,7 +438,7 @@ class IndexedDrawBatchBuilderTest extends DisplayListTestFixture {
|
||||
final List<BatchedIndexedDrawCmd> cmds = allBatchedCmds(list);
|
||||
assertEquals(2, cmds.size());
|
||||
assertEquals(2, batchesOf(list).size(), "different enabled locations → two batches");
|
||||
assertNotEquals(cmds.get(0).getSharedVAO(), cmds.get(1).getSharedVAO(), "VAOs from separate batches must be distinct");
|
||||
assertNotSame(batchOf(cmds.get(0)), batchOf(cmds.get(1)), "separate layouts must get distinct batches");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -495,13 +498,13 @@ class IndexedDrawBatchBuilderTest extends DisplayListTestFixture {
|
||||
final List<BatchedIndexedDrawCmd> ba = allBatchedCmds(listBA);
|
||||
// Placeholders sit in command-stream order (A-first vs B-first).
|
||||
// Batches must be ordered so that placeholder[0] points at batch[0].
|
||||
assertEquals(ab.get(0).getSharedVAO(), batchesOf(listAB).get(0).getSharedVAO(),
|
||||
assertSame(batchesOf(listAB).get(0), batchOf(ab.get(0)),
|
||||
"listAB: batch[0] must match the first-recorded layout");
|
||||
assertEquals(ab.get(1).getSharedVAO(), batchesOf(listAB).get(1).getSharedVAO(),
|
||||
assertSame(batchesOf(listAB).get(1), batchOf(ab.get(1)),
|
||||
"listAB: batch[1] must match the second-recorded layout");
|
||||
assertEquals(ba.get(0).getSharedVAO(), batchesOf(listBA).get(0).getSharedVAO(),
|
||||
assertSame(batchesOf(listBA).get(0), batchOf(ba.get(0)),
|
||||
"listBA: batch[0] must match the first-recorded layout");
|
||||
assertEquals(ba.get(1).getSharedVAO(), batchesOf(listBA).get(1).getSharedVAO(),
|
||||
assertSame(batchesOf(listBA).get(1), batchOf(ba.get(1)),
|
||||
"listBA: batch[1] must match the second-recorded layout");
|
||||
}
|
||||
|
||||
|
||||
+10
-5
@@ -18,7 +18,10 @@ import java.util.List;
|
||||
import static com.gtnewhorizons.angelica.glsm.GlTestSupport.drainErrors;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@@ -72,7 +75,8 @@ class IndexedDrawReplayTest extends DisplayListTestFixture {
|
||||
assertNotNull(batched);
|
||||
final IndexedDrawBatch batch = firstBatch(list);
|
||||
|
||||
GLStateManager.glBindVertexArray(batched.getSharedVAO());
|
||||
replay(list);
|
||||
GLStateManager.glBindVertexArray(vaoOf(batch));
|
||||
assertEquals(batch.getSharedEBO(), GLStateManager.getBoundEBO(),
|
||||
"batched VAO's EBO binding corrupted");
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
@@ -120,8 +124,6 @@ class IndexedDrawReplayTest extends DisplayListTestFixture {
|
||||
|
||||
final List<BatchedIndexedDrawCmd> cmds = allBatchedCmds(list);
|
||||
assertEquals(2, cmds.size());
|
||||
final int sharedVAO = cmds.getFirst().getSharedVAO();
|
||||
assertEquals(sharedVAO, cmds.get(1).getSharedVAO());
|
||||
|
||||
final int distractor = newVao();
|
||||
GLStateManager.glBindVertexArray(distractor);
|
||||
@@ -129,6 +131,9 @@ class IndexedDrawReplayTest extends DisplayListTestFixture {
|
||||
|
||||
compiledOf(list).render();
|
||||
|
||||
assertSame(batchOf(cmds.getFirst()), batchOf(cmds.get(1)));
|
||||
final int sharedVAO = vaoOf(batchOf(cmds.getFirst()));
|
||||
assertNotEquals(0, sharedVAO);
|
||||
assertEquals(sharedVAO, GLStateManager.getBoundVAO());
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
}
|
||||
@@ -160,8 +165,8 @@ class IndexedDrawReplayTest extends DisplayListTestFixture {
|
||||
|
||||
try {
|
||||
assertThrows(IllegalStateException.class, builder::build);
|
||||
assertEquals(0, good.placeholder.getSharedVAO());
|
||||
assertEquals(0, huge.placeholder.getSharedVAO());
|
||||
assertNull(batchOf(good.placeholder));
|
||||
assertNull(batchOf(huge.placeholder));
|
||||
} finally {
|
||||
MemoryUtilities.memFree(tinyVtx);
|
||||
MemoryUtilities.memFree(tinyIdx);
|
||||
|
||||
+14
@@ -8,6 +8,7 @@ import com.gtnewhorizons.angelica.glsm.GLTypes;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.CompiledDisplayList;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.commands.BatchedIndexedDrawCmd;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.commands.IndexedDrawBatch;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
@@ -176,6 +177,19 @@ public abstract class DisplayListTestFixture {
|
||||
return batchesOf(listId).getFirst();
|
||||
}
|
||||
|
||||
protected static void replay(int listId) {
|
||||
compiledOf(listId).render();
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
}
|
||||
|
||||
protected static IndexedDrawBatch batchOf(BatchedIndexedDrawCmd cmd) {
|
||||
return Reflect.get(cmd, "batch");
|
||||
}
|
||||
|
||||
protected static int vaoOf(IndexedDrawBatch batch) {
|
||||
return Reflect.<Integer>get(batch, "vao");
|
||||
}
|
||||
|
||||
protected static ByteBuffer readBufferBytes(int target, int bufferId, int size) {
|
||||
final int prev;
|
||||
if (target == GL15.GL_ARRAY_BUFFER) prev = GLStateManager.getBoundVBO();
|
||||
|
||||
Reference in new issue
Block a user