mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-13 17:04:15 +00:00
Set entity, block entity and item IDs per vertex (#2265)
This commit is contained in:
1 parent
cfc6e12e00
commit
ab3bf17696
26 files changed
+720
-95
No files matched your search
@@ -34,6 +34,7 @@ import com.gtnewhorizons.angelica.glsm.states.PixelStoreState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.ImageUnitArray;
|
||||
import com.gtnewhorizons.angelica.glsm.states.SamplerUnitArray;
|
||||
import com.gtnewhorizons.angelica.glsm.states.TextureUnitArray;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.Instancing;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.VAOManager;
|
||||
@@ -104,6 +105,8 @@ public class GLContextState {
|
||||
public boolean dirtyNormalAttrib;
|
||||
public boolean dirtyTexCoordAttrib;
|
||||
public boolean dirtyLightmapAttrib = true;
|
||||
public long entityIds = InstancedAttribs.DEFAULT_ENTITY_IDS;
|
||||
public boolean dirtyEntityIdsAttrib = true;
|
||||
public boolean unit23TexCoordSetDuringDraw = false;
|
||||
public int maxBoundTextureUnit = 0;
|
||||
public int maxBoundImageUnit = 0;
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.gtnewhorizons.angelica.glsm.backend.BackendManager;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.GLDebugMessageListener;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.VSyncMode;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.Instancing;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.ShaderManager;
|
||||
@@ -25,6 +26,7 @@ import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.BatchStateGuard;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMInitConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GlintColorHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.CommandRecorder;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.CompiledDisplayList;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.ImmediateModeRecorder;
|
||||
@@ -68,6 +70,7 @@ import com.gtnewhorizons.angelica.glsm.states.ImageUnitBinding;
|
||||
import com.gtnewhorizons.angelica.glsm.states.TextureBinding;
|
||||
import com.gtnewhorizons.angelica.glsm.states.TextureUnitArray;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.LineQuads;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.TessellatorEntityIds;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.TessellatorStreamingDrawer;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.TextureInfo;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.TextureInfoCache;
|
||||
@@ -396,6 +399,26 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setEntityIds(int entity, int blockEntity, int item) {
|
||||
if (!isMainThread()) return;
|
||||
final GLContextState glCtx = ctx();
|
||||
final long ids = InstancedAttribs.packEntityInfo(entity, blockEntity, item);
|
||||
if (ids == glCtx.entityIds) return;
|
||||
TessellatorEntityIds.onIdsChanged(glCtx.entityIds, ids);
|
||||
glCtx.entityIds = ids;
|
||||
glCtx.dirtyEntityIdsAttrib = true;
|
||||
}
|
||||
|
||||
public static void flushEntityIds(GLContextState glCtx) {
|
||||
if (!glCtx.dirtyEntityIdsAttrib || glCtx.activeProgram == 0) return;
|
||||
final ImmediateExtendedAttribHandler handler = GLSMHooks.immediateExtendedHandler;
|
||||
if (handler == null || !handler.wantsEntityIds()) return;
|
||||
final long ids = glCtx.entityIds;
|
||||
RENDER_BACKEND.vertexAttrib4f(ImmediateExtendedAttribHandler.LOC_ENTITY_IDS,
|
||||
InstancedAttribs.normalizedId(ids, 0), InstancedAttribs.normalizedId(ids, 16), InstancedAttribs.normalizedId(ids, 32), 0.0f);
|
||||
glCtx.dirtyEntityIdsAttrib = false;
|
||||
}
|
||||
|
||||
|
||||
public static int getMaxBoundTextureUnit() {
|
||||
return ctx().maxBoundTextureUnit;
|
||||
@@ -4823,6 +4846,7 @@ public class GLStateManager {
|
||||
glCtx.dirtyNormalAttrib = true;
|
||||
glCtx.dirtyTexCoordAttrib = true;
|
||||
glCtx.dirtyLightmapAttrib = true;
|
||||
glCtx.dirtyEntityIdsAttrib = true;
|
||||
}
|
||||
|
||||
private static void applyPolygonOffset(GLContextState glCtx) {
|
||||
|
||||
@@ -25,6 +25,8 @@ public final class InstancedAttribs {
|
||||
public static final int OFFSET_LIGHTMAP = HEAD_SIZE;
|
||||
public static final int STRIDE = 72;
|
||||
|
||||
public static final long DEFAULT_ENTITY_IDS = packEntityInfo(-1, 0, -1);
|
||||
|
||||
public static void writeHead(long ptr, float[] colMajor, int off, int colorABGR, int overlayABGR, long entityInfo) {
|
||||
writeRows(ptr, colMajor, off);
|
||||
writeTail(ptr, colorABGR, overlayABGR, entityInfo);
|
||||
@@ -60,13 +62,21 @@ public final class InstancedAttribs {
|
||||
return id == 0xFFFF ? -1 : id;
|
||||
}
|
||||
|
||||
public static float normalizedId(long info, int shift) {
|
||||
return ((info >>> shift) & 0xFFFF) / 65535.0f;
|
||||
}
|
||||
|
||||
public static void pointHead(long base, int stride) {
|
||||
for (int r = 0; r < 3; r++) {
|
||||
GLStateManager.glVertexAttribPointer(LOC_ROW0 + r, 4, GL11.GL_FLOAT, false, stride, base + OFFSET_ROWS + r * 16L);
|
||||
}
|
||||
GLStateManager.glVertexAttribPointer(LOC_COLOR, 4, GL11.GL_UNSIGNED_BYTE, true, stride, base + OFFSET_COLOR);
|
||||
GLStateManager.glVertexAttribPointer(LOC_OVERLAY, 4, GL11.GL_UNSIGNED_BYTE, true, stride, base + OFFSET_OVERLAY);
|
||||
GLStateManager.glVertexAttribIPointer(LOC_ENTITY, 4, GL11.GL_UNSIGNED_SHORT, stride, base + OFFSET_ENTITY);
|
||||
pointEntityIds(LOC_ENTITY, stride, base + OFFSET_ENTITY);
|
||||
}
|
||||
|
||||
public static void pointEntityIds(int location, int stride, long offset) {
|
||||
GLStateManager.glVertexAttribPointer(location, 4, GL11.GL_UNSIGNED_SHORT, true, stride, offset);
|
||||
}
|
||||
|
||||
public static void pointTemplate(long base) {
|
||||
|
||||
@@ -139,6 +139,7 @@ public final class ShaderManager {
|
||||
GLSMHooks.resolvePendingProgram();
|
||||
final DeferredBlendHandler bh = GLSMHooks.blendHandler;
|
||||
if (bh != null) bh.flushDeferredBlend();
|
||||
GLStateManager.flushEntityIds(glCtx);
|
||||
|
||||
// Handle FFP & Iris uniforms
|
||||
final int currentProgramId = glCtx.activeProgram;
|
||||
|
||||
+10
@@ -3,15 +3,18 @@ package com.gtnewhorizons.angelica.glsm.hooks;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormatElement;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public interface ImmediateExtendedAttribHandler {
|
||||
|
||||
int EXT_STRIDE = 12;
|
||||
int ENTITY_IDS_STRIDE = 8;
|
||||
int LOC_MC_ENTITY = 11;
|
||||
int LOC_MID_TEX = 12;
|
||||
int LOC_TANGENT = 13;
|
||||
int LOC_MIDBLOCK = 14;
|
||||
int LOC_ENTITY_IDS = 15;
|
||||
|
||||
int RAW_NORMAL_INDEX = 6;
|
||||
|
||||
@@ -19,6 +22,8 @@ public interface ImmediateExtendedAttribHandler {
|
||||
|
||||
boolean wantsTangent();
|
||||
|
||||
boolean wantsEntityIds();
|
||||
|
||||
boolean wantsExtendedCapture();
|
||||
|
||||
boolean wantsFaceNormals();
|
||||
@@ -65,4 +70,9 @@ public interface ImmediateExtendedAttribHandler {
|
||||
GLStateManager.glEnableVertexAttribArray(LOC_TANGENT);
|
||||
GLStateManager.glVertexAttribPointer(LOC_TANGENT, 4, GL11.GL_BYTE, true, stride, baseOffset + 8);
|
||||
}
|
||||
|
||||
static void setupEntityIdsPointer(long offset, int stride) {
|
||||
GLStateManager.glEnableVertexAttribArray(LOC_ENTITY_IDS);
|
||||
InstancedAttribs.pointEntityIds(LOC_ENTITY_IDS, stride, offset);
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,25 @@ import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFlags;
|
||||
public final class StreamingVaos {
|
||||
private static final int FORMAT_COUNT = VertexFlags.BITSET_SIZE;
|
||||
|
||||
static final int MID_TEX_AND_TANGENT = 1;
|
||||
static final int ENTITY_IDS = 2;
|
||||
private static final int EXTENDED_LAYOUTS = MID_TEX_AND_TANGENT | ENTITY_IDS;
|
||||
|
||||
final int[] persistentVAOs = new int[FORMAT_COUNT];
|
||||
final int[] orphanVAOs = new int[FORMAT_COUNT];
|
||||
|
||||
final int[] extendedPersistentVAOs = new int[FORMAT_COUNT];
|
||||
final int[] extendedOrphanVAOs = new int[FORMAT_COUNT];
|
||||
// An extended draw always carries at least one layout, so row 0 is layout 1
|
||||
private final int[][] extendedPersistentVAOs = new int[EXTENDED_LAYOUTS][FORMAT_COUNT];
|
||||
private final int[][] extendedOrphanVAOs = new int[EXTENDED_LAYOUTS][FORMAT_COUNT];
|
||||
|
||||
final int[] lineQuadPersistentVAOs = new int[FORMAT_COUNT];
|
||||
final int[] lineQuadOrphanVAOs = new int[FORMAT_COUNT];
|
||||
|
||||
int[] extendedPersistent(int layout) {
|
||||
return extendedPersistentVAOs[layout - 1];
|
||||
}
|
||||
|
||||
int[] extendedOrphan(int layout) {
|
||||
return extendedOrphanVAOs[layout - 1];
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package com.gtnewhorizons.angelica.glsm.streaming;
|
||||
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memPutLong;
|
||||
|
||||
/**
|
||||
* Entity, block entity, and item ids of the vertices in the main Tessellator batch.
|
||||
*/
|
||||
public final class TessellatorEntityIds {
|
||||
|
||||
private static Tessellator owner;
|
||||
private static int runCount;
|
||||
private static int[] runStarts = new int[8];
|
||||
private static long[] runIds = new long[8];
|
||||
|
||||
private TessellatorEntityIds() {}
|
||||
|
||||
public static void onIdsChanged(long previous, long next) {
|
||||
final Tessellator tess = Tessellator.instance;
|
||||
if (tess == null || !tess.isDrawing || tess.vertexCount == 0) return;
|
||||
final int start = tess.vertexCount;
|
||||
if (owner != tess) {
|
||||
owner = tess;
|
||||
runCount = 0;
|
||||
}
|
||||
if (runCount == 0) addRun(0, previous);
|
||||
if (runStarts[runCount - 1] == start) {
|
||||
runIds[runCount - 1] = next;
|
||||
if (runCount > 1 && runIds[runCount - 2] == next) runCount--;
|
||||
} else {
|
||||
addRun(start, next);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onReset(Tessellator tess) {
|
||||
if (tess != owner) return;
|
||||
owner = null;
|
||||
runCount = 0;
|
||||
}
|
||||
|
||||
public static boolean hasIdChanges(Tessellator tess) {
|
||||
return tess == owner && runCount > 1;
|
||||
}
|
||||
|
||||
static int runsFor(Tessellator tess, int vertexCount) {
|
||||
if (tess != owner) return 0;
|
||||
int runs = runCount;
|
||||
while (runs > 0 && runStarts[runs - 1] >= vertexCount) runs--;
|
||||
return runs;
|
||||
}
|
||||
|
||||
static long firstRunIds() {
|
||||
return runIds[0];
|
||||
}
|
||||
|
||||
static void write(long dst, int stride, int vertexCount, int runs) {
|
||||
for (int run = 0; run < runs; run++) {
|
||||
final int end = run + 1 < runs ? runStarts[run + 1] : vertexCount;
|
||||
final long ids = runIds[run];
|
||||
for (int vertex = runStarts[run]; vertex < end; vertex++) {
|
||||
memPutLong(dst + (long) vertex * stride, ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addRun(int start, long ids) {
|
||||
if (runCount == runStarts.length) {
|
||||
runStarts = Arrays.copyOf(runStarts, runCount * 2);
|
||||
runIds = Arrays.copyOf(runIds, runCount * 2);
|
||||
}
|
||||
runStarts[runCount] = start;
|
||||
runIds[runCount] = ids;
|
||||
runCount++;
|
||||
}
|
||||
}
|
||||
+64
-28
@@ -130,20 +130,34 @@ public class TessellatorStreamingDrawer {
|
||||
final int extPrim = extHandler == null ? 0 : ImmediateExtendedAttribHandler.extPrimVerts(tess.drawMode, vertexCount);
|
||||
final boolean wantsExt = extHandler != null && extHandler.wantsExtended();
|
||||
final boolean doExt = extPrim != 0 && tess.hasTexture && wantsExt;
|
||||
if (doExt) {
|
||||
final int combinedStride = vertexSize + ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
final int combinedBytes = vertexCount * combinedStride;
|
||||
ensureExtScratch(combinedBytes);
|
||||
interleaveBase(repackAddress, extScratchAddress, vertexCount, vertexSize, combinedStride);
|
||||
// format expansion backfills a normal into rawBuffer, so trust effectiveFlags rather than tess.hasNormals
|
||||
final int normalIndex = (effectiveFlags & VertexFlags.NORMAL_BIT) != 0 ? ImmediateExtendedAttribHandler.RAW_NORMAL_INDEX : -1;
|
||||
extHandler.build(tess.rawBuffer, vertexCount, extPrim, normalIndex, extScratchAddress + vertexSize, combinedStride);
|
||||
extScratch.position(0);
|
||||
extScratch.limit(combinedBytes);
|
||||
uploadAndDrawExtended(extScratch, effectiveFlags, format, combinedStride, tess.drawMode, vertexCount);
|
||||
shrinkExtScratchIfOversized(combinedBytes);
|
||||
} else {
|
||||
uploadAndDraw(repackBuffer, effectiveFlags, format, vertexSize, tess.drawMode, vertexCount);
|
||||
final int idRuns = TessellatorEntityIds.runsFor(tess, vertexCount);
|
||||
final boolean doIds = idRuns > 1 && extHandler != null && extHandler.wantsEntityIds() && !LineQuads.isLineMode(tess.drawMode);
|
||||
final GLContextState swappedCtx = idRuns >= 1 && !doIds ? GLStateManager.ctx() : null;
|
||||
final long restoreIds = swappedCtx != null ? swapEntityIds(swappedCtx, TessellatorEntityIds.firstRunIds()) : 0L;
|
||||
try {
|
||||
if (doExt || doIds) {
|
||||
final int layout = (doExt ? StreamingVaos.MID_TEX_AND_TANGENT : 0) | (doIds ? StreamingVaos.ENTITY_IDS : 0);
|
||||
final int combinedStride = combinedStride(format, layout);
|
||||
final int combinedBytes = vertexCount * combinedStride;
|
||||
ensureExtScratch(combinedBytes);
|
||||
interleaveBase(repackAddress, extScratchAddress, vertexCount, vertexSize, combinedStride);
|
||||
long extAddress = extScratchAddress + vertexSize;
|
||||
if (doExt) {
|
||||
// format expansion backfills a normal into rawBuffer, so trust effectiveFlags rather than tess.hasNormals
|
||||
final int normalIndex = (effectiveFlags & VertexFlags.NORMAL_BIT) != 0 ? ImmediateExtendedAttribHandler.RAW_NORMAL_INDEX : -1;
|
||||
extHandler.build(tess.rawBuffer, vertexCount, extPrim, normalIndex, extAddress, combinedStride);
|
||||
extAddress += ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
}
|
||||
if (doIds) TessellatorEntityIds.write(extAddress, combinedStride, vertexCount, idRuns);
|
||||
extScratch.position(0);
|
||||
extScratch.limit(combinedBytes);
|
||||
uploadAndDrawExtended(extScratch, effectiveFlags, format, layout, combinedStride, tess.drawMode, vertexCount);
|
||||
shrinkExtScratchIfOversized(combinedBytes);
|
||||
} else {
|
||||
uploadAndDraw(repackBuffer, effectiveFlags, format, vertexSize, tess.drawMode, vertexCount);
|
||||
}
|
||||
} finally {
|
||||
if (swappedCtx != null) swapEntityIds(swappedCtx, restoreIds);
|
||||
}
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
@@ -253,7 +267,7 @@ public class TessellatorStreamingDrawer {
|
||||
final long srcBase = memAddress0(packed) + packed.position();
|
||||
final int texOffset = ImmediateExtendedAttribHandler.texOffset(format);
|
||||
final int normalOffset = ImmediateExtendedAttribHandler.normalOffset(format);
|
||||
final int combinedStride = vertexSize + ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
final int combinedStride = combinedStride(format, StreamingVaos.MID_TEX_AND_TANGENT);
|
||||
final int combinedBytes = vertexCount * combinedStride;
|
||||
final boolean locked = GLStateManager.acquireDrawLock();
|
||||
try {
|
||||
@@ -262,7 +276,7 @@ public class TessellatorStreamingDrawer {
|
||||
extHandler.buildPacked(srcBase, vertexSize, 0, texOffset, normalOffset, vertexCount, extPrim, extScratchAddress + vertexSize, combinedStride);
|
||||
extScratch.position(0);
|
||||
extScratch.limit(combinedBytes);
|
||||
uploadAndDrawExtended(extScratch, flags, format, combinedStride, drawMode, vertexCount);
|
||||
uploadAndDrawExtended(extScratch, flags, format, StreamingVaos.MID_TEX_AND_TANGENT, combinedStride, drawMode, vertexCount);
|
||||
shrinkExtScratchIfOversized(combinedBytes);
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
@@ -458,11 +472,11 @@ public class TessellatorStreamingDrawer {
|
||||
}
|
||||
}
|
||||
|
||||
private static void uploadAndDrawExtended(ByteBuffer combined, int flags, VertexFormat format, int combinedStride, int drawMode, int vertexCount) {
|
||||
private static void uploadAndDrawExtended(ByteBuffer combined, int flags, VertexFormat format, int layout, int combinedStride, int drawMode, int vertexCount) {
|
||||
final GLContextState glCtx = GLStateManager.ctx();
|
||||
final StreamingVaos vaos = glCtx.streamingVaos;
|
||||
ensureVAO(vaos.persistentVAOs, vaos.orphanVAOs, flags, format);
|
||||
ensureExtendedVAOs(vaos, flags, format);
|
||||
ensureExtendedVAOs(vaos, flags, format, layout);
|
||||
|
||||
int firstVertex = -1;
|
||||
|
||||
@@ -471,9 +485,9 @@ public class TessellatorStreamingDrawer {
|
||||
}
|
||||
|
||||
if (firstVertex >= 0) {
|
||||
GLStateManager.glBindVertexArray(vaos.extendedPersistentVAOs[flags]);
|
||||
GLStateManager.glBindVertexArray(vaos.extendedPersistent(layout)[flags]);
|
||||
} else {
|
||||
GLStateManager.glBindVertexArray(vaos.extendedOrphanVAOs[flags]);
|
||||
GLStateManager.glBindVertexArray(vaos.extendedOrphan(layout)[flags]);
|
||||
orphanBuffers[flags].upload(combined);
|
||||
firstVertex = 0;
|
||||
}
|
||||
@@ -482,14 +496,14 @@ public class TessellatorStreamingDrawer {
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
}
|
||||
|
||||
private static void ensureExtendedVAOs(StreamingVaos vaos, int flags, VertexFormat format) {
|
||||
final int[] extendedOrphanVAOs = vaos.extendedOrphanVAOs;
|
||||
final int[] extendedPersistentVAOs = vaos.extendedPersistentVAOs;
|
||||
private static void ensureExtendedVAOs(StreamingVaos vaos, int flags, VertexFormat format, int layout) {
|
||||
final int[] extendedOrphanVAOs = vaos.extendedOrphan(layout);
|
||||
final int[] extendedPersistentVAOs = vaos.extendedPersistent(layout);
|
||||
if (extendedOrphanVAOs[flags] == 0) {
|
||||
extendedOrphanVAOs[flags] = GLStateManager.glGenVertexArrays();
|
||||
GLStateManager.glBindVertexArray(extendedOrphanVAOs[flags]);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, orphanBuffers[flags].getBufferId());
|
||||
setupExtendedBufferState(format);
|
||||
setupExtendedBufferState(format, layout);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
}
|
||||
@@ -498,20 +512,42 @@ public class TessellatorStreamingDrawer {
|
||||
extendedPersistentVAOs[flags] = GLStateManager.glGenVertexArrays();
|
||||
GLStateManager.glBindVertexArray(extendedPersistentVAOs[flags]);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, persistentBuffer.getBufferId());
|
||||
setupExtendedBufferState(format);
|
||||
setupExtendedBufferState(format, layout);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setupExtendedBufferState(VertexFormat format) {
|
||||
final int combinedStride = format.getVertexSize() + ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
private static long swapEntityIds(GLContextState glCtx, long ids) {
|
||||
final long previous = glCtx.entityIds;
|
||||
if (previous != ids) {
|
||||
glCtx.entityIds = ids;
|
||||
glCtx.dirtyEntityIdsAttrib = true;
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
|
||||
private static int combinedStride(VertexFormat format, int layout) {
|
||||
int stride = format.getVertexSize();
|
||||
if ((layout & StreamingVaos.MID_TEX_AND_TANGENT) != 0) stride += ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
if ((layout & StreamingVaos.ENTITY_IDS) != 0) stride += ImmediateExtendedAttribHandler.ENTITY_IDS_STRIDE;
|
||||
return stride;
|
||||
}
|
||||
|
||||
private static void setupExtendedBufferState(VertexFormat format, int layout) {
|
||||
final int combinedStride = combinedStride(format, layout);
|
||||
long offset = 0;
|
||||
for (final VertexFormatElement element : format.elementsArray) {
|
||||
element.setupBufferState(offset, combinedStride);
|
||||
offset += element.getByteSize();
|
||||
}
|
||||
ImmediateExtendedAttribHandler.setupExtAttribPointers(offset, combinedStride);
|
||||
if ((layout & StreamingVaos.MID_TEX_AND_TANGENT) != 0) {
|
||||
ImmediateExtendedAttribHandler.setupExtAttribPointers(offset, combinedStride);
|
||||
offset += ImmediateExtendedAttribHandler.EXT_STRIDE;
|
||||
}
|
||||
if ((layout & StreamingVaos.ENTITY_IDS) != 0) {
|
||||
ImmediateExtendedAttribHandler.setupEntityIdsPointer(offset, combinedStride);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureExtScratch(int requiredBytes) {
|
||||
|
||||
@@ -85,7 +85,7 @@ class InstancedFFPDrawGLTest {
|
||||
GLSMHooks.pendingProgramSelection = null;
|
||||
GLSMHooks.blendHandler = null;
|
||||
log.clear();
|
||||
FfpFixture.IntegerInstances.delete();
|
||||
FfpFixture.EntityIdInstances.delete();
|
||||
FfpFixture.resetFfpState();
|
||||
CubeParityFixture.disableDirectionalLight();
|
||||
CubeParityFixture.deleteResources();
|
||||
@@ -196,14 +196,14 @@ class InstancedFFPDrawGLTest {
|
||||
GLStateManager.disableDepthTest();
|
||||
GLStateManager.disableCull();
|
||||
|
||||
FfpFixture.IntegerInstances.build(0.66f);
|
||||
FfpFixture.EntityIdInstances.build(0.66f);
|
||||
|
||||
GLStateManager.glClearColor(0f, 0f, 0f, 1f);
|
||||
GLStateManager.glClear(GL11.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
FfpFixture.IntegerInstances.draw();
|
||||
FfpFixture.EntityIdInstances.draw();
|
||||
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "instanced ivec4 draw must not raise a GL error");
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "instanced entity id draw must not raise a GL error");
|
||||
|
||||
assertPixel(51, 50, 255, 0, 0, "entity -1 must render red");
|
||||
assertPixel(150, 50, 0, 255, 0, "entity 7 must render green");
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.gtnewhorizons.angelica.glsm.streaming;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.EntityIdsOnlyHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.GLCompatTest;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.GlTestSupport;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpFixture;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
|
||||
@GLCompatTest
|
||||
class TessellatorEntityIdsGLTest {
|
||||
|
||||
private static final int[] GREEN = { 0, 255, 0, 255 };
|
||||
private static final int[] BLUE = { 0, 0, 255, 255 };
|
||||
|
||||
private ImmediateExtendedAttribHandler previousHandler;
|
||||
private int program;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
previousHandler = EntityIdsOnlyHandler.install();
|
||||
program = GlTestSupport.program(TessellatorEntityIdsFixture.VERTEX, TessellatorEntityIdsFixture.FRAGMENT);
|
||||
GLStateManager.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
GLStateManager.disableDepthTest();
|
||||
GLStateManager.disableCull();
|
||||
GLStateManager.glViewport(0, 0, 8, 8);
|
||||
GLStateManager.glUseProgram(program);
|
||||
GLStateManager.glClearColor(0, 0, 0, 1);
|
||||
GLStateManager.glClear(GL11.GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
GLStateManager.glUseProgram(0);
|
||||
GLStateManager.glDeleteProgram(program);
|
||||
GLStateManager.glPopAttrib();
|
||||
GLSMHooks.immediateExtendedHandler = previousHandler;
|
||||
}
|
||||
|
||||
@Test
|
||||
void idsChangedMidBatchApplyToTheVerticesAddedAfterTheChange() {
|
||||
TessellatorEntityIdsFixture.drawIdsChangedMidBatch();
|
||||
|
||||
assertColor(1, GREEN, "left quad was added under item 7");
|
||||
assertColor(6, BLUE, "right quad was added under item 50020");
|
||||
}
|
||||
|
||||
@Test
|
||||
void idsChangedAfterTheLastVertexLeaveTheBatchAlone() {
|
||||
TessellatorEntityIdsFixture.drawIdsChangedAfterTheLastVertex();
|
||||
|
||||
assertColor(1, GREEN, "every vertex was added under item 7");
|
||||
assertColor(6, GREEN, "every vertex was added under item 7");
|
||||
}
|
||||
|
||||
private static void assertColor(int x, int[] expected, String message) {
|
||||
final int[] pixel = FfpFixture.readPixel(x, 4);
|
||||
assertArrayEquals(expected, pixel, message + ", got " + Arrays.toString(pixel));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
|
||||
public final class EntityIdsOnlyHandler implements ImmediateExtendedAttribHandler {
|
||||
|
||||
public static ImmediateExtendedAttribHandler install() {
|
||||
final ImmediateExtendedAttribHandler previous = GLSMHooks.immediateExtendedHandler;
|
||||
GLSMHooks.immediateExtendedHandler = new EntityIdsOnlyHandler();
|
||||
GLStateManager.ctx().dirtyEntityIdsAttrib = true;
|
||||
return previous;
|
||||
}
|
||||
|
||||
@Override public boolean wantsExtended() { return false; }
|
||||
@Override public boolean wantsTangent() { return false; }
|
||||
@Override public boolean wantsEntityIds() { return GLStateManager.getActiveProgram() != 0; }
|
||||
@Override public boolean wantsExtendedCapture() { return false; }
|
||||
@Override public boolean wantsFaceNormals() { return false; }
|
||||
@Override public void writeFaceNormals(int[] rawBuffer, int vertexCount) {}
|
||||
@Override public void build(int[] rawBuffer, int vertexCount, int vertsPerPrim, int normalIntIndex, long dstAddr, int dstStride) {}
|
||||
@Override public void buildPacked(long srcBase, int stride, int posOffset, int texOffset, int normalOffset,
|
||||
int vertexCount, int vertsPerPrim, long dstAddr, int dstStride) {}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ public final class FfpFixture {
|
||||
|
||||
private FfpFixture() {}
|
||||
|
||||
public static final class IntegerInstances {
|
||||
public static final class EntityIdInstances {
|
||||
|
||||
private static final int INSTANCES = 3;
|
||||
|
||||
@@ -31,16 +31,17 @@ public final class FfpFixture {
|
||||
layout(location = 5) in vec4 a_InstRow0;
|
||||
layout(location = 6) in vec4 a_InstRow1;
|
||||
layout(location = 7) in vec4 a_InstRow2;
|
||||
layout(location = 11) in uvec4 iris_Entity;
|
||||
layout(location = 11) in vec4 iris_InstEntity;
|
||||
flat out vec3 v_Color;
|
||||
void main() {
|
||||
""";
|
||||
|
||||
private static final String VS_TAIL = """
|
||||
gl_Position = instMV * vec4(a_Position, 1.0);
|
||||
if (iris_Entity.x == 65535u) { v_Color = vec3(1.0, 0.0, 0.0); }
|
||||
else if (iris_Entity.x == 7u) { v_Color = vec3(0.0, 1.0, 0.0); }
|
||||
else if (iris_Entity.x == 50020u) { v_Color = vec3(0.0, 0.0, 1.0); }
|
||||
int entity = int(round(iris_InstEntity.x * 65535.0));
|
||||
if (entity == 65535) { v_Color = vec3(1.0, 0.0, 0.0); }
|
||||
else if (entity == 7) { v_Color = vec3(0.0, 1.0, 0.0); }
|
||||
else if (entity == 50020) { v_Color = vec3(0.0, 0.0, 1.0); }
|
||||
else { v_Color = vec3(1.0, 0.0, 1.0); }
|
||||
}
|
||||
""";
|
||||
@@ -59,7 +60,7 @@ public final class FfpFixture {
|
||||
private static int templateVbo;
|
||||
private static int instanceVbo;
|
||||
|
||||
private IntegerInstances() {}
|
||||
private EntityIdInstances() {}
|
||||
|
||||
public static void build(float spacing) {
|
||||
program = buildProgram();
|
||||
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
package com.gtnewhorizons.angelica.glsm.streaming;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public final class TessellatorEntityIdsFixture {
|
||||
|
||||
public static final String VERTEX = """
|
||||
#version 330 core
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = %d) in vec4 iris_Entity;
|
||||
flat out vec3 v_Color;
|
||||
void main() {
|
||||
gl_Position = vec4(a_Position, 1.0);
|
||||
int item = int(round(iris_Entity.z * 65535.0));
|
||||
v_Color = item == 7 ? vec3(0.0, 1.0, 0.0) : item == 50020 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
||||
}
|
||||
""".formatted(ImmediateExtendedAttribHandler.LOC_ENTITY_IDS);
|
||||
|
||||
public static final String FRAGMENT = """
|
||||
#version 330 core
|
||||
flat in vec3 v_Color;
|
||||
out vec4 fragColor;
|
||||
void main() { fragColor = vec4(v_Color, 1.0); }
|
||||
""";
|
||||
|
||||
private TessellatorEntityIdsFixture() {}
|
||||
|
||||
public static void drawIdsChangedMidBatch() {
|
||||
draw(() -> {
|
||||
GLStateManager.setEntityIds(-1, 0, 7);
|
||||
startQuads();
|
||||
addQuad(-1.0f, 0.0f);
|
||||
GLStateManager.setEntityIds(-1, 0, 50020);
|
||||
addQuad(0.0f, 1.0f);
|
||||
GLStateManager.setEntityIds(-1, 0, -1);
|
||||
});
|
||||
}
|
||||
|
||||
public static void drawIdsChangedAfterTheLastVertex() {
|
||||
draw(() -> {
|
||||
GLStateManager.setEntityIds(-1, 0, 7);
|
||||
startQuads();
|
||||
addQuad(-1.0f, 1.0f);
|
||||
GLStateManager.setEntityIds(-1, 0, 50020);
|
||||
});
|
||||
}
|
||||
|
||||
private static void draw(Runnable fill) {
|
||||
final Tessellator tess = Tessellator.instance;
|
||||
final int[] savedRawBuffer = tess.rawBuffer;
|
||||
final int savedRawBufferSize = tess.rawBufferSize;
|
||||
final int savedRawBufferIndex = tess.rawBufferIndex;
|
||||
final int savedVertexCount = tess.vertexCount;
|
||||
final int savedDrawMode = tess.drawMode;
|
||||
final boolean savedIsDrawing = tess.isDrawing;
|
||||
final boolean savedHasTexture = tess.hasTexture;
|
||||
final boolean savedHasColor = tess.hasColor;
|
||||
final boolean savedHasNormals = tess.hasNormals;
|
||||
final boolean savedHasBrightness = tess.hasBrightness;
|
||||
try {
|
||||
fill.run();
|
||||
TessellatorStreamingDrawer.draw(tess);
|
||||
} finally {
|
||||
TessellatorEntityIds.onReset(tess);
|
||||
GLStateManager.setEntityIds(-1, 0, -1);
|
||||
tess.rawBuffer = savedRawBuffer;
|
||||
tess.rawBufferSize = savedRawBufferSize;
|
||||
tess.rawBufferIndex = savedRawBufferIndex;
|
||||
tess.vertexCount = savedVertexCount;
|
||||
tess.drawMode = savedDrawMode;
|
||||
tess.isDrawing = savedIsDrawing;
|
||||
tess.hasTexture = savedHasTexture;
|
||||
tess.hasColor = savedHasColor;
|
||||
tess.hasNormals = savedHasNormals;
|
||||
tess.hasBrightness = savedHasBrightness;
|
||||
}
|
||||
}
|
||||
|
||||
private static void startQuads() {
|
||||
final Tessellator tess = Tessellator.instance;
|
||||
tess.rawBuffer = new int[64];
|
||||
tess.rawBufferSize = tess.rawBuffer.length;
|
||||
tess.rawBufferIndex = 0;
|
||||
tess.vertexCount = 0;
|
||||
tess.drawMode = GL11.GL_QUADS;
|
||||
tess.hasTexture = false;
|
||||
tess.hasColor = false;
|
||||
tess.hasNormals = false;
|
||||
tess.hasBrightness = false;
|
||||
tess.isDrawing = true;
|
||||
}
|
||||
|
||||
private static void addQuad(float left, float right) {
|
||||
addVertex(left, -1.0f);
|
||||
addVertex(right, -1.0f);
|
||||
addVertex(right, 1.0f);
|
||||
addVertex(left, 1.0f);
|
||||
}
|
||||
|
||||
private static void addVertex(float x, float y) {
|
||||
final Tessellator tess = Tessellator.instance;
|
||||
final int base = tess.rawBufferIndex;
|
||||
tess.rawBuffer[base] = Float.floatToRawIntBits(x);
|
||||
tess.rawBuffer[base + 1] = Float.floatToRawIntBits(y);
|
||||
tess.rawBuffer[base + 2] = Float.floatToRawIntBits(0.0f);
|
||||
tess.rawBufferIndex += 8;
|
||||
tess.vertexCount++;
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.GlTestSupport;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.CubeInstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@Tag("glsm-sdl")
|
||||
@ExtendWith(GlsmSdlFrameExtension.class)
|
||||
class GlsmSdlAttribBindingTest {
|
||||
|
||||
private static final String INSTANCED_VERTEX = """
|
||||
#version 330 core
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = %d) in vec4 iris_InstEntity;
|
||||
layout(location = %d) in vec4 iris_CubeTex;
|
||||
void main() { gl_Position = vec4(a_Position, 1.0) + iris_InstEntity + iris_CubeTex; }
|
||||
""".formatted(InstancedAttribs.LOC_ENTITY, CubeInstancedAttribs.LOC_CUBE_TEX);
|
||||
|
||||
private static final String IMMEDIATE_VERTEX = """
|
||||
#version 330 core
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = %d) in vec4 mc_Entity;
|
||||
layout(location = %d) in vec4 iris_Entity;
|
||||
void main() { gl_Position = vec4(a_Position, 1.0) + mc_Entity + iris_Entity; }
|
||||
""".formatted(ImmediateExtendedAttribHandler.LOC_MC_ENTITY, ImmediateExtendedAttribHandler.LOC_ENTITY_IDS);
|
||||
|
||||
@Test
|
||||
void instancedEntityIdsStayAtTheInstanceSlot() {
|
||||
final int program = linkWithIrisBindings(INSTANCED_VERTEX);
|
||||
try {
|
||||
assertEquals(InstancedAttribs.LOC_ENTITY, GLStateManager.glGetAttribLocation(program, "iris_InstEntity"));
|
||||
assertEquals(CubeInstancedAttribs.LOC_CUBE_TEX, GLStateManager.glGetAttribLocation(program, "iris_CubeTex"));
|
||||
} finally {
|
||||
GLStateManager.glDeleteProgram(program);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void immediateEntityIdsDoNotMoveOntoMcEntity() {
|
||||
final int program = linkWithIrisBindings(IMMEDIATE_VERTEX);
|
||||
try {
|
||||
assertEquals(ImmediateExtendedAttribHandler.LOC_MC_ENTITY, GLStateManager.glGetAttribLocation(program, "mc_Entity"));
|
||||
assertEquals(ImmediateExtendedAttribHandler.LOC_ENTITY_IDS, GLStateManager.glGetAttribLocation(program, "iris_Entity"));
|
||||
} finally {
|
||||
GLStateManager.glDeleteProgram(program);
|
||||
}
|
||||
}
|
||||
|
||||
private static int linkWithIrisBindings(String vertexSource) {
|
||||
final int program = GLStateManager.glCreateProgram();
|
||||
GLStateManager.glAttachShader(program, GlTestSupport.compile(GL20.GL_VERTEX_SHADER, vertexSource));
|
||||
GLStateManager.glAttachShader(program, GlTestSupport.compile(GL20.GL_FRAGMENT_SHADER, GlTestSupport.TRIVIAL_FS));
|
||||
GLStateManager.glBindAttribLocation(program, InstancedAttribs.LOC_ENTITY, "iris_InstEntity");
|
||||
GLStateManager.glBindAttribLocation(program, ImmediateExtendedAttribHandler.LOC_MC_ENTITY, "mc_Entity");
|
||||
GLStateManager.glLinkProgram(program);
|
||||
return program;
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ class GlsmSdlFfpTest {
|
||||
GLStateManager.setFfpInstancing(Instancing.NONE);
|
||||
CubeParityFixture.deleteResources();
|
||||
ParticleParityFixture.deleteResources();
|
||||
FfpFixture.IntegerInstances.delete();
|
||||
FfpFixture.EntityIdInstances.delete();
|
||||
}
|
||||
|
||||
private static void bindBaseTexture() {
|
||||
@@ -172,11 +172,11 @@ class GlsmSdlFfpTest {
|
||||
|
||||
@Test
|
||||
void entityAttribSelectsColorPerInstance() {
|
||||
FfpFixture.IntegerInstances.build(0.6f);
|
||||
FfpFixture.EntityIdInstances.build(0.6f);
|
||||
|
||||
GlsmSdlHeadlessRig.beginFrameAndClear();
|
||||
|
||||
FfpFixture.IntegerInstances.draw();
|
||||
FfpFixture.EntityIdInstances.draw();
|
||||
|
||||
final int[] pixels = GlsmSdlHeadlessRig.readTarget();
|
||||
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.EntityIdsOnlyHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.GlTestSupport;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.TessellatorEntityIdsFixture;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import static com.gtnewhorizons.angelica.sdlgpu.glsm.GlsmSdlHeadlessRig.BLUE;
|
||||
import static com.gtnewhorizons.angelica.sdlgpu.glsm.GlsmSdlHeadlessRig.GREEN;
|
||||
import static com.gtnewhorizons.angelica.sdlgpu.glsm.GlsmSdlHeadlessRig.SIZE;
|
||||
|
||||
@Tag("glsm-sdl")
|
||||
@ExtendWith(GlsmSdlFrameExtension.class)
|
||||
class GlsmSdlTessellatorEntityIdsTest {
|
||||
|
||||
private ImmediateExtendedAttribHandler previousHandler;
|
||||
private int program;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
previousHandler = EntityIdsOnlyHandler.install();
|
||||
program = GlTestSupport.program(TessellatorEntityIdsFixture.VERTEX, TessellatorEntityIdsFixture.FRAGMENT);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
GLStateManager.glUseProgram(0);
|
||||
GLStateManager.glDeleteProgram(program);
|
||||
GLSMHooks.immediateExtendedHandler = previousHandler;
|
||||
}
|
||||
|
||||
@Test
|
||||
void idsChangedMidBatchApplyToTheVerticesAddedAfterTheChange() {
|
||||
GlsmSdlHeadlessRig.beginFrameAndClear();
|
||||
GLStateManager.glUseProgram(program);
|
||||
TessellatorEntityIdsFixture.drawIdsChangedMidBatch();
|
||||
|
||||
final int[] pixels = GlsmSdlHeadlessRig.readTarget();
|
||||
GlsmSdlHeadlessRig.assertPixel(pixels, SIZE, SIZE / 4, SIZE / 2, GREEN, "left quad was added under item 7");
|
||||
GlsmSdlHeadlessRig.assertPixel(pixels, SIZE, 3 * SIZE / 4, SIZE / 2, BLUE, "right quad was added under item 50020");
|
||||
}
|
||||
|
||||
@Test
|
||||
void idsChangedAfterTheLastVertexLeaveTheBatchAlone() {
|
||||
GlsmSdlHeadlessRig.beginFrameAndClear();
|
||||
GLStateManager.glUseProgram(program);
|
||||
TessellatorEntityIdsFixture.drawIdsChangedAfterTheLastVertex();
|
||||
|
||||
final int[] pixels = GlsmSdlHeadlessRig.readTarget();
|
||||
GlsmSdlHeadlessRig.assertPixel(pixels, SIZE, SIZE / 4, SIZE / 2, GREEN, "every vertex was added under item 7");
|
||||
GlsmSdlHeadlessRig.assertPixel(pixels, SIZE, 3 * SIZE / 4, SIZE / 2, GREEN, "every vertex was added under item 7");
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ public final class ImmediateExtendedAttribs implements ImmediateExtendedAttribHa
|
||||
|
||||
private static final int WANTS_MID = 1;
|
||||
private static final int WANTS_TANGENT = 2;
|
||||
private static final int WANTS_ENTITY_IDS = 4;
|
||||
|
||||
private static final int NEUTRAL_TANGENT = NormI8.pack(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
@@ -57,6 +58,7 @@ public final class ImmediateExtendedAttribs implements ImmediateExtendedAttribHa
|
||||
wants = 0;
|
||||
if (GLStateManager.glGetAttribLocation(program, "mc_midTexCoord") >= 0) wants |= WANTS_MID;
|
||||
if (GLStateManager.glGetAttribLocation(program, "at_tangent") >= 0) wants |= WANTS_TANGENT;
|
||||
if (GLStateManager.glGetAttribLocation(program, "iris_Entity") == LOC_ENTITY_IDS) wants |= WANTS_ENTITY_IDS;
|
||||
programWantsExtCache.put(program, wants);
|
||||
}
|
||||
currentProgramWants = wants;
|
||||
@@ -83,8 +85,7 @@ public final class ImmediateExtendedAttribs implements ImmediateExtendedAttribHa
|
||||
|
||||
@Override
|
||||
public boolean wantsExtended() {
|
||||
GLSMHooks.resolvePendingProgram();
|
||||
return Iris.enabled && currentProgramWants != 0 && GLStateManager.getActiveProgram() != 0;
|
||||
return programWants(WANTS_MID | WANTS_TANGENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,6 +93,17 @@ public final class ImmediateExtendedAttribs implements ImmediateExtendedAttribHa
|
||||
return (currentProgramWants & WANTS_TANGENT) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsEntityIds() {
|
||||
return programWants(WANTS_ENTITY_IDS);
|
||||
}
|
||||
|
||||
private static boolean programWants(int mask) {
|
||||
if (!Iris.enabled) return false;
|
||||
GLSMHooks.resolvePendingProgram();
|
||||
return (currentProgramWants & mask) != 0 && GLStateManager.getActiveProgram() != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsExtendedCapture() {
|
||||
return Iris.enabled && Iris.getCurrentPack().isPresent();
|
||||
|
||||
@@ -26,6 +26,7 @@ import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
import net.coderbot.iris.samplers.IrisSamplers;
|
||||
import net.coderbot.iris.texture.pbr.PBRTextureManager;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.coderbot.iris.uniforms.SystemTimeUniforms;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -65,6 +66,9 @@ public class IrisGLSMBridge {
|
||||
|
||||
public static void installImmediateExtendedHandler() {
|
||||
GLSMHooks.immediateExtendedHandler = new ImmediateExtendedAttribs();
|
||||
final CapturedRenderingState state = CapturedRenderingState.INSTANCE;
|
||||
state.setEntityIdsListener(() -> GLStateManager.setEntityIds(
|
||||
state.getCurrentRenderedEntity(), state.getCurrentRenderedBlockEntity(), state.getCurrentRenderedItem()));
|
||||
}
|
||||
|
||||
public static void installPostTransformHook() {
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.gtnewhorizons.angelica.glsm.ffp.CubeParams;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.TessellatorEntityIds;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.TessellatorStreamingDrawer;
|
||||
import com.gtnewhorizons.angelica.glsm.states.AlphaState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
@@ -652,6 +653,7 @@ public final class ModelPartBatcher {
|
||||
private TessellatorRoute routeTessellatorDraw(Tessellator tess) {
|
||||
if (!active || mode != Mode.BLOCK_ENTITIES || !GLStateManager.isMainThread() || !BatchEligibility.insideRenderer()) return TessellatorRoute.DRAW_NOW;
|
||||
if (!tess.isDrawing || tess.drawMode != GL11.GL_QUADS || tess.vertexCount == 0 || (tess.vertexCount & 3) != 0) return TessellatorRoute.DRAW_NOW;
|
||||
if (shaderPipeline != null && TessellatorEntityIds.hasIdChanges(tess)) return TessellatorRoute.DRAW_NOW;
|
||||
if (DisplayListManager.isRecording() || !GLStateManager.glIsEnabled(GL11.GL_DEPTH_TEST) || !unitTexIdentity()) return TessellatorRoute.DRAW_NOW;
|
||||
if (GLStateManager.getActiveProgram() != (shaderPipeline != null ? shaderPipeline.getActivePassProgramId() : 0)) return TessellatorRoute.DRAW_NOW;
|
||||
final TesrMaterial material = EntityMaterials.fromCurrentState(true);
|
||||
|
||||
@@ -5,6 +5,7 @@ package net.coderbot.iris.gl.shader;
|
||||
import com.gtnewhorizons.angelica.glsm.GLDebug;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.shader.ProgramBinaryCache;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -24,8 +25,8 @@ public class ProgramCreator {
|
||||
public static final int AT_MIDBLOCK = ImmediateExtendedAttribHandler.LOC_MIDBLOCK;
|
||||
|
||||
// TODO: This is *really* hardcoded, we need to refactor this to support external calls to glBindAttribLocation
|
||||
private static final String[] ATTRIBUTE_NAMES = { "iris_Entity", "mc_Entity", "mc_midTexCoord", "iris_CubeTangent", "at_tangent", "at_midBlock" };
|
||||
private static final int[] ATTRIBUTE_LOCATIONS = { MC_ENTITY, MC_ENTITY, MC_MID_TEX_COORD, AT_TANGENT, AT_TANGENT, AT_MIDBLOCK };
|
||||
private static final String[] ATTRIBUTE_NAMES = { "iris_InstEntity", "mc_Entity", "mc_midTexCoord", "iris_CubeTangent", "at_tangent", "at_midBlock" };
|
||||
private static final int[] ATTRIBUTE_LOCATIONS = { InstancedAttribs.LOC_ENTITY, MC_ENTITY, MC_MID_TEX_COORD, AT_TANGENT, AT_TANGENT, AT_MIDBLOCK };
|
||||
|
||||
@Nullable
|
||||
public static ProgramBinaryCache.Key cacheKey() {
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
package net.coderbot.iris.pipeline.transform;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.shader.ShaderIndex;
|
||||
import com.gtnewhorizons.angelica.glsm.shader.ShaderType;
|
||||
import net.coderbot.iris.pipeline.transform.parameter.AttributeParameters;
|
||||
import org.antlr.v4.runtime.CommonToken;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.taumc.glsl.Transformer;
|
||||
import org.taumc.glsl.grammar.GLSLParser;
|
||||
|
||||
class EntityPatcher {
|
||||
|
||||
private static final String[] ID_NAMES = { "entityId", "blockEntityId", "currentRenderedItemId" };
|
||||
private static final String[] ID_COMPONENTS = { ".x", ".y", ".z" };
|
||||
|
||||
public static void patchEntityId(Transformer transformer, AttributeParameters parameters) {
|
||||
if (!hasInstanceAttributes(parameters)) {
|
||||
injectUniformIfUndeclared(transformer, "entityId", "uniform int entityId;");
|
||||
injectUniformIfUndeclared(transformer, "blockEntityId", "uniform int blockEntityId;");
|
||||
injectUniformIfUndeclared(transformer, "currentRenderedItemId", "uniform int currentRenderedItemId;");
|
||||
return;
|
||||
}
|
||||
|
||||
removeIfDeclared(transformer, "entityId");
|
||||
removeIfDeclared(transformer, "blockEntityId");
|
||||
removeIfDeclared(transformer, "currentRenderedItemId");
|
||||
|
||||
final String geometryIn = parameters.hasTesselation ? "iris_entityInfoTES" : "iris_entityInfo";
|
||||
final String info = switch (parameters.type) {
|
||||
case GEOMETRY -> geometryIn + "[0]";
|
||||
@@ -26,17 +23,37 @@ class EntityPatcher {
|
||||
case TESSELATION_EVAL -> "iris_entityInfoTCS[0]";
|
||||
default -> "iris_entityInfo";
|
||||
};
|
||||
transformer.replaceExpression("entityId", info + ".x", GLSLParser::postfix_expression);
|
||||
transformer.replaceExpression("blockEntityId", info + ".y", GLSLParser::postfix_expression);
|
||||
transformer.replaceExpression("currentRenderedItemId", info + ".z", GLSLParser::postfix_expression);
|
||||
final StringBuilder assignments = new StringBuilder();
|
||||
for (int i = 0; i < ID_NAMES.length; i++) {
|
||||
final String name = ID_NAMES[i];
|
||||
if (!transformer.containsCall(name)) continue;
|
||||
final GLSLParser.Typeless_declarationContext global = topLevelDeclarator(transformer, name);
|
||||
if (global != null) {
|
||||
if (!isUniform(global)) continue;
|
||||
// removeVariable takes the last declaration it finds by name, which can be a pack local
|
||||
final String removed = "iris_removed_" + name;
|
||||
((CommonToken) global.IDENTIFIER().getSymbol()).setText(removed);
|
||||
transformer.removeVariable(removed);
|
||||
}
|
||||
transformer.injectVariable("int " + name + ";");
|
||||
assignments.append(name).append(" = ").append(info).append(ID_COMPONENTS[i]).append("; ");
|
||||
}
|
||||
if (parameters.type != ShaderType.VERTEX && assignments.length() > 0) {
|
||||
transformer.prependMain("{ " + assignments + "}");
|
||||
}
|
||||
|
||||
switch (parameters.type) {
|
||||
case VERTEX -> {
|
||||
final boolean instanced = hasInstanceAttributes(parameters);
|
||||
final String input = instanced ? "iris_InstEntity" : "iris_Entity";
|
||||
final int location = instanced ? InstancedAttribs.LOC_ENTITY : ImmediateExtendedAttribHandler.LOC_ENTITY_IDS;
|
||||
removeIfDeclared(transformer, "iris_Entity");
|
||||
transformer.injectVariable("layout(location = " + InstancedAttribs.LOC_ENTITY + ") in uvec4 iris_Entity;");
|
||||
removeIfDeclared(transformer, "iris_InstEntity");
|
||||
transformer.injectVariable("layout(location = " + location + ") in vec4 " + input + ";");
|
||||
transformer.injectVariable("flat out ivec3 iris_entityInfo;");
|
||||
transformer.prependMain("iris_entityInfo = ivec3(iris_Entity.x == 65535u ? -1 : int(iris_Entity.x), "
|
||||
+ "iris_Entity.y == 65535u ? -1 : int(iris_Entity.y), iris_Entity.z == 65535u ? -1 : int(iris_Entity.z));");
|
||||
transformer.prependMain("{ ivec3 iris_ids = ivec3(round(" + input + ".xyz * 65535.0)); "
|
||||
+ "iris_entityInfo = ivec3(iris_ids.x == 65535 ? -1 : iris_ids.x, iris_ids.y == 65535 ? -1 : iris_ids.y, "
|
||||
+ "iris_ids.z == 65535 ? -1 : iris_ids.z); " + assignments + "}");
|
||||
}
|
||||
case TESSELATION_CONTROL -> {
|
||||
transformer.injectVariable("flat out ivec3 iris_entityInfoTCS[];");
|
||||
@@ -113,6 +130,27 @@ class EntityPatcher {
|
||||
}
|
||||
}
|
||||
|
||||
private static GLSLParser.Typeless_declarationContext topLevelDeclarator(Transformer transformer, String name) {
|
||||
final GLSLParser.Typeless_declarationContext[] found = new GLSLParser.Typeless_declarationContext[1];
|
||||
transformer.mutateTree(root -> {
|
||||
for (GLSLParser.External_declarationContext external : root.external_declaration()) {
|
||||
final GLSLParser.DeclarationContext declaration = external.declaration();
|
||||
if (declaration == null || declaration.init_declarator_list() == null) continue;
|
||||
for (GLSLParser.Typeless_declarationContext declarator : ShaderIndex.declarators(declaration.init_declarator_list())) {
|
||||
if (declarator.IDENTIFIER().getText().equals(name)) found[0] = declarator;
|
||||
}
|
||||
}
|
||||
});
|
||||
return found[0];
|
||||
}
|
||||
|
||||
private static boolean isUniform(GLSLParser.Typeless_declarationContext declarator) {
|
||||
final ParserRuleContext parent = declarator.getParent();
|
||||
final GLSLParser.Init_declarator_listContext list = (GLSLParser.Init_declarator_listContext)
|
||||
(parent instanceof GLSLParser.Single_declarationContext ? parent.getParent() : parent);
|
||||
return ShaderIndex.hasStorageQualifier(list.single_declaration().fully_specified_type().type_qualifier(), "uniform");
|
||||
}
|
||||
|
||||
private static boolean hasInstanceAttributes(AttributeParameters parameters) {
|
||||
return parameters.instancing.hasInstanceHead();
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ public class CapturedRenderingState {
|
||||
@Getter
|
||||
private int currentRenderedItem = -1;
|
||||
private Runnable itemIdListener = null;
|
||||
private Runnable entityIdsListener = null;
|
||||
private final IntArrayList itemStack = new IntArrayList();
|
||||
private final IntArrayList entityStack = new IntArrayList();
|
||||
private final IntArrayList blockEntityStack = new IntArrayList();
|
||||
@@ -88,15 +89,25 @@ public class CapturedRenderingState {
|
||||
if (this.blockEntityIdListener != null) {
|
||||
this.blockEntityIdListener.run();
|
||||
}
|
||||
notifyEntityIdsChanged();
|
||||
}
|
||||
|
||||
private void setCurrentEntity(int entity) {
|
||||
if (currentRenderedEntity == entity) return;
|
||||
this.currentRenderedEntity = entity;
|
||||
|
||||
if (this.entityIdListener != null) {
|
||||
this.entityIdListener.run();
|
||||
private void applyCurrentEntityAndItem(int entity, int item) {
|
||||
final boolean entityChanged = currentRenderedEntity != entity;
|
||||
final boolean itemChanged = currentRenderedItem != item;
|
||||
if (entityChanged) {
|
||||
this.currentRenderedEntity = entity;
|
||||
if (this.entityIdListener != null) {
|
||||
this.entityIdListener.run();
|
||||
}
|
||||
}
|
||||
if (itemChanged) {
|
||||
this.currentRenderedItem = item;
|
||||
if (this.itemIdListener != null) {
|
||||
this.itemIdListener.run();
|
||||
}
|
||||
}
|
||||
if (entityChanged || itemChanged) notifyEntityIdsChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,15 +115,13 @@ public class CapturedRenderingState {
|
||||
*/
|
||||
public void setCurrentEntityAndItem(int entity, int item) {
|
||||
IrisDisplayListState.recordEntityAndItem(entity, item);
|
||||
setCurrentEntity(entity);
|
||||
applyCurrentRenderedItem(item);
|
||||
applyCurrentEntityAndItem(entity, item);
|
||||
}
|
||||
|
||||
public void setCurrentNamedEntity(NamespacedId entity) {
|
||||
IrisDisplayListState.recordNamedEntity(entity);
|
||||
final var ids = BlockRenderingSettings.INSTANCE.getEntityIds();
|
||||
setCurrentEntity(ids == null ? -1 : ids.applyAsInt(entity));
|
||||
applyCurrentRenderedItem(0);
|
||||
applyCurrentEntityAndItem(ids == null ? -1 : ids.applyAsInt(entity), 0);
|
||||
}
|
||||
|
||||
public void pushCurrentEntityAndItem() {
|
||||
@@ -123,15 +132,13 @@ public class CapturedRenderingState {
|
||||
|
||||
public void setCurrentRenderedEntity(Entity entity) {
|
||||
IrisDisplayListState.recordEntity(entity);
|
||||
setCurrentEntity(EntityIdHelper.getEntityId(entity));
|
||||
applyCurrentRenderedItem(0);
|
||||
applyCurrentEntityAndItem(EntityIdHelper.getEntityId(entity), 0);
|
||||
}
|
||||
|
||||
public void popCurrentEntityAndItem() {
|
||||
IrisDisplayListState.recordEntityScope(false);
|
||||
// Restore the playback caller, never the IDs seen while compiling the list.
|
||||
setCurrentEntity(entityStack.popInt());
|
||||
applyCurrentRenderedItem(itemStack.popInt());
|
||||
applyCurrentEntityAndItem(entityStack.popInt(), itemStack.popInt());
|
||||
}
|
||||
|
||||
public void setCurrentEntityColor(float r, float g, float b, float a) {
|
||||
@@ -209,6 +216,18 @@ public class CapturedRenderingState {
|
||||
if (this.itemIdListener != null) {
|
||||
this.itemIdListener.run();
|
||||
}
|
||||
notifyEntityIdsChanged();
|
||||
}
|
||||
|
||||
public void setEntityIdsListener(Runnable listener) {
|
||||
this.entityIdsListener = listener;
|
||||
notifyEntityIdsChanged();
|
||||
}
|
||||
|
||||
private void notifyEntityIdsChanged() {
|
||||
if (this.entityIdsListener != null) {
|
||||
this.entityIdsListener.run();
|
||||
}
|
||||
}
|
||||
|
||||
public ValueUpdateNotifier getEntityIdNotifier() {
|
||||
|
||||
+7
@@ -1,11 +1,13 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.ffp;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.TessellatorEntityIds;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.ModelPartBatcher;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
/**
|
||||
@@ -19,4 +21,9 @@ public class MixinTessellator_CoreProfile {
|
||||
private void angelica$coreProfileDraw(CallbackInfoReturnable<Integer> cir) {
|
||||
cir.setReturnValue(ModelPartBatcher.drawTessellator((Tessellator) (Object) this));
|
||||
}
|
||||
|
||||
@Inject(method = "reset", at = @At("HEAD"))
|
||||
private void angelica$forgetEntityIds(CallbackInfo ci) {
|
||||
TessellatorEntityIds.onReset((Tessellator) (Object) this);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.coderbot.iris.pipeline;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.EntityIdsOnlyHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.GLCoreTest;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.GlTestSupport;
|
||||
@@ -7,6 +8,7 @@ import com.gtnewhorizons.angelica.glsm.ffp.Instancing;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpFixture;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.shader.ShaderType;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.BatchEligibility;
|
||||
@@ -403,15 +405,19 @@ class IrisInstancingGLTest {
|
||||
""";
|
||||
final String fragmentSource = """
|
||||
#version 120
|
||||
uniform int entityId;
|
||||
uniform int blockEntityId;
|
||||
uniform int entityId, blockEntityId;
|
||||
uniform int currentRenderedItemId;
|
||||
uniform int expectedId;
|
||||
// a parameter and a local sharing the id names keep their own values
|
||||
bool isFortyTwo(int entityId) { return entityId == 42; }
|
||||
void main() {
|
||||
bool matches = entityId == expectedId && blockEntityId == expectedId && currentRenderedItemId == expectedId;
|
||||
gl_FragData[0] = matches ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
|
||||
bool shadowed = isFortyTwo(42);
|
||||
{ int blockEntityId = 7; shadowed = shadowed && blockEntityId == 7; }
|
||||
gl_FragData[0] = matches && shadowed ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
|
||||
}
|
||||
""";
|
||||
final int[] ids = { -1, 0, 32767, 32768, 45020, 50020, 50072, 65534 };
|
||||
final int vao = GLStateManager.glGenVertexArrays();
|
||||
final int buffer = GLStateManager.glGenBuffers();
|
||||
GLStateManager.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
|
||||
@@ -432,7 +438,7 @@ class IrisInstancingGLTest {
|
||||
GLStateManager.glEnableVertexAttribArray(InstancedAttribs.LOC_ENTITY);
|
||||
GLStateManager.glVertexAttribDivisor(InstancedAttribs.LOC_ENTITY, 1);
|
||||
final ByteBuffer data = BufferUtils.createByteBuffer(InstancedAttribs.HEAD_SIZE);
|
||||
for (int id : new int[] { -1, 0, 32767, 32768, 45020, 50020, 50072, 65534 }) {
|
||||
for (int id : ids) {
|
||||
data.putLong(InstancedAttribs.OFFSET_ENTITY, InstancedAttribs.packEntityInfo(id, id, id));
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
GLStateManager.glUniform1i(GLStateManager.glGetUniformLocation(program, "expectedId"), id);
|
||||
@@ -449,6 +455,30 @@ class IrisInstancingGLTest {
|
||||
GLStateManager.glDeleteProgram(program);
|
||||
}
|
||||
}
|
||||
|
||||
final int program = linkProgram("highIdsImmediate", TransformPatcher.patchAttributes(vertexSource, null, null, null, fragmentSource, TEX_LM, false));
|
||||
final ImmediateExtendedAttribHandler previousHandler = GLSMHooks.immediateExtendedHandler;
|
||||
try {
|
||||
EntityIdsOnlyHandler.install();
|
||||
GLStateManager.glUseProgram(program);
|
||||
GLStateManager.glUniform1i(GLStateManager.glGetUniformLocation(program, "iris_currentAlphaFunc"), 7);
|
||||
GLStateManager.glBindVertexArray(vao);
|
||||
for (int id : ids) {
|
||||
GLStateManager.setEntityIds(id, id, id);
|
||||
GLStateManager.glUniform1i(GLStateManager.glGetUniformLocation(program, "expectedId"), id);
|
||||
GLStateManager.glClearColor(0, 0, 0, 1);
|
||||
GLStateManager.glClear(GL11.GL_COLOR_BUFFER_BIT);
|
||||
GLStateManager.glDrawArrays(GL11.GL_TRIANGLES, 0, 3);
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "draw error");
|
||||
final int[] pixel = FfpFixture.readPixel(0, 0);
|
||||
assertEquals(255, pixel[1], "immediate material ID " + id + " pixel " + Arrays.toString(pixel));
|
||||
}
|
||||
} finally {
|
||||
GLStateManager.glUseProgram(0);
|
||||
GLStateManager.glDeleteProgram(program);
|
||||
GLSMHooks.immediateExtendedHandler = previousHandler;
|
||||
GLStateManager.setEntityIds(-1, 0, -1);
|
||||
}
|
||||
} finally {
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
|
||||
+14
-9
@@ -5,6 +5,7 @@ import com.gtnewhorizons.angelica.glsm.ffp.CubeInstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.InstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.Instancing;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.ParticleInstancedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability;
|
||||
import net.coderbot.iris.pipeline.transform.parameter.AttributeParameters;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
@@ -259,9 +260,10 @@ class AttributeTransformerInstancedTest {
|
||||
assertLacks(v, "uniform int entityId;");
|
||||
assertLacks(v, "uniform int blockEntityId;");
|
||||
assertLacks(v, "uniform int currentRenderedItemId;");
|
||||
assertHas(v, "layout(location = " + InstancedAttribs.LOC_ENTITY + ") in uvec4 iris_Entity;");
|
||||
assertHas(v, "layout(location = " + InstancedAttribs.LOC_ENTITY + ") in vec4 iris_InstEntity;");
|
||||
assertLacks(v, "in vec4 iris_Entity;");
|
||||
assertHas(v, "flat out ivec3 iris_entityInfo;");
|
||||
assertHas(v, "iris_entityInfo = ivec3(iris_Entity.x == 65535u ? -1 : int(iris_Entity.x), iris_Entity.y == 65535u ? -1 : int(iris_Entity.y), iris_Entity.z == 65535u ? -1 : int(iris_Entity.z));");
|
||||
assertHas(v, "ivec3 iris_ids = ivec3(round(iris_InstEntity.xyz * 65535.0));");
|
||||
|
||||
assertLacks(f, "uniform int entityId;");
|
||||
assertHas(f, "flat in ivec3 iris_entityInfo;");
|
||||
@@ -362,6 +364,8 @@ class AttributeTransformerInstancedTest {
|
||||
assertHas(v, "layout(location = 3) in vec4 iris_CubeDelta");
|
||||
assertHas(v, "layout(location = " + CubeInstancedAttribs.LOC_CUBE_TEX + ") in vec4 iris_CubeTex");
|
||||
assertHas(v, "layout(location = " + CubeInstancedAttribs.LOC_LIGHTMAP_SCALE + ") in vec4 iris_InstLightmapScale");
|
||||
assertHas(v, "layout(location = " + InstancedAttribs.LOC_ENTITY + ") in vec4 iris_InstEntity;");
|
||||
assertLacks(v, "in vec4 iris_Entity;");
|
||||
assertLacks(v, "layout(location = 2) in vec4 iris_MultiTexCoord0");
|
||||
assertHas(v, "vec4 iris_MultiTexCoord0;");
|
||||
assertHas(v, "iris_MultiTexCoord1 = vec4(iris_InstLightmapScale.xy, 0.0, 1.0)");
|
||||
@@ -417,10 +421,11 @@ class AttributeTransformerInstancedTest {
|
||||
assertEquals(ParticleInstancedAttribs.LOC_UV, locationOf(byLocation, "iris_InstUv"));
|
||||
assertEquals(InstancedAttribs.LOC_COLOR, locationOf(byLocation, "iris_InstColor"));
|
||||
assertEquals(InstancedAttribs.LOC_LIGHTMAP, locationOf(byLocation, "iris_InstLightmap"));
|
||||
assertEquals(ImmediateExtendedAttribHandler.LOC_ENTITY_IDS, locationOf(byLocation, "iris_Entity"));
|
||||
|
||||
assertFalse(byLocation.containsKey(7), "location 7 is unused");
|
||||
for (final int loc : byLocation.keySet()) {
|
||||
assertTrue(loc < 11, "unexpected attribute location " + loc + " declared for the particle variant");
|
||||
assertTrue(loc < 11 || loc == ImmediateExtendedAttribHandler.LOC_ENTITY_IDS, "unexpected attribute location " + loc + " declared for the particle variant");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,7 +436,7 @@ class AttributeTransformerInstancedTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void particleEntityIdAndOverlayColorStayAsPlainUniformsLikeTheNonePath() {
|
||||
void particleEntityIdsAndOverlayColorFollowTheNonePath() {
|
||||
final Map<PatchShaderType, String> result = TransformPatcher.patchAttributesInstanced(VERTEX_ENTITY_AND_COLOR, null, null, null, FRAGMENT_ENTITY_AND_COLOR, TEX_LM, false, Instancing.PARTICLE);
|
||||
assertNotNull(result);
|
||||
final String v = result.get(PatchShaderType.VERTEX);
|
||||
@@ -441,16 +446,16 @@ class AttributeTransformerInstancedTest {
|
||||
ShaderParser.parseShader(v);
|
||||
ShaderParser.parseShader(f);
|
||||
|
||||
assertHas(v, "uniform int entityId;");
|
||||
assertLacks(v, "uniform int entityId;");
|
||||
assertHas(v, "layout(location = " + ImmediateExtendedAttribHandler.LOC_ENTITY_IDS + ") in vec4 iris_Entity;");
|
||||
assertHas(v, "uniform vec4 entityColor;");
|
||||
assertLacks(v, "iris_entityInfo");
|
||||
assertLacks(v, "iris_InstOverlay");
|
||||
assertLacks(v, "out vec4 entityColor;");
|
||||
|
||||
assertHas(f, "uniform int entityId;");
|
||||
assertLacks(f, "uniform int entityId;");
|
||||
assertHas(f, "flat in ivec3 iris_entityInfo;");
|
||||
assertHas(f, "uniform vec4 entityColor;");
|
||||
assertLacks(f, "in vec4 entityColor;");
|
||||
assertLacks(f, "flat in ivec3 iris_entityInfo;");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -465,6 +470,6 @@ class AttributeTransformerInstancedTest {
|
||||
|
||||
final Map<PatchShaderType, String> entityResult = TransformPatcher.patchAttributes(VERTEX_ENTITY, null, null, null, FRAGMENT_ENTITY, TEX_LM, false);
|
||||
assertNotNull(entityResult);
|
||||
assertHas(entityResult.get(PatchShaderType.VERTEX), "uniform int entityId;");
|
||||
assertHas(entityResult.get(PatchShaderType.VERTEX), "layout(location = " + ImmediateExtendedAttribHandler.LOC_ENTITY_IDS + ") in vec4 iris_Entity;");
|
||||
}
|
||||
}
|
||||
@@ -118,10 +118,10 @@ class VertexReplayExtractionTest {
|
||||
final RwImageStoreExtractor.Result result = replayOf(TransformPatcher.patchAttributesInstanced(CRYSTAL_VERTEX, null, null, null, FRAGMENT, TEX_LM, false, Instancing.TEMPLATE));
|
||||
final List<VertexInput> inputs = RwImageStoreExtractor.parseVertexReplayInputs(result.computeSource());
|
||||
|
||||
final VertexInput entity = input(inputs, "iris_Entity");
|
||||
final VertexInput entity = input(inputs, "iris_InstEntity");
|
||||
assertEquals(InstancedAttribs.LOC_ENTITY, entity.location());
|
||||
assertEquals("uvec4", entity.glslType());
|
||||
assertTrue(result.computeSource().contains("iris_Entity = uvec4(_vg_uint("), result.computeSource());
|
||||
assertEquals("vec4", entity.glslType());
|
||||
assertTrue(result.computeSource().contains("iris_InstEntity = vec4(_vg_float("), result.computeSource());
|
||||
assertFalse(result.computeSource().contains("location"), "a location on a former interface variable does not compile in compute");
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user